pax_global_header00006660000000000000000000000064137266337770014537gustar00rootroot0000000000000052 comment=d3e72da77f0073624c7cd5c1a2663bb721211f7f UnixAgent-2.8/000077500000000000000000000000001372663377700133125ustar00rootroot00000000000000UnixAgent-2.8/.github/000077500000000000000000000000001372663377700146525ustar00rootroot00000000000000UnixAgent-2.8/.github/Contributing.md000066400000000000000000000123101372663377700176400ustar00rootroot00000000000000

Banner

OCS Inventory

Some Links:
Ask question | Installation | Website

# OCS Inventory Contributing Guidelines ## Pull Request Process 1. Fork it! 2. Create your feature branch: `git checkout -b my-new-feature` 3. Add your changes: `git add folder/file1.php` 4. Commit your changes: `git commit -m 'Add some feature'` 5. Push to the branch: `git push origin my-new-feature` 6. Submit a pull request ! ## Pull Request Informations When contributing, please open an issue before or contact the team using mail. This will prevent all the duplicate of work. Also, check if your contribution is not already in the roadmap or affiliated to an issue. If you are contributing on a small scale (translation, a few line modification), you don't need open an issue or contact the team but you will need to explain what you've done in the Pull Request comment and provide as accurate commit messages as possible. Cf. Commits Messages Name Informations If you need to discuss about a big change or need some help of our team during the development of your contribution, we can use other communication method like Telegram, IRC, Skype. ## Commits Messages Name Informations Try to create as accurate as possible commit messages. This will help us to speed up the review process and to reduce the misunderstanding (which can lead to a Pull Request to be rejected) There is no commit messages convention but here are some examples : 1. Create as short as possible commit name 2. One commit for one modification 3. Always leave the second commit line blank If it seems difficult to summarize what your commit does, it may be because it includes several logical changes or bug fixes, and are better split up into several commits using `git add -p`. ## Code of Conduct ### Our Pledge In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. ### Our Standards Examples of behavior that contributes to creating a positive environment include: * Using welcoming and inclusive language * Being respectful of differing viewpoints and experiences * Gracefully accepting constructive criticism * Focusing on what is best for the community * Showing empathy towards other community members Examples of unacceptable behavior by participants include: * The use of sexualized language or imagery and unwelcome sexual attention or advances * Trolling, insulting/derogatory comments, and personal or political attacks * Public or private harassment * Publishing others' private information, such as a physical or electronic address, without explicit permission * Other conduct which could reasonably be considered inappropriate in a professional setting ### Our Responsibilities Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. ### Scope This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. ### Enforcement Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at `contact@ocsinventory-ng.org` . All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. ### Attribution This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] [homepage]: http://contributor-covenant.org [version]: http://contributor-covenant.org/version/1/4/ UnixAgent-2.8/.github/ISSUE_TEMPLATE.md000066400000000000000000000005661372663377700173660ustar00rootroot00000000000000*It's hard to solve a problem when important details are missing, that why we added this template, to help you and us.* ### General informations Operating system : Perl version : ### OCS Inventory informations Unix agent version : ### Problem's description *Describe your problem here* ### Inventory log file ( optional ) *Use github cloud or trusted upload website* UnixAgent-2.8/.github/PULL_REQUEST_TEMPLATE.md000066400000000000000000000020301372663377700204460ustar00rootroot00000000000000## Must read before submitting Please, take a look to our contributing guidelines before submitting your pull request. There's some simple rules that will help us to speed up the review process and avoid any misunderstanding [Contributors GuideLines](https://github.com/OCSInventory-NG/OCSInventory-ocsreports/blob/master/.github/Contributing.md) ## Status **READY/IN DEVELOPMENT/HOLD** ## Description A few sentences describing the overall goals of the pull request's commits. ## Related Issues Put here all the related issues link ## Todos - [ ] Tests - [ ] Documentation ## Test environment If some tests has been already made, please give us your test environment' specs #### General informations Operating system : Perl version : #### OCS Inventory informations Unix agent version : ## Deploy Notes Notes regarding deployment the contained body of work. These should note any dependencies changes, logical changes, etc. 1. ## Impacted Areas in Application List general components of the application that this PR will affect: * UnixAgent-2.8/.gitignore000066400000000000000000000007571372663377700153130ustar00rootroot00000000000000# Mac OS Specific dir .DS_Store build/ *.old # Iceberg specific dir tools/macosx/installer_gui/iceberg/OCSNG.app/ tools/macosx/installer_gui/iceberg/ocscontact tools/macosx/installer_gui/iceberg/plugins/ # Ignore darwin perl lib if un tar from script repository tools/macosx/scripts/darwin-perl-lib/ # Xcworkspace and user data project.xcworkspace/ xcuserdata/ # perl Makefile.PL /MYMETA.json /MYMETA.yml /Makefile /ipdiscover /run-postinst # make /blib/ /pm_to_blib # make dist /*.tar.gz UnixAgent-2.8/.travis.yml000066400000000000000000000005221372663377700154220ustar00rootroot00000000000000language: perl perl: - "5.30" - "5.28" - "5.26" - "5.20" before_install: - sudo apt -y install dmidecode make gcc - cpanm --quiet --installdeps --notest . script: env PERL_AUTOINSTALL=1 perl Makefile.PL && sudo make && sudo make install addons: apt: update: true branches: only: - masterUnixAgent-2.8/AUTHORS000066400000000000000000000006601372663377700143640ustar00rootroot00000000000000Maintainer: Frank Bourdeau Former maintainers: Guillaume PROTET Gonéri LE BOUDER Based on the legacy OCS Linux agent (Copyright (C) 2005-2008 Pascal DANEK ) Copyright 2006-2020 OCS Inventory contributors Website: http://www.ocsinventory-ng.org Please read THANKS to get the list of the contributors UnixAgent-2.8/Changes000066400000000000000000001472701372663377700146200ustar00rootroot00000000000000Revision history for Ocsinventory::Agent 2.8 * Rework SNMP Interface and configuration * Rework IPDiscover manager * Rework LDAP Authenticaiton * Rework Auth backend * Rework software inventory data structure * Add MySQL 8 compatibility * Add ASCII code management on deployment messages * Add "is not empty" criteria on multi search * Add computer archive feature * Add IPDiscover scan split by TAG * Add CVE Matching regex * Add chinese translation * Add perl injector related inventory on main dashboard * Update German translation * Improve CVE Inventory * Improve translation on deployment form * Move networks submenu to inventory menu for better visibility * Fix date interval search on multi criteria * Fix IPDiscover subnet blacklist * Fix CVE-2020-14947 * Fix stats to match user TAG restrictions * Fix CSV export to match table show / hide configuration * Fix minor bugs on CVE Inventory * Fix deployment estimation time when editing a packaged * Fix deployment fragment bug * Fix small package deployment (< 1024 bytes) * Fix a bug on MySQL SSL connection * Remove SNMP_INVENTORY_DIFF * Typos fix * Minor bug fix 2.6.1 * Allow encode http password in base64 * Fix repository inventory #254 * MacOS installer / packaging rework * Suppress error message for LSPCI * Fix oracle package setup * Remove uninitialized value message * Now use os-release file * Improve drives management (Linux / MacOS) * Imprive IPv6 inventory 2.6.0 * Fix issue Service-Pack wrong info on Linux Clients (reports on https://github.com/OCSInventory-NG/OCSInventory-ocsreports/issues/741) * Fix issues #181, #187, #194, #197 * Merge PR #175, #178, #190, #191, #193, #196, #199, #201 2.4.2 * Fix warning argument freebsd isn't numeric * Fix Debian repository * Update manifest * Fix name and url in Repository * Fix for Ubuntu and older Debian version * Merge PR #141,#135,#143 * Fix spelling errors * Add arcconf for Adaptec * Fix issue #124 * Replace hpacucli with ssacli * Merge PR #144,#145,#146,#147,#148,#150 * Make use of EDID utilities optional on modern kernels * Fallback to mainboard serial if bios serial is not available * Merge PR #152, #156, #158, #159 * Fix issue for ipdiscover * Indicate god value for memory * Use now Parse::EDID module to retrieve monitor infomrations * Merge PR #161, #163, #164, #165, #169, #170, #172, #173, #174 2.4.1 * Add the date of installation for debian/ubuntu packages * Add support for zfs * Rewrite cpu bsd * Fix some bugs on Repository/Deb.pm file * Ipmi.pm : fix fatal typo * Bios.pm : fix "invalid" message * UUID.pm : fix "invalid" message * Virtualization : fix for Proxmox * Fix for vlans * Fix virsh out 2.4 * Add test to switch 'waitpid command' according to OS * change bazar revision number to git revision number * ipdiscover: fix default latency * Ignore files which are created during installation * Fix and improve comments in module.conf * Fix some typos * Update MANIFEST * Fix code which disables SSL certificate verification * Fix storage parameters from smartctl * Fix markdown syntax and typo in README.md * Use pkg command on Solaris 11 to create the Software Inventory * Upgraded memconf to v3.14 (support for SPARC T7-4 and S7-2) * New feature: repositories inventory * Fix problem line 280 * Issues corrections * Retrieve info for apfs formatted drive * correct df check for AIX * Fix regexp for listing network interfaces on macOS * Update Mem.pm * Update Agent.pm 2.3 * Suppress functions can_run, can_load, can_read from Backend. Those from Common.pm are now used * Update libraries snapshot for release 2.2 * Suppress reference message to support "No support detected. Registration key: N/A" * Linux storages now supports Megacli raid * Merge Mysteq PR "centos-release is the correct file to check" * Merge XANI PR "read edid from sysfs, fallback to old method if no monitor is found" * Fix bugs in Network.pm and IP.pm files (OS Linux) * Correction for usb inventory * Retrieve Docker container informations * Update memconf command to last revision * Add enhancement support for Xen xl command (xm command already present) 2.2rc1 * Update memconf command to last revision * Fix Bug #1466748 Interface Detection Infiniband MAC wrong * Fix Bug #1423905 Failed HTTP auth if password contains # character * Fix syntax error in BSDpkg.pm file * HPUX/Solaris: use --nosoftware instead of --nosoft * Correction of graphics resolution * Retrieve speed and duplex from a different way * Enhancement: unix agent can now report battery inventory * Enhancement: unified agent can retrieve lxc container * Suppress --nosoft option * Fix Bug #1440626 Typo error in Alpha/CPU.pm * Fix Bug #1438719 pkg_list has been deprecated on FreeBSD so no software inventory is gathered on those systems * Fix Bug #1438021 Support s390x processors * Fix Bug #1436702 Wrong disk size * Fix Bug #1435675 AIX typo error in Hardware.pm * Fix Bug #1431844 données de HDD SAS/SAN manquantes AIX 5.3, 6.1 et 7.1 * Fix Bug #1420073 Linux/Archs/i386/CPU.pm reports incorrect CPU information * Fix Bug #1409671 PROCESSORS bad value on PowerPC arch * Fix Bug #1405167 Presentation of OS Name and OS Version * Fix Bug #1389255 Nombre d'interfaces recherchees * Fix Bug #1376787 [UNIX Agent] Feature request: report Fusion-io cards * Fix Bug #1364123 created script perl for xenserver * Fix Bug #1350240 --nosoftware does'nt work on aix * Fix Bug #1342038 Wrong data for cores on Unix Agent 2.1.1 * Fix Bug #1322088 CPU show 0 on VM libvirt * Fix Bug #1319683 libvirt VM partial detection * Fix Bug #1293588 CPU on Ubuntu may not be detected because of `arch` command and Dumper reference * Fix Bug #1246427 CentOS Linux 6 not identified * Fix Bug #1201734 Hyper-V virtual machines not recognized as "Virtual Machine" by agent * Fix Bug #1159742 Ipmi.pm does not load Net::IP at the right place * Fix Bug #1064296 ipv4 handling fix 2.1.1 * Add number of socket in Linux/Archs/i386/CPU.pm * Add hyperthreading support in Linux/Archs/i386/CPU.pm * Fix Bug #1312830 about missing CPU information * Update memconf command to last revision * Add new file to detect Oracle distro * Fix CPU.pm which couldn't retrieve multi socket processors * Fix Bug #1045356 about regression in ifconfig parsing * Fix a mistake in tag in 6876.xml * Move lib/Ocsinventory/Oracle and lib/Ocsinventory/Apache directories in lib/Ocsinventory/agent/Modules directory * Fix a mistake in Hooks.pm which makes Download.pm and Snmp.pm not loaded by agent * Fix problem on path of arch command * Fix debug trace in CPU.pm * Fix a translation mistake in MacOSX agent French installer 2.1 * Fix #Bug 1272425 about status of libvirt virtual machines not reported * Fix blueprint about installation date in the report of the installed software * Fix blueprint about UUID value in the hardware Table * Fix Bug #1247190 about default gateway as gateway for all interfaces under Linux * Add new screen code for edid (PTS) * Add new module to retrieve Nvidia cards * Add new module to retrieve virtual machines on vmware workstation * Return corrected values for storage under Fedora 19 * Fix Bug #1247190 about default gateway as gateway for all interfaces under Linux * Add new screen code for edid (PTS) * Add new module to retrieve Nvidia cards * Add new file to detect CentOS distro * Add new module to retrieve virtual machines on vmware workstation * Return corrected values for storage under Fedora 19 * Fix Bug #1206514 about enhancing modules loading to allow directories * Fix a bug in Common.pm about processes data marked as virtualmachines data * Fix Bug #1216935 about Mac user agent not generating UUID * Fix Bug #1237682 about RPM.pm INSTALLDATE format not always accepted by MySQL * Retrieve the speed of network card * Add a new log message when unable to scan a SNMP devices in Snmp.pm * Fix problem about IP address tests in Snmp.pm * Remove "-pP" option passed to nmap in Snmp.pm * New module to retrieve NetApp devices using SNMP * New module to retrieve Sun devices using SNMP * Add new value to BIOS.pm * Fix bugs in CUPS.pm and Usb.pm files * Retrieve new values for CPU * Update memconf command to latest version * Fix bugs about usb in Lsusb.pm and Common.pm * Add retrieve of usb connected devices * Fix Bug #1198088 about wrong data for processors under 2.1 RC1 * Fix bug about SNMP v3 in 9.pm * Fix bug about custom network scanning in Snmp.pm * Add retrieve of video memory size * Fix Bug #1169675 about error message about SSL_verify_mode of SSL_VERIFY_NONE under Fedora 18 2.1rc1 * Fix Bug #1095989 about a bad regex in Libvirt.pm * Fix Bug #1032393 about softwares bot inventoried vi dpkg-query * Add custom SNMP MIBs XML copy from sources in postinst.pl * Getting monitor serial number in MacOS/Video.pm * Add a new configuration option for SSL certificate check in MacOSX agent installer * Add new screen codes for edid * Fix Bug ##1117110 about missing number of CPU socket * Add availibility to reforce a package deployment * Code rewrite in Common.pm to prevent sending empty XML tags to OCS server * Fix Bug #1086086 about uses of initialized value in Snmp.pm * Fix Bug #1087270 about zombie processes when running in daemon mode * Fix Bug #1086078 about use of initialized value * Fix Bug #1070788 about zip packages support * Fix Bug #1045356 about ifconfig parsing issue (Fedora >=17) * New availability to scan custom network with SNMP using a network address received from server * Fix Bug #1049626 about Qemu virtualization not detected on proxmox * Fix Bug #1040197 about VLAN interface AIX support * Add detect CPU architecture * AIX memory module change * Add many informations about CPU (l2cachesize, status, socket designation, cores number) * Fix Bug #882574 about parsing of dmidecode fails on SMBIOS warning * Fix Bug #984699 about the Output of 'ps' in VirtualBox module is displayed in stdout * Fix Bug #571655 about the Wrong Sys:Syslog usage * Retrieve family, serial number, number of processors, clockrate for BSDsystems * New module for inventoring Oracle databases * Multiples monitors patch added * Fix Bug #1023670 about memconf not working with HP-UX 11.31 * New version of Gentoo.pm * New Backend/Virtualization/Parallels.pm module for Parallels virtual machines inventory * Plugin Processes moved as module * Fix Bug #911492 about Freebsd Storage drives not being reported * Fix Bug #911491 about Freebsd CPU info not reporting properly * Fix Bug #873377 about Installed packages on Gentoo * Add OS/Linux/LVM.pm module for Logical Volume Manager support * New Snmp/231.pm module for Fujistu devices * postinst.pl can now be launched in non-interactive mode using new "--nowizard" launch option * Adding all the configuration options as launching arguments in postinst.pl * Adding new interactive questions about "debug", "logfile", "ssl" and "ca" configuration options in postinst.pl * Download.pm uses LWP useragent initiated by Network.pm for SSL checks * Download.pm uses LWP useragent initiated by Network.pm for info and frags files downloads * Network.pm can use LWP version 6 SSL useragent options * New --ca configuration option to specify a CA certificates file path for SSL certificate checks * New --ssl configuration option to enable/disable SSL certificate checks * Customize SNMP scans using a special XML format received from server * Getting network devices MAC address during SNMP scans * Availibity to scan any networks SNMP devices using nmap or ping scans * SNMP v3 available for SNMP scans * Add new --ssl configuration option to enable or disable certificate check during SSL communications * Change 'SERIAL' field name and add checksum for inventory XML CPUS section * Now getting MANUFACTURER and SERIALNUMBER in Snmp/3375.pm * Add new fields in setSnmpLoadBalancer() method in Common.pm * Fix Bug #1085020 about ERR_ALREADY_IN_HISTORY message that should be success * Fix bug with SNMP cartridges and trays in Common.pm * Add new MacOS/Controller.pm module to get controllers inventory under MacOSX * Add new MacOS/Slots.pm module to get slots inventory under MacOSX * Add missing DESCRIPTION field in addController() in Common.pm * Set debug and lazy options to 0, in generated ocsinventory-agent.cfg file by macOSX graphic installer, if check boxes are not selected * Add a new configuration option to set lazy mode in MacOSX graphic installer * Improve MacOSX postinstall script to able to deploy MacOSX agent using NetInstall 2.0.5 * Fix Bug #953968 about MacOSX OCSNG.app crash under MacOSX 10.4 64 bits * Fix bug about illegal hexadecimal digit in Snmp/Host_Resources_Mib.pm * Fix segfault and buffer overflow bugs in ipdiscover.c * Improve OCS MacOSX agent internationalization support * Back to previous pane after wrong OCS server address warning in MacOSX installer 2.0.4 * Improve memory slots detection under MacOSX 10.7 in MacOS/Mem.pm * Force OCSNG.app to become the topmost window in tools/macosx/ocsng_app-xcode/main.m * Fix Bug #901570 about wrong printer name if no printer found in MacOS/Printers.pm * Solving CPU and memories inventory detection under MacOSX Snow Leopard and MacOSX Lion * Modifying MacOSX backend files to use the new Mac::Sysprole Perl module version * Fix Bug #887534 about invalid CREATEDATE in lib/Ocsinventory/Agent/Backend/OS/Linux/Drives.pm 2.0.3 * Fix Bug #881406 about security issue due to snmp_com.txt file which is no longer used * Fix Bug #874269 about wrong conversion if hard drive >= TB in MacOS/Storages.pm * Fix Bug #879487 about a misplaced object release in ocs_agent_configPane.m 2.0.2 * Fix bug on "Debug Mode" checkbox in MacoSX installer * Fix bug while sending ERR_DOWNLOAD_INFO message in Donwload.pm * Fix Bug #856161 about installer problems on MacOSX Tiger 2.0.1 * New SNMP data using If_Mib.pm: IP address, netmask, gateway and routing informations * Use the "public" SNMP community if no community defined in OCS server configuration * Various bug fixes in Snmp.pm * New 2.0 MacOSX integration * Bug #798428 about standalone agent building * Change variable names to lowercase in Snmp/3375.pm * Fix a closedir omission in Solaris/Packages.pm * Modify releases tarball name when building it using make dist command * Various patches for CPU, Bios and Drives detection for HPUX systems * Fix Bug #781732 about a missing chomp() in Processes.pm 2.0 * Fix Bug #778692 about using authentication when sending messages in Download.pm * Patch from Yoann Le Bihan for Solaris zones support * Fix Bug #586321 about wrong version comparison in Vmsystem.pm * Bug #772436 about download end message report in Download.pm * Display support log received from PROLOG * Various patches for Snmp/9.pm module (Cisco) * Add --nolocal option to desactivate local mode even if it is set in config file or command line * Fix Bug #767290 about /etc/sysconfig/ocsinventory-agent server settings ignore (only for Redhat like distributions) * Only inventory vitualmachines which have an UUID in VirtualBox.pm to prevent inventoring USB devices or shared folders as virtualmachines 2.0rc4 * Complety clean the disastrous treatments of accountinfos while receiving it from server,storing it in file and adding it in inventory * Fix UTF8 problems due to XML::Simple::XMLIn() 2.0rc3 * Fix Bug #720635 about lspci usage on old Linux distributions * Fix Bug #720626 about Gentoo packages with hyphen in their names * Fix a bug with the use of pacman tool on ArchLinux. We now launch the real packages manager instead of the famous game ;) ;) * Avoid perl errors when no answer from OCS server * Enhance logging in Snmp.pm and Download.pm when disabling this modules (local mode or prerequisites not OK) * Patches from Bernhard Denner to enhance CPU and memry detection on old SUN solaris workstations * Patch from Bernhard Denner to enhance dhcp-leases files detection on Linux systems 2.0rc2 * Add a new cleanXml() subroutine in Common.pm to clean non printable characters in both standard inventory and SNMP inventory * Various patches for Snmp/9.pm module (Cisco) * Add a new addSnmpCPU() subroutine in Common.pm * Disabling Download.pm if agent running in local mode 2.0rc1 * Add download_start_handler to check if Net::SSLeay can be load and disable Download.pm if not * Add Net::SNMP optional dependency in README file. * Delete Win32 from backend * Various patches for 9.pm and If_Mib.pm to enhance ethernet ports speed display (Françs Mermet) * New SNMP modules for Juniper, Futjitsu and F5 vendors (Françs Mermet) * Fix Bug #682689 about missing data for disk when can't run lshal command (Bernhard Denner) * Add a warning message about user privacy in man page for --scan-homedirs option * Various patches for 8072.pm an If_Mib.pm (Françs Mermet) * Change timeout for Backend modules from 180 to 600 seconds * Change timeout for Backend modules from 180 to 600 seconds * Back on the ipdiscover binary from the old OCS Linux Agent to make network scans lighter than Nmap. Ipdiscover binary is only available under Linux systems * Use LaunchDaemons instead of LaunchAgents in MacOSX package * Fix SSL errors if no URL is given by the server in Snmp.pm * Do SNMP scans and treatments only if asked by the server * Delete some useless logs in debug for SNMP constructors and standard MIBs modules * Change oid_value in snmp_info subroutine in Printer_Mib.pm * New SNMP 2620.pm module for Checkpoint Software Technologies constructor (Françs Mermet) * Add new "DEVICEPORT" and "DEVICETYPE" fields in addSnmpnetwork() in Common.pm * 311.pm and 8072.pm use setSnmpComputer() to set the type of SNMP device * Add a new addSnmpInput() subroutine in Common.pm * Fix a bug in addSnmpSwitch subroutine in Common.pm * Replace SetSnmpSwitch() subroutine by SetSnmpSwitchInfos() in Common.pm * Set right fields for AddSnmpSwitch() subroutine in Common.pm * Fix various bug on snmp_oid_run subroutine for constructors and standard MIB modules * Fix various mistakes and missing fields in snmp subroutines in Common.pm * Fix a warning due to deprecated syntax in 3ware.pm * Fix a warning due to deprecated syntax in 3ware.pm * Fix a catastrophic performance issue by preventing to run sysctl at every line of demidecode output to get CPU informations on BSD systems * Snmp.pm now download snmp_com.txt file to get informations about SNMP communities for scans using HTTPS * New subroutines called "getHttpFile" and "getHttpsFile" in Network.pm to download files easily using HTTP or HTTPS. * Fix bugs and minor mistakes in Common.pm and If_Mib.pm * Add Lenovo EDID for monitors (Adam Buchbinder) * Disabling Snmp.pm if agent running in local mode * Fix a warning if network interface is down in Ipdiscover.pm * Enhance inventory initialization for a better modularity * Local mode can now use the "inventory_handler" hook * Various patches for SNMP constructors or standard MIB module (Françs Mermet) * Prevent a bug in using Default.pm (Françs Mermet) * Add "ACR" and "EPI" EDID ID for monitors (Adam Buchbinder) * Fix Bug #597752 about TYPE and VOLUMN fiels reversal for BSD systems. * Fix Bug #612515 to report network interface that don't have an IP address (Mick K) * Don't take care of host with no MAC address in Nmap.pm * Add the SOFTWARE field in addSnmpCard subroutine * Enhance Printer_Mib.pm to add information about printer status and printer error state * Snmp.pm now use Default.pm to launch standard MIB modules by default (Françs Mermet) * Upgrade several SNMP contructors/standard MIB modules * Add a new SNMP constructor module for Lexmark * Add a new SNMP module for the standard Entity MIB. * Add a new SNMP module to load standard MIB modules by default * Add new subroutines for SNMP XML feeding for informations about switches, network cards, blades, firewalls etc.... * Correct a log mistacke in Printer_Mib.pm * New 11.pm module to enable SNMP scans on HP devices * Get the SNMP device MACADDR from PROLOG resp to generate the SNMPDEVICEID in Snmp.pm * Add new subroutines in Common.pm for special SNMP XML feed or SNMP special treatments * New Printer_Mib.pm module to get SNMP printers informations 2.0 alpha Tue, 27 Jul 2010 22:27:27 +0100 * Snmp.pm use flushXMLTags() from Common.pm to flush the content of $common->{xmltags} * Modifying the inventory backend to use functions from Common.pm instead of Inventory.pm * New Snmp.pm for SNMP scans integration. It comes with its constructors modules to enhance scans results (a lot of beers to Françs Mermet to thank himfor his help) * Modifying postinst.pl to include Ocsinventory::Agent::Modules::Snmp * Agent.pm : add $logger object in Ocsinventory::Agent::Common instantiation * Common.pm : adding the can_run(), can_load(), can_read() and runcmdi() generic methods. Adding the use of the $logger object * Common.pm : add a new field 'TYPE' in setSnmpCommons() * Agent.pm now uses the new Networks.pm methods and add the $network object in the $context hash * Networks.pm now gives generic methods to send a XML to OCS server and receive a XML from OCS server * New addInput() method in Common.pm to add mouses and keyboards in inventory * Donwload.pm now use 'get_path' and 'already_in_array' functions from the new Common.pm * Common.pm : Replace the former Common.pm by a new one. Common.pm now give a lot of methods for other agent modules * Agent.pm : instanciate Ocsinventory::Agent::Common object and add a reference to it in $context * Use of the Nmap::Parser perl module to correct the very buggy Nmap implementation for Ipdiscover * Various patches for Solaris support (Lucas MASSE) * Fix the network speed data oblivion in Inventory.pm. The network speed can now be added in Network.pm of the several OS backends * Put the prolog_reader hook run at the right place to avoid an error if the agent failed to reach the server * Enhance dom0 support for Xen support (Guillaume ROUSSE) * Add bios informations for Xen PV hosts (Guillaume ROUSSE) * Fix Bug #552727 about getting processes that are running in Solaris (Emengao) * Add the availiability to disable a module using start_handler hook * Debug and code cleaning in Download.pm * Fix Bug #552097 * Add XML::SAX::Expat module include * Replace {REQUEST} and {ADM} by {xmlroot} in xml handling for a better and better readability * Remove text about Win32 port in the README file * Correct a bug in Hooks.pm to pass inventory or prolog to modules * Add headers for the modules logs * Correct a bug in postinst.pl when removing the old Linux agent * Ocsinventory::Agent::Option:: namespace is now Ocsinventory::Agent::Modules:: * Modules now use Perl's object system * Hooks are now methods and not simple subroutines * Hook.pm is now Hooks.pm * Use of a new context hash in Agent.pm * CompatibilityLayer.pm is now Hook.pm * Calling hooks only in Agent.pm * Update HPUX support (Francois Mermet) * Verify ID value received by server in Download.pm * Verify the network syntax in Nmap.pm * Replace an hard coded pattern in Linux/devices.pm * Removing non posix cp option in Download.pm * Upgrade to memconf V2.13 * Add an in contrib example of script to identify specific software (Simon CLARA) * An example of script to use tarball to identify installed software * HP-UX: initial support, tested on RP3440 * Solaris/Network: support Zone * Solaris: use regex to identify CPU class * Improve the README about non-interactive installation * MacOSX: Correctly identify the CPU frequency on MacOSX 1.6 French 1.1.2.1 Tue, 12 Oct 2010 19:42:41 +0100 * Fix a secutiry bug due to the use of ExtUtils::Installed in Backend.pm. See http://bugs.debian.org/590879 and http://www.debian.org/security/2009/dsa-1828 for more informations. Thanks to Remi Collet for his report. 1.1.2 Sun, 27 Dec 2009 17:24:43 +0100 * Avoid problem with dmidecode -V output on RHEL3.9 (Remi COLLET) * Fix internal --delaytime handling. That's seconds, not hours! * Download.pm: improve a error message 1.1.1 Mon, 21 Dec 2009 22:38:12 +0100 * NETWORKS/VIRTUALDEV should be 1 or 0 * FreeBSD: Fix CPU detection (David DURIEUX) * Virtualization::Qemu, fix kvm detection * Don't run brctl if it's not installed * Various wording fixes (Vincent KNECHT) * Improve README (Barius DRUBECK) * Get serial number from ext4 partition if ext4dev driver is used * LP: #494908 Agent fails to retrieve info file when a package is activated only with the server name (Pascal DANEK) * LP: #495398 Fix RedHat version detection (Stéane URBANOVSKI) * LP: #490774 Fix PowerPC CPU detection on Linux, thanks darkpep for the bug report 1.1 Fri, 06 Nov 2009 16:07:08 +0100 * addMemorie() renamed to addMemories(), this had been broken during the addMemories() . addMemory() transition * Debug mode: msg "check function failed" changed to "ignored" since the fails may be wanted by the check() function * CompatibilityLayer: $self->{params} changed to $self->{config}, this restore the debug mode in Download.pm * Continue XML::Inventory functions name clean up. Rename: - addSlots() calls to addSlot() - addMemories() calls to addMemory() * Move ocsinventory-agent POD documentation frol Ocsinventory::Agent to the ocsinventory-agent shell script. So now the manpage has the correct name * Fix RPM output parsing (Remi COLLET) * VMWareESX: avoid breakage is VM has spaces in its name (Christian Michallek) * Try to detect kvm --uuid value * Makefile.PL, check for Net::SSLeay * Move Ocsinventory::Agent in a .pm and add a wrapper script to load in order to by able to process --devlib * Parallels.pm: doesn't use sudo anymore and check for --scan-homedirs * Prune 'Mac OS X' from the version on Mac + typo fixes (Scott HANNAHS) * POD doc, add a paragraph about the config file * LP: #462529, Fix EDID screen detection, thanks Sergio MERINO * Use boolean for networks/virtualdev * Generic/Screen: chomp uuencode output * Generic/Screen: HSD code for "Hanns.G" (Remi COLLET) * postinst.pl, put user $PATH in /etc/cron.d/ocsinventory-agent 1.1_beta1 Fri, 18 Sep 2009 11:54:12 +0200 * Can use Net::CUPS to find the default printer * AIX: Hide procfs in Filesystem * OS::Linux::Storages, correctly retrieve the serial (Vladimir ELISSEEV) * load $http_proxy env settings and --proxy option is available * Add OS::Linux::Distro::NonLSB::ArchLinux (Julien SAFAR) * New Backend OS::Generic::Processes * Linux/BSD: detect DNS servers config * Solaris: Better output for $OSVErsion (Vladimir ELISSEEV) * Solaris: Sun Fire T1000 patches for memory (Vladimir ELISSEEV) * Solaris: memory SPARC Enterprise T5220 (Vladimir ELISSEEV) * Solaris: CPU SPARC Enterprise T5220 (Vladimir ELISSEEV) * Solaris: CPU SPARC Enterprise T5220 (Vladimir ELISSEEV) * Linux: split the /proc/cpuinfo parsing depending on the arch * Linux: drop Linux::Controllers which is duplicated with Generic::Lspci::Controllers (Vladimir ELISSEEV) * AIX: Various fixes in Memory.pm (Sebastien DAGNICOURT) * AIX: Storages.pm, Virtual disks support and fixes (Sebastien DAGNICOURT) * Backend.pm: Bump the default timeout from 30 to 180 secondes * Agent/XML/Inventory: Fix when version == 0, bug found by neisen * AIX: device type adjustment (Sebastien DAGNICOURT) * Solaris: Sun-Fire-V440 support (Sebastien DAGNICOURT) * Add a missing space if the name banner in --debug mode * Agent/XML/Inventory.pm: Add FROM and INSTALLDATE fields in software list and LASTLOGGEDUSER DATELASTLOGGEDUSER in HARDWARE (Nicolas EISEN) * Initialize etcdir key even if there is no config file * CompatibilityLayer: correctly set $debug * CompatibilityLayer: better log messages * getOptionInfoByName return an array ref now * rename getOptionInfoByName to getOptionsInfoByName * --debug print the XML on STDERR * Rename the params key to config to avoid ambiguity with $params * set HARDWARE/DEFAULTGATEWAY (Nicolas EISEN) * RPM: collect the install date and the size (Nicolas EISEN) * Linux: Collect LASTLOGGEDUSER and DATELASTLOGGEDUSER (Nicolas EISEN) * DPKG: collect the Installed-Size (Nicolas EISEN) * Linux: Collect the ext{2,3,4} and xfs serial number * Linux: Collect the ext{2,3,4} creation date * Add a warning when no certificat is found * Turns off alarm once it's backend run is finish * Fix the IPMI module detection * Linux: Store the PCISLOT and the driver name * NETWORKDS, only store Networks with an address * Linux: detect virtual network device * Linux: Store CONTROLLERS/DRIVER and CONTROLLERS/PCISLOT * Linux: Collects xfs, ext{2,3,4} and vfat label * runs the backend module from main() it's possible to reuse the Backend object. * Linux: filter non standard MAC address returned by ifconfig like 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00 mac * Linux: Fix the Uptime check() * Preliminary libvirt support * Partial rewrite of the Download.pm backend * Add a warning if the user is no root, thanks Nicolas EISEN and Sylvain LUCE * SPARC-Enterprise M4000 and M5000 support (Sylvain LUCE) * Libvirt: collect VCPU info (Philippe LIBAT) * Add Virtualization::Xen module (Philippe LIBAT) * Solaris: add a warning if memconf is not in $PATH * Switch the XML content from ISO-8859-1 to UTF-8, BTW we force LC_ALL=C... * Fix the history flood in Download.pm (Pascal DANEK) https://sourceforge.net/tracker/index.php?func=detail&aid=2806585&group_id=58373&atid=487492 * Stores PCIID in CONTROLLERS/PCIID * Storage the monitor EDID string in BASE64 and UUENCODE * Linux: Storages: reorganize the code base and use lshal * Linux: Drives, complete inforamtions with lshal (Nicolas EISEN) * Linux: fix the PowerPC CPU detection https://sourceforge.net/tracker/?func=detail&atid=487492&aid=2043221&group_id=58373 * Warns the user during the install process if one of the recommended module is not installed * Update out copy of memconf, thanks WeatherDave who notified the new revision and of course Tom Schmidt who do a great job * MacOSX: Avoid a scalar used has hash ref error, thanks Adadov * Save VIDEOS/MEMORY and VIDEOS/RESOLUTION * MacOSX: Correctilly detect Up/Down network interfaces (David OLIVIER) * AddNetwork() doesn't ignore network with no IP address (David OLIVIER) * add --backend-collect-timeout parameter (Nicolas EISEN) * MacOSX: convert the IP mask from hex (David OLIVIER) * MacOSX: add a workaround to avoid Mac::SysProfile failure on MacOSX 10.5.7 (David OLIVIER) * Add Virtualization::VirtualBox module (Nicolas EISEN) * Add Virtualization::Qemu module (Nicolas EISEN) * Add Virtualization::Vmsystem module (Nicolas EISEN) * Better smartctl detection (Nicolas EISEN) * optimization and vm users detection Virtualization::VirtualBox (Nicolas EISEN) * Add Virtualization::VmwareFusion module (Walid NOUH) * Don't use hdparm prior 9.2.2 anymore to avoid crap in kernel log, see http://forums.ocsinventory-ng.org/viewtopic.php?pid=20768 * Correctly detect ipmitool * Solaris: i86pc Memory support (Jean-Françs BOUCHER) * Solaris Zone support (Maurizio BERTABONI) * Always send tag, even if server already has one * Add the byHand software collect method (Séstien DAGNICOURT) * add logging to can_read(), can_load() and can_run() * use addUser() instead of setHardware() * Add the runcmd() in the Backend modules 1.0.1 Sun, 22 Mar 2009 20:48:49 +0100 * Fix a typo in Ocsinventory::Agent::Backend::OS::AIX::Memory 1.0 Sun, 22 Mar 2009 20:14:26 +0100 * Hide warning messages when tw_cli or hpacucli are not present on CentOS * Avoid unnecessary about missing 'http://' in local mode * Ipmi.pm: use can_run do detect ipmitool * LSB.pm: properly use can_run * Avoid a warning in CompatibilityLayer.pm in local mode * Improve the README file * Avoid a warning at runtime if rpm is not correctly installed * BSD: Detect AMD64 arch (David DURIEUX) * HP.pm: force detection even if slot 1 is 0 (Remi COLLET) * HP.pm minor clean up + indentation * HP.pm send the $model as NAME to avoid NAME == 'unknown' (Remi COLLET) * New backend module ServeRaid for IBM ServeRAID card (Remi COLLET) * Linux::Storages, fix the hdparm call (Remi COLLET) * OS::Generic::Dmidecode::Bios, fix for RHEL2 dmidecode (Remi COLLET) * launch backend modules with a 30sec timeout * post-inst.pl: use prompt() from ExtUtils::MakeMaker to avoid unexpected error with cpan * avoid the "No LSB modules are available." warning message * Backend: --debug print a warning when arun() function is not found * Fix the Debian/Ubuntu detection for non lsb system * postinst.pl also drops /etc/cron.d/ocsinventory-client if the user wants to drop the old linux_agent * Backend::OS::Solaris::Memory: use the Logger instead of "print" * Solaris: Drop unwanted spaces around OSVERSION and STORAGES/DESCRIPTION * Solaris: Avoid warning if the user can't use fstyp * MANIFEST.SKIP: ignore .git/ and .gitignore * add a workaround for http://rt.cpan.org/Ticket/Display.html?id=38067 * build-perl-tree.sh use cpanp and perl 5.10 now * Backend.pm: do a eval around require File::Find * Add a workaround to find the backend modules for PAR::Packer * Backend.pm: internal change, now do eval 'use $pmodule' instead of require * fix serialnum detection in Lsilogic.pm and Adaptec.pm (Edouard GAMIN) * Makefile.PL: drop wait(), not used * Makefile.PL: fix a syntax error * add tools/makedist.sh to document the workaround used to avoid http://rt.cpan.org/Public/Bug/Display.html?id=43060 * Fix --logfile=/somewhere.log, see http://forums.ocsinventory-ng.org/viewtopic.php?id=3092 * tools/build-perl-tree.sh, add a new script * Don't print ugly error if next_timefile can't be saved * OS::Linux::Domains, improve the way it deals with multiple domaine entries (Remi COLLET) * AIX: Record the last memory Slot (Wilfried BRUNKEN) http://sourceforge.net/tracker/?func=detail&atid=487492&aid=2350694&group_id=58373 * Bump 0.0.10 to 1.0 because it's the first release to be officially part of the OCSInventory distribution 0.0.10beta2 Wed, 24 Sep 2008 23:41:21 +0200 * README: add a not about the $PATH varible on Solaris. * Added extra section support for backends (Pascal DANEK) * Fix the way submodules are disabled with $runMeIfTheseChecksFailed * Linux: Use lsb_release if presents to detect the OS, this will fix the Ubuntu detection * Hide a Perl warning if the agent is run by the user want the last_state file is missing * Add Ipmi backend module (Jean PARPAILLON) * Drop the control characters from the inventory XML https://sourceforge.net/tracker/index.php?func=detail&aid=2100606&group_id=58373&atid=487492 * Apply a little change in standalone.sh that may fix the ParserDetails.ini problem, thanks tharoun 0.0.10beta1 Thu, 04 Sep 2008 18:16:49 +0200 * Fix a "ocs server name" => URI side effect (Pascal DANEK) * Download::Store: used absolute path to "cp" on STORE action (Pascal DANEK) * Download::Store: set -dpR flags to "cp" (Pascal DANEK) * Solaris: Replaced hostid in serialnumber by real serialnumber (Nicolas DORFSMAN) (SUNWsneep becomes mandatory on sparc) * Solaris: Return only one IP address (trying to guess which one corresponds to hostname) (Nicolas DORFSMAN) * Solaris: return disks SERIALNUMBER and FIRMWARE as XML fields (Nicolas DORFSMAN) * Redirection and stderr issue on Solaris (Nicolas DORFSMAN) - Removed close of stderr fd - Modified lspci and screen check() to avoid pollution of stdout/stderr * fix the previous changelog entry, the 0.0.9.1 fix had been done by Nicolas DORFSMAN * postinst.pl checks for MANIFEST present * improve the backend module detection by also scanning the symlinked directory * add the --devlib flag to load ./lib only if wanted and remove '.' from the directory to scan with File::Find. * import the can_run, can_load and can_read functions in the Backend modules * the backend module can have no check function, in this case OCS assume it's ok * apply a patch by Etienne GUILLAUMONT to fix CPU detection on AIX 4 * standalone.sh checks PAR::Packer presence now * only inventory installed .deb * postinst.pl: accept another vardir if the first one was invalide https://sourceforge.net/tracker/?func=detail&atid=487492&aid=1961771&group_id=58373 * postinst.pl Download.pm correctly activated in modules.conf if the user needs it * add MacOSX support thanks to Wes YOUNG (Wes YOUNG) - Added tools/darwin/ support scripts/code for OS X enterprise deployment * add the follow_skip==2 flag to File::Find in Backend.pm so it doesn't detect the same file two time * import of backend module for RAID controller on Linux (3ware, Adaptec, HP and Lsilogic) (Edouard GAMIN) * remove a warning in Debug mod, if a backend module has no run() function * don't crash in Daemon mode if the server is unreachable (Wes YOUNG) * Net::IP is just (strongly) suggested now * fix --basevardir so it really accepts a parameter, thanks Gubluts from the forum who pointed out the bug * postinst.pl use which to find ocsinventory-agent location * Makefile.PL, Perl 5.6 doesn't have Config::config_re, I call it from an eval now * Added --delaytime option as commandline / .cfg file adjustable (Wes YOUNG) * standalone.sh, don't use grep -v since it's not POSIX * doesn't die if Storable.pm is missing like with perl 5.6 * avoid a warning with gzip -h on AIX if Compress::Zlib is missing * README: depends on Perl 5.8 * README: On solaris the Makefile needs gmake * README: Add a note about crontab and PATH * Linux: redirect hdparm error to /dev/null * postinst.pl yes/no questions have a default value now * postinst.pl fix a bug in the import of the old ocsinv.adm https://sourceforge.net/tracker/index.php?func=detail&aid=1991668&group_id=58373&atid=487492 * postinst.pl doesn't create two vardir directories anymore * do not print a wrning is --nosoftware is used. Thanks Knarfling and Remi who pointed the issue out. http://forums.ocsinventory-ng.org/viewtopic.php?pid=12569 * fix the POD documentation, some mistakes were detected by Perl 5.10's perldoc. * the agent doesn't crash anymore if ocsinv.adm or ocsinv.conf is corrupted * Makefile.pl: install memconf on Solaris * Solaris: apply patches to use memconf for CPU, Drives and Memory (Christoph HALMES) 0.0.9.2 04/18/2008 Bug fix * Add /ocsinventory in the server path if the user enter just the hostname https://sourceforge.net/tracker/?func=detail&atid=487492&aid=1945865&group_id=58373 0.0.9.1 04/03/2008 Bug fix * fix a error in the previous release that was forcing the local mode (Nicolas DORFSMAN) https://sourceforge.net/tracker/?func=detail&atid=487492&aid=1945863&group_id=58373 0.0.9 04/01/2008 April Fool release! * Added fallback for --lazy if no prolog freq was found and server error (Pascal DANEK) * Fixed accountinfos handling bugs (Pascal DANEK) * Changed --wait behaviour (--wait=number_of_seconds || "server") (Pascal DANEK) * PROLOG_FREQ is handled in prolog phase (Pascal DANEK) * the random value for file_nexttime is computed only if prolog_freq has changed since last prolog (Pascal DANEK) * import the documentation documentation by adding a description of the agent and pointer to the official website * --nosoft option renamed to --nosoftware, --nosoft still works but with a warning * add --basevardir to be able to use a specific place to store the var file * add the --lazy parameter: send an inventory only if the a random delay between 0 and PROLOG_FREQ had been run over. Useful for package maintainer (Remi COLLET) * return 1 to the shell if the agent failed to contact the server * postinst.pl asks for the basevardir * postinst.pl write the modules.conf * OS::Linux::Network::Networks, correctly reset the ipaddress before every loop so now a network can't have the address of the previous one * rename the key $params->{conffile} to $params->{accountconfig} * fix the way accountinfo information are stored * improve (a bit) tools/standalone.sh to avoid error if people launch it from the tools directory * --server is ignore if --local is in use * adjust Backend::OS::Generic::Screen to be able to use monitor-edid with DVI link (Remi COLLET) * OS::Linux::Storages, add NEC as a know manufacturer add assume the manifacturer is Seagate if the model doesn't match the others and begin with ST (rjhill) * fix the CPU detection on Linux Sparc64 and ARM (Linksys NSLU2) * improve the Solaris version detection by reading the /etc/release file (Nicolas DORFSMAN) * Solaris: fix the MAC addresses when the leading zeros is missing (Jean-Jacques MICHEL) * Solaris: Add publisher is possible in the software list (Nicolas DORFSMAN) * Solaris: improve the hard drive detection (Nicolas DORFSMAN) * postinst.pl can remove the previous linux_agent * postinst.pl reuse linux_agent old config file to set the default server and tag * return the SERIALNUMBER and the FIRMWARE on Linux with hdparm, the feature is not supported yet by the server (egamin) 0.0.8.1 02/20/2008 * postinst.pl, correctly save the realm, do not override the password * Added "CAPTION" field to memory (Pascal DANEK) * Fix a bug with "NUMSLOTS" memory field (Pascal DANEK) * improve the parsing of the config file to accept quote and spaces in the value * postinst.pl save the configfile with 0600 right since the server password maybe be stored in it * standalone.sh doesn't scan the inc/ directory anymore * remove the BUNDLE packages which seem to break the install process * change Solaris::CPU to use psrinfo -v to get the CPUs which works fine on x86 * fix a path error in Ocsinventory::LoggerBackend::File (Remi COLLET) * fix: don't send the inventory if the server doesn't need it (Remi COLLET) 0.0.8 02/05/2008 * fix the deviceid and old_deviceid handling (Pascal DANEK) * fix a debug message in Network.pm (Pascal DANEK) * different fixes on Compress.pm (Pascal DANEK) * fix an event message name in Option/Download.pm (Pascal DANEK) * fix the Compatibility Layer with prolog_read hook (Pascal DANEK) * merge PowerPC and PC code to detect the CPU and improve/fix the regex * looks for config file in /etc/ocsinventory /usr/local/etc/ocsinventory and /etc/ocsinventory-agent * add a pod documentation about the different config files and directories * Compress::Zlib is required but recommended now. In fact, you need it with ocs server prior 1.02 0.0.7.2 01/16/2008 * fix the post installation script to avoid invalid cron time 0.0.7.1 01/14/2008 * add setup.sh in the MANIFEST.SKIP to keep it out of the tarball 0.0.7 01/13/2008 * Ocsinventory::Agent::AccountInfo does not warn accountinfofile if runned in debug mode without root privilege * fix params->{etcdir} to /etc/ocsinventory, /etc/ocsinventory-agent/modules.conf must be moved to /etc/ocsinventory/modules.conf * Solaris: Improve the CPU detection (Olivier ROUSSY) * AIX: Return the directory with the AIX package name (Olivier ROUSSY) * Ocsinventory::Agent::XML::Inventory can now write software inventory value of FILESIZE, FOLDER and PUBLISHER * processChecksum() and feedInventory() are called by Ocsinventory::Agent::XML::Inventory directly now * the server responses are not parsed in the main script anymore * do not create an inventory if the server doesnn't need it * new parameters for the backend modules (run and check functions): - prologresp, the Ocsinventory::Agent::XML::Response::Prolog object returned by the prolog - storage: an hashref stored on the harddrive at the end of the execution of the module * a backend module without a run function is accepted now * Inventory.pm: add addIpDiscoverEntry() to add host from the same network * @runMeIfTheseChecksFailed: new optional setting for Backend module * Ipdiscover is now a backend module and nmap can be used instead of ipdiscover * --nosoft disable the Ocsinventory::Agent::Backend::OS::Generic::Packaging modules * Remove the deprecated modules Ocsinventory::Agent::Option::Ipdiscover and Ocsinventory::Agent::Option::Update * the check function of the backend accepts the same parameter than the run function * Linux::Archs::I386 regex are more robust * perldoc documentation for the ocsinventory-agent command * minor improvment on the Makefile.PL * change the way --server parameter is read. Now we can have a full URL, --remotedir is now useless * fix: correctly load the last_state * improve the Makefile.PL by using inc::Module::Install and adding new check * add a --version parameter and improve the --help * come with bundled dependency to simply the build process * fix the login/passwd/realm authentification * remove Agent/Pid.pm, I've to prepare a better system to keep the pid first * try to read the config in /usr/local/etc/ocsinventory/ocsinventory-agent.cfg if the standard one is missing 0.0.6.2 07/16/2007 Bug fix release * remove a debug "die" in the code 0.0.6.1 06/12/2007 Bug fix release * Fix an undef value in Ocsinventory::Agent::Backend::OS::BSD::Mem * AIX: retrieve correctly the MAC address of some FibberChannel card * now standalone.sh will try to find every module before the build to avoid unexplicated error 0.0.6 06/07/2007 * Enable "verbose" is debug is turned on * AIX: Ocsinventory::Agent::Backend::OS::AIX::Networks rewrote * AIX: Memory.pm, remove the spaces from the end of the DESCRIPTION * add standalone.sh, a script designed to prepare a stand-alone binary of the agent * AIX: Retrieve all the gateway of every subnet instead of just the default one * Config.pm renamed to AccountConfig.pm * New flag: --stdout to print the inventory directly on STDOUT * If the use want write on the system var directory, the agent create one in ~/.ocsinventory/var * The agent setting can be preinitialised with /etc/ocsinventory/ocsinventory-agent.cfg or ~/ocsinventory/ocsinventory-agent.cfg. * remove two debug messages printed during accountinfo rewrite and the daemon starting process * remove a stupid check in Ocsinventory::Agent::AccountConfig, the accountconfig file was not written unless the file was already present * add a recMkdir function in ocsinventory-agent to create directory recursivly * do not process checksum in local mode 0.0.5 04/17/2007 * AIX: use lslpp -c -l to find installed packages * AIX: fixes on CPU.pm, Networks.pm and Memory.pm * AIX: fetch the serial number with lscfg unless it was found with lsvpd * add the .ocs extension to local written files * with --local flag: don't not warn if last_state doesn't exit * Solaris: retrieve installed package * downgrade some message important from info to debug * read screen serial number in the EDID (DDC screen) * Xorg.pm replaced by Screen.pm * Screen.pm all the data are read from EDID now * Initial Linux PPC support (tested in Debian Etch). thanks Walid Nouh for the hardware * Apply patch by Remi Collet to fix an issue with Linux distro detection and Perl 5.6.1 * Turn of STDERR during the module execution to avoid useless message (e.g: foo: not found) use --debug to turn them back * If the system side vardir can't be created. The agent try to create one in ~/.ocs-inventory-agent * Add a THANKS file 0.0.4 03/20/2007 * use of gzip when Compress:Zlib is not avalaible. OCS server 1.01 and prior are not supported. * dmidecode parsing improved * lspci stuffs moved to generic * Linux: find Wifi connection * fix: pass correctly the logger to the modules * don't write the last_state if the connexion failed * Deals correctly with the accountinfo if it's internaly stored in a array ref * BSD support by Thierry Lacoste UnixAgent-2.8/LICENSE000066400000000000000000000431031372663377700143200ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. UnixAgent-2.8/MANIFEST.SKIP000077500000000000000000000004121372663377700152100ustar00rootroot00000000000000CVS/ .git .bzr ^00 ^.gitignore$ ^.cvsignore$ .svn .merge ^blib ^_build ^Build$ ^cover_db ^nytprof ^Makefile(\.old)?$ ^MANIFEST\. ^MYMETA\. ^pm_to_blib$ ^run-postinst ~$ \.bak$ \.old$ \.sw[a-z]$ \.# \.swp ^Ocsinventory-agent.* /tarballs/ ^setup.sh .*\.tmp var/ UnixAgent-2.8/META.yml000077500000000000000000000016431372663377700145720ustar00rootroot00000000000000--- abstract: 'Ocs-Inventory unified Agent for UNIX, Linux and MacOSX' author: - 'OCS Inventory Team' build_requires: ExtUtils::MakeMaker: 6.59 configure_requires: ExtUtils::MakeMaker: 6.59 distribution_type: module dynamic_config: 1 generated_by: 'Module::Install version 1.19' license: gpl meta-spec: url: http://module-build.sourceforge.net/META-spec-v1.4.html version: 1.4 name: Ocsinventory-Unix-Agent no_index: directory: - inc recommends: Compress::Zlib: 0 Net::IP: 0 Nvidia::ml: 0 Proc::Daemon: 0 Proc::PID::File: 0 requires: Digest::MD5: 0 File::Temp: 0 LWP: 0 XML::Simple: 0 perl: 5.6.0 resources: homepage: http://www.ocsinventory-ng.org bugtracker: https://github.com/OCSInventory-NG/UnixAgent/issues repository: https://github.com/OCSInventory-NG/UnixAgent irc: irc://irc.freenode.net/#ocsinventory-ng license: http://opensource.org/licenses/gpl-license.php version: 2.4.2 UnixAgent-2.8/Makefile.PL000077500000000000000000000112111372663377700152630ustar00rootroot00000000000000BEGIN { # Avoid installation issue introduced by perl 5.24.1 removing '.' path from # @INC to avoid possible module injection in normal running perl scripts push @INC, '.' if ( $^V && $^V gt 'v5.24' ); } use inc::Module::Install; use English qw(-no_match_vars); use Config; require 'lib/Ocsinventory/Agent/Config.pm'; # Hack to be able to run a post install script sub MY::postamble { my $re; $re = ' install :: all pure_install doc_install $(NOECHO) $(NOOP)'; $re .= "\n\t[ ! -f run-postinst ] || $^X postinst.pl\n"; return $re; } my $version = $Ocsinventory::Agent::Config::VERSION; name 'Ocsinventory-Unix-Agent'; include 'Module::AutoInstall'; abstract 'OCS Inventory unified Agent for UNIX, Linux and MacOSX'; license 'gpl'; repository 'https://github.com/OCSInventory-NG/UnixAgent/'; version $version; perl_version '5.006'; authors 'OCS Inventory Team'; # mandatory dependencies requires 'Digest::MD5' => undef; requires 'XML::Simple' => undef; requires 'LWP' => '5.8'; requires 'File::Temp' => undef; requires 'Net::IP' => undef; recommends 'IO::Socket::SSL' => undef; recommends 'Compress::Zlib' => undef; recommends 'Proc::Daemon' => undef; recommends 'Proc::PID::File' => undef; # test dependencies test_requires 'IO::Socket::SSL' => '0'; test_requires 'Net::SNMP' => '0'; test_requires 'LWP::Protocol::https' => '0'; # deployement or https communication recommends 'Crypt::SSLeay' => undef; recommends 'LWP::Protocol::https' => undef; # inventory recommends 'Net::CUPS' => undef; recommends 'Parse::EDID' => undef; # network recommends 'Net::SNMP' => undef; recommends 'Net::Netmask' => undef; recommends 'Net::Ping' => undef; recommends 'Nmap::Parser' => undef; resources bugtracker => 'https://github.com/OCSinventory-NG/Unixagent/issues', homepage => 'http://www.ocsinventory-ng.org', IRC => 'irc://irc.freenode.net/#ocsinventory-ng', repository => 'https://github.com/OCSinventory-NG/Unixagent'; install_script 'ocsinventory-agent'; # We want a release bundled with the needed dependency to be able to # prepare a standalone binary with PAR::Packer if ($ENV{OCS_BUNDLE_RELEASE}) { foreach my $module (qw/Archive::Zip HTML::Parser LWP URI XML::NamespaceSupport Net::IP Net::Netmask HTML::Tagset Proc::Daemon Module::ScanDeps PAR::Packer AutoLoader PAR PAR::Dist File::Remove YAML::Tiny Getopt::ArgvFile ExtUtils::Install ExtUtils::ParseXS XML::SAX XML::Simple/) { bundle $module; requires $module; } } #Ugly hack to include ipdiscover binary compilation and install for Linux systems if ($^O =~ /^linux$/i && can_cc()) { my $cc=$Config::Config{cc}; system("$cc resources/ipdiscover/ipdiscover.c -o ipdiscover"); if (-f 'ipdiscover') { install_script 'ipdiscover'; } } if (defined ($ENV{PERL_AUTOINSTALL}) || defined ($ENV{PERL_AUTOINSTALL})) { unlink 'run-postinst'; } else { open POSTINST, '>run-postinst' or die $!; close POSTINST; } if (!can_use('Compress::Zlib')) { print "Please install Compress::Zlib if you use an OCS server prior 1.02.\n"; } if (!can_use('Net::SSLeay')) { print "Please install Net::SSLeay if you want to use the software deployment.\n"; } if (!can_run('ipdiscover') && !can_run('nmap')) { print "Please install nmap "; print "or ipdiscover " if $^O =~ /^linux$/i; print "if you want to use the network ". "discover feature.\n"; } if (!can_use('Net::IP')) { print "Net::IP is strongly recommended since it's required to retrieve " ."network information\n"; } if (!can_use('Net::Netmask')) { print "Net::Netmask is strongly recommended since it's required to retrieve " ."snmp information\n"; } if (!can_use('Proc::Daemon') || !can_use('Proc::PID::File')) { print "Please install Proc::Daemon and Proc::PID::File if you ". "want to use the daemon mode.\n"; } my $archname; eval { # config_re is not available on Perl 5.6 my @t = Config::config_re('archname'); $archname = $t[0]; }; if ($^O =~ /(linux|bsd)/i && (!$archname ||$archname =~ /(i[3456x]86|x86_64|amd64)/i)) { foreach (qw/dmidecode lspci/) { if (!can_run($_)) { print "\n"; print "[WARNING] $_ is needed if you want a complete inventory on x86 and AMD64/x86_64.\n"; print "\n"; } } } if ($^O =~ /^darwin$/ && !can_use('Mac::SysProfile')) { print "\n"; print "[WARNING] Mac::SysProfile are needed on MacOS to detect most of the device information.\n"; print "\n"; requires 'Mac::SysProfile' => undef; } # memconf is needed by Solaris backend module if ($^O =~ /^solaris$/i) { install_script 'memconf'; } #for i in inc/BUNDLES/* ; do rm -rf `basename $i` ;done` #auto_install; WriteAll; UnixAgent-2.8/README.md000066400000000000000000000130601372663377700145710ustar00rootroot00000000000000

Banner

OCS Inventory UnixAgent

Some Links:
Ask question | Installation | Website | OCS Professional

Ocsinventory-Agent is an agent for ocsinventory NG. It supports Linux, Solaris and AIX. *BSD support is in progress.

Prerequisites

- Perl 5.8 minimum #### The following modules are needed: - Digest::MD5 - XML::Simple - Net::IP optional, it is only needed to compute the network information - LWP - Mac::SysProfile 0.0.5 : this module is need on MacOSX to collect the device informations. - To get SSL communications working (for packages deployment or HTTPS communications to OCS server), you need these modules: - Crypt::SSLeay if you use LWP prior to version 6 - LWP::Protocol::https if you use LWP version 6 or more - Net::CUPS is used to detect the printer - Net::SNMP to scan network devices using SNMP - To enhance SNMP feature with custom networks scans, you need these modules: - Net::Netmask - Net::Ping or Nmap::Parser - Data::UUID is used to create a unique id for every machine - Parse::EDID is used to inventory monitor and will replace monitor-edid from Mandriva. #### The following commands are needed: - dmidecode on Linux and *BSD (i386, amd64, ia64) => dmidecode is required to read the BIOS stats. - lspci on Linux and *BSD (pciutils package) => lspci is required to list PCI devices. - sneep on Solaris/sparc, you must install sneep and record the Serial Number with it (download it from http://www.sun.com/download/products.xml?id=4304155a) - To get the serial number of the screen you will need one of these tools: - monitor-edid from Mandriva is needed to fetch the monitor. A package is available in Fedora repository. information http://wiki.mandriva.com/en/Tools/monitor-edid - get-edid from the read-edid package - ipmitool if you want to collect information about IPMI - Nmap (v3.90 or superior) to scan network devices for Ipdiscover #### The following PERL modules are optional: - Proc::Daemon Daemon mode - Proc::PID::File brings the pid file support if Proc::Daemon is installed - Compress::Zlib #### The following module is needed if you plan to prepare a tarball or install directly from the Bazaar devel branch. (See SOURCES below.): - Module::Install

Build / Install

Once the archive is unpacked, use these commands: ``` perl Makefile.PL make make install ``` If you want to turn off the interactive post install script, just do (instead of perl Makefile.PL) ``` PERL_AUTOINSTALL=1 perl Makefile.PL ``` You can also run the agent from the tarball directory. In this case, use the `--devlib` flag to load the library from the local directory. You need to launch the agent with root privilege. For debugging you can try to launch it with the `-l` flag: Ex: `ocsinventory-agent -l /tmp --debug` It's also possible to run directly from the tarball directory: `sudo ./ocsinventory-agent --devlib --server http://foo/ocsinventory`

Note

Solaris: - Sun Studio seems to be needed to build the dependency. - The generated Makefile needs gmake to be exectuted - The default installation will install the binary in /usr/perl5/5.XXXXX/bin, set your $PATH variable according to that. Crontab: - If you use crontab to launch the agent you'll probably have to redefine the PATH. For example, just add something like: `PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin` At the beginning of the cron file.
## Contributing 1. Fork it! 2. Create your feature branch: `git checkout -b my-new-feature` 3. Add your changes: `git add folder/file1.php` 4. Commit your changes: `git commit -m 'Add some feature'` 5. Push to the branch: `git push origin my-new-feature` 6. Submit a pull request ! ## License OCS Inventory is GPLv2 licensed The memconf script is maintained by Tom Schmidt http://www.4schmidts.com/memconf.html Copyright © 1996-2017 Tom Schmidt memconf is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. Ocsinventory::Agent::Backend::Virtualization::Vmsystem uses code from imvirt: Authors: Thomas Liske Copyright Holder: 2008 (C) IBH IT-Service GmbH [http://www.ibh.de/] License: This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. Ocsinventory::Agent::Backend::OS::Linux::Storages::Adaptec uses code from Parse-Arcconf: https://github.com/kumy/Parse-Arcconf License and Copyright: Copyright (C) 2012 Mathieu Alorent This program is free software; you can redistribute it and/or modify it under the terms of either: the GNU General Public License as published by the Free Software Foundation; or the Artistic License. See http://dev.perl.org/licenses/ for more information. UnixAgent-2.8/THANKS000066400000000000000000000044331372663377700142310ustar00rootroot00000000000000Olivier ANDREOTTI: AIX, Solaris patches Thierry LACOSTE: BSD portage Didier LIROULET: Installation script Remi COLLET: bug fixes and Fedora/RedHat maintainer Walid NOUH: gave access to PowerPC hardware to help the portage Olivier ROUSSY: minor patches Dennis CABOOTER: FreeBSD maintainer Pierre CHIFFLIER: Debian maintainer Nicolas DORFSMAN: Solaris patches Jean-Jacques MICHEL: Solaris patches Etienne GUILLAUMONT: AIX4 CPU detection Wes YOUNG: MacOSX support and patches Edouard GAMIN: RAID devices support for Linux Christoph HALMES: Solaris patches Jean PARPAILLON: IPMI backends and patches David DURIEUX: AMD64 detection on BSD systems Wilfried BRUNKEN: patch for memory detection on AIX Vladimir ELISSEEV: various patches Julien SAFAR: ArchLinux support Damien MAURAN: MacOSX packaging, doc and support Sebastien DAGNICOURT: AIX and Solaris patches Nicolas EISEN: patches Sylvain LUCE: Sun M5000 and M4000 support Philippe LIBAT: patchs and Xen support David OLIVIER: MacOSX patches Jean-François BOUCHER: Solaris patch Scott HANNAHS: MacOSX patches Maurizio Bertaboni: Solaris Zone support Scott HANNAHS: patch Sergio MERINO: patch Vincent KNECHT: wording patch Barius DRUBECK: documentation patch Stéphane URBANOVSKI: patch Jerome LEBASE: Solaris patches François MERMET: HP-UX support and SNMP integration Dmitry ILYIN: Patches Guillaume ROUSSE: various patches for Xen support Lucas MASSE: various patches for Solaris support Adam BUCHBINDER: various patches Bernhard Denner: various patches Yoann Le Bihan: Solaris patches Andreas Xenos: MacOSX patches and Parallels support Francois Laupetre: LVM modules Christophe Borivant Viper233: patch monitor edid Alexandre Bossot: oracle module Javier Barroso: VLAN interface on AIX Yves GUIMARD: download.pm patch for zip files Marco Tizzoni: Host_Resources_Mib.pm and Agent.pm patches Matthias Vedrines: patch + various modules Trois Six: patch DerJoern: patch Serge Roux: patch Guillaume Lecerf: Xen support Mikkel Paulson: patch XANI: patch Philippe Beaumont: patch lhchin: patch pilch-cit: patch lj6: patch nerijus: patch GSponda: patch JHeidinga: patch Unrankar: patch jfcoz: patch xalasys-luc: patch stweil: patch ivmaks: patches MikaelUranker: patches nnn-dev: patches jmechnich: patches matt335672: patches temperatur: patch RudyLaurent: patches guimard: patches UnixAgent-2.8/contrib/000077500000000000000000000000001372663377700147525ustar00rootroot00000000000000UnixAgent-2.8/contrib/Tarballs.pm000066400000000000000000000027461372663377700170650ustar00rootroot00000000000000# Write by Simon CLARA 2010-01-25 # # The complete name of the package # the path MUST be valid or the package won't be loaded package Ocsinventory::Agent::Backend::OS::Generic::Tarballs; use strict; # I need to declare $runAfter because of the strict mode use vars qw($runAfter); # The package must be run after OS::Generic $runAfter = ["Ocsinventory::Agent::Backend::OS::Generic"]; # This is the check function. The agent runs it just once the module is loaded. # If the function return false, the module and its children are not executed # eg: OS::Linux and OS::Linux::* won't executed if this run() function return # false # Check if we are on a linux server sub check { $^O =~ /^linux$/ } # uncomment this if you want check for FreeBSD server # sub check {can_run("pkg_info")} # its the main function of the script, it's called during the hardware inventory sub run { my $params = shift; # I need to get the inventory object to update it my $inventory = $params->{inventory}; # our software are in /usr/local/src/ foreach (`ls /usr/local/src/*.{bz2,tar.gz}`){ /^(\/.*\/)(\S+)-(\d+\S*)(\.tar.gz|\.bz2)$/i; my $name = $2; my $version = $3; my $comments = "Software in /usr/local/src/ \n".`$2 --version`; # and I updated the information collected $inventory->addSoftwares({ COMMENTS => $comments, NAME => $name, VERSION => $version }); } } 1; UnixAgent-2.8/cpanfile000066400000000000000000000007511372663377700150210ustar00rootroot00000000000000requires 'XML::Simple', '>= 2.12'; requires 'Compress::Zlib', '>= 1.33'; requires 'Net::IP', '>= 1.20'; requires 'Switch', '>= 2.0'; requires 'Proc::Daemon', '>= 0.20'; requires 'Proc::PID::File', '>= 1.20'; requires 'Net::SNMP', '>= 6.0'; requires 'Net::Netmask', '>= 1.9'; requires 'LWP::Protocol::https', '>= 6.0'; requires 'Parse::EDID', '>= 1.0'; requires 'Data::UUID', '>= 1.2'; requires 'LWP::UserAgent', '>= 6.4';UnixAgent-2.8/etc/000077500000000000000000000000001372663377700140655ustar00rootroot00000000000000UnixAgent-2.8/etc/cron.d/000077500000000000000000000000001372663377700152505ustar00rootroot00000000000000UnixAgent-2.8/etc/cron.d/ocsinventory-agent000066400000000000000000000012521372663377700210310ustar00rootroot00000000000000# # File generated by OCS Inventory NG Unified Unix Agent setup # ################################################################################ # # OCS Inventory NG Unified Unix Agent # # Copyleft 2007 Didier LIROULET # Web: http://www.ocsinventory-ng.org # # This code is open source and may be copied and modified as long as the source # code is always made freely available. # Please refer to the General Public Licence http://www.gnu.org/ or Licence.txt ################################################################################ # # Launch OCS Inventory NG Agent once a day under root account, at HH:MM # MM HH * * * root /usr/bin/ocsinventory-agent > /dev/null 2>&1 UnixAgent-2.8/etc/default/000077500000000000000000000000001372663377700155115ustar00rootroot00000000000000UnixAgent-2.8/etc/default/ocsinventory-agent000066400000000000000000000000231372663377700212650ustar00rootroot00000000000000SERVER="localhost" UnixAgent-2.8/etc/init.d/000077500000000000000000000000001372663377700152525ustar00rootroot00000000000000UnixAgent-2.8/etc/init.d/ocsinventory-agent000077500000000000000000000104011372663377700210320ustar00rootroot00000000000000#! /bin/sh ### BEGIN INIT INFO # Provides: ocs-inventory-agent # Required-Start: $local_fs $remote_fs # Required-Stop: $local_fs $remote_fs # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Short-Description: OCS-Inventory Agent # Description: This script launches OCS Agent as daemon ### END INIT INFO # Author: Gonéri Le Bouder # # Do NOT "set -e" # PATH should only include /usr/* if it runs after the mountnfs.sh script PATH=/sbin:/usr/sbin:/bin:/usr/bin DESC="OCS Inventory Agent" NAME=ocsinventory-agent DAEMON=/usr/sbin/$NAME PIDFILE=/var/run/$NAME.pid SCRIPTNAME=/etc/init.d/$NAME # Exit if the package is not installed [ -x "$DAEMON" ] || exit 0 # Read configuration variable file if it is present [ -r /etc/default/$NAME ] && . /etc/default/$NAME DAEMON_ARGS="-d -s $SERVER" # Load the VERBOSE setting and other rcS variables . /lib/init/vars.sh # Define LSB log_* functions. # Depend on lsb-base (>= 3.0-6) to ensure that this file is present. . /lib/lsb/init-functions # # Function that starts the daemon/service # do_start() { # Return # 0 if daemon has been started # 1 if daemon was already running # 2 if daemon could not be started start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON --test > /dev/null \ || return 1 start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON -- \ $DAEMON_ARGS \ || return 2 # Add code here, if necessary, that waits for the process to be ready # to handle requests from services started subsequently which depend # on this one. As a last resort, sleep for some time. } # # Function that stops the daemon/service # do_stop() { # Return # 0 if daemon has been stopped # 1 if daemon was already stopped # 2 if daemon could not be stopped # other if a failure occurred start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --pidfile $PIDFILE --name $NAME RETVAL="$?" [ "$RETVAL" = 2 ] && return 2 # Wait for children to finish too if this is a daemon that forks # and if the daemon is only ever run from this initscript. # If the above conditions are not satisfied then add some other code # that waits for the process to drop all resources that could be # needed by services started subsequently. A last resort is to # sleep for some time. start-stop-daemon --stop --quiet --oknodo --retry=0/30/KILL/5 --exec $DAEMON [ "$?" = 2 ] && return 2 # Many daemons don't delete their pidfiles when they exit. rm -f $PIDFILE return "$RETVAL" } # # Function that sends a SIGHUP to the daemon/service # do_reload() { # # If the daemon can reload its configuration without # restarting (for example, when it is sent a SIGHUP), # then implement that here. # start-stop-daemon --stop --signal 1 --quiet --pidfile $PIDFILE --name $NAME return 0 } case "$1" in start) [ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME" do_start case "$?" in 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;; 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;; esac ;; stop) [ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME" do_stop case "$?" in 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;; 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;; esac ;; #reload|force-reload) # # If do_reload() is not implemented then leave this commented out # and leave 'force-reload' as an alias for 'restart'. # #log_daemon_msg "Reloading $DESC" "$NAME" #do_reload #log_end_msg $? #;; restart|force-reload) # # If the "reload" option is implemented then remove the # 'force-reload' alias # log_daemon_msg "Restarting $DESC" "$NAME" do_stop case "$?" in 0|1) do_start case "$?" in 0) log_end_msg 0 ;; 1) log_end_msg 1 ;; # Old process is still running *) log_end_msg 1 ;; # Failed to start esac ;; *) # Failed to stop log_end_msg 1 ;; esac ;; *) #echo "Usage: $SCRIPTNAME {start|stop|restart|reload|force-reload}" >&2 echo "Usage: $SCRIPTNAME {start|stop|restart|force-reload}" >&2 exit 3 ;; esac : UnixAgent-2.8/etc/logrotate.d/000077500000000000000000000000001372663377700163075ustar00rootroot00000000000000UnixAgent-2.8/etc/logrotate.d/ocsinventory-agent000066400000000000000000000013541372663377700220730ustar00rootroot00000000000000# # File generated by OCS Inventory NG Unified Unix Agent setup # ################################################################################ # # OCS Inventory NG Unified Unix Agent # # Copyleft 2007 Didier LIROULET # Web: http://www.ocsinventory-ng.org # # This code is open source and may be copied and modified as long as the source # code is always made freely available. # Please refer to the General Public Licence http://www.gnu.org/ or Licence.txt ################################################################################ # # Rotate OCS Inventory NG agent logs daily, only if not empty # Save 7 days old logs under compressed mode PATH_TO_LOG_DIRECTORY/*.log { daily rotate 7 compress notifempty missingok } UnixAgent-2.8/etc/ocsinventory-agent/000077500000000000000000000000001372663377700177235ustar00rootroot00000000000000UnixAgent-2.8/etc/ocsinventory-agent/modules.conf000066400000000000000000000005101372663377700222360ustar00rootroot00000000000000# This list of modules will be loaded by the agent at run time. # To check its syntax do: # $perl modules.conf # You must have NO error, else the content will be ignored. use Ocsinventory::Agent::Modules::Download; #use Ocsinventory::Agent::Modules::Snmp; use Ocsinventory::Agent::Modules::SnmpScan; # DO NOT REMOVE the 1; 1; UnixAgent-2.8/etc/ocsinventory-agent/softwares/000077500000000000000000000000001372663377700217405ustar00rootroot00000000000000UnixAgent-2.8/etc/ocsinventory-agent/softwares/example.sh000077500000000000000000000007101372663377700237300ustar00rootroot00000000000000#! /bin/bash # This is an example script for the byHand software collect method # # You can create your own script to detect the installed software # and install them in /etc/ocsinventory/softwares # #ligne=$(ls --version| head -n 1) # #soft=$(echo $ligne | cut -f1 -d'('| sed 's/ //') #vendor=$(echo $ligne | cut -f2 -d'('| cut -f1 -d')') #version=$(echo $ligne | cut -f2 -d'('| cut -f2 -d')'|sed 's/ //') # #echo "$vendor#$soft#$version#simple test" # # UnixAgent-2.8/inc/000077500000000000000000000000001372663377700140635ustar00rootroot00000000000000UnixAgent-2.8/inc/Module/000077500000000000000000000000001372663377700153105ustar00rootroot00000000000000UnixAgent-2.8/inc/Module/AutoInstall.pm000066400000000000000000000630161372663377700201130ustar00rootroot00000000000000#line 1 package Module::AutoInstall; use strict; use Cwd (); use File::Spec (); use ExtUtils::MakeMaker (); use vars qw{$VERSION}; BEGIN { $VERSION = '1.14'; } # special map on pre-defined feature sets my %FeatureMap = ( '' => 'Core Features', # XXX: deprecated '-core' => 'Core Features', ); # various lexical flags my ( @Missing, @Existing, %DisabledTests, $UnderCPAN, $InstallDepsTarget, $HasCPANPLUS ); my ( $Config, $CheckOnly, $SkipInstall, $AcceptDefault, $TestOnly, $AllDeps, $UpgradeDeps ); my ( $PostambleActions, $PostambleActionsNoTest, $PostambleActionsUpgradeDeps, $PostambleActionsUpgradeDepsNoTest, $PostambleActionsListDeps, $PostambleActionsListAllDeps, $PostambleUsed, $NoTest); # See if it's a testing or non-interactive session _accept_default( $ENV{AUTOMATED_TESTING} or ! -t STDIN ); _init(); sub _accept_default { $AcceptDefault = shift; } sub _installdeps_target { $InstallDepsTarget = shift; } sub missing_modules { return @Missing; } sub do_install { __PACKAGE__->install( [ $Config ? ( UNIVERSAL::isa( $Config, 'HASH' ) ? %{$Config} : @{$Config} ) : () ], @Missing, ); } # initialize various flags, and/or perform install sub _init { foreach my $arg ( @ARGV, split( /[\s\t]+/, $ENV{PERL_AUTOINSTALL} || $ENV{PERL_EXTUTILS_AUTOINSTALL} || '' ) ) { if ( $arg =~ /^--config=(.*)$/ ) { $Config = [ split( ',', $1 ) ]; } elsif ( $arg =~ /^--installdeps=(.*)$/ ) { __PACKAGE__->install( $Config, @Missing = split( /,/, $1 ) ); exit 0; } elsif ( $arg =~ /^--upgradedeps=(.*)$/ ) { $UpgradeDeps = 1; __PACKAGE__->install( $Config, @Missing = split( /,/, $1 ) ); exit 0; } elsif ( $arg =~ /^--default(?:deps)?$/ ) { $AcceptDefault = 1; } elsif ( $arg =~ /^--check(?:deps)?$/ ) { $CheckOnly = 1; } elsif ( $arg =~ /^--skip(?:deps)?$/ ) { $SkipInstall = 1; } elsif ( $arg =~ /^--test(?:only)?$/ ) { $TestOnly = 1; } elsif ( $arg =~ /^--all(?:deps)?$/ ) { $AllDeps = 1; } } } # overrides MakeMaker's prompt() to automatically accept the default choice sub _prompt { goto &ExtUtils::MakeMaker::prompt unless $AcceptDefault; my ( $prompt, $default ) = @_; my $y = ( $default =~ /^[Yy]/ ); print $prompt, ' [', ( $y ? 'Y' : 'y' ), '/', ( $y ? 'n' : 'N' ), '] '; print "$default\n"; return $default; } # the workhorse sub import { my $class = shift; my @args = @_ or return; my $core_all; print "*** $class version " . $class->VERSION . "\n"; print "*** Checking for Perl dependencies...\n"; my $cwd = Cwd::getcwd(); $Config = []; my $maxlen = length( ( sort { length($b) <=> length($a) } grep { /^[^\-]/ } map { ref($_) ? ( ( ref($_) eq 'HASH' ) ? keys(%$_) : @{$_} ) : '' } map { +{@args}->{$_} } grep { /^[^\-]/ or /^-core$/i } keys %{ +{@args} } )[0] ); # We want to know if we're under CPAN early to avoid prompting, but # if we aren't going to try and install anything anyway then skip the # check entirely since we don't want to have to load (and configure) # an old CPAN just for a cosmetic message $UnderCPAN = _check_lock(1) unless $SkipInstall || $InstallDepsTarget; while ( my ( $feature, $modules ) = splice( @args, 0, 2 ) ) { my ( @required, @tests, @skiptests ); my $default = 1; my $conflict = 0; if ( $feature =~ m/^-(\w+)$/ ) { my $option = lc($1); # check for a newer version of myself _update_to( $modules, @_ ) and return if $option eq 'version'; # sets CPAN configuration options $Config = $modules if $option eq 'config'; # promote every features to core status $core_all = ( $modules =~ /^all$/i ) and next if $option eq 'core'; next unless $option eq 'core'; } print "[" . ( $FeatureMap{ lc($feature) } || $feature ) . "]\n"; $modules = [ %{$modules} ] if UNIVERSAL::isa( $modules, 'HASH' ); unshift @$modules, -default => &{ shift(@$modules) } if ( ref( $modules->[0] ) eq 'CODE' ); # XXX: bugward compatibility while ( my ( $mod, $arg ) = splice( @$modules, 0, 2 ) ) { if ( $mod =~ m/^-(\w+)$/ ) { my $option = lc($1); $default = $arg if ( $option eq 'default' ); $conflict = $arg if ( $option eq 'conflict' ); @tests = @{$arg} if ( $option eq 'tests' ); @skiptests = @{$arg} if ( $option eq 'skiptests' ); next; } printf( "- %-${maxlen}s ...", $mod ); if ( $arg and $arg =~ /^\D/ ) { unshift @$modules, $arg; $arg = 0; } # XXX: check for conflicts and uninstalls(!) them. my $cur = _version_of($mod); if (_version_cmp ($cur, $arg) >= 0) { print "loaded. ($cur" . ( $arg ? " >= $arg" : '' ) . ")\n"; push @Existing, $mod => $arg; $DisabledTests{$_} = 1 for map { glob($_) } @skiptests; } else { if (not defined $cur) # indeed missing { print "missing." . ( $arg ? " (would need $arg)" : '' ) . "\n"; } else { # no need to check $arg as _version_cmp ($cur, undef) would satisfy >= above print "too old. ($cur < $arg)\n"; } push @required, $mod => $arg; } } next unless @required; my $mandatory = ( $feature eq '-core' or $core_all ); if ( !$SkipInstall and ( $CheckOnly or ($mandatory and $UnderCPAN) or $AllDeps or $InstallDepsTarget or _prompt( qq{==> Auto-install the } . ( @required / 2 ) . ( $mandatory ? ' mandatory' : ' optional' ) . qq{ module(s) from CPAN?}, $default ? 'y' : 'n', ) =~ /^[Yy]/ ) ) { push( @Missing, @required ); $DisabledTests{$_} = 1 for map { glob($_) } @skiptests; } elsif ( !$SkipInstall and $default and $mandatory and _prompt( qq{==> The module(s) are mandatory! Really skip?}, 'n', ) =~ /^[Nn]/ ) { push( @Missing, @required ); $DisabledTests{$_} = 1 for map { glob($_) } @skiptests; } else { $DisabledTests{$_} = 1 for map { glob($_) } @tests; } } if ( @Missing and not( $CheckOnly or $UnderCPAN) ) { require Config; my $make = $Config::Config{make}; if ($InstallDepsTarget) { print "*** To install dependencies type '$make installdeps' or '$make installdeps_notest'.\n"; } else { print "*** Dependencies will be installed the next time you type '$make'.\n"; } # make an educated guess of whether we'll need root permission. print " (You may need to do that as the 'root' user.)\n" if eval '$>'; } print "*** $class configuration finished.\n"; chdir $cwd; # import to main:: no strict 'refs'; *{'main::WriteMakefile'} = \&Write if caller(0) eq 'main'; return (@Existing, @Missing); } sub _running_under { my $thing = shift; print <<"END_MESSAGE"; *** Since we're running under ${thing}, I'll just let it take care of the dependency's installation later. END_MESSAGE return 1; } # Check to see if we are currently running under CPAN.pm and/or CPANPLUS; # if we are, then we simply let it taking care of our dependencies sub _check_lock { return unless @Missing or @_; if ($ENV{PERL5_CPANM_IS_RUNNING}) { return _running_under('cpanminus'); } my $cpan_env = $ENV{PERL5_CPAN_IS_RUNNING}; if ($ENV{PERL5_CPANPLUS_IS_RUNNING}) { return _running_under($cpan_env ? 'CPAN' : 'CPANPLUS'); } require CPAN; if ($CPAN::VERSION > '1.89') { if ($cpan_env) { return _running_under('CPAN'); } return; # CPAN.pm new enough, don't need to check further } # last ditch attempt, this -will- configure CPAN, very sorry _load_cpan(1); # force initialize even though it's already loaded # Find the CPAN lock-file my $lock = MM->catfile( $CPAN::Config->{cpan_home}, ".lock" ); return unless -f $lock; # Check the lock local *LOCK; return unless open(LOCK, $lock); if ( ( $^O eq 'MSWin32' ? _under_cpan() : == getppid() ) and ( $CPAN::Config->{prerequisites_policy} || '' ) ne 'ignore' ) { print <<'END_MESSAGE'; *** Since we're running under CPAN, I'll just let it take care of the dependency's installation later. END_MESSAGE return 1; } close LOCK; return; } sub install { my $class = shift; my $i; # used below to strip leading '-' from config keys my @config = ( map { s/^-// if ++$i; $_ } @{ +shift } ); my ( @modules, @installed, @modules_to_upgrade ); while (my ($pkg, $ver) = splice(@_, 0, 2)) { # grep out those already installed if (_version_cmp(_version_of($pkg), $ver) >= 0) { push @installed, $pkg; if ($UpgradeDeps) { push @modules_to_upgrade, $pkg, $ver; } } else { push @modules, $pkg, $ver; } } if ($UpgradeDeps) { push @modules, @modules_to_upgrade; @installed = (); @modules_to_upgrade = (); } return @installed unless @modules; # nothing to do return @installed if _check_lock(); # defer to the CPAN shell print "*** Installing dependencies...\n"; return unless _connected_to('cpan.org'); my %args = @config; my %failed; local *FAILED; if ( $args{do_once} and open( FAILED, '.#autoinstall.failed' ) ) { while () { chomp; $failed{$_}++ } close FAILED; my @newmod; while ( my ( $k, $v ) = splice( @modules, 0, 2 ) ) { push @newmod, ( $k => $v ) unless $failed{$k}; } @modules = @newmod; } if ( _has_cpanplus() and not $ENV{PERL_AUTOINSTALL_PREFER_CPAN} ) { _install_cpanplus( \@modules, \@config ); } else { _install_cpan( \@modules, \@config ); } print "*** $class installation finished.\n"; # see if we have successfully installed them while ( my ( $pkg, $ver ) = splice( @modules, 0, 2 ) ) { if ( _version_cmp( _version_of($pkg), $ver ) >= 0 ) { push @installed, $pkg; } elsif ( $args{do_once} and open( FAILED, '>> .#autoinstall.failed' ) ) { print FAILED "$pkg\n"; } } close FAILED if $args{do_once}; return @installed; } sub _install_cpanplus { my @modules = @{ +shift }; my @config = _cpanplus_config( @{ +shift } ); my $installed = 0; require CPANPLUS::Backend; my $cp = CPANPLUS::Backend->new; my $conf = $cp->configure_object; return unless $conf->can('conf') # 0.05x+ with "sudo" support or _can_write($conf->_get_build('base')); # 0.04x # if we're root, set UNINST=1 to avoid trouble unless user asked for it. my $makeflags = $conf->get_conf('makeflags') || ''; if ( UNIVERSAL::isa( $makeflags, 'HASH' ) ) { # 0.03+ uses a hashref here $makeflags->{UNINST} = 1 unless exists $makeflags->{UNINST}; } else { # 0.02 and below uses a scalar $makeflags = join( ' ', split( ' ', $makeflags ), 'UNINST=1' ) if ( $makeflags !~ /\bUNINST\b/ and eval qq{ $> eq '0' } ); } $conf->set_conf( makeflags => $makeflags ); $conf->set_conf( prereqs => 1 ); while ( my ( $key, $val ) = splice( @config, 0, 2 ) ) { $conf->set_conf( $key, $val ); } my $modtree = $cp->module_tree; while ( my ( $pkg, $ver ) = splice( @modules, 0, 2 ) ) { print "*** Installing $pkg...\n"; MY::preinstall( $pkg, $ver ) or next if defined &MY::preinstall; my $success; my $obj = $modtree->{$pkg}; if ( $obj and _version_cmp( $obj->{version}, $ver ) >= 0 ) { my $pathname = $pkg; $pathname =~ s/::/\\W/; foreach my $inc ( grep { m/$pathname.pm/i } keys(%INC) ) { delete $INC{$inc}; } my $rv = $cp->install( modules => [ $obj->{module} ] ); if ( $rv and ( $rv->{ $obj->{module} } or $rv->{ok} ) ) { print "*** $pkg successfully installed.\n"; $success = 1; } else { print "*** $pkg installation cancelled.\n"; $success = 0; } $installed += $success; } else { print << "."; *** Could not find a version $ver or above for $pkg; skipping. . } MY::postinstall( $pkg, $ver, $success ) if defined &MY::postinstall; } return $installed; } sub _cpanplus_config { my @config = (); while ( @_ ) { my ($key, $value) = (shift(), shift()); if ( $key eq 'prerequisites_policy' ) { if ( $value eq 'follow' ) { $value = CPANPLUS::Internals::Constants::PREREQ_INSTALL(); } elsif ( $value eq 'ask' ) { $value = CPANPLUS::Internals::Constants::PREREQ_ASK(); } elsif ( $value eq 'ignore' ) { $value = CPANPLUS::Internals::Constants::PREREQ_IGNORE(); } else { die "*** Cannot convert option $key = '$value' to CPANPLUS version.\n"; } push @config, 'prereqs', $value; } elsif ( $key eq 'force' ) { push @config, $key, $value; } elsif ( $key eq 'notest' ) { push @config, 'skiptest', $value; } else { die "*** Cannot convert option $key to CPANPLUS version.\n"; } } return @config; } sub _install_cpan { my @modules = @{ +shift }; my @config = @{ +shift }; my $installed = 0; my %args; _load_cpan(); require Config; if (CPAN->VERSION < 1.80) { # no "sudo" support, probe for writableness return unless _can_write( MM->catfile( $CPAN::Config->{cpan_home}, 'sources' ) ) and _can_write( $Config::Config{sitelib} ); } # if we're root, set UNINST=1 to avoid trouble unless user asked for it. my $makeflags = $CPAN::Config->{make_install_arg} || ''; $CPAN::Config->{make_install_arg} = join( ' ', split( ' ', $makeflags ), 'UNINST=1' ) if ( $makeflags !~ /\bUNINST\b/ and eval qq{ $> eq '0' } ); # don't show start-up info $CPAN::Config->{inhibit_startup_message} = 1; # set additional options while ( my ( $opt, $arg ) = splice( @config, 0, 2 ) ) { ( $args{$opt} = $arg, next ) if $opt =~ /^(?:force|notest)$/; # pseudo-option $CPAN::Config->{$opt} = $arg; } if ($args{notest} && (not CPAN::Shell->can('notest'))) { die "Your version of CPAN is too old to support the 'notest' pragma"; } local $CPAN::Config->{prerequisites_policy} = 'follow'; while ( my ( $pkg, $ver ) = splice( @modules, 0, 2 ) ) { MY::preinstall( $pkg, $ver ) or next if defined &MY::preinstall; print "*** Installing $pkg...\n"; my $obj = CPAN::Shell->expand( Module => $pkg ); my $success = 0; if ( $obj and _version_cmp( $obj->cpan_version, $ver ) >= 0 ) { my $pathname = $pkg; $pathname =~ s/::/\\W/; foreach my $inc ( grep { m/$pathname.pm/i } keys(%INC) ) { delete $INC{$inc}; } my $rv = do { if ($args{force}) { CPAN::Shell->force( install => $pkg ) } elsif ($args{notest}) { CPAN::Shell->notest( install => $pkg ) } else { CPAN::Shell->install($pkg) } }; $rv ||= eval { $CPAN::META->instance( 'CPAN::Distribution', $obj->cpan_file, ) ->{install} if $CPAN::META; }; if ( $rv eq 'YES' ) { print "*** $pkg successfully installed.\n"; $success = 1; } else { print "*** $pkg installation failed.\n"; $success = 0; } $installed += $success; } else { print << "."; *** Could not find a version $ver or above for $pkg; skipping. . } MY::postinstall( $pkg, $ver, $success ) if defined &MY::postinstall; } return $installed; } sub _has_cpanplus { return ( $HasCPANPLUS = ( $INC{'CPANPLUS/Config.pm'} or _load('CPANPLUS::Shell::Default') ) ); } # make guesses on whether we're under the CPAN installation directory sub _under_cpan { require Cwd; require File::Spec; my $cwd = File::Spec->canonpath( Cwd::getcwd() ); my $cpan = File::Spec->canonpath( $CPAN::Config->{cpan_home} ); return ( index( $cwd, $cpan ) > -1 ); } sub _update_to { my $class = __PACKAGE__; my $ver = shift; return if _version_cmp( _version_of($class), $ver ) >= 0; # no need to upgrade if ( _prompt( "==> A newer version of $class ($ver) is required. Install?", 'y' ) =~ /^[Nn]/ ) { die "*** Please install $class $ver manually.\n"; } print << "."; *** Trying to fetch it from CPAN... . # install ourselves _load($class) and return $class->import(@_) if $class->install( [], $class, $ver ); print << '.'; exit 1; *** Cannot bootstrap myself. :-( Installation terminated. . } # check if we're connected to some host, using inet_aton sub _connected_to { my $site = shift; return ( ( _load('Socket') and Socket::inet_aton($site) ) or _prompt( qq( *** Your host cannot resolve the domain name '$site', which probably means the Internet connections are unavailable. ==> Should we try to install the required module(s) anyway?), 'n' ) =~ /^[Yy]/ ); } # check if a directory is writable; may create it on demand sub _can_write { my $path = shift; mkdir( $path, 0755 ) unless -e $path; return 1 if -w $path; print << "."; *** You are not allowed to write to the directory '$path'; the installation may fail due to insufficient permissions. . if ( eval '$>' and lc(`sudo -V`) =~ /version/ and _prompt( qq( ==> Should we try to re-execute the autoinstall process with 'sudo'?), ((-t STDIN) ? 'y' : 'n') ) =~ /^[Yy]/ ) { # try to bootstrap ourselves from sudo print << "."; *** Trying to re-execute the autoinstall process with 'sudo'... . my $missing = join( ',', @Missing ); my $config = join( ',', UNIVERSAL::isa( $Config, 'HASH' ) ? %{$Config} : @{$Config} ) if $Config; return unless system( 'sudo', $^X, $0, "--config=$config", "--installdeps=$missing" ); print << "."; *** The 'sudo' command exited with error! Resuming... . } return _prompt( qq( ==> Should we try to install the required module(s) anyway?), 'n' ) =~ /^[Yy]/; } # load a module and return the version it reports sub _load { my $mod = pop; # method/function doesn't matter my $file = $mod; $file =~ s|::|/|g; $file .= '.pm'; local $@; return eval { require $file; $mod->VERSION } || ( $@ ? undef: 0 ); } # report version without loading a module sub _version_of { my $mod = pop; # method/function doesn't matter my $file = $mod; $file =~ s|::|/|g; $file .= '.pm'; foreach my $dir ( @INC ) { next if ref $dir; my $path = File::Spec->catfile($dir, $file); next unless -e $path; require ExtUtils::MM_Unix; return ExtUtils::MM_Unix->parse_version($path); } return undef; } # Load CPAN.pm and it's configuration sub _load_cpan { return if $CPAN::VERSION and $CPAN::Config and not @_; require CPAN; # CPAN-1.82+ adds CPAN::Config::AUTOLOAD to redirect to # CPAN::HandleConfig->load. CPAN reports that the redirection # is deprecated in a warning printed at the user. # CPAN-1.81 expects CPAN::HandleConfig->load, does not have # $CPAN::HandleConfig::VERSION but cannot handle # CPAN::Config->load # Which "versions expect CPAN::Config->load? if ( $CPAN::HandleConfig::VERSION || CPAN::HandleConfig->can('load') ) { # Newer versions of CPAN have a HandleConfig module CPAN::HandleConfig->load; } else { # Older versions had the load method in Config directly CPAN::Config->load; } } # compare two versions, either use Sort::Versions or plain comparison # return values same as <=> sub _version_cmp { my ( $cur, $min ) = @_; return -1 unless defined $cur; # if 0 keep comparing return 1 unless $min; $cur =~ s/\s+$//; # check for version numbers that are not in decimal format if ( ref($cur) or ref($min) or $cur =~ /v|\..*\./ or $min =~ /v|\..*\./ ) { if ( ( $version::VERSION or defined( _load('version') )) and version->can('new') ) { # use version.pm if it is installed. return version->new($cur) <=> version->new($min); } elsif ( $Sort::Versions::VERSION or defined( _load('Sort::Versions') ) ) { # use Sort::Versions as the sorting algorithm for a.b.c versions return Sort::Versions::versioncmp( $cur, $min ); } warn "Cannot reliably compare non-decimal formatted versions.\n" . "Please install version.pm or Sort::Versions.\n"; } # plain comparison local $^W = 0; # shuts off 'not numeric' bugs return $cur <=> $min; } # nothing; this usage is deprecated. sub main::PREREQ_PM { return {}; } sub _make_args { my %args = @_; $args{PREREQ_PM} = { %{ $args{PREREQ_PM} || {} }, @Existing, @Missing } if $UnderCPAN or $TestOnly; if ( $args{EXE_FILES} and -e 'MANIFEST' ) { require ExtUtils::Manifest; my $manifest = ExtUtils::Manifest::maniread('MANIFEST'); $args{EXE_FILES} = [ grep { exists $manifest->{$_} } @{ $args{EXE_FILES} } ]; } $args{test}{TESTS} ||= 't/*.t'; $args{test}{TESTS} = join( ' ', grep { !exists( $DisabledTests{$_} ) } map { glob($_) } split( /\s+/, $args{test}{TESTS} ) ); my $missing = join( ',', @Missing ); my $config = join( ',', UNIVERSAL::isa( $Config, 'HASH' ) ? %{$Config} : @{$Config} ) if $Config; $PostambleActions = ( ($missing and not $UnderCPAN) ? "\$(PERL) $0 --config=$config --installdeps=$missing" : "\$(NOECHO) \$(NOOP)" ); my $deps_list = join( ',', @Missing, @Existing ); $PostambleActionsUpgradeDeps = "\$(PERL) $0 --config=$config --upgradedeps=$deps_list"; my $config_notest = join( ',', (UNIVERSAL::isa( $Config, 'HASH' ) ? %{$Config} : @{$Config}), 'notest', 1 ) if $Config; $PostambleActionsNoTest = ( ($missing and not $UnderCPAN) ? "\$(PERL) $0 --config=$config_notest --installdeps=$missing" : "\$(NOECHO) \$(NOOP)" ); $PostambleActionsUpgradeDepsNoTest = "\$(PERL) $0 --config=$config_notest --upgradedeps=$deps_list"; $PostambleActionsListDeps = '@$(PERL) -le "print for @ARGV" ' . join(' ', map $Missing[$_], grep $_ % 2 == 0, 0..$#Missing); my @all = (@Missing, @Existing); $PostambleActionsListAllDeps = '@$(PERL) -le "print for @ARGV" ' . join(' ', map $all[$_], grep $_ % 2 == 0, 0..$#all); return %args; } # a wrapper to ExtUtils::MakeMaker::WriteMakefile sub Write { require Carp; Carp::croak "WriteMakefile: Need even number of args" if @_ % 2; if ($CheckOnly) { print << "."; *** Makefile not written in check-only mode. . return; } my %args = _make_args(@_); no strict 'refs'; $PostambleUsed = 0; local *MY::postamble = \&postamble unless defined &MY::postamble; ExtUtils::MakeMaker::WriteMakefile(%args); print << "." unless $PostambleUsed; *** WARNING: Makefile written with customized MY::postamble() without including contents from Module::AutoInstall::postamble() -- auto installation features disabled. Please contact the author. . return 1; } sub postamble { $PostambleUsed = 1; my $fragment; $fragment .= <<"AUTO_INSTALL" if !$InstallDepsTarget; config :: installdeps \t\$(NOECHO) \$(NOOP) AUTO_INSTALL $fragment .= <<"END_MAKE"; checkdeps :: \t\$(PERL) $0 --checkdeps installdeps :: \t$PostambleActions installdeps_notest :: \t$PostambleActionsNoTest upgradedeps :: \t$PostambleActionsUpgradeDeps upgradedeps_notest :: \t$PostambleActionsUpgradeDepsNoTest listdeps :: \t$PostambleActionsListDeps listalldeps :: \t$PostambleActionsListAllDeps END_MAKE return $fragment; } 1; __END__ #line 1197 UnixAgent-2.8/inc/Module/Install.pm000066400000000000000000000327441372663377700172660ustar00rootroot00000000000000#line 1 package Module::Install; # For any maintainers: # The load order for Module::Install is a bit magic. # It goes something like this... # # IF ( host has Module::Install installed, creating author mode ) { # 1. Makefile.PL calls "use inc::Module::Install" # 2. $INC{inc/Module/Install.pm} set to installed version of inc::Module::Install # 3. The installed version of inc::Module::Install loads # 4. inc::Module::Install calls "require Module::Install" # 5. The ./inc/ version of Module::Install loads # } ELSE { # 1. Makefile.PL calls "use inc::Module::Install" # 2. $INC{inc/Module/Install.pm} set to ./inc/ version of Module::Install # 3. The ./inc/ version of Module::Install loads # } use 5.006; use strict 'vars'; use Cwd (); use File::Find (); use File::Path (); use vars qw{$VERSION $MAIN}; BEGIN { # All Module::Install core packages now require synchronised versions. # This will be used to ensure we don't accidentally load old or # different versions of modules. # This is not enforced yet, but will be some time in the next few # releases once we can make sure it won't clash with custom # Module::Install extensions. $VERSION = '1.14'; # Storage for the pseudo-singleton $MAIN = undef; *inc::Module::Install::VERSION = *VERSION; @inc::Module::Install::ISA = __PACKAGE__; } sub import { my $class = shift; my $self = $class->new(@_); my $who = $self->_caller; #------------------------------------------------------------- # all of the following checks should be included in import(), # to allow "eval 'require Module::Install; 1' to test # installation of Module::Install. (RT #51267) #------------------------------------------------------------- # Whether or not inc::Module::Install is actually loaded, the # $INC{inc/Module/Install.pm} is what will still get set as long as # the caller loaded module this in the documented manner. # If not set, the caller may NOT have loaded the bundled version, and thus # they may not have a MI version that works with the Makefile.PL. This would # result in false errors or unexpected behaviour. And we don't want that. my $file = join( '/', 'inc', split /::/, __PACKAGE__ ) . '.pm'; unless ( $INC{$file} ) { die <<"END_DIE" } Please invoke ${\__PACKAGE__} with: use inc::${\__PACKAGE__}; not: use ${\__PACKAGE__}; END_DIE # This reportedly fixes a rare Win32 UTC file time issue, but # as this is a non-cross-platform XS module not in the core, # we shouldn't really depend on it. See RT #24194 for detail. # (Also, this module only supports Perl 5.6 and above). eval "use Win32::UTCFileTime" if $^O eq 'MSWin32' && $] >= 5.006; # If the script that is loading Module::Install is from the future, # then make will detect this and cause it to re-run over and over # again. This is bad. Rather than taking action to touch it (which # is unreliable on some platforms and requires write permissions) # for now we should catch this and refuse to run. if ( -f $0 ) { my $s = (stat($0))[9]; # If the modification time is only slightly in the future, # sleep briefly to remove the problem. my $a = $s - time; if ( $a > 0 and $a < 5 ) { sleep 5 } # Too far in the future, throw an error. my $t = time; if ( $s > $t ) { die <<"END_DIE" } Your installer $0 has a modification time in the future ($s > $t). This is known to create infinite loops in make. Please correct this, then run $0 again. END_DIE } # Build.PL was formerly supported, but no longer is due to excessive # difficulty in implementing every single feature twice. if ( $0 =~ /Build.PL$/i ) { die <<"END_DIE" } Module::Install no longer supports Build.PL. It was impossible to maintain duel backends, and has been deprecated. Please remove all Build.PL files and only use the Makefile.PL installer. END_DIE #------------------------------------------------------------- # To save some more typing in Module::Install installers, every... # use inc::Module::Install # ...also acts as an implicit use strict. $^H |= strict::bits(qw(refs subs vars)); #------------------------------------------------------------- unless ( -f $self->{file} ) { foreach my $key (keys %INC) { delete $INC{$key} if $key =~ /Module\/Install/; } local $^W; require "$self->{path}/$self->{dispatch}.pm"; File::Path::mkpath("$self->{prefix}/$self->{author}"); $self->{admin} = "$self->{name}::$self->{dispatch}"->new( _top => $self ); $self->{admin}->init; @_ = ($class, _self => $self); goto &{"$self->{name}::import"}; } local $^W; *{"${who}::AUTOLOAD"} = $self->autoload; $self->preload; # Unregister loader and worker packages so subdirs can use them again delete $INC{'inc/Module/Install.pm'}; delete $INC{'Module/Install.pm'}; # Save to the singleton $MAIN = $self; return 1; } sub autoload { my $self = shift; my $who = $self->_caller; my $cwd = Cwd::getcwd(); my $sym = "${who}::AUTOLOAD"; $sym->{$cwd} = sub { my $pwd = Cwd::getcwd(); if ( my $code = $sym->{$pwd} ) { # Delegate back to parent dirs goto &$code unless $cwd eq $pwd; } unless ($$sym =~ s/([^:]+)$//) { # XXX: it looks like we can't retrieve the missing function # via $$sym (usually $main::AUTOLOAD) in this case. # I'm still wondering if we should slurp Makefile.PL to # get some context or not ... my ($package, $file, $line) = caller; die <<"EOT"; Unknown function is found at $file line $line. Execution of $file aborted due to runtime errors. If you're a contributor to a project, you may need to install some Module::Install extensions from CPAN (or other repository). If you're a user of a module, please contact the author. EOT } my $method = $1; if ( uc($method) eq $method ) { # Do nothing return; } elsif ( $method =~ /^_/ and $self->can($method) ) { # Dispatch to the root M:I class return $self->$method(@_); } # Dispatch to the appropriate plugin unshift @_, ( $self, $1 ); goto &{$self->can('call')}; }; } sub preload { my $self = shift; unless ( $self->{extensions} ) { $self->load_extensions( "$self->{prefix}/$self->{path}", $self ); } my @exts = @{$self->{extensions}}; unless ( @exts ) { @exts = $self->{admin}->load_all_extensions; } my %seen; foreach my $obj ( @exts ) { while (my ($method, $glob) = each %{ref($obj) . '::'}) { next unless $obj->can($method); next if $method =~ /^_/; next if $method eq uc($method); $seen{$method}++; } } my $who = $self->_caller; foreach my $name ( sort keys %seen ) { local $^W; *{"${who}::$name"} = sub { ${"${who}::AUTOLOAD"} = "${who}::$name"; goto &{"${who}::AUTOLOAD"}; }; } } sub new { my ($class, %args) = @_; delete $INC{'FindBin.pm'}; { # to suppress the redefine warning local $SIG{__WARN__} = sub {}; require FindBin; } # ignore the prefix on extension modules built from top level. my $base_path = Cwd::abs_path($FindBin::Bin); unless ( Cwd::abs_path(Cwd::getcwd()) eq $base_path ) { delete $args{prefix}; } return $args{_self} if $args{_self}; $args{dispatch} ||= 'Admin'; $args{prefix} ||= 'inc'; $args{author} ||= ($^O eq 'VMS' ? '_author' : '.author'); $args{bundle} ||= 'inc/BUNDLES'; $args{base} ||= $base_path; $class =~ s/^\Q$args{prefix}\E:://; $args{name} ||= $class; $args{version} ||= $class->VERSION; unless ( $args{path} ) { $args{path} = $args{name}; $args{path} =~ s!::!/!g; } $args{file} ||= "$args{base}/$args{prefix}/$args{path}.pm"; $args{wrote} = 0; bless( \%args, $class ); } sub call { my ($self, $method) = @_; my $obj = $self->load($method) or return; splice(@_, 0, 2, $obj); goto &{$obj->can($method)}; } sub load { my ($self, $method) = @_; $self->load_extensions( "$self->{prefix}/$self->{path}", $self ) unless $self->{extensions}; foreach my $obj (@{$self->{extensions}}) { return $obj if $obj->can($method); } my $admin = $self->{admin} or die <<"END_DIE"; The '$method' method does not exist in the '$self->{prefix}' path! Please remove the '$self->{prefix}' directory and run $0 again to load it. END_DIE my $obj = $admin->load($method, 1); push @{$self->{extensions}}, $obj; $obj; } sub load_extensions { my ($self, $path, $top) = @_; my $should_reload = 0; unless ( grep { ! ref $_ and lc $_ eq lc $self->{prefix} } @INC ) { unshift @INC, $self->{prefix}; $should_reload = 1; } foreach my $rv ( $self->find_extensions($path) ) { my ($file, $pkg) = @{$rv}; next if $self->{pathnames}{$pkg}; local $@; my $new = eval { local $^W; require $file; $pkg->can('new') }; unless ( $new ) { warn $@ if $@; next; } $self->{pathnames}{$pkg} = $should_reload ? delete $INC{$file} : $INC{$file}; push @{$self->{extensions}}, &{$new}($pkg, _top => $top ); } $self->{extensions} ||= []; } sub find_extensions { my ($self, $path) = @_; my @found; File::Find::find( sub { my $file = $File::Find::name; return unless $file =~ m!^\Q$path\E/(.+)\.pm\Z!is; my $subpath = $1; return if lc($subpath) eq lc($self->{dispatch}); $file = "$self->{path}/$subpath.pm"; my $pkg = "$self->{name}::$subpath"; $pkg =~ s!/!::!g; # If we have a mixed-case package name, assume case has been preserved # correctly. Otherwise, root through the file to locate the case-preserved # version of the package name. if ( $subpath eq lc($subpath) || $subpath eq uc($subpath) ) { my $content = Module::Install::_read($subpath . '.pm'); my $in_pod = 0; foreach ( split /\n/, $content ) { $in_pod = 1 if /^=\w/; $in_pod = 0 if /^=cut/; next if ($in_pod || /^=cut/); # skip pod text next if /^\s*#/; # and comments if ( m/^\s*package\s+($pkg)\s*;/i ) { $pkg = $1; last; } } } push @found, [ $file, $pkg ]; }, $path ) if -d $path; @found; } ##################################################################### # Common Utility Functions sub _caller { my $depth = 0; my $call = caller($depth); while ( $call eq __PACKAGE__ ) { $depth++; $call = caller($depth); } return $call; } # Done in evals to avoid confusing Perl::MinimumVersion eval( $] >= 5.006 ? <<'END_NEW' : <<'END_OLD' ); die $@ if $@; sub _read { local *FH; open( FH, '<', $_[0] ) or die "open($_[0]): $!"; binmode FH; my $string = do { local $/; }; close FH or die "close($_[0]): $!"; return $string; } END_NEW sub _read { local *FH; open( FH, "< $_[0]" ) or die "open($_[0]): $!"; binmode FH; my $string = do { local $/; }; close FH or die "close($_[0]): $!"; return $string; } END_OLD sub _readperl { my $string = Module::Install::_read($_[0]); $string =~ s/(?:\015{1,2}\012|\015|\012)/\n/sg; $string =~ s/(\n)\n*__(?:DATA|END)__\b.*\z/$1/s; $string =~ s/\n\n=\w+.+?\n\n=cut\b.+?\n+/\n\n/sg; return $string; } sub _readpod { my $string = Module::Install::_read($_[0]); $string =~ s/(?:\015{1,2}\012|\015|\012)/\n/sg; return $string if $_[0] =~ /\.pod\z/; $string =~ s/(^|\n=cut\b.+?\n+)[^=\s].+?\n(\n=\w+|\z)/$1$2/sg; $string =~ s/\n*=pod\b[^\n]*\n+/\n\n/sg; $string =~ s/\n*=cut\b[^\n]*\n+/\n\n/sg; $string =~ s/^\n+//s; return $string; } # Done in evals to avoid confusing Perl::MinimumVersion eval( $] >= 5.006 ? <<'END_NEW' : <<'END_OLD' ); die $@ if $@; sub _write { local *FH; open( FH, '>', $_[0] ) or die "open($_[0]): $!"; binmode FH; foreach ( 1 .. $#_ ) { print FH $_[$_] or die "print($_[0]): $!"; } close FH or die "close($_[0]): $!"; } END_NEW sub _write { local *FH; open( FH, "> $_[0]" ) or die "open($_[0]): $!"; binmode FH; foreach ( 1 .. $#_ ) { print FH $_[$_] or die "print($_[0]): $!"; } close FH or die "close($_[0]): $!"; } END_OLD # _version is for processing module versions (eg, 1.03_05) not # Perl versions (eg, 5.8.1). sub _version { my $s = shift || 0; my $d =()= $s =~ /(\.)/g; if ( $d >= 2 ) { # Normalise multipart versions $s =~ s/(\.)(\d{1,3})/sprintf("$1%03d",$2)/eg; } $s =~ s/^(\d+)\.?//; my $l = $1 || 0; my @v = map { $_ . '0' x (3 - length $_) } $s =~ /(\d{1,3})\D?/g; $l = $l . '.' . join '', @v if @v; return $l + 0; } sub _cmp { _version($_[1]) <=> _version($_[2]); } # Cloned from Params::Util::_CLASS sub _CLASS { ( defined $_[0] and ! ref $_[0] and $_[0] =~ m/^[^\W\d]\w*(?:::\w+)*\z/s ) ? $_[0] : undef; } 1; # Copyright 2008 - 2012 Adam Kennedy. UnixAgent-2.8/inc/Module/Install/000077500000000000000000000000001372663377700167165ustar00rootroot00000000000000UnixAgent-2.8/inc/Module/Install/Base.pm000066400000000000000000000022571372663377700201340ustar00rootroot00000000000000#line 1 package Module::Install::Base; use strict 'vars'; use vars qw{$VERSION}; BEGIN { $VERSION = '1.14'; } # Suspend handler for "redefined" warnings BEGIN { my $w = $SIG{__WARN__}; $SIG{__WARN__} = sub { $w }; } #line 42 sub new { my $class = shift; unless ( defined &{"${class}::call"} ) { *{"${class}::call"} = sub { shift->_top->call(@_) }; } unless ( defined &{"${class}::load"} ) { *{"${class}::load"} = sub { shift->_top->load(@_) }; } bless { @_ }, $class; } #line 61 sub AUTOLOAD { local $@; my $func = eval { shift->_top->autoload } or return; goto &$func; } #line 75 sub _top { $_[0]->{_top}; } #line 90 sub admin { $_[0]->_top->{admin} or Module::Install::Base::FakeAdmin->new; } #line 106 sub is_admin { ! $_[0]->admin->isa('Module::Install::Base::FakeAdmin'); } sub DESTROY {} package Module::Install::Base::FakeAdmin; use vars qw{$VERSION}; BEGIN { $VERSION = $Module::Install::Base::VERSION; } my $fake; sub new { $fake ||= bless(\@_, $_[0]); } sub AUTOLOAD {} sub DESTROY {} # Restore warning handler BEGIN { $SIG{__WARN__} = $SIG{__WARN__}->(); } 1; #line 159 UnixAgent-2.8/inc/Module/Install/Can.pm000066400000000000000000000067731372663377700177720ustar00rootroot00000000000000#line 1 package Module::Install::Can; use strict; use Config (); use ExtUtils::MakeMaker (); use Module::Install::Base (); use vars qw{$VERSION @ISA $ISCORE}; BEGIN { $VERSION = '1.14'; @ISA = 'Module::Install::Base'; $ISCORE = 1; } # check if we can load some module ### Upgrade this to not have to load the module if possible sub can_use { my ($self, $mod, $ver) = @_; $mod =~ s{::|\\}{/}g; $mod .= '.pm' unless $mod =~ /\.pm$/i; my $pkg = $mod; $pkg =~ s{/}{::}g; $pkg =~ s{\.pm$}{}i; local $@; eval { require $mod; $pkg->VERSION($ver || 0); 1 }; } # Check if we can run some command sub can_run { my ($self, $cmd) = @_; my $_cmd = $cmd; return $_cmd if (-x $_cmd or $_cmd = MM->maybe_command($_cmd)); for my $dir ((split /$Config::Config{path_sep}/, $ENV{PATH}), '.') { next if $dir eq ''; require File::Spec; my $abs = File::Spec->catfile($dir, $cmd); return $abs if (-x $abs or $abs = MM->maybe_command($abs)); } return; } # Can our C compiler environment build XS files sub can_xs { my $self = shift; # Ensure we have the CBuilder module $self->configure_requires( 'ExtUtils::CBuilder' => 0.27 ); # Do we have the configure_requires checker? local $@; eval "require ExtUtils::CBuilder;"; if ( $@ ) { # They don't obey configure_requires, so it is # someone old and delicate. Try to avoid hurting # them by falling back to an older simpler test. return $self->can_cc(); } # Do we have a working C compiler my $builder = ExtUtils::CBuilder->new( quiet => 1, ); unless ( $builder->have_compiler ) { # No working C compiler return 0; } # Write a C file representative of what XS becomes require File::Temp; my ( $FH, $tmpfile ) = File::Temp::tempfile( "compilexs-XXXXX", SUFFIX => '.c', ); binmode $FH; print $FH <<'END_C'; #include "EXTERN.h" #include "perl.h" #include "XSUB.h" int main(int argc, char **argv) { return 0; } int boot_sanexs() { return 1; } END_C close $FH; # Can the C compiler access the same headers XS does my @libs = (); my $object = undef; eval { local $^W = 0; $object = $builder->compile( source => $tmpfile, ); @libs = $builder->link( objects => $object, module_name => 'sanexs', ); }; my $result = $@ ? 0 : 1; # Clean up all the build files foreach ( $tmpfile, $object, @libs ) { next unless defined $_; 1 while unlink; } return $result; } # Can we locate a (the) C compiler sub can_cc { my $self = shift; my @chunks = split(/ /, $Config::Config{cc}) or return; # $Config{cc} may contain args; try to find out the program part while (@chunks) { return $self->can_run("@chunks") || (pop(@chunks), next); } return; } # Fix Cygwin bug on maybe_command(); if ( $^O eq 'cygwin' ) { require ExtUtils::MM_Cygwin; require ExtUtils::MM_Win32; if ( ! defined(&ExtUtils::MM_Cygwin::maybe_command) ) { *ExtUtils::MM_Cygwin::maybe_command = sub { my ($self, $file) = @_; if ($file =~ m{^/cygdrive/}i and ExtUtils::MM_Win32->can('maybe_command')) { ExtUtils::MM_Win32->maybe_command($file); } else { ExtUtils::MM_Unix->maybe_command($file); } } } } 1; __END__ #line 236 UnixAgent-2.8/inc/Module/Install/Fetch.pm000066400000000000000000000046401372663377700203110ustar00rootroot00000000000000#line 1 package Module::Install::Fetch; use strict; use Module::Install::Base (); use vars qw{$VERSION @ISA $ISCORE}; BEGIN { $VERSION = '1.14'; @ISA = 'Module::Install::Base'; $ISCORE = 1; } sub get_file { my ($self, %args) = @_; my ($scheme, $host, $path, $file) = $args{url} =~ m|^(\w+)://([^/]+)(.+)/(.+)| or return; if ( $scheme eq 'http' and ! eval { require LWP::Simple; 1 } ) { $args{url} = $args{ftp_url} or (warn("LWP support unavailable!\n"), return); ($scheme, $host, $path, $file) = $args{url} =~ m|^(\w+)://([^/]+)(.+)/(.+)| or return; } $|++; print "Fetching '$file' from $host... "; unless (eval { require Socket; Socket::inet_aton($host) }) { warn "'$host' resolve failed!\n"; return; } return unless $scheme eq 'ftp' or $scheme eq 'http'; require Cwd; my $dir = Cwd::getcwd(); chdir $args{local_dir} or return if exists $args{local_dir}; if (eval { require LWP::Simple; 1 }) { LWP::Simple::mirror($args{url}, $file); } elsif (eval { require Net::FTP; 1 }) { eval { # use Net::FTP to get past firewall my $ftp = Net::FTP->new($host, Passive => 1, Timeout => 600); $ftp->login("anonymous", 'anonymous@example.com'); $ftp->cwd($path); $ftp->binary; $ftp->get($file) or (warn("$!\n"), return); $ftp->quit; } } elsif (my $ftp = $self->can_run('ftp')) { eval { # no Net::FTP, fallback to ftp.exe require FileHandle; my $fh = FileHandle->new; local $SIG{CHLD} = 'IGNORE'; unless ($fh->open("|$ftp -n")) { warn "Couldn't open ftp: $!\n"; chdir $dir; return; } my @dialog = split(/\n/, <<"END_FTP"); open $host user anonymous anonymous\@example.com cd $path binary get $file $file quit END_FTP foreach (@dialog) { $fh->print("$_\n") } $fh->close; } } else { warn "No working 'ftp' program available!\n"; chdir $dir; return; } unless (-f $file) { warn "Fetching failed: $@\n"; chdir $dir; return; } return if exists $args{size} and -s $file != $args{size}; system($args{run}) if exists $args{run}; unlink($file) if $args{remove}; print(((!exists $args{check_for} or -e $args{check_for}) ? "done!" : "failed! ($!)"), "\n"); chdir $dir; return !$?; } 1; UnixAgent-2.8/inc/Module/Install/Include.pm000066400000000000000000000010451372663377700206370ustar00rootroot00000000000000#line 1 package Module::Install::Include; use strict; use Module::Install::Base (); use vars qw{$VERSION @ISA $ISCORE}; BEGIN { $VERSION = '1.14'; @ISA = 'Module::Install::Base'; $ISCORE = 1; } sub include { shift()->admin->include(@_); } sub include_deps { shift()->admin->include_deps(@_); } sub auto_include { shift()->admin->auto_include(@_); } sub auto_include_deps { shift()->admin->auto_include_deps(@_); } sub auto_include_dependent_dists { shift()->admin->auto_include_dependent_dists(@_); } 1; UnixAgent-2.8/inc/Module/Install/Makefile.pm000066400000000000000000000321001372663377700207650ustar00rootroot00000000000000#line 1 package Module::Install::Makefile; use strict 'vars'; use ExtUtils::MakeMaker (); use Module::Install::Base (); use Fcntl qw/:flock :seek/; use vars qw{$VERSION @ISA $ISCORE}; BEGIN { $VERSION = '1.14'; @ISA = 'Module::Install::Base'; $ISCORE = 1; } sub Makefile { $_[0] } my %seen = (); sub prompt { shift; # Infinite loop protection my @c = caller(); if ( ++$seen{"$c[1]|$c[2]|$_[0]"} > 3 ) { die "Caught an potential prompt infinite loop ($c[1]|$c[2]|$_[0])"; } # In automated testing or non-interactive session, always use defaults if ( ($ENV{AUTOMATED_TESTING} or -! -t STDIN) and ! $ENV{PERL_MM_USE_DEFAULT} ) { local $ENV{PERL_MM_USE_DEFAULT} = 1; goto &ExtUtils::MakeMaker::prompt; } else { goto &ExtUtils::MakeMaker::prompt; } } # Store a cleaned up version of the MakeMaker version, # since we need to behave differently in a variety of # ways based on the MM version. my $makemaker = eval $ExtUtils::MakeMaker::VERSION; # If we are passed a param, do a "newer than" comparison. # Otherwise, just return the MakeMaker version. sub makemaker { ( @_ < 2 or $makemaker >= eval($_[1]) ) ? $makemaker : 0 } # Ripped from ExtUtils::MakeMaker 6.56, and slightly modified # as we only need to know here whether the attribute is an array # or a hash or something else (which may or may not be appendable). my %makemaker_argtype = ( C => 'ARRAY', CONFIG => 'ARRAY', # CONFIGURE => 'CODE', # ignore DIR => 'ARRAY', DL_FUNCS => 'HASH', DL_VARS => 'ARRAY', EXCLUDE_EXT => 'ARRAY', EXE_FILES => 'ARRAY', FUNCLIST => 'ARRAY', H => 'ARRAY', IMPORTS => 'HASH', INCLUDE_EXT => 'ARRAY', LIBS => 'ARRAY', # ignore '' MAN1PODS => 'HASH', MAN3PODS => 'HASH', META_ADD => 'HASH', META_MERGE => 'HASH', PL_FILES => 'HASH', PM => 'HASH', PMLIBDIRS => 'ARRAY', PMLIBPARENTDIRS => 'ARRAY', PREREQ_PM => 'HASH', CONFIGURE_REQUIRES => 'HASH', SKIP => 'ARRAY', TYPEMAPS => 'ARRAY', XS => 'HASH', # VERSION => ['version',''], # ignore # _KEEP_AFTER_FLUSH => '', clean => 'HASH', depend => 'HASH', dist => 'HASH', dynamic_lib=> 'HASH', linkext => 'HASH', macro => 'HASH', postamble => 'HASH', realclean => 'HASH', test => 'HASH', tool_autosplit => 'HASH', # special cases where you can use makemaker_append CCFLAGS => 'APPENDABLE', DEFINE => 'APPENDABLE', INC => 'APPENDABLE', LDDLFLAGS => 'APPENDABLE', LDFROM => 'APPENDABLE', ); sub makemaker_args { my ($self, %new_args) = @_; my $args = ( $self->{makemaker_args} ||= {} ); foreach my $key (keys %new_args) { if ($makemaker_argtype{$key}) { if ($makemaker_argtype{$key} eq 'ARRAY') { $args->{$key} = [] unless defined $args->{$key}; unless (ref $args->{$key} eq 'ARRAY') { $args->{$key} = [$args->{$key}] } push @{$args->{$key}}, ref $new_args{$key} eq 'ARRAY' ? @{$new_args{$key}} : $new_args{$key}; } elsif ($makemaker_argtype{$key} eq 'HASH') { $args->{$key} = {} unless defined $args->{$key}; foreach my $skey (keys %{ $new_args{$key} }) { $args->{$key}{$skey} = $new_args{$key}{$skey}; } } elsif ($makemaker_argtype{$key} eq 'APPENDABLE') { $self->makemaker_append($key => $new_args{$key}); } } else { if (defined $args->{$key}) { warn qq{MakeMaker attribute "$key" is overridden; use "makemaker_append" to append values\n}; } $args->{$key} = $new_args{$key}; } } return $args; } # For mm args that take multiple space-separated args, # append an argument to the current list. sub makemaker_append { my $self = shift; my $name = shift; my $args = $self->makemaker_args; $args->{$name} = defined $args->{$name} ? join( ' ', $args->{$name}, @_ ) : join( ' ', @_ ); } sub build_subdirs { my $self = shift; my $subdirs = $self->makemaker_args->{DIR} ||= []; for my $subdir (@_) { push @$subdirs, $subdir; } } sub clean_files { my $self = shift; my $clean = $self->makemaker_args->{clean} ||= {}; %$clean = ( %$clean, FILES => join ' ', grep { length $_ } ($clean->{FILES} || (), @_), ); } sub realclean_files { my $self = shift; my $realclean = $self->makemaker_args->{realclean} ||= {}; %$realclean = ( %$realclean, FILES => join ' ', grep { length $_ } ($realclean->{FILES} || (), @_), ); } sub libs { my $self = shift; my $libs = ref $_[0] ? shift : [ shift ]; $self->makemaker_args( LIBS => $libs ); } sub inc { my $self = shift; $self->makemaker_args( INC => shift ); } sub _wanted_t { } sub tests_recursive { my $self = shift; my $dir = shift || 't'; unless ( -d $dir ) { die "tests_recursive dir '$dir' does not exist"; } my %tests = map { $_ => 1 } split / /, ($self->tests || ''); require File::Find; File::Find::find( sub { /\.t$/ and -f $_ and $tests{"$File::Find::dir/*.t"} = 1 }, $dir ); $self->tests( join ' ', sort keys %tests ); } sub write { my $self = shift; die "&Makefile->write() takes no arguments\n" if @_; # Check the current Perl version my $perl_version = $self->perl_version; if ( $perl_version ) { eval "use $perl_version; 1" or die "ERROR: perl: Version $] is installed, " . "but we need version >= $perl_version"; } # Make sure we have a new enough MakeMaker require ExtUtils::MakeMaker; if ( $perl_version and $self->_cmp($perl_version, '5.006') >= 0 ) { # This previous attempted to inherit the version of # ExtUtils::MakeMaker in use by the module author, but this # was found to be untenable as some authors build releases # using future dev versions of EU:MM that nobody else has. # Instead, #toolchain suggests we use 6.59 which is the most # stable version on CPAN at time of writing and is, to quote # ribasushi, "not terminally fucked, > and tested enough". # TODO: We will now need to maintain this over time to push # the version up as new versions are released. $self->build_requires( 'ExtUtils::MakeMaker' => 6.59 ); $self->configure_requires( 'ExtUtils::MakeMaker' => 6.59 ); } else { # Allow legacy-compatibility with 5.005 by depending on the # most recent EU:MM that supported 5.005. $self->build_requires( 'ExtUtils::MakeMaker' => 6.36 ); $self->configure_requires( 'ExtUtils::MakeMaker' => 6.36 ); } # Generate the MakeMaker params my $args = $self->makemaker_args; $args->{DISTNAME} = $self->name; $args->{NAME} = $self->module_name || $self->name; $args->{NAME} =~ s/-/::/g; $args->{VERSION} = $self->version or die <<'EOT'; ERROR: Can't determine distribution version. Please specify it explicitly via 'version' in Makefile.PL, or set a valid $VERSION in a module, and provide its file path via 'version_from' (or 'all_from' if you prefer) in Makefile.PL. EOT if ( $self->tests ) { my @tests = split ' ', $self->tests; my %seen; $args->{test} = { TESTS => (join ' ', grep {!$seen{$_}++} @tests), }; } elsif ( $Module::Install::ExtraTests::use_extratests ) { # Module::Install::ExtraTests doesn't set $self->tests and does its own tests via harness. # So, just ignore our xt tests here. } elsif ( -d 'xt' and ($Module::Install::AUTHOR or $ENV{RELEASE_TESTING}) ) { $args->{test} = { TESTS => join( ' ', map { "$_/*.t" } grep { -d $_ } qw{ t xt } ), }; } if ( $] >= 5.005 ) { $args->{ABSTRACT} = $self->abstract; $args->{AUTHOR} = join ', ', @{$self->author || []}; } if ( $self->makemaker(6.10) ) { $args->{NO_META} = 1; #$args->{NO_MYMETA} = 1; } if ( $self->makemaker(6.17) and $self->sign ) { $args->{SIGN} = 1; } unless ( $self->is_admin ) { delete $args->{SIGN}; } if ( $self->makemaker(6.31) and $self->license ) { $args->{LICENSE} = $self->license; } my $prereq = ($args->{PREREQ_PM} ||= {}); %$prereq = ( %$prereq, map { @$_ } # flatten [module => version] map { @$_ } grep $_, ($self->requires) ); # Remove any reference to perl, PREREQ_PM doesn't support it delete $args->{PREREQ_PM}->{perl}; # Merge both kinds of requires into BUILD_REQUIRES my $build_prereq = ($args->{BUILD_REQUIRES} ||= {}); %$build_prereq = ( %$build_prereq, map { @$_ } # flatten [module => version] map { @$_ } grep $_, ($self->configure_requires, $self->build_requires) ); # Remove any reference to perl, BUILD_REQUIRES doesn't support it delete $args->{BUILD_REQUIRES}->{perl}; # Delete bundled dists from prereq_pm, add it to Makefile DIR my $subdirs = ($args->{DIR} || []); if ($self->bundles) { my %processed; foreach my $bundle (@{ $self->bundles }) { my ($mod_name, $dist_dir) = @$bundle; delete $prereq->{$mod_name}; $dist_dir = File::Basename::basename($dist_dir); # dir for building this module if (not exists $processed{$dist_dir}) { if (-d $dist_dir) { # List as sub-directory to be processed by make push @$subdirs, $dist_dir; } # Else do nothing: the module is already present on the system $processed{$dist_dir} = undef; } } } unless ( $self->makemaker('6.55_03') ) { %$prereq = (%$prereq,%$build_prereq); delete $args->{BUILD_REQUIRES}; } if ( my $perl_version = $self->perl_version ) { eval "use $perl_version; 1" or die "ERROR: perl: Version $] is installed, " . "but we need version >= $perl_version"; if ( $self->makemaker(6.48) ) { $args->{MIN_PERL_VERSION} = $perl_version; } } if ($self->installdirs) { warn qq{old INSTALLDIRS (probably set by makemaker_args) is overridden by installdirs\n} if $args->{INSTALLDIRS}; $args->{INSTALLDIRS} = $self->installdirs; } my %args = map { ( $_ => $args->{$_} ) } grep {defined($args->{$_} ) } keys %$args; my $user_preop = delete $args{dist}->{PREOP}; if ( my $preop = $self->admin->preop($user_preop) ) { foreach my $key ( keys %$preop ) { $args{dist}->{$key} = $preop->{$key}; } } my $mm = ExtUtils::MakeMaker::WriteMakefile(%args); $self->fix_up_makefile($mm->{FIRST_MAKEFILE} || 'Makefile'); } sub fix_up_makefile { my $self = shift; my $makefile_name = shift; my $top_class = ref($self->_top) || ''; my $top_version = $self->_top->VERSION || ''; my $preamble = $self->preamble ? "# Preamble by $top_class $top_version\n" . $self->preamble : ''; my $postamble = "# Postamble by $top_class $top_version\n" . ($self->postamble || ''); local *MAKEFILE; open MAKEFILE, "+< $makefile_name" or die "fix_up_makefile: Couldn't open $makefile_name: $!"; eval { flock MAKEFILE, LOCK_EX }; my $makefile = do { local $/; }; $makefile =~ s/\b(test_harness\(\$\(TEST_VERBOSE\), )/$1'inc', /; $makefile =~ s/( -I\$\(INST_ARCHLIB\))/ -Iinc$1/g; $makefile =~ s/( "-I\$\(INST_LIB\)")/ "-Iinc"$1/g; $makefile =~ s/^(FULLPERL = .*)/$1 "-Iinc"/m; $makefile =~ s/^(PERL = .*)/$1 "-Iinc"/m; # Module::Install will never be used to build the Core Perl # Sometimes PERL_LIB and PERL_ARCHLIB get written anyway, which breaks # PREFIX/PERL5LIB, and thus, install_share. Blank them if they exist $makefile =~ s/^PERL_LIB = .+/PERL_LIB =/m; #$makefile =~ s/^PERL_ARCHLIB = .+/PERL_ARCHLIB =/m; # Perl 5.005 mentions PERL_LIB explicitly, so we have to remove that as well. $makefile =~ s/(\"?)-I\$\(PERL_LIB\)\1//g; # XXX - This is currently unused; not sure if it breaks other MM-users # $makefile =~ s/^pm_to_blib\s+:\s+/pm_to_blib :: /mg; seek MAKEFILE, 0, SEEK_SET; truncate MAKEFILE, 0; print MAKEFILE "$preamble$makefile$postamble" or die $!; close MAKEFILE or die $!; 1; } sub preamble { my ($self, $text) = @_; $self->{preamble} = $text . $self->{preamble} if defined $text; $self->{preamble}; } sub postamble { my ($self, $text) = @_; $self->{postamble} ||= $self->admin->postamble; $self->{postamble} .= $text if defined $text; $self->{postamble} } 1; __END__ #line 544 UnixAgent-2.8/inc/Module/Install/Metadata.pm000066400000000000000000000501071372663377700207770ustar00rootroot00000000000000#line 1 package Module::Install::Metadata; use strict 'vars'; use Module::Install::Base (); use vars qw{$VERSION @ISA $ISCORE}; BEGIN { $VERSION = '1.14'; @ISA = 'Module::Install::Base'; $ISCORE = 1; } my @boolean_keys = qw{ sign }; my @scalar_keys = qw{ name module_name abstract version distribution_type tests installdirs }; my @tuple_keys = qw{ configure_requires build_requires requires recommends bundles resources }; my @resource_keys = qw{ homepage bugtracker repository }; my @array_keys = qw{ keywords author }; *authors = \&author; sub Meta { shift } sub Meta_BooleanKeys { @boolean_keys } sub Meta_ScalarKeys { @scalar_keys } sub Meta_TupleKeys { @tuple_keys } sub Meta_ResourceKeys { @resource_keys } sub Meta_ArrayKeys { @array_keys } foreach my $key ( @boolean_keys ) { *$key = sub { my $self = shift; if ( defined wantarray and not @_ ) { return $self->{values}->{$key}; } $self->{values}->{$key} = ( @_ ? $_[0] : 1 ); return $self; }; } foreach my $key ( @scalar_keys ) { *$key = sub { my $self = shift; return $self->{values}->{$key} if defined wantarray and !@_; $self->{values}->{$key} = shift; return $self; }; } foreach my $key ( @array_keys ) { *$key = sub { my $self = shift; return $self->{values}->{$key} if defined wantarray and !@_; $self->{values}->{$key} ||= []; push @{$self->{values}->{$key}}, @_; return $self; }; } foreach my $key ( @resource_keys ) { *$key = sub { my $self = shift; unless ( @_ ) { return () unless $self->{values}->{resources}; return map { $_->[1] } grep { $_->[0] eq $key } @{ $self->{values}->{resources} }; } return $self->{values}->{resources}->{$key} unless @_; my $uri = shift or die( "Did not provide a value to $key()" ); $self->resources( $key => $uri ); return 1; }; } foreach my $key ( grep { $_ ne "resources" } @tuple_keys) { *$key = sub { my $self = shift; return $self->{values}->{$key} unless @_; my @added; while ( @_ ) { my $module = shift or last; my $version = shift || 0; push @added, [ $module, $version ]; } push @{ $self->{values}->{$key} }, @added; return map {@$_} @added; }; } # Resource handling my %lc_resource = map { $_ => 1 } qw{ homepage license bugtracker repository }; sub resources { my $self = shift; while ( @_ ) { my $name = shift or last; my $value = shift or next; if ( $name eq lc $name and ! $lc_resource{$name} ) { die("Unsupported reserved lowercase resource '$name'"); } $self->{values}->{resources} ||= []; push @{ $self->{values}->{resources} }, [ $name, $value ]; } $self->{values}->{resources}; } # Aliases for build_requires that will have alternative # meanings in some future version of META.yml. sub test_requires { shift->build_requires(@_) } sub install_requires { shift->build_requires(@_) } # Aliases for installdirs options sub install_as_core { $_[0]->installdirs('perl') } sub install_as_cpan { $_[0]->installdirs('site') } sub install_as_site { $_[0]->installdirs('site') } sub install_as_vendor { $_[0]->installdirs('vendor') } sub dynamic_config { my $self = shift; my $value = @_ ? shift : 1; if ( $self->{values}->{dynamic_config} ) { # Once dynamic we never change to static, for safety return 0; } $self->{values}->{dynamic_config} = $value ? 1 : 0; return 1; } # Convenience command sub static_config { shift->dynamic_config(0); } sub perl_version { my $self = shift; return $self->{values}->{perl_version} unless @_; my $version = shift or die( "Did not provide a value to perl_version()" ); # Normalize the version $version = $self->_perl_version($version); # We don't support the really old versions unless ( $version >= 5.005 ) { die "Module::Install only supports 5.005 or newer (use ExtUtils::MakeMaker)\n"; } $self->{values}->{perl_version} = $version; } sub all_from { my ( $self, $file ) = @_; unless ( defined($file) ) { my $name = $self->name or die( "all_from called with no args without setting name() first" ); $file = join('/', 'lib', split(/-/, $name)) . '.pm'; $file =~ s{.*/}{} unless -e $file; unless ( -e $file ) { die("all_from cannot find $file from $name"); } } unless ( -f $file ) { die("The path '$file' does not exist, or is not a file"); } $self->{values}{all_from} = $file; # Some methods pull from POD instead of code. # If there is a matching .pod, use that instead my $pod = $file; $pod =~ s/\.pm$/.pod/i; $pod = $file unless -e $pod; # Pull the different values $self->name_from($file) unless $self->name; $self->version_from($file) unless $self->version; $self->perl_version_from($file) unless $self->perl_version; $self->author_from($pod) unless @{$self->author || []}; $self->license_from($pod) unless $self->license; $self->abstract_from($pod) unless $self->abstract; return 1; } sub provides { my $self = shift; my $provides = ( $self->{values}->{provides} ||= {} ); %$provides = (%$provides, @_) if @_; return $provides; } sub auto_provides { my $self = shift; return $self unless $self->is_admin; unless (-e 'MANIFEST') { warn "Cannot deduce auto_provides without a MANIFEST, skipping\n"; return $self; } # Avoid spurious warnings as we are not checking manifest here. local $SIG{__WARN__} = sub {1}; require ExtUtils::Manifest; local *ExtUtils::Manifest::manicheck = sub { return }; require Module::Build; my $build = Module::Build->new( dist_name => $self->name, dist_version => $self->version, license => $self->license, ); $self->provides( %{ $build->find_dist_packages || {} } ); } sub feature { my $self = shift; my $name = shift; my $features = ( $self->{values}->{features} ||= [] ); my $mods; if ( @_ == 1 and ref( $_[0] ) ) { # The user used ->feature like ->features by passing in the second # argument as a reference. Accommodate for that. $mods = $_[0]; } else { $mods = \@_; } my $count = 0; push @$features, ( $name => [ map { ref($_) ? ( ref($_) eq 'HASH' ) ? %$_ : @$_ : $_ } @$mods ] ); return @$features; } sub features { my $self = shift; while ( my ( $name, $mods ) = splice( @_, 0, 2 ) ) { $self->feature( $name, @$mods ); } return $self->{values}->{features} ? @{ $self->{values}->{features} } : (); } sub no_index { my $self = shift; my $type = shift; push @{ $self->{values}->{no_index}->{$type} }, @_ if $type; return $self->{values}->{no_index}; } sub read { my $self = shift; $self->include_deps( 'YAML::Tiny', 0 ); require YAML::Tiny; my $data = YAML::Tiny::LoadFile('META.yml'); # Call methods explicitly in case user has already set some values. while ( my ( $key, $value ) = each %$data ) { next unless $self->can($key); if ( ref $value eq 'HASH' ) { while ( my ( $module, $version ) = each %$value ) { $self->can($key)->($self, $module => $version ); } } else { $self->can($key)->($self, $value); } } return $self; } sub write { my $self = shift; return $self unless $self->is_admin; $self->admin->write_meta; return $self; } sub version_from { require ExtUtils::MM_Unix; my ( $self, $file ) = @_; $self->version( ExtUtils::MM_Unix->parse_version($file) ); # for version integrity check $self->makemaker_args( VERSION_FROM => $file ); } sub abstract_from { require ExtUtils::MM_Unix; my ( $self, $file ) = @_; $self->abstract( bless( { DISTNAME => $self->name }, 'ExtUtils::MM_Unix' )->parse_abstract($file) ); } # Add both distribution and module name sub name_from { my ($self, $file) = @_; if ( Module::Install::_read($file) =~ m/ ^ \s* package \s* ([\w:]+) [\s|;]* /ixms ) { my ($name, $module_name) = ($1, $1); $name =~ s{::}{-}g; $self->name($name); unless ( $self->module_name ) { $self->module_name($module_name); } } else { die("Cannot determine name from $file\n"); } } sub _extract_perl_version { if ( $_[0] =~ m/ ^\s* (?:use|require) \s* v? ([\d_\.]+) \s* ; /ixms ) { my $perl_version = $1; $perl_version =~ s{_}{}g; return $perl_version; } else { return; } } sub perl_version_from { my $self = shift; my $perl_version=_extract_perl_version(Module::Install::_read($_[0])); if ($perl_version) { $self->perl_version($perl_version); } else { warn "Cannot determine perl version info from $_[0]\n"; return; } } sub author_from { my $self = shift; my $content = Module::Install::_read($_[0]); if ($content =~ m/ =head \d \s+ (?:authors?)\b \s* ([^\n]*) | =head \d \s+ (?:licen[cs]e|licensing|copyright|legal)\b \s* .*? copyright .*? \d\d\d[\d.]+ \s* (?:\bby\b)? \s* ([^\n]*) /ixms) { my $author = $1 || $2; # XXX: ugly but should work anyway... if (eval "require Pod::Escapes; 1") { # Pod::Escapes has a mapping table. # It's in core of perl >= 5.9.3, and should be installed # as one of the Pod::Simple's prereqs, which is a prereq # of Pod::Text 3.x (see also below). $author =~ s{ E<( (\d+) | ([A-Za-z]+) )> } { defined $2 ? chr($2) : defined $Pod::Escapes::Name2character_number{$1} ? chr($Pod::Escapes::Name2character_number{$1}) : do { warn "Unknown escape: E<$1>"; "E<$1>"; }; }gex; } elsif (eval "require Pod::Text; 1" && $Pod::Text::VERSION < 3) { # Pod::Text < 3.0 has yet another mapping table, # though the table name of 2.x and 1.x are different. # (1.x is in core of Perl < 5.6, 2.x is in core of # Perl < 5.9.3) my $mapping = ($Pod::Text::VERSION < 2) ? \%Pod::Text::HTML_Escapes : \%Pod::Text::ESCAPES; $author =~ s{ E<( (\d+) | ([A-Za-z]+) )> } { defined $2 ? chr($2) : defined $mapping->{$1} ? $mapping->{$1} : do { warn "Unknown escape: E<$1>"; "E<$1>"; }; }gex; } else { $author =~ s{E}{<}g; $author =~ s{E}{>}g; } $self->author($author); } else { warn "Cannot determine author info from $_[0]\n"; } } #Stolen from M::B my %license_urls = ( perl => 'http://dev.perl.org/licenses/', apache => 'http://apache.org/licenses/LICENSE-2.0', apache_1_1 => 'http://apache.org/licenses/LICENSE-1.1', artistic => 'http://opensource.org/licenses/artistic-license.php', artistic_2 => 'http://opensource.org/licenses/artistic-license-2.0.php', lgpl => 'http://opensource.org/licenses/lgpl-license.php', lgpl2 => 'http://opensource.org/licenses/lgpl-2.1.php', lgpl3 => 'http://opensource.org/licenses/lgpl-3.0.html', bsd => 'http://opensource.org/licenses/bsd-license.php', gpl => 'http://opensource.org/licenses/gpl-license.php', gpl2 => 'http://opensource.org/licenses/gpl-2.0.php', gpl3 => 'http://opensource.org/licenses/gpl-3.0.html', mit => 'http://opensource.org/licenses/mit-license.php', mozilla => 'http://opensource.org/licenses/mozilla1.1.php', open_source => undef, unrestricted => undef, restrictive => undef, unknown => undef, ); sub license { my $self = shift; return $self->{values}->{license} unless @_; my $license = shift or die( 'Did not provide a value to license()' ); $license = __extract_license($license) || lc $license; $self->{values}->{license} = $license; # Automatically fill in license URLs if ( $license_urls{$license} ) { $self->resources( license => $license_urls{$license} ); } return 1; } sub _extract_license { my $pod = shift; my $matched; return __extract_license( ($matched) = $pod =~ m/ (=head \d \s+ L(?i:ICEN[CS]E|ICENSING)\b.*?) (=head \d.*|=cut.*|)\z /xms ) || __extract_license( ($matched) = $pod =~ m/ (=head \d \s+ (?:C(?i:OPYRIGHTS?)|L(?i:EGAL))\b.*?) (=head \d.*|=cut.*|)\z /xms ); } sub __extract_license { my $license_text = shift or return; my @phrases = ( '(?:under )?the same (?:terms|license) as (?:perl|the perl (?:\d )?programming language)' => 'perl', 1, '(?:under )?the terms of (?:perl|the perl programming language) itself' => 'perl', 1, 'Artistic and GPL' => 'perl', 1, 'GNU general public license' => 'gpl', 1, 'GNU public license' => 'gpl', 1, 'GNU lesser general public license' => 'lgpl', 1, 'GNU lesser public license' => 'lgpl', 1, 'GNU library general public license' => 'lgpl', 1, 'GNU library public license' => 'lgpl', 1, 'GNU Free Documentation license' => 'unrestricted', 1, 'GNU Affero General Public License' => 'open_source', 1, '(?:Free)?BSD license' => 'bsd', 1, 'Artistic license 2\.0' => 'artistic_2', 1, 'Artistic license' => 'artistic', 1, 'Apache (?:Software )?license' => 'apache', 1, 'GPL' => 'gpl', 1, 'LGPL' => 'lgpl', 1, 'BSD' => 'bsd', 1, 'Artistic' => 'artistic', 1, 'MIT' => 'mit', 1, 'Mozilla Public License' => 'mozilla', 1, 'Q Public License' => 'open_source', 1, 'OpenSSL License' => 'unrestricted', 1, 'SSLeay License' => 'unrestricted', 1, 'zlib License' => 'open_source', 1, 'proprietary' => 'proprietary', 0, ); while ( my ($pattern, $license, $osi) = splice(@phrases, 0, 3) ) { $pattern =~ s#\s+#\\s+#gs; if ( $license_text =~ /\b$pattern\b/i ) { return $license; } } return ''; } sub license_from { my $self = shift; if (my $license=_extract_license(Module::Install::_read($_[0]))) { $self->license($license); } else { warn "Cannot determine license info from $_[0]\n"; return 'unknown'; } } sub _extract_bugtracker { my @links = $_[0] =~ m#L<( https?\Q://rt.cpan.org/\E[^>]+| https?\Q://github.com/\E[\w_]+/[\w_]+/issues| https?\Q://code.google.com/p/\E[\w_\-]+/issues/list )>#gx; my %links; @links{@links}=(); @links=keys %links; return @links; } sub bugtracker_from { my $self = shift; my $content = Module::Install::_read($_[0]); my @links = _extract_bugtracker($content); unless ( @links ) { warn "Cannot determine bugtracker info from $_[0]\n"; return 0; } if ( @links > 1 ) { warn "Found more than one bugtracker link in $_[0]\n"; return 0; } # Set the bugtracker bugtracker( $links[0] ); return 1; } sub requires_from { my $self = shift; my $content = Module::Install::_readperl($_[0]); my @requires = $content =~ m/^use\s+([^\W\d]\w*(?:::\w+)*)\s+(v?[\d\.]+)/mg; while ( @requires ) { my $module = shift @requires; my $version = shift @requires; $self->requires( $module => $version ); } } sub test_requires_from { my $self = shift; my $content = Module::Install::_readperl($_[0]); my @requires = $content =~ m/^use\s+([^\W\d]\w*(?:::\w+)*)\s+([\d\.]+)/mg; while ( @requires ) { my $module = shift @requires; my $version = shift @requires; $self->test_requires( $module => $version ); } } # Convert triple-part versions (eg, 5.6.1 or 5.8.9) to # numbers (eg, 5.006001 or 5.008009). # Also, convert double-part versions (eg, 5.8) sub _perl_version { my $v = $_[-1]; $v =~ s/^([1-9])\.([1-9]\d?\d?)$/sprintf("%d.%03d",$1,$2)/e; $v =~ s/^([1-9])\.([1-9]\d?\d?)\.(0|[1-9]\d?\d?)$/sprintf("%d.%03d%03d",$1,$2,$3 || 0)/e; $v =~ s/(\.\d\d\d)000$/$1/; $v =~ s/_.+$//; if ( ref($v) ) { # Numify $v = $v + 0; } return $v; } sub add_metadata { my $self = shift; my %hash = @_; for my $key (keys %hash) { warn "add_metadata: $key is not prefixed with 'x_'.\n" . "Use appopriate function to add non-private metadata.\n" unless $key =~ /^x_/; $self->{values}->{$key} = $hash{$key}; } } ###################################################################### # MYMETA Support sub WriteMyMeta { die "WriteMyMeta has been deprecated"; } sub write_mymeta_yaml { my $self = shift; # We need YAML::Tiny to write the MYMETA.yml file unless ( eval { require YAML::Tiny; 1; } ) { return 1; } # Generate the data my $meta = $self->_write_mymeta_data or return 1; # Save as the MYMETA.yml file print "Writing MYMETA.yml\n"; YAML::Tiny::DumpFile('MYMETA.yml', $meta); } sub write_mymeta_json { my $self = shift; # We need JSON to write the MYMETA.json file unless ( eval { require JSON; 1; } ) { return 1; } # Generate the data my $meta = $self->_write_mymeta_data or return 1; # Save as the MYMETA.yml file print "Writing MYMETA.json\n"; Module::Install::_write( 'MYMETA.json', JSON->new->pretty(1)->canonical->encode($meta), ); } sub _write_mymeta_data { my $self = shift; # If there's no existing META.yml there is nothing we can do return undef unless -f 'META.yml'; # We need Parse::CPAN::Meta to load the file unless ( eval { require Parse::CPAN::Meta; 1; } ) { return undef; } # Merge the perl version into the dependencies my $val = $self->Meta->{values}; my $perl = delete $val->{perl_version}; if ( $perl ) { $val->{requires} ||= []; my $requires = $val->{requires}; # Canonize to three-dot version after Perl 5.6 if ( $perl >= 5.006 ) { $perl =~ s{^(\d+)\.(\d\d\d)(\d*)}{join('.', $1, int($2||0), int($3||0))}e } unshift @$requires, [ perl => $perl ]; } # Load the advisory META.yml file my @yaml = Parse::CPAN::Meta::LoadFile('META.yml'); my $meta = $yaml[0]; # Overwrite the non-configure dependency hashes delete $meta->{requires}; delete $meta->{build_requires}; delete $meta->{recommends}; if ( exists $val->{requires} ) { $meta->{requires} = { map { @$_ } @{ $val->{requires} } }; } if ( exists $val->{build_requires} ) { $meta->{build_requires} = { map { @$_ } @{ $val->{build_requires} } }; } return $meta; } 1; UnixAgent-2.8/inc/Module/Install/Scripts.pm000066400000000000000000000011211372663377700206760ustar00rootroot00000000000000#line 1 package Module::Install::Scripts; use strict 'vars'; use Module::Install::Base (); use vars qw{$VERSION @ISA $ISCORE}; BEGIN { $VERSION = '1.14'; @ISA = 'Module::Install::Base'; $ISCORE = 1; } sub install_script { my $self = shift; my $args = $self->makemaker_args; my $exe = $args->{EXE_FILES} ||= []; foreach ( @_ ) { if ( -f $_ ) { push @$exe, $_; } elsif ( -d 'script' and -f "script/$_" ) { push @$exe, "script/$_"; } else { die("Cannot find script '$_'"); } } } 1; UnixAgent-2.8/inc/Module/Install/Win32.pm000066400000000000000000000035571372663377700201700ustar00rootroot00000000000000#line 1 package Module::Install::Win32; use strict; use Module::Install::Base (); use vars qw{$VERSION @ISA $ISCORE}; BEGIN { $VERSION = '1.14'; @ISA = 'Module::Install::Base'; $ISCORE = 1; } # determine if the user needs nmake, and download it if needed sub check_nmake { my $self = shift; $self->load('can_run'); $self->load('get_file'); require Config; return unless ( $^O eq 'MSWin32' and $Config::Config{make} and $Config::Config{make} =~ /^nmake\b/i and ! $self->can_run('nmake') ); print "The required 'nmake' executable not found, fetching it...\n"; require File::Basename; my $rv = $self->get_file( url => 'http://download.microsoft.com/download/vc15/Patch/1.52/W95/EN-US/Nmake15.exe', ftp_url => 'ftp://ftp.microsoft.com/Softlib/MSLFILES/Nmake15.exe', local_dir => File::Basename::dirname($^X), size => 51928, run => 'Nmake15.exe /o > nul', check_for => 'Nmake.exe', remove => 1, ); die <<'END_MESSAGE' unless $rv; ------------------------------------------------------------------------------- Since you are using Microsoft Windows, you will need the 'nmake' utility before installation. It's available at: http://download.microsoft.com/download/vc15/Patch/1.52/W95/EN-US/Nmake15.exe or ftp://ftp.microsoft.com/Softlib/MSLFILES/Nmake15.exe Please download the file manually, save it to a directory in %PATH% (e.g. C:\WINDOWS\COMMAND\), then launch the MS-DOS command line shell, "cd" to that directory, and run "Nmake15.exe" from there; that will create the 'nmake.exe' file needed by this module. You may then resume the installation process described in README. ------------------------------------------------------------------------------- END_MESSAGE } 1; UnixAgent-2.8/inc/Module/Install/WriteAll.pm000066400000000000000000000026701372663377700210040ustar00rootroot00000000000000#line 1 package Module::Install::WriteAll; use strict; use Module::Install::Base (); use vars qw{$VERSION @ISA $ISCORE}; BEGIN { $VERSION = '1.14'; @ISA = qw{Module::Install::Base}; $ISCORE = 1; } sub WriteAll { my $self = shift; my %args = ( meta => 1, sign => 0, inline => 0, check_nmake => 1, @_, ); $self->sign(1) if $args{sign}; $self->admin->WriteAll(%args) if $self->is_admin; $self->check_nmake if $args{check_nmake}; unless ( $self->makemaker_args->{PL_FILES} ) { # XXX: This still may be a bit over-defensive... unless ($self->makemaker(6.25)) { $self->makemaker_args( PL_FILES => {} ) if -f 'Build.PL'; } } # Until ExtUtils::MakeMaker support MYMETA.yml, make sure # we clean it up properly ourself. $self->realclean_files('MYMETA.yml'); if ( $args{inline} ) { $self->Inline->write; } else { $self->Makefile->write; } # The Makefile write process adds a couple of dependencies, # so write the META.yml files after the Makefile. if ( $args{meta} ) { $self->Meta->write; } # Experimental support for MYMETA if ( $ENV{X_MYMETA} ) { if ( $ENV{X_MYMETA} eq 'JSON' ) { $self->Meta->write_mymeta_json; } else { $self->Meta->write_mymeta_yaml; } } return 1; } 1; UnixAgent-2.8/lib/000077500000000000000000000000001372663377700140605ustar00rootroot00000000000000UnixAgent-2.8/lib/Ocsinventory/000077500000000000000000000000001372663377700165625ustar00rootroot00000000000000UnixAgent-2.8/lib/Ocsinventory/Agent.pm000066400000000000000000000355261372663377700201710ustar00rootroot00000000000000#!/usr/bin/perl package Ocsinventory::Agent; use strict; use warnings; use POSIX ":sys_wait_h"; # THIS IS AN UGLY WORKAROUND FOR # http://rt.cpan.org/Ticket/Display.html?id=38067 use XML::Simple; eval {XMLout("b");}; if ($@){ no strict 'refs'; ${*{"XML::SAX::"}{HASH}{'parsers'}} = sub { return [ { 'Features' => { 'http://xml.org/sax/features/namespaces' => '1' }, 'Name' => 'XML::SAX::PurePerl' }] }; } # END OF THE UGLY FIX! require Exporter; use Ocsinventory::Logger; use Ocsinventory::Agent::XML::Inventory; use Ocsinventory::Agent::XML::Prolog; use Ocsinventory::Agent::Network; use Ocsinventory::Agent::Backend; use Ocsinventory::Agent::AccountConfig; use Ocsinventory::Agent::AccountInfo; use Ocsinventory::Agent::Config; use Ocsinventory::Agent::Hooks; #use Ocsinventory::Agent::Pid; use Ocsinventory::Agent::Common; sub run { # Load setting from the config file my $config = new Ocsinventory::Agent::Config; #$params->{$_} = $config->{$_} foreach (keys %$config); $ENV{LC_ALL} = 'C'; # Turn off localised output for commands $ENV{LANG} = 'C'; # Turn off localised output for commands ##################################### ################ MAIN ############### ##################################### ############################ #### CLI parameters ######## ############################ $config->loadUserParams(); # I close STDERR to avoid error message during the module execution # at the beginning I was doing shell redirection: # my @ret = `cmd 2> /dev/null`; # but this syntax is not supported on (at least) FreeBSD and Solaris # c.f: http://www.perlmonks.org/?node_id=571072 #my $tmp; #open ($tmp, ">&STDERR"); #$params->{"savedstderr"} = $tmp; #if($params->{debug}) { # $params->{verbose} = 1; #} else { # close(STDERR); #} if ($config->{config}{logfile}) { $config->{config}{logger} = 'File'; } my $logger = new Ocsinventory::Logger ({ config => $config->{config} }); my $common = new Ocsinventory::Agent::Common({ logger => $logger, config => $config->{config}, }); # $< == $REAL_USER_ID if ( $< ne '0' ) { $logger->info("You should run this program as super-user."); } if (not $config->{config}{scanhomedirs}) { $logger->debug("--scan-homedirs missing. Don't scan user directories"); } if ($config->{config}{nosoftware}) { $config->{config}{nosoftware} = 1 } # desactivate local mode even if it is set in config file or command line if (defined($config->{config}{nolocal})) { undef $config->{config}{'local'}; } # TODO put that in Ocsinventory::Agent::Config if (!$config->{config}{'stdout'} && !$config->{config}{'local'} && $config->{config}{server} !~ /^http(|s):\/\//) { $logger->debug("the --server passed doesn't have a protocol, assume http as default"); $config->{config}{server} = "http://".$config->{config}{server}.'/ocsinventory'; } ######################## Objects initilisation ############################################################### # The agent can contact different servers. Each server accountconfig is # stored in a specific file: if (!recMkdir ($config->{config}{basevardir})) { if (! -d $ENV{HOME}."/.ocsinventory/var") { $logger->info("Failed to create ".$config->{config}{basevardir}." directory: $!. ". "I'm going to use the home directory instead (~/.ocsinventory/var)."); } $config->{config}{basevardir} = $ENV{HOME}."/.ocsinventory/var"; if (!recMkdir ($config->{config}{basevardir})) { $logger->error("Failed to create ".$config->{config}{basedir}." directory: $!". "The HOSTID will not be written on the harddrive. You may have duplicated ". "entry of this computer in your OCS database"); } $logger->debug("var files are stored in ".$config->{config}{basevardir}); } if (defined($config->{config}{server}) && $config->{config}{server}) { my $dir = $config->{config}{server}; $dir =~ s/\//_/g; $config->{config}{vardir} = $config->{config}{basevardir}."/".$dir; if (defined ($config->{config}{local}) && $config->{config}{local}) { $logger->debug ("--server ignored since you also use --local"); $config->{config}{server} = undef; } } elsif (defined($config->{config}{local}) && $config->{config}{local}) { $config->{config}{vardir} = $config->{config}{basevardir}."/__LOCAL__"; } else { $logger->error("You must set either --server or --local"); } if (!recMkdir ($config->{config}{vardir})) { $logger->error("Failed to create ".$config->{config}{vardir}." directory: $!"); } if (-d $config->{config}{vardir}) { $config->{config}{accountconfig} = $config->{config}{vardir}."/ocsinv.conf"; $config->{config}{accountinfofile} = $config->{config}{vardir}."/ocsinv.adm"; $config->{config}{last_statefile} = $config->{config}{vardir}."/last_state"; $config->{config}{next_timefile} = $config->{config}{vardir}."/next_timefile"; } # Setting SSL CA file path if not set in configuration unless ($config->{config}{ca}) { $config->{config}{ca} = $config->{config}{vardir}."/cacert.pem"; } ################################################################################################################ ########################## load CFG files ###################################################################### my $accountconfig = new Ocsinventory::Agent::AccountConfig({ logger => $logger, config => $config->{config}, }); my $srv = $accountconfig->get('OCSFSERVER'); $config->{config}{server} = $srv if $srv; $config->{config}{deviceid} = $accountconfig->get('DEVICEID'); # Should I create a new deviceID? chomp(my $hostname = `uname -n| cut -d . -f 1`); if ((!$config->{config}{deviceid}) || $config->{config}{deviceid} !~ /\Q$hostname\E-(?:\d{4})(?:-\d{2}){5}/) { my ($YEAR, $MONTH , $DAY, $HOUR, $MIN, $SEC) = (localtime(time))[5,4,3,2,1,0]; $config->{config}{old_deviceid} = $config->{config}{deviceid}; $config->{config}{deviceid} =sprintf "%s-%02d-%02d-%02d-%02d-%02d-%02d", $hostname, ($YEAR+1900), ($MONTH+1), $DAY, $HOUR, $MIN, $SEC; $accountconfig->set('DEVICEID',$config->{config}{deviceid}); } my $accountinfo = new Ocsinventory::Agent::AccountInfo({ logger => $logger, # TODOparams => $params, config => $config->{config}, common => $common, }); # --lazy if ($config->{config}{lazy}) { my $nexttime = (stat($config->{config}{next_timefile}))[9]; if ($nexttime && $nexttime > time) { $logger->info("[Lazy] Must wait until ".localtime($nexttime)." exiting..."); exit 0; } } if ($config->{config}{daemon}) { $logger->debug("Time to call Proc::Daemon"); eval { require Proc::Daemon; }; if ($@) { print "Can't load Proc::Daemon. Is the module installed?"; exit 1; } Proc::Daemon::Init(); $logger->debug("Daemon started"); if (isAgentAlreadyRunning({ logger => $logger, })) { $logger->debug("An agent is already runnnig, exiting..."); exit 1; } } $logger->debug("OCS Agent initialised"); ################# Now we can create a context hash ######################################################### my $context = { installpath => $config->{config}->{vardir}, servername => $config->{config}->{server}, authuser => $config->{config}->{user}, authpwd => $config->{config}->{password}, authrealm => $config->{config}->{realm}, deviceid => $config->{config}->{deviceid}, version => $config->{VERSION}, config => $config->{config}, accountconfig => $accountconfig, accountinfo => $accountinfo, logger => $logger, common => $common, # OCS_AGENT_CMDL => "TOTO", # TODO cmd line parameter changed with the unified agent }; ################################# HERE WE GO !!! ################################################### while (1) { my $exitcode = 0; my $wait; my $child; if ($config->{config}{daemon} || $config->{config}{wait}) { my $serverdelay; if(($config->{config}{wait} eq 'server') || ($config->{config}{wait}!~/^\d+$/)){ $serverdelay = $accountconfig->get('PROLOG_FREQ')*3600; } else { $serverdelay = $config->{config}{wait}; } $wait = int rand($serverdelay?$serverdelay:$config->{config}{delaytime}); $logger->info("Going to sleep for $wait second(s)"); sleep ($wait); } # Create an hook object to use handlers of modules. my $hooks = new Ocsinventory::Agent::Hooks($context); # Using start_handler hook $hooks->run({name => 'start_handler'}); #################### Local Mode ####################### if ($config->{config}{stdout} || $config->{config}{local}) { # TODO, avoid to create Backend at two different places my $backend = new Ocsinventory::Agent::Backend ({ context => $context, }); my $inventory = new Ocsinventory::Agent::XML::Inventory ({ # TODO, check if the accoun{info,config} are needed in localmode backend => $backend, context => $context, }); # Launching inventory $inventory->initialise(); # Using inventory_writer hook $hooks->run({name => 'inventory_handler'}, $inventory); if ($config->{config}{stdout}) { $inventory->printXML(); } elsif ($config->{config}{local}) { $inventory->writeXML(); } } else { ############ I've to contact the server ########################" my $network = new Ocsinventory::Agent::Network ({ accountconfig => $accountconfig, accountinfo => $accountinfo, logger => $logger, config => $config->{config}, common => $common, }); # Adding the network object in $context $context->{network}= $network; my $sendInventory = 1; my $httpresp; my $prologresp; if (!$config->{config}{force}) { my $prolog = new Ocsinventory::Agent::XML::Prolog({ context => $context, }); # Using prolog_writer hook $hooks->run({name => 'prolog_writer'}, $prolog); # Formatting the XML my $prologXML = $prolog->getContent(); $httpresp = $network->sendXML({message => $prologXML}); $prologresp = $network->getXMLResp($httpresp,'Prolog'); if ($prologresp) { # Using prolog_reader hook $hooks->run({name => 'prolog_reader'}, $prologresp->getRawXML()); if (!$prologresp->isInventoryAsked()) { $sendInventory = 0; } } else { # Failed to reach the server if ($config->{config}{lazy}) { # To avoid flooding a heavy loaded server my $previousPrologFreq; if (!($previousPrologFreq = $accountconfig->get('PROLOG_FREQ'))){ $previousPrologFreq = $config->{config}{delaytime}; $logger->info("No previous PROLOG_FREQ found - using fallback delay(".$config->{config}{delaytime}." seconds)"); } else { $logger->info("Previous PROLOG_FREQ found ($previousPrologFreq)"); $previousPrologFreq = $previousPrologFreq*3600; } my $time = time + $previousPrologFreq; utime $time,$time,$config->{config}{next_timefile}; } exit 1 unless $config->{config}{daemon}; $sendInventory = 0; } } if (!$sendInventory) { $logger->info("Don't send the inventory"); } else { # Send the inventory! my $backend = new Ocsinventory::Agent::Backend ({ prologresp => $prologresp, context => $context, }); my $inventory = new Ocsinventory::Agent::XML::Inventory ({ # TODO, check if the accoun{info,config} are needed in localmode backend => $backend, context => $context, }); # Launching inventory $inventory->initialise(); # Using inventory_writer hook $hooks->run({name => 'inventory_handler'}, $inventory); # Formatting the XML my $inventoryXML = $inventory->getContent(); # Sending Inventory $httpresp = $network->sendXML({message => $inventoryXML}); if (my $invresp = $network->getXMLResp($httpresp,'Inventory')) { $inventory->saveLastState(); } else { exit (1) unless $config->{config}{daemon}; } } } # Using end_handler_hook $hooks->run({name => 'end_handler'}); # Avoid zombie process if ($^O ne 'darwin'){ do { $child = waitpid(-1, WNOHANG); } while $child > 0; } else { waitpid(-1, 0); } exit (0) unless $config->{config}{daemon}; } } ########################################## ############Functions##################### ########################################## sub recMkdir { my $dir = shift; my @t = split /\//, $dir; shift @t; return unless @t; my $t; foreach (@t) { $t .= '/'.$_; if ((!-d $t) && (!mkdir $t)) { return; } } 1; } sub isAgentAlreadyRunning { my $params = shift; my $logger = $params->{logger}; # TODO add a workaround if Proc::PID::File is not installed eval { require Proc::PID::File; }; if(!$@) { $logger->debug('Proc::PID::File available, checking for pid file'); if (Proc::PID::File->running()) { $logger->debug('parent process already exists'); return 1; } } return 0; } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/000077500000000000000000000000001372663377700176205ustar00rootroot00000000000000UnixAgent-2.8/lib/Ocsinventory/Agent/AccountConfig.pm000066400000000000000000000036141372663377700227040ustar00rootroot00000000000000package Ocsinventory::Agent::AccountConfig; use strict; use warnings; # AccountConfig read and write the setting for the client given by the server # This file will be overwrite and is not designed to be changed by the user # DESPITE ITS NAME, ACCOUNTCONFIG IS NOT A CONFIG FILE! sub new { my (undef,$params) = @_; my $self = {}; bless $self; $self->{config} = $params->{config}; my $logger = $self->{logger} = $params->{logger}; # Configuration reading $self->{xml} = {}; if ($self->{config}->{accountconfig}) { if (! -f $self->{config}->{accountconfig}) { $logger->debug ('accountconfig file: `'. $self->{config}->{accountconfig}. " doesn't exist. I create an empty one"); $self->write(); } else { eval { $self->{xml} = XML::Simple::XMLin( $self->{config}->{accountconfig}, SuppressEmpty => undef ); }; } } $self; } sub get { my ($self, $name) = @_; my $logger = $self->{logger}; return $self->{xml}->{$name} if $name; return $self->{xml}; } sub set { my ($self, $name, $value) = @_; my $logger = $self->{logger}; $self->{xml}->{$name} = $value; $self->write(); # save the change } sub write { my ($self, $args) = @_; my $logger = $self->{logger}; return unless $self->{config}->{accountconfig}; my $xml = XML::Simple::XMLout( $self->{xml} , RootName => 'CONF', NoAttr => 1 ); my $fault; if (!open CONF, ">".$self->{config}->{accountconfig}) { $fault = 1; } else { print CONF $xml; $fault = 1 if (!close CONF); } if (!$fault) { $logger->debug ("ocsinv.conf updated successfully"); } else { $logger->error ("Can't save setting change in `".$self->{config}->{accountconfig}."'"); } } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/AccountInfo.pm000066400000000000000000000072031372663377700223700ustar00rootroot00000000000000package Ocsinventory::Agent::AccountInfo; use strict; use warnings; sub new { my (undef,$params) = @_; my $self = {}; bless $self; $self->{config} = $params->{config}; $self->{logger} = $params->{logger}; $self->{common} = $params->{common}; my $logger = $self->{logger} = $params->{logger}; if ($self->{config}->{accountinfofile}) { $logger->debug ('Accountinfo file: '. $self->{config}->{accountinfofile}); if (! -f $self->{config}->{accountinfofile}) { $logger->info ("Accountinfo file doesn't exist. I create an empty one."); $self->writeAccountInfoFile(); } else { my $xmladm; eval { $xmladm = $self->{common}->readXml($self->{config}->{accountinfofile}, [ 'ACCOUNTINFO' ]); }; if ($xmladm && exists($xmladm->{ACCOUNTINFO})) { # Store the XML content in a local HASH for(@{$xmladm->{ACCOUNTINFO}}){ if (!$_->{KEYNAME}) { $logger->debug ("Incorrect KEYNAME in ACCOUNTINFO"); } $self->{accountinfo}{ $_->{KEYNAME} } = $_->{KEYVALUE}; } } } } else { $logger->debug("No accountinfo file defined"); } if ($self->{config}->{tag}) { if ($self->{accountinfo}->{TAG}) { $logger->debug("A TAG seems to already exist in the ocsinv.adm file. ". "The -t parameter will be ignored. Don't forget that the TAG value ". "will be ignored by the server unless it has OCS_OPT_ACCEPT_TAG_UPDATE_FROM_CLIENT=1."); } else { $self->{accountinfo}->{TAG} = $self->{config}->{tag}; } } $self; #Because we have already blessed the object } # Add accountinfo stuff to an inventory sub setAccountInfo { my $self = shift; my $inventory = shift; #my $ai = $self->getAll(); $self->{xmlroot}{'CONTENT'}{ACCOUNTINFO} = []; my $ai = $self->{accountinfo}; return unless $ai; foreach (keys %$ai) { push @{$inventory->{xmlroot}{'CONTENT'}{ACCOUNTINFO}}, { KEYNAME => [$_], KEYVALUE => [$ai->{$_}], }; } } sub writeAccountInfoFile { my ($self, $ref) = @_; my $logger = $self->{logger}; my $content; $content->{ACCOUNTINFO} = []; #We clear accountinfo to store the new one undef $self->{accountinfo}; #We get values sent by server if (ref ($ref) =~ /^ARRAY$/) { foreach (@$ref) { $self->{accountinfo}->{$_->{KEYNAME}} = $_->{KEYVALUE} if defined ($_->{KEYNAME}) && defined ($_->{KEYVALUE}); } } elsif (ref ($ref) =~ /^HASH$/) { $self->{accountinfo}->{$ref->{KEYNAME}} = $ref->{KEYVALUE} if defined ($ref->{KEYNAME}) && defined ($ref->{KEYVALUE}); } else { $logger->debug ("Invalid parameter while writing accountinfo file"); } #We feed our XML for accountinfo file foreach (keys %{$self->{accountinfo}}) { push @{$content->{ACCOUNTINFO}}, {KEYNAME => [$_], KEYVALUE => [$self->{accountinfo}{$_}]}; } my $xml=XML::Simple::XMLout($content, RootName => 'ADM', XMLDecl=> ''); #We write accountinfo file my $fault; if (!open ADM, ">".$self->{config}->{accountinfofile}) { $fault = 1; } else { print ADM $xml; $fault = 1 unless close ADM; } if (!$fault) { $logger->debug ("Account info updated successfully"); } else { $logger->error ("Can't save account info in `". $self->{config}->{accountinfofile}); } } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend.pm000066400000000000000000000274231372663377700215150ustar00rootroot00000000000000package Ocsinventory::Agent::Backend; use strict; no strict 'refs'; use warnings; #use ExtUtils::Installed; sub new { my (undef, $params) = @_; my $self = {}; $self->{accountconfig} = $params->{context}->{accountconfig}; $self->{accountinfo} = $params->{context}->{accountinfo}; $self->{config} = $params->{context}->{config}; $self->{inventory} = $params->{inventory}; $self->{common} = $params->{context}->{common}; my $logger = $self->{logger} = $params->{context}->{logger}; $self->{prologresp} = $params->{prologresp}; $self->{modules} = {}; $self->{backendSharedFuncs} = { can_run => sub { my $binary = shift; my $calling_namespace = caller(0); chomp(my $binpath=`which $binary 2>/dev/null`); return unless -x $binpath; $self->{logger}->debug(" - $binary found"); 1 }, can_load => sub { my $module = shift; my $calling_namespace = caller(0); eval "package $calling_namespace; use $module;"; # print STDERR "$module not loaded in $calling_namespace! $!: $@\n" if $@; return if $@; $self->{logger}->debug(" - $module loaded"); # print STDERR "$module loaded in $calling_namespace!\n"; 1; }, can_read => sub { my $file = shift; return unless -r $file; $self->{logger}->debug(" - $file can be read"); 1; }, runcmd => sub { my $cmd = shift; return unless $cmd; # $self->{logger}->debug(" - run $cmd"); return `$cmd`; } }; bless $self; } sub initModList { my $self = shift; my $logger = $self->{logger}; my $config = $self->{config}; my @dirToScan; my @installed_mods; my @installed_files; # This is a workaround for PAR::Packer. Since it resets @INC # I can't find the backend modules to load dynamically. So # I prepare a list and include it. eval "use Ocsinventory::Agent::Backend::ModuleToLoad;"; if (!$@) { $logger->debug("use Ocsinventory::Agent::Backend::ModuleToLoad to get the modules ". "to load. This should not append unless you use the standalone agent built with ". "PAR::Packer (pp)"); push @installed_mods, @Ocsinventory::Agent::Backend::ModuleToLoad::list; } if ($config->{devlib}) { # devlib enable, I only search for backend module in ./lib push (@dirToScan, './lib'); } else { # my ($inst) = ExtUtils::Installed->new(); # eval {@installed_files = # $inst->files('Ocsinventory')}; # ExtUtils::Installed is nice but it needs properly installed package with # .packlist # This is a workaround for 'invalide' installations... foreach (@INC) { next if ! -d || (-l && -d readlink) || /^(\.|lib)$/; push @dirToScan, $_; } } if (@dirToScan) { eval {require File::Find}; if ($@) { $logger->debug("Failed to load File::Find"); } else { # here I need to use $d to avoid a bug with AIX 5.2's perl 5.8.0. It # changes the @INC content if i use $_ directly # thanks to @rgs on irc.perl.org File::Find::find( { wanted => sub { push @installed_files, $File::Find::name if $File::Find::name =~ /Ocsinventory\/Agent\/Backend\/.*\.pm$/; }, follow => 1, follow_skip => 2 } , @dirToScan); } } foreach my $file (@installed_files) { my $t = $file; next unless $t =~ s!.*?(Ocsinventory/Agent/Backend/)(.*?)\.pm$!$1$2!; my $m = join ('::', split /\//, $t); push @installed_mods, $m; } if (!@installed_mods) { $logger->info("ZERO backend module found! Is Ocsinventory-Agent ". "correctly installed? Use the --devlib flag if you want to run the agent ". "directly from the source directory.") } foreach my $m (@installed_mods) { my @runAfter; my @runMeIfTheseChecksFailed; my $enable = 1; if (exists ($self->{modules}->{$m}->{name})) { $logger->debug($m." already loaded."); next; } eval "use $m;"; if ($@) { $logger->debug ("Failed to load $m: $@"); $enable = 0; } my $package = $m."::"; # Load in the module the backendSharedFuncs # foreach my $func (keys %{$self->{backendSharedFuncs}}) { # $package->{$func} = $self->{backendSharedFuncs}->{$func}; # } $self->{modules}->{$m}->{name} = $m; $self->{modules}->{$m}->{done} = 0; $self->{modules}->{$m}->{inUse} = 0; $self->{modules}->{$m}->{enable} = $enable; $self->{modules}->{$m}->{checkFunc} = $package->{"check"}; $self->{modules}->{$m}->{runAfter} = $package->{'runAfter'}; $self->{modules}->{$m}->{runMeIfTheseChecksFailed} = $package->{'runMeIfTheseChecksFailed'}; # $self->{modules}->{$m}->{replace} = \@replace; $self->{modules}->{$m}->{runFunc} = $package->{'run'}; $self->{modules}->{$m}->{mem} = {}; # Load the Storable object is existing or return undef $self->{modules}->{$m}->{storage} = $self->retrieveStorage($m); } # the sort is just for the presentation foreach my $m (sort keys %{$self->{modules}}) { next unless $self->{modules}->{$m}->{checkFunc}; # find modules to disable and their submodules if($self->{modules}->{$m}->{enable} && !$self->runWithTimeout( $m, $self->{modules}->{$m}->{checkFunc}, { accountconfig => $self->{accountconfig}, accountinfo => $self->{accountinfo}, config => $self->{config}, inventory => $self->{inventory}, logger => $self->{logger}, params => $self->{params}, # Compatibiliy with agent 0.0.10 <= prologresp => $self->{prologresp}, mem => $self->{modules}->{$m}->{mem}, storage => $self->{modules}->{$m}->{storage}, common => $self->{common}, })) { $logger->debug ($m." ignored"); foreach (keys %{$self->{modules}}) { $self->{modules}->{$_}->{enable} = 0 if /^$m($|::)/; } } # add submodule in the runAfter array my $t; foreach (split /::/,$m) { $t .= "::" if $t; $t .= $_; if (exists $self->{modules}->{$t} && $m ne $t) { push @{$self->{modules}->{$m}->{runAfter}}, \%{$self->{modules}->{$t}} } } } # Remove the runMeIfTheseChecksFailed if needed foreach my $m (sort keys %{$self->{modules}}) { next unless $self->{modules}->{$m}->{enable}; next unless $self->{modules}->{$m}->{runMeIfTheseChecksFailed}; foreach my $condmod (@{${$self->{modules}->{$m}->{runMeIfTheseChecksFailed}}}) { if ($self->{modules}->{$condmod}->{enable}) { foreach (keys %{$self->{modules}}) { next unless /^$m($|::)/ && $self->{modules}->{$_}->{enable}; $self->{modules}->{$_}->{enable} = 0; $logger->debug ("$_ disabled because of a 'runMeIfTheseChecksFailed' in '$m'\n"); } } } } } sub runMod { my ($self, $params) = @_; my $logger = $self->{logger}; my $m = $params->{modname}; my $common = $params->{common}; return if (!$self->{modules}->{$m}->{enable}); return if ($self->{modules}->{$m}->{done}); $self->{modules}->{$m}->{inUse} = 1; # lock the module # first I run its "runAfter" foreach (@{$self->{modules}->{$m}->{runAfter}}) { if (!$_->{name}) { # The name is defined during module initialisation so if I # can't read it, I can suppose it had not been initialised. $logger->fault ("Module `$m' need to be runAfter a module not found.". "Please fix its runAfter entry or add the module."); } if ($_->{inUse}) { # In use 'lock' is taken during the mod execution. If a module # need a module also in use, we have provable an issue :). $logger->fault ("Circular dependency hell with $m and $_->{name}"); } $self->runMod({ common => $common, modname => $_->{name}, }); } $logger->debug ("Running $m"); if ($self->{modules}->{$m}->{runFunc}) { $self->runWithTimeout( $m, $self->{modules}->{$m}->{runFunc}, { accountconfig => $self->{accountconfig}, accountinfo => $self->{accountinfo}, config => $self->{config}, common => $common, logger => $logger, params => $self->{params}, # For compat with agent 0.0.10 <= prologresp => $self->{prologresp}, mem => $self->{modules}->{$m}->{mem}, storage => $self->{modules}->{$m}->{storage}, common => $self->{common}, } ); } else { $logger->debug("$m has no run() function -> ignored"); } $self->{modules}->{$m}->{done} = 1; $self->{modules}->{$m}->{inUse} = 0; # unlock the module $self->saveStorage($m, $self->{modules}->{$m}->{storage}); } sub feedInventory { my ($self, $params) = @_; my $common = $self->{common}; my $inventory; if ($params->{inventory}) { $inventory = $params->{inventory}; } if (!keys %{$self->{modules}}) { $self->initModList(); } my $begin = time(); foreach my $m (sort keys %{$self->{modules}}) { die ">$m Houston!!!" unless $m; $self->runMod ({ common => $common, modname => $m, }); } # Execution time # $common->setHardware({ETIME => time() - $begin}); $inventory->{xmlroot}->{CONTENT} = $common->{xmltags}; } sub retrieveStorage { my ($self, $m) = @_; my $logger = $self->{logger}; my $storagefile = $self->{config}->{vardir}."/$m.storage"; if (!exists &retrieve) { eval "use Storable;"; if ($@) { $logger->debug("Storable.pm is not available, can't load Backend module data"); return; } } return (-f $storagefile)?retrieve($storagefile):{}; } sub saveStorage { my ($self, $m, $data) = @_; my $logger = $self->{logger}; # Perl 5.6 doesn't provide Storable.pm if (!exists &store) { eval "use Storable;"; if ($@) { $logger->debug("Storable.pm is not available, can't save Backend module data"); return; } } my $storagefile = $self->{config}->{vardir}."/$m.storage"; if ($data && keys (%$data)>0) { store ($data, $storagefile) or die; } elsif (-f $storagefile) { unlink $storagefile; } } sub runWithTimeout { my ($self, $m, $func, $params) = @_; my $logger = $self->{logger}; my $ret; eval { local $SIG{ALRM} = sub { die "alarm\n" }; # NB: \n require my $timeout = $params->{config}{backendCollectTimeout}; alarm $timeout; $ret = &{$func}($params); }; alarm 0; if ($@) { if ($@ ne "alarm\n") { $logger->debug("runWithTimeout(): unexpected error: $@"); } else { $logger->debug("$m killed by a timeout."); return; } } else { return $ret; } } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/000077500000000000000000000000001372663377700211475ustar00rootroot00000000000000UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/AccessLog.pm000066400000000000000000000006301372663377700233470ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::AccessLog; sub run { my $params = shift; my $common = $params->{common}; my ($YEAR, $MONTH , $DAY, $HOUR, $MIN, $SEC) = (localtime (time))[5,4,3,2,1,0]; my $date=sprintf "%02d-%02d-%02d %02d:%02d:%02d", ($YEAR+1900), ($MONTH+1), $DAY, $HOUR, $MIN, $SEC; $common->setAccessLog ({ USERID => 'N/A', LOGDATE => $date }); } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/DeviceID.pm000066400000000000000000000007551372663377700231300ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::DeviceID; # Initialise the DeviceID. In fact this value is a bit specific since # it generates in the main script. sub run { my $params = shift; my $common = $params->{common}; my $config = $params->{config}; my $UsersLoggedIn = join "/", keys %user; if ($config->{old_deviceid}) { $common->setHardware({ OLD_DEVICEID => $config->{old_deviceid} }); } $common->setHardware({ DEVICEID => $config->{deviceid} }); } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/IpDiscover.pm000066400000000000000000000004231372663377700235530ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::IpDiscover; use strict; sub check { my $params = shift; my $prologresp = $params->{prologresp}; my $mem = $params->{mem}; return unless ($prologresp && $prologresp->getOptionsInfoByName("IPDISCOVER")); 1; } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/IpDiscover/000077500000000000000000000000001372663377700232165ustar00rootroot00000000000000UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/IpDiscover/IpDiscover.pm000066400000000000000000000041631372663377700256270ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::IpDiscover::IpDiscover; use strict; use warnings; sub check { my $params = shift; my $common = $params->{common}; $common->can_run ("ipdiscover"); } sub run { my $params = shift; my $common = $params->{common}; my $prologresp = $params->{prologresp}; my $logger = $params->{logger}; # Let's find network interfaces and call ipdiscover on it my $options = $prologresp->getOptionsInfoByName("IPDISCOVER"); my $ipdisc_lat; my $network; if ($options->[0] && exists($options->[0]->{IPDISC_LAT}) && $options->[0]->{IPDISC_LAT}) { $ipdisc_lat = $options->[0]->{IPDISC_LAT}; } if ($options->[0] && exists($options->[0]->{content})) { $network = $options->[0]->{content}; } else { return; } $logger->debug("Scanning the $network network"); my $legacymode; if ( `ipdiscover` =~ /binary ver. (\d+)/ ){ if (!($1>3)) { $legacymode = 1; $logger->debug("ipdiscover ver.$1: legacymode"); } } my $ifname; if ($common->can_run("ip")) { foreach (`ip route`) { if (/^default via (\d+\d.\d+\.\d+\.\d+) dev (\S+).*/) { if ($network = $1 ){ $ifname = $2; last; } } } } elsif ($common->can_run("route")){ foreach (`route -n`) { if (/^(\d+\.\d+\.\d+\.\d+).*?\s(\S+)$/) { if ($network eq $1) { $ifname = $2; last; } elsif (!$ifname && $1 eq "0.0.0.0") { $ifname = $2; } } } } if ($ifname) { my $cmd = "ipdiscover $ifname "; $cmd .= $ipdisc_lat if ($ipdisc_lat && !$legacymode); foreach (`$cmd`) { if (/([\d\.]*)<\/I>([\w\:]*)<\/M>(\S*)<\/N><\/H>/) { $common->addIpDiscoverEntry({ IPADDRESS => $1, MACADDR => $2, NAME => $3 }); } } } } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/IpDiscover/Nmap.pm000066400000000000000000000037751372663377700244630ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::IpDiscover::Nmap; use vars qw($runMeIfTheseChecksFailed); $runMeIfTheseChecksFailed = ["Ocsinventory::Agent::Backend::IpDiscover::IpDiscover"]; use strict; use warnings; sub check { my $params = shift; my $common = $params->{common}; return unless $common->can_run("nmap"); return unless $common->can_load("Nmap::Parser"); # Do we have nmap 3.90 (or >) foreach (`nmap -v 2>&1`) { if (/^Starting Nmap (\d+)\.(\d+)/) { my $release = $1; my $minor = $2; if ($release > 3 || ($release > 3 && $minor >= 90)) { return 1; } } } 0; } sub run { my $params = shift; my $common = $params->{common}; my $prologresp = $params->{prologresp}; my $logger = $params->{logger}; # Let's find network interfaces and call ipdiscover on it my $options = $prologresp->getOptionsInfoByName("IPDISCOVER"); my $network; if ($options->[0] && exists($options->[0]->{content})) { $network = $options->[0]->{content}; } else { return; } unless ($network =~ /^\d+\.\d+\.\d+\.\d+$/) { return; } #Let's go scanning the network and parsing the results $logger->debug("Scanning the $network network"); my $nmaparser = new Nmap::Parser; $nmaparser->parsescan("nmap","-sn","-PR","$network/24"); for my $host ($nmaparser->all_hosts("up")){ my $ip = $host->addr; my $mac = $host->mac_addr; my $hostname = $host->hostname; if ($hostname eq 0) { $hostname = undef; #it's better to send nothing instead of a '0' } if ($mac) { $logger->debug("Host $ip found using Nmap. Adding informations in XML"); # Feeding the Inventory XML $common->addIpDiscoverEntry({ IPADDRESS => $ip, MACADDR => lc($mac), NAME => $hostname, }); } } } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/000077500000000000000000000000001372663377700214705ustar00rootroot00000000000000UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/AIX.pm000066400000000000000000000015071372663377700224520ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::AIX; use strict; use vars qw($runAfter); $runAfter = ["Ocsinventory::Agent::Backend::OS::Generic"]; sub check { my $r; $r = 1 if $^O =~ /^aix$/; $r; } sub run { my $params = shift; my $common = $params->{common}; my @tabOS; my $OSName; my $OSComment; my $OSVersion; my $OSLevel; # Operating system informations chomp($OSName=`uname -s`); # AIX OSVersion = oslevel, OSComment=oslevel -r affiche niveau de maintenance chomp($OSVersion=`oslevel`); chomp($OSLevel=`oslevel -r`); @tabOS=split(/-/,$OSLevel); $OSComment="Maintenance Level :".@tabOS[1]; $OSVersion =~ s/(.0)*$//; $common->setHardware({ OSNAME => "$OSName $OSVersion", OSCOMMENTS => $OSComment, OSVERSION => $OSLevel, }); } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/AIX/000077500000000000000000000000001372663377700221115ustar00rootroot00000000000000UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/AIX/CPU.pm000066400000000000000000000043031372663377700230760ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::AIX::CPU; use strict; use warnings; sub check { 1 } # try to simulate a modern lsattr output on AIX4 sub lsattrForAIX4 { my $device = shift; my @lsattr; my @lsattrtemp=`lsattr -EOl $device -a 'state:type'`; for (@lsattrtemp) { chomp; my $frequency; my (undef,$type)=split /:/; # # On older models, frequency is based on cpu model and uname # if ( $type eq "PowerPC" or $type eq "PowerPC_601" or $type eq "PowerPC_604") { my $uname=`uname -m`; $frequency=112000000 if ($uname=~/E1D|EAD|C1D|R04|C4D|R4D/); $frequency=133000000 if ($uname=~/34M/); $frequency=150000000 if ($uname=~/N4D/); $frequency=200000000 if ($uname=~/X4M|X4D/); $frequency=225000000 if ($uname=~/N4E|K04|K44/); $frequency=320000000 if ($uname=~/N4F/); $frequency=360000000 if ($uname=~/K45/); } elsif ( $type eq "PowerPC_RS64_III" ) { $frequency=400000000; } elsif ( $type eq "PowerPC_620" ) { $frequency=172000000; } else { $frequency=225000000; } push @lsattr,"$device:$frequency\n"; } } sub run { my $params = shift; my $common = $params->{common}; # TODO Need to be able to register different CPU speed! my $processort; my $processorn; my $processors; my $frequency; my @lsdev; my @lsattr; #lsdev -Cc processor -F name #lsattr -EOl proc16 my $aixversion=`uname -v`; for (`lsdev -Cc processor -F name`){ chomp(my $device = $_); if ( $aixversion < 5 ) { @lsattr=lsattrForAIX4($device); } else { @lsattr=`lsattr -EOl $device -a 'state:type:frequency'`; } for (@lsattr) { if ( ! /^#/ && /(.+):(.+):(.+)/ ) { $processorn++; $processort=$2; if ( ($3 % 1000000) >= 50000){ $processors=int (($3/1000000) +1); } else { $processors=int (($3/1000000)); } } } } $processort =~ s/_/ /; $common->setHardware({ PROCESSORT => $processort, PROCESSORN => $processorn, PROCESSORS => $processors }); } 1 UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/AIX/Controller.pm000066400000000000000000000014141372663377700245720ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::AIX::Controller; use strict; sub check { my $params = shift; my $common = $params->{common}; return unless $common->can_run('lsdev'); my @lsdev = `lsdev -Cc adapter -F 'name:type:description'`; return 1 if @lsdev; 0 } sub run { my $params = shift; my $common = $params->{common}; my $name; my $type; my $manufacturer; for (`lsdev -Cc adapter -F 'name:type:description'`){ chomp($_); /^(.+):(.+):(.+)/; my $name = $1; my $type = $2; my $manufacturer = $3; $common->addController({ 'NAME' => $name, 'MANUFACTURER' => $manufacturer, 'TYPE' => $type, }); } } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/AIX/Domains.pm000066400000000000000000000012231372663377700240370ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::AIX::Domains; use strict; sub run { my $params = shift; my $common = $params->{common}; my $domain; # Domain name open RESOLV, "/etc/resolv.conf"; while(){ if (/^(domain|search)\s+(.+)/){ $domain=$2; chomp($domain); } } # If no domain name and no workgroup name (samba), we send "WORKGROUP" # TODO:Check if samba is present and get the windows workgroup or NT domain name unless (defined($domain)){chomp($domain="WORKGROUP");} $domain=~s/^.\.(.)/$1/; $common->setHardware({ WORKGROUP => $domain }); } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/AIX/Drives.pm000066400000000000000000000021061372663377700237020ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::AIX::Drives; use strict; sub check { my $params = shift; my $common = $params->{common}; return unless $common->can_run("df"); 1; } sub run { my $params = shift; my $common = $params->{common}; my $free; my $filesystem; my $total; my $type; my $volumn; my @fs; my @fstype; #Looking for mount points and disk space # Aix option -kP for (`df -kP`) { next if /^Filesystem\s*1024-blocks.*/; if (/^(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\n/) { $volumn = $1; @fs=`lsfs -c $6`; @fstype = split /:/,$fs[1]; $filesystem = $fstype[2]; $total = sprintf("%i",($2/1024)); $free = sprintf("%i",($4/1024)); $type = $6; } next if $filesystem =~ /procfs/; $common->addDrive({ FREE => $free, FILESYSTEM => $filesystem, TOTAL => $total, TYPE => $type, VOLUMN => $volumn }); } } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/AIX/Hardware.pm000066400000000000000000000037231372663377700242110ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::AIX::Hardware; use strict; sub check { 1 } # NOTE: # Q: SSN can also use `uname -n`? What is the best? # A: uname -n since it doesn't need root priv sub run { my $params = shift; my $common = $params->{common}; # Using "type 0" section my( $SystemSerial , $SystemModel, $SystemManufacturer, $BiosManufacturer, $BiosVersion, $BiosDate); # lsvpd my @lsvpd = `lsvpd`; # Remove * (star) at the beginning of lines s/^\*// for (@lsvpd); # Search Firmware Hard my $flag=0; my $fw; for (@lsvpd){ if (/^DS Platform Firmware/) { $flag=1 }; if ( ($flag) && /^RM (.+)/) {$fw=$1;chomp($fw);$fw =~ s/(\s+)$//g;last}; } $flag=0; for (@lsvpd){ if (/^DS System Firmware/) { $flag=1 }; if ( ($flag) && /^RM (.+)/) {$BiosVersion=$1;chomp($BiosVersion);$BiosVersion =~ s/(\s+)$//g;last}; } $flag=0; for (@lsvpd){ if (/^DS System VPD/) { $flag=1 }; if ( ($flag) && /^TM (.+)/) {$SystemModel=$1;chomp($SystemModel);$SystemModel =~ s/(\s+)$//g;}; if ( ($flag) && /^SE (.+)/) {$SystemSerial=$1;chomp($SystemSerial);$SystemSerial =~ s/(\s+)$//g;}; if ( ($flag) && /^FC .+/) {$flag=0;last} } # Fetch the serial number like prtconf do if (! $SystemSerial) { $flag=0; foreach (`lscfg -vpl sysplanar0`) { if ($flag) { if (/\.+(\S*?)$/) { $SystemSerial = $1; } last; } else { $flag = 1 if /\s+System\ VPD/; } } } $BiosManufacturer='IBM'; $SystemManufacturer='IBM'; $BiosVersion .= "(Firmware :".$fw.")"; # Writing data $common->setBios ({ SMANUFACTURER => $SystemManufacturer, SMODEL => $SystemModel, SSN => $SystemSerial, BMANUFACTURER => $BiosManufacturer, BVERSION => $BiosVersion, BDATE => $BiosDate, }); } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/AIX/IPv4.pm000066400000000000000000000011021372663377700232230ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::AIX::IPv4; sub check { my $params = shift; my $common = $params->{common}; $common->can_run("ifconfig") } # Initialise the distro entry sub run { my $params = shift; my $common = $params->{common}; my @ip; # Looking for ip addresses with ifconfig, except loopback # AIX need -a option for (`ifconfig -a`){#ifconfig in the path # AIX ligne inet if(/^\s*inet\s+(\S+).*/){($1=~/127.+/)?next:push @ip, $1}; } $ip=join "/", @ip; $common->setHardware({IPADDR => $ip}); } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/AIX/LVM.pm000066400000000000000000000073061372663377700231130ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::AIX::LVM; use strict; use vars qw($runAfter); $runAfter = ["Ocsinventory::Agent::Backend::OS::AIX::Drives"]; sub check { my $params = shift; my $common = $params->{common}; return unless $common->can_run ("lspv") || $common->can_run('lsvg') || $common->can_run('lslv'); 1 } my $line; sub run { my $params = shift; my $common = $params->{common}; my @physvol; my @volgrp; my $format; my $total; my $total_pps; my $free; my $free_pps; my $lps; my $volume_name; my $volume_size; my $volume_uuid; my $status; my $vg_name; my $type; use constant MB => (1024*1024); # We retrieve the disk list foreach my $line (`lspv`) { chomp; my ($name) = split(/\s+/, $line); push @physvol, $name; } foreach my $nom (@physvol) { foreach my $line (`lspv $nom`){ if ($line =~ /PHYSICAL VOLUME:\s+(\S+)/) { $format = "AIX PV"; } if ($line =~ /PV STATE:\ss+(\S+)/) { $status = $1; } if ($line =~ /FREE PPs:\s+(\d+)/) { $free_pps = $1; } if ($line =~ /TOTAL PPs:\s+(\d+)/) { $total_pps = $1; } if ($line =~ /VOLUME GROUP:\s+(\S+)/) { $vg_name = "VG $1"; } if ($line =~ /PP SIZE:\s+(\d+)/) { $volume_size = $1; } if ($line =~ /PV IDENTIFIER:\s+(\S+)/) { $volume_uuid = $1; } if ($volume_size){ $total = $total_pps * $volume_size; $free = $free_pps * $volume_size; } $common->addDrive({ FREE => $free, FILESYSTEM => $format, TOTAL => $total, TYPE => "DISK", VOLUMN => $status, SERIAL => $volume_uuid }); } } foreach my $nom (@physvol) { foreach my $line (`lslv $nom`){ if ($line =~ /LV IDENTIFIER:\s+(\S+)/) { $volume_uuid = $1; } if ($line =~ /LV STATE:\s+(\S+)/) { $status = $1; } if ($line =~ /PP SIZE:\s+(\d+)/) { $volume_size = $1; } if ($line =~ /LPs:\s+(\d+)/) { $lps = $1; } if ($line =~ /TYPE:\s+(\S+)/) { $type = $1; } $total = $lps * $volume_size; $common->addDrive({ FREE => "", FILESYSTEM => "", TOTAL => $total, TYPE => $type, VOLUMN => $status, SERIAL => $volume_uuid }); } } # We retrieve the disk list foreach my $line (`lsvg`) { chomp; my ($name) = split(/\s+/, $line); push @volgrp, $name; } foreach my $nom (@volgrp) { foreach my $line (`lsvg $nom`){ if ($line =~ /VG IDENTIFIER:\s+(\S+)/) { $volume_uuid = $1; } if ($line =~ /VG STATE:\s+(\S+)/) { $status = $1; } if ($line =~ /TOTAL PPs:\s+(\d+)/) { $volume_size = $1; } if ($line =~ /FREE PPs:\s+(\d+)/) { $free = $1; } $common->addDrive({ FREE => $free, FILESYSTEM => "", TOTAL => $volume_size, TYPE => "AIX VG", VOLUMN => $status, SERIAL => $volume_uuid }); } } } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/AIX/Mem.pm000066400000000000000000000016071372663377700231710ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::AIX::Mem; use strict; sub check { my $params = shift; my $common = $params->{common}; return unless $common->can_run("lsdev"); return unless $common->can_run("which"); return unless $common->can_run("lsattr"); } sub run { my $params = shift; my $common = $params->{common}; my $memory; my $swap; # Memory informations # lsdev -Cc memory -F 'name' -t totmem # lsattr -EOlmem0 my (@lsdev, @lsattr, @grep); $memory=0; @lsdev=`lsdev -Cc memory -F 'name' -t totmem`; for (@lsdev){ $memory += `lsattr -a size -F value -El$_`; } # Paging Space @grep=`lsps -s`; for (@grep){ if ( ! /^Total/){ /^\s*(\d+)\w*\s+\d+.+/; $swap=$1; } } $common->setHardware({ MEMORY => $memory, SWAP => $swap }); } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/AIX/Memory.pm000066400000000000000000000035561372663377700237300ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::AIX::Memory; use strict; sub check { 1 } # TODO create a better check here sub run { my $params = shift; my $common = $params->{common}; my $capacity; my $description; my $numslots; my $speed; my $type; my $n; my $serial; my $mversion; my $caption; my $flag=0; #lsvpd my @lsvpd = `lsvpd`; # Remove * (star) at the beginning of lines s/^\*// for (@lsvpd); $numslots = -1; for (@lsvpd){ if (/^DS Memory DIMM/){ $description = $_; $flag=1; (defined($n))?($n++):($n=0); $description =~ s/DS //; $description =~ s/\n//; } if((/^SZ (.+)/) && ($flag)) {$capacity = $1;} if((/^PN (.+)/) && ($flag)) {$type = $1;} # localisation slot dans type if((/^YL\s(.+)/) && ($flag)) {$caption = "Slot ".$1;} if((/^SN (.+)/) && ($flag)) {$serial = $1;} if((/^VK (.+)/) && ($flag)) {$mversion = $1}; #print $numslots."\n"; # On rencontre un champ FC alors c'est la fin pour ce device if ((/^FC .+/) && ($flag)) { $flag=0; $numslots = $numslots +1; $common->addMemory({ CAPACITY => $capacity, DESCRIPTION => $description, CAPTION => $caption, NUMSLOTS => $numslots, VERSION => $mversion, TYPE => $type, SERIALNUMBER=> $serial, }); } } #$numslots = $numslots +1; # End of Loop # The last *FC ???????? missing # $common->addMemory({ # CAPACITY => $capacity, # DESCRIPTION => $description, # CAPTION => $caption, # NUMSLOTS => $numslots, # VERSION => $mversion, # TYPE => $type, # SERIALNUMBER=> $serial, #}); } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/AIX/Modems.pm000066400000000000000000000010671372663377700236770ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::AIX::Modems; use strict; sub check { my $params = shift; my $common = $params->{common}; $common->can_run("lsdev") } sub run { my $params = shift; my $common = $params->{common}; for (`lsdev -Cc adapter -F 'name:type:description'`){ if (/modem/i && /\d+\s(.+):(.+)$/){ my $name = $1; my $description = $2; $common->addModems({ 'DESCRIPTION' => $description, 'NAME' => $name, }); } } } 1 UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/AIX/Networks.pm000066400000000000000000000100211372663377700242550ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::AIX::Networks; use strict; sub check { my $params = shift; my $common = $params->{common}; $common->can_load("Net::IP qw(:PROC)"); } sub run { my $params = shift; my $common = $params->{common}; my %info; my $ifname; foreach (`lscfg -v -l en*`) { $ifname = "en".$1 if /^\s+ent(\d+)\s+\S+\s+(.+)/; if ($ifname) { $info{$ifname}{type} = $2; $info{$ifname}{status} = "Down"; # default is down if (/Network Address\.+(\w{2})(\w{2})(\w{2})(\w{2})(\w{2})(\w{2})/) { $info{$ifname}{macaddr} = "$1:$2:$3:$4:$5:$6" } } } # Retrieve VLAN information on AIX # Only tested on AIX 6.1 my $pifname; foreach (`lsdev`) { if (/^ent(\d+).*VLAN$/) { $ifname = "en".$1; $pifname = "ent".$1; $info{$ifname}{type} = "VLAN"; $info{$ifname}{status} = "Down"; foreach (`entstat -d $ifname`) { if (/Hardware Address:\s+(.+)$/) { $info{$ifname}{macaddr}="$1"; last; } } foreach (`lsattr -El $pifname`) { if (/^vlan_tag_id\s+(\d+)/) { $info{$ifname}{type}.="$1"; } } } } # uncomment if you prefere verbose information about the link # e.g: 0xe8120000:0xe80c0000:741:3:512:1024:8192:Auto_Negotiation:2048:no:0x000000000000:10000:10:1000:yes:yes:no:no:yes:2048 # etherchannel interfaces # my @lsdev=`lsdev -Cc adapter -s pseudo -t ibm_ech`; # foreach (`lsdev -Cc adapter`) { # next unless /^ent(\d*)\s*(\w*)\s*.*/; # my $ifname = "en".$1; # my $tmpifname = "ent".$1; # #@lsattr=`lsattr -EOl $1 -a 'adapter_names mode netaddr'`; # foreach (`lsattr -EOl $tmpifname`) { # if (/(.+):(.+):(.*)/) { # $info{$ifname}{type}="EtherChannel with : ".$1." (mode :".$2.", ping :".$3.")"; # } # } # $info{$ifname}{status} = 'Down'; # The same # } foreach (split / /,`ifconfig -l`) { # AIX: network interface naming is enX if (/^(en\d+)/) { my $ifname = $1; foreach (`lsattr -E -l $ifname`) { $info{$ifname}{ip} = $1 if /^netaddr \s*([\d*\.?]*).*/i; $info{$ifname}{netmask} = $1 if /^netmask\s*([\d*\.?]*).*/i; $info{$ifname}{status} = $1 if /^state\s*(\w*).*/i; } } } # Looking for the gateways # AIX: the route command doesn't exist. We use netstat -rn instead foreach (`netstat -rn`) { if (/\S+\s+(\S+)\s+\S+\s+\S+\s+\S+\s+(\S+)/) { my $ifname = $2; my $gateway = $1; if (exists ($info{$ifname})) { $info{$ifname}{gateway} = $gateway; } } } foreach my $ifname (sort keys %info) { my $description = $ifname; my $type = $info{$ifname}{type}; my $macaddr = $info{$ifname}{macaddr}; my $status = $info{$ifname}{status}; my $ipaddress = $info{$ifname}{ip}; my $ipmask = $info{$ifname}{netmask}; my $gateway = $info{$ifname}{gateway}; my $ipdhcp = "No"; my $ipsubnet; $status = "Down" unless $ipaddress; # Retrieving ip of the subnet for each interface if ($ipmask and $ipaddress) { # To retrieve the subnet for this iface my $binip = &ip_iptobin ($ipaddress ,4); my $binmask = &ip_iptobin ($ipmask ,4); my $subnet = $binip & $binmask; $ipsubnet = ip_bintoip($subnet,4); } $common->addNetwork({ DESCRIPTION => $description, IPADDRESS => $ipaddress, IPDHCP => $ipdhcp, IPGATEWAY => $gateway, IPMASK => $ipmask, IPSUBNET => $ipsubnet, MACADDR => $macaddr, STATUS => $status, TYPE => $type, }); } } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/AIX/Slots.pm000066400000000000000000000020271372663377700235540ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::AIX::Slots; use strict; sub check { my $params = shift; my $common = $params->{common}; $common->can_run("lsdev") } sub run { my $params = shift; my $common = $params->{common}; my $description; my $designation; my $name; my $status; my @slot; my $flag=0; @slot=`lsdev -Cc bus -F 'name:description'`; for (@slot){ /^(.+):(.+)/; $name = $1; $status = 'available'; $designation = $2; $flag=0; my @lsvpd = `lsvpd`; s/^\*// for (@lsvpd); for (@lsvpd){ if ((/^AX $name/) ) {$flag=1} if ((/^YL (.+)/) && ($flag)){ $description = $2; } if ((/^FC .+/) && $flag) {$flag=0;last} } $common->addSlot({ DESCRIPTION => $description, DESIGNATION => $designation, NAME => $name, STATUS => $status, }); } } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/AIX/Software.pm000066400000000000000000000014521372663377700242430ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::AIX::Software; use strict; use warnings; sub check { my $params = shift; my $common = $params->{common}; # Do not run an package inventory if there is the --nosoftware parameter return if ($params->{config}->{nosoftware}); return unless $common->can_run("lslpp"); 1; } sub run { my $params = shift; my $common = $params->{common}; my @list; my $buff; foreach (`lslpp -c -l`) { my @entry = split /:/,$_; next unless (@entry); next unless ($entry[1]); next if $entry[1] =~ /^device/; $common->addSoftware({ 'COMMENTS' => $entry[6], 'FOLDER' => $entry[0], 'NAME' => $entry[1], 'VERSION' => $entry[2], }); } } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/AIX/Sounds.pm000066400000000000000000000011211372663377700237150ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::AIX::Sounds; use strict; sub check { my $params = shift; my $common = $params->{common}; $common->can_run("lsdev") } sub run { my $params = shift; my $common = $params->{common}; for (`lsdev -Cc adapter -F 'name:type:description'`){ if (/audio/i){ if (/^\S+\s([^:]+):\s*(.+?)(?:\(([^()]+)\))?$/i){ $common->addSound({ 'DESCRIPTION' => $3, 'MANUFACTURER' => $2, 'NAME' => $1, }); } } } } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/AIX/Storages.pm000066400000000000000000000177761372663377700242600ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::AIX::Storages; use strict; #use warning; sub check { `which lsdev 2>&1`; return if($? >> 8)!=0; `which lsattr 2>&1`; ($? >> 8)?0:1} sub run { my $params = shift; my $common = $params->{common}; my(@disques, $device, $model, $capacity, $description, $manufacturer, $n, $i, $flag, @rep, @scsi, @values, @lsattr, $FRU, $status); #lsvpd my @lsvpd = `lsvpd`; s/^\*// for (@lsvpd); #FCP MPIO FC 2145 disks. IBM SDDPCM MPIO Storwize @scsi= (); @lsattr= (); $n=0; @scsi=`lsdev -Cc disk -s fcp -F 'name:description'`; for (@scsi){ chomp $scsi[$n]; /^(.+):(.+)/; $device=$1; $description=$2; @lsattr=`lspv $device 2>&1`; for (@lsattr){ if ( ! ( /^0516-320.*/ ) ){ if (/TOTAL PPs:/ ) { ($capacity,$model) = split(/\(/, $_); ($capacity,$model) = split(/ /,$model); } } else{ $capacity=0; } } $common->addStorages({ MANUFACTURER => "FCP", MODEL => "MPIO Disk", DESCRIPTION => $description, TYPE => 'disk', NAME => $device, DISKSIZE => $capacity }); $n++; } # SAS disks $n=0; @scsi=`lsdev -Cc disk -s sas -F 'name:description'`; for (@scsi){ chomp $scsi[$n]; /^(.+):(.+)/; $device=$1; $description=$2; @lsattr=`lsattr -EOl $device -a 'size_in_mb'`; for (@lsattr){ if (! /^#/ ){ $capacity=$_; chomp($capacity);$capacity =~ s/(\s+)$//; } } for (@lsvpd){ if (/^AX $device/){$flag=1} if ((/^MF (.+)/) && $flag){$manufacturer=$1;chomp($manufacturer);$manufacturer =~ s/(\s+)$//;} if ((/^TM (.+)/) && $flag){$model=$1;chomp($model);$model =~ s/(\s+)$//;} if ((/^FN (.+)/) && $flag){$FRU=$1;chomp($FRU);$FRU =~ s/(\s+)$//;$manufacturer .= ",FRU number :".$FRU} if ((/^FC .+/) && $flag) {$flag=0;last} } $common->addStorages({ MANUFACTURER => $manufacturer, MODEL => $model, DESCRIPTION => $description, TYPE => 'disk', NAME => $device, DISKSIZE => $capacity }); $n++; } #SCSI disks $n=0; @scsi=`lsdev -Cc disk -s scsi -F 'name:description'`; for (@scsi){ chomp $scsi[$n]; /^(.+):(.+)/; $device=$1; $description=$2; @lsattr=`lsattr -EOl $device -a 'size_in_mb'`; for (@lsattr){ if (! /^#/ ){ $capacity= $_; chomp($capacity);$capacity =~ s/(\s+)$//; } } for (@lsvpd){ if(/^AX $device/){$flag=1} if ((/^MF (.+)/) && $flag){$manufacturer=$1;chomp($manufacturer);$manufacturer =~ s/(\s+)$//;} if ((/^TM (.+)/) && $flag){$model=$1;chomp($model);$model =~ s/(\s+)$//;} if ((/^FN (.+)/) && $flag){$FRU=$1;chomp($FRU);$FRU =~ s/(\s+)$//;$manufacturer .= ",FRU number :".$FRU} if ((/^FC .+/) && $flag) {$flag=0;last} } $common->addStorages({ NAME => $device, MANUFACTURER => $manufacturer, MODEL => $model, DESCRIPTION => $description, TYPE => 'disk', DISKSIZE => $capacity }); $n++; } #Virtual disks @scsi= (); @lsattr= (); $n=0; @scsi=`lsdev -Cc disk -s vscsi -F 'name:description'`; for (@scsi){ chomp $scsi[$n]; /^(.+):(.+)/; $device=$1; $description=$2; @lsattr=`lspv $device 2>&1`; for (@lsattr){ if ( ! ( /^0516-320.*/ ) ) { if (/TOTAL PPs:/ ) { ($capacity,$model) = split(/\(/, $_); ($capacity,$model) = split(/ /,$model); } } else { $capacity=0; } } $common->addStorages({ MANUFACTURER => "VIO Disk", MODEL => "Virtual Disk", DESCRIPTION => $description, TYPE => 'disk', NAME => $device, DISKSIZE => $capacity }); $n++; } #CDROM @scsi= (); @lsattr= (); @scsi=`lsdev -Cc cdrom -s scsi -F 'name:description:status'`; $i=0; for (@scsi){ chomp $scsi[$i]; /^(.+):(.+):(.+)/; $device=$1; $status=$3; $description=$2; $capacity=""; if (($status =~ /Available/)){ @lsattr=`lsattr -EOl $device -a 'size_in_mb'`; for (@lsattr){ if (! /^#/ ){ $capacity= $_; chomp($capacity);$capacity =~ s/(\s+)$//; } } $description = $scsi[$n]; for (@lsvpd){ if(/^AX $device/){$flag=1} if ((/^MF (.+)/) && $flag){$manufacturer=$1;chomp($manufacturer);$manufacturer =~ s/(\s+)$//;} if ((/^TM (.+)/) && $flag){$model=$1;chomp($model);$model =~ s/(\s+)$//;} if ((/^FN (.+)/) && $flag){$FRU=$1;chomp($FRU);$FRU =~ s/(\s+)$//;$manufacturer .= ",FRU number :".$FRU} if ((/^FC .+/) && $flag) {$flag=0;last} } $common->addStorages({ NAME => $device, MANUFACTURER => $manufacturer, MODEL => $model, DESCRIPTION => $description, TYPE => 'cd', DISKSIZE => $capacity }); $n++; } $i++; } #TAPE @scsi= (); @lsattr= (); @scsi=`lsdev -Cc tape -s scsi -F 'name:description:status'`; $i=0; for (@scsi){ chomp $scsi[$i]; /^(.+):(.+):(.+)/; $device=$1; $status=$3; $description=$2; $capacity=""; if (($status =~ /Available/)){ @lsattr=`lsattr -EOl $device -a 'size_in_mb'`; for (@lsattr){ if (! /^#/ ){ $capacity= $_; chomp($capacity);$capacity =~ s/(\s+)$//; } } for (@lsvpd){ if(/^AX $device/){$flag=1} if ((/^MF (.+)/) && $flag){$manufacturer=$1;chomp($manufacturer);$manufacturer =~ s/(\s+)$//;} if ((/^TM (.+)/) && $flag){$model=$1;chomp($model);$model =~ s/(\s+)$//;} if ((/^FN (.+)/) && $flag){$FRU=$1;chomp($FRU);$FRU =~ s/(\s+)$//;$manufacturer .= ",FRU number :".$FRU} if ((/^FC .+/) && $flag) {$flag=0;last} } $common->addStorages({ NAME => $device, MANUFACTURER => $manufacturer, MODEL => $model, DESCRIPTION => $description, TYPE => 'tape', DISKSIZE => $capacity }); $n++; } $i++; } #Disquette @scsi= (); @lsattr= (); @scsi=`lsdev -Cc diskette -F 'name:description:status'`; $i=0; for (@scsi){ chomp $scsi[$i]; /^(.+):(.+):(.+)/; $device=$1; $status=$3; $description=$2; $capacity=""; if (($status =~ /Available/)){ @lsattr=`lsattr -EOl $device -a 'fdtype'`; for (@lsattr){ if (! /^#/ ){ $capacity= $_; chomp($capacity);$capacity =~ s/(\s+)$//; } } # On le force en retour taille disquette non affichable $capacity =""; $common->addStorages({ NAME => $device, MANUFACTURER => 'N/A', MODEL => 'N/A', DESCRIPTION => $description, TYPE => 'floppy', DISKSIZE => '' }); $n++; } $i++; } } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/AIX/Users.pm000066400000000000000000000007621372663377700235550ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::AIX::Users; sub check { # Useless check for a posix system i guess my @who = `who 2>/dev/null`; return 1 if @who; return; } # Initialise the distro entry sub run { my $params = shift; my $common = $params->{common}; my %user; # Logged on users for (`who`){ $user{$1} = 1 if /^(\S+)./; } my $UsersLoggedIn = join "/", keys %user; $common->setHardware ({ USERID => $UsersLoggedIn }); } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/AIX/Videos.pm000066400000000000000000000010731372663377700237010ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::AIX::Videos; use strict; sub check { my $params = shift; my $common = $params->{common}; $common->can_run("lsdev"); } sub run { my $params = shift; my $common = $params->{common}; for (`lsdev -Cc adapter -F 'name:type:description'`){ if (/graphics|vga|video/i){ if (/^\S+\s([^:]+):\s*(.+?)(?:\(([^()]+)\))?$/i){ $common->addVideo({ 'CHIPSET' => $1, 'NAME' => $2, }); } } } } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/BSD.pm000066400000000000000000000021201372663377700224310ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::BSD; use strict; use vars qw($runAfter); $runAfter = ["Ocsinventory::Agent::Backend::OS::Generic"]; sub check { $^O =~ /freebsd|openbsd|netbsd|gnukfreebsd|gnuknetbsd/ } sub run { my $params = shift; my $common = $params->{common}; my $OSName; my $OSComment; my $OSVersion; my $OSLevel; my $OSArchi; # Operating system informations chomp($OSName=`uname -s`); chomp($OSVersion=`uname -r`); chomp($OSArchi=`uname -p`); # Retrieve the origin of the kernel configuration file my ($date, $origin, $kernconf); for (`sysctl -n kern.version`) { $date = $1 if /^\S.*\#\d+:\s*(.*)/; ($origin,$kernconf) = ($1,$2) if /^\s+(.+):(.+)$/; } $kernconf =~ s/\/.*\///; # remove the path $OSComment = $kernconf." (".$date.")\n".$origin; # if there is a problem use uname -v chomp($OSComment=`uname -v`) unless $OSComment; $common->setHardware({ OSNAME => $OSName." ".$OSArchi, OSCOMMENTS => $OSComment, OSVERSION => $OSVersion, }); } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/BSD/000077500000000000000000000000001372663377700221005ustar00rootroot00000000000000UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/BSD/Archs/000077500000000000000000000000001372663377700231405ustar00rootroot00000000000000UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/BSD/Archs/Alpha.pm000066400000000000000000000031541372663377700245260ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::BSD::Archs::Alpha; use strict; sub check{ my $arch; chomp($arch=`sysctl -n hw.machine`); $arch eq "alpha"; } sub run { my $params = shift; my $common = $params->{common}; my ($SystemSerial, $SystemModel, $SystemManufacturer, $BiosManufacturer, $BiosVersion, $BiosDate); my ($processort, $processorn, $processors); ### Get system model with "sysctl hw.model" # # example on *BSD # hw.model = AlphaStation 255 4/232 chomp($SystemModel=`sysctl -n hw.model`); $SystemManufacturer = "DEC"; ### Get processor type and speed in dmesg # # NetBSD: AlphaStation 255 4/232, 232MHz, s/n # cpu0 at mainbus0: ID 0 (primary), 21064A-2 # OpenBSD: AlphaStation 255 4/232, 232MHz # cpu0 at mainbus0: ID 0 (primary), 21064A-2 (pass 1.1) # FreeBSD: AlphaStation 255 4/232, 232MHz # CPU: EV45 (21064A) major=6 minor=2 for (`dmesg`) { if (/^cpu[^:]*:\s*(.*)$/i) { $processort = $1; } if (/$SystemModel,\s*(\S+)\s*MHz.*$/) { $processors = $1; } } # number of procs with sysctl (hw.ncpu) chomp($processorn=`sysctl -n hw.ncpu`); # Writing data $common->setBios ({ SMANUFACTURER => $SystemManufacturer, SMODEL => $SystemModel, SSN => $SystemSerial, BMANUFACTURER => $BiosManufacturer, BVERSION => $BiosVersion, BDATE => $BiosDate, }); $common->setHardware({ PROCESSORT => $processort, PROCESSORN => $processorn, PROCESSORS => $processors }); } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/BSD/Archs/I386.pm000066400000000000000000000030421372663377700241260ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::BSD::Archs::I386; # for i386 in case dmidecode is not available use strict; sub check{ my $arch; chomp($arch=`sysctl -n hw.machine`); return if (($arch ne "i386") && ($arch ne "amd64")); # dmidecode must not be present `dmidecode 2>&1`; return if ($? >> 8)==0; 1; } sub run { my $params = shift; my $common = $params->{common}; my ($SystemSerial , $SystemModel, $SystemManufacturer, $BiosManufacturer, $BiosVersion, $BiosDate); my ($processort , $processorn , $processors); # use hw.machine for the system model # TODO see if we can do better chomp($SystemModel=`sysctl -n hw.machine`); # number of procs with sysctl (hw.ncpu) chomp($processorn=`sysctl -n hw.ncpu`); # proc type with sysctl (hw.model) chomp($processort=`sysctl -n hw.model`); # XXX quick and dirty _attempt_ to get proc speed through dmesg for (`dmesg`){ my $tmp; if (/^cpu\S*\s.*\D[\s|\(]([\d|\.]+)[\s|-]mhz/i) { # XXX unsure $tmp = $1; $tmp =~ s/\..*//; $processors=$tmp; last } } # Writing data $common->setBios ({ SMANUFACTURER => $SystemManufacturer, SMODEL => $SystemModel, SSN => $SystemSerial, BMANUFACTURER => $BiosManufacturer, BVERSION => $BiosVersion, BDATE => $BiosDate, }); $common->setHardware({ PROCESSORT => $processort, PROCESSORN => $processorn, PROCESSORS => $processors }); } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/BSD/Archs/Sgimips.pm000066400000000000000000000040101372663377700251040ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::BSD::Archs::Sgimips; use strict; sub check{ my $arch; chomp($arch=`sysctl -n hw.machine`); $arch =~ m/^sgi/; } sub run { my $params = shift; my $common = $params->{common}; my ($SystemSerial , $SystemModel, $SystemManufacturer, $BiosManufacturer, $BiosVersion, $BiosDate); my ($processort , $processorn , $processors ); ### Get system model with "sysctl hw.model" # # example on NetBSD # hw.model = SGI-IP22 # example on OpenBSD # hw.model=SGI-O2 (IP32) chomp($SystemModel=`sysctl -n hw.model`); $SystemManufacturer = "SGI"; ### Get processor type and speed in dmesg # # Examples of dmesg output : # # I) Indy # a) NetBSD # mainbus0 (root): SGI-IP22 [SGI, 6906e152], 1 processor # cpu0 at mainbus0: MIPS R4400 CPU (0x450) Rev. 5.0 with MIPS R4010 FPC Rev. 0.0 # int0 at mainbus0 addr 0x1fbd9880: bus 75MHz, CPU 150MHz # # II) O2 # a) NetBSD # mainbus0 (root): SGI-IP32 [SGI, 8], 1 processor # cpu0 at mainbus0: MIPS R5000 CPU (0x2321) Rev. 2.1 with built-in FPU Rev. 1.0 # b) OpenBSD # mainbus0 (root) # cpu0 at mainbus0: MIPS R5000 CPU rev 2.1 180 MHz with R5000 based FPC rev 1.0 # cpu0: cache L1-I 32KB D 32KB 2 way, L2 512KB direct for (`dmesg`) { if (/$SystemModel\s*\[\S*\s*(\S*)\]/) { $SystemSerial = $1; } if (/cpu0 at mainbus0:\s*(.*)$/) { $processort = $1; } if (/CPU\s*.*\D(\d+)\s*MHz/) { $processors = $1; } } # number of procs with sysctl (hw.ncpu) chomp($processorn=`sysctl -n hw.ncpu`); # Writing data $common->setBios ({ SMANUFACTURER => $SystemManufacturer, SMODEL => $SystemModel, SSN => $SystemSerial, BMANUFACTURER => $BiosManufacturer, BVERSION => $BiosVersion, BDATE => $BiosDate, }); $common->setHardware({ PROCESSORT => $processort, PROCESSORN => $processorn, PROCESSORS => $processors }); } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/BSD/Archs/Sparc.pm000066400000000000000000000056311372663377700245530ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::BSD::Archs::Sparc; use strict; sub check{ my $arch; chomp($arch=`sysctl -n hw.machine`); $arch =~ /^sparc/; } sub run { my $params = shift; my $common = $params->{common}; my( $SystemSerial , $SystemModel, $SystemManufacturer, $BiosManufacturer, $BiosVersion, $BiosDate); my ( $processort , $processorn , $processors ); ### Get system serial with "sysctl kern.hostid" # # sysctl -n kern.hostid gives e.g. 0x807b65c on NetBSD # and 2155570635 on OpenBSD; we keep the hex form chomp ($SystemSerial = `sysctl -n kern.hostid`); if ( $SystemSerial =~ /^\d*$/ ) { # convert to NetBSD format $SystemSerial = sprintf ("0x%x",$SystemSerial); } $SystemSerial =~ s/^0x//; # remove 0x to make it appear as in the firmware ### Get system model and processor type in dmesg # # cannot use "sysctl hw.model" to get SystemModel # because it gives only the CPU on OpenBSD/sparc64 # # Examples of dmesg output : # # I) SPARC # a) NetBSD # mainbus0 (root): SUNW,SPARCstation-20: hostid 72362bb1 # cpu0 at mainbus0: TMS390Z50 v0 or TMS390Z55 @ 50 MHz, on-chip FPU # b) OpenBSD # mainbus0 (root): SUNW,SPARCstation-20 # cpu0 at mainbus0: TMS390Z50 v0 or TMS390Z55 @ 50 MHz, on-chip FPU # # II) SPARC64 # a) NetBSD # mainbus0 (root): SUNW,Ultra-1: hostid 807b65cb # cpu0 at mainbus0: SUNW,UltraSPARC @ 166.999 MHz, version 0 FPU # b) OpenBSD # mainbus0 (root): Sun Ultra 1 SBus (UltraSPARC 167MHz) # cpu0 at mainbus0: SUNW,UltraSPARC @ 166.999 MHz, version 0 FPU # c) FreeBSD # cpu0: Sun Microsystems UltraSparc-I Processor (167.00 MHz CPU) for (`dmesg`) { if (/^mainbus0 \(root\):\s*(.*)$/) { $SystemModel = $1; } if (/^cpu[^:]*:\s*(.*)$/i) { $processort = $1 unless $processort; } } $SystemModel || chomp ($SystemModel = `sysctl -n hw.model`); # for FreeBSD $SystemManufacturer = "SUN"; # some cleanup $SystemModel =~ s/SUNW,//; $SystemModel =~ s/[:\(].*$//; $SystemModel =~ s/^\s*//; $SystemModel =~ s/\s*$//; $processort =~ s/SUNW,//; $processort =~ s/^\s*//; $processort =~ s/\s*$//; # number of procs with "sysctl hw.ncpu" chomp($processorn=`sysctl -n hw.ncpu`); # XXX quick and dirty _attempt_ to get proc speed if ( $processort =~ /(\d+)(\.\d+|)\s*mhz/i ) { # possible decimal point $processors = sprintf("%.0f", "$1$2"); # round number } # Writing data $common->setBios ({ SMANUFACTURER => $SystemManufacturer, SMODEL => $SystemModel, SSN => $SystemSerial, BMANUFACTURER => $BiosManufacturer, BVERSION => $BiosVersion, BDATE => $BiosDate, }); $common->setHardware({ PROCESSORT => $processort, PROCESSORN => $processorn, PROCESSORS => $processors }); } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/BSD/CPU.pm000066400000000000000000000020301372663377700230600ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::BSD::CPU; use strict; sub check { return unless -r "/dev/mem"; 1; } sub run { my $params = shift; my $common = $params->{common}; my $os; my $processort; my $processorn; my $processors; my $family; my $manufacturer; my $serial; chomp($os = `uname -s`); if ($os eq "FreeBSD") { $processors = `sysctl -n hw.clockrate`; } else { $processors = `sysctl -n hw.cpuspeed`; } $processorn = `sysctl -n hw.ncpu`; $processort = `sysctl -n hw.model`; $family = `sysctl -n hw.machine`; $serial = `sysctl -n hw.serialno`; chomp($processort); if ($processort =~ /Intel/) { $manufacturer = "Intel"; } if ($processort =~ /Advanced Micro|AMD/) { $manufacturer = "AMD"; } $common->addCPU({ CPUARCH => $family, MANUFACTURER => $manufacturer, CORES => $processorn, TYPE => $processort, SPEED => $processors, SERIAL => $serial }); } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/BSD/Domains.pm000066400000000000000000000021061372663377700240270ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::BSD::Domains; use strict; sub check { my $hostname; chomp ($hostname = `hostname`); my @domain = split (/\./, $hostname); shift (@domain); return 1 if @domain; -f "/etc/resolv.conf" } sub run { my $params = shift; my $common = $params->{common}; my $domain; my %domain; my @dns_list; my $dns; my $hostname; chomp ($hostname = `hostname`); my @domain = split (/\./, $hostname); shift (@domain); $domain = join ('.',@domain); open RESOLV, "/etc/resolv.conf" or warn; while(){ if (/^nameserver\s+(\S+)/i) { push(@dns_list,$1); } elsif (!$domain) { $domain{$2} = 1 if (/^(domain|search)\s+(.+)/); } } close RESOLV; if (!$domain) { $domain = join "/", keys %domain; } $dns=join("/",@dns_list); # If no domain name, we send "WORKGROUP" $domain = 'WORKGROUP' unless $domain; $common->setHardware({ WORKGROUP => $domain, DNS => $dns }); } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/BSD/Drives.pm000066400000000000000000000016171372663377700236770ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::BSD::Drives; use strict; sub run { my $params = shift; my $common = $params->{common}; my $free; my $filesystem; my $total; my $type; my $volumn; for my $t ("ffs","ufs","zfs") { # OpenBSD has no -m option so use -k to obtain results in kilobytes for (`df -P -t $t -k`){ if (/^(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\n/){ $volumn = $1; $filesystem = $t; $total = sprintf("%i",$2/1024); $free = sprintf("%i",$4/1024); $type = $6; $common->addDrive({ FREE => $free, FILESYSTEM => $filesystem, TOTAL => $total, TYPE => $type, VOLUMN => $volumn }); } } } } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/BSD/IPv4.pm000066400000000000000000000010611372663377700232160ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::BSD::IPv4; sub check { my @ifconfig = `ifconfig -a 2>/dev/null`; return 1 if @ifconfig; return; } # Initialise the distro entry sub run { my $params = shift; my $common = $params->{common}; my @ip; # Looking for ip addresses with ifconfig, except loopback # *BSD need -a option foreach (`ifconfig -a`){ if (/^\s*inet\s+(\S+)/){ ($1=~/127.+/)?next:push @ip, $1 }; } my $ip=join "/", @ip; $common->setHardware({IPADDR => $ip}); } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/BSD/Mem.pm000066400000000000000000000013321372663377700231530ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::BSD::Mem; use strict; sub check { `which sysctl 2>&1`; return 0 if($? >> 8); `which swapctl 2>&1`; return 0 if($? >> 8); 1; }; sub run { my $params = shift; my $common = $params->{common}; my $PhysicalMemory; my $SwapFileSize; # Swap my @bsd_swapctl= `swapctl -sk`; for (@bsd_swapctl){ $SwapFileSize=$1 if /total:\s*(\d+)/i; } # RAM chomp($PhysicalMemory=`sysctl -n hw.physmem`); $PhysicalMemory=$PhysicalMemory/1024; # Send it to inventory object $common->setHardware({ MEMORY => sprintf("%i",$PhysicalMemory/1024), SWAP => sprintf("%i", $SwapFileSize/1024), }); } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/BSD/Networks.pm000066400000000000000000000155611372663377700242620ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::BSD::Networks; use strict; sub check { my $params = shift; my $common = $params->{common}; $common->can_run("ifconfig") && $common->can_load("Net::IP qw(:PROC)") } sub _ipdhcp { my $if = shift; my $path; my $ipdhcp; my $leasepath; foreach ( # XXX BSD paths "/var/db/dhclient.leases.%s", "/var/db/dhclient.leases", # Linux path for some kFreeBSD based GNU system "/var/lib/dhcp3/dhclient.%s.leases", "/var/lib/dhcp3/dhclient.%s.leases", "/var/lib/dhcp/dhclient.leases") { $leasepath = sprintf($_,$if); last if (-e $leasepath); } return undef unless -e $leasepath; if (open DHCP, $leasepath) { my $lease; my $dhcp; my $expire; # find the last lease for the interface with its expire date while(){ $lease = 1 if(/lease\s*{/i); $lease = 0 if(/^\s*}\s*$/); if ($lease) { #inside a lease section if (/interface\s+"(.+?)"\s*/){ $dhcp = ($1 =~ /^$if$/); } #Server IP if (/option\s+dhcp-server-identifier\s+(\d{1,3}(?:\.\d{1,3}){3})\s*;/x) { $ipdhcp = $1; } if (/^\s*expire\s*\d\s*(\d*)\/(\d*)\/(\d*)\s*(\d*):(\d*):(\d*)/x) { $expire=sprintf "%04d%02d%02d%02d%02d%02d",$1,$2,$3,$4,$5,$6; } } } close DHCP or warn; chomp (my $currenttime = `date +"%Y%m%d%H%M%S"`); undef $ipdhcp unless $currenttime <= $expire; } else { warn "Can't open $leasepath\n"; } return $ipdhcp; } # Initialise the distro entry sub run { my $params = shift; my $common = $params->{common}; my $description; my $duplex; my $ipaddress; my $ipmask; my $ipsubnet; my $ipaddress6; my $ipmask6; my $ipsubnet6; my $macaddr; my $mtu; my $speed; my $status; my $type; my @ifconfig = `ifconfig -a`; # -a option required on *BSD # first make the list available interfaces # too bad there's no -l option on OpenBSD my @list; foreach (@ifconfig){ # skip loopback, pseudo-devices and point-to-point interfaces next if /^(lo|fwe|vmnet|sit|pflog|pfsync|enc|strip|plip|sl|ppp)\d+/; if (/^(\S+):/) { push @list , $1; } # new interface name } # for each interface get it's parameters foreach $description (@list) { $ipaddress = $ipmask = $macaddr = $status = $type = $mtu = $speed = $ipaddress6 = $ipmask6 = $ipsubnet6 = undef; # search interface infos @ifconfig = `ifconfig $description`; foreach (@ifconfig){ $ipaddress = $1 if /inet (\S+)/i; if (/inet6 ([\w:]+)\S* prefixlen (\d+)/) { $ipaddress6=$1; $ipmask6=getIPNetmaskV6($2); $ipsubnet6=getSubnetAddressIPv6($ipaddress6,$ipmask6); } $ipmask = $1 if /netmask\s+(\S+)/i; $macaddr = $2 if /(address:|ether|lladdr)\s+(\S+)/i; $status = 1 if /) $mtu = $1 if /mtu (\d+)/i; } # In BSD, netmask is given in hex form my $binmask = sprintf("%b", oct($ipmask)); $ipmask = ip_bintoip($binmask,4); if ($description & $ipaddress ) { $common->addNetwork({ DESCRIPTION => $description, IPADDRESS => $ipaddress, IPDHCP => _ipdhcp($description), IPGATEWAY => getRoute($ipaddress), IPMASK => $ipmask, IPSUBNET => getSubnetAddressIPv4($ipaddress,$ipmask), MACADDR => $macaddr, MTU => $mtu, SPEED => getSpeed($speed), STATUS => $status?"Up":"Down", TYPE => $type, }); # Set default gateway in hardware info $common->setHardware({ DEFAULTGATEWAY => getRoute($ipaddress6) }); } else { $common->addNetwork({ DESCRIPTION => $description, IPADDRESS => $ipaddress6, IPDHCP => _ipdhcp($description), IPGATEWAY => getRoute($ipaddress6), IPMASK => getIPNetmaskV6($ipaddress6), IPSUBNET => getSubnetAddressIPv6($ipaddress6,$ipmask6), MACADDR => $macaddr, MTU => $mtu, SPEED => getSpeed($speed), STATUS => $status?"Up":"Down", TYPE => $type, }); # Set default gateway in hardware info $common->setHardware({ DEFAULTGATEWAY => getRoute($ipaddress6) }); } } } 1; sub getSpeed{ my ($speed)=@_; return unless $speed; if ($speed gt 100 ){ $speed = ($speed/1000)." Gbps"; } else { $speed = $speed." Mbps"; } return $speed; } sub getSubnetAddressIPv4 { my ($address,$mask)=@_; return undef unless $address && $mask; my $binaddress=ip_iptobin($address, 4); my $binmask=ip_iptobin($mask, 4); my $binsubnet=$binaddress & $binmask; return ip_bintoip($binsubnet, 4); } sub getSubnetAddressIPv6 { my ($address,$mask)=@_; return undef unless $address && $mask; my $binaddress = ip_iptobin(ip_expand_address($address, 6),6); my $binmask = ip_iptobin(ip_expand_address($mask, 6),6); my $binsubnet = $binaddress & $binmask; return ip_compress_address(ip_bintoip($binsubnet, 6),6); } sub getIPNetmaskV6 { my ($prefix) = @_; return undef unless $prefix; return ip_compress_address(ip_bintoip(ip_get_mask($prefix, 6), 6),6); } sub getRoute { # Looking for the gateway # 'route show' doesn't work on FreeBSD so we use netstat # XXX IPV4 only my ($prefix) = @_; my $route; return undef unless $prefix; if (ip_is_ipv4($prefix)) { for (`netstat -rn -f inet`){ $route = $1 if /^default\s+(\S+)/i; } } elsif (ip_is_ipv6($prefix)) { for (`netstat -rn -f inet6`){ $route = $1 if /^default\s+(\S+)/i; } } return $route; } =head1 NAME OCSInventory::Agent::Backend::OS::BSD::Networks - Network-related informations =head1 DESCRIPTION This module retrieves network informations. =head1 FUNCTIONS =head2 getSpeed Returns the speed of the card. =head2 getRoute Returns the gateway =back =head2 getIPNetmaskV4 Returns the IP v4 network mask =back =head2 getIPNetmaskV6 Returns the IP v6 network mask =back =head2 getSubnetAddressIPv4 Returns the subnet of ip v4 network =back =head getSubnetAddressIPv6 Returns the subnet of ip v6 network =back UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/BSD/Storages.pm000066400000000000000000000040401372663377700242230ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::BSD::Storages; use strict; sub check { -x '/usr/local/bin/smartctl'; } sub run { my $params = shift; my $common = $params->{common}; my @values; my $devlist; my $osname = `uname -s`; if (chomp($osname) eq "FreeBSD") { $devlist = `/sbin/sysctl -n kern.disks`; } else { $devlist = `/sbin/sysctl -n hw.disknames`; } chomp($devlist); my @devices = split( /\s+/, $devlist ); for my $dev (@devices) { open( CMD, "smartctl -i /dev/$dev |" ); my ( $manufacturer, $serialnumber, $model, $size, $firmware, $type, $desc, $luwwnid ); while () { chomp(); if (/^Vendor:\s+|^Model Family:\s+/i) { $manufacturer = ( split( /:\s+/, $_ ) )[1]; } if (/^Product:\s+|^Device Model:\s+/i) { $model = ( split( /:\s+/, $_ ) )[1]; } if (/^Serial number:\s+/i) { $serialnumber = ( split( /:\s+/, $_ ) )[1]; } if (/^User Capacity:\s+/i) { s/,//g; my $out = ( split( /:\s+/, $_ ) )[1]; $size = ( split( ' ', $out ) )[0] / ( 1024 * 1024 ); } if (/^Revision:\s+|^Firmware Version:\s+/) { $firmware = ( split( /:\s+/, $_ ) )[1]; } if (/^Device type:\s+/) { $type = ( split( /:\s+/, $_ ) )[1]; } if (/^Transport protocol:\s+/) { $desc = ( split( /:\s+/, $_ ) )[1]; } if (/^LU WWN Device Id:\s+/) { $luwwnid = ( split( /:\s+/, $_ ) )[1]; } } $common->addStorages({ NAME => $dev, MANUFACTURER => $manufacturer, MODEL => $model, DESCRIPTION => $desc, TYPE => $type, DISKSIZE => $size, SERIALNUMBER => $serialnumber, FIRMWARE => $firmware, SCSI_UNID => $luwwnid, }); } } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/BSD/Sys.pm000066400000000000000000000004051372663377700232130ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::BSD::Sys; #$LunchAfter = "Ocsinventory::Agent::Backend::OS::Linux::VirtualFs::Sys"; sub check { foreach (`mount`) { return 1 if (/type\ sysfs/); } return; } sub run { # Hum? return ""; } 1 UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/BSD/Uptime.pm000066400000000000000000000016051372663377700237030ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::BSD::Uptime; use strict; sub check { my $boottime = `sysctl -n kern.boottime 2>/dev/null`; return 1 if $boottime; return; } sub run { my $params = shift; my $common = $params->{common}; chomp (my $boottime = `sysctl -n kern.boottime`); $boottime = $1 if $boottime =~ /sec\s*=\s*(\d+)/; chomp (my $currenttime = `date +%s`); my $uptime = $currenttime - $boottime; # Uptime conversion my ($UYEAR, $UMONTH , $UDAY, $UHOUR, $UMIN, $USEC) = (gmtime ($uptime))[5,4,3,2,1,0]; # Write in ISO format $uptime=sprintf "%02d-%02d-%02d %02d:%02d:%02d", ($UYEAR-70), $UMONTH, ($UDAY-1), $UHOUR, $UMIN, $USEC; chomp(my $DeviceType =`uname -m`); # TODO$h->{'CONTENT'}{'HARDWARE'}{'DESCRIPTION'} = [ "$DeviceType/$uptime" ]; $common->setHardware({ DESCRIPTION => "$DeviceType/$uptime" }); } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/Generic.pm000066400000000000000000000001201372663377700233730ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::Generic; use strict; sub run {} 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/Generic/000077500000000000000000000000001372663377700230445ustar00rootroot00000000000000UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/Generic/Dmidecode.pm000066400000000000000000000003761372663377700252650ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::Generic::Dmidecode; use strict; sub check { my $params = shift; my $common = $params->{common}; return unless -r "/dev/mem"; return unless $common->can_run("dmidecode"); 1; } sub run {} 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/Generic/Dmidecode/000077500000000000000000000000001372663377700247215ustar00rootroot00000000000000UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/Generic/Dmidecode/Batteries.pm000066400000000000000000000046011372663377700272020ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::Generic::Dmidecode::Batteries; use strict; sub run { my $params = shift; my $common = $params->{common}; my $dmidecode = `dmidecode`; # TODO retrieve error # some versions of dmidecode do not separate items with new lines # so add a new line before each handle $dmidecode =~ s/\nHandle/\n\nHandle/g; my @dmidecode = split (/\n/, $dmidecode); # add a new line at the end push @dmidecode, "\n"; s/^\s+// for (@dmidecode); my $flag; my $location; my $manufacturer; my $manufacturedate; my $serialnumber; my $name; my $chemistry; my $designcapacity; my $designvoltage; my $sbdsversion; my $maxerror; my $oemspecific; my $numslot; foreach (@dmidecode) { if (/dmi type 22,/i) { # beginning of Memory Device section $flag = 1; $numslot++; } elsif ($flag && /^$/) { # end of section $flag = 0; $common->addBatteries({ LOCATION => $location, MANUFACTURER => $manufacturer, MANUFACTUREDATE => $manufacturedate, SERIALNUMBER => $serialnumber, NAME => $name, CHEMISTRY => $chemistry, DESIGNCAPACITY => $designcapacity, DESIGNVOLTAGE => $designvoltage, SBDSVERSION => $sbdsversion, MAXERROR => $maxerror, OEMSPECIFIC => $oemspecific, }); $location = $manufacturer = $manufacturedate = $serialnumber = $name = $chemistry = $designcapacity = $designvoltage = $sbdsversion = $maxerror = $oemspecific = undef; } elsif ($flag) { # in the section $location = $1 if /^Location:\s*(\S+)/i; $manufacturer = $1 if /^Manufacturer:\s*(.+)/i; $manufacturedate = $1 if /^Manufacture Date:\s*(.+)/i; $serialnumber = $1 if /^Serial Number:\s*(.+)/i; $name = $1 if /^Name:\s*(.+)/i; $chemistry = $1 if /^Chemistry:\s*(.+)/i; $designcapacity = $1 if /^Design Capacity:\s*(.+)/i; $designvoltage = $1 if /^Design Voltage:\s*(.+)/i; $sbdsversion = $1 if /^SBDS Version:\s*(.+)/i; $maxerror = $1 if /^Maximum Error:\s*(.+)/i; $oemspecific = $1 if /^OEM-specific Information:\s*(.+)/i; } } } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/Generic/Dmidecode/Bios.pm000066400000000000000000000063251372663377700261610ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::Generic::Dmidecode::Bios; use strict; sub run { my $params = shift; my $common = $params->{common}; # Parsing dmidecode output # Using "type 0" section my( $SystemSerial , $SystemModel, $SystemManufacturer, $BiosManufacturer, $BiosVersion, $BiosDate, $AssetTag, $MotherboardManufacturer, $MotherboardModel, $MotherboardSerial, $Type ); #System DMI $SystemManufacturer = `dmidecode -s system-manufacturer`; $SystemModel = `dmidecode -s system-product-name`; $SystemSerial = `dmidecode -s system-serial-number`; $AssetTag = `dmidecode -s chassis-asset-tag`; $Type = `dmidecode -s chassis-type`; chomp($SystemModel); $SystemModel =~ s/^(#.*\n)+//g; $SystemModel =~ s/Invalid.*$//g; chomp($SystemManufacturer); $SystemManufacturer =~ s/^(#.*\n)+//g; $SystemManufacturer =~ s/Invalid.*$//g; chomp($SystemSerial); $SystemSerial =~ s/^(#.*\n)+//g; $SystemSerial =~ s/Invalid.*$//g; # System serial number can be filled with whitespace (e.g. Intel NUC) $SystemSerial =~ s/^\s+|\s+$//g; chomp($AssetTag); $AssetTag =~ s/^(#.*\n)+//g; $AssetTag =~ s/Invalid.*$//g; chomp($Type); $Type =~ s/^(#.*\n)+//g; $Type =~ s/Invalid.*$//g; #Motherboard DMI $MotherboardManufacturer = `dmidecode -s baseboard-manufacturer`; $MotherboardModel = `dmidecode -s baseboard-product-name`; $MotherboardSerial = `dmidecode -s baseboard-serial-number`; chomp($MotherboardModel); $MotherboardModel =~ s/^(#.*\n)+//g; $MotherboardModel =~ s/Invalid.*$//g; chomp($MotherboardManufacturer); $MotherboardManufacturer =~ s/^(#.*\n)+//g; $MotherboardManufacturer =~ s/Invalid.*$//g; chomp($MotherboardSerial); $MotherboardSerial =~ s/^(#.*\n)+//g; $MotherboardSerial =~ s/Invalid.*$//g; #BIOS DMI $BiosManufacturer = `dmidecode -s bios-vendor`; $BiosVersion = `dmidecode -s bios-version`; $BiosDate = `dmidecode -s bios-release-date`; chomp($BiosManufacturer); $BiosManufacturer =~ s/^(#.*\n)+//g; $BiosManufacturer =~ s/Invalid.*$//g; chomp($BiosVersion); $BiosVersion =~ s/^(#.*\n)+//g; $BiosVersion =~ s/Invalid.*$//g; chomp($BiosDate); $BiosDate =~ s/^(#.*\n)+//g; $BiosDate =~ s/Invalid.*$//g; # If serial number is empty, assign mainboard serial (e.g Intel NUC) if (!$SystemSerial) { $SystemSerial = $MotherboardSerial; } # Some bioses don't provide a serial number so I check for CPU ID (e.g: server from dedibox.fr) my @cpu; if (!$SystemSerial || $SystemSerial =~ /^0+$/) { @cpu = `dmidecode -t processor`; for (@cpu){ if (/ID:\s*(.*)/i){ $SystemSerial = $1; } } } # Writing data $common->setBios ({ ASSETTAG => $AssetTag, SMANUFACTURER => $SystemManufacturer, SMODEL => $SystemModel, SSN => $SystemSerial, BMANUFACTURER => $BiosManufacturer, BVERSION => $BiosVersion, BDATE => $BiosDate, MMANUFACTURER => $MotherboardManufacturer, MMODEL => $MotherboardModel, MSN => $MotherboardSerial, TYPE => $Type, }); } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/Generic/Dmidecode/Memory.pm000066400000000000000000000074231372663377700265350ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::Generic::Dmidecode::Memory; use strict; sub run { my $params = shift; my $common = $params->{common}; my $dmidecode; my @dmidecode; my %dmidecode; my $capacity; my $speed; my $type; my $numslot; my $serialnumber; my $manufacturer; my $caption; my $description; # DMI type 17 $dmidecode = `dmidecode -t 17`; @dmidecode = split (/Handle\s/i, $dmidecode); shift @dmidecode; $numslot = 0; foreach (@dmidecode) { $capacity = $speed = $type = $serialnumber = $manufacturer = $caption = $description = 0; $caption = $1 if /\s\sLocator:\s([\w\d_\-\s#]+)\n/i; $speed = $1 if /Speed:\s([\w\d]+)/i; $type = $1 if /Type:\s([\s\w]+)\n/i; $description = $1 if /Type\sDetail:\s([\s\w]+)\n/i; $manufacturer = $1 if /Manufacturer:\s([\w\d\-\_\s]+)\n/i; $serialnumber = $1 if /Serial\sNumber:\s([\w\d\-\_\s]+)\n/i; if (/Size:\s(\d+)\s(MB|GB|TB|MByte|GByte|TByte)/i) { if($2 eq "MB" or $2 eq "MByte") { $capacity = $1; } elsif($2 eq "GB" or $2 eq "GByte") { $capacity = $1*1024; } elsif($2 eq "TB" or $2 eq "TByte") { $capacity = $1*1024*1024; } } if (/DMI type 17/i) { $dmidecode{$numslot}{caption} = $caption ? $caption : ""; $dmidecode{$numslot}{description} = $description ? $description : ""; $dmidecode{$numslot}{speed} = $speed ? $speed : ""; $dmidecode{$numslot}{type} = $type ? $type : ""; $dmidecode{$numslot}{manufacturer} = $manufacturer ? $manufacturer : ""; $dmidecode{$numslot}{serialnumber} = $serialnumber ? $serialnumber : ""; $dmidecode{$numslot}{capacity} = $capacity ? $capacity : ""; $numslot++; } } # DMI type 6 if type 17 is not available if (!$numslot) { $dmidecode = `dmidecode -t 6`; # TODO retrieve error @dmidecode = split (/Handle\s/i, $dmidecode); shift @dmidecode; $numslot = 0; foreach (@dmidecode) { $capacity = $speed = $type = $caption = 0; $caption = $1 if /Socket Designation:\s([\w\d_\-\s#]+)\n/i; $capacity = $1 if /Installed\sSize:\s(\d+)/i; $speed = $1 if /Speed:\s([\w\d]+)/i; $type = $1 if /Type:\s([\s\w]+)\n/i; if (/Size:\s(\d+)\s(MB|GB|TB|MByte|GByte|TByte)/i) { if($2 eq "MB" or $2 eq "MByte") { $capacity = $1; } elsif($2 eq "GB" or $2 eq "GByte") { $capacity = $1*1024; } elsif($2 eq "TB" or $2 eq "TByte") { $capacity = $1*1024*1024; } } if (/DMI type 6/i) { $dmidecode{$numslot}{caption} = $caption ? $caption : ""; $dmidecode{$numslot}{description} = $description ? $description : ""; $dmidecode{$numslot}{speed} = $speed ? $speed : ""; $dmidecode{$numslot}{type} = $type ? $type : ""; $dmidecode{$numslot}{capacity} = $capacity ? $capacity : ""; $numslot++; } } } foreach (sort {$a <=> $b} keys %dmidecode) { $common->addMemory({ CAPACITY => $dmidecode{$_}{capacity}, SPEED => $dmidecode{$_}{speed}, TYPE => $dmidecode{$_}{type}, MANUFACTURER => $dmidecode{$_}{manufacturer}, SERIALNUMBER => $dmidecode{$_}{serialnumber}, NUMSLOTS => $_, CAPTION => $dmidecode{$_}{caption}, DESCRIPTION => $dmidecode{$_}{description}, }); } } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/Generic/Dmidecode/Ports.pm000066400000000000000000000024431372663377700263710ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::Generic::Dmidecode::Ports; use strict; sub run { my $params = shift; my $common = $params->{common}; my $dmidecode = `dmidecode`; # TODO retrieve error # some versions of dmidecode do not separate items with new lines # so add a new line before each handle $dmidecode =~ s/\nHandle/\n\nHandle/g; my @dmidecode = split (/\n/, $dmidecode); # add a new line at the end push @dmidecode, "\n"; s/^\s+// for (@dmidecode); my $flag; my $caption; my $description; my $name; my $type; foreach (@dmidecode) { if (/dmi type 8,/i) { $flag = 1; } elsif ($flag && /^$/){ # end of section $flag = 0; $common->addPorts({ CAPTION => $caption, DESCRIPTION => $description, NAME => $name, TYPE => $type, }); $caption = $description = $name = $type = undef; } elsif ($flag) { $caption = $1 if /^external connector type\s*:\s*(.+)/i; $description = $1 if /^internal connector type\s*:\s*(.+)/i; $name = $1 if /^internal reference designator\s*:\s*(.+)/i; $type = $1 if /^port type\s*:\s*(.+)/i; } } } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/Generic/Dmidecode/Psu.pm000066400000000000000000000021211372663377700260220ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::Generic::Dmidecode::Psu; use strict; use warnings; sub run { my $params = shift; my $common = $params->{common}; my $infos=$common->getDmidecodeInfos(); my $psu; foreach my $info (@{$infos->{39}}) { next if $info->{'Type'} && $info->{'Type'} eq 'Battery'; $psu->{NAME}=$1 if ($info =~ /Name:\s*(.*)/i); $psu->{LOCATION}=$1 if ($info =~ /Location:\s*(.*)/i); $psu->{STATUS}=$1 if ($info =~ /Status:\s*(.*)/i); $psu->{SERIALNUMBER}=$1 if ($info =~ /Serial Number:\s*(.*)/i); $psu->{PLUGGED}=$1 if ($info =~ /Plugged:\s*(.*)/i); $psu->{HOTREPLACEABLE}=$1 if ($info =~ /Hot Replaceable:\s*(.*)/i); $psu->{POWERMAX}=$1 if ($info =~ /Max Power Capacity:\s*(.*)/i); $psu->{MANUFACTURER}=$1 if ($info =~ /Manufacturer:\s*(.*)/i); $psu->{PARTNUMBER}=$1 if ($info =~ /Model Part Number:\s*(.*)/i); next unless ($psu); next unless ($psu->{'NAME'} || $psu->{'SERIALNUMBER'} || $psu->{'PARTNUMBER'}); $common->addPSU($psu); } } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/Generic/Dmidecode/Slots.pm000066400000000000000000000023511372663377700263640ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::Generic::Dmidecode::Slots; use strict; sub run { my $params = shift; my $common = $params->{common}; my $dmidecode = `dmidecode`; # some versions of dmidecode do not separate items with new lines # so add a new line before each handle $dmidecode =~ s/\nHandle/\n\nHandle/g; my @dmidecode = split (/\n/, $dmidecode); # add a new line at the end push @dmidecode, "\n"; s/^\s+// for (@dmidecode); my $flag; my $description; my $designation; my $name; my $status; foreach (@dmidecode) { if (/dmi type 9,/i) { $flag=1; } elsif ($flag && /^$/) { $flag=0; $common->addSlot({ DESCRIPTION => $description, DESIGNATION => $designation, NAME => $name, STATUS => $status, }); $description = $designation = $name = $status = undef; } elsif ($flag) { $description = $1 if /^type\s*:\s*(.+)/i; $designation = $1 if /^id\s*:\s*(.+)/i; $name = $1 if /^designation\s*:\s*(.+)/i; $status = $1 if /^current usage\s*:\s*(.+)/i; }; } } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/Generic/Dmidecode/UUID.pm000066400000000000000000000007221372663377700260260ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::Generic::Dmidecode::UUID; use strict; sub check { my $params = shift; my $common = $params->{common}; return $common->can_run('dmidecode') } sub run { my $params = shift; my $common = $params->{common}; my $uuid; $uuid = `dmidecode -s system-uuid`; chomp($uuid); $uuid =~ s/^#+\s+$//g; $uuid =~ s/Invalid.*$//g; $common->setHardware({ UUID => $uuid, }); } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/Generic/Hostname.pm000066400000000000000000000012241372663377700251570ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::Generic::Hostname; sub check { my $params = shift; my $common = $params->{common}; return 1 if $common->can_load ("Sys::Hostname"); return 1 if $common->can_run ("hostname"); 0; } # Initialise the distro entry sub run { my $params = shift; my $common = $params->{common}; my $hostname; if ($common->can_load("Sys::Hostname")) { $hostname = Sys::Hostname::hostname(); } else { chomp ( $hostname = `hostname` ); # TODO: This is not generic. } $hostname =~ s/\..*//; # keep just the hostname $common->setHardware ({NAME => $hostname}); } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/Generic/Ipmi.pm000066400000000000000000000044021372663377700243000ustar00rootroot00000000000000# # OcsInventory agent - IPMI lan channel report # # Copyright (c) 2008 Jean Parpaillon # # The Intelligent Platform Management Interface (IPMI) specification # defines a set of common interfaces to a computer system which system # administrators can use to monitor system health and manage the # system. The IPMI consists of a main controller called the Baseboard # Management Controller (BMC) and other satellite controllers. # # The BMC can be fetched through client like OpenIPMI drivers or # through the network. Though, the BMC hold a proper MAC address. # # This module reports the MAC address and, if any, the IP # configuration of the BMC. This is reported as a standard NIC. # package Ocsinventory::Agent::Backend::OS::Generic::Ipmi; sub check { my $params = shift; my $common = $params->{common}; return unless $common->can_run("ipmitool") && $common->can_load("Net::IP qw(:PROC)"); my @ipmitool = `ipmitool lan print 2> /dev/null`; return unless @ipmitool; } # Initialise the distro entry sub run { my $params = shift; my $common = $params->{common}; my $description; my $ipaddress; my $ipgateway; my $ipmask; my $ipsubnet; my $macaddr; my $status; my $type; foreach (`LANG=C ipmitool lan print 2> /dev/null`) { if (/^IP Address\s+:\s+(\d+\.\d+\.\d+\.\d+)/) { $ipaddress = $1; } if (/^Default Gateway IP\s+:\s+(\d+\.\d+\.\d+\.\d+)/) { $ipgateway = $1; } if (/^Subnet Mask\s+:\s+(\d+\.\d+\.\d+\.\d+)/) { $ipmask = $1; } if (/^MAC Address\s+:\s+([0-9a-f]{2}(:[0-9a-f]{2}){5})/) { $macaddr = $1; } } $description = 'bmc'; my $binip = &ip_iptobin ($ipaddress, 4); my $binmask = &ip_iptobin ($ipmask, 4); my $binsubnet = $binip & $binmask; $ipsubnet = ip_bintoip($binsubnet, 4); $status = 1 if $ipaddress != '0.0.0.0'; $type = 'Ethernet'; $common->addNetwork({ DESCRIPTION => $description, IPADDRESS => $ipaddress, IPDHCP => "", IPGATEWAY => $ipgateway, IPMASK => $ipmask, IPSUBNET => $ipsubnet, MACADDR => $macaddr, STATUS => $status?"Up":"Down", TYPE => $type, }); } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/Generic/Lspci.pm000066400000000000000000000002761372663377700244610ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::Generic::Lspci; use strict; sub check { my $params = shift; my $common = $params->{common}; $common->can_run("lspci") } sub run {} 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/Generic/Lspci/000077500000000000000000000000001372663377700241165ustar00rootroot00000000000000UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/Generic/Lspci/Controllers.pm000066400000000000000000000034571372663377700267730ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::Generic::Lspci::Controllers; use strict; sub check { my $params = shift; my $common = $params->{common}; $common->can_run("lspci") } sub run { my $params = shift; my $common = $params->{common}; my $driver; my $name; my $manufacturer; my $pciid; my $pcislot; my $type; my $lspci_version; my $command = "lspci -vvv 2>/dev/null"; #We get the current lspci version `lspci --version` =~ m/lspci\sversion\s(\d+.*)/ ; $lspci_version=$1; $lspci_version = $common->convertVersion($lspci_version,3); if ($lspci_version >= 224) { #More informations since version 2.2.4 $command = "lspci -vvv -nn 2>/dev/null"; } foreach(`$command`){ if (/^(\S+)\s+(\w+.*?):\s(.*)/) { $pcislot = $1; $name = $2; $manufacturer = $3; if ($manufacturer =~ s/ \((rev \S+)\)//) { $type = $1; } $manufacturer =~ s/\ *$//; # clean up the end of the string $manufacturer =~ s/\s+\(prog-if \d+ \[.*?\]\)$//; # clean up the end of the string if ($manufacturer =~ s/ \[([A-z\d]+:[A-z\d]+)\]$//) { $pciid = $1; } } if ($pcislot && /^\s+Kernel driver in use: (\w+)/) { $driver = $1; } if ($pcislot && /^$/) { $common->addController({ 'DRIVER' => $driver, 'NAME' => $name, 'MANUFACTURER' => $manufacturer, 'PCIID' => $pciid, 'PCISLOT' => $pcislot, 'TYPE' => $type, }); $driver = $name = $pciid = $pcislot = $manufacturer = $type = undef; } } } 1 UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/Generic/Lspci/Modems.pm000066400000000000000000000006701372663377700257030ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::Generic::Lspci::Modems; use strict; sub run { my $params = shift; my $common = $params->{common}; foreach(`lspci`){ if (/modem/i && /\d+\s(.+):\s*(.+)$/){ my $name = $1; my $description = $2; $common->addModems({ 'DESCRIPTION' => $description, 'NAME' => $name, }); } } } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/Generic/Lspci/Sounds.pm000066400000000000000000000006411372663377700257300ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::Generic::Lspci::Sounds; use strict; sub run { my $params = shift; my $common = $params->{common}; foreach(`lspci`){ if (/audio/i && /^\S+\s([^:]+):\s*(.+?)(?:\(([^()]+)\))?$/i){ $common->addSound({ 'DESCRIPTION' => $3, 'MANUFACTURER' => $2, 'NAME' => $1, }); } } } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/Generic/Lspci/Videos.pm000066400000000000000000000020041372663377700257010ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::Generic::Lspci::Videos; use strict; my $memory; my $chipset; my $name; sub run { my $params = shift; my $common = $params->{common}; foreach(`lspci`){ if(/graphics|vga|video|display/i && /^([0-9a-f][0-9a-f]:[0-9a-f][0-9a-f].[0-9a-f])\s([^:]+):\s*(.+?)(?:\(([^()]+)\))?$/i){ my $slot = $1; $chipset = $2; $name = $3; if (defined $slot) { my @detail = `lspci -v -s $slot 2>/dev/null`; $memory = 0; foreach my $m (@detail) { if ($m =~ /.*Memory.*\s+\(.*-bit,\sprefetchable\)\s\[size=(\d*)M\]/) { $memory += $1; } } # Don't record zero memory $memory = undef if $memory == 0; } $common->addVideo({ 'CHIPSET' => $chipset, 'NAME' => $name, 'MEMORY' => $memory, }); } } } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/Generic/Lsusb.pm000066400000000000000000000002761372663377700244770ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::Generic::Lsusb; use strict; sub check { my $params = shift; my $common = $params->{common}; $common->can_run("lsusb") } sub run {} 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/Generic/Lsusb/000077500000000000000000000000001372663377700241345ustar00rootroot00000000000000UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/Generic/Lsusb/Usb.pm000066400000000000000000000032451372663377700252270ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::Generic::Lsusb::Usb; use strict; use Config; use Data::Dumper; my $vendor; my $product; my $interface; my $bus; my $device; my $serial; my $protocol; my $id; sub run { my $params = shift; my $common = $params->{common}; foreach (`lsusb`) { if (/^Bus\s+(\d+)\sDevice\s(\d*):\sID\s(\d+):(\d+)*/i) { next if (grep (/$4/,qw(0001 0002 0024))); $bus=$1; $device=$2; #if (defined $bus && defined $device) { my @detail = `lsusb -v -s $bus:$device 2>/dev/null`; foreach my $d (@detail) { if ($d =~ /^\s*iManufacturer\s*\d+\s*(.*)/i) { $vendor = $1; } elsif ($d =~ /^\s*iProduct\s*\d+\s*(.*)/i) { $product = $1; } elsif ($d =~ /^\s*iSerial\s*\d+\s(.*)/i) { $serial = $1; #} elsif ($d =~ /^\s*bInterfaceProtocol\s*\d\s(.*)/i) { } elsif ($d =~ /^\s*bInterfaceClass\s*\d+\s*(.*)/i) { #$protocol = $1 unless defined $protocol || $1 eq 'None'; $protocol = $1; #} elsif ($d =~ /^\s*iInterface\s*\d\s(\w+)\s(.*)/i){ } elsif ($d =~ /^\s*bInterfaceSubClass\s*\d+\s(.*)/i){ $interface = $1; } } # Add information to $current $common->addUsb({ DESCRIPTION => $product, INTERFACE => $interface, MANUFACTURER => $vendor, SERIAL => $serial, TYPE => $protocol, }); } } } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/Generic/Packaging.pm000066400000000000000000000004111372663377700252620ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::Generic::Packaging; use strict; sub check { my $params = shift; # Do not run an package inventory if there is the --nosoftware parameter return if ($params->{config}->{nosoftware}); 1; } sub run{} 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/Generic/Packaging/000077500000000000000000000000001372663377700247305ustar00rootroot00000000000000UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/Generic/Packaging/AppImage.pm000066400000000000000000000010011372663377700267410ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::Generic::Packaging::AppImage; sub check { my $params = shift; my $common = $params->{common}; $common->can_run("updatedb") } sub run { my $params = shift; my $common = $params->{common}; foreach(`locate -i "*.appimage"`){ /^(\/)(\S+)(\/)(\S+)/; my $name = $4; my $publisher = "AppImage"; $common->addSoftware({ 'NAME' => $name, 'PUBLISHER' => $publisher }); } } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/Generic/Packaging/BSDpkg.pm000066400000000000000000000020761372663377700264050ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::Generic::Packaging::BSDpkg; sub check { my $params = shift; my $common = $params->{common}; return if ( `uname -rs` =~ /SunOS 5.11/ ); $common->can_run("pkg") || $common->can_run("pkg_info") } sub run { my $params = shift; my $common = $params->{common}; if ($common->can_run("pkg")) { foreach(`pkg info`){ /^(\S+)-(\d+\S*)\s+(.*)/; my $name = $1; my $version = $2; my $comments = $3; $common->addSoftware({ 'COMMENTS' => $comments, 'NAME' => $name, 'VERSION' => $version }); } } elsif ($common->can_run("pkg_info")) { foreach(`pkg_info`){ /^(\S+)-(\d+\S*)\s+(.*)/; my $name = $1; my $version = $2; my $comments = $3; $common->addSoftware({ 'COMMENTS' => $comments, 'NAME' => $name, 'VERSION' => $version }); } } } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/Generic/Packaging/ByHand.pm000066400000000000000000000032111372663377700264300ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::Generic::Packaging::ByHand; #How does it work ? # #Create a directory called software in place where you have your #"modules.conf" file. #Put your scripts in this directory. #The scripts have to write on the STDIO with the following format : #publisher#software#version#comment # use strict; use warnings; sub check { return(1); 1; } sub run() { my $params = shift; my $common = $params->{common}; my $ligne; my $soft; my $comm; my $version; my $file; my $vendor; my $commentaire; my @dots; #if (!$file || !-d $file) { foreach (@{$common->{config}{etcdir}}) { $file = $_.'/softwares'; last if -d $file; } #} my $logger = $params->{logger}; if ( opendir(my $dh, $file) ){ @dots = readdir($dh); foreach (@dots) { if ( -f $file."/".$_ ){ $comm = $file."/".$_; $logger->debug("Running appli detection scripts from ".$comm); foreach (`$comm`){ $ligne = $_; chomp($ligne); ($vendor,$soft,$version,$commentaire) = split(/\#/,$ligne); $common->addSoftware ({ 'PUBLISHER' => $vendor, 'NAME' => $soft, 'VERSION' => $version, 'FILESIZE' => "", 'COMMENTS' => $commentaire, 'FROM' => 'ByHand' }); } } } closedir $dh; } 1; } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/Generic/Packaging/Deb.pm000066400000000000000000000043721372663377700257660ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::Generic::Packaging::Deb; use strict; use warnings; use File::Basename; use File::stat; sub check { my $params = shift; my $common = $params->{common}; $common->can_run("dpkg") } sub run { my $params = shift; my $common = $params->{common}; my $logger = $params->{logger}; my $size; my $key; my $value; my %statinfo; my @infos; # List of files from which installation date will be extracted my @listfile=glob('"/var/lib/dpkg/info/*.list"'); foreach my $file_list (@listfile){ my $stat=stat($file_list); my ($year,$month,$day,$hour,$min,$sec)=(localtime($stat->mtime))[5,4,3,2,1,0]; $value=sprintf "%02d/%02d/%02d %02d:%02d:%02d",($year+1900),$month,$day,$hour,$min,$sec; $key=fileparse($file_list, ".list"); $key =~ s/(\s+):.+/$1/; $statinfo{$key}=$value; } # Use binary:Package to see all packages (amd64,deb) with dpkg > 1162 my $ver=`dpkg --list dpkg | tail -n 1 | cut -d" " -f14`; $ver=~chomp($ver); my $vers=$common->convertVersion($ver,4); if ($vers > 1162 ){ @infos=`dpkg-query --show --showformat='\${binary:Package}---\${Architecture}---\${Version}---\${Installed-Size}---\${Status}---\${Homepage}---\${Description}\n'`; } else { @infos=`dpkg-query --show --showformat='\${Package}---\${Architecture}---\${Version}---\${Installed-Size}---\${Status}---\${Homepage}---\${Description}\n'`; } foreach my $line (@infos) { next if $line =~ /^ /; chomp $line; my @deb=split("---",$line); if ($deb[4] && $deb[4] !~ / installed/) { $logger->debug("Skipping $deb[0] package as not installed, status='$deb[4]'"); next; } $key=$deb[0]; if (exists $statinfo{$key}) { $common->addSoftware ({ 'NAME' => $deb[0], 'ARCHITECTURE' => $deb[1], 'VERSION' => $deb[2], 'FILESIZE' => ( $deb[3] || 0 ) * 1024, 'PUBLISHER' => $deb[5], 'INSTALLDATE' => $statinfo{$key}, 'COMMENTS' => $deb[6], 'FROM' => 'deb' }); } } } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/Generic/Packaging/Flatpak.pm000066400000000000000000000014371372663377700266550ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::Generic::Packaging::Flatpak; sub check { my $params = shift; my $common = $params->{common}; return unless $common->can_run("flatpak"); } sub run { my $params = shift; my $common = $params->{common}; if ($common->can_run("flatpak list")) { foreach(`flatpak list`){ /(\S+)(\/)(\S+)(\/)(\S+)\s+(\S+)/; my $name = $1; my $version = $5; my $publisher = "Flatpak package"; my $comments = $6; $common->addSoftware({ 'COMMENTS' => $comments, 'NAME' => $name, 'PUBLISHER' => $publisher, 'VERSION' => $version }); } } } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/Generic/Packaging/Gentoo.pm000066400000000000000000000022171372663377700265230ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::Generic::Packaging::Gentoo; use strict; use warnings; sub check { my $params = shift; my $common = $params->{common}; $common->can_run("equery") } sub run { my $params = shift; my $common = $params->{common}; # TODO: This had been rewrite from the Linux agent _WITHOUT_ being checked! # New format for listing softwares with equery command (equery 0.3.0.5) # Older version don't run with these options my $equery_vers = `equery --version ` =~ /.*\((.*)\).*/; $equery_vers = $1; if ($equery_vers =~ /^0.3/) { foreach (`equery list --format='\$cp \$fullversion' '*'`){ if (/^(.*) (.*)/) { $common->addSoftware({ 'NAME' => $1, 'VERSION' => $2, }); } } } else { # Old version of Gentoo foreach (`equery list -i`){ if (/^([a-z]\w+-\w+\/\.*)-([0-9]+.*)/) { $common->addSoftware({ 'NAME' => $1, 'VERSION' => $2, }); } } } } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/Generic/Packaging/Pacman.pm000066400000000000000000000007521372663377700264710ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::Generic::Packaging::Pacman; sub check { my $params = shift; my $common = $params->{common}; $common->can_run("/usr/bin/pacman") } sub run { my $params = shift; my $common = $params->{common}; foreach(`/usr/bin/pacman -Q`){ /^(\S+)\s+(\S+)/; my $name = $1; my $version = $2; $common->addSoftware({ 'NAME' => $name, 'VERSION' => $version }); } } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/Generic/Packaging/RPM.pm000066400000000000000000000031241372663377700257240ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::Generic::Packaging::RPM; use strict; use warnings; sub check { my $params = shift; my $common = $params->{common}; return unless $common->can_run("rpm"); # Some time rpm is a wrapper or an alias for another `rpm --version 2>&1`; return if ($? >> 8)!=0; 1; } sub run { my $params = shift; my $common = $params->{common}; my $logger = $params->{logger}; my @date; my @list; my $buff; foreach (`rpm -qa --queryformat "%{NAME} --%{ARCH}-- %{VERSION}-%{RELEASE} --%{INSTALLTIME}-- --%{SIZE}-- --%{VENDOR}-- %{SUMMARY}\n--\n" 2>/dev/null`) { if (! /^--/) { chomp; $buff .= $_; } elsif ($buff =~ s/^(.*)\s+--(.*)--\s+(\S+)\s+--(.*)--\s+--(.*)--\s+--(.*)--\s+(.*)//) { my ($name,$arch,$version,$installdate,$filesize,$vendor,$comments) = ( $1,$2,$3,$4,$5,$6,$7 ); @date = localtime($installdate); $installdate = sprintf( "%04d-%02d-%02d %02d:%02d:%02d", $date[5] + 1900, $date[4] + 1, $date[3], $date[2], $date[1], $date[0]); $common->addSoftware({ 'NAME' => $name, 'ARCHITECTURE' => $arch, 'VERSION' => $version, 'INSTALLDATE' => $installdate, 'FILESIZE' => $filesize, 'COMMENTS' => $comments, 'PUBLISHER' => $vendor, 'FROM' => 'rpm' }); } else { $logger->debug("Should never go here!"); $buff = ''; } } } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/Generic/Packaging/Snap.pm000066400000000000000000000016071372663377700261730ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::Generic::Packaging::Snap; sub check { my $params = shift; my $common = $params->{common}; return unless $common->can_run("snap"); } sub run { my $params = shift; my $common = $params->{common}; if ($common->can_run("snap list")) { my $i = 0; foreach(`snap list`){ /^(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)/; if($i >= 1) { my $name = $1; my $version = $2; my $publisher = $5; my $comments = "Snap package"; $common->addSoftware({ 'COMMENTS' => $comments, 'NAME' => $name, 'PUBLISHER' => $publisher, 'VERSION' => $version }); } $i++; } } } 1;UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/Generic/Printers/000077500000000000000000000000001372663377700246525ustar00rootroot00000000000000UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/Generic/Printers/Cups.pm000066400000000000000000000024041372663377700261220ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::Generic::Printers::Cups; use strict; sub check { my $params = shift; my $common = $params->{common}; # If we are on a MAC, Mac::SysProfile will do the job return if -r '/usr/sbin/system_profiler'; return unless $common->can_load("Net::CUPS") && $Net::CUPS::VERSION >= 0.60; return 1; } sub run { my $params = shift; my $common = $params->{common}; my $cups = Net::CUPS->new(); my @destinations = $cups->getDestinations(); my $printer; my $description; my $port; my $driver; foreach (@destinations) { $printer = $_->getName() unless $printer; $description = $_->getDescription() unless $description; $port = $_->getUri() unless $port; $driver = $_->getOptionValue("printer-make-and-model") unless $driver; # Just grab the default printer, if I use getDestinations, CUPS # returns all the printer of the local subnet (if it can) # TODO There is room for improvement here $common->addPrinter({ NAME => $printer, DESCRIPTION => $description, PORT => $port, DRIVER => $driver }); $printer = $description = $port = $driver = undef; } } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/Generic/Repository.pm000066400000000000000000000001331372663377700255560ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::Generic::Repository; use strict; sub run {} 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/Generic/Repository/000077500000000000000000000000001372663377700252235ustar00rootroot00000000000000UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/Generic/Repository/BSD.pm000066400000000000000000000034771372663377700262040ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::Generic::Repository::BSD; use strict; use warnings; sub check { my $params = shift; my $common = $params->{common}; return unless $common->can_run("pkg"); } my $repo_name; my $repo_baseurl; my $repo_priority; my $repo_mirror_type; my $repo_signature_type; my $repo_fingerprints; my $repo_enable; sub run { my $params = shift; my $common = $params->{common}; if ($^O eq 'freebsd') { foreach my $line (`LANG=C pkg -vv 2>/dev/null`){ next if ($line =~ /^Repositories:/i); if ($line =~ /^\s+(.*):\s\{/i){ $repo_name = $1; } elsif ($line =~ /url\s+:\s\"(.*)\"/i) { $repo_baseurl = $1; } elsif ($line =~ /enabled\s+:\s(.*)\,/i){ $repo_enable = $1; } elsif ($line =~ /priority\s+:\s(.*)\,/i) { $repo_priority = $1; } elsif ($line =~ /Mirror_type\s+:\s\"(.*)\"\,/i){ $repo_mirror_type = $1; } elsif ($line =~ /signature_type\s+:\s\"(.*)\"\,/i){ $repo_signature_type = $1; } elsif ($line =~ /fingerprints\s+:\s\"(.*)\"/i){ $repo_fingerprints = $1; } if ($line =~ /^ \}$/) { $common->addRepo({ BASEURL => $repo_baseurl, NAME => $repo_name, ENABLED => $repo_enable, PRIORITY => $repo_priority, MIRROR => $repo_mirror_type, SIGNATURE => $repo_signature_type, FINGERPRINTS => $repo_fingerprints, }); $repo_name = $repo_baseurl = $repo_enable = $repo_priority = $repo_mirror_type = $repo_signature_type = $repo_fingerprints = undef; } } } } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/Generic/Repository/CentOS.pm000066400000000000000000000044601372663377700267200ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::Generic::Repository::CentOS; use strict; use warnings; sub check { my $params = shift; my $common = $params->{common}; return unless $common->can_run("yum"); } my $repo_name; my $repo_baseurl; my $repo_filename; my $repo_pkgs; my $repo_rev; my $repo_size; my $repo_tag; my $repo_updated; my $repo_mirrors; my $repo_expire; my $repo_exclude; my $repo_excluded; my $repo_metalink; sub run { my $params = shift; my $common = $params->{common}; my @repository=`LANG=C yum -v repolist 2>/dev/null`; push @repository, "\n"; for (my $i=0;$i<$#repository;$i++){ my $line=$repository[$i]; if ($line =~ /^$/ && $repo_name && $repo_filename) { $common->addRepo({ BASEURL => $repo_baseurl, EXCLUDE => $repo_exclude, EXCLUDED => $repo_excluded, EXPIRE => $repo_expire, FILENAME => $repo_filename, MIRRORS => $repo_mirrors, NAME => $repo_name, PKGS => $repo_pkgs, REVISION => $repo_rev, SIZE => $repo_size, TAG => $repo_tag, UPDATED => $repo_updated, }); $repo_name = $repo_baseurl = $repo_filename = $repo_pkgs = $repo_size = $repo_tag = $repo_updated = $repo_mirrors = $repo_expire = $repo_exclude = $repo_excluded = $repo_rev = $repo_metalink = undef; } $repo_name = $1 if ($line =~ /^Repo-name\s+:\s(.*)/i); $repo_baseurl = $1 if ($line =~ /^Repo-baseurl\s+:\s(.*)/i); $repo_mirrors = $1 if ($line =~ /^Repo-mirrors\s+:\s(.*)/i); $repo_filename = $1 if ($line =~ /^Repo-filename:\s(.*)/i); $repo_pkgs = $1 if ($line =~ /^Repo-pkgs\s+:\s(.*)/i); $repo_rev = $1 if ($line =~ /^Repo-revision:\s(.*)/i); $repo_size = $1 if ($line =~ /^Repo-size\s+:\s(.*)/i); $repo_tag = $1 if ($line =~ /^Repo-tags\s+:\s(.*)/i); $repo_updated = $1 if ($line =~ /^Repo-updated\s+:\s(.*)/i); $repo_exclude = $1 if ($line =~ /^Repo-exclude\s+:\s(.*)/i); $repo_excluded = $1 if ($line =~ /^Repo-excluded\s+:\s(.*)/i); $repo_expire = $1 if ($line =~ /^Repo-expire\s+:\s(.*)/i); $repo_metalink =$1 if ($line =~ /^Repo-metalink\s+:\s(.*)/i); } } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/Generic/Repository/Debian.pm000066400000000000000000000016131372663377700267440ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::Generic::Repository::Debian; use strict; use warnings; sub check{ my $params = shift; my $common = $params->{common}; return unless $common->can_run("apt-cache"); } sub run{ my $params = shift; my $common = $params->{common}; my ($repo_name, $repo_baseurl); my @repository=`apt-cache policy | grep -i http | awk {'print \$2 " " \$3'} | sort -u`; push @repository, "\n"; for (my $i=0;$i<$#repository;$i++){ my $line=$repository[$i]; $repo_name=$1 if ($line =~ /\/([^\/]*)\n$/); $repo_baseurl=$1 if ($line =~ /^(\S*)\h/); if ($line =~ /(^.*$)/ && $repo_name && $repo_baseurl){ $common->addRepo({ NAME => $repo_name, BASEURL => $repo_baseurl, }); $repo_name = $repo_baseurl = undef; } #$repo_name=$1 if ($line =~ /.*\s(\w-?\/\w)/); } } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/Generic/Repository/Rhel.pm000066400000000000000000000036301372663377700264550ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::Generic::Repository::Rhel; use strict; use warnings; sub check { my $params = shift; my $common = $params->{common}; return unless $common->can_run("dnf"); } my $repo_name; my $repo_baseurl; my $repo_filename; my $repo_pkgs; my $repo_rev; my $repo_size; my $repo_expire; my $repo_updated; my $repo_lastupdated; my $repo_mirrors; sub run { my $params = shift; my $common = $params->{common}; my @repository=`LANG=C dnf -v repolist 2>/dev/null`; for (my $i=0;$i<$#repository;$i++){ my $line=$repository[$i]; if ($line =~ /^$/ && $repo_name && $repo_filename) { $common->addRepo({ BASEURL => $repo_baseurl, FILENAME => $repo_filename, NAME => $repo_name, PKGS => $repo_pkgs, REVISION => $repo_rev, SIZE => $repo_size, UPDATED => $repo_updated, LASTUPDATED => $repo_lastupdated, EXPIRE => $repo_expire, MIRRORS => $repo_mirrors, }); $repo_name = $repo_expire = $repo_baseurl = $repo_filename = $repo_pkgs = $repo_rev = $repo_size = $repo_mirrors = $repo_updated = $repo_lastupdated = undef; } $repo_name=$1 if ($line =~ /^Repo-name\s+:\s(.*)/i); $repo_baseurl=$1 if ($line =~ /^Repo-baseurl\s+:\s(.*)/i); $repo_filename=$1 if ($line =~ /^Repo-filename:\s(.*)/i); $repo_pkgs=$1 if ($line =~ /^Repo-pkgs\s+:\s(.*)/i); $repo_rev=$1 if ($line =~ /^Repo-revision\s+:\s(.*)/i); $repo_size=$1 if ($line =~ /^Repo-size\s+:\s(.*)/i); $repo_expire=$1 if ($line =~ /^Repo-expire\s+:\s(.*)/i); $repo_updated=$1 if ($line =~ /^Repo-updated\s+:\s(.*)/i); $repo_lastupdated=$1 if ($line =~ /Updated\s+:\s(.*)/i); $repo_mirrors=$1 if ($line =~ /^Repo-metalink\s+:\s(.*)/i); } } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/Generic/Screen.pm000066400000000000000000000143251372663377700246260ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::Generic::Screen; use strict; use utf8; use Parse::EDID; sub haveExternalUtils { my $common = shift; return $common->can_run("monitor-get-edid-using-vbe") || $common->can_run("monitor-get-edid") || $common->can_run("get-edid"); } sub check { my $params = shift; my $common = $params->{common}; return unless -d "/sys/devices" || haveExternalUtils($common); 1; } sub _getManufacturerFromCode { my $code = shift; my $h = { "ACR" => "Acer America Corp.", "ACT" => "Targa", "ADI" => "ADI Corporation http://www.adi.com.tw", "AOC" => "AOC International (USA) Ltd.", "API" => "Acer America Corp.", "APP" => "Apple Computer, Inc.", "ART" => "ArtMedia", "AST" => "AST Research", "AMW" => "AMW", "AUO" => "AU Optronics Corporation", "BMM" => "BMM", "BNQ" => "BenQ Corporation", "BOE" => "BOE Display Technology", "CPL" => "Compal Electronics, Inc. / ALFA", "CPQ" => "COMPAQ Computer Corp.", "CPT" => "Chunghwa Picture Tubes, Ltd.", "CTX" => "CTX - Chuntex Electronic Co.", "DEC" => "Digital Equipment Corporation", "DEL" => "Dell Computer Corp.", "DPC" => "Delta Electronics, Inc.", "DWE" => "Daewoo Telecom Ltd", "ECS" => "ELITEGROUP Computer Systems", "ENC" => "EIZO", "EIZ" => "EIZO", "EPI" => "Envision Peripherals, Inc.", "FCM" => "Funai Electric Company of Taiwan", "FUJ" => "Fujitsu", "FUS" => "Fujitsu Siemens", "GSM" => "LG Electronics Inc. (GoldStar Technology, Inc.)", "GWY" => "Gateway 2000", "HEI" => "Hyundai Electronics Industries Co., Ltd.", "HIQ" => "Hyundai ImageQuest", "HIT" => "Hitachi", "HSD" => "Hannspree Inc", "HSL" => "Hansol Electronics", "HTC" => "Hitachi Ltd. / Nissei Sangyo America Ltd.", "HWP" => "Hewlett Packard", "IBM" => "IBM PC Company", "ICL" => "Fujitsu ICL", "IFS" => "InFocus", "IQT" => "Hyundai", "IVM" => "Idek Iiyama North America, Inc.", "KFC" => "KFC Computek", "LEN" => "Lenovo", "LGD" => "LG Display", "LKM" => "ADLAS / AZALEA", "LNK" => "LINK Technologies, Inc.", "LPL" => "LG Philips", "LTN" => "Lite-On", "MAG" => "MAG InnoVision", "MAX" => "Maxdata Computer GmbH", "MEI" => "Panasonic Comm. & Systems Co.", "MEL" => "Mitsubishi Electronics", "MIR" => "Miro Computer Products AG", "MTC" => "MITAC", "MS_" => "Panasonic", "NAN" => "NANAO", "NEC" => "NEC Technologies, Inc.", "NVD" => "Fujitsu", "NOK" => "Nokia", "OQI" => "OPTIQUEST", "PBN" => "Packard Bell", "PCK" => "Daewoo", "PDC" => "Polaroid", "PGS" => "Princeton Graphic Systems", "PHL" => "Philips Consumer Electronics Co.", "PRT" => "Princeton", "PTS" => "ProView/EMC/PTS YakumoTFT17SL", "REL" => "Relisys", "SAM" => "Samsung", "SMI" => "Smile", "SMC" => "Samtron", "SNI" => "Siemens Nixdorf", "SNY" => "Sony Corporation", "SPT" => "Sceptre", "SRC" => "Shamrock Technology", "STN" => "Samtron", "STP" => "Sceptre", "TAT" => "Tatung Co. of America, Inc.", "TOS" => "Toshiba", "TRL" => "Royal Information Company", "TSB" => "Toshiba, Inc.", "UNM" => "Unisys Corporation", "VSC" => "ViewSonic Corporation", "WTC" => "Wen Technology", "ZCM" => "Zenith Data Systems", "___" => "Targa" }; return $h->{$code} if (exists ($h->{$code}) && $h->{$code}); return "Unknown manufacturer code ".$code; } sub getEdid { my $raw_edid; my $port = $_[0]; # Mandriva $raw_edid = `monitor-get-edid-using-vbe --port $port 2>/dev/null`; # Since monitor-edid 1.15, it's possible to retrieve EDID information # through DVI link but we need to use monitor-get-edid if (!$raw_edid) { $raw_edid = `monitor-get-edid --vbe-port $port 2>/dev/null`; } if (!$raw_edid) { foreach (1..5) { # Sometime get-edid return an empty string... $raw_edid = `get-edid 2>/dev/null`; last if (length($raw_edid) == 128 || length($raw_edid) == 256); } } return unless (length($raw_edid) == 128 || length($raw_edid) == 256); return $raw_edid; } sub run { my $params = shift; my $common = $params->{common}; my $logger = $params->{logger}; my $raw_perl = 1; my $verbose; my $MonitorsDB; my $base64; my $uuencode; my %found; my @edid_list; # first check sysfs if there are edid entries for my $file(split(/\0/,`find /sys/devices -wholename '*/card*/edid' -print0`)) { open(my $sys_edid_fd,'<',$file); my $raw_edid = do { local $/; <$sys_edid_fd> }; if (length($raw_edid) == 128 || length($raw_edid) == 256 ) { push @edid_list, $raw_edid; } } # if not fall back to the old method if (!@edid_list && haveExternalUtils($common)) { for my $port(0..20){ my $raw_edid = getEdid($port); if ($raw_edid){ if (length($raw_edid) == 128 || length($raw_edid) == 256) { push @edid_list, $raw_edid; } } } } for my $raw_edid(@edid_list) { my $edid = parse_edid($raw_edid); if (my $err = check_parsed_edid($edid)) { $logger->debug("check failed: bad edid: $err"); } my $caption = $edid->{monitor_name}; my $description = $edid->{week}."/".$edid->{year}; my $manufacturer = _getManufacturerFromCode($edid->{manufacturer_name}); my $serial = $edid->{serial_number}; if (!exists $found{$serial}) { $found{$serial} = 1; eval "use MIME::Base64;"; $base64 = encode_base64($raw_edid) if !$@; if ($common->can_run("uuencode")) { chomp($uuencode = `echo $raw_edid|uuencode -`); if (!$base64) { chomp($base64 = `echo $raw_edid|uuencode -m -`); } } $common->addMonitor ({ BASE64 => $base64, CAPTION => $caption, DESCRIPTION => $description, MANUFACTURER => $manufacturer, SERIAL => $serial, UUENCODE => $uuencode, }); } } } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/Generic/Users.pm000066400000000000000000000063551372663377700245140ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::Generic::Users; use strict; use warnings; use Data::Dumper; sub check { my $params = shift; my $common = $params->{common}; # Useless check for a posix system i guess my @who = `who 2>/dev/null`; my @last = `last 2>/dev/null`; if (($common->can_read("/etc/passwd") && $common->can_read("/etc/group")) || @who || @last ) { return 1; } else { return 0; } } # Initialise the distro entry sub run { my $params = shift; my $common = $params->{common}; my %users; # Logged on users for (`who`){ my $user = $1 if /^(\S+)./; $common->addUser ({ LOGIN => $user }); } # Local users foreach my $user (_getLocalUsers()) { push @{$users{$user->{GID}}}, $user->{LOGIN}; #delete $user->{GID}; $common->addLocalUser({ LOGIN => $user->{LOGIN}, ID => $user->{ID}, GID => $user->{GID}, NAME => $user->{NAME}, HOME => $user->{HOME}, SHELL => $user->{SHELL} }); } # Local groups with members foreach my $group (_getLocalGroups()) { push @{$group->{MEMBER}}, @{$users{$group->{ID}}} if $users{$group->{ID}}; $common->addLocalGroup({ ID => $group->{ID}, NAME => $group->{NAME}, MEMBER => $group->{MEMBER} }); } # last logged user $common->setHardware(_getLast()); } sub _getLocalUsers{ open(my $fh, '<:encoding(UTF-8)', "/etc/passwd") or warn; my @userinfo=<$fh>; close($fh); my @users; foreach my $line (@userinfo){ next if $line =~ /^#/; next if $line =~ /^[+-]/; # old format for external inclusion chomp $line; my ($login, undef, $uid, $gid, $gecos, $home, $shell) = split(/:/, $line); push @users, { LOGIN => $login, ID => $uid, GID => $gid, NAME => $gecos, HOME => $home, SHELL => $shell, }; } return @users; } sub _getLocalGroups { open(my $fh, '<:encoding(UTF-8)', "/etc/group") or warn; my @groupinfo=<$fh>; close($fh); my @groups; foreach my $line (@groupinfo){ next if $line =~ /^#/; chomp $line; my ($name, undef, $gid, $members) = split(/:/, $line); next unless $members; my @members = split(/,/, $members); push @groups, { ID => $gid, NAME => $name, MEMBER => @members, }; } return @groups; } sub _getLast { my ($lastuser,$lastlogged); my @info=`last`; foreach my $last (@info) { chomp $last; next if $last =~ /^(reboot|shutdown)/; my @last = split(/\s+/, $last); next unless (@last); $lastuser = shift @last or next; # Found time on column starting as week day shift @last while ( @last > 3 && $last[0] !~ /^mon|tue|wed|thu|fri|sat|sun/i ); $lastlogged = @last > 3 ? "@last[0..3]" : undef; last; } return unless $lastuser; return { LASTLOGGEDUSER => $lastuser, DATELASTLOGGEDUSER => $lastlogged }; } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/HPUX.pm000066400000000000000000000011771372663377700226200ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::HPUX; use strict; use vars qw($runAfter); $runAfter = ["Ocsinventory::Agent::Backend::OS::Generic"]; sub check { $^O =~ /hpux/ } sub run { my $params = shift; my $common = $params->{common}; my $OSName; my $OSVersion; my $OSComment; #my $uname_path = &_get_path('uname'); # Operating systeminformations chomp($OSName = `uname -s`); chomp($OSVersion = `uname -r`); chomp($OSComment = `uname -l`); $common->setHardware({ OSNAME => $OSName, OSCOMMENTS => $OSComment, OSVERSION => $OSVersion, }); } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/HPUX/000077500000000000000000000000001372663377700222545ustar00rootroot00000000000000UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/HPUX/Bios.pm000066400000000000000000000024031372663377700235050ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::HPUX::Bios; use strict; ### # Version 1.1 # Correction of Bug n 522774 # # thanks to Marty Riedling for this correction # ### sub check { $^O =~ /hpux/ } sub run { my $params = shift; my $common = $params->{common}; my $BiosVersion; my $BiosDate; my $SystemModel; my $SystemSerial; $SystemModel=`model`; if ($common->can_run ("machinfo")) { foreach (`machinfo`) { if (/Firmware\s+revision\s?[:=]\s+(\S+)/) { $BiosVersion=$1; } if (/achine\s+serial\s+number\s?[:=]\s+(\S+)/) { $SystemSerial=$1; } } } else { for (`echo 'sc product cpu;il' | /usr/sbin/cstm | grep "PDC Firmware"`) { if (/Revision:\s+(\S+)/){ $BiosVersion="PDC $1"; } } for (`echo 'sc product system;il' | /usr/sbin/cstm | grep "System Serial Number"`) { if (/:\s+(\w+)/) { $SystemSerial=$1; } } } $common->setBios ({ BVERSION => $BiosVersion, BDATE => $BiosDate, BMANUFACTURER => "HP", SMANUFACTURER => "HP", SMODEL => $SystemModel, SSN => $SystemSerial, }); } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/HPUX/CPU.pm000066400000000000000000000060311372663377700232410ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::HPUX::CPU; ### # Version 1.1 # Correction of Bug n 522774 # # thanks to Marty Riedling for this correction # ### use strict; use LWP::UserAgent; sub check { $^O =~ /hpux/ } sub run { my $params = shift; my $common = $params->{common}; my $processort; my $processorn; my $processors=""; my $DeviceType; my $cpuInfo; my $serie; # Using old system HpUX without machinfo # the Hpux with machinfo will be done after my %cpuInfos = ( "D200"=>"7100LC 75", "D210"=>"7100LC 100", "D220"=>"7300LC 132", "D230"=>"7300LC 160", "D250"=>"7200 100", "D260"=>"7200 120", "D270"=>"8000 160", "D280"=>"8000 180", "D310"=>"7100LC 100", "D320"=>"7300LC 132", "D330"=>"7300LC 160", "D350"=>"7200 100", "D360"=>"7200 120", "D370"=>"8000 160", "D380"=>"8000 180", "D390"=>"8200 240", "K360"=>"8000 180", "K370"=>"8200 200", "K380"=>"8200 240", "K400"=>"7200 100", "K410"=>"7200 120", "K420"=>"7200 120", "K460"=>"8000 180", "K570"=>"8200 200", "K580"=>"8200 240", "L1000-36"=>"8500 360", "L1500-7x"=>"8700 750", "L3000-7x"=>"8700 750", "N4000-44"=>"8500 440", "ia64 hp server rx1620"=>"itanium 1600"); if ( $common->can_run ("machinfo") ) { foreach ( `machinfo`) { if ( /Number of CPUs\s+=\s+(\d+)/ ) { $processorn=$1; } if ( /Clock speed\s+=\s+(\d+)\s+MHz/ ) { $processors=$1; } # Added for HPUX 11.31 if ( /Intel\(R\) Itanium 2 9[01]00 series processor \((\d+\.\d+)/ ) { $processors=$1*1000; } if ( /(\d+)\s+logical processors/ ) { $processorn=$1; } # end HPUX 11.31 } } else { chomp($DeviceType =`model |cut -f 3- -d/`); my $cpuInfo = $cpuInfos{"$DeviceType"}; if ( "$cpuInfo" =~ /^(\S+)\s(\S+)/ ) { $processort=$1; $processors=$2; } else { for ( `echo 'sc product cpu;il' | /usr/sbin/cstm | grep "CPU Module"` ) { if ( /(\S+)\s+CPU\s+Module/ ) { $processort=$1; } }; for ( `echo 'itick_per_usec/D' | adb -k /stand/vmunix /dev/kmem` ) { if ( /tick_per_usec:\s+(\d+)/ ) { $processors=$1; } } }; # NBR CPU chomp($processorn=`ioscan -Fk -C processor | wc -l`); #print "HP $processort A $processorn A $processors "; } chomp($serie = `uname -m`); if ( $serie =~ /ia64/) { $processort="Itanium" } if ( $serie =~ /9000/) { $processort="PA$processort"; } $common->setHardware({ PROCESSORT => $processort, PROCESSORN => $processorn, PROCESSORS => $processors, }); } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/HPUX/Controller.pm000066400000000000000000000014461372663377700247420ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::HPUX::Controller; use strict; sub check { $^O =~ /hpux/ } sub run { my $params = shift; my $common = $params->{common}; my $name; my $interface; my $info; my $type; my @typeScaned=('ext_bus','fc','psi'); my $scaned; for (@typeScaned) { $scaned=$_; for ( `ioscan -kFC $scaned| cut -d ':' -f 9,11,17,18` ) { if ( /(\S+):(\S+):(\S+):(.+)/ ) { $name=$2; $interface=$3; $info=$4; $type=$1; $common->addController({ 'NAME' => $name, 'MANUFACTURER' => "$interface $info", 'TYPE' => $type, }); }; }; }; } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/HPUX/Domains.pm000066400000000000000000000013461372663377700242100ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::HPUX::Domains; use strict; sub check { my $params = shift; my $common = $params->{common}; $common->can_run ("domainname") } sub run { my $params = shift; my $common = $params->{common}; my $domain; chomp($domain = `domainname`); if (!$domain) { my %domain; if (open RESOLV, "/etc/resolv.conf") { while() { $domain{$2} = 1 if (/^(domain|search)\s+(.+)/); } close RESOLV; } $domain = join "/", keys %domain; } # If no domain name, we send "WORKGROUP" $domain = 'WORKGROUP' unless $domain; $common->setHardware({ WORKGROUP => $domain }); } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/HPUX/Drives.pm000066400000000000000000000026151372663377700240520ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::HPUX::Drives; sub check { $^O =~ /hpux/ } sub run { my $params = shift; my $common = $params->{common}; my $type; my $fs; my $lv; my $total; my $free; for ( `fstyp -l | grep -v nfs` ) { if ( /^\s*$/ ) { #Blank line next; } $type=$_; for ( `bdf -t $type `) { if ( /Filesystem/ ) { ; } ; if ( /^(\S+)\s(\d+)\s+(\d+)\s+(\d+)\s+(\d+%)\s+(\S+)/ ) { $lv=$1; $total=$2; $free=$3; $fs=$6; $common->addDrives({ FREE => $free, FILESYSTEM => $fs, TOTAL => $total, TYPE => $type, VOLUMN => $lv, }); }; if ( /^(\S+)\s/) { $lv=$1; }; if ( /(\d+)\s+(\d+)\s+(\d+)\s+(\d+%)\s+(\S+)/) { $total=$1; $free=$3; $fs=$5; # print "fs $fs lv $lv total $total free $free type $type\n"; $common->addDrives({ FREE => $free, FILESYSTEM => $fs, TOTAL => $total, TYPE => $type, VOLUMN => $lv, }); }; }; }; } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/HPUX/IPv4.pm000066400000000000000000000007441372663377700234010ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::HPUX::IPv4; sub check { `which ifconfig 2>&1`; ($? >> 8)?0:1 } # Initialise the distro entry sub run { my $params = shift; my $common = $params->{common}; my $ip; my $hostname; if ( `hostname` =~ /(\S+)/ ) { $hostname=$1; } for ( `grep $hostname /etc/hosts ` ) { if ( /(^\d+\.\d+\.\d+\.\d+)\s+/ ){ $ip=$1; $common->setHardware({IPADDR => $ip}); } } } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/HPUX/Mem.pm000066400000000000000000000010601372663377700233250ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::HPUX::Mem; use strict; sub check { $^O =~ /hpux/ } sub run { my $params = shift; my $common = $params->{common}; my $mem; my $swap; $mem = `grep Physical /var/adm/syslog/syslog.log|tr -s " "|cut -f 7 -d " "` ; if ( $mem eq "" ) { $mem = `grep Physical /var/adm/syslog/OLDsyslog.log|tr -s " "|cut -f 7 -d " "` ; }; $mem = int ($mem/1024); $swap = `swapinfo -mdfq`; $common->setHardware({ MEMORY => $mem, SWAP => $swap, }); } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/HPUX/Memory.pm000066400000000000000000000063521372663377700240700ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::HPUX::Memory; use strict; sub check { $^O =~ /hpux/ } sub run { my $params = shift; my $common = $params->{common}; my $capacity=0; my $caption; my $description; my $numslot; my $subnumslot; my $serialnumber; my $type; my @list_mem=`echo 'sc product mem;il'| /usr/sbin/cstm`; my $ok=0; if ( `uname -m` =~ /ia64/ ) { for ( `echo 'sc product IPF_MEMORY;il' | /usr/sbin/cstm` ) { if ( /\w+IMM\s+Location/ ) { ; } elsif ( /(\w+IMM)\s+(\w+)\s+(\S+)\s+(\w+IMM)\s+(\w+)\s+(\S+)/ ) { $common->addMemories({ CAPACITY => $3, CAPTION => $2 , NUMSLOTS => "1" , TYPE => $1, }); $common->addMemories({ CAPACITY => $6, CAPTION => $5 , NUMSLOTS => "1" , TYPE => $4, }); } } } else { for ( `echo 'sc product system;il' | /usr/sbin/cstm ` ) { if ( /FRU\sSource\s+=\s+\S+\s+\(memory/ ) { $ok=0; #print "FRU Source memory\n"; } if ( /Source\s+Detail\s+=\s4/ ) { $ok=1; #print "Source Detail IMM\n"; } if ( /Extender\s+Location\s+=\s+(\S+)/ ) { $subnumslot=$1; #print "Extended sub $subnumslot\n"; }; if ( /DIMMS\s+Rank\s+=\s+(\S+)/ ) { $numslot=sprintf("%02x",$1); #print "Num slot $numslot\n"; } if ( /FRU\s+Name\.*:\s+(\S+)/ ) { if ( /(\S+)_(\S+)/ ) { $type=$1; $capacity=$2; #print "Type $type capa $capacity\n"; } elsif ( /(\wIMM)(\S+)/ ) { $ok=1; $type=$1; $numslot=$2; #print "Type $type numslot $numslot\n"; } } if ( /Part\s+Number\.*:\s*(\S+)\s+/ ) { $description=$1; #print "ref $description\n"; }; if ( /Serial\s+Number\.*:\s*(\S+)\s+/ ) { $serialnumber=$1; if ( $ok eq 1 ) { if ( $capacity eq 0 ){ foreach ( @list_mem ){ if ( /\s+$numslot\s+(\d+)/ ){ $capacity=$1; #print "Capacity $capacity\n"; } } } $common->addMemories({ CAPACITY => $capacity, CAPTION => "Ext $subnumslot Slot $numslot" , DESCRIPTION => "Part Number $description", NUMSLOTS => "1" , SERIALNUMBER => $serialnumber, TYPE => $type, }); $ok=0; $capacity=0; }; #print "Serial $serialnumber\n\n"; }; }; } } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/HPUX/Networks.pm000066400000000000000000000051061372663377700244300ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::HPUX::Networks; sub check { my $params = shift; my $common = $params->{common}; $common->can_load("Net::IP qw(:PROC)"); } sub run { my $params = shift; my $common = $params->{common}; my $name; my $lanid; my $ipmask; my $ipgateway; my $status; my $macaddr; my $speed; my $type; my $ipsubnet; my $description; my $ipaddress; my $binip; my $binmask; my $binsubnet; for ( `lanscan -iap`) { # Reinit variable $name=""; $lanid=""; $ipmask=""; $ipgateway=""; $status=""; $macaddr=""; $speed=""; $type=""; $ipsubnet=""; $description=""; $ipaddress=""; if ( /^(\S+)\s(\S+)\s(\S+)\s+(\S+)/) { $name=$2; $macaddr=$1; $lanid=$4; #print "name $name macaddr $macaddr lanid $lanid\n"; for ( `lanadmin -g $lanid` ) { if (/Type.+=\s(.+)/) { $type = $1; }; if (/Description\s+=\s(.+)/) { $description = $1; }; if (/Speed.+=\s(\d+)/) { $speed = $1; unless ( $speed <= 1000000 ) { # in old version speed was given in Mbps # we want speed in Mbps $speed = $1/1000000; } }; if (/Operation Status.+=\s(.+)/) { $status = $1; }; }; # for lanadmin #print "name $name macaddr $macaddr lanid $lanid speed $speed status $status \n"; for ( `ifconfig $name 2> /dev/null` ) { if ( /inet\s(\S+)\snetmask\s(\S+)\s/ ) { $ipaddress=$1; $ipmask=$2; if ($ipmask =~ /(..)(..)(..)(..)/) { $ipmask=sprintf ("%i.%i.%i.%i",hex($1),hex($2),hex($3),hex($4)); } }; }; # For ifconfig $binip = ip_iptobin ($ipaddress ,4); $binmask = ip_iptobin ($ipmask ,4); $binsubnet = $binip & $binmask; $ipsubnet = ip_bintoip($binsubnet,4); $common->addNetworks({ DESCRIPTION => $description, IPADDRESS => $ipaddress, IPGATEWAY => $ipgateway, IPMASK => $ipmask, IPSUBNET => $ipsubnet, MACADDR => $macaddr, STATUS => $status, SPEED => $speed, TYPE => $type, }); }; # If }; # For lanscan } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/HPUX/README000066400000000000000000000030671372663377700231420ustar00rootroot00000000000000##################################################### # 17/12/2009 # Auteur: dwizz.donowin@yahoo.fr # # This code is open source and may be copied and modified as long as the source # code is always made freely available. # Please refer to the General Public Licence http://www.gnu.org/ or Licence.txt # ################################################################################ Version Francaise ----------------- (for english version see below) Ces fichiers sont generes pour etre utilisis avec l'agent Unix OCS-NG 1.02 Installation: Installer le client OCS-NG 1.02 avec ces prerequis extraire les fichiers dans le repertoire Ocsinventory/Agent/Backend/OS Ils seront automatiquement pris en compte par le client OCS Je n'ai pu tester ces fichiers que sur N4000 actuellement en version HP-UX 11.0 J'ai commence sur un rp3440 mais je n'ai pas encore toutes les informations car le format des certaines donnees change. N'hesitez pas a m'aider a le faire evoluer. English version --------------- This files are producted for using with the OCS-NG 1.02 Unix Agent Install: Install the OCS-NG 1.02 Agent with the prerequesit Extract the files in the Ocsinventory/Agent/Backend/OS It will be used automatically I have test the script on only n4000 system for th moment on HP-Ux 11.0 I try it on rp3440 but some informations are not in the same format If you wish to help me, you are welwome. the files are HPUX.pm HPUX sub directory Bios.pm CPU.pm Controller.pm Domains.pm Drives.pm IPv4.pm Mem.pm Memory.pm Networks.pm Slots.pm Software.pm Storages.pm UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/HPUX/Slots.pm000066400000000000000000000015251372663377700237210ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::HPUX::Slots; use strict; sub check { $^O =~ /hpux/ } sub run { my $params = shift; my $common = $params->{common}; my $name; my $interface; my $info; my $type; my @typeScaned=('ioa','ba'); my $scaned; for (@typeScaned ) { $scaned=$_; for ( `ioscan -kFC $scaned| cut -d ':' -f 9,11,17,18` ) { if ( /(\S+):(\S+):(\S+):(.+)/ ) { $name=$2; $interface=$3; $info=$4; $type=$1; $common->addSlots({ DESCRIPTION => "$name", DESIGNATION => "$interface $info", NAME => "$type", STATUS => "OK", }); }; }; }; } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/HPUX/Software.pm000066400000000000000000000014361372663377700244100ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::HPUX::Software; sub check { my $params = shift; # Do not run an package inventory if there is the --nosoftware parameter return if ($params->{params}->{nosoftware}); $^O =~ /hpux/ } sub run { my $params = shift; my $common = $params->{common}; my @softList; my $software; @softList = `swlist | grep -v '^ PH' | grep -v '^#' |tr -s "\t" " "|tr -s " "` ; foreach $software (@softList) { chomp( $software ); if ( $software =~ /^ (\S+)\s(\S+)\s(.+)/ ) { $common->addSoftwares({ 'NAME' => $1 , 'VERSION' => $2 , 'COMMENTS' => $3 , 'PUBLISHER' => "HP" , }); } } } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/HPUX/Storages.pm000066400000000000000000000054511372663377700244060ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::HPUX::Storages; sub check { $^O =~ /hpux/ } sub run { my $params = shift; my $common = $params->{common}; my @all_type = ("tape","disk") ; my $type; my $description; my $path; my $vendor; my $ref; my $size; my $devdsk; my $devrdsk; my $revlvl; my $alternate; for ( @all_type ) { $type = "$_"; for ( `ioscan -kFnC $type | cut -d ':' -f 1,11,18` ) { if ( /(\S+)\:(\S+)\:(\S+)\s+(\S+)/ ) { $description = $1; $path = $2; $vendor = $3; $ref = $4; }; $alternate = 0 ; if ( $type eq "disk" ) { if ( /\s+(\/dev\/dsk\/\S+)\s+(\/dev\/rdsk\/\S+)/ ) { #print "1 $1 2 $2 \n"; $devdsk=$1; $devrdsk=$2; # We look if we are on an alternate link for ( `pvdisplay $devdsk 2> /dev/null` ) { if ( /$devdsk\.+lternate/ ) { $alternate=1; }; }; # We are not on an alternate link if ( $alternate eq 0 ) { #$size = `diskinfo -b $devrdsk`; for ( `diskinfo -v $devrdsk`) { if ( /^\s+size:\s+(\S+)/ ) { $size=$1; $size = int ( $size/1024 ) if $size; }; if ( /^\s+rev level:\s+(\S+)/ ) { $revlvl=$1; }; }; #print "vendor $vendor ref $ref type $type description $description path $path size $size\n"; $common->addStorages({ MANUFACTURER => $vendor, MODEL => $ref, NAME => $devdsk, DESCRIPTION => $description, TYPE => $type, DISKSIZE => $size, FIRMWARE => $revlvl, }); }; }; } else { # We look for tapes if ( /^\s+(\/dev\/rmt\/\Sm)\s+/ ) { $devdsk=$1; $common->addStorages({ MANUFACTURER => $vendor, MODEL => $ref, NAME => $devdsk, DESCRIPTION => $description, TYPE => $type, DISKSIZE => '' }); }; }; }; }; } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/Linux.pm000066400000000000000000000015371372663377700231330ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::Linux; use strict; use vars qw($runAfter); $runAfter = ["Ocsinventory::Agent::Backend::OS::Generic"]; sub check { $^O =~ /^linux$/ } sub run { my $params = shift; my $common = $params->{common}; chomp (my $osversion = `uname -r`); my $lastloggeduser; my $datelastlog; my @query = $common->runcmd("last -R"); foreach ($query[0]) { if ( s/^(\S+)\s+\S+\s+(\S+\s+\S+\s+\S+\s+\S+)\s+.*// ) { $lastloggeduser = $1; $datelastlog = $2; } } # This will probably be overwritten by a Linux::Distro module. $common->setHardware({ OSNAME => "Linux", OSCOMMENTS => "Unknown Linux distribution", OSVERSION => $osversion, LASTLOGGEDUSER => $lastloggeduser, DATELASTLOGGEDUSER => $datelastlog }); } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/Linux/000077500000000000000000000000001372663377700225675ustar00rootroot00000000000000UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/Linux/Archs/000077500000000000000000000000001372663377700236275ustar00rootroot00000000000000UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/Linux/Archs/ARM.pm000066400000000000000000000002561372663377700246070ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::Linux::Archs::ARM; use strict; use Config; sub check { return 1 if $Config{'archname'} =~ /^arm/; 0; }; sub run{} 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/Linux/Archs/ARM/000077500000000000000000000000001372663377700242465ustar00rootroot00000000000000UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/Linux/Archs/ARM/CPU.pm000066400000000000000000000013031372663377700252300ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::Linux::Archs::ARM::CPU; use strict; sub check { my $params = shift; my $common = $params->{common}; $common->can_read("/proc/cpuinfo") } sub run { my $params = shift; my $common = $params->{common}; my @cpu; my $current; open CPUINFO, ") { print; if (/^Processor\s+:\s*:/) { if ($current) { $common->addCPU($current); } $current = { CPUARCH => 'ARM', }; } $current->{TYPE} = $1 if /Processor\s+:\s+(\S.*)/; } # The last one $common->addCPU($current); } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/Linux/Archs/Alpha.pm000066400000000000000000000002621372663377700252120ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::Linux::Archs::Alpha; use strict; use Config; sub check { return 1 if $Config{'archname'} =~ /^alpha/; 0; }; sub run{} 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/Linux/Archs/Alpha/000077500000000000000000000000001372663377700246545ustar00rootroot00000000000000UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/Linux/Archs/Alpha/CPU.pm000066400000000000000000000015641372663377700256470ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::Linux::Archs::Alpha::CPU; use strict; sub check { my $params = shift; my $common = $params->{common}; $common->can_read("/proc/cpuinfo") } sub run { my $params = shift; my $common = $params->{common}; my @cpu; my $current; open CPUINFO, ") { print; if (/^cpu\s*:/) { if ($current) { $common->addCPU($current); } $current = { CPUARCH => 'Alpha', }; } else { $current->{SERIAL} = $1 if /^cpu serial number\s+:\s+(\S.*)/; $current->{SPEED} = $1 if /cycle frequency \[Hz\]\s+:\s+(\d+)000000/; $current->{TYPE} = $1 if /platform string\s+:\s+(\S.*)/; } } # The last one $common->addCPU($current); } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/Linux/Archs/MIPS.pm000066400000000000000000000002601372663377700247330ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::Linux::Archs::MIPS; use strict; use Config; sub check { return 1 if $Config{'archname'} =~ /^mips/; 0; }; sub run{} 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/Linux/Archs/MIPS/000077500000000000000000000000001372663377700243775ustar00rootroot00000000000000UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/Linux/Archs/MIPS/CPU.pm000066400000000000000000000013071372663377700253650ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::Linux::Archs::MIPS::CPU; use strict; sub check { my $params = shift; my $common = $params->{common}; $common->can_read("/proc/cpuinfo") } sub run { my $params = shift; my $common = $params->{common}; my @cpu; my $current; open CPUINFO, ") { print; if (/^system type\s+:\s*:/) { if ($current) { $common->addCPU($current); } $current = { CPUARCH => 'MIPS', }; } $current->{TYPE} = $1 if /cpu model\s+:\s+(\S.*)/; } # The last one $common->addCPU($current); } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/Linux/Archs/PowerPC.pm000066400000000000000000000002741372663377700255070ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::Linux::Archs::PowerPC; use strict; use Config; sub check { return 1 if $Config{'archname'} =~ /^(ppc|powerpc)/; 0; }; sub run{} 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/Linux/Archs/PowerPC/000077500000000000000000000000001372663377700251465ustar00rootroot00000000000000UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/Linux/Archs/PowerPC/CPU.pm000066400000000000000000000024471372663377700261420ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::Linux::Archs::PowerPC::CPU; use strict; #processor : 0 #cpu : POWER4+ (gq) #clock : 1452.000000MHz #revision : 2.1 # #processor : 1 #cpu : POWER4+ (gq) #clock : 1452.000000MHz #revision : 2.1 # #timebase : 181495202 #machine : CHRP IBM,7029-6C3 # # sub check { my $params = shift; my $common = $params->{common}; $common->can_read ("/proc/cpuinfo") } sub run { my $params = shift; my $common = $params->{common}; my @cpus; my $current; my $isIBM; open CPUINFO, ") { $isIBM = 1 if /^machine\s*:.*IBM/; $current->{TYPE} = $1 if /cpu\s+:\s+(\S.*)/; $current->{SPEED} = $1 if /clock\s+:\s+(\S.*)/; $current->{SPEED} =~ s/\.[0-9]+MHz//; if (/^\s*$/) { if ($current->{TYPE}) { push @cpus, $current; } $current = {}; } } if (/^\s*$/) { if ($current->{TYPE}) { push @cpus, $current; } $current = {}; } foreach my $cpu (@cpus) { $cpu->{MANUFACTURER} = 'IBM' if $isIBM; $cpu->{CPUARCH} = 'PowerPC'; $common->addCPU($cpu); } } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/Linux/Archs/PowerPC/Various.pm000066400000000000000000000031741372663377700271410ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::Linux::Archs::PowerPC::Various; use strict; sub check { 1 }; sub run { my $params = shift; my $common = $params->{common}; ############ Motherboard my $SystemManufacturer; my $SystemModel; my $SystemSerial; my $BiosManufacturer; my $BiosVersion; my $BiosDate; if (open SERIAL,"; $SystemSerial =~ s/[^\,^\.^\w^\ ]//g; # I remove some unprintable char close SERIAL; } if (open MODEL,"; $SystemModel =~ s/[^\,^\.^\w^\ ]//g; close MODEL; } if (open COLOR,"; close COLOR; my ($color) = unpack "h7" , $tmp; $SystemModel = $SystemModel." color: $color" if $color; } if (open OPENBOOT,"; $BiosVersion =~ s/[^\,^\.^\w^\ ]//g; close OPENBOOT; } if (open COPYRIGHT,"; close COPYRIGHT; if ($tmp =~ /Apple/) { # What about the Apple clone? $BiosManufacturer = "Apple Computer, Inc."; $SystemManufacturer = "Apple Computer, Inc." } } $common->setBios ({ SMANUFACTURER => $SystemManufacturer, SMODEL => $SystemModel, SSN => $SystemSerial, BMANUFACTURER => $BiosManufacturer, BVERSION => $BiosVersion, BDATE => $BiosDate, }); } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/Linux/Archs/SPARC.pm000066400000000000000000000002621372663377700250350ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::Linux::Archs::SPARC; use strict; use Config; sub check { return 1 if $Config{'archname'} =~ /^sparc/; 0; }; sub run{} 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/Linux/Archs/SPARC/000077500000000000000000000000001372663377700244775ustar00rootroot00000000000000UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/Linux/Archs/SPARC/CPU.pm000066400000000000000000000011211372663377700254570ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::Linux::Archs::SPARC::CPU; use strict; sub check { my $params = shift; my $common = $params->{common}; $common->can_read ("/proc/cpuinfo") } sub run { my $params = shift; my $common = $params->{common}; my @cpu; my $current = { CPUARCH => 'ARM' }; my $ncpus = 1; open CPUINFO, ") { $current->{TYPE} = $1 if /cpu\s+:\s+(\S.*)/; $ncpus = $1 if /ncpus probed\s+:\s+(\d+)/ } foreach (1..$ncpus) { $common->addCPU($current); } } 1 UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/Linux/Archs/i386.pm000066400000000000000000000002701372663377700246550ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::Linux::Archs::i386; use strict; use Config; sub check { return 1 if $Config{'archname'} =~ /^(i\d86|x86_64)/; 0; }; sub run{} 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/Linux/Archs/i386/000077500000000000000000000000001372663377700243205ustar00rootroot00000000000000UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/Linux/Archs/i386/CPU.pm000066400000000000000000000045431372663377700253130ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::Linux::Archs::i386::CPU; use strict; use warnings; use Data::Dumper; sub check { my $params = shift; my $common = $params->{common}; $common->can_run("lscpu"); } sub run { my $params = shift; my $common = $params->{common}; my @cpuinfos=`LANG=C lscpu`; my $cpu; my $nbcpus; foreach my $info (@cpuinfos){ chomp $info; $cpu->{CPUARCH}=$1 if ($info =~ /Architecture:\s*(.*)/i); $cpu->{NBCPUS}=$1 if ($info =~ /^CPU\(s\):\s*(\d)/i); $cpu->{THREADS}=$1 if ($info =~ /Thread\(s\)\sper\score:\s*(\d)/i); $cpu->{CORES}=$1 if ($info =~ /Core\(s\)\sper\ssocket:\s*(\d)/i); $cpu->{NBSOCKET}=$1 if ($info =~ /Socket\(s\):\s*(\d)/i); $cpu->{TYPE}=$1 if ($info =~ /Model\sname:\s*(.*)/i); if ($info =~ /Vendor ID:\s*(Authentic|Genuine|)(.+)/i){ $cpu->{MANUFACTURER} = $2; $cpu->{MANUFACTURER} =~ s/(TMx86|TransmetaCPU)/Transmeta/; $cpu->{MANUFACTURER} =~ s/CyrixInstead/Cyrix/; $cpu->{MANUFACTURER} =~ s/CentaurHauls/VIA/; } $cpu->{CURRENT_SPEED} = $1 if ($info =~ /CPU\sMHz:\s*(\d+)(|\.\d+)$/i); $cpu->{L2CACHESIZE} = $1 if ($info =~ /L2\scache:\s*(.*)/i); if ($cpu->{CPUARCH} && $cpu->{CPUARCH} eq 'x86_64'){ $cpu->{DATA_WIDTH}='64'; } else { $cpu->{DATA_WIDTH}='32'; } if ($cpu->{TYPE}) { if ($cpu->{TYPE} =~ /([\d\.]+)MHz$/){ $cpu->{SPEED}=$1; } elsif ($cpu->{TYPE} =~ /([\d\.]+)GHz$/){ $cpu->{SPEED}=$1*1000; } } } # Total Threads = number of cores x number of threads per core $cpu->{THREADS}=$cpu->{CORES}*$cpu->{THREADS}; # Set LOGICAL_CPUS with THREADS value $cpu->{LOGICAL_CPUS}=$cpu->{THREADS}; # set CURRENT_ADDRESS_WIDTH with DATA_WIDTH value $cpu->{CURRENT_ADDRESS_WIDTH}=$cpu->{DATA_WIDTH}; my $infos=$common->getDmidecodeInfos(); foreach my $info (@{$infos->{4}}) { next if $info->{Status} && $info->{Status} =~ /Unpopulated|Disabled/i; $cpu->{SERIALNUMBER}=$info->{'Serial Number'}; $cpu->{VOLTAGE}=$info->{'Voltage'}; $cpu->{SOCKET}=$info->{'Socket Designation'}; } for (my $i=0;$i<$cpu->{NBSOCKET};$i++) { $common->addCPU($cpu); } } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/Linux/Archs/m68k.pm000066400000000000000000000002561372663377700247550ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::Linux::Archs::m68k; use strict; use Config; sub check { return 1 if $Config{'archname'} =~ /^m68k/; 0; }; sub run{} 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/Linux/Archs/m68k/000077500000000000000000000000001372663377700244145ustar00rootroot00000000000000UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/Linux/Archs/m68k/CPU.pm000066400000000000000000000014121372663377700253770ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::Linux::Archs::m68k::CPU; use strict; sub check { my $params = shift; my $common = $params->{common}; $common->can_read("/proc/cpuinfo") } sub run { my $params = shift; my $common = $params->{common}; my @cpu; my $current; open CPUINFO, ") { print; if (/^CPU\s+:\s*:/) { if ($current) { $common->addCPU($current); } $current = { CPUARCH => 'm68k', }; } else { $current->{TYPE} = $1 if /CPU:\s+(\S.*)/; $current->{SPEED} = $1 if /Clocking:\s+:\s+(\S.*)/; } } # The last one $common->addCPU($current); } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/Linux/Archs/s390x.pm000066400000000000000000000002611372663377700250520ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::Linux::Archs::s390x; use strict; use Config; sub check { return 1 if $Config{'archname'} =~ /^s390/; 0; }; sub run{} 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/Linux/Archs/s390x/000077500000000000000000000000001372663377700245155ustar00rootroot00000000000000UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/Linux/Archs/s390x/CPU.pm000066400000000000000000000014351372663377700255050ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::Linux::Archs::s390x::CPU; use strict; sub check { my $params = shift; my $common = $params->{common}; $common->can_read("/proc/cpuinfo") } sub run { my $params = shift; my $common = $params->{common}; my $current; my $cpucores; open CPUINFO, ") { print; if (/^vendor\s*:/) { if ($current) { $common->addCPU($current); } } elsif (/^processor [0-9]:\s+(\S.*)/) { $cpucores++; } $current->{MANUFACTURER} = $1 if /vendor_id\s*:\s+(\S.*)/; $current->{SPEED} = $1 if /bogomips per cpu:\s+(\S.*)/; } $current->{CORES} = $cpucores; $common->addCPU($current); } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/Linux/Distro/000077500000000000000000000000001372663377700240335ustar00rootroot00000000000000UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/Linux/Distro/LSB.pm000066400000000000000000000013241372663377700250110ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::Linux::Distro::LSB; use vars qw($runMeIfTheseChecksFailed); $runMeIfTheseChecksFailed = ["Ocsinventory::Agent::Backend::OS::Linux::Distro::NonLSB"]; sub check { my $params = shift; my $common = $params->{common}; $common->can_run("lsb_release") } sub run { my $params = shift; my $common = $params->{common}; my $OSname; chomp($OSname =`lsb_release -is`); my $OSversion; chomp($OSversion =`lsb_release -rs`); my $OSComment; chomp($OSComment =`uname -v`); my $release = "$OSname $OSVersion"; $common->setHardware({ OSNAME => $release, OSVERSION => $OSversion, OSCOMMENTS => "$OSComment" }); } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/Linux/Distro/NonLSB.pm000066400000000000000000000002421372663377700254620ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::Linux::Distro::NonLSB; $runMeIfTheseChecksFailed = ["Ocsinventory::Agent::Backend::OS::Linux::Distro::OSRelease"]; 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/Linux/Distro/NonLSB/000077500000000000000000000000001372663377700251265ustar00rootroot00000000000000UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/Linux/Distro/NonLSB/ArchLinux.pm000066400000000000000000000007651372663377700273710ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::Linux::Distro::NonLSB::ArchLinux; use strict; sub check {-f "/etc/arch-release"} ##### sub findRelease { my $v; open V, "); close V; return "ArchLinux $v"; } sub run { my $params = shift; my $common = $params->{common}; my $OSComment; chomp($OSComment =`uname -v`); $common->setHardware({ OSNAME => findRelease(), OSCOMMENTS => "$OSComment" }); } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/Linux/Distro/NonLSB/CentOS.pm000066400000000000000000000011021372663377700266110ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::Linux::Distro::NonLSB::CentOS; use strict; sub check { -f "/etc/centos-release" && !readlink ("/etc/centos-release") && !-f "/etc/vmware-release" } #### sub findRelease { my $v; open V, "); close V; $v; } sub run { my $params = shift; my $common = $params->{common}; my $OSComment; chomp($OSComment =`uname -v`); $common->setHardware({ OSNAME => findRelease(), OSCOMMENTS => "$OSComment" }); } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/Linux/Distro/NonLSB/Debian.pm000066400000000000000000000010411372663377700266420ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::Linux::Distro::NonLSB::Debian; use strict; sub check {-f "/etc/debian_version" && !-f "/etc/ubuntu_version"} ##### sub findRelease { my $v; open V, "); close V; return "Debian GNU/Linux $v"; } sub run { my $params = shift; my $common = $params->{common}; my $OSComment; chomp($OSComment =`uname -v`); $common->setHardware({ OSNAME => findRelease(), OSCOMMENTS => "$OSComment" }); } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/Linux/Distro/NonLSB/Fedora.pm000066400000000000000000000007521372663377700266700ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::Linux::Distro::NonLSB::Fedora; use strict; sub check {-f "/etc/fedora-release"} ##### sub findRelease { my $v; open V, "); close V; $v; } sub run { my $params = shift; my $common = $params->{common}; my $OSComment; chomp($OSComment =`uname -v`); $common->setHardware({ OSNAME => findRelease(), OSCOMMENTS => "$OSComment" }); } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/Linux/Distro/NonLSB/Gentoo.pm000066400000000000000000000010001372663377700267060ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::Linux::Distro::NonLSB::Gentoo; use strict; sub check {-f "/etc/gentoo-release"} ##### sub findRelease { my $v; open V, "); close V; return "Gentoo Linux $v"; } sub run { my $params = shift; my $common = $params->{common}; my $OSComment; chomp($OSComment =`uname -v`); $common->setHardware({ OSNAME => findRelease(), OSCOMMENTS => "$OSComment" }); } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/Linux/Distro/NonLSB/Knoppix.pm000066400000000000000000000010331372663377700271110ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::Linux::Distro::NonLSB::Knoppix; use strict; sub check {-f "/etc/knoppix_version"} ##### sub findRelease { my $v; open V, "); close V; print $v."\n"; return "Knoppix GNU/Linux $v"; } sub run { my $params = shift; my $common = $params->{common}; my $OSComment; chomp($OSComment =`uname -v`); $common->setHardware({ OSNAME => findRelease(), OSCOMMENTS => "$OSComment" }); } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/Linux/Distro/NonLSB/Mandrake.pm000066400000000000000000000010131372663377700272010ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::Linux::Distro::NonLSB::Mandrake; use strict; sub check {-f "/etc/mandrake-release" && !-f "/etc/mandriva-release"} ##### sub findRelease { my $v; open V, "); close V; $v; } sub run { my $params = shift; my $common = $params->{common}; my $OSComment; chomp($OSComment =`uname -v`); $common->setHardware({ OSNAME => findRelease(), OSCOMMENTS => "$OSComment" }); } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/Linux/Distro/NonLSB/Mandriva.pm000066400000000000000000000010431372663377700272230ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::Linux::Distro::NonLSB::Mandriva; use strict; sub check {-f "/etc/mandrake-release" && -f "/etc/mandriva-release"} ##### sub findRelease { my $v; open V, "); close V; return $v if $v; 0; } sub run { my $params = shift; my $common = $params->{common}; my $OSComment; chomp($OSComment =`uname -v`); $common->setHardware({ OSNAME => findRelease(), OSCOMMENTS => "$OSComment" }); } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/Linux/Distro/NonLSB/Oracle.pm000066400000000000000000000007731372663377700267000ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::Linux::Distro::NonLSB::Oracle; use strict; sub check {-f "/etc/oracle-release"} ##### sub findRelease { my $v; open V, "); close V; return $v if $v; 0; } sub run { my $params = shift; my $common = $params->{common}; my $OSComment; chomp($OSComment =`uname -v`); $common->setHardware({ OSNAME => findRelease(), OSCOMMENTS => "$OSComment" }); } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/Linux/Distro/NonLSB/Redhat.pm000066400000000000000000000011041372663377700266670ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::Linux::Distro::NonLSB::Redhat; use strict; sub check { -f "/etc/redhat-release" && !readlink ("/etc/redhat-release") && !-f "/etc/vmware-release" } #### sub findRelease { my $v; open V, "); close V; $v; } sub run { my $params = shift; my $common = $params->{common}; my $OSComment; chomp($OSComment =`uname -v`); $common->setHardware({ OSNAME => findRelease(), OSCOMMENTS => "$OSComment" }); } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/Linux/Distro/NonLSB/Slackware.pm000066400000000000000000000011411372663377700273750ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::Linux::Distro::NonLSB::Slackware; use strict; sub check {-f "/etc/slackware-version"} ##### sub findRelease { my $v; open V, "); foreach (){ $v=$1 if (/Slackware ([\d.]+)/); close V; return $v; } } sub run { my $params = shift; my $common = $params->{common}; my $OSComment; chomp($OSComment =`uname -v`); $common->setHardware({ OSNAME => "Slackware", OSVERSION => findRelease(), OSCOMMENTS => "$OSComment" }); } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/Linux/Distro/NonLSB/SuSE.pm000066400000000000000000000013151372663377700263030ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::Linux::Distro::NonLSB::SuSE; use strict; sub check { my $params = shift; my $common = $params->{common}; $common->can_read ("/etc/SuSE-release") } sub run { my $v; my $version; my $patchlevel; my $params = shift; my $common = $params->{common}; open V, ") { next if (/^#/); $version=$1 if (/^VERSION = ([0-9]+)/); $patchlevel=$1 if (/^PATCHLEVEL = ([0-9]+)/); } close V; $common->setHardware({ OSNAME => "SUSE Linux Enterprise Server $version SP$patchlevel", OSVERSION => $version, OSCOMMENTS => $patchlevel }); } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/Linux/Distro/NonLSB/Trustix.pm000066400000000000000000000007551372663377700271550ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::Linux::Distro::NonLSB::Trustix; use strict; sub check {-f "/etc/trustix-release"} ##### sub findRelease { my $v; open V, "); close V; $v; } sub run { my $params = shift; my $common = $params->{common}; my $OSComment; chomp($OSComment =`uname -v`); $common->setHardware({ OSNAME => findRelease(), OSCOMMENTS => "$OSComment" }); } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/Linux/Distro/NonLSB/Ubuntu.pm000066400000000000000000000011441372663377700267460ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::Linux::Distro::NonLSB::Ubuntu; use strict; use vars qw($runAfter); $runAfter = ["Ocsinventory::Agent::Backend::OS::Linux::Distro::NonLSB::Debian"]; sub check {-f "/etc/ubuntu_version"} ##### sub findRelease { my $v; open V, "); close V; return "Ubuntu $v"; } sub run { my $params = shift; my $common = $params->{common}; my $OSComment; chomp($OSComment =`uname -v`); $common->setHardware({ OSNAME => findRelease(), OSCOMMENTS => "$OSComment" }); } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/Linux/Distro/NonLSB/VmWare.pm000066400000000000000000000007521372663377700266710ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::Linux::Distro::NonLSB::VmWare; use strict; sub check { -f "/etc/vmware-release" } #### sub findRelease { my $v; open V, "); close V; $v; } sub run { my $params = shift; my $common = $params->{common}; my $OSComment; chomp($OSComment =`uname -v`); $common->setHardware({ OSNAME => findRelease(), OSCOMMENTS => "$OSComment" }); } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/Linux/Distro/OSRelease.pm000066400000000000000000000020231372663377700262100ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::Linux::Distro::OSRelease; use warnings; use strict; sub check { my $params = shift; my $common = $params->{common}; $common->can_read ("/etc/os-release") } sub run { my $v; my $name; my $version; my $description; my $params = shift; my $common = $params->{common}; open V, "/etc/os-release" or warn; foreach () { next if /^#/; $name = $1 if (/^NAME="?([^"]+)"?/); $version = $1 if (/^VERSION_ID="?([^"]+)"?/); $description=$1 if (/^PRETTY_NAME="?([^"]+)"?/); } close V; chomp($name); # Debian version number is set in/etc/debian_version file if (-r "/etc/debian_version") { open V, "/etc/debian_version" or warn; foreach () { $version = $1 if ($_ =~ /^(\d+.*)/); } close V; chomp($version); } $common->setHardware({ OSNAME => "$name $version", OSVERSION => $version, OSCOMMENTS => $description, }); } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/Linux/Domains.pm000066400000000000000000000017771372663377700245330ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::Linux::Domains; use strict; sub check { my $params = shift; my $common = $params->{common}; return unless $common->can_run ("hostname"); my @domain = `hostname -d`; return 1 if @domain || $common->can_read ("/etc/resolv.conf"); 0; } sub run { my $params = shift; my $common = $params->{common}; my $domain; my %domain; my @dns_list; my $dns; chomp($domain = `hostname -d`); open RESOLV, "/etc/resolv.conf" or warn; while (){ if (/^nameserver\s+(\S+)/i) { push(@dns_list,$1); } elsif (!$domain) { $domain{$2} = 1 if (/^(domain|search)\s+(.+)/); } } close RESOLV; if (!$domain) { $domain = join "/", keys %domain; } $dns=join("/",@dns_list); # If no domain name, we send "WORKGROUP" $domain = 'WORKGROUP' unless $domain; $common->setHardware({ WORKGROUP => $domain, DNS => $dns }); } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/Linux/Drives.pm000066400000000000000000000116371372663377700243710ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::Linux::Drives; use strict; sub check { my $params = shift; my $common = $params->{common}; return unless $common->can_run ("df"); my $df = `df -TP`; return 1 if $df =~ /\w+/; 0 } sub run { my $params = shift; my $common = $params->{common}; my %months = ( Jan => 1, Fev => 2, Mar => 3, Apr => 4, May => 5, Jun => 6, Jul => 7, Aug => 8, Sep => 9, Oct => 10, Nov => 11, Dec => 12, ); my %listVolume = (); # Get complementary information in hash tab if ($common->can_run ("lshal")) { my %temp; my $in = 0; my $value; foreach my $line (`lshal`) { chomp $line; if ( $line =~ s{^udi = '/org/freedesktop/Hal/devices/volume.*}{}) { $in = 1; %temp = (); } elsif ($in == 1 and $line =~ s{^\s+(\S+) = (.*) \s*\((int|string|bool|string list|uint64)\)}{} ) { if ($3 ne 'int' and $3 ne 'uint64') { chomp($value = $2); if ($3 eq 'string') { chop($value); #$value =~ s/^'?(.*)'?$/$1/g; $value=substr($value,1,length($value)); $value=substr($value,0,length($value)-1); } $temp{$1} = $value; } else { $temp{$1} = (split(/\W/,$2))[0]; } } elsif ($in== 1 and $line eq '') { $in = 0 ; $listVolume{$temp{'block.device'}} = {%temp}; } } } foreach(`df -TP`) { # TODO retrieve error my $createdate; my $free; my $filesystem; my $label; my $total; my $type; my $volumn; my $serial; if (/^(\S+)\s+(\S+)\s+(\S+)\s+(?:\S+)\s+(\S+)\s+(?:\S+)\s+(\S+)\n/){ $free = sprintf("%i",($4/1024)); $filesystem = $2; $total = sprintf("%i",($3/1024)); $type = $5; $volumn = $1; # no virtual FS next if ($filesystem =~ /^(tmpfs|usbfs|proc|devpts|devshm|udev)$/); next if ($type =~ /^(tmpfs)$/); if ($filesystem =~ /^ext(2|3|4|4dev)/ && $common->can_run('dumpe2fs')) { foreach (`dumpe2fs -h $volumn 2> /dev/null`) { if (/Filesystem UUID:\s+(\S+)/) { $serial = $1; } elsif (/Filesystem created:\s+\w+ (\w+) (\d+) ([\d:]+) (\d{4})$/) { $createdate = $4.'/'.$months{$1}.'/'.$2.' '.$3; } elsif (/Filesystem volume name:\s*(\S.*)/) { $label = $1 unless $1 eq ''; } } } elsif ($filesystem =~ /^xfs$/ && $common->can_run('xfs_db')) { foreach (`xfs_db -r -c uuid $volumn`) { $serial = $1 if /^UUID =\s+(\S+)/; ; } foreach (`xfs_db -r -c label $volumn`) { $label = $1 if /^label =\s+"(\S+)"/; } } elsif ($filesystem =~ /^vfat$/ && $common->can_run('dosfslabel')) { chomp ($label = `dosfslabel $volumn`); } $label =~ s/\s+$//; $serial =~ s/\s+$//; # Check information and improve it if (keys %listVolume) { if ( defined $listVolume{$volumn} ) { if ($filesystem eq '') { $filesystem = $listVolume{$volumn}->{'volume.fstype'};} if ($label eq '') { $label = $listVolume{$volumn}->{'volume.label'};} if ($total eq '') { $total = int($listVolume{$volumn}->{'volume.size'}/(1024*1024) + 0.5);} if ($type eq '') { $type = $listVolume{$volumn}->{'storage.model'};} if ($serial eq '') { $serial = $listVolume{$volumn}->{'volume.uuid'};} delete ($listVolume{$volumn}); } } $common->addDrive({ CREATEDATE => $createdate, FREE => $free, FILESYSTEM => $filesystem, LABEL => $label, TOTAL => $total, TYPE => $type, VOLUMN => $volumn, SERIAL => $serial }); } } if ($common->can_run ("lshal")) { while (my ($k,$v) = each %listVolume ) { $common->addDrive({ FILESYSTEM => $v->{'volume.fstype'}, LABEL => $v->{'volume.label'}, TOTAL => int ($v->{'volume.size'}/(1024*1024) + 0.5), TYPE => $v->{'storage.model'}, VOLUMN => $k, SERIAL => $v->{'volume.uuid'} }); } } } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/Linux/Inputs.pm000066400000000000000000000026451372663377700244160ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::Linux::Inputs; use strict; use warnings; sub run { my $params = shift; my $common = $params->{common}; my $logger = $params->{logger}; my $in; my $vendor; my $phys; my $name; my $type; if (open INPUTS, ") { if (/^I: Bus=.*Vendor=(.*) Prod/){ $in=1; $vendor=$1; } elsif ($_ =~ /^$/) { $in=0; if ($phys && $phys =~ "input"){ $common->addInput({ DESCRIPTION=>$name, CAPTION=>$name, TYPE=>$type }); } } elsif ($in) { if (/^P: Phys=.*(button).*/i) { $phys="nodev"; } elsif (/^P: Phys=.*(input).*/i) { $phys="input"; } if (/^N: Name=\"(.*)\"/i){ $name=$1; } if (/^H: Handlers=(\w+)/i) { if ($1 =~ ".*kbd.*") { $type="Keyboard"; } elsif ($1 =~ ".*mouse.*") { $type="Pointing"; } else { $type=$1; } } } } close INPUTS; } } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/Linux/LVM.pm000066400000000000000000000042621372663377700235670ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::Linux::LVM; use strict; use vars qw($runAfter); $runAfter = ["Ocsinventory::Agent::Backend::OS::Linux::Drives"]; sub check { my $params = shift; my $common = $params->{common}; return unless $common->can_run ("pvs"); 1 } sub run { my $params = shift; my $common = $params->{common}; use constant MB => (1024*1024); if ($common->can_run('pvs')) { foreach (`pvs --noheading --nosuffix --units b -o +pv_uuid`) { chomp; $_ =~s/^\s+//; my @vs_elem=split('\s+'); my $status='VG: '.$vs_elem[1].', Fmt: '.$vs_elem[2].', Attr: '.$vs_elem[3]; $common->addDrive({ FREE => $vs_elem[5]/MB, FILESYSTEM => 'LVM PV', TOTAL => $vs_elem[4]/MB, TYPE => $vs_elem[0], VOLUMN => $status, SERIAL => $vs_elem[6] }); } } if ($common->can_run('vgs')) { foreach (`vgs --noheading --nosuffix --units b -o +vg_uuid,vg_extent_size`) { chomp; $_ =~s/^\s+//; my @vs_elem=split('\s+'); my $status = 'PV/LV: '.$vs_elem[1].'/'.$vs_elem[2] .', Attr: '.$vs_elem[4].', PE: '.($vs_elem[8]/MB).' MB'; $common->addDrive({ FREE => $vs_elem[6]/MB, FILESYSTEM => 'LVM VG', TOTAL => $vs_elem[5]/MB, TYPE => $vs_elem[0], VOLUMN => $status, SERIAL => $vs_elem[7] }); } } if ($common->can_run('lvs')) { foreach (`lvs -a --noheading --nosuffix --units b -o lv_name,vg_name,lv_attr,lv_size,lv_uuid,seg_count`) { chomp; $_ =~s/^\s+//; my @vs_elem=split('\s+'); my $status='Attr: '.$vs_elem[2].', Seg: '.$vs_elem[5]; $common->addDrive({ FREE => 0, FILESYSTEM => 'LVM LV', TOTAL => $vs_elem[3]/MB, TYPE => $vs_elem[1].'/'.$vs_elem[0], VOLUMN => $status, SERIAL => $vs_elem[4] }); } } } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/Linux/Mem.pm000066400000000000000000000012561372663377700236470ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::Linux::Mem; use strict; sub check { my $params = shift; my $common = $params->{common}; $common->can_read ("/proc/meminfo") } sub run { my $params = shift; my $common = $params->{common}; my $unit = 1024; my $PhysicalMemory; my $SwapFileSize; # Memory informations open MEMINFO, "/proc/meminfo"; while(){ $PhysicalMemory=$1 if /^memtotal\s*:\s*(\S+)/i; $SwapFileSize=$1 if /^swaptotal\s*:\s*(\S+)/i; } # TODO $common->setHardware({ MEMORY => sprintf("%i",$PhysicalMemory/$unit), SWAP => sprintf("%i", $SwapFileSize/$unit), }); } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/Linux/Network/000077500000000000000000000000001372663377700242205ustar00rootroot00000000000000UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/Linux/Network/IP.pm000066400000000000000000000022411372663377700250650ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::Linux::Network::IP; sub check { my $params = shift; my $common = $params->{common}; return unless $common->can_run ("ip") || $common->can_run("ifconfig"); 1; } # Initialise the distro entry sub run { my $params = shift; my $common = $params->{common}; my @ip; my @ip6; if ($common->can_run("ip")){ foreach (`ip a`){ if (/inet (\S+)\/\d{1,2}/){ ($1=~/127.+/)?next:push @ip,$1; } elsif (/inet6 (\S+)\d{2}/){ ($1=~/::1\/128/)?next:push @ip6, $1; } } } elsif ($common->can_run("ifconfig")){ foreach (`ifconfig`){ #if(/^\s*inet\s*(\S+)\s*netmask/){ if (/^\s*inet add?r\s*:\s*(\S+)/ || /^\s*inet\s+(\S+)/){ ($1=~/127.+/)?next:push @ip, $1; } elsif (/^\s*inet6\s+(\S+)/){ ($1=~/::1/)?next:push @ip6, $1; } } } my $ip=join "/", @ip; my $ip6=join "/", @ip6; if (defined $ip) { $common->setHardware({IPADDR => $ip}); } else { $common->setHardware({IPADDR => $ip6}); } } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/Linux/Network/Networks.pm000066400000000000000000000676351372663377700264130ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::Linux::Network::Networks; use strict; use warnings; use Data::Dumper; use File::stat; use Time::Local; sub check { my $params = shift; my $common = $params->{common}; if ($common->can_run("ip") && $common->can_load("Net::IP qw(:PROC)") || ($common->can_run("ifconfig") && $common->can_run("route")) && $common->can_load("Net::IP qw(:PROC)")){ return 1; } else { return 0; } } sub getLeaseFile { my $if = @_; my @directories = qw( /var/db /var/lib/dhclient /var/lib/dhcp3 /var/lib/dhcp /var/lib/NetworkManager ); my @patterns = ("*$if*.lease", "*.lease*", "dhclient.leases.$if"); my @files; foreach my $directory (@directories) { next unless -d $directory; foreach my $pattern (@patterns) { push @files, grep { -s $_ } glob("$directory/$pattern"); } } return unless @files; @files = map {$_->[0]} sort {$a->[1]->ctime()<=>$b->[1]->ctime()} map {[$_,stat($_)]} @files; return $files[-1]; } sub _ipdhcp { my $if = shift; my $path; my $dhcp; my $ipdhcp; my $leasepath; $leasepath = getLeaseFile($if); if ( $leasepath and $leasepath =~ /internal/ ) { if (open DHCP, $leasepath) { while() { if (/SERVER_ADDRESS=(\d{1,3}(?:\.\d{1,3}){3})/) { $ipdhcp=$1; } } close DHCP or warn; } else { warn ("Can't open $leasepath\n"); } } elsif( $leasepath ) { if (open DHCP, $leasepath) { my $lease; while(){ $lease = 1 if(/lease\s*{/i); $lease = 0 if(/^\s*}\s*$/); #Interface name if ($lease) { #inside a lease section if (/interface\s+"(.+?)"\s*/){ $dhcp = ($1 =~ /^$if$/); } #Server IP if (/option\s+dhcp-server-identifier\s+(\d{1,3}(?:\.\d{1,3}){3})\s*;/ and $dhcp){ $ipdhcp = $1; } } } close DHCP or warn; } else { warn "Can't open $leasepath\n"; } } return $ipdhcp; } # Initialise the distro entry sub run { my $params = shift; my $common = $params->{common}; my $logger = $params->{logger}; my $description; my $driver; my $ipaddress; my $ipgateway; my $ipmask; my $ipsubnet; my $ipaddress6; my $ipgateway6; my $ipmask6; my $ipsubnet6; my $macaddr; my $pcislot; my $status; my $type; my $virtualdev; my $settings; my $speed; my $current_speed; my $duplex; my $ssid; my $bssid; my $mode; my $version; my $bitrate; my $mtu; my @netsum; my $basedev; my $slave; my %gateway; my @secondary; my $ipsecond; if ($common->can_run("ip")){ my @netsum = `ip addr show`; push @netsum, "\n"; chomp @netsum; for (my $i=0;$i<=$#netsum;$i+=1) { my $line=$netsum[$i]; if ($line =~ /^(\d+(?) { $driver = $1 if /^DRIVER=(\S+)/; $pcislot = $1 if /^PCI_SLOT_NAME=(\S+)/; } close UEVENT; } if (-d "/sys/class/net/$description/wireless"){ my @wifistatus = `iwconfig $description 2>/dev/null`; foreach my $line (@wifistatus){ $ssid = $1 if ($line =~ /ESSID:(\S+)/); $version = $1 if ($line =~ /IEEE (\S+)/); $mode = $1 if ($line =~ /Mode:(\S+)/); $bssid = $1 if ($line =~ /Access Point: (\S+)/); $bitrate = $1 if ($line =~ /Bit\sRate=\s*(\S+\sMb\/s)/i); } $type = "Wifi"; $status=1; } elsif (-f "/sys/class/net/$description/mode") { $type="infiniband"; } else { $type="ethernet"; } if (defined ($ipgateway)) { $common->setHardware({ DEFAULTGATEWAY => $ipgateway }); } elsif (defined ($ipgateway6)){ $common->setHardware({ DEFAULTGATEWAY => $ipgateway6 }); } # Retrieve speed from /sys/class/net/$description/speed $speed=getSpeed($description); # Retrieve duplex from /sys/class/net/$description/duplex $duplex=getDuplex($description); # Retrieve mtu from /sys/class/net/$description/mtu $mtu=getMTU($description); # Retrieve status from /sys/class/net/$description/status $status=getStatus($description); if ($description && $ipaddress) { if ($type eq "Wifi") { $common->addNetwork({ DESCRIPTION => $description, DRIVER => $driver, IPADDRESS => $ipaddress, IPDHCP => _ipdhcp($description), IPGATEWAY => $ipgateway, IPMASK => $ipmask, IPSUBNET => $ipsubnet, MACADDR => $macaddr, PCISLOT => $pcislot, STATUS => $status?"Up":"Down", TYPE => $type, SPEED => $bitrate, SSID => $ssid, BSSID => $bssid, IEEE => $version, MODE => $mode, MTU => $mtu, }); } else { $common->addNetwork({ DESCRIPTION => $description, DRIVER => $driver, IPADDRESS => $ipaddress, IPDHCP => _ipdhcp($description), IPGATEWAY => $ipgateway, IPMASK => $ipmask, IPSUBNET => $ipsubnet, MACADDR => $macaddr, PCISLOT => $pcislot, STATUS => $status?"Up":"Down", TYPE => $type, VIRTUALDEV => $virtualdev, DUPLEX => $duplex?"Full":"Half", SPEED => $speed, MTU => $mtu, }); } } if ($description && $ipaddress6) { if ($type eq "Wifi") { $common->addNetwork({ DESCRIPTION => $description, DRIVER => $driver, IPADDRESS => $ipaddress6, IPDHCP => undef, IPGATEWAY => $ipgateway6, IPMASK => $ipmask6, IPSUBNET => $ipsubnet6, MACADDR => $macaddr, PCISLOT => $pcislot, STATUS => $status?"Up":"Down", TYPE => $type, SPEED => $bitrate, SSID => $ssid, BSSID => $bssid, IEEE => $version, MODE => $mode, MTU => $mtu, }); } else { $common->addNetwork({ DESCRIPTION => $description, DRIVER => $driver, IPADDRESS => $ipaddress6, IPGATEWAY => $ipgateway6, IPDHCP => undef, IPMASK => $ipmask6, IPSUBNET => $ipsubnet6, MACADDR => $macaddr, PCISLOT => $pcislot, STATUS => $status?"Up":"Down", TYPE => $type, DUPLEX => $duplex?"Full":"Half", SPEED => $speed, MTU => $mtu, VIRTUALDEV => $virtualdev, }); } } if ($description && !$ipaddress && !$ipaddress6) { if ($type eq "Wifi") { $common->addNetwork({ DESCRIPTION => $description, DRIVER => $driver, MACADDR => $macaddr, PCISLOT => $pcislot, STATUS => $status?"Up":"Down", TYPE => $type, SPEED => $bitrate, SSID => $ssid, BSSID => $bssid, IEEE => $version, MODE => $mode, MTU => $mtu, }); } else { $common->addNetwork({ DESCRIPTION => $description, DRIVER => $driver, MACADDR => $macaddr, PCISLOT => $pcislot, STATUS => $status?"Up":"Down", TYPE => $type, VIRTUALDEV => $virtualdev, DUPLEX => $duplex?"Full":"Half", SPEED => $speed, MTU => $mtu, }); } } # Virtual devices # Reliable way to get the info if (-d "/sys/devices/virtual/net/") { $virtualdev = (-d "/sys/devices/virtual/net/$description")?"1":"0"; } elsif ($common->can_run("brctl")) { # Let's guess my %bridge; foreach (`brctl show`) { next if /^bridge name/; $bridge{$1} = 1 if /^(\w+)\s/; } if ($pcislot) { $virtualdev = "1"; } elsif ($bridge{$description}) { $virtualdev = "0"; } $type = "bridge"; $common->addNetwork({ DESCRIPTION => $description, TYPE => $type, VIRTUALDEV => $virtualdev, }); } # Check if this is dialup interface if ($description =~ m/^ppp$/) { $type="dialup"; $virtualdev=1; $common->addNetwork({ DESCRIPTION => $description, TYPE => $type, VIRTUALDEV => $virtualdev, }); } # Check if this is a bonding slave if (-d "/sys/class/net/$description/bonding"){ $slave=getslaves($description); $type="aggregate"; $virtualdev=1; $common->addNetwork({ SLAVE => $slave, TYPE => $type, VIRTUALDEV => $virtualdev, }); } # Check if this is an alias or tagged interface if ($description =~ m/^([\w\d]+)[:.]\d+$/) { $basedev=$1; $type="alias"; $virtualdev=1; $common->addNetwork({ BASE => $basedev, DESCRIPTION => $description, TYPE => $type, VIRTUALDEV => $virtualdev, }); } # Check if this is a vlan if (-f "/proc/net/vlan/$description"){ $type="vlan"; $virtualdev=1; $common->addNetwork({ BASE => $basedev, DESCRIPTION => $description, TYPE => $type, VIRTUALDEV => $virtualdev, }); } # Check if this is a secondary ip address if (@secondary) { foreach my $info (@secondary) { $ipsecond=$1 if ($info =~ /inet ((?:\d{1,3}+\.){3}\d{1,3})\/(\d+)/); $basedev=$description; $type="secondary"; $virtualdev=1; $common->addNetwork({ BASE => $basedev?$basedev : undef, DESCRIPTION => $description, IPADDRESS => $ipsecond, IPGATEWAY => $ipgateway, IPMASK => $ipmask, IPSUBNET => $ipsubnet, MACADDR => $macaddr, TYPE => $type, VIRTUALDEV => $virtualdev?"Virtual":"Physical", }); } } $description = $driver = $ipaddress = $ipgateway = $ipmask = $ipsubnet = $ipaddress6 = $ipgateway6 = $ipmask6 = $ipsubnet6 = $macaddr = $pcislot = $status = $type = $virtualdev = $speed = $duplex = $mtu = undef; @secondary=(); } $description = $1 if ($line =~ /^\d+:\s+([^:@]+)/); # Interface name if ($description && $description eq "lo" ) { next; } # loopback interface is not inventoried if ($line =~ /inet ((?:\d{1,3}+\.){3}\d{1,3})\/(\d+)/i && $line !~ /secondary/i){ $ipaddress=$1; $ipmask=getIPNetmask($2); $ipsubnet=getSubnetAddressIPv4($ipaddress,$ipmask); $ipgateway=getIPRoute($ipaddress); } elsif ($line =~ /\s+link\/(\S+)/){ $type=$1; $macaddr=getMAC($description); } elsif ($line =~ /inet6 (\S+)\/(\d{1,2})/i){ $ipaddress6=$1; $ipmask6=getIPNetmaskV6($2); $ipsubnet6=getSubnetAddressIPv6($ipaddress6,$ipmask6); $ipgateway6=getIPRoute($ipaddress6); } # Retrieve secondary ip addresses if defined if ($line =~ /secondary/i){ push @secondary, $line; } } } elsif ($common->can_run("ifconfig")){ foreach my $line (`ifconfig -a`) { if ($line =~ /^$/ && $description && $macaddr) { # end of interface section # I write the entry if (defined($ipgateway)){ $common->setHardware({ DEFAULTGATEWAY => $ipgateway }); } elsif (defined($ipgateway6)) { $common->setHardware({ DEFAULTGATEWAY => $ipgateway6 }); } if (-d "/sys/class/net/$description/wireless"){ my @wifistatus = `iwconfig $description`; foreach my $line (@wifistatus){ $ssid = $1 if ($line =~ /ESSID:(\S+)/); $version = $1 if ($line =~ /IEEE (\S+)/); $mode = $1 if ($line =~ /Mode:(\S+)/); $bssid = $1 if ($line =~ /Access Point: (\S+)/); $bitrate = $1 if ($line =~ /Bit\sRate=\s*(\S+\sMb\/s)/i); } $type = "Wifi"; } elsif (-f "/sys/class/net/$description/mode") { $type="infiniband"; } if (open UEVENT, ") { $driver = $1 if /^DRIVER=(\S+)/; $pcislot = $1 if /^PCI_SLOT_NAME=(\S+)/; } close UEVENT; } # Retrieve speed from /sys/class/net/$description/speed $speed=getSpeed($description); # Retrieve duplex from /sys/class/net/$description/duplex $duplex=getDuplex($description); # Virtual devices # Reliable way to get the info if (-d "/sys/devices/virtual/net/") { $virtualdev = (-d "/sys/devices/virtual/net/$description")?"1":"0"; } elsif ($common->can_run("brctl")) { # Let's guess my %bridge; foreach (`brctl show`) { next if /^bridge name/; $bridge{$1} = 1 if /^(\w+)\s/; } if ($pcislot) { $virtualdev = "1"; } elsif ($bridge{$description}) { $virtualdev = "0"; } $type = "bridge"; } # Check if this is dialup interface if ($description =~ m/^ppp$/) { $type="dialup"; $virtualdev=1; } # Check if this is an alias or tagged interface if ($description =~ m/^([\w\d]+)[:.]\d+$/) { $basedev=$1; $type="alias"; $virtualdev=1; } # Check if this is a bonding slave if (-d "/sys/class/net/$description/bonding"){ $slave=getslaves($description); $type="aggregate"; $virtualdev=1; } # Check if this is a vlan if (-f "/proc/net/vlan/$description"){ $type="vlan"; $virtualdev=1; } if ($description && $ipaddress) { if ($type eq "Wifi") { $common->addNetwork({ DESCRIPTION => $description, DRIVER => $driver, IPADDRESS => $ipaddress, IPDHCP => _ipdhcp($description), IPGATEWAY => $ipgateway, IPMASK => $ipmask, IPSUBNET => $ipsubnet, MACADDR => $macaddr, PCISLOT => $pcislot, STATUS => $status?"Up":"Down", TYPE => $type, SPEED => $bitrate, SSID => $ssid, BSSID => $bssid, IEEE => $version, MODE => $mode, }); } else { $common->addNetwork({ BASE => $basedev?$basedev : undef, DESCRIPTION => $description, DRIVER => $driver, IPADDRESS => $ipaddress, IPDHCP => _ipdhcp($description), IPGATEWAY => $ipgateway, IPMASK => $ipmask, IPSUBNET => $ipsubnet, MACADDR => $macaddr, PCISLOT => $pcislot, STATUS => $status?"Up":"Down", TYPE => $type, VIRTUALDEV => $virtualdev, DUPLEX => $duplex?"Full":"Half", SPEED => $speed, MTU => $mtu, SLAVE => $slave?$slave : undef, }); } } elsif ($description && $ipaddress6) { $common->addNetwork({ BASE => $basedev?$basedev : undef, DESCRIPTION => $description, DRIVER => $driver, IPADDRESS => $ipaddress6, IPDHCP => _ipdhcp($description), IPGATEWAY => $ipgateway6, IPMASK => $ipmask6, IPSUBNET => $ipsubnet6, MACADDR => $macaddr, PCISLOT => $pcislot, STATUS => $status?"Up":"Down", TYPE => $type, VIRTUALDEV => $virtualdev, DUPLEX => $duplex?"Full":"Half", SPEED => $speed, MTU => $mtu, SLAVE => $slave?$slave : undef, }); } } if ($line =~ /^$/) { # End of section $description = $driver = $ipaddress = $ipgateway = $ipmask = $ipsubnet = $macaddr = $pcislot = $status = $type = $virtualdev = $speed = $duplex = $mtu = undef; } else { # In a section if ($line =~ /^(\S+):/) { $description = $1; # Interface name if ($description && $description eq "lo" ) { next; } # loopback interface is not inventoried } if ($line =~ /inet add?r:(\S+)/i || $line =~ /^\s*inet\s+(\S+)/i || $line =~ /inet (\S+)\s+netmask/i){ $ipaddress=$1; $ipmask=getIPNetmask($ipaddress); $ipsubnet=getSubnetAddressIPv4($ipaddress,$ipmask); $ipgateway=getRouteIfconfig($ipaddress); } elsif ($line =~ /inet6 (\S+)\s+prefixlen\s+(\d{2})/i){ $ipaddress6=$1; $ipmask6=getIPNetmaskV6($ipaddress6); $ipsubnet6=getSubnetAddressIPv6($ipaddress6,$ipmask6); $ipgateway6=getRouteIfconfig($ipaddress6); } $macaddr = $1 if ($line =~ /hwadd?r\s+(\w{2}:\w{2}:\w{2}:\w{2}:\w{2}:\w{2})/i || $line =~ /ether\s+(\w{2}:\w{2}:\w{2}:\w{2}:\w{2}:\w{2})/i); $status = 1 if ($line =~ /^\s+UP\s/ || $line =~ /flags=.*[<,]UP[,>]/); $type = $1 if ($line =~ /link encap:(\S+)/i); $type = $2 if ($line =~ /^\s+(loop|ether).*\((\S+)\)/i); if ($type eq "ether" || $type eq "Ethernet") { $type="ethernet"; } # Retrieve mtu from /sys/class/net/$description/mtu $mtu=getMTU($description); } } } } sub getslaves{ my ($name)=@_; my @slaves= map{$_ =~/\/lowr_(\w+)$/} glob("/sys/class/net/$name/lower_*"); return join(",", @slaves); } sub getSpeed{ my ($prefix)=@_; my $speed; my $current_speed=0; return undef unless $prefix; if ( ! -z "/sys/class/net/$prefix/speed") { open SPEED, "){ $current_speed=$_; } close SPEED; chomp($current_speed); if ($current_speed eq "65535" || $current_speed eq ""){ $current_speed = "Unknown"; } if ($current_speed gt 100 ){ $speed = ($current_speed/1000)." Gbps"; } else { $speed = $current_speed." Mbps"; } } return $speed; } sub getDuplex{ my ($prefix)=@_; my $duplex; return undef unless $prefix; if (open DUPLEX, "){ $duplex=chomp($_); } close DUPLEX; } return $duplex; } sub getMTU { my ($prefix)=@_; my $mtu; return undef unless $prefix; if (open MTU, "){ chomp; $mtu=$_; } close MTU; } return $mtu; } sub getStatus { my ($prefix)=@_; my $status; return undef unless $prefix; if (open STATUS, "){ chomp; $status=$_; } close STATUS; } return $status; } sub getMAC { my ($prefix)=@_; my $mac; return undef unless $prefix; if (open MAC, "){ chomp; $mac=$_; } close MAC; } return $mac; } sub getSubnetAddressIPv4 { my ($address,$mask)=@_; return undef unless $address && $mask; my $binaddress=ip_iptobin($address, 4); my $binmask=ip_iptobin($mask, 4); my $binsubnet=$binaddress & $binmask; return ip_bintoip($binsubnet, 4); } sub getIPNetmask { my ($prefix) = @_; return undef unless $prefix; return ip_bintoip(ip_get_mask($prefix, 4), 4); } sub getSubnetAddressIPv6 { my ($address,$mask)=@_; return undef unless $address && $mask; my $binaddress = ip_iptobin(ip_expand_address($address, 6),6); my $binmask = ip_iptobin(ip_expand_address($mask, 6),6); my $binsubnet = $binaddress & $binmask; return ip_compress_address(ip_bintoip($binsubnet, 6),6); } sub getIPNetmaskV6 { my ($prefix) = @_; return undef unless $prefix; return ip_compress_address(ip_bintoip(ip_get_mask($prefix, 6), 6),6); } sub getIPRoute { my ($prefix) = @_; my $route; return undef unless $prefix; if (ip_is_ipv4($prefix)) { foreach my $line (`ip route`){ $route = $1 if $line =~ /^default via\s+(\S+)/; } } elsif (ip_is_ipv6($prefix)) { foreach my $line (`ip -6 route`){ next if $line =~ /^Unreachable/; $route = $1 if $line =~ /^(.*)\/.*/; } } return $route; } sub getRouteIfconfig { my ($prefix) = @_; my $route; return undef unless $prefix; if (ip_is_ipv4($prefix)) { foreach my $line (`route -n`){ next if $line =~ /^Default/; $route = $1 if $line =~ /^0.0.0.0\s+(\S+)/; } } elsif (ip_is_ipv6($prefix)) { foreach my $line (`route -6n`){ next if $line =~ /^2002/; $route = $1 if $line =~ /^(.*)\/.*/; } } return $route; } 1; =head1 NAME OCSInventory::Agent::Backend::OS::Linux::Network::Networks - Network-related functions =head1 DESCRIPTION This module retrieves network informations. =head1 FUNCTIONS =head2 getSpeed Returns the speed of the card. =head2 getDuplex Returns duplex state of the card. =head2 getMTU Returns the mtu of the card. =head2 getStatus Returns the status of the card. =head2 getMAC Returns the mac address. =head2 getSubnetAddress($address, $mask) Returns the subnet address for IPv4. =head2 getSubnetAddressIPv6($address, $mask) Returns the subnet address for IPv6. =head2 getIPNetmask($prefix) Returns the network mask for IPv4. =head2 getIPNetmaskV6($prefix) Returns the network mask for IPv6. =head2 getslaves Returns if card has a bonding. =head2 getIPRoute Returns the gateway defined int he ip config. =head2 getRouteIfconfig Returns the gateway defined in the ip config. =back UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/Linux/Storages.pm000066400000000000000000000533031372663377700247200ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::Linux::Storages; use strict; use XML::Simple; sub check { my $params = shift; my $common = $params->{common}; return unless ($common->can_run("lshw") || $common->can_run("lsscsi") || $common->can_run("lsblk") || $common->can_run("smartctl") || $common->can_run("multipath") || $common->can_run("udevinfo") || $common->can_run("udevadm") || $common->can_run("hdparm")); } ######## TODO # Do not remove, used by other modules sub getFromUdev { my @devs; foreach (glob ("/dev/.udev/db/*")) { my ($scsi_coid, $scsi_chid, $scsi_unid, $scsi_lun, $path, $device, $vendor, $model, $revision, $serial, $serial_short, $type, $bus, $capacity); if (/^(\/dev\/.udev\/db\/.*)([sh]d[a-z]+)$/) { $path = $1; $device = $2; open (PATH, $1 . $2); while () { if (/^S:.*-scsi-(\d+):(\d+):(\d+):(\d+)/) { $scsi_coid = $1; $scsi_chid = $2; $scsi_unid = $3; $scsi_lun = $4; } $vendor = $1 if /^E:ID_VENDOR=(.*)/; $model = $1 if /^E:ID_MODEL=(.*)/; $revision = $1 if /^E:ID_REVISION=(.*)/; $serial = $1 if /^E:ID_SERIAL=(.*)/; $serial_short = $1 if /^E:ID_SERIAL_SHORT=(.*)/; $type = $1 if /^E:ID_TYPE=(.*)/; $bus = $1 if /^E:ID_BUS=(.*)/; } $serial_short = $serial unless $serial_short =~ /\S/; $capacity = getCapacity($device); push (@devs, {NAME => $device, MANUFACTURER => $vendor, MODEL => $model, DESCRIPTION => $bus, TYPE => $type, DISKSIZE => $capacity, SERIALNUMBER => $serial_short, FIRMWARE => $revision, SCSI_COID => $scsi_coid, SCSI_CHID => $scsi_chid, SCSI_UNID => $scsi_unid, SCSI_LUN => $scsi_lun}); close (PATH); } } return @devs; } sub getFromSysProc { my($dev, $file) = @_; my $value; foreach ("/sys/block/$dev/device/$file", "/proc/ide/$dev/$file") { next unless open PATH, $_; chomp(my $value = ); $value =~ s/^(\w+)\W*/$1/; return $value; } } sub getCapacity { my ($dev) = @_; my $cap; chomp ($cap = `fdisk -s /dev/$dev 2>/dev/null`); #requires permissions on /dev/$dev $cap = int ($cap*1024) if $cap; return $cap; } sub getDescription { my ($name, $manufacturer, $description, $serialnumber) = @_; # detected as USB by udev # TODO maybe we should trust udev detection by default? return "USB" if (defined ($description) && $description =~ /usb/i); if ($name =~ /^s/) { # /dev/sd* are SCSI _OR_ SATA if ($manufacturer =~ /ATA/ || $serialnumber =~ /ATA/ || $description =~ /ATA/i) { return "SATA"; } else { return "SCSI"; } } else { return "IDE"; } } sub getManufacturer { my ($model) = @_; #if($model =~ /(maxtor|western|sony|compaq|hewlett packard|ibm|seagate|toshiba|fujitsu|lg|samsung|nec|transcend)/i) { # return ucfirst(lc($1)); if ($model =~ /^(IBM|LG|NEC$)/){ return $1; } elsif ($model =~ /(maxtor|western|sony|compaq|hewlett packard|ibm|seagate|toshiba|fujitsu|lg|samsung|nec$|transcend)/i) { $model = lc($1); $model = s/\b(\w)/\u$1/g; return $model; } elsif ($model =~ /^HP/) { return "Hewlett-Packard"; } elsif ($model =~ /^WD/) { return "Western Digital"; } elsif ($model =~ /^ST/) { return "Seagate"; } elsif ($model =~ /^(HD|IC|HU)/) { return "Hitachi"; } elsif ($model =~ /^NECVMWar/) { return "VMware"; } elsif ($model =~ /^VBOX/){ return "Virtual Box"; } else { return $model; } } sub getMultipathDisks { my @mpList = `multipath -l`; my @devs; my $volume; my $serial; my $dm; my $manufacturer; my $model; foreach my $line (@mpList) { if ($line =~ /^([\w\d]+)\s\((.*)\)\s(dm-\d+)\s(\w+)\s+,([\w\d\s]+)$/i) { $volume = $1; $serial = $2; $dm = $3; $manufacturer = $4; $model = $5; } if ($line =~ /size=(\d+)(\w+)\s/) { my $size = $1; my $unit = $2; # conversion to mebibyte my %conversion = ( "T" => 1000**4, "G" => 1000**3, "M" => 1000**2, "K" => 1000, ); if ($conversion{$unit}) { $size = $size / $conversion{$unit} * 2**20; } else { $size = $size." ".$unit; } push (@devs, {NAME=>$dm, DESCRIPTION=>$volume, TYPE=>"Multipath volume", MODEL=>$model, SERIALNUMBER=>$serial, MANUFACTURER=>$manufacturer}); } if ($line =~ /(sd[a-z]+)/i) { push (@devs, {NAME=>$1, DESCRIPTION=>"Child of $dm", TYPE=>"Multipath child"}); } } return @devs; } # some hdparm release generated kernel error if they are # run on CDROM device # http://forums.ocsinventory-ng.org/viewtopic.php?pid=20810 sub correctHdparmAvailable { my $hdparmVersion = `hdparm -V`; if ($hdparmVersion =~ /^hdparm v(\d+)\.(\d+)(\.|$)/) { return 1 if $1>9; return 1 if $1==9 && $2>=15; } return; } # get available md softraid devices sub getMdDevices { return unless ( open(my $fh, '<:encoding(UTF-8)', '/proc/mdstat') ); my @lines = <$fh>; close($fh); my $devName; my $raidLevel; my @devs; foreach (@lines) { chomp($_); if (/^(md\d*)\s*:\s*\w*\s*(raid\d)/) { $devName = $1; $raidLevel = $2; push (@devs, {NAME => $devName, MODEL => $raidLevel}); } } return @devs; } # get available block devices from /dev sub getFromDev { my @devs; my @disks; my $dir = "/dev"; opendir (my $dh, $dir) or die $!; @disks = grep{/^sd[a-z][a-z]?$|^vd[a-z][a-z]?$|^sr\d+$/} readdir($dh); foreach (@disks) { push (@devs, {NAME => $_}); } return @devs; } # get data from lshw sub getFromLshw { my @devs; my @inputlines = `lshw -class disk -xml -quiet`; return unless $inputlines[0] =~ /xml/i; my $foundcdroms = 0; my $input; foreach (@inputlines) { if ( /\/g) { # adding "" root element because $input =~ s/\?>/\?>\n/; # prior to version B.02.16, "lshw -class disk -xml" produces xml output $input .= "\n"; # without the "" root element, which does not parse correctly. } my $xml = new XML::Simple; my $data = $xml->XMLin($input); # my $nodes = $data->{list}->{node}; my $nodes = $data->{list}; foreach my $device (sort keys %$nodes) { my $description = ""; my $size = 0; my $sizeUnits = ""; my $name = "not set"; my $type = ""; my $vendor = ""; my $model = ""; my $serial = ""; my $revision = ""; if ($nodes->{$device}->{description}) { $description = $nodes->{$device}->{description}; } if ($nodes->{$device}->{size}) { my %units = ('bytes', 1, 'kilobytes', 10**3, 'megabytes', 10**6, 'gigabytes', 10**9, 'terabytes', 10**12); $sizeUnits = $nodes->{$device}->{size}->{units}; $size = $nodes->{$device}->{size}->{content}; $size = $size * $units{$sizeUnits}; $size = sprintf "%i", $size; } if ($nodes->{$device}->{logicalname}) { $name = $nodes->{$device}->{logicalname}; if (ref($name) eq 'ARRAY') { foreach (@{$name}) { if (!readlink $_) { $name = $_; last; } } } $name =~ s/\/dev\///; } if ($nodes->{$device}->{type}) { $type = $nodes->{$device}->{type}; } if ($nodes->{$device}->{vendor}) { $vendor = $nodes->{$device}->{vendor}; } if ($nodes->{$device}->{model}) { $model = $nodes->{$device}->{model}; } if ($nodes->{$device}->{serial}) { $serial = $nodes->{$device}->{serial}; } push (@devs, { NAME => $name, MANUFACTURER => getManufacturer($vendor), MODEL => $model, DESCRIPTION => $description, TYPE => $type, DISKSIZE => $size, SERIALNUMBER => $serial, FIRMWARE => $revision }); } return @devs; } # get data from lsscsi sub getFromLsscsi { my @devs; my ($id, $type, $vendor, $model, $rev, $device); foreach my $line (`lsscsi`) { ($id, $type, $vendor, $model, $rev, $device) = unpack ('a13a8a9a17a6a15', $line); $vendor =~ s/\s*$//; $type =~ s/\s*$//; $model =~ s/\s*$//; my @columns = split /\s+/, $line; my $deviceName = $columns[-1]; $deviceName =~ s/\/dev\///; #debug print Dumper {NAME => $deviceName, MANUFACTURER => $vendor, TYPE => $type, MODEL => $model}; if ($type =~ /cd\/dvd|disk/) { push (@devs, {NAME => $deviceName, MANUFACTURER => getManufacturer($vendor), TYPE => $type, MODEL => $model}); } } return @devs; } # get data from lsblk sub getFromLsblk { my @devs; foreach my $line (`lsblk -ldbn`) { my @columns = split /\s+/, $line; my $deviceName = $columns[0]; my $size = $columns[3]; my $type = $columns[5]; $size = "" if ($type =~ /rom/); push (@devs, {NAME => $deviceName, TYPE => $type, DISKSIZE => $size}); } return @devs; } # get data from smartctl sub getFromSmartctl { my ($params, $devices) = @_; my @devs; foreach my $device (keys %$devices) { my $vendor = ""; my $product = ""; my $revision = ""; my $size = ""; my $type = ""; my $serialnum = ""; my $description = ""; my $devName = $devices->{$device}->{NAME}; foreach my $line (`smartctl -i /dev/$devName`) { chomp($line); if ($line =~ m/Model Family:\s+(\S+.*)\s*$/i){ $vendor = $1; } elsif ($line =~ m/Vendor:\s+(\S+.*)\s*$/i) { $vendor = $1; } elsif ($line =~ m/Device Model:\s+(\S+.*)\s*$/i){ $product = $1; } elsif ($line =~ m/Product:\s+(\S+.*)\s*$/i) { $product = $1; } elsif ($line =~ m/Revision:\s+(\S+.*)\s*$/i) { $revision = $1; } elsif ($line =~ m/Firmware Version:\s+(\S+.*)\s*$/i) { $revision = $1; } elsif ($line =~ m/Serial Number:\s+(\S+.*)\s*$/i) { $serialnum = $1; } elsif ($line =~ m/User Capacity:\s+([\d\.,]+)\s+bytes/i) { $size = $1; $size =~ s/[\.,]//g; } elsif ($line =~ m/Device type:\s+(\S+.*)\s*$/i) { $type = $1; } elsif ($line =~ m/Model Family\s+(\S.*)\s*/i) { $description = $1; } } push (@devs, { NAME => $devName, MANUFACTURER => getManufacturer($vendor), MODEL => $product, FIRMWARE => $revision, TYPE => $type, DISKSIZE => $size, SERIALNUMBER => $serialnum, DESCRIPTION => $description }); } return @devs; } # get data from UDEV sub getFromuDev2 { my $params = shift; my $common = $params->{common}; my ($devices) = @_; my @input; my @devs; foreach my $device (keys %$devices) { my $type = ""; my $model = ""; my $vendor = ""; my $firmware = ""; my $serial = ""; my $serial_short = ""; my $serial_scsi = ""; my $serial_md = ""; my $devName = $devices->{$device}->{NAME}; if ($common->can_run("udevadm")) { @input = `udevadm info -q all -n /dev/$devName`; } else { @input = `udevinfo -q all -n /dev/$devName`; } foreach my $line (@input) { if ($line =~ m/ID_TYPE=(\S+.*)\s*$/){ $type = $1; } elsif ($line =~ m/ID_MODEL=(\S+.*)\s*$/) { $model = $1; $model =~ s/_/ /g; } elsif ($line =~ m/ID_VENDOR=(\S+.*)\s*$/) { $vendor = $1; } elsif ($line =~ m/ID_REVISION=(\S+.*)\s*$/) { $firmware = $1; } elsif ($line =~ m/ID_SERIAL_SHORT=(\S+.*)\s*$/) { $serial_short = $1; } elsif ($line =~ m/ID_SCSI_SERIAL=(\S+.*)\s*$/) { $serial_scsi = $1; } elsif ($line =~ m/ID_SERIAL=(\S+.*)\s*$/) { $serial = $1; } if ($line =~ m/MD_LEVEL=(\S+.*)\s*$/) { $model = $1; } elsif ($line =~ m/MD_METADATA=(\d\.?\d?)/) { $firmware = $1; $firmware = "MD METADATA ".$firmware; } elsif ($line =~ m/MD_UUID=(\S+.*)\s*$/) { $serial_md = $1; } } $serial = $serial_short unless $serial_short eq ""; # prefer serial_short over serial $serial = $serial_scsi unless $serial_scsi eq ""; $serial = $serial_md unless $serial_md eq ""; if ($devName =~ /md\d+/) { # if device is a multiple disk softraid $type = "MD"; $vendor = "Linux"; } push (@devs, { NAME => $devName, TYPE => $type, MODEL => $model, MANUFACTURER => getManufacturer($vendor), FIRMWARE => $firmware, SERIALNUMBER => $serial }); } return @devs; } sub run { my $params = shift; my $common = $params->{common}; my $logger = $params->{logger}; my $devices = {}; my ($serial,$cap,$unit,$model,$manufacturer,$type,$desc,$firmware,$name); my @partitions; # Get complementary information in hash tab if ($common->can_run ("lshal")) { my %temp; my $in = 0; my $value; foreach my $line (`lshal`) { chomp $line; if ($line =~ s{^udi = '/org/freedesktop/Hal/devices/storage.*}{}) { $in = 1; %temp = (); } elsif ($in == 1 and $line =~ s{^\s+(\S+) = (.*) \s*\((int|string|bool|string list|uint64)\)}{} ) { my $key = $1; my $value = $2; $value =~ s/^'(.*)'\s*$/$1/; # Drop the quote $value =~ s/\s+$//; # Drop the trailing white space if ($key eq 'storage.serial') { $temp{SERIALNUMBER} = $value; } elsif ($key eq 'storage.firmware_version') { $temp{FIRMWARE} = $value; } elsif ($key eq 'block.device') { $value =~ s/\/dev\/(\S+)/$1/; $temp{NAME} = $value; } elsif ($key eq 'info.vendor') { $temp{MANUFACTURER} = getManufacturer($value); } elsif ($key eq 'storage.model') { $temp{MODEL} = $value; } elsif ($key eq 'storage.drive_type') { $temp{TYPE} = $value; } elsif ($key eq 'storage.size') { $temp{DISKSIZE} = int($value/(1024*1024) + 0.5); } } elsif ($in== 1 and $line eq '' and $temp{NAME}) { $in = 0 ; $devices->{$temp{NAME}} = {%temp}; } } } foreach my $device (getMultipathDisks($params)) { my $name = $device->{NAME}; foreach my $f ("NAME", "MANUFACTURER", "MODEL", "SERIALNUMBER", "DESCRIPTION", "TYPE") { $devices->{$name}->{$f} = $device->{$f}; } } foreach my $device (getFromDev($params)) { my $name = $device->{NAME}; foreach my $f ("NAME") { if($devices->{$name}->{$f} eq "") { #debug print "getFromDev $name $f device->{\$f} $device->{$f}\n"; $devices->{$name}->{$f} = $device->{$f}; } } } foreach my $device (getMdDevices($params)) { my $name = $device->{NAME}; foreach my $f ("NAME", "MODEL") { if ($devices->{$name}->{$f} eq "") { $devices->{$name}->{$f} = $device->{$f}; } } } foreach my $device (getFromSmartctl($params,$devices)) { my $name = $device->{NAME}; foreach my $f ("NAME", "MANUFACTURER", "TYPE", "MODEL", "DISKSIZE", "FIRMWARE", "SERIALNUMBER", "DESCRIPTION") { if ($devices->{$name}->{$f} eq "") { #debug print "getFromSmartctl $name $f device->{\$f} $device->{$f}\n"; $devices->{$name}->{$f} = $device->{$f}; } } } foreach my $device (getFromuDev2($params,$devices)) { my $name = $device->{NAME}; foreach my $f ("NAME", "MANUFACTURER", "TYPE", "MODEL", "FIRMWARE", "SERIALNUMBER") { if ($devices->{$name}->{$f} eq "") { #debug print "getFromuDev2 $name $f device->{\$f} $device->{$f}\n"; $devices->{$name}->{$f} = $device->{$f}; } } } foreach my $device (getFromLshw($params)) { my $name = $device->{NAME}; foreach my $f ("NAME", "MANUFACTURER", "MODEL", "DESCRIPTION", "TYPE", "DISKSIZE", "SERIALNUMBER", "FIRMWARE") { if ($devices->{$name}->{$f} eq "") { #debug print "getFromLshw $name $f device->{\$f} $device->{$f}\n"; $devices->{$name}->{$f} = $device->{$f}; } } } foreach my $device (getFromLsblk($params)) { my $name = $device->{NAME}; foreach my $f ("NAME", "DISKSIZE", "TYPE") { if ($devices->{$name}->{$f} eq "") { #debug print "getFromLsblk $name $f device->{\$f} $device->{$f}\n"; $devices->{$name}->{$f} = $device->{$f}; } } } foreach my $device (getFromUdev($params)) { my $name = $device->{NAME}; foreach my $f ("NAME", "MANUFACTURER", "MODEL", "DESCRIPTION", "TYPE", "DISKSIZE", "SERIALNUMBER", "FIRMWARE", "SCSI_COID", "SCSI_CHID", "SCSI_UNID", "SCSI_LUN") { if ($devices->{$name}->{$f} eq "") { #debug print "getFromuDev $name $f device->{\$f} $device->{$f}\n"; $devices->{$name}->{$f} = $device->{$f}; } } } foreach my $device (getFromLsscsi($params)) { my $name = $device->{NAME}; foreach my $f ("NAME", "MANUFACTURER", "TYPE", "MODEL") { if ($devices->{$name}->{$f} eq "") { #debug print "getFromLsscsi $name $f device->{\$f} $device->{$f}\n"; $devices->{$name}->{$f} = $device->{$f}; } } } my $logical_drive = undef; if ($common->can_run ('arcconf') ) { my ($cur_cont,$info,$key,$dev,$controller); $controller = Ocsinventory::Agent::Backend::OS::Linux::Storages::Adaptec::parse_config(); foreach $cur_cont (keys %{$controller}){ #travers Controller $info = $controller->{$cur_cont}; foreach $key (keys %{$info}){ #travers Infos of Controller if ($key=~m/logical drive/) { $logical_drive= $info->{$key}; } } } } foreach my $device (sort (keys %$devices)) { if ($devices->{$device}->{TYPE} =~ /(CD)|(CD\/DVD)|(DVD)|(BD)/i) { $devices->{$device}->{DISKSIZE} = "0000"; } elsif ($devices->{$device}->{DISKSIZE}) { $devices->{$device}->{DISKSIZE} = $devices->{$device}->{DISKSIZE} * 10**-6; # we need MB for the view } if (!$devices->{$device}->{DESCRIPTION}) { $devices->{$device}->{DESCRIPTION} = getFromSysProc($device,"description"); } if (!$devices->{$device}->{MANUFACTURER} or $devices->{$device}->{MANUFACTURER} eq 'ATA'or $devices->{$device}->{MANUFACTURER} eq '') { $devices->{$device}->{MANUFACTURER} = getManufacturer($devices->{$device}->{MODEL}); } if (!$devices->{$device}->{DISKSIZE} && $devices->{$device}->{TYPE} =~ /disk/) { $devices->{$device}->{DISKSIZE} = getCapacity($devices->{$device}->{NAME})*10**-6; } #if ($devices->{$device}->{CAPACITY} =~ /^cdrom$/) { # $devices->{$device}->{CAPACITY} = getCapacity($devices->{$device}->{NAME})*10**-6; #} if ($devices->{$device}->{MANUFACTURER}=~m/Adaptec/) {#check if found devices are Logical Devices foreach my $devkey (keys %{$logical_drive}) { if($devices->{$device}->{MODEL} =~m/$logical_drive->{$devkey}->{'Logical device name'}/) { #Correct infos $devices->{$device}->{TYPE}="Logical Drive"; $devices->{$device}->{DISKSIZE} = $logical_drive->{$devkey}->{'Size'}; } } } $common->addStorages($devices->{$device}); } } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/Linux/Storages/000077500000000000000000000000001372663377700243565ustar00rootroot00000000000000UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/Linux/Storages/3ware.pm000066400000000000000000000144051372663377700257410ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::Linux::Storages::3ware; use Ocsinventory::Agent::Backend::OS::Linux::Storages; # Tested on 2.6.* kernels # # Cards tested : # # 8006-2LP # 9500S-4LP # 9550SXU-4LP # 9550SXU-8LP # 9650SE-2LP # 9650SE-4LPML # 9650SE-8LPML # # AMCC/3ware CLI (version 2.00.0X.XXX) use strict; sub check { my $params = shift; my $common = $params->{common}; my ($card, $res); # Do we have tw_cli ? if ($common->can_run("tw_cli")) { foreach (`tw_cli info`) { $card = $1 if /^(c\d+).*/; if ($card) { $res = `tw_cli info $card numdrives`; $card = undef; $res =~ s/^.*=\s(\d+)/$1/; # Do we have drives on the card ? ($res == 0)?return 0:return 1; } } } } sub run { my $params = shift; my $common = $params->{common}; my $logger = $params->{logger}; my ($tw_cli, $hd); my ($card, $card_model, $unit, $unit_id, $port, $serialnumber, $serial, $model, $capacity, $firmware, $description, $media, $device, $manufacturer, $sn); my @devices = Ocsinventory::Agent::Backend::OS::Linux::Storages::getFromUdev(); # First, getting the cards : c0, c1... etc. foreach (`tw_cli info`) { # Should output something like this : # # Ctl Model Ports Drives Units NotOpt RRate VRate BBU # ------------------------------------------------------------------------ # c0 9650SE-2LP 2 2 1 0 1 1 - if (/^(c\d)+\s+([\w|-]+)/) { $card = $1; $card_model = $2; $logger->debug("Card : $card - Model : $card_model"); } if ($card) { # Second, getting the units : u0, u1... etc. foreach (`tw_cli info $card`) { # Example output : # # Unit UnitType Status %RCmpl %V/I/M Stripe Size(GB) Cache AVrfy # ------------------------------------------------------------------------------ # u0 RAID-1 OK - - - 65.1826 ON OFF # # Port Status Unit Size Blocks Serial # --------------------------------------------------------------- # p0 OK u0 69.25 GB 145226112 WD-WMANS1648590 # p1 OK u0 69.25 GB 145226112 WD-WMANS1344790 if (/^(u)(\d+).*/) { $unit = $1 . $2; $unit_id = $2; } if ($unit) { # Try do get unit's serial in order to compare it to what was found in udev db. # Works only on newer cards. # Allow us to associate a node to a drive : sda -> WD-WMANS1648590 $sn = `tw_cli info $card $unit serial 2> /dev/null`; $sn =~ s/^.*serial number\s=\s(\w*)\s*/$1/; # Third, getting the ports : p0, p1... etc. foreach(`tw_cli info $card $unit`) { $port = $1 if /^.*(p\d+).*/; if ($port) { # Finally, getting drives' values. foreach (`tw_cli info $card $port model serial capacity firmware`) { # Example output : # # /c0/p0 Model = WDC WD740ADFD-00NLR4 # /c0/p0 Serial = WD-WMANS1648590 # /c0/p0 Capacity = 69.25 GB (145226112 Blocks) # /c0/p0 Firmware Version = 21.07QR4 $model = $1 if /^.*Model\s=\s(.*)/; $serialnumber = $1 if /^.*Serial\s=\s(.*)/; $capacity = 1024*$1 if /^.*Capacity\s=\s(\S+)\sGB.*/; $firmware = $1 if /^.*Firmware Version\s=\s(.*)/; } foreach $hd (@devices) { # How does this work with multiple older cards where serial for units is not implemented ? # Need to be tested on a system with multiple 3ware cards. if (($hd->{SERIALNUMBER} eq 'AMCC_' . $sn) or ($hd->{MODEL} eq 'Logical_Disk_' . $unit_id)) { $device = $hd->{NAME}; } } # Getting description from card model, very basic and unreliable # Assuming only IDE drives can be plugged in 5xxx/6xxx cards and # SATA drives only to 7xxx/8xxx/9xxxx cards $description = undef; foreach ($card_model) { $description = "IDE" if /^[5-6].*/; $description = "SATA" if /^[7-9].*/; } $media = 'disk'; $manufacturer = Ocsinventory::Agent::Backend::OS::Linux::Storages::getManufacturer($model); $port = undef; $logger->debug("3ware: $device, $manufacturer, $model, $description, $media, $capacity, $serialnumber, $firmware"); $common->addStorages({ NAME => $device, MANUFACTURER => $manufacturer, MODEL => $model, DESCRIPTION => $description, TYPE => $media, DISKSIZE => $capacity, SERIALNUMBER => $serialnumber, FIRMWARE => $firmware, }); } $port = undef; } $unit = undef; } } $card = undef; $card_model = undef; } } } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/Linux/Storages/Adaptec.pm000066400000000000000000000261101372663377700262550ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::Linux::Storages::Adaptec; use Ocsinventory::Agent::Backend::OS::Linux::Storages; #Function parse_config and parse_config_fh are taken from https://github.com/kumy/Parse-Arcconf # #LICENSE AND COPYRIGHT # #Copyright (C) 2012 Mathieu Alorent # #This program is free software; you can redistribute it and/or modify it #under the terms of either: the GNU General Public License as published #by the Free Software Foundation; or the Artistic License. # #See http://dev.perl.org/licenses/ for more information. # Tested on 2.6.* kernels # # Cards tested : # # Adaptec AAC-RAID use strict; my @devices = Ocsinventory::Agent::Backend::OS::Linux::Storages::getFromUdev(); sub check { my $params = shift; my $common = $params->{common}; #Do we have arcconf if ($common->can_run ('arcconf') ) { my $conf = `arcconf GETCONFIG 1`; if($conf =~ /Controllers found: (\d+)/) { if($1>0) { return 1; } } } #Do we have smartctl if ($common->can_run ('smartctl') ) { foreach my $hd (@devices) { $hd->{MANUFACTURER} eq 'Adaptec'?return 1:1; } } return 0; } sub run { my $params = shift; my $common = $params->{common}; my $logger = $params->{logger}; my ($name,$vendor,$model,$serialnumber,$firmware, $size, $description, $media, $manufacturer); my ($conf, $cur_cont,$info,$key, $dev, $devkey,$controller); #get infos from arcconf if possible if ($common->can_run ('arcconf') ) { $conf = `arcconf GETCONFIG 1`; if($conf =~ /Controllers found: (\d+)/) { if($1>0) { $controller = parse_config(); foreach $cur_cont (keys %{$controller}){ #travers Controller $info = $controller->{$cur_cont}; foreach $key (keys %{$info}){ #travers Infos of Controller #physical drives if ($key=~m/physical drive/) { $dev = $info->{$key}; foreach $devkey (keys %{$dev}) { #get infos $vendor = $dev->{$devkey}->{'Vendor'}; $model = $dev->{$devkey}->{'Model'}; $serialnumber = $dev->{$devkey}->{'Serial number'}; $firmware = $dev->{$devkey}->{'Firmware'}; $size = $dev->{$devkey}->{'Size'}; $description = $dev->{$devkey}->{'Transfer Speed'}; $media = $dev->{$devkey}->{'Device is'}; unless ( $media=~m/an Enclosure services device/) { #Dont need services device just drives if ( $media=~m/a Hard drive/ ){ $media = "HDD"; #try to determine if Drive is a Solid State Disk if (exists $dev->{$devkey}->{'SSD'}) { #SSD Info is explicit in config my $ssd = $dev->{$devkey}->{'SSD'}; if ($ssd=~m/Yes/) { $media = "SSD"; } } else { #No explicit info try to get it through model name if($model =~m/SSD|Solid State|WDS/) { $media = "SSD"; } } } $manufacturer = Ocsinventory::Agent::Backend::OS::Linux::Storages::getManufacturer($vendor); $logger->debug("Adaptec: $manufacturer $media $size, $manufacturer, $model, $description, $media, $size , $serialnumber, $firmware"); $common->addStorages({ NAME => "$manufacturer $media $size", MANUFACTURER => $manufacturer, MODEL => $model, DESCRIPTION => $description, TYPE => $media, DISKSIZE => $size, SERIALNUMBER => $serialnumber, FIRMWARE => $firmware, }); } } } } } } } } elsif (-r '/proc/scsi/scsi') { foreach my $hd (@devices) { open (PATH, '/proc/scsi/scsi'); # Example output: # # Attached devices: # Host: scsi0 Channel: 00 Id: 00 Lun: 00 # Vendor: Adaptec Model: raid10 Rev: V1.0 # Type: Direct-Access ANSI SCSI revision: 02 # Host: scsi0 Channel: 01 Id: 00 Lun: 00 # Vendor: HITACHI Model: HUS151436VL3800 Rev: S3C0 # Type: Direct-Access ANSI SCSI revision: 03 # Host: scsi0 Channel: 01 Id: 01 Lun: 00 # Vendor: HITACHI Model: HUS151436VL3800 Rev: S3C0 # Type: Direct-Access ANSI SCSI revision: 03 my ($host, $model, $firmware, $manufacturer, $size, $serialnumber); my $count = -1; while () { ($host, $count) = (1, $count+1) if /^Host:\sscsi$hd->{SCSI_COID}.*/; if ($host) { if ((/.*Model:\s(\S+).*Rev:\s(\S+).*/) and ($1 !~ 'raid.*')) { $model = $1; $firmware = $2; $manufacturer = Ocsinventory::Agent::Backend::OS::Linux::Storages::getManufacturer($model); foreach (`smartctl -i /dev/sg$count`) { $serialnumber = $1 if /^Serial Number:\s+(\S*).*/; } $logger->debug("Adaptec: $hd->{NAME}, $manufacturer, $model, SATA, disk, $hd->{DISKSIZE}, $serialnumber, $firmware"); $host = undef; $common->addStorages({ NAME => $hd->{NAME}, MANUFACTURER => $manufacturer, MODEL => $model, DESCRIPTION => 'SATA', TYPE => 'disk', DISKSIZE => $size, SERIALNUMBER => $serialnumber, FIRMWARE => $firmware, }); } } } close (PATH); } } } sub parse_config { my $arcconf = "arcconf"; my $argument = "GETCONFIG 1"; my $command = sprintf("%s %s|", $arcconf, $argument); my $fh; if(open $fh, $command) { my $c = parse_config_fh($fh); close $fh; return $c; } return undef; } sub parse_config_fh { my $fh = $_[0]; my $controller = {}; my $total_controller = 0; my $current_controller = 0; my $current_logical_drive = undef; my $current_physical_drive = undef; my $ctrl = undef; my $line = undef; LEVEL1: while($line = <$fh>) { chomp $line; next if($line =~ /^$/); next if($line =~ /^-+$/); if($line =~ /^Controllers found: (\d+)$/) { $total_controller = $1; } if($line =~ /^Controller information/) { $current_controller = $current_controller + 1; $current_logical_drive = undef; $current_physical_drive = undef; $controller->{$current_controller} = {}; $ctrl = $controller->{$current_controller}; while($line = <$fh>) { chomp $line; if ($line =~ /^\s+(.*\w)\s+:\s+(.*)$/) { $ctrl->{$1} = $2; } elsif ($line =~ /^\s+-+$/) { last; } } LEVEL2: while($line = <$fh>) { if ($line =~ /^\s+-+$/) { $line = <$fh>; chomp $line; } if($line =~ /^\s+(.*\w)\s*/) { my $cat = $1; $line = <$fh>; LEVEL3: while($line = <$fh>) { chomp $line; if ($line =~ /^\s+(.*\w)\s+:\s+(.*)$/) { $ctrl->{$cat}{$1} = $2; } elsif ($line =~ /^\s+-+$/) { last LEVEL3; } elsif ($line =~ /^$/) { last LEVEL2; } } } } } next if(!defined($current_controller)); if($line =~ /^Logical drive information/ or $line =~ /^Logical device information/) { LEVEL4: while($line = <$fh>) { chomp $line; if ($line =~ /^\S+.*\w\s+(\d+)$/) { $current_logical_drive = $1; } elsif ($line =~ /^\s+(\S.*\S+)\s+:\s+(.*)$/) { $ctrl->{'logical drive'}{$current_logical_drive}{$1} = $2; } elsif ($line =~ /^\s+-+$/) { my $cat = <$fh>; $cat =~ s/^\s+(\S.*\S+)\s+/$1/; chomp $cat; LEVEL5: while($line = <$fh>) { chomp $line; if ($line =~ /^\s+(\S.*\S+)\s+:\s+(.*)$/) { $ctrl->{'logical drive'}{$current_logical_drive}{$cat}{$1} = $2; } elsif ($line =~ /^\S+.*\w\s+(\d+)$/) { $current_logical_drive = $1; last LEVEL5; } elsif ($line =~ /^-+$/) { last LEVEL4; } elsif ($line =~ /^\s+-+$/) { next; } } } } } if($line =~ /^Physical Device information/) { LEVEL2: while($line = <$fh>) { if ($line =~ /^\s+-+$/) { $line = <$fh>; chomp $line; } if ($line =~ /^\s+Device\s+#(\d+)$/) { $current_physical_drive = $1; } elsif ($line =~ /^\s+Device is (.*\w)/) { $ctrl->{'physical drive'}{$current_physical_drive}{'Device is'} = $1; } elsif ($line =~ /^\s+(.*\w)\s+:\s+(.*)$/) { $ctrl->{'physical drive'}{$current_physical_drive}{$1} = $2; } elsif ($line =~ /^\s+-+$/) { last LEVEL3; } elsif ($line =~ /^$/) { last LEVEL2; } } } } return $controller; } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/Linux/Storages/FusionIO.pm000066400000000000000000000034051372663377700264110ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::Linux::Storages::FusionIO; use Ocsinventory::Agent::Backend::OS::Linux::Storages; use strict; sub trim { my $s = shift; $s =~ s/^\s+|\s+$//g; return $s }; sub check { my $params = shift; my $common = $params->{common}; my $ret; # Do we have fio-status? if ($common->can_run("fio-status")) { foreach (`fio-status 2> /dev/null`) { if (/^fct(\d*).*/) { $ret=1; last; } } } return $ret; } sub run { my $params = shift; my $common = $params->{common}; my $logger = $params->{logger}; my ($pd, $serialnumber, $model, $capacity, $firmware, $description, $media, $manufacturer); foreach (`fio-status 2> /dev/null`) { if (/^fct(\d*).*/) { my $slot = $1; my $cmd = "fio-status /dev/fct$slot --field"; $model = trim(`$cmd iom.board_name`); $description = trim(`$cmd adapter.product_name`); $media = trim('disk'); $capacity = trim(`$cmd iom.size_bytes`); $serialnumber = 'OEM:'.trim(`$cmd adapter.oem_serial_number`).' FIO:'.trim(`$cmd adapter.fio_serial_number`).' IOM:'.trim(`$cmd iom.serial_number`); $firmware = trim(`$cmd iom.fw_current_version`.' rev '.`$cmd iom.fw_current_revision`); $logger->debug("Fusion-io: N/A, $manufacturer, $model, $description, $media, $capacity, $serialnumber, $firmware"); $common->addStorages({ NAME => $model, MANUFACTURER => 'Fusion-io', MODEL => $model, DESCRIPTION => $description, TYPE => $media, DISKSIZE => $capacity, SERIALNUMBER => $serialnumber, FIRMWARE => $firmware }); } } } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/Linux/Storages/HP.pm000066400000000000000000000105311372663377700252230ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::Linux::Storages::HP; use Ocsinventory::Agent::Backend::OS::Linux::Storages; # Tested on 2.6.* kernels # # Cards tested : # # Smart Array E200 # # HP Array Configuration Utility CLI 7.85-18.0 use strict; sub check { my $params = shift; my $common = $params->{common}; my $ret; # Do we have ssacli ? if ($common->can_run("ssacli")) { foreach (`ssacli ctrl all show 2> /dev/null`) { if (/.*Slot\s(\d*).*/) { $ret = 1; last; } } } return $ret; } sub run { my $params = shift; my $common = $params->{common}; my $logger = $params->{logger}; my ($pd, $serialnumber, $model, $capacity, $firmware, $description, $media, $manufacturer); foreach (`ssacli ctrl all show 2> /dev/null`) { # Example output : # # Smart Array E200 in Slot 2 (sn: PA6C90K9SUH1ZA) if (/.*Slot\s(\d*).*/) { my $slot = $1; foreach (`ssacli ctrl slot=$slot pd all show 2> /dev/null`) { # Example output : # Smart Array E200 in Slot 2 # # array A # # physicaldrive 2I:1:1 (port 2I:box 1:bay 1, SATA, 74.3 GB, OK) # physicaldrive 2I:1:2 (port 2I:box 1:bay 2, SATA, 74.3 GB, OK) if (/.*physicaldrive\s(\S*)/) { my $pd = $1; foreach (`ssacli ctrl slot=$slot pd $pd show 2> /dev/null`) { # Example output : # # Smart Array E200 in Slot 2 # # array A # # physicaldrive 1:1 # Port: 2I # Box: 1 # Bay: 1 # Status: OK # Drive Type: Data Drive # Interface Type: SATA # Size: 74.3 GB # Firmware Revision: 21.07QR4 # Serial Number: WD-WMANS1732855 # Model: ATA WDC WD740ADFD-00 # SATA NCQ Capable: False # PHY Count: 1 $model = $1 if /.*Model:\s(.*)/; $description = $1 if /.*Interface Type:\s(.*)/; $media = $1 if /.*Drive Type:\s(.*)/; $capacity = $1 if /^\s*Size:\s(.*)/; $serialnumber = $1 if /.*Serial Number:\s(.*)/; $firmware = $1 if /.*Firmware Revision:\s(.*)/; } $serialnumber =~ s/^\s+//; $model =~ s/^ATA\s+//; # ex: ATA WDC WD740ADFD-00 $model =~ s/\s+/ /; $manufacturer = Ocsinventory::Agent::Backend::OS::Linux::Storages::getManufacturer($model); if ($media eq 'Data Drive') { $media = 'HDD'; if ($description =~m/SSD|Solid State/) { $media = 'SSD'; } elsif ($model =~m/SSD|Solid State|WDS/) { $media = 'SSD'; } } if ($capacity =~m/TB/) { $capacity *= 1000000; } elsif ($capacity =~m/GB/) { $capacity *= 1000; } else { $capacity *= 1; } $logger->debug("HP: N/A, $manufacturer, $model, $description, $media, $capacity, $serialnumber, $firmware"); $common->addStorages({ NAME => $model, MANUFACTURER => $manufacturer, MODEL => $model, DESCRIPTION => $description, TYPE => $media, DISKSIZE => $capacity, SERIALNUMBER => $serialnumber, FIRMWARE => $firmware }); } } } } } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/Linux/Storages/Lsilogic.pm000066400000000000000000000051351372663377700264650ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::Linux::Storages::Lsilogic; use Ocsinventory::Agent::Backend::OS::Linux::Storages; # Tested on 2.6.* kernels # # Cards tested : # # LSI Logic / Symbios Logic SAS1064E PCI-Express Fusion-MPT SAS # # mpt-status version : 1.2.0 use strict; sub check { my $params = shift; my $common = $params->{common}; my $device; # Do we have smartctl ? if ($common->can_run('smartctl')) { foreach my $node (glob("/dev/sd?")) { foreach (`smartctl -i $node`) { $device = $1 if /.*Device:\s(\w*).*/; } } ($device eq 'LSILOGIC')?return 1:return 0; } return 0; } sub run { my $params = shift; my $common = $params->{common}; my $logger = $params->{logger}; my $serialnumber; my @devices = Ocsinventory::Agent::Backend::OS::Linux::Storages::getFromUdev(); foreach my $hd (@devices) { foreach (`mpt-status -n -i $hd->{SCSI_UNID}`) { # Example output : # # ioc:0 vol_id:0 type:IM raidlevel:RAID-1 num_disks:2 size(GB):148 state: OPTIMAL flags: ENABLED # ioc:0 phys_id:1 scsi_id:2 vendor:ATA product_id:ST3160815AS revision:D size(GB):149 state: ONLINE flags: NONE sync_state: 100 ASC/ASCQ:0xff/0xff SMART ASC/ASCQ:0xff/0xff #ioc:0 phys_id:0 scsi_id:1 vendor:ATA product_id:ST3160815AS revision:D size(GB):149 state: ONLINE flags: NONE sync_state: 100 ASC/ASCQ:0xff/0xff SMART ASC/ASCQ:0xff/0xff #scsi_id:1 100% #scsi_id:0 100% if (/.*phys_id:(\d+).*product_id:\s*(\S*)\s+revision:(\S+).*size\(GB\):(\d+).*/) { $serialnumber = undef; foreach (`smartctl -i /dev/sg$1`) { $serialnumber = $1 if /^Serial Number:\s+(\S*)/; } my $model = $2; my $size = 1024*$4; # GB => MB my $firmware = $3; my $manufacturer = Ocsinventory::Agent::Backend::OS::Linux::Storages::getManufacturer($model); $logger->debug("Lsilogic: $hd->{NAME}, $manufacturer, $model, SATA, disk, $size, $serialnumber, $firmware"); $common->addStorages({ NAME => $hd->{NAME}, MANUFACTURER => $manufacturer, MODEL => $model, DESCRIPTION => 'SATA', TYPE => 'disk', DISKSIZE => $size, SERIALNUMBER => $serialnumber, FIRMWARE => $firmware, }); } } } } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/Linux/Storages/Megacli.pm000066400000000000000000000052101372663377700262530ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::Linux::Storages::Megacli; use Ocsinventory::Agent::Backend::OS::Linux::Storages; use strict; sub check { my $params = shift; my $common = $params->{common}; my $ret; my $cont; if ($common->can_run("megacli")) { foreach (`megacli -adpCount 2>/dev/null`) { if (/^Controller\sCount:\s(\d+)/) { $cont=$1; if (defined $cont && $cont == 1) { $ret=1; last; } } } } return $ret; } sub run { my $params = shift; my $common = $params->{common}; my $logger = $params->{logger}; my $adpc; my $model; my $description; my $capacity; my $firmware; my $serial; my $manufacturer; my $index; my @partitions; my @sl; # Retrieve the partition open PARTINFO, '){ if (/^\s*(\d*)\s*(\d*)\s*(\d*)\s*([sh]d[a-z]+)$/i){ push(@partitions,$4); } } # How adapters are present? foreach (`megacli -adpCount 2> /dev/null`){ $adpc=$1 if (/^Controller Count:\s(\d+)./i); } # How slot are used on the controller? for (my $count=0;$count<$adpc;$count++){ foreach (`megacli -ShowSummary -a$count`){ # Slot number : Connector : 0: Slot 1 if (/Connector\s*:\s*\d+(?:): Slot (\d+)/){ push (@sl, $1); } } # use smartctcl command to retrieve information foreach my $dev (@partitions){ foreach my $slo (@sl){ # smartctl -i -d megaraid,0 /dev/sda my $result=`smartctl -i -d megaraid,$slo /dev/$dev`; $model=$1 if ($result =~ /Model Family:\s*(.*)/); $description=$1 if ($result =~ /Device Model:\s*(.*)/); $manufacturer = Ocsinventory::Agent::Backend::OS::Linux::Storages::getManufacturer($description); $serial=$1 if ($result =~ /Serial Number:\s*(.*)/); $firmware=$1 if ($result =~ /Firmware Version:\s*(.*)/); $capacity=$1 if ($result =~ /User Capacity:\s*.*\[(.*)\]/); $common->addStorages({ NAME => $description, MANUFACTURER => $manufacturer, MODEL => $model, DESCRIPTION => $description, TYPE => "Disk", DISKSIZE => $capacity, SERIALNUMBER => $serial, FIRMWARE => $firmware }); } } } } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/Linux/Storages/ServeRaid.pm000066400000000000000000000073141372663377700266050ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::Linux::Storages::ServeRaid; use Ocsinventory::Agent::Backend::OS::Linux::Storages; # Tested on 2.6.* kernels # # Cards tested : # # IBM ServeRAID-6M # IBM ServeRAID-6i use strict; sub check { my $params = shift; my $common = $params->{common}; my $ret = 0; # Do we have ipssend installed ? if ($common->can_run("ipssend")) { foreach (`ipssend GETVERSION 2>/dev/null`) { if (/.*ServeRAID Controller Number\s(\d*).*/) { $ret = $1; last; } } } return $ret; } sub run { my $params = shift; my $common = $params->{common}; my $logger = $params->{logger}; my $slot; $logger->debug("ServeRaid: ipssend GETVERSION"); foreach (`ipssend GETVERSION 2>/dev/null`) { # Example Output : # Found 1 IBM ServeRAID controller(s). #---------------------------------------------------------------------- #ServeRAID Controller(s) Version Information #---------------------------------------------------------------------- # Controlling BIOS version : 7.00.14 # #ServeRAID Controller Number 1 # Controller type : ServeRAID-6M # Controller slot information : 2 # Actual BIOS version : 7.00.14 # Firmware version : 7.00.14 # Device driver version : 7.10.18 $slot = $1 if /.*ServeRAID Controller Number\s(\d*).*/; if (/.*Controller type.*:\s(.*)/) { my $name = $1; my ($serial, $capacity, $scsi, $channel, $state); $logger->debug("ServeRaid: ipssend GETCONFIG $slot PD"); foreach (`ipssend GETCONFIG $slot PD 2>/dev/null`) { # Example Output : # Channel #1: # Target on SCSI ID 0 # Device is a Hard disk # SCSI IDg: 0 # PFA (Yes/No) : No # Stateg : Online (ONL) # Size (in MB)/(in sectors): 34715/71096368 # Device ID : IBM-ESXSCBR036C3DFQDB2Q6CDKM # FRU part number : 32P0729 $channel = $1 if /.*Channel #(.*):/; $scsi = $1 if /.*SCSI ID.*:\s(.*)/; $state = $1 if /.*State.*\((.*)\)/; $capacity = $1 if /.*Size.*:\s(\d*)\/(\d*)/; $serial = $1 if /.*Device ID.*:\s(.*)/; if (/.*FRU part number.*:\s(.*)/) { my $model = $1; my $manufacturer = Ocsinventory::Agent::Backend::OS::Linux::Storages::getManufacturer($serial); ## my $fullname = "$name $slot/$channel/$scsi $state"; $logger->debug("ServeRaid: found $model, $manufacturer, $model, SCSI, disk, $capacity, $serial, "); $common->addStorages({ NAME => "$manufacturer $model", MANUFACTURER => $manufacturer, MODEL => $model, DESCRIPTION => "SCSI", TYPE => "disk", DISKSIZE => $capacity, SERIALNUMBER => $serial, FIRMWARE => "" }); # don't undef $channel, appear only once for several drive. $scsi = $state = $capacity = $serial = undef; } } } } } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/Linux/Sys.pm000066400000000000000000000005251372663377700237050ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::Linux::Sys; #$LunchAfter = "Ocsinventory::Agent::Backend::OS::Linux::VirtualFs::Sys"; sub check { my $params = shift; my $common = $params->{common}; return unless $common->can_run ("mount"); foreach (`mount`) { return 1 if (/type\ sysfs/); } 0; } sub run {} 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/Linux/Uptime.pm000066400000000000000000000015041372663377700243700ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::Linux::Uptime; use strict; sub check { my $params = shift; my $common = $params->{common}; $common->can_read("/proc/uptime") } sub run { my $params = shift; my $common = $params->{common}; # Uptime open UPTIME, "/proc/uptime"; my $uptime = ; $uptime =~ s/^(.+)\s+.+/$1/; close UPTIME; # Uptime conversion my ($UYEAR, $UMONTH , $UDAY, $UHOUR, $UMIN, $USEC) = (gmtime ($uptime))[5,4,3,2,1,0]; # Write in ISO format $uptime=sprintf "%02d-%02d-%02d %02d:%02d:%02d", ($UYEAR-70), $UMONTH, ($UDAY-1), $UHOUR, $UMIN, $USEC; chomp(my $DeviceType =`uname -m`); # TODO$h->{'CONTENT'}{'HARDWARE'}{'DESCRIPTION'} = [ "$DeviceType/$uptime" ]; $common->setHardware({ DESCRIPTION => "$DeviceType/$uptime" }); } 1 UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/Linux/Videos.pm000066400000000000000000000035751372663377700243700ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::Linux::Videos; use strict; use warnings; sub check { my $params = shift; my $common = $params->{common}; return unless $common->can_run ("nvidia-smi"); return unless $common->can_run ("nvidia-settings"); } sub run { my $params = shift; my $common = $params->{common}; my $logger = $params->{logger}; my $nvidia; my @nvidia_infos=`nvidia-smi -q`; my @nvidia_settings=`nvidia-settings -q all`; my @prime=`nvidia-settings --query=PrimeOutputsData`; foreach my $info (@nvidia_infos) { $nvidia->{SERIALNUMBER}=$1 if ($info =~ /Serial Number\s+: (.*)/i); $nvidia->{DRVVERSION}=$1 if ($info =~ /Driver Version\s+: ([0-9]+\.[0-9]+)/i); $nvidia->{NBGPU}=$1 if ($info =~ /Attached GPUs\s+: ([0-9])/i); $nvidia->{VBIOS}=$1 if ($info =~ /VBIOS Version\s+: (.*)/i); $nvidia->{NAME}=$1 if ($info =~ /Product Name\s+:(.*)/i); $nvidia->{UUID}=$1 if ($info =~ /GPU UUID\s+:(.*)/i); $nvidia->{PCISLOT}=$1 if ($info =~ /Bus Id\s+:(.*)/i); } # Resolution foreach my $inf (@prime) { next if ($inf =~ /^\s*$/); my $width=$1 if ($inf =~ /width=(\d{1,4})/); my $height=$1 if ($inf =~ /height=(\d{1,4})/); $nvidia->{RESOLUTION}=$width."x".$height; } $nvidia->{MEMORY}=`nvidia-smi --query-gpu=memory.total --format=csv,noheader,nounits`; $nvidia->{MEMORY} =~ s/\s+$//g; $nvidia->{NAME} =~ s/^\s//g; $nvidia->{UUID} =~ s/^\s//g; $nvidia->{PCISLOT} =~ s/^\s0{8}://g; foreach my $settings (@nvidia_settings) { $nvidia->{DATA_WIDTH}=$1 if ($settings =~ /Attribute \'GPUMemoryInterface\'\s\(.*\):\s(\d{2})./i); $nvidia->{CUDACORES}=$1 if ($settings =~ /Attribute \'CUDACores\'\s\(.*\):\s(\d{2})./i); } for (my $i=0; $i<$nvidia->{NBGPU};$i++) { $common->addVideo($nvidia); } } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/MacOS.pm000066400000000000000000000032761372663377700230000ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::MacOS; use strict; require Exporter; our @ISA = qw /Exporter/; our @EXPORT = qw /get_sysprofile_devices_names/; sub check { my $r; # we check far darwin because that's the _real_ underlying OS $r = 1 if (uc($^O) =~ /^DARWIN$/); return($r); } sub run { my $params = shift; my $common = $params->{common}; my $OSName; my $OSComment; my $OSVersion; my $uuid; # if we can load the system profiler, gather the information from that if ($common->can_load("Mac::SysProfile")){ my $profile = Mac::SysProfile->new(); my $data = $profile->gettype('SPSoftwareDataType'); return(undef) unless(ref($data) eq 'ARRAY'); my $h = $data->[0]; my $SystemVersion = $h->{'os_version'}; if ($SystemVersion =~ /^(.*?)\s+(\d+.*)/) { $OSName=$1; $OSVersion=$2; } else { # Default values $OSName="Mac OS X"; $OSVersion="Unknown"; } } else { # we can't load the system profiler, use the basic BSD stype information # Operating system informations chomp($OSName=`uname -s`); chomp($OSVersion=`uname -r`); } # add the uname -v as the comment, not really needed, but extra info never hurt chomp($OSComment=`uname -v`); # We get UUID if ($common->can_run("ioreg")) { my @ioreg = split ("=", `ioreg -rd1 -c IOPlatformExpertDevice | grep -E '(UUID)'`); chomp($uuid = $ioreg[1]); $uuid =~ s/\"|\s//g; } $common->setHardware({ OSNAME => $OSName, OSCOMMENTS => $OSComment, OSVERSION => $OSVersion, UUID => $uuid, }); } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/MacOS/000077500000000000000000000000001372663377700224325ustar00rootroot00000000000000UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/MacOS/Bios.pm000066400000000000000000000021721372663377700236660ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::MacOS::Bios; use strict; sub check { my $params = shift; my $common = $params->{common}; return $common->can_load("Mac::SysProfile") } sub run { my $params = shift; my $common = $params->{common}; # use Mac::SysProfile to get the respected datatype my $profile = Mac::SysProfile->new(); my $data = $profile->gettype('SPHardwareDataType'); # unless we get a real hash value, return with nothing return(undef) unless($data && ref($data) eq 'ARRAY'); my $h = $data->[0]; # set the bios informaiton from the apple system profiler $common->setBios({ SMANUFACTURER => 'Apple Inc', # duh SMODEL => $h->{'model_identifier'} || $h->{'machine_model'}, # SSN => $h->{'Serial Number'} # New method to get the SSN, because of MacOS 10.5.7 update # system_profiler gives 'Serial Number (system): XXXXX' where 10.5.6 # and lower give 'Serial Number: XXXXX' SSN => $h->{'serial_number'}, BVERSION => $h->{'boot_rom_version'}, }); } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/MacOS/CPU.pm000066400000000000000000000040661372663377700234250ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::MacOS::CPU; use strict; sub check { my $params = shift; my $common = $params->{common}; return(undef) unless -r '/usr/sbin/system_profiler'; return(undef) unless $common->can_load("Mac::SysProfile"); return 1; } sub run { my $params = shift; my $common = $params->{common}; my $processors; my $arch; my $datawidth; # 32 or 64 bits arch? my $sysctl_arch = `sysctl -n hw.cpu64bit_capable`; if ($sysctl_arch == 1){ $arch = "x86_64"; $datawidth = 64; } else { $arch = "x86"; $datawidth = 32; } # How much processor socket ? my $ncpu=`sysctl -n hw.packages`; # For each processor socket foreach my $cpu (1..$ncpu) { $processors->{$cpu}->{MANUFACTURER} = `sysctl -n machdep.cpu.vendor`; if ($processors->{$cpu}->{MANUFACTURER} =~ /(Authentic|Genuine|)(.+)/i) { $processors->{$cpu}->{MANUFACTURER} = $2; } chomp($processors->{$cpu}->{MANUFACTURER} ); $processors->{$cpu}->{TYPE} = `sysctl -n machdep.cpu.brand_string`; chomp($processors->{$cpu}->{TYPE} ); $processors->{$cpu}->{SPEED} = `sysctl -n hw.cpufrequency` / 1000 / 1000; $processors->{$cpu}->{L2CACHESIZE} = `sysctl -n hw.l2cachesize` / 1024; $processors->{$cpu}->{CORES} = `sysctl -n machdep.cpu.core_count`; chomp($processors->{$cpu}->{CORES}); $processors->{$cpu}->{THREADS} = `sysctl -n machdep.cpu.thread_count`; chomp($processors->{$cpu}->{THREADS}); $processors->{$cpu}->{LOGICAL_CPUS} = `sysctl -n machdep.cpu.logical_per_package`; chomp($processors->{$cpu}->{LOGICAL_CPUS}); $processors->{$cpu}->{CPUARCH} = $arch; $processors->{$cpu}->{DATA_WIDTH} = $datawidth; $processors->{$cpu}->{NBSOCKET} = $cpu; chomp($processors->{$cpu}->{NBSOCKET}); $processors->{$cpu}->{SERIALNUMBER} = "N/A"; } # Add new cpu infos to inventory foreach (keys %{$processors}){ $common->addCPU($processors->{$_}); } } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/MacOS/Camera.pm000066400000000000000000000011041372663377700241540ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::MacOS::Camera; use strict; sub check { return(undef) unless -r '/usr/sbin/system_profiler'; # check perms return 1; } sub run { my $params = shift; my $common = $params->{common}; # create profiler obj, bail if datatype fails my $data = $common->get_sysprofile_devices_names('SPCameraDataType'); return(undef) unless(ref($data) eq 'ARRAY'); # add sound cards foreach my $cam (@$data){ $common->addCamera({ 'MODEL' => $cam, 'UUID' => $cam, }); } } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/MacOS/Controllers.pm000066400000000000000000000045601372663377700253030ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::MacOS::Controllers; sub check { my $params = shift; my $common = $params->{common}; return(undef) unless -r '/usr/sbin/system_profiler'; # check perms return (undef) unless $common->can_load("Mac::SysProfile"); return 1; } sub run { my $params = shift; my $common = $params->{common}; my ($caption, $description, $name, $type); my $datatypes = { #usb => 'SPUSBDataType', TODO: fix problems with SPUSBDataType in Mac::Sysprofile firewire => 'SPFireWireDataType', thunderbolt => 'SPThunderboltDataType', ethernet => 'SPEthernetDataType', }; for my $datatype (keys %$datatypes) { # create the profile object and return undef unless we get something back my $pro = Mac::SysProfile->new(); my $data = $pro->gettype($datatypes->{$datatype}); return(undef) unless(ref($data) eq 'ARRAY'); foreach my $port (@$data) { if ($datatype =~ /usb/) { $name = $port->{'usb_bus_number'}; $type = 'USB Bus'; $description = $port->{'controller_location'} . ", PCI Device ID: " . $port->{'pci_device'}; } elsif ($datatype =~ /firewire/) { $name = 'FireWire'; $type = 'FireWire Bus'; $description = 'Max Speed: ' . $port->{'max_device_speed'}; } elsif ($datatype =~ /thunderbolt/) { $name = $port->{'device_name_key'}; next unless $name; $type = 'Thunderbolt'; $description = 'UID: ' . $port->{'switch_uid_key'}; } elsif ($datatype =~ /ethernet/) { $name = $port->{'_name'}; if ($name ne '') { $name = $port->{'spethernet_device-id'} if ($name eq 'ethernet'); $type = 'Ethernet Controller'; $description = 'BSD: ' . $port->{'spethernet_BSD_Name'}; } } $common->addController({ CAPTION => $caption, DESCRIPTION => $description, NAME => $name, TYPE => $type, }); $caption = $description = $name = $type = undef; } } } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/MacOS/Domains.pm000066400000000000000000000022651372663377700243670ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::MacOS::Domains; use strict; # straight up theft from the other modules... sub check { my $hostname; chomp ($hostname = `hostname`); my @domain = split (/\./, $hostname); shift (@domain); return 1 if @domain; -f "/etc/resolv.conf" } sub run { my $params = shift; my $common = $params->{common}; my $domain; my $hostname; chomp ($hostname = `hostname`); my @domain = split (/\./, $hostname); shift (@domain); $domain = join ('.',@domain); if (!$domain) { my %domain; open RESOLV, "/etc/resolv.conf" or warn; while(){ $domain{$2} = 1 if (/^(domain|search)\s+(.+)/); } close RESOLV; $domain = join "/", keys %domain; } # If no domain name, we send "WORKGROUP" $domain = 'WORKGROUP' unless $domain; # User domain my $userdomain = `defaults read /Library/Preferences/SystemConfiguration/com.apple.smb.server Workgroup 2>/dev/null`; chomp($userdomain); if ($userdomain eq "" ) { $userdomain = `hostname -s`; chomp($userdomain); } $common->setHardware({ WORKGROUP => $domain }); } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/MacOS/Drives.pm000066400000000000000000000021151372663377700242230ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::MacOS::Drives; use strict; # yea BSD theft!!!! # would have used Mac::SysProfile, but the xml isn't quite fully supported # the drives come back in apple xml tree's, and the module can't handle it yet (soon as I find the time to fix the patch) sub check {1} sub run { my $params = shift; my $common = $params->{common}; my $free; my $filesystem; my $total; my $type; my $volumn; for my $t ("apfs", "ffs","ufs", "hfs") { # OpenBSD has no -m option so use -k to obtain results in kilobytes for(`df -P -k -t $t`){ # darwin needs the -t to be last if(/^(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\n/){ $type = $1; $filesystem = $t; $total = sprintf("%i",$2/1024); $free = sprintf("%i",$4/1024); $volumn = $6; $common->addDrive({ FREE => $free, FILESYSTEM => $filesystem, TOTAL => $total, TYPE => $type, VOLUMN => $volumn }) } } } } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/MacOS/Hostname.pm000066400000000000000000000011031372663377700245410ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::MacOS::Hostname; sub check { my $params = shift; my $common = $params->{common}; return 1 if $common->can_load ("Mac::SysProfile"); 0; } # Initialise the distro entry sub run { my $params = shift; my $common = $params->{common}; my $hostname; my $profile = Mac::SysProfile->new(); my $data = $profile->gettype('SPSoftwareDataType'); return undef unless(ref($data) eq 'ARRAY'); my $h = $data->[0]; $hostname = $h->{'local_host_name'}; $common->setHardware ({NAME => $hostname}) if $hostname; } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/MacOS/IPv4.pm000066400000000000000000000011201372663377700235440ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::MacOS::IPv4; # straight up theft from the other modules sub check { my @ifconfig = `ifconfig -a 2>/dev/null`; return 1 if @ifconfig; return; } # Initialise the distro entry sub run { my $params = shift; my $common = $params->{common}; my @ip; # Looking for ip addresses with ifconfig, except loopback # *BSD need -a option foreach (`ifconfig -a`){ if(/^\s*inet\s+(\S+)/){ ($1=~/127.+/)?next:push @ip, $1 }; } my $ip=join "/", @ip; $common->setHardware({IPADDR => $ip}); } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/MacOS/Mem.pm000066400000000000000000000043071372663377700235120ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::MacOS::Mem; use strict; sub check { my $params = shift; my $common = $params->{common}; return(undef) unless -r '/usr/sbin/system_profiler'; # check perms return (undef) unless $common->can_load("Mac::SysProfile"); return 1; } sub run { my $params = shift; my $common = $params->{common}; my $PhysicalMemory; # create the profile object and return undef unless we get something back my $profile = Mac::SysProfile->new(); my $data = $profile->gettype('SPMemoryDataType'); return(undef) unless(ref($data) eq 'ARRAY'); # Workaround for MacOSX 10.5.7 #if ($h->{'Memory Slots'}) { # $h = $h->{'Memory Slots'}; #} foreach my $memory (@$data){ next unless $memory->{'_name'} =~ /^BANK|SODIMM|DIMM/; # tare out the slot number my $slot = $memory->{'_name'}; # memory in 10.5 if($slot =~ /^BANK (\d)\/DIMM\d/){ $slot = $1; } # 10.4 if($slot =~ /^SODIMM(\d)\/.*$/){ $slot = $1; } # 10.4 PPC if($slot =~ /^DIMM(\d)\/.*$/){ $slot = $1; } # 10.7 if ($slot =~ /^DIMM (\d)/) { $slot = $1; } my $size = $memory->{'dimm_size'}; my $desc = $memory->{'dimm_part_number'}; if ($desc !~ /empty/) { # dimm_part_number is an hex string, convert it to ascii $desc = pack "H*", $desc; $desc =~ s/\s+$//; } # if system_profiler lables the size in gigs, we need to trim it down to megs so it's displayed properly if($size =~ /GB$/){ $size =~ s/GB$//; $size *= 1024; } $common->addMemory({ 'CAPACITY' => $size, 'SPEED' => $memory->{'dimm_speed'}, 'TYPE' => $memory->{'dimm_type'}, 'SERIALNUMBER' => $memory->{'dimm_serial_number'}, 'DESCRIPTION' => $desc, 'NUMSLOTS' => $slot, 'CAPTION' => 'Status: '.$memory->{'dimm_status'}, }); } # Send total memory size to inventory object my $sysctl_memsize=`sysctl -n hw.memsize`; $common->setHardware({ MEMORY => $sysctl_memsize / 1024 / 1024, }); } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/MacOS/Networks.pm000066400000000000000000000113271372663377700246100ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::MacOS::Networks; # I think I hijacked most of this from the BSD/Linux modules use strict; sub check { my $params = shift; my $common = $params->{common}; $common->can_run("ifconfig") && $common->can_load("Net::IP qw(:PROC)") } sub _ipdhcp { my $if = shift; my $path; my $ipdhcp; my $leasepath; foreach ( # XXX BSD paths "/var/db/dhclient.leases.%s", "/var/db/dhclient.leases", # Linux path for some kFreeBSD based GNU system "/var/lib/dhcp3/dhclient.%s.leases", "/var/lib/dhcp3/dhclient.%s.leases", "/var/lib/dhcp/dhclient.leases") { $leasepath = sprintf($_,$if); last if (-e $leasepath); } return undef unless -e $leasepath; if (open DHCP, $leasepath) { my $lease; my $dhcp; my $expire; # find the last lease for the interface with its expire date while(){ $lease = 1 if(/lease\s*{/i); $lease = 0 if(/^\s*}\s*$/); if ($lease) { #inside a lease section if(/interface\s+"(.+?)"\s*/){ $dhcp = ($1 =~ /^$if$/); } #Server IP if(/option\s+dhcp-server-identifier\s+(\d{1,3}(?:\.\d{1,3}){3})\s*;/ and $dhcp){ $ipdhcp = $1; } if (/^\s*expire\s*\d\s*(\d*)\/(\d*)\/(\d*)\s*(\d*):(\d*):(\d*)/ and $dhcp) { $expire=sprintf "%04d%02d%02d%02d%02d%02d",$1,$2,$3,$4,$5,$6; } } } close DHCP or warn; chomp (my $currenttime = `date +"%Y%m%d%H%M%S"`); undef $ipdhcp unless $currenttime <= $expire; } else { warn "Can't open $leasepath\n"; } return $ipdhcp; } # Initialise the distro entry sub run { my $params = shift; my $common = $params->{common}; my $description; my $ipaddress; my $ipgateway; my $ipmask; my $ipsubnet; my $macaddr; my $status; my $type; my $speed; # Looking for the gateway # 'route show' doesn't work on FreeBSD so we use netstat # XXX IPV4 only for(`netstat -nr -f inet`){ $ipgateway=$1 if /^default\s+(\S+)/i; } my @ifconfig = `ifconfig -a`; # -a option required on *BSD # first make the list available interfaces # too bad there's no -l option on OpenBSD my @list; foreach (@ifconfig){ # skip loopback, pseudo-devices and point-to-point interfaces #next if /^(lo|fwe|vmnet|sit|pflog|pfsync|enc|strip|plip|sl|ppp)\d+/; next unless(/^en([0-9])/); # darwin has a lot of interfaces, for this purpose we only want to deal with eth0 and eth1 if (/^(\S+):/) { push @list , $1; } # new interface name } # for each interface get it's parameters foreach $description (@list) { $ipaddress = $ipmask = $macaddr = $status = $type = undef; # search interface infos @ifconfig = `ifconfig $description`; foreach (@ifconfig){ $ipaddress = $1 if /inet (\S+)/i; $ipmask = $1 if /netmask\s+(\S+)/i; $macaddr = $2 if /(address:|ether|lladdr)\s+(\S+)/i; $status = 1 if /status:\s+active/i; $type = $1 if /media:\s+(\S+)/i; $speed = $1 if /media:\s+(\S+)\s+(\S+)/i && ! /supported media:/; if ($speed =~ /autoselect/i) { $speed = $2 if /media:\s+(\S+)\s+(\S+)/i && ! /supported media:/; $speed .= " $3" if /media:\s+(\S+)\s+(\S+)\s+(\S+)/i && ! /supported media:/; } else { $speed .= " $2" if /media:\s+(\S+)\s+(\S+)/i && ! /supported media:/; } } if ($status != 1) { $speed = ""; } else { $speed =~ s/\(|\)|\<|\>|baseTX|baseT|,flow-control//g; $speed =~ s/1000 /1 Gb\/s /g; $speed =~ s/100 /100 Mb\/s /g; $speed =~ s/10 /10 Mb\/s /g; $speed =~ s/full-duplex/FDX/g; $speed =~ s/half-duplex/HDX/g; } my $binip = &ip_iptobin ($ipaddress ,4); # In BSD, netmask is given in hex form my $binmask = sprintf("%b", oct($ipmask)); my $binsubnet = $binip & $binmask; $ipsubnet = ip_bintoip($binsubnet,4); my $mask = ip_bintoip($binmask,4); $common->addNetwork({ DESCRIPTION => $description, IPADDRESS => ($status?$ipaddress:undef), IPDHCP => _ipdhcp($description), IPGATEWAY => ($status?$ipgateway:undef), IPMASK => ($status?$mask:undef), IPSUBNET => ($status?$ipsubnet:undef), MACADDR => $macaddr, STATUS => ($status?"Up":"Down"), TYPE => ($status?$type:undef), SPEED => $speed, }); } } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/MacOS/Packages.pm000066400000000000000000000036641372663377700245170ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::MacOS::Packages; use strict; use warnings; sub check { my $params = shift; my $common = $params->{common}; return unless $common->can_load("Mac::SysProfile"); # Do not run an package inventory if there is the --nosoftware parameter return if ($params->{config}->{nosoftware}); 1; } sub run { my $params = shift; my $common = $params->{common}; my $profile = Mac::SysProfile->new(); my $data = $profile->gettype('SPApplicationsDataType'); # might need to check version of darwin return unless($data && ref($data) eq 'ARRAY'); # for each app, normalize the information, then add it to the inventory stack foreach my $app (@$data){ #my $a = $apps->{$app}; my $path = $app->{'path'} ? $app->{'path'} : 'unknown'; #Exlude from /System/Library/xxx : you can save 150 entries if ($path =~ /^\/System\/Library\//) {next;} if ($path =~ /\/System\/Library\// and $path =~ /^\/Volumes\//) {next;} #Exlude from xxx/Library/Printers/xxx : you can save 10 entries because a printer is an app if ($path =~ /\/Library\/Printers\//) {next;} my $kind = $app->{'runtime_environment'} ? $app->{'runtime_environment'} : 'UNKNOWN'; my $store = $app->{'app_store'} ? $app->{'app_store'} : 'no'; my $comments = 'AppStore: '.$store.' - Type: '.$kind.' '; my $bits = $app->{'has64BitIntelCode'} ? $app->{'has64BitIntelCode'} : 'unknown'; if ($bits eq 'yes') {$bits = '64';} else {$bits = '32';} $common->addSoftware({ 'NAME' => $app->{'_name'}, 'VERSION' => $app->{'version'} || 'unknown', 'COMMENTS' => $comments, 'PUBLISHER' => $app->{'info'} || 'unknown', 'INSTALLDATE' => $app->{'lastModified'}, 'FOLDER' => $path, 'BITSWIDTH' => $bits, }); } } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/MacOS/Printers.pm000066400000000000000000000034721372663377700246040ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::MacOS::Printers; use strict; sub check { my $params = shift; my $common = $params->{common}; return(undef) unless -r '/usr/sbin/system_profiler'; return(undef) unless $common->can_load("Mac::SysProfile"); return 1; } sub run { my $params = shift; my $common = $params->{common}; my $profile = Mac::SysProfile->new(); my $data = $profile->gettype('SPPrintersDataType'); return(undef) unless(ref($data) eq 'ARRAY'); my $status = ""; my $description = ""; my $shared = ""; my @shared = ""; my $oslevel = `sw_vers -productVersion`; if ($oslevel =~ /10\.[3-6]\./) { $shared = `awk \'/Info / {gsub("Info ",""); printf \$0">"}; /Shared/ {print \$NF}\' /etc/cups/printers.conf 2>/dev/null | grep -i yes`; @shared = split(/\n/,$shared); } foreach my $printer (@$data){ next if ($printer->{'_name'} =~ /^The\sprinters\slist\sis\sempty\.(.*)$/); $description = "Status: $printer->{'status'}"; next if ($description =~ /^Status:\s$/); next if ($description =~ /^Status:\sno_info_found$/); if ($printer->{'default'} eq "Yes") { $description .= " - Default printer"; } if ($oslevel =~ /10\.[3-6]\./) { foreach my $printShared (@shared) { my ($thisPrinter,$isShared) = split(/>/,$printShared); if ($printer->{'_name'} eq $thisPrinter) { $description .= " - Shared: yes"; } } } else { if ($printer->{'shared'} eq "Yes") { $description .= " - Shared: yes"; } } $common->addPrinter({ NAME => $printer->{'_name'}, DRIVER => $printer->{'ppd'}, PORT => $printer->{'uri'}, DESCRIPTION => $description, }); } } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/MacOS/Slots.pm000066400000000000000000000020051372663377700240710ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::MacOS::Slots; sub check { my $params = shift; my $common = $params->{common}; return(undef) unless -r '/usr/sbin/system_profiler'; # check perms return (undef) unless $common->can_load("Mac::SysProfile"); return 1; } sub run { my $params = shift; my $common = $params->{common}; my ($name, $description, $status); # create the profile object and return undef unless we get something back my $pro = Mac::SysProfile->new(); my $data = $pro->gettype('SPPCIDataType'); return(undef) unless(ref($data) eq 'ARRAY'); foreach my $slot (@$data) { $name = $slot->{'_name'}; $description = $slot->{'sppci_link-width'}." ".$slot->{'sppci_bus'}." ".$slot->{'sppci_slot_name'}; $common->addSlot({ NAME => $name, DESCRIPTION => $description, }); $name = $description = $status = undef; } } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/MacOS/Sound.pm000066400000000000000000000011751372663377700240640ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::MacOS::Sound; use strict; sub check { return(undef) unless -r '/usr/sbin/system_profiler'; # check perms return 1; } sub run { my $params = shift; my $common = $params->{common}; # create profiler obj, bail if datatype fails my $data = $common->get_sysprofile_devices_names('SPAudioDataType'); return(undef) unless(ref($data) eq 'ARRAY'); # add sound cards foreach my $sound (@$data){ $common->addSound({ 'NAME' => $sound, 'MANUFACTURER' => $sound, 'DESCRIPTION' => $sound, }); } } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/MacOS/Storages.pm000066400000000000000000000146511372663377700245660ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::MacOS::Storages; use strict; sub check { my $params = shift; my $common = $params->{common}; return $common->can_load('Mac::SysProfile'); return $common->can_run('system_profiler'); } sub getManufacturer { my $model = shift; $model =~ s/APPLE HDD //; if ($model =~ /(maxtor|western|sony|compaq|hewlett packard|ibm|seagate|toshiba|fujitsu|lg|samsung|nec|transcend|matshita|pioneer|hitachi)/i) { return ucfirst(lc($1)); } elsif ($model =~ /^APPLE SSD/) { return "Apple"; } elsif ($model =~ /^HP/) { return "Hewlett Packard"; } elsif ($model =~ /^WDC/) { return "Western Digital"; } elsif ($model =~ /^ST/) { return "Seagate"; } elsif ($model =~ /^HDi|^HT/ or $model =~ /^IC/ or $model =~ /^HU/) { return "Hitachi"; } } sub run { my $params = shift; my $common = $params->{common}; my $logger = $params->{logger}; my $devices = {}; my $profile = Mac::SysProfile->new(); # Get SATA Drives my $sata = $profile->gettype('SPSerialATADataType'); if ( ref($sata) eq 'ARRAY') { foreach my $storage ( @$sata ) { next unless ( ref($storage) eq 'HASH' ); my $type; if ( $storage->{'_name'} =~ /DVD/i || $storage->{'_name'} =~ /CD/i ) { $type = 'CD-ROM Drive'; } elsif ($storage->{'_name'} =~ /SSD/i || $storage->{'spsata_medium_type'} =~ /Solid State/i) { $type = 'Disk SSD drive'; }else { $type = 'Disk drive'; } my $size = $storage->{'size'}; if ($size =~ /GB/) { $size =~ s/ GB//; $size *= 1024; } if ($size =~ /TB/) { $size =~ s/ TB//; $size *= 1048576; } my $manufacturer = getManufacturer($storage->{'_name'}); my $model = $storage->{'device_model'}; $model =~ s/\s*$manufacturer\s*//i; my $description = "Status: $storage->{'smart_status'}"; if ($storage->{'spsata_trim_support'} =~ /Yes/ ) { $description .= " - Trim: $storage->{'spsata_trim_support'}";} $devices->{$storage->{'_name'}} = { NAME => $storage->{'bsd_name'}, SERIALNUMBER => $storage->{'device_serial'}, DISKSIZE => $size, FIRMWARE => $storage->{'device_revision'}, MANUFACTURER => $manufacturer, DESCRIPTION => $description, TYPE => $type, MODEL => $model }; } } # Get PATA Drives my $scsi = $profile->gettype('SPParallelSCSIDataType'); if ( ref($scsi) eq 'ARRAY') { foreach my $storage ( @$scsi ) { next unless ( ref($storage) eq 'HASH' ); my $type; if ( $storage->{'_name'} =~ /DVD/i || $storage->{'_name'} =~ /CD/i ) { $type = 'CD-ROM Drive'; } else { $type = 'Disk drive'; } my $size = $storage->{'size'}; if ($size =~ /GB/) { $size =~ s/ GB//; $size *= 1024; } if ($size =~ /TB/) { $size =~ s/ TB//; $size *= 1048576; } my $manufacturer = getManufacturer($storage->{'_name'}); my $model = $storage->{'device_model'}; $model =~ s/\s*$manufacturer\s*//i; my $description = "Status: $storage->{'smart_status'}"; if ($storage->{'spsata_trim_support'} =~ /Yes/ ) { $description .= " - Trim: $storage->{'spsata_trim_support'}";} $devices->{$storage->{'_name'}} = { NAME => $storage->{'_name'}, SERIAL => $storage->{'device_serial'}, DISKSIZE => $size, FIRMWARE => $storage->{'device_revision'}, MANUFACTURER => $manufacturer, DESCRIPTION => $description, MODEL => $model }; } } # Get PATA drives my $pata = $profile->gettype('SPParallelATADataType'); if ( ref($pata) eq 'ARRAY') { foreach my $storage ( @$pata ) { next unless ( ref($storage) eq 'HASH' ); my $type; if ( $storage->{'_name'} =~ /DVD/i || $storage->{'_name'} =~ /CD/i ) { $type = 'CD-ROM Drive'; } else { $type = 'Disk drive'; } my $manufacturer = getManufacturer($storage->{'_name'}); my $model = $storage->{'device_model'}; my $size = $storage->{'size'}; if ($size =~ /GB/) { $size =~ s/ GB//; $size *= 1024; } if ($size =~ /TB/) { $size =~ s/ TB//; $size *= 1048576; } my $description = ""; $devices->{$storage->{'_name'}} = { NAME => $storage->{'bsd_name'}, SERIALNUMBER=> $storage->{'device_serial'}, DISKSIZE => $size, FIRMWARE => $storage->{'device_revision'}, MANUFACTURER => $manufacturer, DESCRIPTION => $description, TYPE => $type, MODEL => $model }; } } # Get NVMe Drives my $nve = $profile->gettype('SPNVMeDataType'); if ( ref($nve) eq 'ARRAY') { foreach my $storage ( @$nve ) { next unless ( ref($storage) eq 'HASH' ); my $type = 'Disk NVMe Drive'; my $size = $storage->{'size'}; if ($size =~ /GB/) { $size =~ s/ GB//; $size *= 1024; } if ($size =~ /TB/) { $size =~ s/ TB//; $size *= 1048576; } my $manufacturer = getManufacturer($storage->{'_name'}); my $model = $storage->{'device_model'}; $model =~ s/\s*$manufacturer\s*//i; my $description = ""; $devices->{$storage->{'_name'}} = { NAME => $storage->{'bsd_name'}, SERIALNUMBER=> $storage->{'device_serial'}, DISKSIZE => $size, FIRMWARE => $storage->{'device_revision'}, MANUFACTURER => $manufacturer, DESCRIPTION => $description, TYPE => $type, MODEL => $model }; } } foreach my $device ( keys %$devices ) { $common->addStorages($devices->{$device}); } } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/MacOS/UUID.pm000066400000000000000000000010571372663377700235410ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::MacOS::UUID; use strict; use warnings; sub check { my $params = shift; my $common = $params->{common}; return(undef) unless -r '/usr/sbin/system_profiler'; return 1; } sub run { my $params = shift; my $common = $params->{common}; my @sphardware=`system_profiler SPHardwareDataType`; my $uuid; foreach my $line (@sphardware){ chomp $line; $uuid = $1 if ($line =~ /Hardware UUID:\s(.*)/i); } $common->setHardware({ UUID => $uuid, }); } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/MacOS/Uptime.pm000066400000000000000000000015501372663377700242340ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::MacOS::Uptime; use strict; sub check { my $boottime = `sysctl -n kern.boottime 2>/dev/null`; # straight from the BSD module ;-) return 1 if $boottime; return; } sub run { my $params = shift; my $common = $params->{common}; # stolen code from bsd. chomp (my $boottime = `sysctl -n kern.boottime`); $boottime = $1 if $boottime =~ /sec\s*=\s*(\d+)/; chomp (my $currenttime = `date +%s`); my $uptime = $currenttime - $boottime; # Uptime conversion my ($UYEAR, $UMONTH , $UDAY, $UHOUR, $UMIN, $USEC) = (gmtime ($uptime))[5,4,3,2,1,0]; # Write in ISO format $uptime=sprintf "%02d-%02d-%02d %02d:%02d:%02d", ($UYEAR-70), $UMONTH, ($UDAY-1), $UHOUR, $UMIN, $USEC; chomp(my $DeviceType =`uname -m`); $common->setHardware({ DESCRIPTION => "$DeviceType/$uptime" }); } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/MacOS/Video.pm000066400000000000000000000050151372663377700240370ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::MacOS::Video; use strict; use Parse::EDID qw(parse_edid); sub check { my $params = shift; my $common = $params->{common}; # make sure the user has access, cause that's the command that's gonna be run return(undef) unless -r '/usr/sbin/ioreg'; return(undef) unless -r '/usr/sbin/system_profiler'; return(undef) unless $common->can_load("Mac::SysProfile"); return 1; } sub run { my $params = shift; my $common = $params->{common}; # run the profiler to get our datatype my $profile = Mac::SysProfile->new(); my $data = $profile->gettype('SPDisplaysDataType'); # unless we get a valid return, bail out return(undef) unless(ref($data) eq 'ARRAY'); # we get video card because system_profiler XML output does not provide a human readable value my $video_names = $common->get_sysprofile_devices_names('SPDisplaysDataType'); return(undef) unless(ref($video_names) eq 'ARRAY'); my $count = 0; #Getting monitor serial number #TODO: get serial for multiples monitors my $ioreg_binary = `ioreg -lw0 | grep "EDID" | sed "/[^<]*{'monitor_name'}; my $ioreg_name = $ioreg->{'serial_number2'}; # add the video information foreach my $video (@$data){ my $memory; # macOS 10.13 doesn't have spdisplays_vram but has _spdisplays_vram if (exists($video->{'spdisplays_vram'})) { $memory = $video->{'spdisplays_vram'}; } elsif (exists($video->{'_spdisplays_vram'})) { $memory = $video->{'_spdisplays_vram'}; } $memory =~ s/ MB$//; $common->addVideo({ 'NAME' => $$video_names[$count], 'CHIPSET' => $video->{'sppci_model'}, 'MEMORY' => $memory, 'RESOLUTION' => $video->{'spdisplays_ndrvs'}[0]->{'spdisplays_resolution'}, }); foreach my $display (@{$video->{'spdisplays_ndrvs'}}){ my $serial; next unless(ref($display) eq 'HASH'); next if($display->{'_name'} eq 'spdisplays_display_connector'); $serial = $ioreg_serial if ($ioreg_name eq $display->{'_name'}); $common->addMonitor({ 'CAPTION' => $display->{'_name'}, 'SERIAL' => $serial, }) } $count++; } } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/Solaris.pm000066400000000000000000000021641372663377700234450ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::Solaris; use strict; use vars qw($runAfter); $runAfter = ["Ocsinventory::Agent::Backend::OS::Generic"]; sub check {$^O =~ /^solaris$/} sub run { my $params = shift; my $common = $params->{common}; my $OSName; my $OSComment; my $OSVersion; my $OSLevel; my $HWDescription; my ( $karch, $hostid, $proct, $platform); #Operating system informations chomp($OSName=`uname -s`); chomp($OSLevel=`uname -r`); chomp($OSComment=`uname -v`); open(FH, "< /etc/release") and do { chomp($OSVersion = readline (FH)); $OSVersion =~ s/^\s+//; close FH; }; chomp($OSVersion=`uname -v`) unless $OSVersion; chomp($OSVersion); $OSVersion=~s/^\s*//; $OSVersion=~s/\s*$//; # Hardware informations chomp($karch=`arch -k`); chomp($hostid=`hostid`); chomp($proct=`uname -p`); chomp($platform=`uname -i`); $HWDescription = "$platform($karch)/$proct HostID=$hostid"; $common->setHardware({ OSNAME => "$OSName $OSLevel", OSCOMMENTS => $OSComment, OSVERSION => $OSVersion, DESCRIPTION => $HWDescription }); } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/Solaris/000077500000000000000000000000001372663377700231045ustar00rootroot00000000000000UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/Solaris/Bios.pm000066400000000000000000000141351372663377700243420ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::Solaris::Bios; # SPARC # $ showrev #Hostname: 157501s021plc #Hostid: 83249bbf #Release: 5.10 #Kernel architecture: sun4u #Application architecture: sparc #Hardware provider: Sun_Microsystems #Domain: be.cnamts.fr #Kernel version: SunOS 5.10 Generic_118833-17 # # $ prtconf -pv (-b would be great...but doesn't work before S10) #System Configuration: Sun Microsystems sun4u #Memory size: 16384 Megabytes #System Peripherals (PROM Nodes): # #Node 0xf0819f00 # scsi-initiator-id: 00000007 # node#: 00000000 # #size-cells: 00000002 # stick-frequency: 00bebc20 # clock-frequency: 08f0d180 # idprom: 01840014.4f4162cb.45255cf4.4162cb16.55555555.55555555.55555555.55555555 # breakpoint-trap: 0000007f # device_type: 'gptwo' # banner-name: 'Sun Fire E6900' # compatible: 'SUNW,Serengeti' # newio-addr: 00000001 # name: 'SUNW,Sun-Fire' # X64 # $ showrev #Hostname: stlaurent #Hostid: 403100b #Release: 5.10 #Kernel architecture: i86pc #Application architecture: i386 #Hardware provider: #Domain: #Kernel version: SunOS 5.10 Generic_127112-07 # # $ smbios -t SMB_TYPE_SYSTEM #ID SIZE TYPE #1 76 SMB_TYPE_SYSTEM (system information) # # Manufacturer: Sun Microsystems, Inc. # Product: Sun Fire V40z # Version: 00 # Serial Number: R00T34E0009 # # UUID: be1630df-d130-41a4-be32-fd28bb4bd1ac # Wake-Up Event: 0x6 (power switch) # SKU Number: # Family: use strict; sub run { my $params = shift; my $common = $params->{common}; my $zone; my( $SystemSerial , $SystemModel, $SystemManufacturer, $ChassisType, $MotherBoardSerial, $MotherBoardModel, $MotherBoardManufacturer, $BiosManufacturer, $BiosVersion, $BiosDate, $aarch); if ( !$common->can_run("zonename") || `zonename` =~ /global/ ) { # Ether pre Sol10 or in Sol10/Sol11 global zone $zone = "global"; } else { $zone = ""; } if ($zone){ chomp($SystemModel = `uname -m`); chomp($aarch = `uname -p`); if( $aarch eq "i386" ){ # # For a Intel/AMD arch, we're using smbios # foreach(`/usr/sbin/smbios -t SMB_TYPE_SYSTEM`) { if(/^\s*Manufacturer:\s*(.+)$/){$SystemManufacturer = $1}; if(/^\s*Serial Number:\s*(.+)$/){$SystemSerial = $1;} if(/^\s*Product:\s*(.+)$/){$SystemModel = $1;} } foreach(`/usr/sbin/smbios -t SMB_TYPE_BIOS`) { if(/^\s*Vendor:\s*(.+)$/){$BiosManufacturer = $1}; if(/^\s*Version String:\s*(.+)$/){$BiosVersion = $1}; if(/^\s*Release Date:\s*(.+)$/){$BiosDate = $1}; } foreach(`/usr/sbin/smbios -t SMB_TYPE_BASEBOARD`) { if(/^\s*Product\s*(.+)$/){$MotherBoardModel = $1}; if(/^\s*Serial Number:\s*(.+)$/){$MotherBoardSerial = $1}; if(/^\s*Manufacturer:\s*(.+)$/){$MotherBoardManufacturer = $1}; } foreach(`/usr/sbin/smbios -t SMB_TYPE_CHASSIS`) { if(/^\s*Chassis Type:.*\((.+)\)$/) {$ChassisType = $1}; } } elsif( $aarch eq "sparc" ) { # # For a Sparc arch, we're using prtconf # my $name; my $OBPstring; my $found=0; if ( $common->can_run("virtinfo") && `virtinfo -t` =~ /.*LDoms guest.*/ ) { foreach(`virtinfo -a`) { if(/^Domain role:\s*(.+)$/) {$ChassisType = $1}; if(/^Chassis serial.:\s*(.+)$/) {$SystemSerial = $1}; } } foreach(`/usr/sbin/prtconf -pv`) { # prtconf is an awful thing to parse if(/^System Configuration:\s*(.+)\s+\S+$/) {$SystemManufacturer = $1; $BiosManufacturer = $1; } if(/^\s*banner-name:\s*'(.+)'$/){$SystemModel = $1;} unless ($name) { if(/^\s*name:\s*'(.+)'$/){$name = $1;} } unless ($OBPstring) { if(/^\s*version:\s*'(.+)'$/){ $OBPstring = $1; # looks like : "OBP 4.33.6.f 2014/07/10 10:24" # with further informations sometimes if( $OBPstring =~ m@OBP\s+(\S+)\s+(\d+)/(\d+)/(\d+)@ ){ $BiosVersion = "OBP $1"; $BiosDate = "$2/$3/$4"; } else { $BiosVersion = $OBPstring } } } } $SystemModel .= " ($name)" if( $name ); if ( $common->can_run("ipmitool") ) { foreach(`/usr/sbin/ipmitool fru print`) { if (/^\s*Chassis Type\s+:\s+(.+)/) { $ChassisType = $1; $found = 1; } elsif ( $found && /^\s*Product Serial\s+:\s+(.+)/) { $SystemSerial = $1; last; } } } if ( !$SystemSerial ) { # No serial found via ipmitool, so use sneep if( -x "/opt/SUNWsneep/bin/sneep" ) { chomp($SystemSerial = `/opt/SUNWsneep/bin/sneep`); }else { foreach(`/bin/find /opt -name sneep`) { chomp($SystemSerial = `$1`) if /^(\S+)/; } if (!$SystemSerial){ $SystemSerial = "Please install package SUNWsneep"; } } } } }else{ foreach(`showrev`){ if(/^Hardware provider:\s+(\S+)/){$SystemManufacturer = $1}; } $SystemModel = "Solaris Containers"; $SystemSerial = "Solaris Containers"; } # Writing data $common->setBios ({ BVERSION => $BiosVersion, BDATE => $BiosDate, BMANUFACTURER => $BiosManufacturer, SMANUFACTURER => $SystemManufacturer, SMODEL => $SystemModel, SSN => $SystemSerial, MMANUFACTURER => $MotherBoardManufacturer, MSN => $MotherBoardSerial, TYPE => $ChassisType, MMODEL => $MotherBoardModel }); } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/Solaris/CPU.pm000066400000000000000000000035331372663377700240750ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::Solaris::CPU; use strict; use warnings; use English qw(-no_match_vars); sub run { my $params = shift; my $common = $params->{common}; my $logger = $params->{logger}; my (%params) = @_; my $current; my $cpus=`/usr/bin/kstat -m cpu_info | egrep "chip_id|core_id|module: cpu_info" | grep chip_id | awk '{ print \$2 }' | sort -u | wc -l | tr -d ' '`; my $ncores=`/usr/bin/kstat -m cpu_info | egrep "chip_id|core_id|module: cpu_info" | grep core_id | awk '{ print \$2 }' | sort -u | wc -l | tr -d ' '`; my $vproc=`/usr/bin/kstat -m cpu_info | egrep "chip_id|core_id|module: cpu_info" | grep 'module: cpu_info' | awk '{ print \$4 }' | sort -u | wc -l | tr -d ' '`; my $cores=$ncores / $cpus; my $threads=$vproc / $cpus; my $speed=`/usr/bin/kstat -m cpu_info | grep clock_MHz | awk '{ print \$2 }' | sort -u`; my $type=`/usr/bin/kstat -m cpu_info | grep brand | awk '{\$1=""}; { print \$0 }' | sort -u`; my $manufacturer = $type =~ /SPARC/ ? 'SPARC' : $type =~ /Xeon/ ? 'Intel' : undef ; my $cpuarch=`isainfo | tr ' ' '_'`; $logger->debug("NB CPUs: $cpus"); $logger->debug("CORES: $cores"); $logger->debug("LOGICAL_CPUS: $threads"); $logger->debug("SPEED: $speed"); $logger->debug("TYPE: $type"); $logger->debug("MANUFACTURER: $manufacturer"); $logger->debug("CPUARCH: $cpuarch"); for my $i (1 .. $cpus) { $current->{MANUFACTURER} = $manufacturer if chomp($manufacturer); $current->{SPEED} = $speed if chomp($speed); $current->{TYPE} = $type if chomp($type); $current->{CORES} = $cores if $cores; $current->{LOGICAL_CPUS} = $threads if $threads; $current->{CPUARCH} = $cpuarch if chomp($cpuarch); $common->addCPU($current); } } #run(); 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/Solaris/Controllers.pm000066400000000000000000000015301372663377700257470ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::Solaris::Controllers; use strict; sub check { my $params = shift; my $common = $params->{common}; $common->can_run ("cfgadm") } sub run { my $params = shift; my $common = $params->{common}; my $name; my $type; my $description; foreach(`cfgadm -s cols=ap_id:type:info`){ $name = $type = $description = ""; next if (/^Ap_Id/); if (/^(\S+)\s+/){ $name = $1; } if(/^\S+\s+(\S+)/){ $type = $1; } #No manufacturer, but informations about controller if(/^\S+\s+\S+\s+(.*)/){ $description = $1; } $common->addController({ 'NAME' => $name, 'TYPE' => $type, 'DESCRIPTION' => $description, }); } } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/Solaris/Domains.pm000066400000000000000000000013451372663377700250370ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::Solaris::Domains; use strict; sub check { my $params = shift; my $common = $params->{common}; $common->can_run ("domainname") } sub run { my $params = shift; my $common = $params->{common}; my $domain; chomp($domain = `domainname`); if (!$domain) { my %domain; if (open RESOLV, "/etc/resolv.conf") { while() { $domain{$2} = 1 if (/^(domain|search)\s+(.+)/); } close RESOLV; } $domain = join "/", keys %domain; } # If no domain name, we send "WORKGROUP" $domain = 'WORKGROUP' unless $domain; $common->setHardware({ WORKGROUP => $domain }); } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/Solaris/Drives.pm000066400000000000000000000037021372663377700247000ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::Solaris::Drives; #Filesystem kbytes used avail capacity Mounted on #/dev/vx/dsk/bootdg/rootvol 16525754 5423501 10936996 34% / #/devices 0 0 0 0% /devices #ctfs 0 0 0 0% /system/contract #proc 0 0 0 0% /proc #mnttab 0 0 0 0% /etc/mnttab use strict; sub check { my $params = shift; my $common = $params->{common}; $common->can_run ("df") } sub run { my $params = shift; my $common = $params->{common}; my $free; my $filesystem; my $total; my $type; my $volumn; #Looking for mount points and disk space for (`df -k`){ if (/^Filesystem\s*/){next}; # on Solaris 10 and up, /devices is an extra mount which we like to exclude if (/^\/devices/){next}; # on Solaris 10 and up, /platform/.../libc_psr_hwcap1.so.1 is an extra mount which we like to exclude if (/^\/platform/){next}; # exclude cdrom mount point if (/^\/.*\/cdrom/){next}; if (/^swap.*/){next}; # exclude special entries such as ctfs, proc, mnttab, etc... if (/^.*\s+0\s+0\s+0.*/){next}; # skip nfs (dirty hack) if (/^\S+:\/.*/){next}; # everything else is a local filesystem if (/^(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\n/){ $filesystem = $6; $total = sprintf("%i",($2/1024)); $free = sprintf("%i",($4/1024)); $volumn = $1; chomp($type = `mount -v | grep " $filesystem "`); $type =~ s/\S+\s+on\s+\S+\s+type\s+(\S+)\s+.*/$1/; $common->addDrive({ FREE => $free, FILESYSTEM => $filesystem, TOTAL => $total, TYPE => $type, VOLUMN => $volumn }); } } } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/Solaris/IPv4.pm000066400000000000000000000022011372663377700242170ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::Solaris::IPv4; sub check { my $params = shift; my $common = $params->{common}; $common->can_run ("ifconfig") } # Initialise the distro entry sub run { my $params = shift; my $common = $params->{common}; my %ip; my $ip; my $hostn; #Looking for ip addresses with ifconfig, except loopback # Solaris need -a option for (`ifconfig -a`){#ifconfig in the path #Solarisligne inet if (/^\s*inet\s+(\S+).*/){($1=~/127.+/)?next:($ip{$1}=1)}; } # Ok. Now, we have the list of IP addresses configured # We could have too many addresses to list them in HW # (details will be sent in Networks instead) # # How could we choose ? # # Let's try to resolve the name of our server # chomp( $hostn = `uname -n` ); if ($hostn) { my $aip; foreach (`ping -s $hostn 10 1`) { unless ( $ip ) { if( /^.*\((\d+\.\d+\.\d+\.\d+)\):.*/ ) { $aip = $1; $ip = $aip if( exists($ip{$aip}) ); } } } } $common->setHardware({IPADDR => $ip}); } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/Solaris/Mem.pm000066400000000000000000000013241372663377700241600ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::Solaris::Mem; use strict; sub check { my $params = shift; my $common = $params->{common}; $common->can_run ("swap") && $common->can_run ("prtconf") } sub run { my $params = shift; my $common = $params->{common}; #my $unit = 1024; my $PhysicalMemory; my $SwapFileSize; # Memory informations foreach(`prtconf`){ if(/^Memory\ssize:\s+(\S+)/){ #print "total memoire: $1"; $PhysicalMemory = $1}; } #Swap Informations foreach(`swap -l`){ if(/\s+(\S+)$/){$SwapFileSize = $1}; } $common->setHardware({ MEMORY => $PhysicalMemory, SWAP => $SwapFileSize }); } 1 UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/Solaris/Memory.pm000066400000000000000000000545031372663377700247210ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::Solaris::Memory; use strict; sub check { my $params = shift; my $common = $params->{common}; $common->can_run ("memconf") } sub run { my $model; my $params = shift; my $common = $params->{common}; my $logger = $params->{logger}; my $capacity; my $description; my $numslots; my $speed = undef; my $type = undef; my $banksize; my $module_count=0; my $empty_slots; my $flag=0; my $flag_mt=0; my $caption; my $sun_class=0; my $OSLevel; my $zone; my $aarch; # for debug only my $j=0; # first, we need determinate on which model of sun server we run, # because prtdiags output (and with that memconfs output) is differend # from server model to server model # we try to classified our box in one of the known classes chomp($OSLevel = `uname -r`); chomp($aarch = `uname -p`); if ( !$common->can_run("zonename") || `zonename` =~ /global/ ) { # Either pre Sol10 or in Sol10/Sol11 global zone $zone = "global"; }else{ # Sol10/Sol11 local zone $zone = ""; } #print "Nom :".$zone."*************************\n"; if ($zone) { if ( $aarch =~ /sparc/ && $common->can_run("virtinfo") && `virtinfo -t` =~ /.*LDoms guest.*/ ) { $model = "Solaris Ldom"; }else{ chomp($model = `uname -i`); } }else{ $model="Solaris Containers"; } #print "Memory Model: $model\n"; #$model=`uname -i`; # debug print model #print "Model: '$model'"; # cut the CR from string model #$model = substr($model, 0, length($model)-1); # we map (hopfully) our server model to a known class #if ($model eq "SUNW,Sun-Fire-280R") { $sun_class = 1; } #if ($model eq "SUNW,Sun-Fire-480R") { $sun_class = 1; } #if ($model eq "SUNW,Sun-Fire-V490") { $sun_class = 1; } #if ($model eq "SUNW,Sun-Fire-880") { $sun_class = 1; } #if ($model eq "SUNW,Sun-Fire-V240") { $sun_class = 2; } #if ($model eq "SUNW,Sun-Fire-V440") { $sun_class = 2; } #if ($model eq "SUNW,Sun-Fire-V250") { $sun_class = 2; } #if ($model eq "SUNW,Sun-Fire-T200") { $sun_class = 3; } #if ($model eq "SUNW,Sun-Fire-T1000") { $sun_class = 3; } #if ($model eq "SUNW,SPARC-Enterprise-T5220") { $sun_class = 4; } #if ($model eq "SUNW,SPARC-Enterprise") { $sun_class = 5; } # for M5000 && M4000 if ($model =~ /SUNW,SPARC-Enterprise/) { $sun_class = 5; } # for M5000 && M4000 if ($model =~ /SUNW,SPARC-Enterprise-T\d/){ $sun_class = 4; } if ($model =~ /SUNW,Netra-T/){ $sun_class = 2; } if ($model =~ /SUNW,Sun-Fire-\d/){ $sun_class = 1; } if ($model =~ /SUNW,Sun-Fire-V/){ $sun_class = 2; } if ($model =~ /SUNW,Sun-Fire-V490/) { $sun_class = 1; } if ($model =~ /SUNW,Sun-Fire-T\d/) { $sun_class = 3; } if ($model =~ /SUNW,SPARCstation/) { $sun_class = 3; } if ($model =~ /SUNW,Ultra-/) { $sun_class = 3; } if ($model =~ /SUNW,Sun-Blade-100/) { $sun_class = 8; } if ($model =~ /SUNW,Sun-Blade-1500/) { $sun_class = 8; } if ($model =~ /SUNW,T\d/) { $sun_class = 3; } if ($model =~ /Solaris Containers/){ $sun_class = 7; } if ($model =~ /Solaris Ldom/) { $sun_class = 7; } if ($model =~ /i86pc/) { $sun_class = 6; } if ($model =~ /sun4v/) { $sun_class = 3; } # debug print model #print "Sunclass: $sun_class\n"; # now we can look at memory information, depending from our class if($sun_class == 0) { $logger->debug("sorry, unknown model, could not detect memory configuration"); } if($sun_class == 1) { foreach(`memconf 2>&1`) { # debug #print "count: " .$j++ . " " . $flag_mt . " : " . "$_"; # if we find "empty groups:", we have reached the end and indicate that by setting flag = 0 if(/^empty \w+:\s(\S+)/) { $flag = 0; if($1 eq "None"){$empty_slots = 0;} } # grep the type of memory modules from heading if($flag_mt && /^\s*\S+\s+\S+\s+\S+\s+\S+\s+(\S+)/) {$flag_mt=0; $description = $1;} # only grap for information if flag = 1 if ($flag && /^\s*(\S+)\s+(\S+)/) { $caption = "Board " . $1 . " MemCtl " . $2; } if ($flag && /^\s*\S+\s+\S+\s+(\S+)/) { $numslots = $1; } if ($flag && /^\s*\S+\s+\S+\s+\S+\s+(\d+)/) { $banksize = $1; } if ($flag && /^\s*\S+\s+\S+\s+\S+\s+\S+\s+\S+\s+(\d+)/) { $capacity = $1; } if ($flag) { for (my $i = 1; $i <= ($banksize / $capacity); $i++) { #print "Caption: " . $caption . " Description: " . $description . " Bank Number: " . $numslots . " DIMM Capacity: " . $capacity . "MB\n"; $module_count++; $common->addMemory({ CAPACITY => $capacity, DESCRIPTION => $description, CAPTION => $caption, SPEED => $speed, TYPE => $type, NUMSLOTS => $numslots }) } } # this is the caption line if(/^\s+Logical Logical Logical/) { $flag_mt = 1; } # if we find "---", we set flag = 1, and in next line, we start to look for information if(/^-+/){ $flag = 1; } } #print "# of RAM Modules: " . $module_count . "\n"; #print "# of empty slots: " . $empty_slots . "\n"; } if($sun_class == 2) { foreach(`memconf 2>&1`) { # debug #print "line: " .$j++ . " " . $flag_mt . "/" . $flag ." : " . "$_"; # if we find "empty sockets:", we have reached the end and indicate that by resetting flag = 0 # emtpy sockets is follow by a list of emtpy slots, where we extract the slot names if(/^empty sockets:\s*(\S+)/) { $flag = 0; # cut of first 15 char containing the string empty sockets: substr ($_,0,15) = ""; $capacity = "empty"; $numslots = 0; foreach $caption (split) { if ($caption eq "None") { $empty_slots = 0; # no empty slots -> exit loop last; } # debug #print "Caption: " . $caption . " Description: " . $description . " Bank Number: " . $numslots . " DIMM Capacity: " . $capacity . "MB\n"; $empty_slots++; $common->addMemory({ CAPACITY => $capacity, DESCRIPTION => $description, CAPTION => $caption, SPEED => $speed, TYPE => $type, NUMSLOTS => $numslots }) } } if(/.*Memory Module Groups.*/) { $flag = 0; $flag_mt = 0; } # we only grap for information if flag = 1 if($flag && /^\s*\S+\s+\S+\s+(\S+)/){ $caption = $1; } if($flag && /^\s*(\S+)/){ $numslots = $1; } if($flag && /^\s*\S+\s+\S+\s+\S+\s+(\d+)/){ $capacity = $1; } if($flag) { # debug #print "Caption: " . $caption . " Description: " . $description . " Bank Number: " . $numslots . " DIMM Capacity: " . $capacity . "MB\n"; $module_count++; $common->addMemory({ CAPACITY => $capacity, DESCRIPTION => "DIMM", CAPTION => "Ram slot ".$numslots, SPEED => $speed, TYPE => $type, NUMSLOTS => $numslots }) } # this is the caption line if(/^ID ControllerID/) { $flag_mt = 1; $description = $1;} # if we find "---", we set flag = 1, and in next line, we start to look for information if($flag_mt && /^-+/){ $flag = 1;} } # debug: show number of modules found and number of empty slots } if($sun_class == 3) { # socket MB/MEM3/CMP3/BR1/CH1/D2 has a Micron Technology 36HTF51272F80EE1D4 4GB FB-DIMM foreach(`memconf 2>&1`) { # debug if(/^empty sockets:\s*(\S+)/) { # cut of first 15 char containing the string empty sockets: substr ($_,0,15) = ""; $description = ""; $type = ""; $capacity = "empty"; $numslots = 0; foreach $caption (split) { if ($caption eq "None") { $empty_slots = 0; # no empty slots -> exit loop last; } # debug #print "Caption: " . $caption . " Description: " . $description . " Bank Number: " . $numslots . " DIMM Capacity: " . $capacity . "MB\n"; $empty_slots++; $common->addMemory({ CAPACITY => $capacity, DESCRIPTION => $description, CAPTION => $caption, SPEED => $speed, TYPE => $type, NUMSLOTS => $numslots }) } } # socket MB/MEM3/CMP3/BR1/CH1/D2 has a Micron Technology 36HTF51272F80EE1D4 4GB FB-DIMM if(/^socket\s+(\S+) has a (.+) (\d+)GB (\S+)/) { $caption = $1; $description = $2; $type = $4; $numslots = 0; $capacity = $3 * 1024; # debug #print "Caption: " . $caption . " Description: " . $description . " Bank Number: " . $numslots . " DIMM Capacity: " . $capacity . "MB\n"; $module_count++; $common->addMemory({ CAPACITY => $capacity, DESCRIPTION => $description, CAPTION => $caption, SPEED => $speed, TYPE => $type, NUMSLOTS => $numslots }) } # socket P1C1/B31/C1/D0 (LUN 0 ID 124): Samsung 32768MB DDR4 SDRAM DIMM, M393A4K40BB1-CRC if(/^socket\s+(\S+) \(LUN \d+ ID \d+\): (.+) (\d+)MB (\S+) (\S+) DIMM, (\S+)/) { $caption = $1; $description = "$2 $6"; $type = "$4 $5"; $numslots = 0; $capacity = $3; $module_count++; $common->addMemory({ CAPACITY => $capacity, DESCRIPTION => $description, CAPTION => $caption, SPEED => $speed, TYPE => $type, NUMSLOTS => $numslots }) } } # debug: show number of modules found and number of empty slots #print "# of RAM Modules: " . $module_count . "\n"; #print "# of empty slots: " . $empty_slots . "\n"; } if($sun_class == 4) { foreach(`memconf 2>&1`) { # debug #print "line: " .$j++ . " " . $flag_mt . "/" . $flag ." : " . "$_"; # if we find "empty sockets:", we have reached the end and indicate that by resetting flag = 0 # emtpy sockets is follow by a list of emtpy slots, where we extract the slot names if(/^empty sockets:\s*(\S+)/) { $flag = 0; # cut of first 15 char containing the string empty sockets: substr ($_,0,15) = ""; $capacity = "empty"; $numslots = 0; foreach $caption (split) { if ($caption eq "None") { $empty_slots = 0; # no empty slots -> exit loop last; } # debug print "Caption: " . $caption . " Description: " . $description . " Bank Number: " . $numslots . " DIMM Capacity: " . $capacity . "MB\n"; $empty_slots++; $common->addMemory({ CAPACITY => $capacity, DESCRIPTION => $description, CAPTION => $caption, SPEED => $speed, TYPE => $type, NUMSLOTS => $numslots }) } } # we only grap for information if flag = 1 # socket MB/CMP0/BR0/CH0/D0 has a Samsung 501-7953-01 Rev 05 2GB FB-DIMM if(/^socket\s+(\S+) has a (.+)\s+(\S+)GB\s+(\S+)$/i) { $caption = $1; $description = $2; $type = $4; $numslots = 0; $capacity = $3 * 1024; # debug #print "Caption: " . $caption . " Description: " . $description . " Bank Number: " . $numslots . " DIMM Capacity: " . $capacity . "MB\n"; $module_count++; $common->addMemory({ CAPACITY => $capacity, DESCRIPTION => $description, CAPTION => $caption, SPEED => $speed, TYPE => $type, NUMSLOTS => $numslots }) } } # debug: show number of modules found and number of empty slots #print "# of RAM Modules: " . $module_count . "\n"; #print "# of empty slots: " . $empty_slots . "\n"; } if ($sun_class == 5 ) { foreach(`memconf 2>&1`) { # debug #print "line: " .$j++ . " " . $flag_mt . "/" . $flag ." : " . "$_"; # if we find "empty sockets:", we have reached the end and indicate that by resetting flag = 0 # emtpy sockets is follow by a list of emtpy slots, where we extract the slot names if(/^total memory.*(\S+)/) { $flag = 0;} #print "flag : $flag\n"; if($flag_mt && /^\s+\S+\s+\S+\s+\S+\s+(\S+)/) {$flag_mt=0; $type = $1;} #print "description : $description\n"; if ($flag && /^\s(\S+)\s+(\S+)/) { $numslots = "LSB " . $1 . " Group " . $2; } if ($flag && /^\s(\S+)\s+(\S+)/) { $caption = "LSB " . $1 . " Group " . $2; } if ($flag && /^\s+\S+\s+\S\s+\S+\s+\S+\s+(\d+)/) { $capacity = $1; } if ($flag && /^\s+\S+\s+\S\s+(\d+)/) { $banksize = $1; } #print "Num slot ". $numslots . " Bank Number: " . $numslots . " Bank size " . $banksize . " DIMM Capacity: " . $capacity . "MB\n"; if ($flag && $capacity > 1 ) { for (my $i = 1; $i <= ($banksize / $capacity); $i++) { #print "caption ". $caption . " Bank Number: " . $numslots . " Bank size " . $banksize . " DIMM Capacity: " . $capacity . "MB\n"; $common->addMemory({ CAPACITY => $capacity, DESCRIPTION => $description, CAPTION => $caption, SPEED => $speed, TYPE => $type, NUMSLOTS => $module_count }) } $module_count++; } #Caption Line if (/^Sun Microsystems/) { $flag_mt=1; $flag=1; } } } if($sun_class == 6) { #CPU1_D2 BANK2: 4096MB DDR3 DIMM, Samsung M393B5170EH1-CH9 (SUN FIRE X4270) #DIMM 1A: 4096MB Synchronous DDR2 FBDIMM (ProLiant DL380 G5) #Board 1, DIMM 1A: 8192MB Synchronous DDR3 (ProLiant DL580 G7) #PROC 1 DIMM 12: 16384MB Synchronous DDR3 DIMM, HP (ProLiant DL380p Gen8) #PROC 1 DIMM 12: 32768MB Synchronous DIMM, HP 752372-081 (ProLiant DL380 Gen9) #XMM1: 2048MB Synchronous DDR2 DIMM, Elpida EBE21UE8AEFA-8G-E (HP Desktop PC) #DIMM_1: 1024MB Synchronous DDR2 DIMM, Kingston KCM633-ELC (Dell Desktop PC) foreach(`memconf 2>&1`) { # debug #print "line: " .$j++ . " " . $flag_mt . "/" . $flag ." : " . "$_"; if(/^empty memory sockets:\s*(\S+)/) { # cut of first 22 char containing the string empty sockets: substr ($_,0,22) = ""; chomp(); $capacity = "0"; $numslots = 0; foreach $caption (split(/, /,$_)) { if ($caption eq "None") { $empty_slots = 0; # no empty slots -> exit loop last; } # debug #print "Caption: " . $caption . " Description: " . $description . " Bank Number: " . $numslots . " DIMM Capacity: " . $capacity . "MB\n"; $empty_slots++; if ($caption =~ /.* (\d+)$/) { $numslots = $1; } $common->addMemory({ CAPACITY => $capacity, DESCRIPTION => "empty", CAPTION => $caption, SPEED => 'n/a', TYPE => 'n/a', NUMSLOTS => $numslots }) } } # These are the non-emtpy sockets in various formats #DIMM 1A: 4096MB Synchronous DDR2 FBDIMM (ProLiant DL380 G5) #Board 1, DIMM 1A: 8192MB Synchronous DDR3 (ProLiant DL580 G7) #PROC 1 DIMM 12: 16384MB Synchronous DDR3 DIMM, HP (ProLiant DL380p Gen8) if(/^(.*DIMM) (\S+):\s+(\d+)MB\s(\S+ DDR\d+)\s*(\w*)?(,?.*)/) { $caption = "$1 $2"; $description = "$4 $5$6"; $numslots = $2; $capacity = $3; $type = $5; unless ($type) { $type = "DIMM" }; # Default if nothing else found # debug #print "Caption: " . $caption . " Description: " . $description . " Bank Number: " . $numslots . " DIMM Capacity: " . $capacity . "MB\n"; $module_count++; $common->addMemory({ CAPACITY => $capacity, DESCRIPTION => $description, CAPTION => $caption, SPEED => $speed, TYPE => $type, NUMSLOTS => $numslots }) } #CPU1_D2 BANK2: 4096MB DDR3 DIMM, Samsung M393B5170EH1-CH9 (SUN FIRE X4270) if(/^(.*BANK)(\S+):\s+(\d+)MB\s(\S*DDR\d+)\s*(\w+)?(,?.*)/) { $caption = "$1 $2"; $description = "$4 $5$6"; $numslots = $2; $capacity = $3; $type = $5; # debug #print "Caption: " . $caption . " Description: " . $description . " Bank Number: " . $numslots . " DIMM Capacity: " . $capacity . "MB\n"; $module_count++; $common->addMemory({ CAPACITY => $capacity, DESCRIPTION => $description, CAPTION => $caption, SPEED => $speed, TYPE => $type, NUMSLOTS => $numslots }) } #PROC 1 DIMM 12: 32768MB Synchronous DIMM, HP 752372-081 (ProLiant DL380 Gen9) if(/^(.*DIMM) (\S+):\s+(\d+)MB\s(\S+)\s+(DIMM\w*)(,?.*)/) { $caption = "$1 $2"; $description = "$4 $5$6"; $numslots = $2; $capacity = $3; $type = $5; # debug #print "Caption: " . $caption . " Description: " . $description . " Bank Number: " . $numslots . " DIMM Capacity: " . $capacity . "MB\n"; $module_count++; $common->addMemory({ CAPACITY => $capacity, DESCRIPTION => $description, CAPTION => $caption, SPEED => $speed, TYPE => $type, NUMSLOTS => $numslots }) } #XMM1: 2048MB Synchronous DDR2 DIMM, Elpida EBE21UE8AEFA-8G-E (HP Desktop PC) #DIMM_1: 1024MB Synchronous DDR2 DIMM, Kingston KCM633-ELC (Dell Desktop PC) if(/^(\S+):\s+(\d+)MB\s(.+)\s+(DIMM\w*)(,?.*)/) { $caption = "$1"; $description = "$3 $4$5"; $numslots = $1; $capacity = $2; $type = $4; # debug #print "Caption: " . $caption . " Description: " . $description . " Bank Number: " . $numslots . " DIMM Capacity: " . $capacity . "MB\n"; $module_count++; $common->addMemory({ CAPACITY => $capacity, DESCRIPTION => $description, CAPTION => $caption, SPEED => $speed, TYPE => $type, NUMSLOTS => $numslots }) } } # debug: show number of modules found and number of empty slots #print "# of RAM Modules: " . $module_count . "\n"; #print "# of empty slots: " . $empty_slots . "\n"; } if ($sun_class == 7) { foreach (`prctl -n project.max-shm-memory $$ 2>&1`) { $description = $1 if /^project.(\S+)$/; $capacity = $1 if /^\s*system+\s*(\d+).*$/; if(($description && $capacity)){ $capacity = $capacity * 1024; $numslots = 1 ; $description = "Memory Allocated"; $caption = "Memory Share"; #print $description."_".$capacity."***\n"; $common->addMemory({ CAPACITY => $capacity, DESCRIPTION => $description, CAPTION => $caption, SPEED => $speed, TYPE => $type, NUMSLOTS => $numslots }) } } } if($sun_class == 8) { # example output of a Sun Blade 100 Workstation #Sun Microsystems, Inc. Sun Blade 100 (UltraSPARC-IIe 502MHz) #Memory Segment Table: #----------------------------------------------------------------------- #Base Address Size Interleave Factor Contains #----------------------------------------------------------------------- #0x0 256MB 1 chassis/system-board/DIMM0 #empty sockets: DIMM1 DIMM2 DIMM3 #total memory = 256MB #Sun Microsystems, Inc. Sun Blade 100 (UltraSPARC-IIe 502MHz) #Memory Segment Table: #----------------------------------------------------------------------- #Base Address Size Interleave Factor Contains #----------------------------------------------------------------------- #0x0 256MB 1 Label DIMM0 #0x20000000 256MB 1 Label DIMM1 #empty sockets: DIMM2 DIMM3 #total memory = 512MB foreach(`memconf 2>&1`) { if (/^empty sockets:\s*(.+)/) { foreach $caption (split(/ /, $1)) { if ($caption eq "None") { $empty_slots = 0; last; } $empty_slots++; # print "empty slot\n"; $common->addMemory({ CAPACITY => "empty", DESCRIPTION => '', CAPTION => $caption, SPEED => '', TYPE => '', NUMSLOTS => $numslots }) } } if (/^0x(\d+)\s+(\d+)(\S)B\s+(\S+)\s+(.+)/) { $caption = "$5"; $description = ""; $numslots = 0; $capacity = $2 if ( $3 eq "M" ); $capacity = $2 * 1024 if ( $3 eq "G" ); $type = ""; # debug # print "Caption: " . $caption . " Description: " . $description . " Bank Number: " . $numslots . " DIMM Capacity: " . $capacity . "MB\n"; $module_count++; $common->addMemory({ CAPACITY => $capacity, DESCRIPTION => $description, CAPTION => $caption, SPEED => $speed, TYPE => $type, NUMSLOTS => $numslots }) } } } } #run(); 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/Solaris/Networks.pm000066400000000000000000000113141372663377700252560ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::Solaris::Networks; #ce5: flags=1000843 mtu 1500 index 3 # inet 55.37.101.171 netmask fffffc00 broadcast 55.37.103.255 # ether 0:3:ba:24:9b:bf #aggr40001:2: flags=201000843 mtu 1500 index 3 # inet 55.37.101.172 netmask ffffff00 broadcast 223.0.146.255 use strict; sub check { my $params = shift; my $common = $params->{common}; $common->can_run("ifconfig") && $common->can_run("netstat") && $common->can_load ("Net::IP qw(:PROC)") } # Initialise the distro entry sub run { my $params = shift; my $common = $params->{common}; my $description; my $ipaddress; my $ipgateway; my $ipmask; my $ipsubnet; my $macaddr; my $status; my $type; my $zone; my @zoneadmcmd; my @zacsplitted; # get the first field of the first line of "zoneadm list -p" @zoneadmcmd = `zoneadm list -p`; @zacsplitted = split(/:/, $zoneadmcmd[0]); $zone = $zacsplitted[0]; foreach (`netstat -rn`){ $ipgateway=$1 if /^default\s+(\S+)/i; } #print "Nom :".$zone."*************************\n"; ### STEP 1: get aliases and zones' interfaces foreach (`ifconfig -a`){ # resets if new interface $ipaddress = $description = $macaddr = $status = $type = undef if /^(\S+):/; # interface name and other data $description = $1.":".$2 if /^(\S+):(\S+):/; $ipaddress = $1 if /inet\s+(\S+)/i; $ipmask = $1 if /\S*netmask\s+(\S+)/i; if (/ether\s+(\S+)/i) { # See # https://sourceforge.net/tracker/?func=detail&atid=487492&aid=1819948&group_id=58373 $macaddr = sprintf "%02x:%02x:%02x:%02x:%02x:%02x" , map hex, split /\:/, $1; } $status = 1 if /addNetwork({ DESCRIPTION => $description, IPADDRESS => $ipaddress, IPGATEWAY => $ipgateway, IPMASK => $ipmask, IPSUBNET => $ipsubnet, MACADDR => $macaddr, STATUS => $status?"Up":"Down", TYPE => $type, }); } } ### STEP 2: get physical interfaces when not a zone if (!$zone){ foreach (`ifconfig -a`){ # resets if new interface $ipaddress = $description = $macaddr = $status = $type = undef if /^(\S+):/; # interface name and other data $description = $1 if /^(\S+): /; $ipaddress = $1 if /inet\s+(\S+)/i; $ipmask = $1 if /\S*netmask\s+(\S+)/i; if (/ether\s+(\S+)/i) { # See # https://sourceforge.net/tracker/?func=detail&atid=487492&aid=1819948&group_id=58373 $macaddr = sprintf "%02x:%02x:%02x:%02x:%02x:%02x" , map hex, split /\:/, $1; } $status = 1 if /addNetwork({ DESCRIPTION => $description, IPADDRESS => $ipaddress, IPGATEWAY => $ipgateway, IPMASK => $ipmask, IPSUBNET => $ipsubnet, MACADDR => $macaddr, STATUS => $status?"Up":"Down", TYPE => $type, }); } } } } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/Solaris/Packages.pm000066400000000000000000000051201372663377700251560ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::Solaris::Packages; use strict; use warnings; sub check { my $params = shift; my $common = $params->{common}; # Do not run an package inventory if there is the --nosoftware parameter return if ($params->{config}->{nosoftware}); $common->can_run("pkginfo") || $common->can_run("pkg"); } sub run { my $params = shift; my $common = $params->{common}; my $chaine ; my @tab; my $name; my $version; my $comments; my $publisher; if ( `uname -r` =~ /5.11/ ) { # Solaris 11 foreach (`pkg info`) { if (/^\s*$/) { $common->addSoftware({ 'NAME' => $name, 'VERSION' => $version, 'COMMENTS' => $comments, 'PUBLISHER' => $publisher, }); $name = ''; $version = ''; $comments = ''; $publisher = ''; } elsif (/Name:\s+(.+)/) { $name = $1; } elsif (/Version:\s+(.+)/) { $version = $1; } elsif (/Publisher:\s+(.+)/) { $publisher = $1; } elsif (/Summary:\s+(.+)/) { $comments = $1; } } } else { # Solaris 10 and lower foreach (`pkginfo -l`) { if (/^\s*$/) { $common->addSoftware({ 'NAME' => $name, 'VERSION' => $version, 'COMMENTS' => $comments, 'PUBLISHER' => $publisher, }); $name = ''; $version = ''; $comments = ''; $publisher = ''; } elsif (/PKGINST:\s+(.+)/) { $name = $1; } elsif (/VERSION:\s+(.+)/) { $version = $1; } elsif (/VENDOR:\s+(.+)/) { $publisher = $1; } elsif (/DESC:\s+(.+)/) { $comments = $1; } } my $testrep; $testrep=0; #opendir(DIR,'/var/sis/') || exit ; opendir(DIR,'/var/sis/') || ($testrep=1) ; if ($testrep==0) { foreach (`ls /var/sis/*.SIS`) { $chaine= `cat $_` ; @tab = split(/;/, $chaine); if (/^\/var\/sis\/(\S+).SIS/){ $common->addSoftware({ 'VERSION' => $tab[2], 'NAME' => $tab[0]." ($1)", 'PUBLISHER' => $tab[1], 'COMMENTS' => $1, }); } } } closedir(DIR); } } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/Solaris/Ports.pm000066400000000000000000000026321372663377700245540ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::Solaris::Ports; use strict; sub run { my $params = shift; my $common = $params->{common}; my $zone; my $SystemModel; my $aarch; my $flag; my $caption; my $description; my $name; my $type; if ( !$common->can_run("zonename") || `zonename` =~ /global/ ) { # Ether pre Sol10 or in Sol10/Sol11 global zone $zone = "global"; } else { $zone = ""; } if ($zone) { chomp($SystemModel = `uname -m`); chomp($aarch = `uname -p`); if( $aarch eq "i386" ){ # # For a Intel/AMD arch, we're using smbios # foreach(`/usr/sbin/smbios -t SMB_TYPE_PORT`) { if(/\s+Internal Reference Designator:\s*(.+)/i ) { $flag = 1; $name = $1; } elsif ($flag && /^$/) { # end of section $flag = 0; $common->addPorts({ CAPTION => $caption, DESCRIPTION => $description, NAME => $name, TYPE => $type, }); $caption = $description = $name = $type = undef; } elsif ($flag) { $caption = $1 if /\s+External Connector Type:.*\((.+)\)/i; $description = $1 if /\s+External Reference Designator:\s*(.+)/i; $type = $1 if /\s+Port Type:.*\((.+)\)/i; } } } elsif( $aarch eq "sparc" ) { # # For a Sparc arch, we're done # } } } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/Solaris/Slots.pm000066400000000000000000000317021372663377700245510ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::Solaris::Slots; use strict; sub check { my $params = shift; my $common = $params->{common}; $common->can_run ("prtdiag") } sub run { my $params = shift; my $common = $params->{common}; my $description; my $designation; my $name; my $status; my @pci; my $flag; my $flag_pci; my $model; my $sun_class; chomp($model = `uname -i`); # debug print model #print "Model: '$model'"; $sun_class = 0; # we map (hopfully) our server model to a known class if ($model =~ /SUNW,SPARC-Enterprise/) { $sun_class = 1; } # M9000 if ($model =~ /SUNW,SPARC-Enterprise-T\d/) { $sun_class = 22; } # T5220 if ($model =~ /SUNW,Sun-Fire-\d/) { $sun_class = 3; } # 280R, 480R if ($model =~ /SUNW,Sun-Fire-V\d/) { $sun_class = 3; } # V490 if ($model =~ /SUNW,Sun-Fire-T\d/) { $sun_class = 4; } # T2000 if ($model =~ /SUNW,Sun-Blade-1500/) { $sun_class = 8; } # Blade 1500 workstation if ($model =~ /i86pc/) { $sun_class = 21; } # x86 hardware if ($model =~ /SUNW,T5/) { $sun_class = 22; } # T5240, T5440 if ($model =~ /sun4v/) { $sun_class = 22; } # T3-x, T4-x, T5-x #Debug #print "sun_class : $sun_class\n"; if ( $sun_class == 0 ) { # Default class, probably doesn't work foreach (`prtdiag `) { last if(/^\=+/ && $flag_pci); next if(/^\s+/ && $flag_pci); if($flag && $flag_pci && /^(\S+)\s+/) { $name = $1; } if($flag && $flag_pci && /(\S+)\s*$/) { $designation = $1; } if($flag && $flag_pci && /^\S+\s+\S+\s+\S+\s+\S+\s+\S+\s+\S+\s+\S+\s+\S+\s+\S+\s+(\S+)/) { $description = $1; } if($flag && $flag_pci && /^\S+\s+\S+\s+\S+\s+\S+\s+\S+\s+\S+\s+\S+\s+\S+\s+(\S+)/) { $status = $1; } if($flag && $flag_pci) { $common->addSlot({ DESCRIPTION => $description, DESIGNATION => $designation, NAME => $name, STATUS => $status, }); } if(/^=+\s+IO Cards/){$flag_pci = 1;} if($flag_pci && /^-+/){$flag = 1;} } } if ( $sun_class == 1 ) { # M9000 #========================= IO Devices ========================= # # IO Lane/Frq #LSB Type LPID RvID,DvID,VnID BDF State Act, Max Name Model #--- ----- ---- ------------------ --------- ----- ----------- ------------------------------ -------------------- # Logical Path # ------------ #00 PCIx 0 8, 125, 1033 2, 0, 0 okay 133, 133 pci-pciexclass,060400 N/A # /pci@0,600000/pci@0 # foreach (`prtdiag -v`) { last if(/^\=+/ && $flag_pci && $flag); if ($flag && $flag_pci && /^(\d+)\s+(\S+)\s+\S+\s+\S+\s+\S+\s+\S+\s+\S+\s+\S+\s+\S+\s+(\S+)\s+\S+\s+\S+\s+((\S+)-\S+)\s+(\S+).*/ ) { $designation = "LSB " . $1; $status = $3; $name = $4; $description = "[$2] $5"; $description .= " ($6)" unless ($6=~/N\/A/); $common->addSlot({ DESCRIPTION => $description, DESIGNATION => $designation, NAME => $name, STATUS => $status, }); } if(/^=+\S+\s+IO Devices/){$flag_pci = 1; } if($flag_pci && /^-+/){$flag = 1;} } } if ( $sun_class == 2 ) { # to be checked foreach (`prtdiag `) { if (/pci/) { @pci = split(/ +/); $name=$pci[4]." ".$pci[5]; $description=$pci[0]." (".$pci[1].")"; $designation=$pci[3]; $status=""; $common->addSlot({ DESCRIPTION => $description, DESIGNATION => $designation, NAME => $name, STATUS => $status, }); } } } if ( $sun_class == 3 ) { # SUNW,Sun-Fire-480R # ========================= IO Cards ========================= # # Bus Max # IO Port Bus Freq Bus Dev, # Type ID Side Slot MHz Freq Func State Name Model # ---- ---- ---- ---- ---- ---- ---- ----- -------------------------------- ---------------------- # PCI 8 B 3 33 33 3,0 ok SUNW,qlc-pci1077,2312.1077.101.2+ # PCI 8 B 3 33 33 3,1 ok SUNW,qlc-pci1077,2312.1077.101.2+ # PCI 8 B 5 33 33 5,0 ok pci-pci1011,25.4/pci108e,1000 PCI-BRIDGE # PCI 8 B 5 33 33 0,0 ok pci108e,1000-pci108e,1000.1 device on pci-bridge # PCI 8 B 5 33 33 0,1 ok SUNW,qfe-pci108e,1001 SUNW,pci-qfe/pci-bridg+ foreach (`prtdiag `) { last if(/^\=+/ && $flag_pci && $flag); # End of IO Devices, next section starts here if($flag && $flag_pci && /PCI/) { @pci = split(/ +/); $name=join(" ",@pci[9..$#pci]); $description="[".$pci[0]."] ".$pci[8]; $designation=$pci[0]."/".$pci[1]."/".$pci[2]."/".$pci[3]; $status=$pci[7]; $common->addSlot({ DESCRIPTION => $description, DESIGNATION => $designation, NAME => $name, STATUS => $status, }); } if(/^=+\S+\s+IO Cards/){ $flag_pci = 1; # Start of IO Devices section, still header to skip } if($flag_pci && /^-+/){ $flag = 1; # End of IO Devices header, real info starts here } } } if ( $sun_class == 21 ) { # x86 hardware $flag = 0; foreach (`/usr/sbin/smbios -t SMB_TYPE_SLOT`) { if ($flag && /^ID.*/) { # write current slot $common->addSlot({ DESCRIPTION => "$description ($status)", DESIGNATION => $designation, NAME => $name, STATUS => $status, }); $flag = 0; } elsif(/\s+Location Tag:\s+(.*)$/) { $description = $1; } elsif(/\s+Slot ID:\s+(.*)$/) { $designation= $1; } elsif(/\s+Type:\s+\S+\s+\((.*)\)$/) { $name= $1; } elsif(/\s+Usage:\s+\S+\s+\((.*)\).*$/) { $status = $1; } $flag = 1; } # Finally add the last card $common->addSlot({ DESCRIPTION => "$description ($status)", DESIGNATION => $designation, NAME => $name, STATUS => $status, }); } if ( $sun_class == 4 ) { # SUNW,Sun-Fire-T200 #========================= IO Configuration ========================= # # IO #Location Type Slot Path Name Model #----------- ----- ---- --------------------------------------------- ------------------------- --------- #IOBD/PCIE0 PCIE 0 /pci@780/pci@0/pci@8/network@0 network-pciex8086,105e SUNW,pcie+ foreach(`prtdiag `) { last if(/^\=+/ && $flag_pci && $flag); # End of IO Devices, next section starts here if($flag && $flag_pci && /PCI/) { @pci = split(/ +/); $name=$pci[5]; $description="[".$pci[1]."] ".$pci[4]; $designation=$pci[0]; $status=" "; if($flag && $flag_pci) { $common->addSlot({ DESCRIPTION => $description, DESIGNATION => $designation, NAME => $name, STATUS => $status, }); } } if(/^=+\S+\s+IO Configuration/){ $flag_pci = 1; # Start of IO Devices section, still header to skip } if($flag_pci && /^-+/){ $flag = 1; # End of IO Devices header, real info starts here } } } if ( $sun_class == 8 ) { # SUNW,Sun-Blade-1500 #================================= IO Devices ================================= #Bus Freq Slot + Name + #Type MHz Status Path Model #------ ---- ---------- ---------------------------- -------------------- #pci 33 MB isa/su (serial) # okay /pci@1e,600000/isa@7/serial@0,3f8 foreach (`prtdiag `) { last if(/^\=+/ && $flag_pci && $flag); # End of IO Devices, next section starts here # pci 33 MB isa/su(serial) SUNW,xxx if($flag && $flag_pci && /(\S+)\s+(\S+)\s+(\S+)\s+(\S+\s+\(\S+\))\s*(.*)/) { $name = $5; $designation = $3; $description = "[$1] $4"; $status = " "; $common->addSlot({ DESCRIPTION => $description, DESIGNATION => $designation, NAME => $name, STATUS => $status, }); } if(/^=+\S+\s+IO Devices/){ $flag_pci = 1; # Start of IO Devices section, still header to skip } if($flag_pci && /^-+/){ $flag = 1; # End of IO Devices header, real info starts here } } } if ( $sun_class == 22 ) { # SUNW,T5440 #======================================== IO Devices ======================================= #Slot + Bus Name + Model Max Speed Cur Speed #Status Type Path /Width /Width #------------------------------------------------------------------------------------------- #MB/HBA PCIE scsi-pciex1000,58 LSI,1068E -- -- # /pci@400/pci@0/pci@1/scsi@0 # SPARC T3-1 #================================= IO Devices ================================= #Slot + Bus Name + Model Speed #Status Type Path #------------------------------------------------------------------------------ #/SYS/MB/SASHBA0 PCIE scsi-pciex1000,72 LSI,2008 -- # /pci@400/pci@1/pci@0/pci@4/scsi@0 #/SYS/MB/RISER2/PCIE2PCIE network-pciex108e,abcd SUNW,pcie-qgc -- # /pci@400/pci@1/pci@0/pci@6/network@0 # SPARC T4-4 #======================================== IO Devices ======================================= #Slot + Bus Name + Model Max Speed Cur Speed #Status Type Path /Width /Width #------------------------------------------------------------------------------------------- #/SYS/MB/REM0/SASHBA0 PCIE LSI,sas-pciex1000,72 LSI,2008 -- -- # /pci@400/pci@1/pci@0/pci@0/LSI,sas@0 #/SYS/RIO/NET0 PCIE network-pciex8086,10c9 -- -- # /pci@400/pci@1/pci@0/pci@2/network@0 #/SYS/RIO/NET1 PCIE network-pciex8086,10c9 -- -- # /pci@400/pci@1/pci@0/pci@2/network@0,1 #/SYS/PCI-EM2 PCIE SUNW,qlc-pciex1077,2532 QEM3572 -- -- # /pci@400/pci@1/pci@0/pci@4/pci@0/pci@2/SUNW,qlc@0 # SPARC T5-4 #======================================== IO Devices ======================================= #Slot + Bus Name + Model Max Speed Cur Speed #Status Type Path /Width /Width #------------------------------------------------------------------------------------------- #/SYS/MB/USB_CTLR PCIE usb-pciexclass,0c0330 -- -- # /pci@300/pci@1/pci@0/pci@4/pci@0/pci@6/usb@0 #/SYS/RIO/XGBE0 PCIE network-pciex8086,1528 -- -- # /pci@300/pci@1/pci@0/pci@4/pci@0/pci@8/network@0 #/SYS/MB/SASHBA0 PCIE scsi-pciex1000,87 LSI,2308_2 -- -- # /pci@300/pci@1/pci@0/pci@4/pci@0/pci@c/scsi@0 foreach (`prtdiag `) { last if(/^\=+/ && $flag_pci && $flag); # End of IO Devices, next section starts here # Lazy match for $name due to differences in prtdiag output: # * the "Model" column does not always have a value # * 5-column output on Sol10, 6-column output on Sol11 if($flag && $flag_pci && /(\S+)\s+(\S+)\s+((\S+)-\S+)\s+(\S+)\s+.*/) { $designation = $1; $status = " "; $name = $3; $description = "[$2] $4"; $description .= " ($5)" unless ($5=~/.*GT\/?x\d+|--/); $common->addSlot({ DESCRIPTION => $description, DESIGNATION => $designation, NAME => $name, STATUS => $status, }); } if(/^=+\S+\s+IO Devices/){ $flag_pci = 1; # Start of IO Devices section, still header to skip } if($flag_pci && /^-+/){ $flag = 1; # End of IO Devices header, real info starts here } } } } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/Solaris/Storages.pm000066400000000000000000000057011372663377700252340ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::Solaris::Storages; use strict; #use warning; #sd0 Soft Errors: 0 Hard Errors: 0 Transport Errors: 0 #Vendor: HITACHI Product: DK32EJ72NSUN72G Revision: PQ08 Serial No: 43W14Z080040A34E #Size: 73.40GB <73400057856 bytes> #Media Error: 0 Device Not Ready: 0 No Device: 0 Recoverable: 0 #Illegal Request: 0 Predictive Failure Analysis: 0 # With -En : #c8t60060E80141A420000011A420000300Bd0 Soft Errors: 1 Hard Errors: 0 Transport Errors: 0 #Vendor: HITACHI Product: OPEN-V -SUN Revision: 5009 Serial No: #Size: 64.42GB <64424509440 bytes> #Media Error: 0 Device Not Ready: 0 No Device: 0 Recoverable: 0 #Illegal Request: 1 Predictive Failure Analysis: 0 sub check { my $params = shift; my $common = $params->{common}; $common->can_run ("iostat") } sub run { my $params = shift; my $common = $params->{common}; my $manufacturer; my $model; my $description; my $capacity; my $name; my $rev; my $sn; my $type; my $flag_first_line; my $rdisk_path; foreach(`iostat -En`){ #print; if ($flag_first_line){ ## To be removed when FIRMWARE will be supported if ($rev) { $description .= ' ' if $description; $description .= "FW:$rev"; } $rdisk_path=`ls -l /dev/rdsk/${name}s2`; if ( $rdisk_path =~ /.*->.*scsi_vhci.*/ ) { $type="MPxIO"; } elsif( $rdisk_path =~ /.*->.*fp@.*/ ) { $type="FC"; } elsif( $rdisk_path =~ /.*->.*scsi@.*/ ) { $type="SCSI"; } elsif( $rdisk_path =~ /.*->.*virtual-devices.*/ ) { $type="Virtual"; } $common->addStorages({ NAME => $name, MANUFACTURER => $manufacturer, MODEL => $model, DESCRIPTION => $description, TYPE => $type, FIRMWARE => $rev, SERIALNUMBER => $sn, DISKSIZE => $capacity }); $manufacturer=''; $model=''; $description=''; $name=''; $rev=''; $sn=''; $type=''; } $flag_first_line = 0; if (/^(\S+)\s+Soft/){ $name = $1; } if (/^.*Product:\s*(\S+)/){ $model = $1; } if (/^.*<(\S+)\s*bytes/){ $capacity = $1; $capacity = $capacity/(1024*1024); #print $capacity."\n"; } if (/^.*Serial No:\s*(\S+)/){ $sn = $1; ## To be removed when SERIALNUMBER will be supported $description = "S/N:$sn"; ## } if (/^.*Revision:\s*(\S+)/){ $rev = $1; } if (/^Vendor:\s*(\S+)/){ $manufacturer = $1; $flag_first_line = 1; } } } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/OS/Solaris/Users.pm000066400000000000000000000007311372663377700245440ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::OS::Solaris::Users; sub check { my $params = shift; my $common = $params->{common}; $common->can_run ("who") } # Initialise the distro entry sub run { my $params = shift; my $common = $params->{common}; my %user; # Logged on users for (`who`){ $user{$1} = 1 if /^(\S+)./; } my $UsersLoggedIn = join "/", keys %user; $common->setHardware ({ USERID => $UsersLoggedIn }); } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/Virtualization/000077500000000000000000000000001372663377700241735ustar00rootroot00000000000000UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/Virtualization/Docker.pm000066400000000000000000000025741372663377700257500ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::Virtualization::Docker; use strict; sub check { my $params = shift; my $common = $params->{common}; return unless $common->can_run("docker"); } my @image; sub run { my $params = shift; my $common = $params->{common}; foreach my $cont (`docker ps 2>/dev/null`) { next if ($cont =~ /^CONTAINER ID/); my $container_id=$1 if ($cont =~ /^(\w+)/i); push @image, $container_id; } foreach my $c (@image) { my $tab=`docker inspect $c`; my $memory=$1 if ($tab =~ /\s+"Memory":\s(\d+),/); my $name=$1 if ($tab =~ /\s+"Hostname":\s"(\w+)",/); my $status=$1 if ($tab =~ /\s+"Status":\s"(\w+)",/); my $vcpu=$1 if ($tab =~ /\s+"CpuShares":\s(\d+),/); my $vmid=$1 if ($tab =~ /\s+"Id":\s"(\w+)",/); my $ipaddr=$1 if ($tab =~ /\s+"IPAddress":\s"(.*)"/); my $macaddr=$1 if ($tab =~ /\s+"MacAddress":\s"(.*)"/); my $gateway=$1 if ($tab =~ /\s+"Gateway":\s"(.*)"/); $common->addVirtualMachine({ CPUSHARES => $vcpu, GATEWAY => $gateway, IPADDR => $ipaddr, MACADDR => $macaddr, MEMORY => $memory, NAME => $name, STATUS => $status, SUBSYSTEM => "Docker Container", VMID => $vmid, VTYPE => "Docker", }); } } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/Virtualization/Jails.pm000066400000000000000000000027371372663377700256040ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::Virtualization::Jails; use strict; sub check { return(undef) unless -r '/usr/sbin/jls'; return 1; } my @jail; sub run { my $params = shift; my $common = $params->{common}; foreach my $line (`jls -h 2>/dev/null | sed -e "1d"`) { push @jail, $line; } foreach my $j (@jail) { my @jparam=split('\s',$j); my $vmid=$jparam[6]; my $name=$jparam[7]; my $subsystem=$jparam[9]; my $status="running"; my @ip; my $ipv4=$jparam[39]; if ($ipv4 ne '-') { my @ipv4=split(",",$ipv4); foreach my $i (@ipv4) { push @ip, $i; } } my $ipv6=$jparam[41]; if ($ipv6 ne '-') { my @ipv6=split(",",$ipv6); foreach my $i (@ipv6) { push @ip, $i; } } my $ip=join "/", @ip; if (defined $ip) { $common->addVirtualMachine({ IPADDR => $ip, NAME => $name, STATUS => $status, SUBSYSTEM => "FreeBSD $subsystem", VMID => $vmid, VTYPE => "Jail", }); } else { $common->addVirtualMachine({ NAME => $name, STATUS => $status, SUBSYSTEM => "FreeBSD $subsystem", VMID => $vmid, VTYPE => "Jail", }); } } } 1;UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/Virtualization/Libvirt.pm000066400000000000000000000026041372663377700261460ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::Virtualization::Libvirt; use strict; use XML::Simple; sub check { my $params = shift; my $common = $params->{common}; $common->can_run('virsh') } sub run { my $params = shift; my $common = $params->{common}; foreach (`virsh --readonly list --all`) { if (/^\s*(\d+|\s+\-)\s+(\S+)\s+(\S.+)/){ my $memory; my $vcpu; my $name = $2; my $status = $3; $status =~ s/^shut off/off/; my $xml = `virsh --readonly dumpxml $name`; my $data = XMLin($xml); my $vcpu = $data->{vcpu}; my $uuid = $data->{uuid}; my $vmtype = $data->{type}; if ($data->{currentMemory}->{unit}) { $memory = $1 if $data->{currentMemory}->{content} =~ /(\d+)\d{3}$/; $vcpu = $data->{vcpu}->{content}; } else { $memory = $1 if $data->{currentMemory} =~ /(\d+)\d{3}$/; $vcpu = $data->{vcpu}; } my %machine = ( MEMORY => $memory, NAME => $name, UUID => $uuid, STATUS => $status, SUBSYSTEM => "Libvirt", VMTYPE => $vmtype, VCPU => $vcpu, ); $common->addVirtualMachine(\%machine); } } } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/Virtualization/Lxc.pm000066400000000000000000000047001372663377700252600ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::Virtualization::Lxc; use strict; sub check { my $params = shift; my $common = $params->{common}; $common->can_run('lxc-ls') && $common->can_run('lxc-info') } my $memory; my $status; my $name; my $vmtype; my $vmid; my $vcpu=0; my $lstatus=""; my $cpu; my @lxc_vm; sub run { my $params = shift; my $common = $params->{common}; # Retrieve name and state of the vm foreach (`lxc-ls -1`) { my $vm = $1 if (/^(\S+)$/); #push (@lxc_vm, $vm); foreach (`lxc-info -n $vm`){ $name = $1 if (/^Name:\s*(\S+)$/); $vmid = $1 if (/^PID:\s*(\S+)$/); $lstatus = $1 if (/^State:\s*(\S+)$/); if ($lstatus eq "RUNNING") { $status = "Running"; $memory = $1 if (`lxc-cgroup -n $name memory.limit_in_bytes` =~ /(\S+)/); if (`lxc-cgroup -n $name cpuset.cpus` =~ /(\S+)/) { $cpu = $1; if ($cpu =~ /^(\d+)-(\d+)/){ my @tmp = ($1..$2); $vcpu += $#tmp + 1; } else { $vcpu += 1; } } } elsif ($lstatus eq "FROZEN") { $status = "Paused"; } elsif ($lstatus eq "STOPPED") { $status = "Off"; open LXC, ") { next if (/^#.*/); if (/^lxc.cgroup.memory.limit_in_bytes\s+=\s*(\S+)\s*$/){ $memory = $1; } if (/^lxc.cgroup.cpuset.cpus\s+=\s*(\S+)\s*$/){ foreach $cpu (split(/,/,$1)){ $cpu = $1; if ($cpu =~ /(\d+)-(\d+)/){ my @tmp = ($1..$2); $vcpu += $#tmp + 1; } else { $vcpu += 1; } } } } } } my $machine = { MEMORY => $memory, NAME => $name, STATUS => $status, SUBSYSTEM => "LXC Container", VCPU => $vcpu, VMID => $vmid, VMTYPE => "LXC", }; $common->addVirtualMachine($machine); } } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/Virtualization/Parallels.pm000066400000000000000000000151271372663377700264560ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::Virtualization::Parallels; use strict; use warnings; use XML::Simple; sub check { my $params = shift; my $common = $params->{common}; return $common->can_run('prlctl') } sub run { my $params = shift; my $common = $params->{common}; my $config = $params->{config}; my %status_list = ( 'running' => 'running', 'blocked' => 'blocked', 'paused' => 'paused', 'suspended' => 'suspended', 'crashed' => 'crashed', 'dying' => 'dying', ); my $xmlfile = undef; if (defined($config->{server}) && $config->{server}) { my $dir = $config->{server}; $dir =~ s/\//_/g; $config->{vardir} = $config->{basevardir}."/".$dir; } elsif (defined($config->{local}) && $config->{local}) { $config->{vardir} = $config->{basevardir}."/__LOCAL__"; } if (-d $config->{vardir}) { $xmlfile = $config->{vardir}."/uuid.xml"; } my ($uuid,$mem,$status,$name,$subsys)=undef; my $cpus = 1; my @users = (); # We don't want to scan user directories unless --scan-homedirs is used return unless $config->{scanhomedirs}; foreach my $lsuser ( glob("/Users/*") ) { $lsuser =~ s/.*\///; # Just keep the login next if $lsuser =~ /Shared/i; next if $lsuser =~ /^\./i; # Ignore hidden directory next if $lsuser =~ /\ /; # Ignore directory with space in the name next if $lsuser =~ /'/; # Ignore directory with space in the name push(@users,$lsuser); } foreach my $user (@users) { my @command = `su $user -c "prlctl list -a"`; shift (@command); foreach my $line ( @command ) { chomp $line; my @params = split(/ /, $line); $uuid = $params[0]; $status = $params[1]; # Avoid security risk. Should never appends next if $uuid =~ /(;\||&)/; foreach my $infos ( `sudo -u $user prlctl list -i $uuid`) { if ($infos =~ m/^\s\smemory\s(.*)Mb/) { $mem = $1; } elsif ($infos =~ m/^\s\scpu\s([0-9]{1,2})/) { $cpus= $1; } elsif ($infos =~ m/^Name:\s(.*)/) { $name = $1; } elsif ($infos =~ m/^OS:\s(.*)/) { $subsys = $1; } } $uuid =~ s/{// if ($uuid =~ m/{/); $uuid =~ s/}// if ($uuid =~ m/}/); my ($hwUUID,$currentUUID)=undef; # if vm is running, fetch the real uuid if ($status eq 'running') { my $command = "sudo -u $user prlctl exec $uuid /usr/sbin/ioreg -rd1 -c IOPlatformExpertDevice"; open(IOREG, "$command |") or die "Failed to run '$command': $!\n"; while() { if (/^[\s|]*"(\w+)"\s*=\s*(.*)$/) { next unless $1 eq "IOPlatformUUID"; $currentUUID = $2; $currentUUID =~ s/\"//g; } } } if (! -e $xmlfile) { my $uuid_xml = { 'PARALLELS' => { 'VIRTUALMACHINES' => { 'NAME' => [$name], 'PARALLELSUUID' => [$uuid], # Damned random uuid value 'GUESTUUID' => [$currentUUID], # The true and great uuid value }, }, }; my $xs = XML::Simple->new( ForceArray => 1, KeepRoot => 1, XMLDecl => ''); my $xml = $xs->XMLout($uuid_xml); open (MYFILE, "> $xmlfile"); print MYFILE "$xml"; # write xml output to the newly created file close (MYFILE); $hwUUID = $currentUUID; # fetch guest uuid value, even if it's empty (vm not currently running) } else { my $parallels = XML::Simple->new( ForceArray => 1, KeepRoot => 1, XMLDecl => '', ); my $vm = $parallels->XMLin($xmlfile); my $numberOfVMs = 0; my $boolean = 0; while (defined $vm->{PARALLELS}[0]{VIRTUALMACHINES}[$numberOfVMs]) { $numberOfVMs+=1; } for (my $counter=0; $counter<$numberOfVMs; $counter++) { if ( $vm->{PARALLELS}[0]{VIRTUALMACHINES}[$counter]{NAME}[0] eq $name ) { # if the vm with this name exists in the file, set its GUESTUUID value, if the currentUUID isn't empty if ( defined ($currentUUID)) { $vm->{PARALLELS}[0]{VIRTUALMACHINES}[$counter]{GUESTUUID}[0] = $currentUUID; } $vm->{PARALLELS}[0]{VIRTUALMACHINES}[$counter]{PARALLELSUUID}[0] = $uuid; # if vm re-registered, parallels uuid changes $boolean = 1; if ( defined ($vm->{PARALLELS}[0]{VIRTUALMACHINES}[$counter]{GUESTUUID}[0])) { $hwUUID = $vm->{PARALLELS}[0]{VIRTUALMACHINES}[$counter]{GUESTUUID}[0]; } } } unless ($boolean) { # if vm doesn't exist, push it to the file push @{$vm->{PARALLELS}[0]{VIRTUALMACHINES}}, { NAME => [$name], PARALLELSUUID => [$uuid], GUESTUUID => [$currentUUID], }; } open (MYFILE, "> $xmlfile"); print MYFILE $parallels->XMLout($vm); close (MYFILE); } $common->addVirtualMachine ({ NAME => $name, VCPU => $cpus, MEMORY => $mem, STATUS => $status, SUBSYSTEM => $subsys, VMTYPE => "Parallels", UUID => $hwUUID, }); } } } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/Virtualization/Qemu.pm000066400000000000000000000036121372663377700254420ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::Virtualization::Qemu; # With Qemu 0.10.X, some option will be added to get more and easly information (UUID, memory, ...) use strict; sub check { my $params = shift; my $common = $params->{common}; return ($common->can_run('qemu') || $common->can_run('kvm') || $common->can_run('qemu-kvm')) } sub run { my $params = shift; my $common = $params->{common}; foreach ( `ps -ef` ) { if (m/^\S+\s+(\d+).*((qemu|kvm|(qemu-kvm)).*\-([fh]d[a-d]|drive|cdrom).*)$/) { # match only if an qemu instance my $name = "N/A"; my $mem = 0; my $uuid; my $vmtype = $3; my $vcpu = 1; my $pid = $1; if (open F, "/proc/$pid/cmdline") { my @a=split "\000-", ; close F; foreach my $option ( @a ) { if ($option =~ m/^name\000(\S+)/) { $name = $1; } elsif ($option =~ m/^m\000(\S+)/) { $mem = $1; } elsif ($option =~ m/^uuid\000(\S+)/) { $uuid = $1; } elsif ($option =~ m/.*uuid=(\S+)/) { $uuid = $1; } elsif ($option =~ m/^smp\000(\d+)/) { $vcpu = $1; } } } if ($mem == 0 ) { # Default value $mem = 128; } $common->addVirtualMachine ({ NAME => $name, UUID => $uuid, VCPU => $vcpu, MEMORY => $mem, STATUS => "running", SUBSYSTEM => $vmtype, VMTYPE => $vmtype, }); } } } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/Virtualization/SolarisLdoms.pm000066400000000000000000000026201372663377700271440ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::Virtualization::SolarisLdoms; use strict; sub check { my $params = shift; my $common = $params->{common}; return unless $common->can_run('ldm'); } sub run { my @ldoms; my $ldom; my @ldomdetails; my $ldomdetail; my $ldomname; my $ldomstatus; my $ldommem; my $ldomncpu; my $ldomuuid; my $ldomsoftstate; my $params = shift; my $common = $params->{common}; my $logger = $params->{logger}; @ldoms = `/usr/sbin/ldm list-domain -p`; foreach $ldom (@ldoms) { if($ldom =~ /^DOMAIN\|name=(\S+)\|state=(\S+)\|flags=\S+\|cons=\S+\|ncpu=(\d+)\|mem=(\d+)\|.*/) { $ldomname=$1; $ldomstatus=$2; $ldomncpu=$3; $ldommem=$4/1024/1024; $ldomsoftstate=""; @ldomdetails = `/usr/sbin/ldm list-domain -o domain -p $ldomname`; foreach $ldomdetail (@ldomdetails) { if($ldomdetail =~ /^DOMAIN\|.*\|softstate=(.*)$/) { $ldomsoftstate=$1; } elsif($ldomdetail =~ /^UUID\|uuid=(.*)$/) { $ldomuuid=$1; } } my $machine = { MEMORY => $ldommem, NAME => $ldomname, UUID => $ldomuuid, STATUS => $ldomstatus, SUBSYSTEM => $ldomsoftstate, VMTYPE => "Solaris Ldom", VCPU => $ldomncpu, }; $common->addVirtualMachine($machine); } } } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/Virtualization/SolarisZones.pm000066400000000000000000000044741372663377700271750ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::Virtualization::SolarisZones; use strict; sub check { my $params = shift; my $common = $params->{common}; return unless $common->can_run('zoneadm'); return unless $common->can_run('zonecfg'); return unless check_solaris_valid_release(); } sub check_solaris_valid_release{ #check if Solaris 10 release is higher than 08/07 #no problem if Solaris 11 my $OSlevel; my @rlines; my $release_file; my $release; my $year; my $month; $OSlevel=`uname -r`; if ( $OSlevel =~ /5.10/ ) { $release_file = "/etc/release"; if (!open(SOLVERSION, $release_file)) { return; } @rlines = ; @rlines = grep(/Solaris/,@rlines); $release = @rlines[0]; $release =~ m/(\d)\/(\d+)/; $month = $1; $year = $2; $month =~ s/^0*//g; $year =~ s/^0*//g; if ($year <= 7 and $month < 8 ){ return 0; } } 1 } sub run { my @zones; my @lines; my $zone; my $zoneid; my $zonename; my $zonestatus; my $zonefile; my $pathroot; my $uuid; my $zonetype; my $memory; my $memcap; my $vcpu; my $params = shift; my $common = $params->{common}; my $logger = $params->{logger}; @zones = `/usr/sbin/zoneadm list -p`; @zones = grep (!/global/,@zones); foreach $zone (@zones) { ($zoneid,$zonename,$zonestatus,$pathroot,$uuid,$zonetype)=split(/:/,$zone); $memory=""; foreach (`/usr/sbin/zonecfg -z $zonename info capped-memory`) { if (/\s+physical:\s+(\S+)(\S)/) { # recalculate to GB $memory = $1 if ( $2 eq "G" ) ; $memory = $1 / 1024 if ( $2 eq "M" ) ; } } $vcpu=""; foreach (`/usr/sbin/zonecfg -z $zonename info dedicated-cpu`) { if (/\s+ncpus:\s+\S*(\d+)/) { $vcpu = $1; } } my $machine = { MEMORY => $memory, NAME => $zonename, UUID => $uuid, STATUS => $zonestatus, SUBSYSTEM => $zonetype, VMTYPE => "Solaris Zones", VMID => $zoneid, VCPU => $vcpu, }; $common->addVirtualMachine($machine); } } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/Virtualization/VirtualBox.pm000066400000000000000000000155221372663377700266350ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::Virtualization::VirtualBox; # This module detects only all VMs create by the user who launch this module (root VMs). use strict; use XML::Simple; use File::Glob ':glob'; sub check { my $params = shift; my $common = $params->{common}; return $common->can_run('VirtualBox') and $common->can_run('VBoxManage') } sub run { my $params = shift; my $common = $params->{common}; my $scanhomedirs = $params->{accountinfo}{config}{scanhomedirs}; my $cmd_list_vms = "VBoxManage -nologo list vms"; my ( $version ) = ( `VBoxManage --version` =~ m/^(\d\.\d).*$/ ) ; if ( $version > 2.1 ) { # detect VirtualBox version 2.2 or higher $cmd_list_vms = "VBoxManage -nologo list --long vms"; } my $in = 0; my $uuid; my $mem; my $status; my $name; foreach my $line (`$cmd_list_vms`){ # read only the information on the first paragraph of each vm chomp ($line); if ($in == 0 and $line =~ m/^Name:\s+(.*)$/) { # begin $name = $1; $in = 1; } elsif ($in == 1 ) { if ($line =~ m/^UUID:\s+(.*)/) { $uuid = $1; } elsif ($line =~ m/^Memory size:\s+(.*)/ ) { $mem = $1; } elsif ($line =~ m/^State:\s+(.*)\(.*/) { $status = ( $1 =~ m/off/ ? "off" : $1 ); } elsif ($line =~ m/^\s*$/) { # finish $in = 0 ; next if $uuid =~ /^N\\A$/ ; #If no UUID found, it is not a virtualmachine $common->addVirtualMachine ({ NAME => $name, VCPU => 1, UUID => $uuid, MEMORY => $mem, STATUS => $status, SUBSYSTEM => "Oracle xVM VirtualBox", VMTYPE => "VirtualBox", }); $name = $status = $mem = $uuid = 'N\A'; # useless but need it for security (new version, ...) } } } if ($in == 1) { # Anormal situation ! save the current vm information ... $common->addVirtualMachine ({ NAME => $name, VCPU => 1, UUID => $uuid, MEMORY => $mem, STATUS => $status, SUBSYSTEM => "Oracle xVM VirtualBox", VMTYPE => "VirtualBox", }); } # try to found another VMs, not exectute by root my @vmRunnings = (); my $index = 0 ; foreach my $line ( `ps -ef` ) { chomp($line); if ( $line !~ m/^root/) { if ($line =~ m/^.*VirtualBox (.*)$/) { my @process = split (/\s*\-\-/, $1); #separate options $name = $uuid = "N/A"; foreach my $option ( @process ) { #print $option."\n"; if ($option =~ m/^comment (.*)/) { $name = $1; } elsif ($option =~ m/^startvm (\S+)/) { $uuid = $1; } } if ($scanhomedirs == 1 ) { # If I will scan Home directories, $vmRunnings [$index] = $uuid; # save the no-root running machine $index += 1; } else { $common->addVirtualMachine ({ # add in inventory NAME => $name, VCPU => 1, UUID => $uuid, STATUS => "running", SUBSYSTEM => "Oracle xVM VirtualBox", VMTYPE => "VirtualBox", }); } } } } # If home directories scan is authorized if ($scanhomedirs == 1 ) { # Read every Machines Xml File of every user foreach my $xmlMachine (bsd_glob("/home/*/.VirtualBox/Machines/*/*.xml")) { chomp($xmlMachine); # Open config file ... my $configFile = new XML::Simple; my $data = $configFile->XMLin($xmlMachine); # ... and read it if ($data->{Machine}->{uuid}) { my $uuid = $data->{Machine}->{uuid}; $uuid =~ s/^{?(.{36})}?$/$1/; my $status = "off"; foreach my $vmRun (@vmRunnings) { if ($uuid eq $vmRun) { $status = "running"; } } $common->addVirtualMachine ({ NAME => $data->{Machine}->{name}, VCPU => $data->{Machine}->{Hardware}->{CPU}->{count}, UUID => $uuid, MEMORY => $data->{Machine}->{Hardware}->{Memory}->{RAMSize}, STATUS => $status, SUBSYSTEM => "Oracle xVM VirtualBox", VMTYPE => "VirtualBox", }); } } foreach my $xmlVirtualBox (bsd_glob("/home/*/.VirtualBox/VirtualBox.xml")) { chomp($xmlVirtualBox); # Open config file ... my $configFile = new XML::Simple; my $data = $configFile->XMLin($xmlVirtualBox); # ... and read it my $defaultMachineFolder = $data->{Global}->{SystemProperties}->{defaultMachineFolder}; if ( $defaultMachineFolder != 0 and $defaultMachineFolder != "Machines" and $defaultMachineFolder =~ /^\/home\/S+\/.VirtualBox\/Machines$/ ) { foreach my $xmlMachine (bsd_glob($defaultMachineFolder."/*/*.xml")) { my $configFile = new XML::Simple; my $data = $configFile->XMLin($xmlVirtualBox); if ( $data->{Machine} != 0 and $data->{Machine}->{uuid} != 0 ) { my $uuid = $data->{Machine}->{uuid}; $uuid =~ s/^{?(.{36})}?$/$1/; my $status = "off"; foreach my $vmRun (@vmRunnings) { if ($uuid eq $vmRun) { $status = "running"; } } $common->addVirtualMachine ({ NAME => $data->{Machine}->{name}, VCPU => $data->{Machine}->{Hardware}->{CPU}->{count}, UUID => $uuid, MEMORY => $data->{Machine}->{Hardware}->{Memory}->{RAMSize}, STATUS => $status, SUBSYSTEM => "Oracle xVM VirtualBox", VMTYPE => "VirtualBox", }); } } } } } } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/Virtualization/VmWareDesktop.pm000066400000000000000000000026141372663377700272670ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::Virtualization::VmWareDesktop; # # initial version: Walid Nouh # use strict; sub check { my $params = shift; my $common = $params->{common}; return $common->can_run('/Library/Application\ Support/VMware\ Fusion/vmrun') } sub run { my $params = shift; my $common = $params->{common}; my $logger = $params->{logger}; my $uuid; my $mem; my $status; my $name; my $i = 0; my $commande = "/Library/Application\\ Support/VMware\\ Fusion\/vmrun list"; foreach my $vmxpath ( `$commande` ) { next unless $i++ > 0; # Ignore the first line if (!open TMP, "<$vmxpath") { $logger->debug("Can't open $vmxpath\n"); next; } my @vminfos = ; close TMP; foreach my $line (@vminfos) { if ($line =~ m/^displayName =\s\"+(.*)\"/) { $name = $1; } elsif ($line =~ m/^memsize =\s\"+(.*)\"/) { $mem = $1; } elsif ($line =~ m/^uuid.bios =\s\"+(.*)\"/) { $uuid = $1; } } $common->addVirtualMachine ({ NAME => $name, VCPU => 1, UUID => $uuid, MEMORY => $mem, STATUS => "running", SUBSYSTEM => "VmWare Fusion", VMTYPE => "VmWare", }); } } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/Virtualization/VmWareESX.pm000066400000000000000000000025761372663377700263240ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::Virtualization::VmWareESX; use strict; sub check { my $params = shift; my $common = $params->{common}; $common->can_run('vmware-cmd') } sub run { my $params = shift; my $common = $params->{common}; foreach my $vmx (`vmware-cmd -l`) { chomp $vmx; next unless -f $vmx; my %machineInfo; open VMX, "<$vmx" or warn; foreach () { if (/^(\S+)\s*=\s*(\S+.*)/) { my $key = $1; my $value = $2; $value =~ s/(^"|"$)//g; $machineInfo{$key} = $value; } } close VMX; my $status = 'unknow'; if ( `vmware-cmd "$vmx" getstate` =~ /=\ (\w+)/ ) { # off $status = $1; } my $memory = $machineInfo{'memsize'}; my $name = $machineInfo{'displayName'}; my $uuid = $machineInfo{'uuid.bios'}; # correct uuid format $uuid =~ s/\s+//g;# delete space $uuid =~ s!^(........)(....)(....)-(....)(.+)$!\1-\2-\3-\4-\5!; # add dashs my $machine = { MEMORY => $memory, NAME => $name, UUID => $uuid, STATUS => $status, SUBSYSTEM => "VmWareESX", VMTYPE => "VmWare", }; $common->addVirtualMachine($machine); } } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/Virtualization/VmWareWorkstation.pm000066400000000000000000000030751372663377700302040ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::Virtualization::VmWareWorkstation; # # initial version: Walid Nouh # use strict; sub check { my $params = shift; my $common = $params->{common}; return $common->can_run('/bin/vmrun') } sub run { my $params = shift; my $common = $params->{common}; my $logger = $params->{logger}; my $cpu; my $cores; my $uuid; my $mem; my $status; my $name; my $i = 0; my $commande = "/bin/vmrun list"; foreach my $vmxpath ( `$commande` ) { next unless $i++ > 0; # Ignore the first line if (!open TMP, "<$vmxpath") { $logger->debug("Can't open $vmxpath\n"); next; } my @vminfos = ; close TMP; foreach my $line (@vminfos) { if ($line =~ m/^displayName =\s\"+(.*)\"/) { $name = $1; } elsif ($line =~ m/^numvcpus =\s\"+(.*)\"/){ $cpu = $1; } elsif ($line =~ m/^cpuid.coresPerSocket =\s\"+(.*)\" /){ $cores = $1; } elsif ($line =~ m/^memsize =\s\"+(.*)\"/) { $mem = $1; } elsif ($line =~ m/^uuid.bios =\s\"+(.*)\"/) { $uuid = $1; } } $common->addVirtualMachine ({ NAME => $name, VCPU => $cpu, CORES => $cores, UUID => $uuid, MEMORY => $mem, STATUS => "running", SUBSYSTEM => "VmWare Workstation", VMTYPE => "VmWare", }); } } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/Virtualization/Vmsystem.pm000066400000000000000000000150771372663377700263720ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::Virtualization::Vmsystem; # Initial Ocsinventory::Agent::Backend::Virtualization::Vmsystem version: Nicolas EISEN # # Code include from imvirt - I'm virtualized? # http://micky.ibh.net/~liske/imvirt.html # # Authors: # Thomas Liske # # Copyright Holder: # 2008 (C) IBH IT-Service GmbH [http://www.ibh.de/] # # License: # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this package; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # ## # # Outputs: # Xen # VirtualBox # Virtual Machine # VMware # QEMU # SolarisZone # # If no virtualization has been detected: # Physical # ## use strict; sub check { my $params = shift; my $common = $params->{common}; if ( $common->can_run("zoneadm")){ # Is a solaris zone system capable ? return 1; } if ( $common->can_run ("dmidecode") ) { # 2.6 and under haven't -t parameter my $dmidecode_ver = `dmidecode -V 2>/dev/null`; my @SplitVersion = split(/\./, $dmidecode_ver); if (@SplitVersion[0] > 2) { return 1; } elsif (@SplitVersion[0] == 2 && @SplitVersion[1] >= 7) { return 1; } } return 0; } sub run { my $params = shift; my $common = $params->{common}; my $dmidecode = '/usr/sbin/dmidecode'; my $cmd = '$dmidecode -t system'; my $dmesg = '/bin/dmesg | head -n 750'; my $status = "Physical"; my $found = 0; # Solaris zones my @solaris_zones; @solaris_zones = `/usr/sbin/zoneadm list`; @solaris_zones = grep (!/global/,@solaris_zones); if(@solaris_zones){ $status = "SolarisZone"; $found = 1; } if ( -d '/proc/xen' || check_file_content('/sys/devices/system/clocksource/clocksource0/available_clocksource','xen')) { $found = 1 ; if (check_file_content('/proc/xen/capabilities', 'control_d')) { # dom0 host } else { # domU PV host $status = "Xen"; # those information can't be extracted from dmidecode $common->setBios ({ SMANUFACTURER => 'Xen', SMODEL => 'PVM domU' }); } } # dmidecode needs root to work :( if ($found == 0 and -r '/dev/mem' && -x $dmidecode) { my $sysprod = `$dmidecode -s system-product-name`; if ($sysprod =~ /^VMware/) { $status = "VMware"; $found = 1; } elsif ($sysprod =~ /^Virtual Machine/) { $status = "Virtual Machine"; $found = 1; } elsif ($sysprod =~ /^Microsoft Corporation/) { $status = "Hyper-V"; $found=1; } else { my $biosvend = `$dmidecode -s bios-vendor`; if ($biosvend =~ /^QEMU/) { $status = "QEMU"; $found = 1; } elsif ($biosvend =~ /^Xen/) { # virtualized Xen $status = "Xen"; $found = 1; } } } # Parse loaded modules my %modmap = ( '^vmxnet\s' => 'VMware', '^xen_\w+front\s' => 'Xen', ); if ($found == 0 and open(HMODS, '/proc/modules')) { while() { foreach my $str (keys %modmap) { if (/$str/) { $status = "$modmap{$str}"; $found = 1; last; } } } close(HMODS); } # Let's parse some logs & /proc files for well known strings my %msgmap = ( 'VMware vmxnet virtual NIC driver' => 'VMware', 'Vendor: VMware\s+Model: Virtual disk' => 'VMware', 'Vendor: VMware,\s+Model: VMware Virtual ' => 'VMware', ': VMware Virtual IDE CDROM Drive' => 'VMware', ' QEMUAPIC ' => 'QEMU', 'QEMU Virtual CPU' => 'QEMU', ': QEMU HARDDISK,' => 'QEMU', ': QEMU CD-ROM,' => 'QEMU', ': Virtual HD,' => 'Virtual Machine', ': Virtual CD,' => 'Virtual Machine', ' VBOXBIOS ' => 'VirtualBox', ': VBOX HARDDISK,' => 'VirtualBox', ': VBOX CD-ROM,' => 'VirtualBox', 'Hypervisor signature: xen' => 'Xen', 'Xen virtual console successfully installed' => 'Xen', 'Xen reported:' => 'Xen', 'Xen: \d+ - \d+' => 'Xen', 'xen-vbd: registered block device' => 'Xen', 'ACPI: RSDP \(v\d+\s+Xen ' => 'Xen', 'ACPI: XSDT \(v\d+\s+Xen ' => 'Xen', 'ACPI: FADT \(v\d+\s+Xen ' => 'Xen', 'ACPI: MADT \(v\d+\s+Xen ' => 'Xen', 'ACPI: HPET \(v\d+\s+Xen ' => 'Xen', 'ACPI: SSDT \(v\d+\s+Xen ' => 'Xen', 'ACPI: DSDT \(v\d+\s+Xen ' => 'Xen', ); if ($found == 0 and open(HDMSG, '/var/log/dmesg')) { while() { foreach my $str (keys %msgmap) { if (/$str/) { $status = "$msgmap{$str}"; $found = 1; last; } } } close(HDMSG); } # Read kernel ringbuffer directly if ($found == 0 and open(HDMSG, '$dmesg |')) { while() { foreach my $str (keys %msgmap) { if (/$str/) { $status = "$msgmap{$str}"; $found = 1; last; } } } close(HDMSG); } if ($found == 0 and open(HSCSI, '/proc/scsi/scsi')) { while() { foreach my $str (keys %msgmap) { if (/$str/) { $status = "$msgmap{$str}"; $found = 1; last; } } } close(HSCSI); } $common->setHardware ({ VMSYSTEM => $status, }); } sub check_file_content { my ($file, $pattern) = @_; return 0 unless -r $file; my $found = 0; open (my $fh, '<', $file) or die "Can't open file $file: $!"; while (my $line = <$fh>) { if ($line =~ /$pattern/) { $found = 1; last; } } close ($fh); return $found; } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/Virtualization/Xen.pm000066400000000000000000000002271372663377700252640ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::Virtualization::Xen; $runMeIfTheseChecksFailed = ["Ocsinventory::Agent::Backend::Virtualization::Libvirt"]; 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/Virtualization/Xen/000077500000000000000000000000001372663377700247255ustar00rootroot00000000000000UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/Virtualization/Xen/XL.pm000066400000000000000000000042331372663377700256100ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::Virtualization::Xen::XL; use strict; sub check { my $params = shift; my $common = $params->{common}; my $can_run = $common->can_run('xl'); if ($can_run) { system('xl list'); my $exit_val = $? >> 8; return $exit_val eq 0; } return $can_run; } sub run { my $params = shift; my $common = $params->{common}; # output: xm list # # Name ID Mem(MiB) VCPUs State Time(s) # Domain-0 0 98 1 r----- 5068.6 # Fedora3 164 128 1 r----- 7.6 # Fedora4 165 128 1 ------ 0.6 # Mandrake2006 166 128 1 -b---- 3.6 # Mandrake10.2 167 128 1 ------ 2.5 # Suse9.2 168 100 1 ------ 1.8 # xl status my %status_list = ( 'r' => 'running', 'b' => 'blocked', 'p' => 'paused', 's' => 'shutdown', 'c' => 'crashed', 'd' => 'dying', ); my $vmtype = 'xen'; my $subsystem = 'xl'; my @xl_list = `xl list`; # remove first line shift @xl_list; foreach my $vm (@xl_list) { chomp $vm; my ($name, $vmid, $memory, $vcpu, $status, $time) = split(' ',$vm); $status =~ s/-//g; $status = ( $status ? $status_list{$status} : 'off'); my @vm_info = `xl list -l $name`; my $uuid; foreach my $value (@vm_info) { chomp $value; if ($value =~ /uuid/) { $value =~ s/"//g; $value =~ s/,//g; $value =~ s/\s+.*uuid:\s+(.*)/\1/; $uuid = $value; last; } } my $machine = { MEMORY => $memory, NAME => $name, UUID => $uuid, STATUS => $status, SUBSYSTEM => $subsystem, VMTYPE => $vmtype, VCPU => $vcpu, VMID => $vmid, }; $common->addVirtualMachine($machine); } } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/Virtualization/Xen/XM.pm000066400000000000000000000041661372663377700256160ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::Virtualization::Xen::XM; use strict; sub check { my $params = shift; my $common = $params->{common}; my $can_run = $common->can_run('xm'); if ($can_run) { system('xm list'); my $exit_val = $? >> 8; return $exit_val eq 0; } return $can_run; } sub run { my $params = shift; my $common = $params->{common}; # output: xm list # # Name ID Mem(MiB) VCPUs State Time(s) # Domain-0 0 98 1 r----- 5068.6 # Fedora3 164 128 1 r----- 7.6 # Fedora4 165 128 1 ------ 0.6 # Mandrake2006 166 128 1 -b---- 3.6 # Mandrake10.2 167 128 1 ------ 2.5 # Suse9.2 168 100 1 ------ 1.8 # xm status my %status_list = ( 'r' => 'running', 'b' => 'blocked', 'p' => 'paused', 's' => 'shutdown', 'c' => 'crashed', 'd' => 'dying', ); my $vmtype = 'xen'; my $subsystem = 'xm'; my @xm_list = `xm list`; # remove first line shift @xm_list; foreach my $vm (@xm_list) { chomp $vm; my ($name, $vmid, $memory, $vcpu, $status, $time) = split(' ',$vm); $status =~ s/-//g; $status = ( $status ? $status_list{$status} : 'off'); my @vm_info = `xm list -l $name`; my $uuid; foreach my $value (@vm_info) { chomp $value; if ($value =~ /uuid/) { $value =~ s/\(|\)//g; $value =~ s/\s+.*uuid\s+(.*)/\1/; $uuid = $value; last; } } my $machine = { MEMORY => $memory, NAME => $name, UUID => $uuid, STATUS => $status, SUBSYSTEM => $subsystem, VMTYPE => $vmtype, VCPU => $vcpu, VMID => $vmid, }; $common->addVirtualMachine($machine); } } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Backend/Virtualization/XenCitrixServer.pm000066400000000000000000000026671372663377700276500ustar00rootroot00000000000000package Ocsinventory::Agent::Backend::Virtualization::XenCitrixServer; use strict; use warnings; sub check { my $params = shift; my $common = $params->{common}; $common->can_run('xe') } sub run { my $params = shift; my $common = $params->{common}; my $hostname = `hostname`; my $residenton; foreach (`xe host-list params=uuid hostname=$hostname`) { $residenton = $1 if /:\s+(.+)/; } foreach (`xe vm-list params=uuid resident-on=$residenton`) { if (/:\s+(.+)/) { my $uuid = $1 if /:\s+(.+)/; my $fname = `xe vm-list params=name-label uuid=$uuid`; my $name = $1 if $fname =~ /:\s+(.+)/; my $fstatus = `xe vm-list params=power-state uuid=$uuid`; my $status = $1 if $fstatus =~ /:\s+(.+)/; my $fvcpu = `xe vm-list params=VCPUs-max uuid=$uuid`; my $vcpu = $1 if $fvcpu =~ /:\s+(.+)/; my $fmemory = `xe vm-list params=memory-actual uuid=$uuid`; my $tmemory = $1 if $fmemory =~ /:\s+(.+)/; my $memory = $1 if $tmemory =~ /(\d+)\d{6}$/; my $machine = { MEMORY => $memory, NAME => $name, UUID => $uuid, STATUS => $status, SUBSYSTEM => "xe", VMTYPE => "XEN", VCPU => $vcpu, }; $common->addVirtualMachine($machine); } } } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Common.pm000066400000000000000000000721401372663377700214120ustar00rootroot00000000000000############################################################################### ## OCSINVENTORY-NG ## Copyleft Guillaume PROTET 2010 ## Web : http://www.ocsinventory-ng.org ## ## This code is open source and may be copied and modified as long as the source ## code is always made freely available. ## Please refer to the General Public Licence http://www.gnu.org/ or Licence.txt ################################################################################ package Ocsinventory::Agent::Common; use strict; no strict 'refs'; use warnings; use Encode qw(encode); =head1 NAME Ocsinventory::Agent::Common - give common methods to other modules =over =item addController() Add a controller in the inventory. =item addUsb() Add external usb devices in the inventory. =item addInput() Add internal inputs as keyboard, mouse in the inventory. =item addModem() Add a modem in the inventory. =item addDrive() Add a partition in the inventory. =item addStorages() Add a storage system (hard drive, USB key, SAN volume, etc) in the inventory. =item addMemory() Add a memory module in the inventory. =item addPort() Add a port module in the inventory. =item addSlot() Add a slot in the inventory. =item addSoftware() Register a software in the inventory. =item addMonitor() Add a monitor (screen) in the inventory. =item addVideo() Add a video card in the inventory. =item addSound() Add a sound card in the inventory. =item addNetwork() Register a network in the inventory. =item addRepo() Register a repository in the inventory. =item setHardware() Save global information regarding the machine. The use of setHardware() to update USERID and PROCESSOR* information is deprecated, please, use addUser() and addCPU() instead. =item setBios() Set BIOS information. =item addCPU() Add a CPU in the inventory. =item addUser() Add an user in the list of logged user. =item addLocalUser() Add local users in the inventory. =item addLocalGroup() Add local groups in the inventory. =item addPrinter() Add a printer in the inventory. =item addVirtualMachine() Add a Virtual Machine in the inventory. =item addProcess() Record a running process in the inventory. =item addCamera() Add a camera device in the inventory. Only avalaible for MacOSX =item addIpDiscoverEntry() IpDiscover is used to identify network interface on the local network. This is done on the ARP level. This function adds a network interface in the inventory. =item setAccessLog() What is that for? :) =item flushXMLTags() Clear the content of $common->{xmltags} (to use after adding it in XML) =item addBatteries() Add a memory module in the inventory. =back =cut ################################################################################## # Ocsinventory::Agent::Common is use to give common methods to other modules # ################################################################################## sub new { my (undef, $params) = @_; my $self = {}; $self->{logger} = $params->{logger}; $self->{config} = $params->{config}; $self->{xmltags} = {}; bless $self; } sub addController { my ($self, $args) = @_; my $xmltags = $self->{xmltags}; my $content = {}; foreach my $key (qw/DESCRIPTION DRIVER NAME MANUFACTURER PCIID PCISLOT TYPE/) { if (exists $args->{$key}) { $content->{$key}[0] = $args->{$key} if $args->{$key}; } } push @{$xmltags->{CONTROLLERS}},$content; } sub addUsb { my ($self, $args) = @_; my $xmltags = $self->{xmltags}; my $content = {}; foreach my $key (qw/DESCRIPTION INTERFACE MANUFACTURER SERIAL TYPE/) { if (exists $args->{$key}) { $content->{$key}[0] = $args->{$key} if $args->{$key}; } } push @{$xmltags->{USBDEVICES}},$content; } sub addInput { my ($self, $args) = @_; my $xmltags = $self->{xmltags}; my $content = {}; foreach my $key (qw/DESCRIPTION INTERFACE MANUFACTURER SERIAL TYPE/) { if (exists $args->{$key}) { $content->{$key}[0] = $args->{$key} if $args->{$key}; } } push @{$xmltags->{INPUTS}},$content; } sub addModem { my ($self, $args) = @_; my $xmltags = $self->{xmltags}; my $content = {}; foreach my $key (qw/DESCRIPTION NAME/) { if (exists $args->{$key}) { $content->{$key}[0] = $args->{$key} if $args->{$key}; } } push @{$xmltags->{MODEMS}}, $content; } # For compatibility sub addModems { my $self = shift; my $logger = $self->{logger}; $logger->debug("please rename addModems to addModem()"); $self->addModem(@_); } sub addDrive { my ($self, $args) = @_; my $xmltags = $self->{xmltags}; my $content = {}; foreach my $key (qw/CREATEDATE FREE FILESYSTEM LABEL SERIAL TOTAL TYPE VOLUMN/) { if (exists $args->{$key}) { $content->{$key}[0] = $args->{$key} if $args->{$key}; } } push @{$xmltags->{DRIVES}}, $content; } # For compatibility sub addDrives { my $self = shift; my $logger = $self->{logger}; $logger->debug("please rename addDrives to addDrive()"); $self->addDrive(@_); } sub addStorages { my ($self, $args) = @_; my $xmltags = $self->{xmltags}; my $content = {}; foreach my $key (qw/DESCRIPTION DISKSIZE FIRMWARE MANUFACTURER MODEL NAME SERIALNUMBER SCSI_CHID SCSI_COID SCSI_LUN SCSI_UNID TYPE/) { if (exists $args->{$key}) { $content->{$key}[0] = $args->{$key} if $args->{$key}; } } push @{$xmltags->{STORAGES}}, $content; } # For compatibility sub addStorage { my $self = shift; my $logger = $self->{logger}; $logger->debug("please rename addStorages to addStorage()"); $self->addStorage(@_); } sub addMemory { my ($self, $args) = @_; my $xmltags = $self->{xmltags}; my $content = {}; foreach my $key (qw/CAPACITY CAPTION DESCRIPTION ERRORCORRECTIONTYPE MANUFACTURER NUMSLOTS SERIALNUMBER SPEED TYPE/) { if (exists $args->{$key}) { $content->{$key}[0] = $args->{$key} if $args->{$key}; } } push @{$xmltags->{MEMORIES}}, $content; } # For compatibility sub addMemories { my $self = shift; my $logger = $self->{logger}; $logger->debug("please rename addMemories to addMemory()"); $self->addMemory(@_); } sub addPorts{ my ($self, $args) = @_; my $xmltags = $self->{xmltags}; my $content = {}; foreach my $key (qw/CAPTION DESCRIPTION NAME TYPE/) { if (exists $args->{$key}) { $content->{$key}[0] = $args->{$key} if $args->{$key}; } } push @{$xmltags->{PORTS}}, $content; } # For compatibility sub addPort { my $self = shift; my $logger = $self->{logger}; $logger->debug("please rename addPorts to addPort()"); $self->addPort(@_); } sub addSlot { my ($self, $args) = @_; my $xmltags = $self->{xmltags}; my $content = {}; foreach my $key (qw/DESCRIPTION DESIGNATION NAME STATUS/) { if (exists $args->{$key}) { $content->{$key}[0] = $args->{$key} if $args->{$key}; } } push @{$xmltags->{SLOTS}}, $content; } # For compatibility sub addSlots { my $self = shift; my $logger = $self->{logger}; $logger->debug("please rename addSlots to addSlot()"); $self->addSlot(@_); } sub addSoftware { my ($self, $args) = @_; my $xmltags = $self->{xmltags}; my $content = {}; foreach my $key (qw/STATUS ARCHITECTURE COMMENTS FILESIZE FOLDER FROM INSTALLDATE NAME PUBLISHER VERSION/) { if (exists $args->{$key}) { $content->{$key}[0] = $args->{$key} if $args->{$key}; } } push @{$xmltags->{SOFTWARES}}, $content; } # For compatibility sub addSoftwares { my $self = shift; my $logger = $self->{logger}; $logger->debug("please rename addSoftwares to addSoftware()"); $self->addSoftware(@_); } sub addMonitor { my ($self, $args) = @_; my $xmltags = $self->{xmltags}; my $content = {}; foreach my $key (qw/BASE64 CAPTION DESCRIPTION MANUFACTURER SERIAL UUENCODE/) { if (exists $args->{$key}) { $content->{$key}[0] = $args->{$key} if $args->{$key}; } } push @{$xmltags->{MONITORS}}, $content; } # For compatibility sub addMonitors { my $self = shift; my $logger = $self->{logger}; $logger->debug("please rename addMonitors to addMonitor()"); $self->addMonitor(@_); } sub addVideo { my ($self, $args) = @_; my $xmltags = $self->{xmltags}; my $content = {}; foreach my $key (qw/CHIPSET DRVVERSION MEMORY NAME PCISLOT PCIID RESOLUTION SPEED UUID VBIOS/) { if (exists $args->{$key}) { $content->{$key}[0] = $args->{$key} if $args->{$key}; } } push @{$xmltags->{VIDEOS}}, $content; } # For compatibility sub addVideos { my $self = shift; my $logger = $self->{logger}; $logger->debug("please rename addVideos to addVideo()"); $self->addVideo(@_); } sub addSound { my ($self, $args) = @_; my $xmltags = $self->{xmltags}; my $content = {}; foreach my $key (qw/DESCRIPTION MANUFACTURER NAME/) { if (exists $args->{$key}) { $content->{$key}[0] = $args->{$key} if $args->{$key}; } } push @{$xmltags->{SOUNDS}}, $content; } # For compatibility sub addSounds { my $self = shift; my $logger = $self->{logger}; $logger->debug("please rename addSounds to addSound()"); $self->addSound(@_); } sub addNetwork { my ($self, $args) = @_; my $xmltags = $self->{xmltags}; my $content = {}; foreach my $key (qw/BASE BSSID DESCRIPTION DRIVER DUPLEX IPADDRESS IPDHCP IPGATEWAY IPMASK IPSUBNET MACADDR MODE MTU PCISLOT SLAVE SPEED SSID STATUS TYPE VERSION VIRTUALDEV /) { if (exists $args->{$key}) { $content->{$key}[0] = $args->{$key} if $args->{$key}; } } push @{$xmltags->{NETWORKS}}, $content; } # For compatibility sub addNetworks { my $self = shift; my $logger = $self->{logger}; $logger->debug("please rename addNetworks to addNetwork()"); $self->addNetwork(@_); } sub addRepo { my ($self, $args) = @_; my $xmltags = $self->{xmltags}; my $content = {}; foreach my $key (qw/BASEURL ENABLED EXCLUDE EXPIRE EXPIRED FILENAME LASTUPDATED MIRRORS NAME PKGS REVISION SIZE UPDATED/) { if (exists $args->{$key}) { $content->{$key}[0] = $args->{$key} if $args->{$key}; } } push @{$xmltags->{REPOSITORY}}, $content; } # For compatibility sub addRepos { my $self = shift; my $logger = $self->{logger}; $logger->debug("please rename addRepos to addRepo()"); $self->addRepo(@_); } sub setHardware { my ($self, $args, $nonDeprecated) = @_; my $xmltags = $self->{xmltags}; my $logger = $self->{logger}; foreach my $key (qw/USERID OSVERSION PROCESSORN OSCOMMENTS CHECKSUM PROCESSORT NAME PROCESSORS SWAP ETIME TYPE OSNAME IPADDR WORKGROUP DESCRIPTION MEMORY UUID DNS LASTLOGGEDUSER DATELASTLOGGEDUSER DEFAULTGATEWAY VMSYSTEM/) { if (exists $args->{$key}) { if ($key eq 'PROCESSORS' && !$nonDeprecated) { $logger->debug("PROCESSORN, PROCESSORS and PROCESSORT shouldn't be set directly anymore. Please use addCPU() method instead."); } if ($key eq 'USERID' && !$nonDeprecated) { $logger->debug("USERID shouldn't be set directly anymore. Please use addUser() method instead."); } $xmltags->{'HARDWARE'}{$key}[0] = $args->{$key}; } } } sub setBios { my ($self, $args) = @_; my $xmltags = $self->{xmltags}; foreach my $key (qw/SMODEL SMANUFACTURER SSN BDATE BVERSION BMANUFACTURER MMANUFACTURER MSN MMODEL ASSETTAG TYPE/) { if (exists $args->{$key}) { $xmltags->{'BIOS'}{$key}[0] = $args->{$key}; } } } sub addCPU { my ($self, $args) = @_; my $xmltags = $self->{xmltags}; my $content = {}; foreach my $key (qw/CORES CPUARCH CPUSTATUS CURRENT_SPEED DATA_WIDTH HPT L2CACHESIZE LOGICAL_CPUS MANUFACTURER NBSOCKET SERIALNUMBER SOCKET SPEED THREADS TYPE VOLTAGE LOGICAL_CPUS/) { if (exists $args->{$key}) { $content->{$key}[0] = $args->{$key} if $args->{$key}; } } push @{$xmltags->{CPUS}}, $content; # For the compatibility with HARDWARE/PROCESSOR* my $processorn = int @{$xmltags->{CPUS}}; my $processors = $xmltags->{CPUS}[0]{SPEED}[0]; my $processort = $xmltags->{CPUS}[0]{TYPE}[0]; $self->setHardware ({ PROCESSORN => $processorn, PROCESSORS => $processors, PROCESSORT => $processort, }, 1); } sub addUser { my ($self, $args) = @_; my $xmltags = $self->{xmltags}; my $login = $args->{LOGIN}; return unless $login; # Is the login, already in the XML ? foreach my $user (@{$xmltags->{USERS}}) { return if $user->{LOGIN}[0] eq $login; } push @{$xmltags->{USERS}}, { LOGIN => [$login] }; my $userString = $xmltags->{HARDWARE}->{USERID}[0] || ""; $userString .= '/' if $userString; $userString .= $login; $self->setHardware ({ USERID => $userString, }, 1); } sub addLocalUser { my ($self, $args) = @_; my $xmltags = $self->{xmltags}; my $content = {}; foreach my $key (qw/GID HOME ID LOGIN NAME SHELL/) { if (exists $args->{$key}) { $content->{$key}[0] = $args->{$key} if $args->{$key}; } } push @{$xmltags->{LOCAL_USERS}}, $content; } sub addLocalGroup { my ($self, $args) = @_; my $xmltags = $self->{xmltags}; my $content = {}; foreach my $key (qw/ID MEMBER NAME/) { if (exists $args->{$key}) { $content->{$key}[0] = $args->{$key} if $args->{$key}; } } push @{$xmltags->{LOCAL_GROUPS}}, $content; } sub addPrinter { my ($self, $args) = @_; my $xmltags = $self->{xmltags}; my $content = {}; foreach my $key (qw/DESCRIPTION DRIVER NAME PORT/) { if (exists $args->{$key}) { $content->{$key}[0] = $args->{$key} if $args->{$key}; } } push @{$xmltags->{PRINTERS}}, $content; } # For compatibility sub addPrinters { my $self = shift; my $logger = $self->{logger}; $logger->debug("please rename addPrinters to addPrinter()"); $self->addPrinter(@_); } sub addBatteries { my ($self, $args) = @_; my $xmltags = $self->{xmltags}; my $content = {}; foreach my $key (qw/CHEMISTRY DESIGNCAPACITY DESIGNVOLTAGE LOCATION MANUFACTURER MANUFACTUREDATE MAXERROR NAME OEMSPECIFIC SBDSVERSION SERIALNUMBER /) { if (exists $args->{$key}) { $content->{$key}[0] = $args->{$key} if $args->{$key}; } } push @{$xmltags->{BATTERIES}}, $content; } sub addVirtualMachine { my ($self, $args) = @_; my $xmltags = $self->{xmltags}; my $content = {}; foreach my $key (qw/CORES IPADDR MEMORY NAME UUID STATUS SUBSYSTEM VMTYPE VCPU VMID/) { if (exists $args->{$key}) { $content->{$key}[0] = $args->{$key} if $args->{$key}; } } push @{$xmltags->{VIRTUALMACHINES}}, $content; } sub addProcess { my ($self, $args) = @_; my $xmltags = $self->{xmltags}; my $content = {}; foreach my $key (qw/COMMANDLINE CPUUSAGE PROCESSMEMORY PROCESSID STARTED TTY USERNAME VIRTUALMEMORY/) { if (exists $args->{$key}) { $content->{$key}[0] = $args->{$key} if $args->{$key}; } } push @{$xmltags->{RUNNING_PROCESSES}}, $content; } sub addCamera { my ($self, $args) = @_; my $xmltags = $self->{xmltags}; my $content = {}; foreach my $key (qw/MODEL UUID/){ if (exists $args->{$key}) { $content->{$key}[0] = $args->{$key} if $args->{$key}; } } push @{$xmltags->{RUNNING_PROCESSES}}, $content; } sub addPSU { my ($self, $args) = @_; my $xmltags = $self->{xmltags}; my $content = {}; foreach my $key (qw/HOTREPLACEABLE LOCATION MANUFACTURER NAME PARTNUMBER PLUGGED POWERMAX SERIALNUMBER STATUS/){ if (exists $args->{$key}) { $content->{$key}[0] = $args->{$key} if $args->{$key}; } } push @{$xmltags->{POWERSUPPLIES}}, $content; } sub addIpDiscoverEntry { my ($self, $args) = @_; my $xmltags = $self->{xmltags}; my $ipaddress = $args->{IPADDRESS}; my $macaddr = $args->{MACADDR}; my $name = $args->{NAME}; if (!$xmltags->{IPDISCOVER}{H}) { $xmltags->{IPDISCOVER}{H} = []; } push @{$xmltags->{IPDISCOVER}{H}}, { # If I or M is undef, the server will ignore the host I => [$ipaddress?$ipaddress:""], M => [$macaddr?$macaddr:""], N => [$name?$name:"-"], # '-' is the default value returned by ipdiscover }; } sub setAccessLog { my ($self, $args) = @_; foreach my $key (qw/USERID LOGDATE/) { if (exists $args->{$key}) { $self->{xmlroot}{'CONTENT'}{'ACCESSLOG'}{$key}[0] = $args->{$key}; } } } sub flushXMLTags { my $self= shift; $self->{xmltags} = {}; } ### SNMP specifics subroutines #### sub getSnmpTable { my ($self,$snmp_table,$baseoid,$snmp_infos) = @_; # $snmp_infos is a hash passed for the SNMP information we want to get # It has to be created like this : # my $hash = { # INFORMATION => OID, #}; my $results={}; #The final hash which will contain one key per SNMP reference for my $oid ( keys %$snmp_table ) { if ( $oid =~ /$baseoid\.\d+\.\d+\.(\S+)/ ) { my $reference=$1; #Getting the last digits of the OID separated by a dot # Getting information if one the values from $snmp_infos hash is found for the current OID for my $value (keys %$snmp_infos) { if ($oid =~ /$snmp_infos->{$value}\.$reference/) { $results->{$reference}->{$value}= $snmp_table->{$oid} } } } } return $results; } sub setSnmpCommons { my ($self,$args) = @_; my $xmltags = $self->{xmltags}; foreach my $key (qw/IPADDR MACADDR SNMPDEVICEID NAME DESCRIPTION CONTACT LOCATION UPTIME DOMAIN TYPE / ) { if (exists $args->{$key}) { $xmltags->{COMMON}[0]{$key}[0] = $args->{$key}; } } } sub setSnmpPrinter { my ($self,$args) = @_; my $xmltags = $self->{xmltags}; foreach my $key (qw/NAME SERIALNUMBER COUNTER STATUS ERRORSTATE/ ) { if (exists $args->{$key}) { $xmltags->{PRINTERS}[0]{$key}[0] = $args->{$key}; } } } sub setSnmpSwitchInfos { my ($self,$args) = @_; my $xmltags = $self->{xmltags}; foreach my $key (qw/TYPE/) { if (exists $args->{$key}) { $xmltags->{SWITCHINFOS}[0]{$key}[0] = $args->{$key}; } } } sub setSnmpFirewalls { my ($self,$args) = @_; my $xmltags = $self->{xmltags}; foreach my $key (qw/SERIALNUMBER SYSTEM/) { if (exists $args->{$key}) { $xmltags->{FIREWALLS}[0]{$key}[0] = $args->{$key}; } } } sub setSnmpLoadBalancer { my ($self,$args) = @_; my $xmltags=$self->{xmltags}; foreach my $key (qw/SERIALNUMBER SYSTEM MANUFACTURER TYPE/ ) { if (exists $args->{$key}) { $xmltags->{LOADBALANCERS}[0]{$key}[0] = $args->{$key}; } } } sub setSnmpBlade { my ($self,$args) = @_; my $xmltags = $self->{xmltags}; foreach my $key (qw/SERIALNUMBER SYSTEM/) { if (exists $args->{$key}) { $xmltags->{BLADES}[0]{$key}[0] = $args->{$key}; } } } sub setSnmpComputer { my ($self,$args) = @_; my $xmltags = $self->{xmltags}; foreach my $key (qw/SYSTEM/) { if (exists $args->{$key}) { $xmltags->{COMPUTERS}[0]{$key}[0] = $args->{$key}; } } } sub addSnmpPrinterCartridge { my ($self,$args) = @_; my $xmltags = $self->{xmltags}; my $content = {}; foreach my $key (qw/DESCRIPTION TYPE LEVEL MAXCAPACITY COLOR/) { if (exists $args->{$key}) { $content->{$key}[0] = $args->{$key}; } } push @{$xmltags->{CARTRIDGES}},$content; } sub addSnmpPrinterTray { my ($self,$args) = @_; my $xmltags = $self->{xmltags}; my $content = {}; foreach my $key (qw/NAME DESCRIPTION LEVEL MAXCAPACITY/) { if (exists $args->{$key}) { $content->{$key}[0] = $args->{$key}; } } push @{$xmltags->{TRAYS}},$content; } sub addSnmpNetwork { my ($self,$args) = @_; my $xmltags = $self->{xmltags}; my $content = {}; foreach my $key (qw/DESCRIPTION MACADDR DEVICEMACADDR SLOT STATUS SPEED TYPE DEVICEADDRESS DEVICENAME DEVICEPORT DEVICETYPE TYPEMIB IPADDR IPMASK IPGATEWAY IPSUBNET IPDHCP DRIVER VIRTUALDEV/) { if (exists $args->{$key}) { $content->{$key}[0] = $args->{$key}; } } push @{$xmltags->{NETWORKS}},$content; } sub addSnmpBackPlane { my ($self,$args) = @_; my $xmltags = $self->{xmltags}; my $content = {}; foreach my $key (qw/DESCRIPTION FIRMWARE MANUFACTURER REFERENCE SERIALNUMBER TYPE/) { if (exists $args->{$key}) { $content->{$key}[0] = $args->{$key}; } } push @{$xmltags->{BACKPLANE}},$content; } sub addSnmpCard { my ($self,$args) = @_; my $xmltags = $self->{xmltags}; my $content = {}; foreach my $key (qw/DESCRIPTION REFERENCE FIRMWARE SOFTWARE REVISION SERIALNUMBER MANUFACTURER TYPE/) { if (exists $args->{$key}) { $content->{$key}[0] = $args->{$key}; } } push @{$xmltags->{CARDS}},$content; } sub addSnmpFan { my ($self,$args) = @_; my $xmltags = $self->{xmltags}; my $content = {}; foreach my $key (qw/DESCRIPTION REFERENCE REVISION SERIALNUMBER MANUFACTURER TYPE/) { if (exists $args->{$key}) { $content->{$key}[0] = $args->{$key}; } } push @{$xmltags->{FANS}},$content; } sub addSnmpPowerSupply { my ($self,$args) = @_; my $xmltags = $self->{xmltags}; my $content = {}; foreach my $key (qw/MANUFACTURER REFERENCE TYPE SERIALNUMBER DESCRIPTION REVISION/ ) { if (exists $args->{$key}) { $content->{$key}[0]=$args->{$key}; } } push @{$xmltags->{POWERSUPPLIES}},$content; } sub addSnmpSwitch { my ($self,$args) = @_; my $xmltags = $self->{xmltags}; my $content = {}; foreach my $key (qw/MANUFACTURER REFERENCE TYPE SOFTVERSION FIRMVERSION SERIALNUMBER REVISION DESCRIPTION/) { if (exists $args->{$key}) { $content->{$key}[0]=$args->{$key}; } } push @{$xmltags->{SWITCHS}},$content; } sub addSnmpLocalPrinter { my ($self,$args) = @_; my $xmltags = $self->{xmltags}; my $content = {}; foreach my $key (qw/NAME/) { if (exists $args->{$key}) { $content->{$key}[0] = $args->{$key}; } } push @{$xmltags->{LOCALPRINTERS}},$content; } sub addSnmpInput { my ($self,$args) = @_; my $xmltags = $self->{xmltags}; my $content = {}; foreach my $key (qw/DESCRIPTION TYPE/) { if (exists $args->{$key}) { $content->{$key}[0] = $args->{$key}; } } push @{$xmltags->{INPUTS}},$content; } sub addSnmpCPU { my ($self,$args) = @_; my $xmltags = $self->{xmltags}; my $content = {}; foreach my $key (qw/MANUFACTURER TYPE SPEED/) { if (exists $args->{$key}) { $content->{$key}[0] = $args->{$key}; } } push @{$xmltags->{CPUS}},$content; } #Subroutine to add 0 in 'Sun like' MAC address if needed sub padSnmpMacAddress { my ($self,$mac) = @_; my @splitedAddr = split(':', $mac); for (@splitedAddr) { unless ($_ =~ /\w{2}/) { $_ = sprintf("%02s", $_); } } $mac=join (':', @splitedAddr); return $mac; } sub cleanXml { my ($self,$content) = @_; my $logger = $self->{logger}; my $clean_content = encode('UTF-8', $content, Encode::FB_DEFAULT | Encode::LEAVE_SRC | Encode::FB_XMLCREF); $logger->debug("cleanXml changed content") if ($content ne $clean_content); return $clean_content."\n"; } #Subroutine to read XML structure (returned by XML::Simple::XMLin) and encode content in utf8. sub readXml { my ($self, $xml, $forcearray) = @_; my $logger = $self->{logger}; my $content = XML::Simple::XMLin($xml, ForceArray => [@{$forcearray}]); foreach my $key (keys %$content) { if (grep(/^$key$/, @{$forcearray})) { #Forced array in XML parsing $self->parseXmlArray($content->{$key},$forcearray); } else { #Not a forced array in XML parsing if (ref ($content->{$key}) =~ /^HASH$/ && !keys %{$content->{$key}}) { # If empty hash from XMLin() $content->{$key} = ''; } else { encode('UTF-8', $content->{$key}, Encode::FB_DEFAULT) }; } } return $content; } #Subroutine to parse array in XML structure (returned by XML::Simple::XMLin) and encode it in utf8 sub parseXmlArray { my ($self,$array,$forcearray) = @_; foreach my $hash (@{$array}) { foreach my $key (keys %$hash) { if ( grep (/^$key$/,@$forcearray)) { #Forced array in XML parsing $self->parseXmlArray($hash->{$key},$forcearray); } else { #Not a forced array in XML parsing if (ref ($hash->{$key}) =~ /^HASH$/ && !keys %{$hash->{$key}}) { # If empty hash from XMLin() $hash->{$key} = ''; } else { encode('UTF-8', $hash->{$key}, Encode::FB_DEFAULT) }; } } } } #Subroutine to convert versions to numbers (with icutting or right padding if needed) # We create it because Perl 5.8 does not include version comparison modules or functions sub convertVersion { my ($self,$version,$length) = @_; $version =~ s/\.//g; #We convert to number my $ver_length = length ($version); if ($ver_length > $length) { # We cut the number $version = substr $version, 0, $length; } elsif ($ver_length < $length) { #We add 0 to the right $version = substr($version . (0 x $length), 0, $length); } return $version; } #We create this subroutine because MacOSX system_profiler XML output does not give all ##the neeeded data (for videos and sounds for example) sub get_sysprofile_devices_names { my ($self,$type) = @_; return(undef) unless -r '/usr/sbin/system_profiler'; my $output=`system_profiler $type`; my $name; my $names=[]; # Code inspired from Mac::Sysprofile 0.03 from Daniel Muey for(split /\n/, $output) { next if m/^\s*$/ || m/^\w/; if(m/^\s{4}\w/) { $name = $_; $name =~ s/^\s+//; $name =~ s/:.*$//; push(@$names,$name); } } return $names; } # Function getDmidecodeInfos. # sub getDmidecodeInfos { my @dmidecode=`dmidecode`; my ($info, $block, $type); foreach my $line (@dmidecode){ chomp $line; if ($line =~ /DMI type (\d+)/) { if ($block) { push (@{$info->{$type}}, $block); undef $block; } $type=$1; next; } next unless defined $type; next unless $line =~ /^\s+ ([^:]+) : \s (.*\S)/x; next if $2 eq 'N/A' || $2 eq 'Not Specified' || $2 eq 'Not Present' || $2 eq 'Unknown' || $2 eq '' || $2 eq '' || $2 eq ''; $block->{$1} = $2; } if ($block) { push(@{$info->{$type}}, $block); } return if keys %{$info} < 2; return $info; } ### Generic shared subroutines ##### sub can_run { my $self = shift; my $binary = shift; my $logger = $self->{logger}; my $calling_namespace = caller(0); chomp(my $binpath=`which $binary 2>/dev/null`); return unless -x $binpath; $self->{logger}->debug(" - $binary found"); 1; } sub can_load { my $self = shift; my $module = shift; my $logger = $self->{logger}; my $calling_namespace = caller(0); eval "package $calling_namespace; use $module;"; return if $@; $self->{logger}->debug(" - $module loaded"); 1; } sub can_read { my $self = shift; my $file = shift; my $logger = $self->{logger}; return unless -r $file; $self->{logger}->debug(" - $file can be read"); 1; } sub runcmd { my $self = shift; my $cmd = shift; my $logger = $self->{logger}; return unless $cmd; # $self->{logger}->debug(" - run $cmd"); return `$cmd`; } #### Old subroutines from the former Common.pm used by Download.pm ####### sub get_path{ my $self = shift; my $binary = shift; my $path; my @bin_directories = qw { /usr/local/sbin/ /sbin/ /usr/sbin/ /bin/ /usr/bin/ /usr/local/bin/ /etc/ocsinventory-client/}; print "\n=> retrieving $binary...\n" if $::debug; for (@bin_directories){ $path = $_.$binary,last if -x $_.$binary; } # For debbuging purposes if ($path){ print "=> $binary is at $path\n\n" if $::debug; } else { print "$binary not found (Maybe it is not installed ?) - Some functionnalities may lack !!\n\n"; } return $path; } sub already_in_array { my $self = shift; my $lookfor = shift; my @array = @_; foreach (@array){ if ($lookfor eq $_){ return 1 ; } } return 0; } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Config.pm000066400000000000000000000171561372663377700213750ustar00rootroot00000000000000package Ocsinventory::Agent::Config; use strict; use Getopt::Long; our $VERSION = '2.8.0'; my $basedir = ''; my $default = { 'daemon' => 0, 'debug' => 0, 'devlib' => 0, 'force' => 0, 'help' => 0, 'info' => 1, 'lazy' => 0, 'local' => '', # 'logger' => 'Syslog,File,Stderr', 'logger' => 'Stderr', 'logfacility' => 'LOG_USER', 'logfile' => '', 'password' => '', 'proxy' => '', 'realm' => '', 'remotedir' => '/ocsinventory', # deprecated, give a complete URL to # --server instead 'server' => 'http://ocsinventory-ng/ocsinventory', 'stdout' => 0, 'tag' => '', 'user' => '', 'version' => 0, 'wait' => '', # 'xml' => 0, 'nosoftware'=> 0, 'delaytime' => '3600', # max delay time (seconds) 'backendCollectTimeout' => '600', # timeOut of process : see Backend.pm 'scanhomedirs' => 0, 'ssl' => 1, 'ca' => '', 'snmp' => 0, # Other values that can't be changed with the # CLI parameters 'VERSION' => $VERSION, 'deviceid' => '', 'basevardir'=> $basedir.'/var/lib/ocsinventory-agent', 'logdir' => $basedir.'/var/log/ocsinventory-agent', # 'pidfile' => $basedir.'/var/run/ocsinventory-agent.pid', }; sub new { my (undef, $params) = @_; my $self = {}; bless $self; $self->{file} = $params->{file}; $self->{config} = $default; $self->loadFromCfgFile(); return $self; } sub loadFromCfgFile { my $self = shift; my $config; $self->{config}{etcdir} = []; push (@{$self->{config}{etcdir}}, '/etc/ocsinventory'); push (@{$self->{config}{etcdir}}, '/usr/local/etc/ocsinventory'); push (@{$self->{config}{etcdir}}, '/etc/ocsinventory-agent'); push (@{$self->{config}{etcdir}}, $ENV{HOME}.'/.ocsinventory'); # Should I? my $file; if (!$file || !-f $file) { foreach (@{$self->{config}{etcdir}}) { $file = $_.'/ocsinventory-agent.cfg'; last if -f $file; } return $config unless -f $file; } $self->{configfile} = $file; if (!open (CONFIG, "<".$file)) { print(STDERR "Config: Failed to open $file\n"); return $config; } foreach () { s/^#.+//; if (/(\w+)\s*=\s*(.+)/) { my $key = $1; my $val = $2; # Remove the quotes $val =~ s/\s+$//; $val =~ s/^'(.*)'$/$1/; $val =~ s/^"(.*)"$/$1/; $self->{config}{$key} = $val; } } close CONFIG; } sub loadUserParams { my $self = shift; my %options = ( "backend-collect-timeout=s" => \$self->{config}{backendCollectTimeout}, "basevardir=s" => \$self->{config}{basevardir}, "d|daemon" => \$self->{config}{daemon}, "debug" => \$self->{config}{debug}, "devlib" => \$self->{config}{devlib}, "f|force" => \$self->{config}{force}, "h|help" => \$self->{config}{help}, "i|info" => \$self->{config}{info}, "lazy" => \$self->{config}{lazy}, "l|local=s" => \$self->{config}{local}, "logfile=s" => \$self->{config}{logfile}, "nosoftware" => \$self->{config}{nosoftware}, "p|password=s" => \$self->{config}{password}, "P|proxy=s" => \$self->{config}{proxy}, "r|realm=s" => \$self->{config}{realm}, "R|remotedir=s" => \$self->{config}{remotedir}, "s|server=s" => \$self->{config}{server}, "stdout" => \$self->{config}{stdout}, "t|tag=s" => \$self->{config}{tag}, "u|user=s" => \$self->{config}{user}, "version" => \$self->{config}{version}, "w|wait=s" => \$self->{config}{wait}, # "x|xml" => \$self->{config}{xml}, "delaytime" => \$self->{config}{delaytime}, "scan-homedirs" => \$self->{config}{scanhomedirs}, "nolocal" => \$self->{config}{nolocal}, "ssl=s" => \$self->{config}{ssl}, "ca=s" => \$self->{config}{ca}, "snmp=s" => \$self->{config}{snmp}, ); $self->help() if (!GetOptions(%options) || $self->{config}{help}); $self->version() if $self->{config}{version}; } sub help { my ($self, $error) = @_; if ($error) { chomp $error; print "ERROR: $error\n\n"; } if ($self->{configfile}) { print STDERR "Setting initialised with values retrieved from ". "the config found at ".$self->{configfile}."\n"; } print STDERR "\n"; print STDERR "Usage:\n"; print STDERR "\t--backend-collect-timeout set a max delay time of one action (search package id, ...) is set (".$self->{config}{backendCollectTimeout}.")\n"; print STDERR "\t--basevardir=/path indicate the directory where should the agent store its files (".$self->{config}{basevardir}.")\n"; print STDERR "\t-d --daemon detach the agent in background (".$self->{config}{daemon}.")\n"; print STDERR "\t --debug debug mode (".$self->{config}{debug}.")\n"; print STDERR "\t --devlib search for Backend mod in ./lib only (".$self->{config}{devlib}.")\n"; print STDERR "\t-f --force always send data to server (Don't ask before) (".$self->{config}{force}.")\n"; print STDERR "\t-i --info verbose mode (".$self->{config}{info}.")\n"; print STDERR "\t--lazy do not contact the server more than one time during the PROLOG_FREQ (".$self->{config}{lazy}.")\n"; print STDERR "\t-l --local=DIR do not contact server but write inventory in DIR directory in XML (".$self->{config}{local}.")\n"; print STDERR "\t --logfile=FILE log message in FILE (".$self->{config}{logfile}.")\n"; print STDERR "\t-p --password=PWD password for server auth\n"; print STDERR "\t-P --proxy=PROXY proxy address. e.g: http://user:pass\@proxy:port (".$self->{config}{proxy}.")\n"; print STDERR "\t-r --realm=REALM realm for server auth. e.g: 'Restricted Area' (".$self->{config}{realm}.")\n"; print STDERR "\t-s --server=uri server uri (".$self->{config}{server}.")\n"; print STDERR "\t --stdout do not write or post the inventory but print it on STDOUT\n"; print STDERR "\t-t --tag=TAG use TAG as tag (".$self->{config}{tag}."). Will be ignored by server if a value already exists.\n"; print STDERR "\t-u --user=USER user for server auth (".$self->{config}{user}.")\n"; print STDERR "\t --version print the version\n"; print STDERR "\t-w --wait=seconds wait a random period before contacting server like --daemon does (".$self->{config}{wait}.")\n"; # print STDERR "\t-x --xml write output in a xml file ($self->{config}{xml})\n"; print STDERR "\t--nosoftware do not return installed software list (".$self->{config}{nosoftware}.")\n"; print STDERR "\t--delaytime set a max delay time (in second) if no PROLOG_FREQ is set (".$self->{config}{delaytime}.")\n"; print STDERR "\t--scan-homedirs permit to scan home user directories (".$self->{config}{scanhomedirs}.")\n" ; print STDERR "\t--ssl=0|1 disable or enable SSL communications check\n" ; print STDERR "\t--ca=FILE path to CA certificates file in PEM format\n" ; print STDERR "\n"; print STDERR "Manpage:\n"; print STDERR "\tSee man ocsinventory-agent\n"; print STDERR "\n"; print STDERR "Ocsinventory-Agent is released under GNU GPL 2 license\n"; exit 1; } sub version { print "Ocsinventory unified agent for UNIX, Linux and MacOSX (".$VERSION.")\n"; exit 0; } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Encrypt.pm000066400000000000000000000002271372663377700216030ustar00rootroot00000000000000package Ocsinventory::Agent::Encrypt; use MIME::Base64; sub getClearText { my ($encodedpass) = @_; return decode_base64($encodedpass); } 1;UnixAgent-2.8/lib/Ocsinventory/Agent/Hooks.pm000066400000000000000000000060251372663377700212440ustar00rootroot00000000000000package Ocsinventory::Agent::Hooks; # This package give possibility to use hooks in unified unix agent. use strict; use warnings; #use FindBin qw($Bin); sub new { my (undef, $context) = @_; my $self = {}; $self->{accountinfo} = $context->{accountinfo}; $self->{accountconfig} = $context->{accountconfig}; my $logger = $self->{logger}=$context->{logger}; $self->{config} = $context->{config}; $self->{dontuse} = 1; my $modulefile; foreach (@{$self->{config}->{etcdir}}) { $modulefile = $_.'/modules.conf'; if (-f $modulefile) { if (do $modulefile) { $logger->debug("Turns hooks on for $modulefile"); $self->{dontuse} = 0; last; } else { $logger->debug("Failed to load `$modulefile': $?"); } } } if ($self->{dontuse}) { $logger->debug("No modules will be used."); } else { my $ocsAgentServerUri; # to avoid a warning if $self->{config}->{server} is not defined if ($self->{config}->{server}) { $ocsAgentServerUri = "http://".$self->{config}->{server}.$self->{config}->{remotedir}; } if ($self->{config}->{debug}) { $::debug = 2; } } # Create objects for modules foreach my $package (searchModules(\%Ocsinventory::Agent::Modules::)){ my $module = new $package($context); my $name = $module->{structure}->{name}; # Store the reference in a key to access modules easily $self->{modules}->{$name}=$module; } bless $self; } # This function recursively searches for modules in a given namespace # Param: a hash reference to the namespace # Returns: an array with modules fully qualified names sub searchModules { my $symbols_href = shift; my @modules_list = (); my %symbols_h = %{$symbols_href}; my @symbols_a = sort(keys(%symbols_h)); foreach(@symbols_a){ if ($_ eq 'new'){ # Found a "new" method -> this is a usable module my $module_fqn = $symbols_h{$_}; # Keep the module fqn, without '*' at start $module_fqn =~ s/\*?(.+)::new$/$1/; push(@modules_list, $module_fqn); } elsif (substr($_, -2) eq '::') { # If we meet a package, continue walking push(@modules_list, searchModules($symbols_h{$_})); } } return @modules_list; } sub run { my ($self, $args, $moduleparam) = @_; return if $self->{dontuse}; my $name = $args->{name}; #type of hook asked my $logger = $self->{logger}; $logger->debug("Calling handlers : `$name'"); # Launching hook for modules if not 'undef' and if modules are not disabled by start_handler for (keys %{$self->{modules}}) { my $module = $self->{modules}->{$_}; unless ($module->{disabled}) { my $hook = $module->{structure}->{$name}; if ($hook) { $module->$hook($moduleparam); } } } } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Modules/000077500000000000000000000000001372663377700212305ustar00rootroot00000000000000UnixAgent-2.8/lib/Ocsinventory/Agent/Modules/Apache/000077500000000000000000000000001372663377700224115ustar00rootroot00000000000000UnixAgent-2.8/lib/Ocsinventory/Agent/Modules/Apache/Vhosts/000077500000000000000000000000001372663377700236775ustar00rootroot00000000000000UnixAgent-2.8/lib/Ocsinventory/Agent/Modules/Apache/Vhosts/Common.pm000066400000000000000000000246101372663377700254700ustar00rootroot00000000000000############################################################################### # Apache::Vhosts::Common - Common stuff for apache vhosts inventory # # Author: Linkbynet ############################################################################### package Ocsinventory::Agent::Modules::Apache::Vhosts::Common; =head1 NAME Apache::Vhosts::Common - Lib for common operations in vhosts inventory =head1 DESCRIPTION This package is meant to contain common functions used by OCS modules for Apache virtualhosts. For example, we could have two OCS modules: =over =item ApacheVhostsPackaged which would deal with packaged apache setups =item ApacheVhostsCompiled which would deal with compiled apache versions =back At different times, these modules still would need to do the same things, such as parsing apache configuration files, reading and extracting information from a vhost dump, reading a x509 certificate with openssl, ... To avoid code duplication, the specific modules can call the functions contained in this common package. =head2 Exports The module exports the following functions: =over =item C =item C =back =cut use Exporter; our @ISA = qw(Exporter); our @EXPORT = qw(&readVhostsDump &readVhostConfFile); use strict; use warnings; #### BEGIN: Define regexes # Useful lines in vhosts dump (NameVirtualHosts and IP vhosts only) my $dumpline_name_re = qr/^port ([0-9]+) namevhost (\S+) \((\S+):([0-9]+)\)/; my $dumpline_ip_re = qr/^([0-9.]+):([0-9]+)\s+(\S+) \((\S+):([0-9]+)\)/; # "subject=" line of openssl x509 command output (used to extract CN) my $subject_cn_re = qr/^subject=.*\/CN=([^\s\/]+).*$/; # Simplistic email address pattern my $damn_simple_email_re = qr/.+\@.+\..+/; #### END: Define regexes =head2 readVhostsDump() Return an array of hashes with the virtualhosts found thanks to Apache's vhosts dump (C command). =head3 Return type The function returns a reference to an array of hashes. =head3 Process The function's workflow is as follows: =over =item 1 Open C command output, with the current configuration file =item 2 Read dump line by line to match IP-based or name-based virtualhost information (both types of lines should be recognized): port 80 namevhost mynamevhost.fr (/etc/httpd/.../10-mynamevhost.conf:50) 10.0.0.1:80 myvhost myipvhost.fr (/etc/httpd/.../20-myipvhost.conf:1) =item 3 Create a hash with the virtualhost's data We put the following attributes in it: (string) computedname, (int) port, (string) srvname, (string) vhostfile, (string) vhostline, (string) docroot, (bool) ssl At this stage we do not know docroot or ssl, so they are "/nonexistent" and false (0), respectively. =item 4 Push the vhost hash to the array. =back =head3 Return example [ { 'computedname' => "[httpd] myvhost.fr:80", 'port' => 80, 'srvname' => 'myvhost.fr', 'vhostfile' => '/etc/httpd/conf.d/10-myvhost.conf', 'vhostline' => 1, 'docroot' => '/nonexistent', 'ssl' => 0 }, { 'computedname' => "[httpd] myvhost.fr:443", 'port' => 443, 'srvname' => 'myvhost.fr', 'vhostfile' => '/etc/httpd/conf.d/10-myvhost.conf', 'vhostline' => 20, 'docroot' => '/nonexistent', 'ssl' => 0 } ] =head3 Calling my $vhosts = readVhostsDump($httpd_bin, $httpd_conf_file, $logger); =over =item Parameter: $httpd_bin (string) Path to the httpd binary to execute (for example: C). Specific options (such as C<-D> parameters) may be added to the string. =item Parameter: $httpd_conf_file (string) Path to the main httpd configuration file (for example: C). =item Parameter: $logger (reference to OCS logger instance) To make use of OCS logging capabilities within the function. =back =cut sub readVhostsDump { my ($httpd_bin, $httpd_conf_file, $logger) = @_; my @vhosts = (); # 2>&1 because some very old Apache versions write the vhosts dump # on stderr! open(my $DUMPFILE, "$httpd_bin -S -f $httpd_conf_file 2>&1 |") or die("Cannot open \$(httpd -S -f $httpd_conf_file) $!"); while (<$DUMPFILE>) { chomp; s/^\s+//; # lstrip my ($ip, $port, $srvname, $vhostfile, $vhostline); if ($_ =~ $dumpline_name_re) { ($port, $srvname, $vhostfile, $vhostline) = ($1, $2, $3, $4); } elsif ($_ =~ $dumpline_ip_re) { ($ip, $port, $srvname, $vhostfile, $vhostline) = ($1, $2, $3, $4, $5); } if (defined($port)) { # sufficient test to know if line was found my %vhost = ( 'computedname' => "$srvname:$port", 'port' => int($port), 'srvname' => $srvname, 'vhostfile' => $vhostfile, 'vhostline' => int($vhostline), 'docroot' => '/nonexistent', 'ssl' => 0 ); push(@vhosts, \%vhost); } } close($DUMPFILE); return \@vhosts; } =head2 readVhostConfFile() Enhance a virtualhost's information with elements found when parsing the vhost's configuration file. =head3 Return type The function returns nothing. It only operates on the (referenced) vhost hash it got in parameter. =head3 Process The function must read the apache configuration file in which the vhost gets defined ( block). The path to the particular configuration file and the line number of the vhost declaration are known in the C and C attributes, thanks to the vhost dump. The function's process, for the given vhost, is as follows: =over =item 1 Open the configuration file at C =item 2 Read line by line, waiting to be at correct line number (C) to start searching for information. =item 3 Search for the following information in the and enhance the given vhost hash with: =over =item * docroot (string) the value of the C directive =item * ssl (bool) we turn it to true if we find a C directive =item * sslcertpath (string) value of the C directive, if such a directive is present =back =item 4 File reading stops when we find the C<< >> closing block (in case multiple vhosts are declared in the same configuration file). =back =head3 Calling foreach my $vhost (@$vhosts) # Generally { readVhostConfFile($vhost, $httpd_basedir); } =over =item Parameter: $vhost (reference to hash) The virtualhost hash to enhance. =item Parameter: $httpd_basedir (string) The path to base directory of httpd, in case we encounter a relative path in C and need to complete it. B: the given path is expected to end with a slash '/', for example: "/etc/httpd/" =back =cut sub readVhostConfFile { my ($vhost, $relpath_prefix) = @_; my $nr = 0; open(my $VHOST_FILE, '<', $vhost->{'vhostfile'}) or die ("Cannot open $vhost->{'vhostfile'}"); while (my $vline = <$VHOST_FILE>) { # Waiting the correct line to start reading next if ++$nr < $vhost->{'vhostline'}; $vline =~ s/^\s+//; # lstrip # Get various vhost properties # -- DocumentRoot if ($vline =~ m/^DocumentRoot ["']?([^\s'"]+)["']?/i) { $vhost->{'docroot'} = $1; } # -- SSLEngine (bool) elsif ($vline =~ m/^SSLEngine on/i) { $vhost->{'ssl'} = 1; } # -- SSLCertificateFile path elsif ($vline =~ m/^SSLCertificateFile ["']?([^\s'"]+)["']?/i) { $vhost->{'sslcertpath'} = $1; readVhostSSLCert($vhost, $relpath_prefix); } # Stop reading on block closing tag last if $vline =~ m@^@i; } close($VHOST_FILE); } ############################################################################### # readVhostSSLCert() - read a vhost's SSL certificate to get its details # # Invoking: # readVhostSSLCert($vhost, $relpath_prefix) # # Params: # - $vhost - a reference to the vhost hash # - $relpath_prefix - the prefix to use in case the SSLCertificateFile path # is a relative one, in order to make it an absolute path # # Returns: # nothing. # # We read the certificate with an "openssl x509" command. # We try to retrieve the following fields: # # - "subject" (specifically to get the CN) # - "notBefore" and "notAfter" dates # - "email" (we catch the first email returned) # # The certificate details found here are gently stuffed in # $vhost->{'sslcertdetails'}, as follows: # # { # # (in a vhost here) # # [...] # 'srvname' => 'myvhost.fr', # 'ssl' => 1, # 'sslcertpath' => 'conf/ssl/myvhost.fr.crt', # 'sslcertdetails' => { # 'cn' => 'myvhost.fr', # 'startdate' => '31/12/2012', # 'enddate' => '31/12/2042', # 'email' => 'certadmin-email@example.com' # } # } sub readVhostSSLCert { my ($vhost, $relpath_prefix) = @_; $vhost->{'sslcertdetails'} = (); my $sslcertpath = $vhost->{'sslcertpath'}; my $absolute = (substr($sslcertpath, 0, 1) eq '/'); if (!$absolute) { $sslcertpath = "${relpath_prefix}${sslcertpath}"; } open(my $OPENSSL_CMD, "openssl x509 -in \"$sslcertpath\" -noout -subject -dates -email |"); while (my $oline = <$OPENSSL_CMD>) { if ($oline =~ $subject_cn_re) { $vhost->{'sslcertdetails'}->{'cn'} = $1; } elsif ($oline =~ m/^notBefore=(.+)$/) { $vhost->{'sslcertdetails'}->{'startdate'} = formatDate($1); } elsif ($oline =~ m/^notAfter=(.+)$/) { $vhost->{'sslcertdetails'}->{'enddate'} = formatDate($1); } elsif ($oline =~ $damn_simple_email_re) { chomp $oline; $vhost->{'sslcertdetails'}->{'email'} = $oline; # stop processing from the first email address # (it should be the last line of the command output) last; } } close($OPENSSL_CMD); } ############################################################################### # formatDate() - reformat date, with help of system command date(1) # # Invoking: # formatDate($date) # # Params: # - $date - the date string to reformat, in a format parsable by date(1) # # Returns: # the ISO 8601 (%Y-%m-%d) formatted date (string) # sub formatDate { my ($date) = @_; my $formattedDate = `date --date="$date" --iso-8601`; chomp $formattedDate; return $formattedDate; } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Modules/Apache/VhostsEL.pm000066400000000000000000000125741372663377700244670ustar00rootroot00000000000000################################################################################ ## Author: Linkbynet ## ## This code is open source and may be copied and modified as long as the source ## code is always made freely available. ## Please refer to the General Public Licence http://www.gnu.org/ or Licence.txt ## ## ############################################################################# ## ## This module retrieves information about Apache virtualhosts. ## ## It handles setups where Apache was installed by package (Enterprise Linux ## distributionsi family: RHEL, CentOS, Fedora) with configuration in standard ## dir /etc/httpd. ## ## Information gets written to tags at XPaths: ## ## /REQUEST/CONTENT/APACHE_VHOST ## /REQUEST/CONTENT/APACHE_VHOST_CERTIFICATE ## ## Example: ## ## ## ## /var/www/example.com ## example.com:443 ## example.com ## 443 ## ## ## ## example.com ## 30/06/2023 ## 01/07/2013 ## example.com:443 ## certmaster@example.com ## ## ## ################################################################################ package Ocsinventory::Agent::Modules::Apache::VhostsEL; use strict; use warnings; use Ocsinventory::Agent::Modules::Apache::Vhosts::Common; sub new { my $name = "apachevhosts_el"; # Set the name of your module here my (undef,$context) = @_; my $self = {}; # Create a special logger for the module $self->{logger} = new Ocsinventory::Logger ({ config => $context->{config} }); $self->{logger}->{header} = "[$name]"; $self->{context} = $context; $self->{structure} = { name => $name, start_handler => $name."_start_handler", # or undef if don't use this hook prolog_writer => undef, # or undef if don't use this hook prolog_reader => undef, # or undef if don't use this hook inventory_handler => $name."_inventory_handler", # or undef if don't use this hook end_handler => undef # or undef if don't use this hook }; # Path to httpd bin $self->{modinfos}->{httpd_bin} = '/usr/sbin/httpd'; # Path to httpd dir in /etc # (basis for relative paths or SSLCertificateFile, for example) $self->{modinfos}->{httpd_basedir} = '/etc/httpd/'; # Path to httpd conf dir $self->{modinfos}->{httpd_confdir} = '/etc/httpd/conf'; # Path to httpd main conf file $self->{modinfos}->{httpd_conf_file} = '/etc/httpd/conf/httpd.conf'; bless $self; } ######### Hook methods ############ sub apachevhosts_el_start_handler { # Use this hook to test prerequisites needed by module and disble it if needed my $self = shift; my $logger = $self->{logger}; my $prerequisites = 1; # TESTS: # # 1 - Apache HTTPD server is installed the packet way (conf dir present) # 2 - We can execute the httpd binary # 3 - We can read the main conf file (httpd.conf or equivalent) if (! -d $self->{modinfos}->{httpd_confdir}) { # No apache found on this server (or not in the expected place) $logger->debug("- no $self->{modinfos}->{httpd_confdir} directory found"); $prerequisites = 0; } elsif (! -x $self->{modinfos}->{httpd_bin}) { $logger->debug("- no executable $self->{modinfos}->{httpd_bin} found"); $prerequisites = 0; } elsif (! -f $self->{modinfos}->{httpd_conf_file}) { $logger->debug("- did not find $self->{modinfos}->{httpd_conf_file} file"); $prerequisites = 0; } if ($prerequisites == 0) { $self->{disabled} = 1; # Use this to disable the module $logger->debug("Humm my prerequisites are not OK...disabling module :( :( "); } } sub apachevhosts_el_inventory_handler { # Use this hook to add or modify entries in the inventory XML my $self = shift; my $logger = $self->{logger}; my $common = $self->{context}->{common}; $logger->debug(__PACKAGE__); # Reading httpd -S output my $vhosts = readVhostsDump($self->{modinfos}->{httpd_bin}, $self->{modinfos}->{httpd_conf_file}, $logger); # Enhancing information by parsing each vhost's configuration foreach my $vhost (@$vhosts) { readVhostConfFile($vhost, $self->{modinfos}->{httpd_basedir}); } # Write OCS XML foreach my $vhost (@$vhosts) { push @{$common->{'xmltags'}->{'APACHE_VHOST'}}, { "NAME" => [$vhost->{'computedname'}], "URL" => [$vhost->{'srvname'}], "DIRECTORY" => [$vhost->{'docroot'}], "PORT_NUMBER" => [$vhost->{'port'}] }; if ($vhost->{'ssl'}) { push @{$common->{'xmltags'}->{'APACHE_VHOST_CERTIFICATE'}}, { "SITE" => [$vhost->{'computedname'}], "DOMAINNAME" => [$vhost->{'sslcertdetails'}->{'cn'}], "REGISTRATIONDATE" => [$vhost->{'sslcertdetails'}->{'startdate'}], "EXPIRATIONDATE" => [$vhost->{'sslcertdetails'}->{'enddate'}], "EMAIL" => [$vhost->{'sslcertdetails'}->{'email'}] }; } } } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Modules/Databases/000077500000000000000000000000001372663377700231175ustar00rootroot00000000000000UnixAgent-2.8/lib/Ocsinventory/Agent/Modules/Databases/Oracle.pm000066400000000000000000000065711372663377700246730ustar00rootroot00000000000000################################################################################ ## Author: Linkbynet ## ## This code is open source and may be copied and modified as long as the source ## code is always made freely available. ## Please refer to the General Public Licence http://www.gnu.org/ or Licence.txt ## ## ############################################################################# ## ## This module finds and retrieves information about Oracle instances. ## ## First elements are taken from the /etc/oratab file. For each instance listed ## in it, we get the precise version number (with tnsping utility) and bundle ## name by reading the file below: ## ## $ORACLE_HOME/inventory/Components21/oracle.server/*/context.xml ## ## Information gets written to tags at XPaths: ## ## /REQUEST/CONTENT/ORACLE_INSTANCE ## ## Example: ## ## ## ## 0 ## Standard ## EXDB01 ## 11.2.0.4.0 ## ## ## ################################################################################ package Ocsinventory::Agent::Modules::Databases::Oracle; use strict; use warnings; use Ocsinventory::Agent::Modules::Databases::Oracle::Instances; sub new { my $name = "oracleinstances"; # Set the name of your module here my (undef,$context) = @_; my $self = {}; # Create a special logger for the module $self->{logger} = new Ocsinventory::Logger ({ config => $context->{config} }); $self->{logger}->{header} = "[$name]"; $self->{context} = $context; $self->{structure} = { name => $name, start_handler => $name."_start_handler", # or undef if don't use this hook prolog_writer => undef, # or undef if don't use this hook prolog_reader => undef, # or undef if don't use this hook inventory_handler => $name."_inventory_handler", # or undef if don't use this hook end_handler => undef # or undef if don't use this hook }; bless $self; } ######### Hook methods ############ sub oracleinstances_start_handler { # Use this hook to test prerequisites needed by module and disble it if needed my $self = shift; my $logger = $self->{logger}; my $prerequisites = 1; if (!(-f '/etc/oratab' && -r '/etc/oratab')) { $logger->debug("- no readable /etc/oratab file"); $prerequisites = 0; } if ($prerequisites == 0) { $self->{disabled} = 1; # Use this to disable the module $logger->debug("Humm my prerequisites are not OK...disabling module :( :( "); } } sub oracleinstances_inventory_handler { # Use this hook to add or modify entries in the inventory XML my $self = shift; my $logger = $self->{logger}; my $common = $self->{context}->{common}; $logger->debug(__PACKAGE__); my $database = getInstances(); # Write to OCS XML foreach my $instance (keys(%$database)) { push @{$common->{xmltags}->{ORACLE_INSTANCE}}, { 'NAME' => [$instance], 'AUTOSTART' => [$database->{$instance}->{'AUTOSTART'}], 'VERSION' => [$database->{$instance}->{'VERSION'}], 'BUNDLE' => [$database->{$instance}->{'BUNDLE'}] }; } } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Modules/Databases/Oracle/000077500000000000000000000000001372663377700243245ustar00rootroot00000000000000UnixAgent-2.8/lib/Ocsinventory/Agent/Modules/Databases/Oracle/Instances.pm000066400000000000000000000135341372663377700266170ustar00rootroot00000000000000################################################################################ # Oracle::Instances - Common stuff to get Oracle instances and versions # # Author: Linkbynet ################################################################################ package Ocsinventory::Agent::Modules::Databases::Oracle::Instances; =head1 NAME Oracle::Instances - Lib for Oracle instances and versions retrieval =head1 DESCRIPTION This module provides a function to retrieve information about Oracle instances on the current server. To do so, the function reads the /etc/oratab file to find instances and then: =over =item 1 Checks the existence of the ORACLE_HOME directory. =item 2 Add (ORACLE_SID, ORACLE_HOME, AUTOSTART) to the databases hash. =item 3 Go and find server version and bundle for each ORACLE_HOME. This information is found by executing the C command and by reading the following XML file: $ORACLE_HOME/inventory/Components21/oracle.server/*/context.xml The following bundles are known: SE1 (Standard Edition One), SE (Standard Edition), EE (Enterprise Edition), XE (Express Edition). =item 4 Returns the database hash as follows: { 'SID' => { 'BUNDLE' => 'Standard', 'AUTOSTART' => 0, 'ORA_HOME' => '/home/oracle/oracle/product/11.2.0', 'VERSION' => '11.2.0.4.0' } }; =back Optionally, you can call C to return only the hash of versions and bundles, instead of the complete instances hash: { '/home/oracle/oracle/product/11.2.0' => { 'BUNDLE' => 'Standard', 'VERSION' => '11.2.0.4.0' } }; In that case, you just have to pass parameter 1 (integer one) when calling the function. =head2 Exports The module exports the C function. =cut use Exporter; our @ISA = qw(Exporter); our @EXPORT = qw(&getInstances); use strict; use warnings; ######### BEGIN: Constants ############ # Known Oracle editions. The two-letter codes are the ones which can be # encountered in the context.xml file. my %bundles = ( 'SE1' => 'Standard One', 'SE' => 'Standard', 'EE' => 'Enterprise', 'XE' => 'Express' ); ######### END: Constants ############ =head2 getInstances() =head3 Synopsis getInstances($version_only) where $versions_only is a integer (tested as a bool) my $database = getInstances() my $versions = getInstances(1) =head3 Return values The function returns a hash reference containing the instances or versions. =cut sub getInstances { my $versions_only = shift; my %database; my %versions; # First, read the /etc/oratab to find out Oracle instances # Here we already get the SID, path and autostart open(my $ORATAB, '<', '/etc/oratab') or die("Cannot open /etc/oratab $!"); while (my $oratab_line = <$ORATAB>) { chomp $oratab_line; next if $oratab_line =~ /^(#|$)/; # skip comments and empty lines my ($ora_sid, $ora_home, $dbstart_yn) = split(/:/, $oratab_line); # Keep existing instances only if (-d $ora_home) { $database{$ora_sid} = { 'ORA_HOME' => $ora_home, 'AUTOSTART' => $dbstart_yn eq 'Y' ? 1 : 0 }; } } close($ORATAB); # Retrieve version and bundle information in %versions # and put information in global %database hash too foreach my $ora_sid (keys(%database)) { my $ora_home = $database{$ora_sid}{'ORA_HOME'}; unless (exists($versions{$ora_home})) { $versions{$ora_home} = _getVersionAndBundle($ora_home); } my $version_bundle = $versions{$ora_home}; $database{$ora_sid}{'VERSION'} = $version_bundle->{'VERSION'}; $database{$ora_sid}{'BUNDLE'} = $version_bundle->{'BUNDLE'}; } # Return complete database hash or only version and bundle, according to # $versions_only argument if ($versions_only) { return \%versions; } else { return \%database; } } # _getVersionAndBundle($ora_home) # # Simple method building a hash with two keys 'VERSION' and 'BUNDLE' and their # values. # # Return: a hash reference sub _getVersionAndBundle { my $ora_home = shift; my %version_bundle = ( 'VERSION' => _getVersion($ora_home), 'BUNDLE' => _getBundle($ora_home) ); return \%version_bundle; } # _getVersion($ora_home) # # Find Oracle server version installed in ORACLE_HOME. # # We are using the tnsping command for that. # Return: the version string (for example "11.2.0.4.0" or "N/A" by default) sub _getVersion { my $ora_home = shift; my $version = 'N/A'; my $tnsping = "$ora_home/bin/tnsping"; if (-x $tnsping) { open(my $TNSPING_OUT, "$tnsping localhost |") or die("Cannot exec tnsping $!"); while (my $tp_line = <$TNSPING_OUT>) { if ($tp_line =~ m/^TNS Ping Utility for Linux: Version ([0-9.]+)/) { $version = $1; } } close($TNSPING_OUT); } return $version; } # _getBundle($ora_home) # # Find bundle version, reading a context.xml file down below ORACLE_HOME. # # Return: the full name of the install type (e.g. Standard or Enterprise) or, # by default, "N/A" sub _getBundle { my $ora_home = shift; my $bundle = 'N/A'; my $xml_re = qr/^\s*) { if ($xml_line =~ $xml_re) { $xml_line =~ $type_re; my $abbr = $1; $bundle = $bundles{$abbr} if exists($bundles{$abbr}); last; } } close($CONTEXT_XML); } return $bundle; } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Modules/Download.pm000066400000000000000000000757731372663377700233600ustar00rootroot00000000000000############################################################################### ## OCSINVENTORY-NG ## Copyleft Pascal DANEK 2005 ## Web : http://ocsinventory.sourceforge.net ## ## This code is open source and may be copied and modified as long as the source ## code is always made freely available. ## Please refer to the General Public Licence http://www.gnu.org/ or Licence.txt ################################################################################ # Function by hook: # -download_prolog_reader, download_message, download # -download_inventory_handler # -download_end_handler, begin, done, clean, finish, period, download, execute, # check_signature and build_package package Ocsinventory::Agent::Modules::Download; use strict; use Fcntl qw/:flock/; use XML::Simple; use LWP::UserAgent; use Compress::Zlib; use Digest::MD5; use File::Path; use Socket; # Can be missing. By default, we use MD5 # You have to install it if you want to use SHA1 digest eval{ require Digest::SHA1 }; #Global vars my $ua; my $download_config; my @prior_pkgs; sub new { my $name="download"; #Set the name of your module here my (undef,$context) = @_; my $self = {}; # Create a special logger for the module $self->{logger} = new Ocsinventory::Logger ({ config => $context->{config}, }); # We use the common object for the module $self->{common} = $context->{common}; $self->{context} = $context; $self->{logger}->{header}="[$name]"; $self->{structure} = { name => $name, start_handler => $name."_start_handler", prolog_writer => undef, prolog_reader => $name."_prolog_reader", inventory_handler => $name."_inventory_handler", end_handler => $name."_end_handler" }; $self->{settings} = { https_port => '443', # Time to wait between scheduler periods, scheduling cycles and fragments downloads frag_latency_default => 10, period_latency_default => 0, cycle_latency_default => 10, max_error_count => 30, # Number of loops for one period period_lenght_default => 10, }; $self->{messages} = { # Errors code_success => 'SUCCESS', success_already_setup => 'SUCCESS_ALREADY_SETUP', err_bad_id => 'ERR_BAD_ID', err_download_info => 'ERR_DOWNLOAD_INFO', err_bad_digest => 'ERR_BAD_DIGEST', err_download_pack => 'ERR_DOWNLOAD_PACK', err_build => 'ERR_BUILD', err_execute => 'ERR_EXECUTE', err_clean => 'ERR_CLEAN', err_timeout => 'ERR_TIMEOUT', }; # Special hash for packages $self->{packages}= {}; bless $self; } sub download_start_handler { my $self = shift; my $logger = $self->{logger}; my $common = $self->{context}->{common}; my $config = $self->{context}->{config}; $logger->debug("Calling download_start_handler"); # Disabling module if local mode if ($config->{stdout} || $config->{local}) { $self->{disabled} = 1; $logger->info("Agent is running in local mode...disabling module"); } # If we cannot load prerequisite, we disable the module if ($common->can_load('LWP')) { my $lwp_version = $LWP::VERSION; $lwp_version=$self->{common}->convertVersion($lwp_version,3); if ($lwp_version > 583) { #Newer LWP version unless ($common->can_load('LWP::Protocol::https')) { $self->{disabled} = 1; $logger->error("LWP::Protocol::https perl module is missing !!"); $logger->error("Humm my prerequisites are not OK...disabling module :( :("); } } else { unless ($common->can_load('Crypt::SSLeay')) { $self->{disabled} = 1; $logger->error("Crypt::SSLeay perl module is missing !!"); $logger->error("Humm my prerequisites are not OK...disabling module :( :("); } } } else { $self->{disabled} = 1; $logger->error("LWP perl module is missing !!"); $logger->error("Humm my prerequisites are not OK...disabling module :( :("); } } sub download_prolog_reader{ #Read prolog response my ($self,$prolog) = @_; my $context = $self->{context}; my $logger = $self->{logger}; my $config = $self->{context}->{config}; my $network = $self->{context}->{network}; my $common = $self->{common}; my $settings = $self->{settings}; my $messages = $self->{messages}; my $packages = $self->{packages}; $logger->debug("Calling download_prolog_reader"); $logger->debug($prolog); $prolog = XML::Simple::XMLin( $prolog, ForceArray => ['OPTION', 'PARAM']); my $option; # Create working directory my $opt_dir = $context->{installpath}.'/download'; mkdir($opt_dir) unless -d $opt_dir; # We create a file to tell to download process that we are running open SUSPEND, ">$opt_dir/suspend"; close(SUSPEND); # Create history file if needed unless(-e "$opt_dir/history"){ open HISTORY, ">$opt_dir/history" or die("Cannot create history file: $!"); close(HISTORY); } # Create lock file if needed unless(-e "$opt_dir/lock"){ open LOCK, ">$opt_dir/lock" or die("Cannot create lock file: $!"); close(LOCK); } # Retrieve our options for $option (@{$prolog->{OPTION}}){ if ($option->{NAME} =~/download/i){ for (@{ $option->{PARAM} } ) { # Type of param if ($_->{'TYPE'} eq 'CONF'){ # Writing configuration open CONFIG, ">$opt_dir/config" or die("Cannot open/create config file ($opt_dir/config)"); if (flock(CONFIG, LOCK_EX)){ $logger->debug("Writing config file."); print CONFIG XMLout($_, RootName => 'CONF'); close(CONFIG); $download_config = $_; } else { $logger->error("Cannot lock config file !!"); close(CONFIG); return 0; } # Apply config # ON ? if ($_->{'ON'} == '0'){ $logger->info("Download is off."); open LOCK, "$opt_dir/lock" or die("Cannot open lock file: $!"); if (flock(LOCK, LOCK_EX|LOCK_NB)){ close(LOCK); unlink("$opt_dir/suspend"); return 0; } else { $logger->debug("Try to kill current download process..."); my $pid = ; close(LOCK); $logger->debug("Sending USR1 to $pid..."); if (kill("USR1", $pid)){ $logger->debug("Success."); } else { $logger->debug("Failed."); } return 0; } } # Maybe a new package to download } elsif ($_->{'TYPE'} eq 'PACK'){ $packages->{$_->{'ID'}} = { 'PACK_LOC' => $_->{'PACK_LOC'}, 'INFO_LOC' => $_->{'INFO_LOC'}, #'ID' => $_->{'ID'}, 'CERT_PATH' => $_->{'CERT_PATH'}, 'CERT_FILE' => $_->{'CERT_FILE'}, 'FORCE' => $_->{'FORCE'} }; } } } } # We are now in download child # Connect to server if ($context->{network}) { $ua = $context->{network}->{ua}; } else { $logger->info("Cannot find network settings to make this module works properly...disabling module"); $self->{disabled} = 1; } # Check history file unless(open HISTORY, "$opt_dir/history") { flock(HISTORY, LOCK_EX); unlink("$opt_dir/suspend"); $logger->error("Cannot read history file: $!"); return 1; } chomp(my @done = ); close(HISTORY); # Package is maybe already handled for (keys %$packages){ my $dir = $opt_dir."/".$_; my $fileid = $_; my $infofile = 'info'; my $location = $packages->{$_}->{'INFO_LOC'}; unless ($packages->{$_}->{'FORCE'} == 1) { if($common->already_in_array($fileid, @done)){ $logger->info("Will not download $fileid. (already in history file)"); &download_message($fileid, $messages->{success_already_setup},$logger,$context); next; } } # Looking for packages status unless(-d $dir){ $logger->debug("Making working directory for $fileid."); mkdir($dir) or die("Cannot create $fileid directory: $!"); open FH, ">$dir/since" or die("Cannot create $fileid since file: $!");; print FH time(); close(FH); } # Retrieve and writing info file if needed unless(-f "$dir/$infofile"){ # Special value INSTALL_PATH $packages->{$_}->{CERT_PATH} =~ s/INSTALL_PATH/$context->{installpath}/; $packages->{$_}->{CERT_FILE} =~ s/INSTALL_PATH/$context->{installpath}/; # Getting info file if ($network->getFile("https","$location/$fileid","info","$dir/info")){ download_message($fileid, $self->{messages}->{err_download_info},$logger,$context); $logger->error("Error download info file !!! Wrong URL or SSL certificate ?"); next; } } } unless(unlink("$opt_dir/suspend")){ $logger->error("Cannot delete suspend file: $!"); return 1; } return 0; } sub ssl_verify_callback { my ($ok, $x509_store_ctx) = @_; return $ok; } sub download_inventory_handler{ # Adding the ocs package ids to softwares my ($self,$inventory) = @_; my $context = $self->{context}; my $logger = $self->{logger}; $logger->debug("Calling download_inventory_handler"); my @history; # Read download history file if ( open PACKAGES, "$context->{installpath}/download/history" ){ flock(PACKAGES, LOCK_SH); while(){ chomp( $_ ); push @history, { ID => $_ }; } } close(PACKAGES); # Add it to inventory (will be handled by Download.pm server module push @{ $inventory->{xmlroot}->{'CONTENT'}->{'DOWNLOAD'}->{'HISTORY'} },{ 'PACKAGE'=> \@history }; } sub download_end_handler{ # Get global structure my $self = shift; my $context = $self->{context}; my $logger = $self->{logger}; my $common = $self->{common}; my $settings = $self->{settings}; my $messages = $self->{messages}; my $packages = $self->{packages}; $logger->debug("Calling download_end_handler"); my $dir = $context->{installpath}."/download"; my $pidfile = $dir."/lock"; return 0 unless -d $dir; # We have jobs, we do it alone my $fork = fork(); if ($fork>0){ return 0; } elsif ($fork<0){ return 1; } else { $SIG{'USR1'} = sub { print "Exiting on signal...\n"; &finish($logger, $context); }; # Go into working directory chdir($dir) or die("Cannot chdir to working directory...Abort\n"); } # Maybe an other process is running exit(0) if begin($pidfile,$logger); # Retrieve the packages to download opendir DIR, $dir or die("Cannot read working directory: $!"); my $end; while(1){ # If agent is running, we wait if (-e "suspend") { $logger->debug('Found a suspend file... Will wait 10 seconds before retry'); sleep(10); next; } $end = 1; #TODO Uncomment this line #undef $packages; # Reading configuration open FH, "$dir/config"; if (flock(FH, LOCK_SH)){ $download_config = XMLin("$dir/config"); close(FH); # If Frag latency is null, download is off if ($download_config->{'ON'} eq '0'){ $logger->info("Option turned off. Exiting."); finish($logger, $context); } } else { close(FH); if (-e "$dir/config") { $logger->error("Cannot read config file :-( . Exiting."); } else { $logger->debug("Download not configured"); } finish($logger, $context); } # Retrieving packages to download and their priority while (my $entry = readdir(DIR)){ next if $entry !~ /^\d+$/; next unless(-d $entry); # Clean package if info file does not still exist unless(-e "$entry/info"){ $logger->debug("No info file found for $entry!!"); clean( $entry, $logger, $context, $messages, $packages ); next; } my $info = XML::Simple::XMLin( "$entry/info" ) or next; # Check that fileid == directory name if ($info->{'ID'} ne $entry){ $logger->debug("ID in info file does not correspond!!"); clean( $entry, $logger, $context, $messages, $packages ); download_message($entry, $messages->{err_bad_id},$logger,$context); next; } # Manage package timeout # Clean package if since timestamp is not present unless(-e "$entry/since"){ $logger->debug("No since file found!!"); clean($entry, $logger, $context,$messages,$packages ); next; } else { my $time = time(); if (open SINCE, "$entry/since"){ my $since = ; if ($since=~/\d+/){ if ((($time-$since)/86400) > $download_config->{TIMEOUT}){ $logger->error("Timeout Reached for $entry."); clean($entry, $logger, $context,$messages,$packages ); &download_message($entry, $messages->{err_timeout},$logger,$context); close(SINCE); next; } else { $logger->debug("Checking timeout for $entry... OK"); } } else { $logger->error("Since data for $entry is incorrect."); clean($entry, $logger, $context, $messages, $packages ); &download_message($entry, $messages->{err_timeout},$logger,$context); close(SINCE); next; } close(SINCE); } else { $logger->error("Cannot find since data for $entry."); clean($entry, $logger, $context, $messages, $packages ); &download_message($entry, $messages->{err_timeout},$logger,$context); next; } } # Building task file if needed unless( -f "$entry/task" and -f "$entry/task_done" ){ open FH, ">$entry/task" or die("Cannot create task file for $entry: $!"); my $i; my $frags = $info->{'FRAGS'}; # There are no frags if there is only a command if ($frags){ for ($i=1;$i<=$frags;$i++){ print FH "$entry-$i\n"; } }; close FH; # To be sure that task file is fully created open FLAG, ">$entry/task_done" or die ("Cannot create task flag file for $entry: $!"); close(FLAG); } # Store info XML descriptions in package attributes for (keys %$info){ $packages->{$entry}->{$_} = $info->{$_} } $end = 0; } # Rewind directory rewinddir(DIR); # Call packages scheduler if ($end){ last; } else { period($packages,$logger,$context,$self->{messages},$settings); } } $logger->info("No more package to download."); finish($logger, $context); } # Schedule the packages sub period{ my ($packages,$logger,$context,$messages,$settings) = @_ ; my $period_lenght_default = $settings->{period_lenght_default} ; my $frag_latency_default= $settings->{frag_latency_default} ; my $cycle_latency_default= $settings->{cycle_latency_default} ; my $period_latency_default= $settings->{period_latency_default} ; my $i; #Serching packages with the priority 0 for (keys %$packages) { if ($packages->{$_}->{'PRI'} eq "0") { push (@prior_pkgs,$_); } } $logger->debug("New period. Nb of cycles: ". (defined($download_config->{'PERIOD_LENGTH'})?$download_config->{'PERIOD_LENGTH'}:$period_lenght_default)); for ($i=1;$i<=( defined($download_config->{'PERIOD_LENGTH'})?$download_config->{'PERIOD_LENGTH'}:$period_lenght_default);$i++){ # Highest priority if (@prior_pkgs){ $logger->debug("Managing ".scalar(@prior_pkgs)." package(s) with absolute priority."); for (@prior_pkgs){ # If done file found, clean package if (-e "$_/done"){ $logger->debug("done file found!!"); done($_,$logger,$context,$messages,$settings,$packages); next; } download($_,$logger,$context,$messages,$settings,$packages); $logger->debug("Now pausing for a fragment latency => ".( defined($download_config->{'FRAG_LATENCY'})?$download_config->{'FRAG_LATENCY'}:$frag_latency_default) ." seconds"); sleep( defined($download_config->{'FRAG_LATENCY'})?$download_config->{'FRAG_LATENCY'}:$frag_latency_default ); } next; } # Normal priority for (keys %$packages){ # If done file found, clean package if(-e "$_/done"){ $logger->debug("done file found!!"); done($_,$logger,$context,$messages,$settings,$packages); next; } next if $i % $packages->{$_}->{'PRI'} != 0; download($_,$logger,$context,$messages,$settings,$packages); $logger->debug("Now pausing for a fragment latency => ". (defined( $download_config->{'FRAG_LATENCY'} )?$download_config->{'FRAG_LATENCY'}:$frag_latency_default) ." seconds"); sleep(defined($download_config->{'FRAG_LATENCY'})?$download_config->{'FRAG_LATENCY'}:$frag_latency_default); } $logger->debug("Now pausing for a cycle latency => ".( defined($download_config->{'CYCLE_LATENCY'})?$download_config->{'CYCLE_LATENCY'}:$cycle_latency_default) ." seconds"); sleep(defined($download_config->{'CYCLE_LATENCY'})?$download_config->{'CYCLE_LATENCY'}:$cycle_latency_default); } sleep($download_config->{'PERIOD_LATENCY'}?$download_config->{'PERIOD_LATENCY'}:$period_latency_default); } # Download a fragment of the specified package sub download { my ($id,$logger,$context,$messages,$settings,$packages) = @_; my $error; my $proto = $packages->{$id}->{'PROTO'}; my $location = $packages->{$id}->{'PACK_LOC'}; my $network = $context->{network}; # If we find a temp file, we know that the update of the task file has failed for any reason. So we retrieve it from this file if (-e "$id/task.temp") { unlink("$id/task.temp"); rename("$id/task.temp","$id/task") or return 1; } # Retrieve fragments already downloaded unless(open TASK, "$id/task"){ $logger->error("Cannot open $id/task."); return 1; } my @task = ; # Done if (!@task){ $logger->debug("Download of $id... Finished."); close(TASK); execute($id,$logger,$context,$messages,$settings,$packages); return 0; } my $fragment = shift(@task); $logger->debug("Downloading $fragment..."); # Using proxy if possible my $res = $network->getFile(lc($proto),"$location/$id",$fragment,"$id/$fragment"); # Checking if connected unless($res) { #Success $error = 0; # Updating task file rename(">$id/task", ">$id/task.temp"); open TASK, ">$id/task" or return 1; print TASK @task; close(TASK); unlink(">$id/task.temp"); } else { $error++; if ($error > $settings->{max_error_count}){ $logger->error("Error : Max errors count reached"); finish($logger,$context); } return 1; } return 0; } # Assemble and handle downloaded package sub execute{ my ($id,$logger,$context,$messages,$settings,$packages) = @_; my $common = $context->{common}; my $tmp = $id."/tmp"; my $exit_code; $logger->debug("Execute orders for package $id."); if (build_package($id,$logger,$context,$messages,$packages)){ clean($id,$logger, $context,$messages,$packages); return 1; } else { # First, we get in temp directory unless( chdir($tmp) ){ $logger->error("Cannot chdir to working directory: $!"); download_message($id, $messages->{err_execute}, $logger,$context); clean($id,$logger, $context,$messages,$packages); return 1; } # Executing preorders (notify user, auto launch, etc.... # $id->{NOTIFY_USER} # $id->{NOTIFY_TEXT} # $id->{NOTIFY_COUNTDOWN} # $id->{NOTIFY_CAN_ABORT} # TODO: notification to send through DBUS to the user eval{ # Execute instructions if ($packages->{$id}->{'ACT'} eq 'LAUNCH'){ my $exe_line = $packages->{$id}->{'NAME'}; $packages->{$id}->{'NAME'} =~ s/^([^ -]+).*/$1/; # Exec specified file (LAUNCH => NAME) if (-e $packages->{$id}->{'NAME'}){ $logger->debug("Launching $packages->{$id}->{'NAME'}..."); chmod(0755, $packages->{$id}->{'NAME'}) or die("Cannot chmod: $!"); $exit_code = system( "./".$exe_line ) >> 8; } else { die(); } } elsif ($packages->{$id}->{'ACT'} eq 'EXECUTE'){ # Exec specified command EXECUTE => COMMAND $logger->debug("Execute $packages->{$id}->{'COMMAND'}..."); system( $packages->{$id}->{'COMMAND'} ) and die(); } elsif ($packages->{$id}->{'ACT'} eq 'STORE'){ # Store files in specified path STORE => PATH $packages->{$id}->{'PATH'} =~ s/INSTALL_PATH/$context->{installpath}/; # Build it if needed my @dir = split('/', $packages->{$id}->{'PATH'}); my $dir; for (@dir){ $dir .= "$_/"; unless(-e $dir){ mkdir($dir); $logger->debug("Create $dir..."); } } $logger->debug("Storing package to $packages->{$id}->{'PATH'}..."); # Stefano Brandimarte => Stevenson! system($common->get_path('cp')." -pr * ".$packages->{$id}->{'PATH'}) and die(); } }; if ($@){ # Notify success to ocs server download_message($id, $messages->{err_execute},$logger,$context); chdir("../..") or die("Cannot go back to download directory: $!"); clean($id,$logger,$context,$messages,$packages); return 1; } else { chdir("../..") or die("Cannot go back to download directory: $!"); done($id,$logger,$context,$messages,$settings,$packages,(defined($exit_code)?$exit_code:'_NONE_')); return 0; } } } # Check package integrity sub build_package{ my ($id,$logger,$context,$messages,$packages) = @_; my $common = $context->{common}; my $count = $packages->{$id}->{'FRAGS'}; my $i; my $tmp = "./$id/tmp"; unless(-d $tmp){ mkdir("$tmp"); } # No job if no files return 0 unless $count; # Assemble package $logger->info("Building package for $id."); for ($i=1;$i<=$count;$i++){ if (-f "./$id/$id-$i"){ # We make a tmp working directory if ($i==1){ open PACKAGE, ">$tmp/build.tar.gz" or return 1; } # We write each fragment in the final package open FRAGMENT, "./$id/$id-$i" or return 1; my $row; while ($row = ){ print PACKAGE $row; } close(FRAGMENT); } else { return 1; } } close(PACKAGE); # if (check_signature($packages->{$id}->{'DIGEST'}, "$tmp/build.tar.gz", $packages->{$id}->{'DIGEST_ALGO'}, $packages->{$id}->{'DIGEST_ENCODE'},$logger)){ download_message($id, $messages->{err_bad_digest},$logger,$context); return 1; } if ( system( $common->get_path("tar")." -xvzf $tmp/build.tar.gz -C $tmp") ){ $logger->error("Cannot extract $id with tar, trying with unzip."); if ( system( $common->get_path("unzip")." $tmp/build.tar.gz -d $tmp") ){ $logger->error("Cannot extract $id with unzip."); download_message($id,$messages->{err_build},$logger,$context); return 1; } } $logger->debug("Building of $id... Success."); unlink("$tmp/build.tar.gz") or die ("Cannot remove build file: $!\n"); return 0; } sub check_signature{ my ($checksum, $file, $digest, $encode,$logger) = @_; $logger->info("Checking signature for $file."); my $base64; # Open file unless(open FILE, $file){ $logger->error("cannot open $file: $!"); return 1; } binmode(FILE); # Retrieving encoding form if ($encode =~ /base64/i){ $base64 = 1; $logger->debug('Digest format: Base 64'); } elsif ($encode =~ /hexa/i){ $logger->debug('Digest format: Hexadecimal'); } else { $logger->debug('Digest format: Not supported'); return 1; } eval{ # Check it if ($digest eq 'MD5'){ $logger->debug('Digest algo: MD5'); if ($base64){ die unless Digest::MD5->new->addfile(*FILE)->b64digest eq $checksum; } else { die unless Digest::MD5->new->addfile(*FILE)->hexdigest eq $checksum; } } elsif ($digest eq 'SHA1'){ $logger->debug('Digest algo: SHA1'); if ($base64){ die unless Digest::SHA1->new->addfile(*FILE)->b64digest eq $checksum; } else { die unless Digest::SHA1->new->addfile(*FILE)->hexdigest eq $checksum; } } else { $logger->debug('Digest algo unknown: '.$digest); die; } }; if ($@){ $logger->debug("Digest checking error !!"); close(FILE); return 1; } else { close(FILE); $logger->debug("Digest OK..."); return 0; } } # Launch a download error to ocs server sub download_message{ my ($id, $code,$logger,$context) = @_; $logger->debug("Sending message for $id, code=$code."); my $xml = { 'DEVICEID' => $context->{deviceid}, 'QUERY' => 'DOWNLOAD', 'ID' => $id, 'ERR' => $code }; # Generate xml $xml = XMLout($xml, RootName => 'REQUEST'); # Compress data $xml = Compress::Zlib::compress( $xml ); my $URI = $context->{servername}; # Send request my $request = HTTP::Request->new(POST => $URI); $request->header('Pragma' => 'no-cache', 'Content-type', 'application/x-compress'); $request->content($xml); my $res = $ua->request($request); # Checking result if ($res->is_success) { return 0; }else{ return 1; } } # At the beginning of end handler sub begin{ my ($pidfile,$logger) = @_; open LOCK_R, "$pidfile" or die("Cannot open pid file: $!"); if (flock(LOCK_R,LOCK_EX|LOCK_NB)){ open LOCK_W, ">$pidfile" or die("Cannot open pid file: $!"); select(LOCK_W) and $|=1; select(STDOUT) and $|=1; print LOCK_W $$; $logger->info("Beginning work. I am $$."); return 0; } else { close(LOCK_R); $logger->error("$pidfile locked. Cannot begin work... :-("); return 1; } } sub done{ my ($id,$logger,$context,$messages,$settings,$packages,$suffix) = @_; my $common = $context->{common}; my $frag_latency_default = $settings->{frag_latency_default}; $logger->debug("Package $id... Done. Sending message..."); # Trace installed package open DONE, ">$id/done"; close(DONE); # Read history file open HISTORY,"$context->{installpath}/download/history" or warn("Cannot open history file: $!"); chomp(my @historyIds = ); close(HISTORY); # Put it in history file open HISTORY,">>$context->{installpath}/download/history" or warn("Cannot open history file: $!"); flock(HISTORY, LOCK_EX); if ( $common->already_in_array($id, @historyIds) ){ $logger->debug("Warning: ID $id has been found in the history file (package was already deployed)"); } else { $logger->debug("Writing $id reference in history file"); print HISTORY $id,"\n"; } close(HISTORY); # Notify success to ocs server my $code; if ($suffix ne '_NONE_'){ $code = $messages->{code_success}."_$suffix"; } else { $code = $messages->{code_success}; } unless(download_message($id, $code,$logger,$context)){ clean($id,$logger,$context,$messages,$packages); } else { sleep( defined($download_config->{'FRAG_LATENCY'})?$download_config->{'FRAG_LATENCY'}:$frag_latency_default ); } return 0; } sub clean{ my ($id,$logger,$context,$messages,$packages) = @_; $logger->info("Cleaning $id package."); delete $packages->{$id}; #If the package is priority 0 if ((my $index) = grep { $prior_pkgs[$_] eq $id } 0..$#prior_pkgs){ delete $prior_pkgs[$index]; } unless(File::Path::rmtree($id, 0)){ $logger->error("Cannot clean $id!! Abort..."); download_message($id, $messages->{err_clean},$logger,$context); die(); } return 0; } # At the end sub finish{ my ($logger,$context) = @_; open LOCK, '>'.$context->{installpath}.'/download/lock'; $logger->debug("End of work...\n"); exit(0); } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Modules/Example.pm000066400000000000000000000052601372663377700231640ustar00rootroot00000000000000############################################################################### ## OCSINVENTORY-NG ## Copyleft Guillaume PROTET 2010 ## Web : http://www.ocsinventory-ng.org ## ## This code is open source and may be copied and modified as long as the source ## code is always made freely available. ## Please refer to the General Public Licence http://www.gnu.org/ or Licence.txt ################################################################################ package Ocsinventory::Agent::Modules::Example; sub new { my $name="example"; #Set the name of your module here my (undef,$context) = @_; my $self = {}; #Create a special logger for the module $self->{logger} = new Ocsinventory::Logger ({ config => $context->{config} }); $self->{logger}->{header}="[$name]"; $self->{context}=$context; $self->{structure}= { name => $name, start_handler => $name."_start_handler", #or undef if don't use this hook prolog_writer => $name."_prolog_writer", #or undef if don't use this hook prolog_reader => $name."_prolog_reader", #or undef if don't use this hook inventory_handler => $name."_inventory_handler", #or undef if don't use this hook end_handler => $name."_end_handler" #or undef if don't use this hook }; bless $self; } ######### Hook methods ############ sub example_start_handler { #Use this hook to test prerequisites needed by module and disble it if needed my $self = shift; my $logger = $self->{logger}; $logger->debug("Yeah you are in example_start_handler :)"); my $prerequisites = 1 ; if ( $prerequisites == 0 ) { $self->{disabled} = 1; #Use this to disable the module $logger->debug("Humm my prerequisites are not OK...disabling module :( :( "); } } sub example_prolog_writer { #Use this hook to add information the prolog XML my $self = shift; my $logger = $self->{logger}; $logger->debug("Yeah you are in example_prolog_writer :)"); } sub example_prolog_reader { #Use this hook to read the answer from OCS server my $self = shift; my $logger = $self->{logger}; $logger->debug("Yeah you are in example_prolog_reader :)"); } sub example_inventory_handler { #Use this hook to add or modify entries in the inventory XML my $self = shift; my $logger = $self->{logger}; $logger->debug("Yeah you are in example_inventory_handler :)"); } sub example_end_handler { #Use this hook to add treatments before the end of agent launch my $self = shift; my $logger = $self->{logger}; $logger->debug("Yeah you are in example_end_handler :)"); } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Modules/Snmp.pm000066400000000000000000001004351372663377700225060ustar00rootroot00000000000000############################################################################### ## OCSINVENTORY-NG ## Copyleft Guillaume PROTET 2010 ## Web : http://www.ocsinventory-ng.org ## ## This code is open source and may be copied and modified as long as the source ## code is always made freely available. ## Please refer to the General Public Licence http://www.gnu.org/ or Licence.txt ################################################################################ package Ocsinventory::Agent::Modules::Snmp; use strict; no strict 'refs'; use warnings; use XML::Simple; use Digest::MD5; # New lib for scanning sub new { my $name="snmp"; #Set the name of your module here my (undef,$context) = @_; my $self = {}; #Create a special logger for the module $self->{logger} = new Ocsinventory::Logger ({ config => $context->{config} }); $self->{logger}->{header}="[$name]"; $self->{common} = $context->{common}; $self->{context}=$context; $self->{structure}= { name => $name, start_handler => $name."_start_handler", prolog_writer => undef, prolog_reader => $name."_prolog_reader", inventory_handler => undef, end_handler => $name."_end_handler", }; $self->{number_scan}=0; $self->{snmp_oid_run}=$name."_oid_run"; $self->{snmp_oid_xml}=$name."_oid_xml"; $self->{func_oid}={}; $self->{snmp_dir}=[]; $self->{snmp_vardir} = ["$self->{context}->{installpath}/snmp/mibs/local/","$self->{context}->{installpath}/snmp/mibs/remote/"]; my $spec_dir_snmp="Ocsinventory/Agent/Modules/Snmp/"; $self->{spec_dir_snmp}=$spec_dir_snmp; $self->{spec_module_snmp}="Ocsinventory::Agent::Modules::Snmp::"; # We are going to search where is the directory Ocsinventory/Modules/snmp foreach my $dir ( @INC ) { my $res_dir=$dir."/".$spec_dir_snmp; if ( -d $res_dir ) { push(@{$self->{snmp_dir}},$res_dir); } } # We create a xml for the snmp inventory that we will be sent to server $self->{inventory}={}; bless $self; } sub snmp_start_handler { my $self = shift; my $logger = $self->{logger}; my $common = $self->{context}->{common}; my $config = $self->{context}->{config}; $logger->debug("Calling snmp_start_handler"); # Disabling module if local mode if ($config->{stdout} || $config->{local}) { $self->{disabled} = 1; $logger->info("Agent is running in local mode...disabling module"); } # If we cannot load prerequisite, we disable the module unless ($common->can_load('Net::SNMP')) { $self->{disabled} = 1; $logger->error("Net::SNMP perl module is missing !!"); $logger->error("Humm my prerequisites are not OK...disabling module :( :("); } } sub snmp_prolog_reader { my ($self, $prolog) = @_; my $logger = $self->{logger}; my $network = $self->{context}->{network}; my $snmp_vardir = $self->{snmp_vardir}; my $option; $logger->debug("Calling snmp_prolog_reader"); $prolog = XML::Simple::XMLin( $prolog, ForceArray => ['OPTION', 'PARAM']); for $option (@{$prolog->{OPTION}}){ if ( $option->{NAME} =~/snmp/i){ $self->{doscans} = 1 ; for ( @{ $option->{PARAM} } ) { if ($_->{'TYPE'} eq 'DEVICE'){ # Adding the IP in the devices array push @{$self->{netdevices}},{ IPADDR => $_->{IPADDR}, MACADDR => $_->{MACADDR}, }; } if ($_->{'TYPE'} eq 'COMMUNITY'){ # Adding the community in the communities array push @{$self->{communities}},{ VERSION=>$_->{VERSION}, NAME=>$_->{NAME}, USERNAME=>$_->{USERNAME}, AUTHPROTO=>$_->{AUTHPROTO}, AUTHPASSWD=>$_->{AUTHPASSWD}, PRIVPROTO=>$_->{PRIVPROTO}, PRIVPASSWD=>$_->{PRIVPASSWD} }; } if ($_->{'TYPE'} eq 'NETWORK'){ push @{$self->{nets_to_scan}},$_->{SUBNET}; } # Creating the directory for xml if they don't yet exist mkdir($self->{context}->{installpath}."/snmp") unless -d $self->{context}->{installpath}."/snmp"; mkdir($self->{context}->{installpath}."/snmp/mibs") unless -d $self->{context}->{installpath}."/snmp/mibs"; foreach my $dir ( @{$snmp_vardir}) { mkdir($dir) unless -d $dir; } } } } } sub snmp_end_handler { my $self = shift; my $logger = $self->{logger}; my $common = $self->{context}->{common}; my $network = $self->{context}->{network}; $logger->debug("Calling snmp_end_handler"); # If no order form server return unless $self->{doscans}; # Flushing xmltags if it has not been done $common->flushXMLTags(); # We get the config my $config = $self->{context}->{config}; my $communities=$self->{communities}; if ( ! defined ($communities ) ) { $logger->debug("We have no Community from server, we use default public community"); $communities=[{VERSION=>"2c",NAME=>"public"}]; } my ($name,$comm,$error,$system_oid); # sysName.0 my $snmp_sysname="1.3.6.1.2.1.1.5.0"; # sysDescr.0 my $snmp_sysdescr="1.3.6.1.2.1.1.1.0"; # sysLocation.0 my $snmp_syslocation="1.3.6.1.2.1.1.6.0"; # sysUpTime.0 my $snmp_sysuptime="1.3.6.1.2.1.1.3.0"; # sysObjectId.0 my $snmp_sysobjectid="1.3.6.1.2.1.1.2.0"; # syscontact.0 my $snmp_syscontact="1.3.6.1.2.1.1.4.0"; # ifPhysAddress.1 my $snmp_macaddr="1.3.6.1.2.1.2.2.1.6."; my $snmp_ifdescr="1.3.6.1.2.1.2.2.1.2."; my $snmp_iftype="1.3.6.1.2.1.2.2.1.3"; # Initalising the XML properties my $snmp_inventory = $self->{inventory}; $snmp_inventory->{xmlroot}->{QUERY} = ['SNMP']; $snmp_inventory->{xmlroot}->{DEVICEID} = [$self->{context}->{config}->{deviceid}]; # Scanning network $logger->debug("Snmp: Scanning network"); my $nets_to_scan=$self->{nets_to_scan}; foreach my $net_to_scan ( @$nets_to_scan ){ $self->snmp_ip_scan($net_to_scan); } $logger->debug("Snmp: Ending Scanning network"); # Begin scanning ip tables my $ip=$self->{netdevices}; foreach my $device ( @$ip ) { my $session=undef; my $full_oid=undef; my $devicedata = $common->{xmltags}; #To fill the xml informations for this device $logger->debug("Scanning $device->{IPADDR} device"); # Search for the good snmp community in the table community LIST_SNMP: foreach $comm ( @$communities ) { # Test if we use SNMP v3 if ( $comm->{VERSION} eq "3" ) { ($session, $error) = Net::SNMP->session( -retries => 2 , -timeout => 3, -version => 'snmpv'.$comm->{VERSION}, -hostname => $device->{IPADDR}, -translate => [-nosuchinstance => 0, -nosuchobject => 0], -username => $comm->{USERNAME}, -authpassword => $comm->{AUTHPASSWD}, -authprotocol => $comm->{AUTHPROTO}, -privpassword => $comm->{PRIVPASSWD}, -privprotocol => $comm->{PRIVPROTO}, ); # For a use in constructor module (Cisco) $self->{username}=$comm->{USERNAME}; $self->{authpassword}=$comm->{AUTHPASSWD}; $self->{authprotocol}=$comm->{AUTHPROTO}; $self->{privpassword}=$comm->{PRIVPASSWD}; $self->{privprotocol}= $comm->{PRIVPROTO}; } else { # We have an older version v2c ou v1 ($session, $error) = Net::SNMP->session( -retries => 1 , -timeout => 3, -version => 'snmpv'.$comm->{VERSION}, -hostname => $device->{IPADDR}, -community => $comm->{NAME}, -translate => [-nosuchinstance => 0, -nosuchobject => 0], ); }; unless (defined($session)) { $logger->error("Snmp ERROR: $error"); } else { $self->{snmp_session}=$session; # For a use in constructor module (Cisco) $self->{snmp_community}=$comm->{NAME}; $self->{snmp_version}=$comm->{VERSION}; $full_oid=$session->get_request( -varbindlist => [$snmp_sysobjectid] ); last LIST_SNMP if ( defined $full_oid); $session->close; $self->{snmp_session}=undef; } } if ( defined $full_oid ) { $full_oid=$full_oid->{$snmp_sysobjectid}; $session->max_msg_size(8192); # We have found the good Community, we can scan this equipment my ($constr_oid,$device_name,$description,$location,$contact,$uptime,$domain,$macaddr); # We indicate that we scan a new equipment $self->{number_scan}++; my $result; $result=$session->get_request( -varbindlist => [$snmp_sysname]); if ( defined ( $result->{$snmp_sysname} ) && length($result->{$snmp_sysname}) > 0 ) { $device_name=$result->{$snmp_sysname}; } else { $device_name="Not Defined"; } $result=$session->get_request(-varbindlist => [$snmp_sysobjectid]); $full_oid=$result->{$snmp_sysobjectid}; $result=$session->get_request(-varbindlist => [$snmp_sysdescr]); $description=$result->{$snmp_sysdescr}; $result=$session->get_request(-varbindlist => [$snmp_syslocation]); $location=$result->{$snmp_syslocation}; $result=$session->get_request(-varbindlist => [$snmp_sysuptime]); $uptime=$result->{$snmp_sysuptime}; $result=$session->get_request(-varbindlist => [$snmp_syscontact]); $contact=$result->{$snmp_syscontact}; #################### # finding MACADDRESS for checksum #################### my $index=$snmp_iftype; $result=$session->get_next_request(-varbindlist => [$index]); $macaddr=undef; my $ref_iftype=3; # We scan the kinod of connexion, if it is a ethernet, we can use this mac address # If we have a ref_iftype > 3 then we have no eth (type 6) while ( ! defined($macaddr) && defined( $result) && $ref_iftype == 3 ) { foreach $index ( keys %{$result} ) { if ( $index =~ /1\.3\.6\.1\.2\.1\.2\.2\.1\.(\S+)\.(\S+)/ ) { $ref_iftype=$1; my $ref_mac=$2; if ( $result->{$index} == 6 ) { my $res_mac=$session->get_request(-varbindlist => [$snmp_macaddr.$ref_mac]); if ( defined ($res_mac ) && defined ($res_mac->{$snmp_macaddr.$ref_mac}) && $res_mac->{$snmp_macaddr.$ref_mac} ne '' ) { $macaddr=" ".$res_mac->{$snmp_macaddr.$ref_mac}; } else { $result=$session->get_next_request(-varbindlist => [$index]); } } else { $result=$session->get_next_request(-varbindlist => [$index]); } } else { $result=undef; } } } if ( defined($macaddr) && $macaddr =~ /^ 0x(\w{2})(\w{2})(\w{2})(\w{2})(\w{2})(\w{2})$/ ) { $macaddr="$1:$2:$3:$4:$5:$6"; } elsif ( ! defined($macaddr) || $macaddr eq "endOfMibView" ) { if (defined ( $device->{MACADDR} ) ) { $macaddr = $device->{MACADDR}; } else { $macaddr=$device_name; # $macaddr=$device->{IPADDR}."_".$device_name; } } if ( defined ($macaddr) ) { if ( $full_oid =~ /1\.3\.6\.1\.4\.1\.(\d+)/ ) { $system_oid=$1; } # Create SnmpDeviceID my $md5 = Digest::MD5->new; $md5->add($macaddr, $system_oid); my $snmpdeviceid = $md5->hexdigest; # Adding standard informations $common->setSnmpCommons({ IPADDR => $device->{IPADDR}, MACADDR => $macaddr, SNMPDEVICEID => $snmpdeviceid, NAME => $device_name, DESCRIPTION => $description, CONTACT => $contact, LOCATION => $location, UPTIME => $uptime, WORKGROUP => $domain, }); # We run the special treatments for the OID vendor if ( $self->{snmp_oid_run}($self,$system_oid) == 1 ) { # We have no vendor oid for this equipment (run or xml) # we use default.pm $self->{snmp_oid_run}($self,"Default"); } # Add all the informations in the xml for this device push @{$snmp_inventory->{xmlroot}->{CONTENT}->{DEVICE}},$devicedata; } } else { $logger->debug("Failure in scanning Device $device->{IPADDR}: no snmp communication"); } # We have finished with this equipment if (defined $session) { $session->close; } $self->{snmp_session}=undef; # We clear the xml data for this device $common->flushXMLTags(); } $logger->info("No more SNMP device to scan"); # Formatting the XML and sendig it to the server my $content = XMLout( $snmp_inventory->{xmlroot}, RootName => 'REQUEST' , XMLDecl => '', SuppressEmpty => undef ); #Cleaning XML to delete unprintable characters my $clean_content = $common->cleanXml($content); $network->sendXML({message => $clean_content}); $logger->debug("End snmp_end_handler :)"); } ######################################################### # # # function for scanning range of ip and determining if # # there is an equipment for snmp scan # # Parameters: # # (self) # # net_to_scan indicate the subnet to scan # # # ######################################################### sub snmp_ip_scan { my ($self,$net_to_scan) = @_; my $logger=$self->{logger}; my $common=$self->{common}; if ($common->can_load('Net::Netmask') ) { my $block=Net::Netmask->new($net_to_scan); my $size=$block->size()-2; my $index=1; if ( $common->can_run('nmap') && $common->can_load('Nmap::Parser') ) { $logger->debug("Scannig $net_to_scan with nmap"); my $nmaparser = Nmap::Parser->new; $nmaparser->parsescan("nmap","-sP",$net_to_scan); for my $host ($nmaparser->all_hosts("up")) { my $res=$host->addr; $logger->debug("Found $res"); push( @{$self->{netdevices}},{ IPADDR=>$res }) unless $self->search_netdevice($res); } } elsif ($common->can_load('Net::Ping')) { $logger->debug("Scanning $net_to_scan with ping"); my $ping=Net::Ping->new("icmp",1); while ($index <= $size) { my $res=$block->nth($index); if ($ping->ping($res)) { $logger->debug("Found $res"); push( @{$self->{netdevices}},{ IPADDR=>$res }) unless $self->search_netdevice($res); } $index++; } $ping->close(); } else { $logger->debug("No scan possible"); } } else { $logger->debug("Net::Netmask not present: no scan possible"); } } ######################################################### # # # function for executing sub perl with the oid # # Parameters: # # (self) # # system oid for execute the .pm associated # # # ######################################################### sub snmp_oid_run { my ($self,$system_oid)=@_; my $logger=$self->{logger}; my $session=$self->{snmp_session}; my $spec_module_snmp=$self->{spec_module_snmp}; my $return_pm=0; unless ( defined ( $self->{func_oid}{$system_oid} )) { my $spec_dir_snmp=$self->{spec_dir_snmp}; # We init the default value $self->{func_oid}{$system_oid}={}; $self->{func_oid}{$system_oid}{active}=0; $self->{func_oid}{$system_oid}{oid_value}="1.3.6.1.2.1.1.2.0"; $self->{func_oid}{$system_oid}{oid_name}="Undefined"; # Can we find it in the snmp directory foreach my $dir ( @{$self->{snmp_dir}} ) { if ( -r $dir.$system_oid.".pm" ) { # We find the module my $module_found=$spec_module_snmp.$system_oid; eval "use $module_found"; if ($@) { $logger->debug ("Failed to load $module_found: $@"); } else { # We have execute it. We can get the function pointer on snmp_run my $package=$module_found."::"; $self->{func_oid}{$system_oid}{snmp_run}=$package->{'snmp_run'}; if ( defined ( $package->{'snmp_info'} ) ) { my $return_info=&{$package->{'snmp_info'}}; if ( defined $return_info->{oid_value} ) { $self->{func_oid}{$system_oid}{oid_value}=$return_info->{oid_value}; } if ( defined $return_info->{oid_name} ) { $self->{func_oid}{$system_oid}{oid_name}=$return_info->{oid_name}; } } $self->{func_oid}{$system_oid}{active}=1; $self->{func_oid}{$system_oid}{last_exec}=0; } } } } if ( $self->{func_oid}{$system_oid}{active} == 1 && $self->{func_oid}{$system_oid}{last_exec} < $self->{number_scan} ) { # we test that this function as never been executed for this equipment # We test first that this OID exist for this equipment my $oid_scan=$self->{func_oid}{$system_oid}{oid_value}; my $result=$session->get_request(-varbindlist => [ $oid_scan ] ); # We indicate that this equipment is the last scanned $self->{func_oid}{$system_oid}{last_exec}=$self->{number_scan}; if (defined ($result) && length ($result->{$oid_scan}) != 0 ){ # This OID exist, we can execute it $logger->debug("Launching $system_oid\n"); &{$self->{func_oid}{$system_oid}{snmp_run}}($session,$self); } else { $return_pm=1; } } my $return_xml=snmp_oid_xml($self,$system_oid); if ( $return_pm == 1 ) { return(1); } return($return_xml); } ######################################################### # # # function for executing sub xml with the oid # # Parameters: # # (self) # # system oid for execute the .xml associated # # # # $xml_oid->{system_oid} Ref the oid in the xml # # {active} 0 Ko 1 OK # # {xml_data} info get in xml file # # {last_exec} num for verify that # # this equipment is already scaned with this xml or no # ######################################################### sub snmp_oid_xml { my ($self,$system_oid)=@_; my $logger=$self->{logger}; my $spec_module_snmp=$self->{spec_module_snmp}; my $snmp_vardir = $self->{snmp_vardir}; if ( ! defined ( $self->{xml_oid}{$system_oid} )) { # We init the default value $self->{xml_oid}{$system_oid}={}; $self->{xml_oid}{$system_oid}{active}=0; # Can we find it in the snmp directory foreach my $dir ( @{$self->{snmp_vardir}} ) { # Can we find it in the snmp var directory if ( $self->{xml_oid}{$system_oid}{active} == 0 ) { if ( -r $dir.$system_oid.".xml" ) { # We find the xml # my $module_found=$spec_module_snmp.$system_oid; # eval "use $module_found"; if ( $self->{xml_oid}{$system_oid}{xml_data}=XML::Simple::XMLin($dir.$system_oid.".xml",ForceArray => 1 ) ) { # We have load the xml $logger->debug("Load module xml $system_oid"); $self->{xml_oid}{$system_oid}{active}=1; $self->{xml_oid}{$system_oid}{last_exec}=0; if ( defined( $self->{xml_oid}{$system_oid}{PARAMETERS}[0]{NAME}[0] ) ) { $self->{xml_oid}{$system_oid}{oid_name}=$self->{xml_oid}{$system_oid}{PARAMETERS}[0]{NAME}[0]; } } else { $logger->debug ("Failed to load xml $system_oid: $@"); $self->{xml_oid}{$system_oid}{active} = 0; } } } } } # now we have an information for the xml associated with this oid # It can be active or no if ( $self->{xml_oid}{$system_oid}{active} == 1 && $self->{xml_oid}{$system_oid}{last_exec} < $self->{number_scan} ) { $logger->debug ("Begin xml on $system_oid"); $self->{xml_oid}{$system_oid}{last_exec}=$self->{number_scan}; # We have done other scan so we can now execute own scan # We have actually only v1, we can have after other parallel version if ( xml_scan_v1($self,$system_oid,$self->{xml_oid}{$system_oid}{xml_data}) == 1 ) { $self->{xml_oid}{$system_oid}{active}=0; return 1; } return 0; } return 1; } ######################################################### # # # function for executing xml scan v1 # # Parameters: # # (self) # # system oid # # xml in input # # # ######################################################### sub xml_scan_v1 { my ($self,$system_oid,$xml)=@_; my $xmltags=$self->{context}->{common}->{xmltags}; my $logger=$self->{logger}; return 1 if ( xml_parameters_v1($self,$system_oid,$xml) == 1 ) ; if ( ! defined ($xmltags) ) { $xmltags={}; } $logger->debug("Begin scanning v1 on $system_oid"); my $filters=[]; if ( defined ($xml->{LOOPS}) ) { return 1 if ( xml_loops_v1($self,$xml->{LOOPS},$xmltags,$filters) == 1 ); } if ( defined ($xml->{DATA}) ) { return 1 if ( xml_data_v1($self,$xml->{DATA}[0],$xmltags,$filters,0) == 1 ); } return 0; } ######################################################### # # # function for parameters of xml v1 # # Parameters: # # (self) # # system oid # # xml in input # # # ######################################################### sub xml_parameters_v1 { my ($self,$system_oid,$xml)=@_; my $logger=$self->{logger}; $logger->debug("Validating xml parameters"); return 1 if ( ! defined($xml->{PARAMETERS}) ) ; return 0 if ( ! defined($xml->{PARAMETERS}[0]{EXECUTE}) ) ; # We first look if there is other scan to do $logger->debug("Begin looking other scan"); foreach my $type_exec ( "RUN","XML" ) { if ( defined( $xml->{PARAMETERS}[0]{EXECUTE}[0]{$type_exec}) ) { my $liste_exec=$xml->{PARAMETERS}[0]{EXECUTE}[0]{$type_exec}; my $lower_type_exec=lc($type_exec); foreach my $exec_perl ( @{$liste_exec} ) { my $a_exec="snmp_oid_".$lower_type_exec; $self->{$a_exec}($self,$exec_perl); } } } return 0; } ######################################################### # # # function for reading for a loops # # Parameters: # # (self) # # xml_loops (contain VALUE/INDEX/FILTER # # and a sub DATA # # result_table: pointer on where we # # put result information # # # # Return: 1 Pb # # 0 OK # ######################################################### sub xml_loops_v1 { my ($self,$xml_loops,$result_table,$filters)=@_; my $session=$self->{snmp_session}; my $logger=$self->{logger}; ALL_LOOPS: foreach my $uniq_loops ( @{$xml_loops} ) { if ( ! defined ($uniq_loops->{VALUE}) || ! defined($uniq_loops->{INDEX})|| ! defined($uniq_loops->{NAME_INDEX}) ) { $logger->debug("Error in xml File: VALUE, INDEX or NAME_INDEX not defined"); return 1 ; } # We now replace already existent filters my $data_value=$uniq_loops->{VALUE}[0]; my $index_value=$uniq_loops->{INDEX}[0]; foreach my $filter ( @{$filters} ) { $data_value=~s/$filter->{NAME}/$filter->{VALUE}/g; $index_value=~s/$filter->{NAME}/$filter->{VALUE}/g; } my $index_equipement=$session->get_entries(-columns => [ $data_value ] ); # If we have no data for this index it s not a problem in the xml next ALL_LOOPS if ( ! defined ( $index_equipement ) ) ; # We first verify if there is a filter on this value # in this case, we must filter the topic if this filter is not OK my $nbr_data=0; foreach my $uniq_index_equipement ( keys %{$index_equipement} ) { if ( defined ($uniq_loops->{FILTER}) && ! $index_equipement->{$uniq_index_equipement} =~ /$uniq_loops->{FILTER}[0]/ ) { delete $index_equipement->{$uniq_index_equipement}; # The Filter is OK, we can looks sub tables for this INDEX } elsif ( $uniq_index_equipement =~ /$index_value/ ) { # we use the index on the value for finding what are the INDEX values push(@{$filters},{VALUE=>$1,NAME=>$uniq_loops->{NAME_INDEX}[0]}); return 1 if ( xml_data_v1($self,$uniq_loops->{DATA}[0],$result_table,$filters,$nbr_data++) == 1); # After use this filter, we must take it out # so it can be used for other loops pop(@{$filters}); } } } return 0; } ######################################################### # # # function for reading for a table # # Parameters: # # (self) # # xml_line (containt SET/VALUE/FILTER # # or a sub DATA # # value_IDX for subtitution in the information # # result_table: pointer on the table where we # # put result information # # # # Return: 1 Pb # # 0 OK # ######################################################### sub xml_data_v1 { my ($self,$xml_table,$result_table,$filters,$pos_table)=@_; my $logger=$self->{logger}; foreach my $table ( keys %{$xml_table} ) { if ( $table eq "DATA" ) { foreach my $subtable ( @{$xml_table->{DATA}} ) { if ( !defined $result_table->{$subtable}[0] ) { $result_table->{$subtable}[0]={}; } return 1 if ( xml_data_v1($self,$xml_table->{$subtable},$filters,$result_table->[0]{$subtable}[0],0) == 1); } } elsif ( $table eq "LOOPS" ) { return 1 if ( xml_loops_v1($self,$xml_table->{LOOPS},$xml_table,$filters) == 1 ); } else { # we look for all lines in this table foreach my $line ( keys %{$xml_table->{$table}[0]} ) { if ( $line eq "LOOPS" ) { if ( ! defined ($result_table->{$table}[$pos_table]) ) { $result_table->{$table}[$pos_table]={}; } return 1 if ( xml_loops_v1($self,$xml_table->{$table}[0]{LOOPS},$result_table->{$table}[$pos_table],$filters) == 1 ); } else { my $result=xml_line_v1($self,$xml_table->{$table}[0]{$line}[0],$filters); if ( defined ($result) ) { $result_table->{$table}[$pos_table]{$line}[0]=$result; } } } } } return 0; } ######################################################### # # # function for reading for a uniq line in a table # # Parameters: # # (self) # # xml_line (containt SET/VALUE/FILTER # # value_IDX for subtitution in the information # # # # Return: undef if no line correct # # the string for this line in others cases # ######################################################### sub xml_line_v1 { my ($self,$xml_line,$filters)=@_; my $session=$self->{snmp_session}; return undef if ( ! defined ($xml_line) ) ; # We have a SET or a VALUE and an optional FILTER if ( defined ( $xml_line->{SET} ) ) { return($xml_line->{SET}[0]); } return undef if ( ! defined ( $xml_line->{VALUE} ) ) ; my $data_value=$xml_line->{VALUE}[0]; # If we have a loop, we must substitute the VLAUE foreach my $filter ( @{$filters} ) { $data_value=~s/$filter->{NAME}/$filter->{VALUE}/g; } # We look for information in the equipment with the snmp interogation my $info_equipment=$session->get_request(-varbindlist => [$data_value]); # We verify that information has been returned for this value return undef if ( ! defined ($info_equipment) ) ; $info_equipment=$info_equipment->{$data_value}; # Verify that we have data return undef if ( ! defined ($info_equipment) || $info_equipment eq "" ); # If there is a fliter, we verifiy that this line pass the filter return undef if ( defined ($xml_line->{FILTER}) && ! ($info_equipment =~ /$xml_line->{FILTER}[0]/ )) ; # Remplacement return $info_equipment if ( ! defined ($xml_line->{REPLACE}) ); foreach my $replace ( @{$xml_line->{REPLACE}} ) { return undef if ( ! defined( $replace->{STRING}) || ! defined ($replace->{BY}) ); $info_equipment=~s/$replace->{STRING}[0]/$replace->{BY}[0]/g; } return $info_equipment; } ######################################################### # # # function to search an IP address in netdevices array # # Parameters: # # (self) # # IP address to search # # # # Return: 1 if IP address was found # # nothing in other case # ######################################################### sub search_netdevice { my ($self,$ip)= @_ ; for (@{$self->{netdevices}}) { if ($ip =~ /^$_->{IPADDR}$/) { return 1; } } } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Modules/Snmp/000077500000000000000000000000001372663377700221455ustar00rootroot00000000000000UnixAgent-2.8/lib/Ocsinventory/Agent/Modules/Snmp/11.pm000066400000000000000000000007111372663377700227230ustar00rootroot00000000000000### # SNMP: OID:11 SYSTEM:HP ### package Ocsinventory::Agent::Modules::Snmp::11; use strict; no strict 'refs'; use warnings; sub snmp_run { my ($session,$snmp) = @_; my $common = $snmp->{common}; my $logger=$snmp->{logger}; my $list_mib=["If_Mib","Host_Resources_Mib", "Printer_Mib","Entity_Mib"]; $logger->debug("Running HP (11) MIB module"); foreach my $mib ( @{$list_mib} ) { $snmp->snmp_oid_run($mib); } } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Modules/Snmp/231.pm000066400000000000000000000006721372663377700230150ustar00rootroot00000000000000### # SNMP: OID:231 SYSTEM:Fujistu ### package Ocsinventory::Agent::Modules::Snmp::231; use strict; no strict 'refs'; use warnings; sub snmp_run { my ($session,$snmp) = @_; my $common = $snmp->{common}; my $logger=$snmp->{logger}; my $list_mib=["If_Mib","Host_Resources_Mib"]; $logger->debug("Running Fujitsu (231) MIB module"); foreach my $mib ( @{$list_mib} ) { $snmp->snmp_oid_run($mib); } } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Modules/Snmp/2620.pm000066400000000000000000000007421372663377700230770ustar00rootroot00000000000000### # SNMP: OID:2620 SYSTEM:Checkpoint ### package Ocsinventory::Agent::Modules::Snmp::2620; use strict; no strict 'refs'; use warnings; sub snmp_info { return ( { oid_value => "1.3.6.1.4.1.2620.1.1.1.0", oid_name => "Checkpoint Mib" } ); } sub snmp_run() { my ($session,$snmp) = @_; my $common = $snmp->{common}; my $logger=$snmp->{logger}; $logger->debug("Running Chekpoint (2620) MIB module"); $common->setSnmpCommons( {TYPE => "Firewall"} ); } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Modules/Snmp/311.pm000066400000000000000000000013421372663377700230070ustar00rootroot00000000000000### # SNMP: OID:311 SYSTEM:Microsoft ### package Ocsinventory::Agent::Modules::Snmp::311; use strict; no strict 'refs'; use warnings; sub snmp_info { return ( { oid_value => "1.3.6.1.4.1.77.1.2.1.0" , oid_name => "Microsoft" } ); } sub snmp_run { my ($session , $snmp )= @_; my $oid_run=$snmp->{snmp_oid_run}; my $common = $snmp->{common}; my $inventory = $snmp->{inventory}; my $logger=$snmp->{logger}; $common->setSnmpCommons( {TYPE => "Microsoft"} ); $common->setSnmpComputer({SYSTEM => 'Microsoft'}); my $list_mib=["If_Mib", "Host_Resources_Mib"]; $logger->debug("Running Microsoft (311) MIB module"); foreach my $mib ( @{$list_mib} ) { $snmp->snmp_oid_run($mib); } } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Modules/Snmp/3224.pm000066400000000000000000000011201372663377700230670ustar00rootroot00000000000000### # SNMP: OID:3224 SYSTEM:Juniper ### package Ocsinventory::Agent::Modules::Snmp::3224; use strict; no strict 'refs'; use warnings; sub snmp_info { return ( { oid_value => "1.3.6.1.4.1.3224.5.1.0", oid_name => "Juniper Mib" } ); } sub snmp_run() { my ($session,$snmp) = @_; my $common = $snmp->{common}; my $logger=$snmp->{logger}; $logger->debug("Running Juniper (3224) MIB module"); $common->setSnmpCommons( {TYPE => "Firewall"} ); my $list_mib=["If_Mib"]; foreach my $mib ( @{$list_mib} ) { $snmp->snmp_oid_run($mib); } } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Modules/Snmp/3375.pm000066400000000000000000000044151372663377700231100ustar00rootroot00000000000000### # SNMP: OID:3375 SYSTEM:F5 ### package Ocsinventory::Agent::Modules::Snmp::3375; use strict; no strict 'refs'; use warnings; sub snmp_info { return ( { oid_value => "1.3.6.1.4.1.3375.2.1.1.1.1.1.0", oid_name => "F5 Mib" } ); } sub snmp_run() { my ($session,$snmp) = @_; my $common = $snmp->{common}; my $logger=$snmp->{logger}; $logger->debug("Running F5 (3375) MIB module"); $common->setSnmpCommons( {TYPE => "Load Balanceur"} ); my $list_mib=["If_Mib"]; foreach my $mib ( @{$list_mib} ) { $snmp->snmp_oid_run($mib); } my $snmp_sysProductName="1.3.6.1.4.1.3375.2.1.4.1.0"; my $snmp_sysProductVersion="1.3.6.1.4.1.3375.2.1.4.2.0"; my $snmp_sysProductBuild="1.3.6.1.4.1.3375.2.1.4.3.0"; my $snmp_sysProductDate="1.3.6.1.4.1.3375.2.1.4.5.0"; my $snmp_sysGeneralHwNumber="1.3.6.1.4.1.3375.2.1.3.3.2.0"; my $snmp_sysGeneralChassisSerialNum="1.3.6.1.4.1.3375.2.1.3.3.3.0"; my $NAME=$session->get_request ( -varbindlist => [ $snmp_sysProductName ] ); if ( defined ( $NAME ) ) { $NAME=$NAME->{$snmp_sysProductName}; } my $VERSION=$session->get_request ( -varbindlist => [ $snmp_sysProductVersion] ); if ( defined ( $VERSION ) ) { $VERSION=$VERSION->{$snmp_sysProductVersion}; } my $COMMENT=$session->get_request ( -varbindlist => [ $snmp_sysProductBuild] ); if ( defined ( $COMMENT ) ) { $COMMENT=$COMMENT->{$snmp_sysProductBuild}; } my $DATE=$session->get_request ( -varbindlist => [ $snmp_sysProductDate ] ); if ( defined ( $DATE ) ) { $DATE=$DATE->{$snmp_sysProductDate}; } $common->addSoftware( { NAME => $NAME , VERSION => $VERSION , INSTALLDATE => $DATE , COMMENT => $COMMENT, }); my $TYPE=$session->get_request ( -varbindlist => [ $snmp_sysGeneralHwNumber ] ) ; if ( defined ( $TYPE ) ) { $TYPE=$TYPE->{$snmp_sysGeneralHwNumber}; } my $SERIALNUMBER=$session->get_request ( -varbindlist => [ $snmp_sysGeneralChassisSerialNum ] ) ; if ( defined ( $SERIALNUMBER ) ) { $SERIALNUMBER=$SERIALNUMBER->{$snmp_sysGeneralChassisSerialNum}; } $common->setSnmpLoadBalancer({ SERIALNUMBER => $SERIALNUMBER , TYPE => $TYPE , MANUFACTURER => "F5" , }); } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Modules/Snmp/42.pm000066400000000000000000000006441372663377700227340ustar00rootroot00000000000000### # SNMP: OID:42 SYSTEM:Sun ### package Ocsinventory::Agent::Modules::Snmp::42; use strict; no strict 'refs'; use warnings; sub snmp_run() { my ($session,$snmp) = @_; my $common = $snmp->{common}; my $logger=$snmp->{logger}; $logger->debug("Running Sun (42) MIB module"); $common->setSnmpCommons( {TYPE => "Sun"} ); $common->setSnmpComputer({SYSTEM => 'Sun'}); } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Modules/Snmp/641.pm000066400000000000000000000007111372663377700230140ustar00rootroot00000000000000### # SNMP: OID:641 SYSTEM:Lexmark ### package Ocsinventory::Agent::Modules::Snmp::641; use strict; no strict 'refs'; use warnings; sub snmp_run { my ($session,$snmp) = @_; my $common = $snmp->{common}; my $logger=$snmp->{logger}; my $list_mib=["If_Mib","Host_Resources_Mib", "Printer_Mib"]; $logger->debug("Running Lexmark (641) MIB module"); foreach my $mib ( @{$list_mib} ) { $snmp->snmp_oid_run($mib); } } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Modules/Snmp/7244.pm000066400000000000000000000007261372663377700231100ustar00rootroot00000000000000### # SNMP: OID:7244 SYSTEM:Fujitsu ### package Ocsinventory::Agent::Modules::Snmp::7244; use strict; no strict 'refs'; use warnings; sub snmp_info { return ( { oid_value => "1.3.6.1.4.1.7244.1.1.1.1.1.0", oid_name => "Fujitsu" } ); } sub snmp_run() { my ($session,$snmp) = @_; my $common = $snmp->{common}; my $logger=$snmp->{logger}; $logger->debug("Running Fujitsu (7244) MIB module"); $common->setSnmpCommons( {TYPE => "Blade"} ); } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Modules/Snmp/789.pm000066400000000000000000000056201372663377700230350ustar00rootroot00000000000000### # SNMP: OID:789 SYSTEM:NetApp ### package Ocsinventory::Agent::Modules::Snmp::789; use strict; no strict 'refs'; use warnings; sub snmp_run() { my ($session,$snmp) = @_; my $common = $snmp->{common}; my $logger=$snmp->{logger}; $logger->debug("Running NetApp (789) MIB module"); $common->setSnmpCommons( {TYPE => "Storage"} ); my $list_mib=["If_Mib"]; foreach my $mib ( @{$list_mib} ) { $snmp->snmp_oid_run($mib); } my $snmp_sysProductName="1.3.6.1.4.1.789.1.1.5.0"; my $snmp_sysProductVersion="1.3.6.1.4.1.789.1.1.2.0"; my $snmp_sysProductBuild="1.3.6.1.4.1.789.1.1.3.0"; my $snmp_volumetable="1.3.6.1.4.1.789.1.5.4.1.2"; my $snmp_storageSize="1.3.6.1.4.1.789.1.5.4.1.29."; my $snmp_storageUsed="1.3.6.1.4.1.789.1.5.4.1.30."; my $name=$session->get_request ( -varbindlist => [ $snmp_sysProductName ] ); if ( defined ( $name ) ) { $name=$name->{$snmp_sysProductName}; } my $version=$session->get_request ( -varbindlist => [ $snmp_sysProductVersion] ); if ( defined ( $version ) ) { $version=$version->{$snmp_sysProductVersion}; } my $comment=$session->get_request ( -varbindlist => [ $snmp_sysProductBuild] ); if ( defined ( $comment ) ) { $comment=$comment->{$snmp_sysProductBuild}; } $common->addSoftware( { NAME => $name , VERSION => $version , COMMENT => $comment, }); my $result; my $result_table; my $ref; # We look for volumes $result_table=$session->get_entries(-columns => [ $snmp_volumetable ]); foreach my $result ( keys %{$result_table} ) { if ( $result =~ /1\.3\.6\.1\.4\.1\.789\.1\.5\.4\.1\.2\.(\S+)/ ) { $ref=$1; # Definition Var for disks my $FREE=""; my $FILESYSTEM=""; my $TOTAL=""; $TOTAL=$session->get_request(-varbindlist => [ $snmp_storageSize.$ref ]); if ( defined ( $TOTAL ) ) { $TOTAL=$TOTAL->{$snmp_storageSize.$ref}; } #print $TOTAL, " "; $FREE=$session->get_request(-varbindlist => [ $snmp_storageUsed.$ref ]); if ( defined ( $FREE ) ) { $FREE=$TOTAL - $FREE->{$snmp_storageUsed.$ref}; } #print $FREE, " "; $FILESYSTEM=$session->get_request(-varbindlist => [ $snmp_volumetable."\.".$ref ]); #print $snmp_volumetable."\.".$ref, " "; if ( defined ( $FILESYSTEM) ) { $FILESYSTEM=$FILESYSTEM->{$snmp_volumetable."\.".$ref}; } #print $FILESYSTEM, "\n"; $common->addDrive( { FILESYSTEM => $FILESYSTEM , FREE => $FREE, TOTAL => $TOTAL, }), } # End index of the element } # End foreach storages } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Modules/Snmp/8072.pm000066400000000000000000000030061372663377700231020ustar00rootroot00000000000000### # SNMP: OID:8072 SYSTEM:Linux ### package Ocsinventory::Agent::Modules::Snmp::8072; use strict; no strict 'refs'; use warnings; sub snmp_run() { my ($session,$snmp) = @_; my $common = $snmp->{common}; my $logger=$snmp->{logger}; my $snmp_nom="1.3.6.1.2.1.1.5.0"; my $list_mib=["If_Mib", "Host_Resources_Mib"]; $logger->debug("Running Linux (8072) MIB module"); $common->setSnmpCommons( {TYPE => "Linux"} ); $common->setSnmpComputer({SYSTEM => 'Linux'}); foreach my $mib ( @{$list_mib} ) { $snmp->snmp_oid_run($mib); } my $snmp_oids="1.3.6.1.4.1.8072.1.2.1.1.4"; my $list_oid_done={8072 => 1}; my $result; my $results_oids=$session->get_next_request(-varbindlist => [$snmp_oids]) ; while ( defined ($results_oids ) ) { foreach $result ( keys %{$results_oids} ) { $snmp_oids=$result; if ( defined ( $results_oids->{$result} ) ) { if ( $results_oids->{$result} =~ /endOfMibView/ ) { $snmp_oids=undef; } elsif ( $result =~ /^1\.3\.6\.1\.4\.1\.8072\.1\.2\.1\.1\.4\S+\.1\.3\.6\.1\.4\.1\.(\d+)\./ ) { my $find_oid=$1; if ( ! defined $list_oid_done->{$find_oid} ) { $list_oid_done->{$find_oid}=1; $snmp->snmp_oid_run($find_oid); } } } } $results_oids=$session->get_next_request(-varbindlist => [$snmp_oids]) ; } } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Modules/Snmp/9.pm000066400000000000000000000317471372663377700226670ustar00rootroot00000000000000### # SNMP: OID: 9 SYSTEM: Cisco ### # Version 1.1 ### package Ocsinventory::Agent::Modules::Snmp::9; use strict; use warnings; use Data::Dumper; sub snmp_run { my ($session , $snmp )= @_; my $logger=$snmp->{logger}; my $common=$snmp->{common}; my $list_mib=["Entity_Mib"]; $logger->debug("Running Cisco (9) MIB module"); foreach my $mib ( @{$list_mib} ) { $snmp->snmp_oid_run($mib); } # OID my $snmp_osversion="1.3.6.1.4.1.9.2.1.73.0"; my $snmp_dot1dBasePortIfIndex="1.3.6.1.2.1.17.1.4.1.2."; my $snmp_ifdesc="1.3.6.1.2.1.2.2.1.2."; my $snmp_iftype="1.3.6.1.2.1.2.2.1.3"; my $snmp_ifspeed="1.3.6.1.2.1.2.2.1.5."; my $snmp_physAddr="1.3.6.1.2.1.2.2.1.6."; my $snmp_ifadminstatus="1.3.6.1.2.1.2.2.1.7."; # Specific Cisco my $snmp_description="1.3.6.1.4.1.9.2.2.1.1.28."; my $snmp_cisco_deviceAddress="1.3.6.1.4.1.9.9.23.1.2.1.1.4."; my $snmp_cisco_deviceId="1.3.6.1.4.1.9.9.23.1.2.1.1.6."; my $snmp_cisco_devicePort="1.3.6.1.4.1.9.9.23.1.2.1.1.7."; my $snmp_cisco_devicePlatform="1.3.6.1.4.1.9.9.23.1.2.1.1.8."; my $snmp_vtp_vlan_state="1.3.6.1.4.1.9.9.46.1.3.1.1.2"; my $snmp_dot1dTpFdbPort="1.3.6.1.2.1.17.4.3.1.2"; my $snmp_cisco_ImageTable="1.3.6.1.4.1.9.9.25.1.1.1.2.4"; my $snmp_cisco_ImageVersion="1.3.6.1.4.1.9.9.25.1.1.1.2.5"; my $snmp_cisco_cpmProcessName="1.3.6.1.4.1.9.9.109.1.2.1.1.2"; my $snmp_cisco_cpmProcessCPU="1.3.6.1.4.1.9.9.109.1.2.1.1.6."; my $oid; my $oid_complet; my $osversion; my $ref; my $serial; my $first_serial=undef; my $software; my $firmware; my $location; my $TotalEthernet=0; my $result_snmp; my $result_sub; my $index_mac={}; my $ref_mac={}; my $DESCRIPTION=undef; my $SPEED=undef; my $MACADDR=undef; my $DEVICEMACADDR=undef; my $SLOT=undef; my $STATUS=undef; my $TYPE=undef; my $DEVICENAME=undef; my $DEVICEADDRESS=undef; my $DEVICEPORT=undef; my $DEVICETYPE=undef; my $VLAN=undef; my $CPU=undef; $common->setSnmpCommons( {TYPE => "Network"} ); # Info interessante SNMPv2-SMI::enterprises.9.9.23.1.2.1.1.6.10140.1 # SNMPv2-SMI::enterprises.9.9.25.1.1.1.2.1 # version IOS $result_snmp=$session->get_request(-varbindlist => [$snmp_osversion]); if ( defined($result_snmp->{$snmp_osversion}) ) { $osversion=$result_snmp->{$snmp_osversion}; } # We are going to look for the vlan existing on this equipment $result_snmp=$session->get_entries(-columns => [$snmp_vtp_vlan_state]); foreach my $resultmac ( keys %{$result_snmp} ) { if ( $resultmac =~ /1\.3\.6\.1\.4\.1\.9\.9\.46\.1\.3\.1\.1\.2\.1\.(\S+)/ ) { my $ref_vlan=$1; my $sub_session; # Now we can scan this vlan for mac address # We must first open a new session with the index associated with the vlan if ( $session->version eq 3 ) { $sub_session= Net::SNMP->session( -retries => 1 , -timeout => 3, -version => $session->version, -hostname => $session->hostname, -community => $snmp->{snmp_community}."@".$ref_vlan, -translate => [-nosuchinstance => 0, -nosuchobject => 0], -username => $snmp->{USER}, -authpassword => $snmp->{AUTHPASSWD}, -authprotocol => $snmp->{AUTHPROTO}, -privpassword => $snmp->{PRIVPASSWD}, -privprotocol => $snmp->{PRIVPROTO}, ); } else { $sub_session= Net::SNMP->session( -retries => 1 , -timeout => 3, -version => $session->version, -hostname => $session->hostname, -community => $snmp->{snmp_community}."@".$ref_vlan, -translate => [-nosuchinstance => 0, -nosuchobject => 0], ); } if ( defined ( $sub_session ) ) { my $result_snmp_mac=$sub_session->get_entries(-columns => [$snmp_dot1dTpFdbPort ]); if ( defined ($result_snmp_mac ) ) { # We scan all lines for my $ligne_snmp_mac ( keys %{$result_snmp_mac} ) { # We first take in the OID the 6 last numbers indicate in decimal the mac address if ( $ligne_snmp_mac =~ /17\.4\.3\.1\.2\.(\S+)\.(\S+)\.(\S+)\.(\S+)\.(\S+)\.(\S+)$/ ) { my $distant_mac=sprintf("%.2x:%.2x:%.2x:%.2x:%.2x:%.2x",$1,$2,$3,$4,$5,$6); my $data_values={}; my $index_bridge=$result_snmp_mac->{$ligne_snmp_mac}; # We have no table for this reference if ( ! defined ( $index_mac->{$index_bridge}) ) { # init of the table $index_mac->{$index_bridge}=[]; # we take the value gived by the OID my $snmp_intero=$snmp_dot1dBasePortIfIndex.$index_bridge; # We take the index reference for the ifdesc # So when we scan this ifdesc, we can add the vlans and mac my $ref_snmp_line=$sub_session->get_request(-varbindlist => [ $snmp_intero ]); # We transmit the ointer value to the ref_mac so we can have a double access for the data # If we have no information: the mac is not associated with a port # It's the switch mac address if ( defined ( $ref_snmp_line->{$snmp_intero}) ) { $ref_mac->{$ref_snmp_line->{$snmp_intero}}=$index_mac->{$index_bridge}; } } $data_values->{MACADRESS}[0]=$distant_mac; $data_values->{VLANID}[0]=$ref_vlan; push(@{$index_mac->{$result_snmp_mac->{$ligne_snmp_mac}}},$data_values); } } } $sub_session->close; } } } # We look for interfaces $result_snmp=$session->get_entries(-columns => [$snmp_iftype]); foreach my $result ( keys %{$result_snmp} ) { # We work on real interface and no vlan if ( $result_snmp->{$result} == 6 ) { if ( $result =~ /1\.3\.6\.1\.2\.1\.2\.2\.1\.3\.(\S+)/ ) { $ref=$1; $TYPE="ethernetCsmacd"; $SLOT=$session->get_request(-varbindlist => [$snmp_ifdesc.$ref]); if ( defined( $SLOT->{$snmp_ifdesc.$ref} ) ) { $SLOT=$SLOT->{$snmp_ifdesc.$ref}; } $SPEED=$session->get_request(-varbindlist => [$snmp_ifspeed.$ref]); if ( defined( $SPEED->{$snmp_ifspeed.$ref}) ) { $SPEED=$SPEED->{$snmp_ifspeed.$ref}; if ( $SPEED / 1000000000000 >= 1 ) { $SPEED=$SPEED / 1000000000000; $SPEED=$SPEED." T"; } elsif ( $SPEED / 1000000000 >= 1 ) { $SPEED=$SPEED / 1000000000; $SPEED=$SPEED." G"; } elsif ( $SPEED / 1000000 >= 1 ) { $SPEED=$SPEED / 1000000; $SPEED=$SPEED." M"; } } $MACADDR=$session->get_request(-varbindlist => [$snmp_physAddr.$ref]); if ( defined( $MACADDR->{$snmp_physAddr.$ref}) ) { # For MACADDR, we need a translation beetween Hexa and string $MACADDR=$MACADDR->{$snmp_physAddr.$ref}; if ( length ($MACADDR) == 14 ) { $MACADDR=substr($MACADDR,2,2).":". substr($MACADDR,4,2).":". substr($MACADDR,6,2).":". substr($MACADDR,8,2).":". substr($MACADDR,10,2).":". substr($MACADDR,12,2); } else { $MACADDR=""; } } if ( defined $ref_mac->{$ref} ) { $VLAN=$ref_mac->{$ref}; } $STATUS=$session->get_request(-varbindlist => [ $snmp_ifadminstatus.$ref ]); if ( $STATUS->{$snmp_ifadminstatus.$ref} == 1 ) { $STATUS="Up"; } else { $STATUS="Down"; } $DESCRIPTION=$session->get_request(-varbindlist => [ $snmp_description.$ref ]); if ( defined( $DESCRIPTION ) ) { $DESCRIPTION=$DESCRIPTION->{$snmp_description.$ref}; } $DEVICEADDRESS=$session->get_entries( -columns => [ $snmp_cisco_deviceAddress.$ref ] ); if ( defined( $DEVICEADDRESS ) ) { my $DEVICEADDRESS_uniq; foreach my $key ( keys %{$DEVICEADDRESS} ) { $DEVICEADDRESS_uniq=$DEVICEADDRESS->{$key} ; if ( length ( $DEVICEADDRESS_uniq ) == 10 ) { $DEVICEADDRESS_uniq=hex(substr($DEVICEADDRESS_uniq,2,2)). ".".hex(substr($DEVICEADDRESS_uniq,4,2)). ".".hex(substr($DEVICEADDRESS_uniq,6,2)). ".".hex(substr($DEVICEADDRESS_uniq,8,2)); } else { $DEVICEADDRESS_uniq=undef; } } $DEVICEADDRESS=$DEVICEADDRESS_uniq; } $DEVICENAME=$session->get_entries( -columns => [ $snmp_cisco_deviceId.$ref ] ); if ( defined( $DEVICENAME ) ) { my $DEVICENAME_uniq; my $DEVICETYPE_uniq; my $DEVICEPORT_uniq; foreach my $key ( keys %{$DEVICENAME} ) { $DEVICENAME_uniq=$DEVICENAME->{$key}; } $DEVICENAME=$DEVICENAME_uniq; # If we have the device name, the cdp can be used for the other informations $DEVICETYPE=$session->get_entries( -columns => [ $snmp_cisco_devicePlatform.$ref ] ); if ( defined( $DEVICETYPE ) ) { foreach my $key ( keys %{$DEVICETYPE} ) { $DEVICETYPE_uniq=$DEVICETYPE->{$key}; } $DEVICETYPE=$DEVICETYPE_uniq; } $DEVICEPORT=$session->get_entries( -columns => [ $snmp_cisco_devicePort.$ref ] ); if ( defined( $DEVICEPORT ) ) { foreach my $key ( keys %{$DEVICEPORT} ) { $DEVICEPORT_uniq=$DEVICEPORT->{$key}; } $DEVICEPORT=$DEVICEPORT_uniq; } } } $common->addSnmpNetwork( { DESCRIPTION => $DESCRIPTION, SPEED => $SPEED, MACADDR => $MACADDR, SLOT => $SLOT, STATUS => $STATUS, TYPE => $TYPE, DEVICENAME => $DEVICENAME, DEVICEADDRESS => $DEVICEADDRESS, DEVICEPORT => $DEVICEPORT, DEVICETYPE => $DEVICETYPE, VLAN => $VLAN, }); $DESCRIPTION=undef; $MACADDR=undef; $SLOT=undef; $STATUS=undef; $TYPE=undef; $SPEED=undef; $MACADDR=undef; $DEVICEADDRESS=undef; $DEVICENAME=undef; $DEVICEPORT=undef; $DEVICETYPE=undef; $VLAN=undef; } } # We have finished for interfaces # We look for Softwares on the switch # We look for feature # All feature are separated by a pipe $result_snmp=$session->get_request ( -varbindlist => [ $snmp_cisco_ImageTable ]) ; if ( defined ( $result_snmp ) ) { $result_snmp=$result_snmp->{$snmp_cisco_ImageTable}; my @tab_feature=split(/\$/,$result_snmp); @tab_feature=split(/\|/,$tab_feature[1]); foreach $result_sub ( @tab_feature ) { $common->addSoftware( { NAME => $result_sub , COMMENTS => "Feature" } ); } } # We look for IOS version $result_snmp=$session->get_request ( -varbindlist => [ $snmp_cisco_ImageVersion ]) ; if ( defined ( $result_snmp ) ) { $result_snmp=$result_snmp->{$snmp_cisco_ImageVersion}; my @tab_feature=split(/\$/,$result_snmp); $common->addSoftware( { NAME => $tab_feature[1] , COMMENTS => "IOS" } ); } } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Modules/Snmp/Default.pm000066400000000000000000000007511372663377700240720ustar00rootroot00000000000000### # SNMP: Default ### package Ocsinventory::Agent::Modules::Snmp::Default; use strict; no strict 'refs'; use warnings; sub snmp_run { my ($session , $snmp )= @_; my $oid_run=$snmp->{snmp_oid_run}; my $inventory = $snmp->{inventory}; my $logger=$snmp->{logger}; my $list_mib=["If_Mib", "Host_Resources_Mib","Printer_Mib"]; $logger->debug("Running Default MIB module \n"); foreach my $mib ( @{$list_mib} ) { $snmp->snmp_oid_run($mib); } } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Modules/Snmp/Entity_Mib.pm000066400000000000000000000114071372663377700245510ustar00rootroot00000000000000### # SNMP: OID: 47 SYSTEM: Entity_Mib ### # Version 0.5 ### package Ocsinventory::Agent::Modules::Snmp::Entity_Mib; use strict; use warnings; sub snmp_run { my ($session , $snmp )= @_; my $logger=$snmp->{logger}; my $common=$snmp->{common}; $logger->debug("Running Entity MIB module"); # OID my $snmp_entPhysicalClass="1.3.6.1.2.1.47.1.1.1.1.5"; my $translation_entPhysicalClass={ #1 => "other", #2 => "unknown", 3 => "chassis", 4 => "backplane", #5 => "container", 6 => "powerSupply", 7 => "fan", #8 => "sensor", 9 => "module", #10 => "port", #11 => "stack", #12 => "cpu", }; my $result_snmp; my $result; my $nbr_switch=0; # We are looking for physical elements $result_snmp=$session->get_entries(-columns => [$snmp_entPhysicalClass]); foreach my $result ( keys %{$result_snmp} ) { if ( $result =~ /1\.3\.6\.1\.2\.1\.47\.1\.1\.1\.1\.5\.(\S+)/ ) { my $ref=$1; my $PhysicalClass=$result_snmp->{$snmp_entPhysicalClass.".".$ref}; my $info = {}; if ( $PhysicalClass =~ /^[3,4,6,7,9,11]$/ ) { info_element($info,$session,$ref,$logger); $info->{TYPE}=$translation_entPhysicalClass->{$PhysicalClass}; if ( $PhysicalClass == 3 ) { # We have a switch $nbr_switch++; $common->addSnmpSwitch( $info ); # Infos for a switch: DESCRIPTION, REFERENCE, REVISION, FIRMWARE, SERIALNUMBER, MANUFACTURER, TYPE } elsif ( $PhysicalClass == 4 ) { # Infos for the backplane : DESCRIPTION, FIRMWARE MANUFACTURER REFERENCE SERIALNUMBER TYPE $common->addSnmpBackPlane( $info ); } elsif ( $PhysicalClass == 6 ) { # Infos for an alimentation DESCRIPTION, REFERENCE, REVISION, SERIALNUMBER, MANUFACTURER, TYPE $common->addSnmpPowerSupply( $info ); } elsif ( $PhysicalClass == 7 ) { # Infos for a Fan: DESCRIPTION, REFERENCE, REVISION, SERIALNUMBER, MANUFACTURER, TYPE $common->addSnmpFan( $info ); } elsif ( $PhysicalClass == 9 && defined ($info->{SERIALNUMBER}) ) { if ( ! ($info->{DESCRIPTION} =~ /[CF]PU/ )) { # Infor for a card: DESCRIPTION, REFERENCE, REVISION, FIRMWARE, SOFTWARE, SERIALNUMBER, MANUFACTURER, TYPE $common->addSnmpCard( $info ); } } } } } # We have scaned all equipment, we know now if we have a switch or a stack of switch if ( $nbr_switch == 1 ) { $common->setSnmpSwitchInfos({TYPE=>"Switch"}); } elsif ( $nbr_switch > 1 ) { $common->setSnmpSwitchInfos({TYPE=>"Switchs Stack"}); } } sub info_element(){ my ($info ,$session, $ref, $logger)=@_; my $snmp_info="1.3.6.1.2.1.47.1.1.1.1.2."; my $snmp_ref="1.3.6.1.2.1.47.1.1.1.1.7."; my $snmp_hardware="1.3.6.1.2.1.47.1.1.1.1.8."; my $snmp_firmware="1.3.6.1.2.1.47.1.1.1.1.9."; my $snmp_software="1.3.6.1.2.1.47.1.1.1.1.10."; my $snmp_serial="1.3.6.1.2.1.47.1.1.1.1.11."; my $snmp_entPhysicalMfgName="1.3.6.1.2.1.47.1.1.1.1.12."; my $snmp_entPhysicalModelName="1.3.6.1.2.1.47.1.1.1.1.13."; my $result; # We have a good element $result=$session->get_request(-varbindlist => [$snmp_info.$ref]); if ( defined( $result) ) { $info->{DESCRIPTION} = $result->{$snmp_info.$ref}; } $result=$session->get_request(-varbindlist => [$snmp_ref.$ref]); if ( defined( $result ) ) { $info->{REFERENCE} = $result->{$snmp_ref.$ref}; } $result=$session->get_request(-varbindlist => [$snmp_hardware.$ref]); if ( defined( $result ) ) { $info->{REVISION} = $result->{$snmp_hardware.$ref}; } $result=$session->get_request(-varbindlist => [$snmp_serial.$ref]); if ( defined( $result ) ) { $info->{SERIALNUMBER} = $result->{$snmp_serial.$ref}; } $result=$session->get_request(-varbindlist => [$snmp_firmware.$ref]); if ( defined( $result) ) { $info->{FIRMWARE} = $result->{$snmp_firmware.$ref}; } $result=$session->get_request(-varbindlist => [$snmp_software.$ref]); if ( defined( $result ) ) { $info->{SOFTWARE} = $result->{$snmp_software.$ref}; } $result=$session->get_request(-varbindlist => [$snmp_entPhysicalMfgName.$ref]); if ( defined( $result ) ) { $info->{MANUFACTURER} = $result->{$snmp_entPhysicalMfgName.$ref}; } $result=$session->get_request(-varbindlist => [$snmp_entPhysicalModelName.$ref]); if ( defined( $result ) ) { $info->{TYPE} = $result->{$snmp_entPhysicalModelName.$ref}; } } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Modules/Snmp/Host_Resources_Mib.pm000066400000000000000000000232671372663377700262530ustar00rootroot00000000000000package Ocsinventory::Agent::Modules::Snmp::Host_Resources_Mib; use strict; use warnings; sub snmp_info { return ( { oid_value => "1.3.6.1.2.1.25.1.1.0", oid_name => "Host_Resources_Mib" } ); } sub snmp_run { my ($session , $snmp )= @_; my $logger=$snmp->{logger}; my $common=$snmp->{common}; $logger->debug("Running Host Resources MIB module"); # OID my $soft="1.3.6.1.2.1.25.6.3.1."; my $memory="1.3.6.1.2.1.25.2.2.0"; my $snmp_storageType="1.3.6.1.2.1.25.2.3.1.2"; my $snmp_storageDescr="1.3.6.1.2.1.25.2.3.1.3."; my $snmp_storageSize="1.3.6.1.2.1.25.2.3.1.5."; my $snmp_storageUsed="1.3.6.1.2.1.25.2.3.1.6."; my $snmp_storageAllocationUnits="1.3.6.1.2.1.25.2.3.1.4."; my $snmp_hrDeviceType="1.3.6.1.2.1.25.3.2.1.2"; my $snmp_cpu="1.3.6.1.2.1.25.3.2.1.3."; my $snmp_Printer="1.3.6.1.2.1.25.3.2.1.5."; my $snmp_Video="1.3.6.1.2.1.25.3.2.1.10."; my $snmp_Audio="1.3.6.1.2.1.25.3.2.1.11."; my $snmp_Keyboard="1.3.6.1.2.1.25.3.2.1.13."; my $snmp_Modem="1.3.6.1.2.1.25.3.2.1.14."; my $snmp_ParallelPort="1.3.6.1.2.1.25.3.2.1.15."; my $snmp_Pointing="1.3.6.1.2.1.25.3.2.1.16."; my $snmp_SerialPort="1.3.6.1.2.1.25.3.2.1.17."; my $DATE; my $result; my $result_table; my $ref; $result_table=$session->get_entries(-columns => [ $soft."2" ] ); foreach my $result ( keys %{$result_table} ) { if ( $result =~ /1\.3\.6\.1\.2\.1\.25\.6\.3\.1\.2\.(\S+)/ ) { $ref=$1; $DATE=$session->get_request ( -varbindlist => [ $soft."5.".$ref ]); if ( defined ( $DATE ) ) { $DATE=$DATE->{$soft."5.".$ref}; if ( defined ($DATE ) ) { if (length($DATE)>0) { $DATE=sprintf("%d/%d/%d",hex(substr($DATE,2,4)),hex(substr($DATE,6,2)),hex(substr($DATE,8,2))); } } } $common->addSoftware( { NAME=>$result_table->{ $result } , INSTALLDATE=>$DATE } ); } } # Memory $result=$session->get_request(-varbindlist => [ $memory ]); if ( defined ($result) ) { $common->addMemory( {CAPACITY => $result->{$memory} } ); } # We look for disk $result_table=$session->get_entries(-columns => [ $snmp_storageType ]); foreach my $result ( keys %{$result_table} ) { if ( $result =~ /1\.3\.6\.1\.2\.1\.25\.2\.3\.1\.2\.(\S+)/ ) { $ref=$1; # We look if the storage is a fixed disk if ( $result_table->{$result} =~ /2\.1\.4$/ ) { # Definition Var for disks my $FREE=""; my $FILESYSTEM=""; my $LABEL=""; my $SERIAL=""; my $TOTAL=""; my $TYPE="HardDisk"; my $VOLUMN=""; my $AllocUnits=$session->get_request(-varbindlist => [ $snmp_storageAllocationUnits.$ref ]); if ( defined ( $AllocUnits ) ) { $AllocUnits=$AllocUnits->{$snmp_storageAllocationUnits.$ref}; # Allocation Units are in Bytes, but we want KB if ( $AllocUnits ) { $AllocUnits/=1024; } } else { $AllocUnits=1; } $TOTAL=$session->get_request(-varbindlist => [ $snmp_storageSize.$ref ]); if ( defined ( $TOTAL ) ) { $TOTAL=$TOTAL->{$snmp_storageSize.$ref}; $TOTAL*=$AllocUnits; } else { $TOTAL=0; } $FREE=$session->get_request(-varbindlist => [ $snmp_storageUsed.$ref ]); if ( defined ( $FREE ) ) { $FREE=$TOTAL - $FREE->{$snmp_storageUsed.$ref}* $AllocUnits; } else { $FREE=0; } $FILESYSTEM=$session->get_request(-varbindlist => [ $snmp_storageDescr.$ref ]); if ( defined ( $FILESYSTEM) ) { $FILESYSTEM=$FILESYSTEM->{$snmp_storageDescr.$ref}; } if ( $FILESYSTEM =~ /(\S+)\s+Label:(\S+)\s+Serial Number\s+(\S+)/ ) { $VOLUMN=$1; $LABEL=$2; $SERIAL=$3; $FILESYSTEM=""; } elsif ( $FILESYSTEM =~ /(\S+)\s+Label:\s+Serial Number\s+(\S+)/ ) { $VOLUMN=$1; $SERIAL=$2; $FILESYSTEM=""; } $common->addDrive( { FILESYSTEM => $FILESYSTEM , VOLUMN => $VOLUMN, TYPE => $TYPE, LABEL => $LABEL, SERIAL => $SERIAL, FREE => $FREE, TOTAL => $TOTAL, }), } # End looking for fixed disk } # End index of the element } # End foreach storages $result_table=$session->get_entries(-columns => [ $snmp_hrDeviceType ]); foreach my $result ( keys %{$result_table} ) { if ( $result =~ /1\.3\.6\.1\.2\.1\.25\.3\.2\.1\.2\.(\S+)/ ) { $ref=$1; if ( $result_table->{$result} =~ /3\.1\.3$/ ) { # We have a CPU my $CPU=$session->get_request(-varbindlist => [ $snmp_cpu.$ref ] ); if ( defined ( $CPU ) ) { $CPU=$CPU->{$snmp_cpu.$ref}; my $TYPE=$CPU; my $MANUFACTURER=""; my $SPEED=""; if ( $CPU =~ /^Intel$/ ) { # We have a windows system and for all processor # it say Intel even if the proc is an AMD $MANUFACTURER="x86 Manufacturer"; $TYPE="x86"; } elsif ( $CPU =~ /[Ii]nte/ ) { $MANUFACTURER="Intel"; if ( $CPU =~ /\s+(\S+[GM][Hh][zZ])/ ) { $SPEED=$1; } } elsif ( $CPU =~ /AMD/ ) { $MANUFACTURER="AMD"; if ( $CPU =~ /\s+(\S+\+)/ ) { $SPEED=$1; } } $logger->debug("Speed $SPEED Manufacturer $MANUFACTURER Type $TYPE"); $common->addSnmpCPU( { SPEED => $SPEED, TYPE => $TYPE, MANUFACTURER => $MANUFACTURER, } ); } } } #end CPU elsif ( $result_table->{$result} =~ /3\.1\.5$/ ) { # We have a Printer my $NAME=$session->get_request(-varbindlist => [ $snmp_Printer.$ref ] ); if ( defined ($NAME) ) { $NAME=$NAME->{$snmp_Printer.$ref }; $common->addSnmpLocalPrinter( { NAME => $NAME } ); } } # End Printer elsif ( $result_table->{$result} =~ /3\.1\.13$/ ) { # We have a Keyboard my $DESCRIPTION=$session->get_request(-varbindlist => [ $snmp_Keyboard.$ref ] ); if ( defined ($DESCRIPTION) ) { $DESCRIPTION=$DESCRIPTION->{$snmp_Keyboard.$ref }; $common->addSnmpInput( { DESCRIPTION => $DESCRIPTION , TYPE => "Keyboard" } ); } } # End Keyboard elsif ( $result_table->{$result} =~ /3\.1\.16$/ ) { # We have a Pointing my $DESCRIPTION=$session->get_request(-varbindlist => [ $snmp_Pointing.$ref ] ); if ( defined ($DESCRIPTION) ) { $DESCRIPTION=$DESCRIPTION->{$snmp_Pointing.$ref }; $common->addSnmpInput( { DESCRIPTION => $DESCRIPTION , TYPE => "Mouse" } ); } } # End Pointing elsif ( $result_table->{$result} =~ /3\.1\.11$/ ) { # We have a Audio my $NAME=$session->get_request(-varbindlist => [ $snmp_Audio.$ref ] ); if ( defined ($NAME) ) { $NAME=$NAME->{$snmp_Audio.$ref }; $common->addSound( { NAME => $NAME } ); } } # End Audio elsif ( $result_table->{$result} =~ /3\.1\.10$/ ) { # We have a Video my $NAME=$session->get_request(-varbindlist => [ $snmp_Video.$ref ] ); if ( defined ($NAME) ) { $NAME=$NAME->{$snmp_Video.$ref }; $common->addVideo( { NAME => $NAME } ); } } # End Video elsif ( $result_table->{$result} =~ /3\.1\.14$/ ) { # We have a Modem my $NAME=$session->get_request(-varbindlist => [ $snmp_Modem.$ref ] ); if ( defined ($NAME) ) { $NAME=$NAME->{$snmp_Modem.$ref }; $common->addModem( { NAME => $NAME } ); } } # End Modem elsif ( $result_table->{$result} =~ /3\.1\.15$/ ) { # We have a ParallelPort my $NAME=$session->get_request(-varbindlist => [ $snmp_ParallelPort.$ref ] ); if ( defined ($NAME) ) { $NAME=$NAME->{$snmp_ParallelPort.$ref }; $common->addPorts( { NAME => $NAME , TYPE => "Parallel" } ); } } # End ParallelPort elsif ( $result_table->{$result} =~ /3\.1\.17$/ ) { # We have a SerialPort my $NAME=$session->get_request(-varbindlist => [ $snmp_SerialPort.$ref ] ); if ( defined ($NAME) ) { $NAME=$NAME->{$snmp_SerialPort.$ref }; $common->addPorts( { NAME => $NAME , TYPE => "Serial" } ); } } # End SerialPort } # End scan of hrDeviceType } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Modules/Snmp/If_Mib.pm000066400000000000000000000162031372663377700236320ustar00rootroot00000000000000### # SNMP: OID: 2 SYSTEM: If_Mib ### package Ocsinventory::Agent::Modules::Snmp::If_Mib; use strict; use warnings; use Data::Dumper; sub snmp_info { return ( { oid_value => "1.3.6.1.2.1.2.1.0", oid_name => "If_Mib" } ); } sub snmp_run { my ($session , $snmp )= @_; my $logger=$snmp->{logger}; my $common=$snmp->{common}; $logger->debug("Running If MIB module"); # OID a recuperer my $snmp_ifdescr="1.3.6.1.2.1.2.2.1.2."; my $snmp_iftype="1.3.6.1.2.1.2.2.1.3"; my $snmp_ifspeed="1.3.6.1.2.1.2.2.1.5."; my $snmp_physAddr="1.3.6.1.2.1.2.2.1.6."; my $snmp_ifadminstatus="1.3.6.1.2.1.2.2.1.7."; my $snmp_ipAdEntIfIndex="1.3.6.1.2.1.4.20.1.2"; my $snmp_ipAdEntNetMask="1.3.6.1.2.1.4.20.1.3."; my $snmp_ipRouteIfIndex="1.3.6.1.2.1.4.21.1.2."; my $snmp_ipRouteNextHop="1.3.6.1.2.1.4.21.1.7."; my $snmp_ipRouteType="1.3.6.1.2.1.4.21.1.8"; my $SPEED=undef; my $MACADDR=undef; my $SLOT=undef; my $STATUS=undef; my $TYPE=undef; my $IPADDR=undef; my $IPMASK=undef; my $IPGATEWAY=undef; my $IPSUBNET=undef; my $ref; my $result_snmp; my $address_index=undef; my $netmask_index=undef; my $network_index=undef; my $gateway_index=undef; # the informations on ip address and gateway are not indexed on the # interfaces so we must get it before and integrate the informations # after for each interface # We take all the snmp_ifadminstatus in a table if this information exist $result_snmp=$session->get_entries(-columns => [$snmp_ipAdEntIfIndex]); foreach my $result ( keys %{$result_snmp} ) { if ( $result =~ /1\.3\.6\.1\.2\.1\.4\.20\.1\.2\.(\S+)/ ) { my $address=$1; $address_index->{$result_snmp->{$result}}=$address; # We have the address so we can lokk for the netmask associated my $netmask=$session->get_request(-varbindlist => [$snmp_ipAdEntNetMask.$address]); if ( defined($netmask->{$snmp_ipAdEntNetMask.$address} ) ) { $netmask_index->{$result_snmp->{$result}}=$netmask->{$snmp_ipAdEntNetMask.$address}; } } } # now we can do the same thing for the gateway # It is an other index and only indirect information (routing) # are required actually $result_snmp=$session->get_entries(-columns => [$snmp_ipRouteType]); foreach my $result ( keys %{$result_snmp} ) { if ( $result =~ /1\.3\.6\.1\.2\.1\.4\.21\.1\.8\.(\S+)/ ) { if ( $result_snmp->{$result} == 4 ) { my $net_address=$1; # We get the index associating the interface with the gateway and subnet my $ind=$session->get_request(-varbindlist => [$snmp_ipRouteIfIndex.$net_address] ); $ind=$ind->{$snmp_ipRouteIfIndex.$net_address}; # We ave already the network so we can add the information with the index $network_index->{$ind}=$net_address; # We get the gateway my $gateway=$session->get_request(-varbindlist => [$snmp_ipRouteNextHop.$net_address] ); $gateway_index->{$ind}=$gateway->{$snmp_ipRouteNextHop.$net_address}; } } } # We look for interfaces $result_snmp=$session->get_entries(-columns => [$snmp_iftype]); foreach my $result ( keys %{$result_snmp} ) { # We work on real interface and no vlan $TYPE=$result_snmp->{$result}; if ( $TYPE == 6 || $TYPE == 94) { if ( $result =~ /1\.3\.6\.1\.2\.1\.2\.2\.1\.3\.(\S+)/ ) { $ref=$1; if ( $TYPE == 6 ) { $TYPE="ethernetCsmacd"; } elsif ( $TYPE == 94 ) { $TYPE="Adsl"; } my $intero=$snmp_ifdescr.$ref; #$SLOT=$session->get_request(-varbindlist => [$snmp_ifdescr.$ref]); $SLOT=$session->get_request(-varbindlist => [$intero]); $SLOT=" $SLOT->{$snmp_ifdescr.$ref}"; #print "Pour $intero Le slot $SLOT\n"; $SPEED=$session->get_request(-varbindlist => [$snmp_ifspeed.$ref]); if ( defined( $SPEED->{$snmp_ifspeed.$ref}) ) { $SPEED=$SPEED->{$snmp_ifspeed.$ref}; if ( $SPEED / 1000000000000 >= 1 ) { $SPEED=$SPEED / 1000000000000; $SPEED=$SPEED." T"; } elsif ( $SPEED / 1000000000 >= 1 ) { $SPEED=$SPEED / 1000000000; $SPEED=$SPEED." G"; } elsif ( $SPEED / 1000000 >= 1 ) { $SPEED=$SPEED / 1000000; $SPEED=$SPEED." M"; } } $MACADDR=$session->get_request(-varbindlist => [$snmp_physAddr.$ref]); if ( defined( $MACADDR->{$snmp_physAddr.$ref}) ) { # For MACADDR, we need a translation beetween Hexa and string $MACADDR=" ".$MACADDR->{$snmp_physAddr.$ref}; if ( $MACADDR =~ /^ 0x(\w{2})(\w{2})(\w{2})(\w{2})(\w{2})(\w{2})$/ ) { $MACADDR="$1:$2:$3:$4:$5:$6"; } $STATUS=$session->get_request(-varbindlist => [ $snmp_ifadminstatus.$ref ]); if ( $STATUS->{$snmp_ifadminstatus.$ref} == 1 ) { $STATUS="Up"; } else { $STATUS="Down"; } # If we have the address ip and netmask we can put it if ( defined ( $address_index ) ) { $IPADDR=$address_index->{$ref}; $IPMASK=$netmask_index->{$ref}; #if ( defined ($IPADDR ) ) { # my $local_info=$session->hostname(); # print "$IPADDR et $local_info"; # if ( $IPADDR eq $session->hostname() ) { # $common->setSnmpCommons({MACADDR => $MACADDR }); # } #} } if ( defined ( $network_index ) ) { $IPGATEWAY=$gateway_index->{$ref}; $IPSUBNET=$network_index->{$ref}; } $common->addSnmpNetwork( { TYPE => $TYPE, SLOT => $SLOT, SPEED => $SPEED, MACADDR => $MACADDR, STATUS => $STATUS, IPADDR => $IPADDR, IPMASK => $IPMASK, IPGATEWAY => $IPGATEWAY, IPSUBNET => $IPSUBNET, }); $MACADDR=undef; $SLOT=undef; $STATUS=undef; $SPEED=undef; $IPADDR=undef; $IPMASK=undef; $IPGATEWAY=undef; $IPSUBNET=undef; } } } } # End foreach result } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Modules/Snmp/Printer_Mib.pm000066400000000000000000000141201372663377700247130ustar00rootroot00000000000000### # SNMP: OID: 43 SYSTEM: Printer_Mib ### package Ocsinventory::Agent::Modules::Snmp::Printer_Mib; use strict; sub snmp_info { #TODO: find a common OID from Printer_Mib (compatible with most printers) instead of using hrPrinterStatus from Host_Ressources_Mib return ( { oid_value => "1.3.6.1.2.1.25.3.5.1.1.1", oid_name => "Printer_Mib" } ); } sub snmp_run { my ($session , $snmp )= @_; my $logger=$snmp->{logger}; my $common=$snmp->{common}; my ($result,$name,$serialnumber,$lifecount,$countunit,$printerstatus,$errorstate); $logger->debug("Running Printer MIB module"); $common->setSnmpCommons( {TYPE => "Printer"} ); # prtGeneralPrinterName my $snmp_name="1.3.6.1.2.1.43.5.1.1.16.1"; # prtInputSerialNumber my $snmp_serialnumber="1.3.6.1.2.1.43.5.1.1.17.1"; # prtMarkerLifeCount my $snmp_lifecount="1.3.6.1.2.1.43.10.2.1.4.1.1"; # prtMarkerCounterUnit my $snmp_countunit="1.3.6.1.2.1.43.10.2.1.3.1.1"; # prtInputTable my $snmp_inputable="1.3.6.1.2.1.43.8.2"; # prtMarkerSuppliesTable my $snmp_markersuppliestable="1.3.6.1.2.1.43.11.1"; # prtMarkerColorantValue my $snmp_colorantvalue="1.3.6.1.2.1.43.12.1.1.4"; # hrPrinterStatus my $snmp_printerstatus="1.3.6.1.2.1.25.3.5.1.1.1"; # PrinterDetectedErrorState my $snmp_errorstate="1.3.6.1.2.1.25.3.5.1.2.1"; #Trays informations we want to get my $trayinfos = { name => "1.3.6.1.2.1.43.8.2.1.13", #prtInputName description => "1.3.6.1.2.1.43.8.2.1.18", #prtInputDescription level => "1.3.6.1.2.1.43.8.2.1.10", #prtInputLevel maxcapacity => "1.3.6.1.2.1.43.8.2.1.9", #prtInputMaxCapacity }; # Cartridges informations we want to get my $cartridgeinfos = { description => "1.3.6.1.2.1.43.11.1.1.6", #prtMarkerSuppliesDescription type => "1.3.6.1.2.1.43.11.1.1.5", #prtMarkerSuppliesType level => "1.3.6.1.2.1.43.11.1.1.9", #prtMarkerSuppliesSupplyLevel maxcapacity => "1.3.6.1.2.1.43.11.1.1.8", #prtMarkerSuppliesMaxCapacity }; # Translation for the prtMarkerCounterUnit integer my $countunit_translation = { 3 => 'tenThousandthsOfInches', 4 => 'micrometers', 5 => 'characters', 6 => 'lines', 7 => 'impressions', 8 => 'sheets', 9 => 'dotRow', 11 => 'hours', 16 => 'feet', 17 => 'meters', }; # Translation for the prtMarkerSuppliesType integer my $suppliestype_translation = { 1 => 'other', 2 => 'unknown', 3 => 'toner', 4 => 'wasteToner', 5 => 'ink', 6 => 'inkCartridge', 7 => 'inkRibbon', 8 => 'wasteInk', 9 => 'opc', 10 => 'developer', 11 => 'fuserOil', 12 => 'solidWax', 13 => 'ribbonWax', 14 => 'wasteWax', }; my $printerstatus_translation = { 1 => 'other', 2 => 'unknown', 3 => 'idle', 4 => 'printing', 5 => 'warmup', }; my $errorstate_translation = { '0x00' => 'lowPaper', '0x01' => 'noPaper', '0x02' => 'lowToner', '0x03' => 'noToner', '0x04' => 'doorOpen', '0x05' => 'jammed', '0x06' => 'offline', '0x07' => 'serviceRequested', '0x08' => 'inputTrayMissing', '0x09' => 'outputTrayMissing', '0x10' => 'markerSupplyMissing', '0x11' => 'outputNearFull', '0x12' => 'outputFull', '0x13' => 'inputTrayEmpty', '0x14' => 'overduePreventMaint', }; ##### #Getting printer informations $result=$session->get_request( -varbindlist => [$snmp_name]); $name=$result->{$snmp_name}; $result=$session->get_request(-varbindlist => [$snmp_serialnumber]); $serialnumber=$result->{$snmp_serialnumber}; $result=$session->get_request(-varbindlist => [$snmp_lifecount]); $lifecount=$result->{$snmp_lifecount}; $result=$session->get_request(-varbindlist => [$snmp_countunit]); $countunit=$countunit_translation->{ $result->{$snmp_countunit} }; $result=$session->get_request(-varbindlist => [$snmp_printerstatus]); $printerstatus=$result->{$snmp_printerstatus}; $result=$session->get_request(-varbindlist => [$snmp_errorstate]); $errorstate=$result->{$snmp_errorstate}; # Adding informations to XML $common->setSnmpPrinter({ NAME => $name, SERIALNUMBER => $serialnumber, COUNTER => "$lifecount $countunit", STATUS => $printerstatus_translation->{$printerstatus}, ERRORSTATE => $errorstate_translation->{$errorstate}, }); # Getting trays informations using the table my $inputable=$session->get_table(-baseoid => $snmp_inputable) ; my $trays = $common->getSnmpTable($inputable,$snmp_inputable,$trayinfos); for my $tray ( keys %$trays ) { #Adding informations about trays in XML $common->addSnmpPrinterTray({ NAME => $trays->{$tray}->{name}, DESCRIPTION => $trays->{$tray}->{description}, LEVEL => $trays->{$tray}->{level}, MAXCAPACITY => $trays->{$tray}->{maxcapacity}, }); } # Getting cartridges informations using the table my $markersuppliestable=$session->get_table(-baseoid => $snmp_markersuppliestable) ; my $cartridges = $common->getSnmpTable($markersuppliestable,$snmp_markersuppliestable,$cartridgeinfos); for my $cartridge ( keys %$cartridges ) { # Getting colorant value $result = $session->get_request(-varbindlist => [$snmp_colorantvalue.$cartridge]); my $colorantvalue = $result->{$snmp_colorantvalue.$cartridge}; # Adding informations about cartridges in XML $common->addSnmpPrinterCartridge({ DESCRIPTION => $cartridges->{$cartridge}->{description}, TYPE => $suppliestype_translation->{ $cartridges->{$cartridge}->{type} }, LEVEL => $cartridges->{$cartridge}->{level}, MAXCAPACITY => $cartridges->{$cartridge}->{maxcapacity}, COLOR => $colorantvalue, }); } } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/Modules/SnmpScan.pm000066400000000000000000000340041372663377700233110ustar00rootroot00000000000000############################################################################### ## OCSINVENTORY-NG ## Copyleft Guillaume PROTET 2010 ## Web : http://www.ocsinventory-ng.org ## ## This code is open source and may be copied and modified as long as the source ## code is always made freely available. ## Please refer to the General Public Licence http://www.gnu.org/ or Licence.txt ################################################################################ package Ocsinventory::Agent::Modules::SnmpScan; use strict; no strict 'refs'; use warnings; use XML::Simple; use Digest::MD5; sub new { my $name="snmpscan"; #Set the name of your module here my (undef,$context) = @_; my $self = {}; #Create a special logger for the module $self->{logger} = new Ocsinventory::Logger ({ config => $context->{config} }); $self->{logger}->{header}="[$name]"; $self->{common} = $context->{common}; $self->{context}=$context; $self->{structure}= { name => $name, start_handler => $name."_start_handler", prolog_writer => undef, prolog_reader => $name."_prolog_reader", inventory_handler => undef, end_handler => $name."_end_handler", }; $self->{number_scan}=0; $self->{snmp_oid_run}=$name."_oid_run"; $self->{snmp_oid_xml}=$name."_oid_xml"; $self->{func_oid}={}; $self->{snmp_dir}=[]; $self->{snmp_vardir} = ["$self->{context}->{installpath}/snmp/mibs/local/","$self->{context}->{installpath}/snmp/mibs/remote/"]; my $spec_dir_snmp="Ocsinventory/Agent/Modules/Snmp/"; $self->{spec_dir_snmp}=$spec_dir_snmp; $self->{spec_module_snmp}="Ocsinventory::Agent::Modules::Snmp::"; # We are going to search where is the directory Ocsinventory/Modules/snmp foreach my $dir ( @INC ) { my $res_dir=$dir."/".$spec_dir_snmp; if ( -d $res_dir ) { push(@{$self->{snmp_dir}},$res_dir); } } # We create a xml for the snmp inventory that we will be sent to server $self->{inventory}={}; bless $self; } sub snmpscan_start_handler { my $self = shift; my $logger = $self->{logger}; my $common = $self->{context}->{common}; my $config = $self->{context}->{config}; $logger->debug("Calling snmp_start_handler"); # Disabling module if local mode if ($config->{stdout} || $config->{local}) { $self->{disabled} = 1; $logger->info("Agent is running in local mode...disabling module"); } # If we cannot load prerequisite, we disable the module unless ($common->can_load('Net::SNMP')) { $self->{disabled} = 1; $logger->error("Net::SNMP perl module is missing !!"); $logger->error("Humm my prerequisites are not OK...disabling module :( :("); } } sub snmpscan_prolog_reader { my ($self, $prolog) = @_; my $logger = $self->{logger}; my $network = $self->{context}->{network}; my $snmp_vardir = $self->{snmp_vardir}; my $option; $logger->debug("Calling snmp_prolog_reader"); $prolog = XML::Simple::XMLin( $prolog, ForceArray => ['OPTION', 'PARAM']); for $option (@{$prolog->{OPTION}}){ if ($option->{NAME} =~/snmp/i){ $self->{doscans} = 1 ; for ( @{ $option->{PARAM} } ) { if ($_->{'TYPE'} eq 'DEVICE'){ # Adding the IP in the devices array push @{$self->{netdevices}},{ IPADDR => $_->{IPADDR}, MACADDR => $_->{MACADDR}, }; } if ($_->{'TYPE'} eq 'COMMUNITY'){ # Adding the community in the communities array push @{$self->{communities}},{ VERSION=>$_->{VERSION}, NAME=>$_->{NAME}, USERNAME=>$_->{USERNAME}, AUTHPROTO=>$_->{AUTHPROTO}, AUTHPASSWD=>$_->{AUTHPASSWD}, PRIVPROTO=>$_->{PRIVPROTO}, PRIVPASSWD=>$_->{PRIVPASSWD} }; } if ($_->{'TYPE'} eq 'NETWORK'){ push @{$self->{nets_to_scan}},$_->{SUBNET}; } if ($_->{'TYPE'} eq 'SNMP_TYPE'){ push @{$self->{snmp_type_condition}},{ TABLE_TYPE_NAME => $_->{TABLE_TYPE_NAME}, CONDITION_OID => $_->{CONDITION_OID}, CONDITION_VALUE => $_->{CONDITION_VALUE} }; push @{$self->{snmp_type_infos}},{ TABLE_TYPE_NAME => $_->{TABLE_TYPE_NAME}, LABEL_NAME => $_->{LABEL_NAME}, OID => $_->{OID} }; } # Creating the directory for xml if they don't yet exist mkdir($self->{context}->{installpath}."/snmp") unless -d $self->{context}->{installpath}."/snmp"; mkdir($self->{context}->{installpath}."/snmp/mibs") unless -d $self->{context}->{installpath}."/snmp/mibs"; foreach my $dir ( @{$snmp_vardir}) { mkdir($dir) unless -d $dir; } } } } } sub snmpscan_end_handler { my $self = shift; my $logger = $self->{logger}; my $common = $self->{context}->{common}; my $network = $self->{context}->{network}; $logger->debug("Calling snmp_end_handler"); # If no order form server return unless $self->{doscans}; # Flushing xmltags if it has not been done $common->flushXMLTags(); # We get the config my $config = $self->{context}->{config}; my $communities=$self->{communities}; if ( ! defined ($communities ) ) { $logger->debug("We have no Community from server, we use default public community"); $communities=[{VERSION=>"2c",NAME=>"public"}]; } my ($name,$comm,$error,$system_oid); # Initalising the XML properties my $snmp_inventory = $self->{inventory}; $snmp_inventory->{xmlroot}->{QUERY} = ['SNMP']; $snmp_inventory->{xmlroot}->{DEVICEID} = [$self->{context}->{config}->{deviceid}]; # Scanning network $logger->debug("Snmp: Scanning network"); my $nets_to_scan=$self->{nets_to_scan}; foreach my $net_to_scan ( @$nets_to_scan ){ $self->snmp_ip_scan($net_to_scan); } $logger->debug("Snmp: Ending Scanning network"); # Begin scanning ip tables my $ip=$self->{netdevices}; foreach my $device ( @$ip ) { my $session = undef; my $oid_condition = undef; my $devicedata = $common->{xmltags}; #To fill the xml informations for this device my $snmp_table = undef; my $snmp_condition_oid = undef; my $snmp_condition_value = undef; $logger->debug("Scanning $device->{IPADDR} device"); # Search for the good snmp community in the table community LIST_SNMP: foreach $comm ( @$communities ) { # Test if we use SNMP v3 if ( $comm->{VERSION} eq "3" ) { ($session, $error) = Net::SNMP->session( -retries => 2 , -timeout => 3, -version => 'snmpv'.$comm->{VERSION}, -hostname => $device->{IPADDR}, -translate => [-nosuchinstance => 0, -nosuchobject => 0], -username => $comm->{USERNAME}, -authpassword => $comm->{AUTHPASSWD}, -authprotocol => $comm->{AUTHPROTO}, -privpassword => $comm->{PRIVPASSWD}, -privprotocol => $comm->{PRIVPROTO}, ); # For a use in constructor module (Cisco) $self->{username}=$comm->{USERNAME}; $self->{authpassword}=$comm->{AUTHPASSWD}; $self->{authprotocol}=$comm->{AUTHPROTO}; $self->{privpassword}=$comm->{PRIVPASSWD}; $self->{privprotocol}= $comm->{PRIVPROTO}; } else { # We have an older version v2c ou v1 ($session, $error) = Net::SNMP->session( -retries => 1 , -timeout => 3, -version => 'snmpv'.$comm->{VERSION}, -hostname => $device->{IPADDR}, -community => $comm->{NAME}, -translate => [-nosuchinstance => 0, -nosuchobject => 0], ); }; unless (defined($session)) { $logger->error("Snmp ERROR: $error"); } else { $self->{snmp_session}=$session; # For a use in constructor module (Cisco) $self->{snmp_community}=$comm->{NAME}; $self->{snmp_version}=$comm->{VERSION}; my $snmp_key = $self->{snmp_type_condition}; LIST_TYPE: foreach my $snmp_value (@$snmp_key) { $oid_condition = $session->get_request(-varbindlist => [$snmp_value->{CONDITION_OID}]); $snmp_table = $snmp_value->{TABLE_TYPE_NAME}; $snmp_condition_oid = $snmp_value->{CONDITION_OID}; $snmp_condition_value = $snmp_value->{CONDITION_VALUE}; last LIST_TYPE if (defined $oid_condition && $oid_condition->{$snmp_value->{CONDITION_OID}} eq $snmp_value->{CONDITION_VALUE}); } last LIST_SNMP if (defined $oid_condition && $oid_condition->{$snmp_condition_oid} eq $snmp_condition_value); $session->close; $self->{snmp_session}=undef; } } if (defined $oid_condition && $oid_condition->{$snmp_condition_oid} eq $snmp_condition_value) { $oid_condition = $oid_condition->{$snmp_condition_oid}; my $xmltags = $common->{xmltags}; $session->max_msg_size(8192); # We have found the good Community, we can scan this equipment # We indicate that we scan a new equipment $self->{number_scan}++; my $data; my $snmp_infos = $self->{snmp_type_infos}; foreach my $datas (@$snmp_infos) { my $data_value = undef; if($datas->{TABLE_TYPE_NAME} eq $snmp_table) { $data = $session->get_request(-varbindlist => [$datas->{OID}]); $data_value = $data->{$datas->{OID}}; if(defined $data_value && $data_value =~ /^0x[0-9A-F]+$/i) { $data_value = substr $data_value, 2; my @split = unpack '(A2)*', $data_value; $data_value = uc(join ':', @split); } if(!defined $data_value) { my @table; $data = $session->get_table(-baseoid => $datas->{OID}); foreach my $key (keys %{$data}) { push @table, $data->{$key}; } $data_value = join ' - ', @table; } $xmltags->{$datas->{LABEL_NAME}}[0] = $data_value; } } push @{$snmp_inventory->{xmlroot}->{CONTENT}->{$snmp_table}},$xmltags; # We have finished with this equipment if (defined $session) { $session->close; } $self->{snmp_session}=undef; # We clear the xml data for this device $common->flushXMLTags(); } } $logger->info("No more SNMP device to scan"); # Formatting the XML and sendig it to the server my $content = XMLout( $snmp_inventory->{xmlroot}, RootName => 'REQUEST' , XMLDecl => '', SuppressEmpty => undef ); #Cleaning XML to delete unprintable characters my $clean_content = $common->cleanXml($content); $network->sendXML({message => $clean_content}); $logger->debug("End snmp_end_handler :)"); } sub snmp_ip_scan { my ($self,$net_to_scan) = @_; my $logger=$self->{logger}; my $common=$self->{common}; if ($common->can_load('Net::Netmask') ) { my $block=Net::Netmask->new($net_to_scan); my $size=$block->size()-2; my $index=1; if ( $common->can_run('nmap') && $common->can_load('Nmap::Parser') ) { $logger->debug("Scannig $net_to_scan with nmap"); my $nmaparser = Nmap::Parser->new; $nmaparser->parsescan("nmap","-sP",$net_to_scan); for my $host ($nmaparser->all_hosts("up")) { my $res=$host->addr; $logger->debug("Found $res"); push( @{$self->{netdevices}},{ IPADDR=>$res }) unless $self->search_netdevice($res); } } elsif ($common->can_load('Net::Ping')) { $logger->debug("Scanning $net_to_scan with ping"); my $ping=Net::Ping->new("icmp",1); while ($index <= $size) { my $res=$block->nth($index); if ($ping->ping($res)) { $logger->debug("Found $res"); push( @{$self->{netdevices}},{ IPADDR=>$res }) unless $self->search_netdevice($res); } $index++; } $ping->close(); } else { $logger->debug("No scan possible"); } } else { $logger->debug("Net::Netmask not present: no scan possible"); } } sub search_netdevice { my ($self,$ip)= @_ ; for (@{$self->{netdevices}}) { if ($ip =~ /^$_->{IPADDR}$/) { return 1; } } } 1;UnixAgent-2.8/lib/Ocsinventory/Agent/Network.pm000066400000000000000000000115461372663377700216160ustar00rootroot00000000000000package Ocsinventory::Agent::Network; # TODO: # - set the correct deviceID and olddeviceID use strict; use warnings; use IO::Socket::SSL qw(SSL_VERIFY_NONE); use LWP::UserAgent; use Socket; use Ocsinventory::Compress; use Ocsinventory::Agent::Encrypt; sub new { my (undef, $params) = @_; my $self = {}; $self->{accountconfig} = $params->{accountconfig}; $self->{accountinfo} = $params->{accountinfo}; $self->{common} = $params->{common}; my $logger = $self->{logger} = $params->{logger}; $self->{config} = $params->{config}; my $uaserver; if ($self->{config}->{server} =~ /^http(|s):\/\//) { $self->{URI} = $self->{config}->{server}; $uaserver = $self->{config}->{server}; $uaserver =~ s/^http(|s):\/\///; $uaserver =~ s/\/.*//; if ($uaserver !~ /:\d+$/) { $uaserver .= ':443' if $self->{config}->{server} =~ /^https:/; $uaserver .= ':80' if $self->{config}->{server} =~ /^http:/; } } else { $self->{URI} = "http://".$self->{config}->{server}.$self->{config}->{remotedir}; $uaserver = $self->{config}->{server}; } $self->{compress} = new Ocsinventory::Compress ({logger => $logger}); # Connect to server $self->{ua} = LWP::UserAgent->new(keep_alive => 1); if ($self->{config}->{proxy}) { $self->{ua}->proxy(['http', 'https'], 'connect://'.$self->{config}->{proxy}.''); } else { $self->{ua}->env_proxy; } my $version = 'OCS-NG_unified_unix_agent_v'; $version .= exists ($self->{config}->{VERSION})?$self->{config}->{VERSION}:''; my $userencrypt = Ocsinventory::Agent::Encrypt::getClearText($self->{config}->{user}); my $pwdencrypt = Ocsinventory::Agent::Encrypt::getClearText($self->{config}->{password}); $self->{ua}->agent($version); $self->{ua}->credentials( $uaserver, # server:port, port is needed $self->{config}->{realm}, $userencrypt, $pwdencrypt ); #Setting SSL configuration depending on LWP version $self->{ua}->_agent =~ /^libwww-perl\/(.*)$/; my $lwp_version= $1; $lwp_version=$self->{common}->convertVersion($lwp_version,3); if ($lwp_version > 583) { $self->{ua}->ssl_opts( verify_hostname => $self->{config}->{ssl}, SSL_ca_file => $self->{config}->{ca} ); if ($self->{config}->{ssl} == 0 ) { $self->{ua}->ssl_opts( SSL_verify_mode => SSL_VERIFY_NONE ); } } elsif ($self->{config}->{ssl} eq 1) { # SSL verification is disabled by default in LWP prior to version 6 # we activate it using Crypt::SSLeay environment variables $ENV{HTTPS_CA_FILE} = $self->{config}->{ca}; } bless $self; } sub sendXML { my ($self, $args) = @_; my $logger = $self->{logger}; my $compress = $self->{compress}; my $message = $args->{message}; my $common = $self->{common}; my $req = HTTP::Request->new(POST => $self->{URI}); $req->header('Pragma' => 'no-cache', 'Content-type', 'application/x-compress'); $logger->debug ("sending XML"); $logger->debug ("sending: ".$message); my $compressed = $compress->compress($message); if (!$compressed) { $logger->error ('failed to compress data'); return; } $req->content($compressed); my $res = $self->{ua}->request($req); # Checking if connected if (!$res->is_success) { $logger->error ('Cannot establish communication : '.$res->status_line); return; } return $res ; } sub getXMLResp { my ($self, $res, $msgtype) = @_; my $logger = $self->{logger}; my $compress = $self->{compress}; # If no answer from OCS server return unless $res; # Reading the XML response from OCS server my $content = $compress->uncompress($res->content); if (!$content) { $logger->error ("Deflating problem"); return; } my $tmp = "Ocsinventory::Agent::XML::Response::".$msgtype; eval "require $tmp"; if ($@) { $logger->error ("Can't load response module $tmp: $@"); } $tmp->import(); my $response = $tmp->new ({ accountconfig => $self->{accountconfig}, accountinfo => $self->{accountinfo}, content => $content, logger => $logger, config => $self->{config}, common => $self->{common}, }); return $response; } sub getFile { my ($self,$proto,$uri,$filetoget,$filepath) = @_; my $logger= $self->{logger}; chomp($proto,$uri,$filetoget,$filepath); my $url = "$proto://$uri/$filetoget"; my $response = $self->{ua}->mirror($url,$filepath); if ($response->is_success){ $logger->debug("Success downloading $filetoget file..."); } else { $logger->error("Failed downloading $filetoget: ".$response->status_line." !!!"); return 1; } } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/XML/000077500000000000000000000000001372663377700202605ustar00rootroot00000000000000UnixAgent-2.8/lib/Ocsinventory/Agent/XML/Inventory.pm000066400000000000000000000205071372663377700226170ustar00rootroot00000000000000package Ocsinventory::Agent::XML::Inventory; # TODO: resort the functions use strict; use warnings; =head1 NAME Ocsinventory::Agent::XML::Inventory - the XML abstraction layer =head1 DESCRIPTION OCS Inventory uses XML for the data transmission. The module is the abstraction layer. It's mostly used in the backend module where it called $inventory in general. =cut use XML::Simple; use Digest::MD5 qw(md5_base64); use Config; use Ocsinventory::Agent::Backend; =over 4 =item new() The usual constructor. =cut sub new { my (undef, $params) = @_; my $self = {}; $self->{accountinfo} = $params->{context}->{accountinfo}; $self->{accountconfig} = $params->{context}->{accountconfig}; $self->{backend} = $params->{backend}; $self->{common} = $params->{context}->{common}; my $logger = $self->{logger} = $params->{context}->{logger}; $self->{config} = $params->{context}->{config}; if (!($self->{config}{deviceid})) { $logger->fault ('deviceid unititalised!'); } $self->{xmlroot}{QUERY} = ['INVENTORY']; $self->{xmlroot}{DEVICEID} = [$self->{config}->{deviceid}]; #$self->{xmlroot}{CONTENT}{HARDWARE} = { # TODO move that in a backend module # ARCHNAME => [$Config{archname}] #}; # Is the XML centent initialised? $self->{isInitialised} = undef; bless $self; } =item initialise() Runs the backend modules to initialise the data. =cut sub initialise { my ($self) = @_; return if $self->{isInitialised}; $self->{backend}->feedInventory ({inventory => $self}); $self->{isInitialised} = 1; } =item getContent() Return the inventory as a XML string. =cut sub getContent { my ($self, $args) = @_; my $logger = $self->{logger}; my $common = $self->{common}; if ($self->{isInitialised}) { $self->processChecksum(); # checks for MAC, NAME and SSN presence my $macaddr = $self->{xmlroot}->{CONTENT}->{NETWORKS}->[0]->{MACADDR}->[0]; my $ssn = $self->{xmlroot}->{CONTENT}->{BIOS}->{SSN}->[0]; my $name = $self->{xmlroot}->{CONTENT}->{HARDWARE}->{NAME}->[0]; my $missing; $missing .= "MAC-address " unless $macaddr; $missing .= "SSN " unless $ssn; $missing .= "HOSTNAME " unless $name; if ($missing) { $logger->debug('Missing value(s): '.$missing.'. I will send this inventory to the server BUT important value(s) to identify the computer are missing'); } $self->{accountinfo}->setAccountInfo($self); my $content = XMLout( $self->{xmlroot}, RootName => 'REQUEST', XMLDecl => '', SuppressEmpty => undef ); # Cleaning XML to delete unprintable characters my $clean_content=$common->cleanXml($content); # Cleaning xmltags content after adding it o inventory $common->flushXMLTags(); return $clean_content; } } =item printXML() Only for debugging purpose. Print the inventory on STDOUT. =cut sub printXML { my ($self, $args) = @_; if ($self->{isInitialised}) { print $self->getContent(); } } =item writeXML() Save the generated inventory as an XML file. The 'local' key of the config is used to know where the file as to be saved. =cut sub writeXML { my ($self, $args) = @_; my $logger = $self->{logger}; if ($self->{config}{local} =~ /^$/) { $logger->fault ('local path unititalised!'); } if ($self->{isInitialised}) { my $localfile = $self->{config}{local}."/".$self->{config}{deviceid}.'.ocs'; $localfile =~ s!(//){1,}!/!; # Convert perl data structure into xml strings if (open OUT, ">$localfile") { print OUT $self->getContent(); close OUT or warn; $logger->info("Inventory saved in $localfile"); } else { warn "Can't open `$localfile': $!" } } } =item processChecksum() Compute the field. This information is used by the server to know which parts of the XML have changed since the last inventory. The is done thank to the last_file file. It has MD5 prints of the previous inventory. =cut sub processChecksum { my $self = shift; my $logger = $self->{logger}; my $common = $self->{common}; # To apply to $checksum with an OR my %mask = ( 'HARDWARE' => 1, 'BIOS' => 2, 'MEMORIES' => 4, 'SLOTS' => 8, 'REGISTRY' => 16, 'CONTROLLERS' => 32, 'MONITORS' => 64, 'PORTS' => 128, 'STORAGES' => 256, 'DRIVES' => 512, 'INPUT' => 1024, 'MODEMS' => 2048, 'NETWORKS' => 4096, 'PRINTERS' => 8192, 'SOUNDS' => 16384, 'VIDEOS' => 32768, 'SOFTWARES' => 65536, 'VIRTUALMACHINES' => 131072, 'CPUS' => 262144, 'BATTERIES' => 1048576, ); if (!$self->{config}->{vardir}) { $logger->fault ("vardir uninitialised!"); } my $checksum = 0; if (!$self->{config}{local} && $self->{config}->{last_statefile}) { if (-f $self->{config}->{last_statefile}) { # TODO: avoid a violant death in case of problem with XML $self->{last_state_content} = XML::Simple::XMLin( $self->{config}->{last_statefile}, SuppressEmpty => undef, ForceArray => 1 ); } else { $logger->debug ('last_state file: `'. $self->{config}->{last_statefile}. "' doesn't exist (yet)."); } } foreach my $section (keys %mask) { # If the checksum has changed... my $hash = md5_base64(XML::Simple::XMLout($self->{xmlroot}{'CONTENT'}{$section})); if (!$self->{last_state_content}->{$section}[0] || $self->{last_state_content}->{$section}[0] ne $hash ) { $logger->debug ("Section $section has changed since last inventory"); # We make OR on $checksum with the mask of the current section $checksum |= $mask{$section}; # Finally I store the new value. $self->{last_state_content}->{$section}[0] = $hash; } } $common->setHardware({CHECKSUM => $checksum}); } =item saveLastState() At the end of the process IF the inventory was saved correctly, the last_state is saved. =cut sub saveLastState { my ($self, $args) = @_; my $logger = $self->{logger}; if (!defined($self->{last_state_content})) { $self->processChecksum(); } if (!defined ($self->{config}->{last_statefile})) { $logger->debug ("Can't save the last_state file. File path is not initialised."); return; } if (open LAST_STATE, ">".$self->{config}->{last_statefile}) { print LAST_STATE my $string = XML::Simple::XMLout( $self->{last_state_content}, RootName => 'LAST_STATE' );; close LAST_STATE or warn; } else { $logger->debug ("Cannot save the checksum values in ".$self->{config}->{last_statefile}.":$!"); } } =item addSection() A generic way to save a section in the inventory. Please avoid this solution. =cut sub addSection { my ($self, $args) = @_; my $logger = $self->{logger}; my $multi = $args->{multi}; my $tagname = $args->{tagname}; for ( keys %{$self->{xmlroot}{CONTENT}} ){ if ( $tagname eq $_ ){ $logger->debug("Tag name `$tagname` already exists - Don't add it"); return 0; } } if ($multi){ $self->{xmlroot}{CONTENT}{$tagname} = []; } else { $self->{xmlroot}{CONTENT}{$tagname} = {}; } return 1; } =item feedSection() Add information in inventory. =back =cut # Q: is that really useful()? Can't we merge with addSection()? sub feedSection{ my ($self, $args) = @_; my $tagname = $args->{tagname}; my $values = $args->{data}; my $logger = $self->{logger}; my $found=0; for ( keys %{$self->{xmlroot}{CONTENT}} ){ $found = 1 if $tagname eq $_; } if (!$found){ $logger->debug("Tag name `$tagname` doesn't exist - Cannot feed it"); return 0; } if ( $self->{xmlroot}{CONTENT}{$tagname} =~ /ARRAY/ ){ push @{$self->{xmlroot}{CONTENT}{$tagname}}, $args->{data}; } else { $self->{xmlroot}{CONTENT}{$tagname} = $values; } return 1; } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/XML/Prolog.pm000066400000000000000000000014221372663377700220570ustar00rootroot00000000000000package Ocsinventory::Agent::XML::Prolog; use strict; use warnings; use XML::Simple; use Digest::MD5 qw(md5_base64); sub new { my (undef, $params) = @_; my $self = {}; $self->{config} = $params->{context}->{config}; $self->{logger} = $params->{context}->{logger}; die unless ($self->{config}->{deviceid}); #XXX $self->{xmlroot}{QUERY} = ['PROLOG']; $self->{xmlroot}{DEVICEID} = [$self->{config}->{deviceid}]; bless $self; } sub dump { my $self = shift; eval "use Data::Dumper;"; print Dumper($self->{xmlroot}); } sub getContent { my ($self, $args) = @_; my $content=XMLout( $self->{xmlroot}, RootName => 'REQUEST', XMLDecl => '', SuppressEmpty => undef ); return $content; } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/XML/Response.pm000066400000000000000000000020651372663377700224170ustar00rootroot00000000000000package Ocsinventory::Agent::XML::Response; use strict; use warnings; use XML::Simple; use Data::Dumper; sub new { my (undef, $params) = @_; my $self = {}; $self->{accountconfig} = $params->{accountconfig}; $self->{accountinfo} = $params->{accountinfo}; $self->{content} = $params->{content}; $self->{config} = $params->{config}; $self->{common} = $params->{common}; my $logger = $self->{logger} = $params->{logger}; $self->{origmsg} = $params->{origmsg}; $logger->debug("=BEGIN=SERVER RET======"); $logger->debug(Dumper($self->{content})); $logger->debug("=END=SERVER RET======"); $self->{parsedcontent} = undef; bless $self; } sub getRawXML { my $self = shift; return $self->{content}; } sub getParsedContent { my ($self,$forcearray) = @_; if (!$self->{parsedcontent}) { $self->{parsedcontent} = $self->{common}->readXml($self->{content},$forcearray); } return $self->{parsedcontent}; } sub origMsgType { my ($self, $package) = @_; return ref($package); } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/XML/Response/000077500000000000000000000000001372663377700220565ustar00rootroot00000000000000UnixAgent-2.8/lib/Ocsinventory/Agent/XML/Response/Inventory.pm000066400000000000000000000010721372663377700244110ustar00rootroot00000000000000package Ocsinventory::Agent::XML::Response::Inventory; use strict; use Ocsinventory::Agent::XML::Response; our @ISA = ('Ocsinventory::Agent::XML::Response'); sub new { my ($class, @params) = @_; my $this = $class->SUPER::new(@params); bless ($this, $class); my $parsedContent = $this->getParsedContent(['ACCOUNTINFO']); if ($parsedContent && exists ($parsedContent->{RESPONSE}) && $parsedContent->{RESPONSE} =~ /^ACCOUNT_UPDATE$/) { $this->{accountinfo}->writeAccountInfoFile($parsedContent->{ACCOUNTINFO}); } return $this; } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/XML/Response/Prolog.pm000066400000000000000000000052761372663377700236700ustar00rootroot00000000000000package Ocsinventory::Agent::XML::Response::Prolog; use strict; use Ocsinventory::Agent::XML::Response; our @ISA = ('Ocsinventory::Agent::XML::Response'); sub new { my ($class, @params) = @_; my $this = $class->SUPER::new(@params); bless ($this, $class); $this->updatePrologFreq(); $this->saveNextTime(); return $this; } sub isInventoryAsked { my $self = shift; my $parsedContent = $self->getParsedContent(['OPTION','PARAM']); if ($parsedContent && exists ($parsedContent->{RESPONSE}) && $parsedContent->{RESPONSE} =~ /^SEND$/) { return 1; } 0 } sub getOptionsInfoByName { my ($self, $name) = @_; my $parsedContent = $self->getParsedContent(['OPTION','PARAM']); my $ret = []; return unless ($parsedContent && $parsedContent->{OPTION}); foreach (@{$parsedContent->{OPTION}}) { if ($_->{NAME} && $_->{NAME} =~ /^$name$/i) { $ret = $_->{PARAM} } } return $ret; } sub updatePrologFreq { my $self = shift; my $parsedContent = $self->getParsedContent(['OPTION','PARAM']); my $logger = $self->{logger}; if ($parsedContent && exists ($parsedContent->{PROLOG_FREQ})) { if( $parsedContent->{PROLOG_FREQ} ne $self->{accountconfig}->get("PROLOG_FREQ")){ $logger->info("PROLOG_FREQ has changed since last process(old=".$self->{accountconfig}->get("PROLOG_FREQ").",new=".$parsedContent->{PROLOG_FREQ}.")"); $self->{prologFreqChanged} = 1; $self->{accountconfig}->set("PROLOG_FREQ", $parsedContent->{PROLOG_FREQ}); } else{ $logger->debug("PROLOG_FREQ has not changed since last process"); } } } sub saveNextTime { my ($self, $args) = @_; my $logger = $self->{logger}; if (!$self->{config}->{next_timefile}) { $logger->debug("no next_timefile to save!"); return; } my $parsedContent = $self->getParsedContent(['OPTION','PARAM']); if (!open NEXT_TIME, ">".$self->{config}->{next_timefile}) { $logger->error ("Cannot create the next_timefile `".$self->{config}->{next_timefile}."': $!"); return; } close NEXT_TIME or warn; my $serverdelay = $self->{accountconfig}->get('PROLOG_FREQ'); my $time; if( $self->{prologFreqChanged} ){ $logger->debug("Compute next_time file with random value"); $time = time + int rand(($serverdelay?$serverdelay*3600:$self->{config}->{delaytime})); } else{ $time = time + ($serverdelay?$serverdelay*3600:$self->{config}->{delaytime}); } utime $time,$time,$self->{config}->{next_timefile}; if ($self->{config}->{cron}) { $logger->info ("Next inventory after ".localtime($time)); } } 1; UnixAgent-2.8/lib/Ocsinventory/Agent/XML/SimpleMessage.pm000066400000000000000000000017411372663377700233570ustar00rootroot00000000000000package Ocsinventory::Agent::XML::SimpleMessage; use strict; use warnings; use Data::Dumper; # XXX Debug use XML::Simple; use Digest::MD5 qw(md5_base64); use Ocsinventory::Agent::XML::Prolog; sub new { my (undef, $params) = @_; my $self = {}; $self->{config} = $params->{config}; $self->{accountinfo} = $params->{accountinfo}; die unless ($self->{config}->{deviceid}); #XXX $self->{xmlroot}{QUERY} = ['PROLOG']; $self->{xmlroot}{DEVICEID} = [$self->{config}->{deviceid}]; bless $self; } sub dump { my $self = shift; print Dumper($self->{xmlroot}); } sub set { my ($self, $args) = @_; foreach (keys %$args) { $self->{xmlroot}{$_} = [$args->{$_}]; } } sub getContent { my ($self, $args) = @_; $self->{accountinfo}->setAccountInfo($self); my $content=XMLout( $self->{xmlroot}, RootName => 'REQUEST', XMLDecl => '', SuppressEmpty => undef ); return $content; } 1; UnixAgent-2.8/lib/Ocsinventory/Compress.pm000066400000000000000000000054421372663377700207200ustar00rootroot00000000000000package Ocsinventory::Compress; use strict; use File::Temp qw/ tempdir tempfile /; sub new { my (undef, $params) = @_; my $self = {}; my $logger = $self->{logger} = $params->{logger}; eval{require Compress::Zlib;}; $self->{mode} = 'natif' unless $@; chomp(my $gzippath=`which gzip 2>/dev/null`); if ($self->{mode} eq 'natif') { $logger->debug ('Compress::Zlib is available.'); } elsif (-x $gzippath) { $logger->debug ( 'Compress::Zlib is not available! The data will be compressed with gzip instead but won\'t be accepted by server prior 1.02'); $self->{mode} = 'gzip'; $self->{tmpdir} = tempdir( CLEANUP => 1 ); mkdir $self->{tmpdir}; if ( ! -d $self->{tmpdir} ) { $logger->fault("Failed to create the temp dir `$self->{tmpdir}'"); } } else { $self->{mode} = 'deflated'; $logger->debug ('I need the Compress::Zlib library or the gzip'. ' command to compress the data - The data will be sent uncompressed but won\'t be accepted by server prior 1.02'); } bless $self; } sub compress { my ($self, $content) = @_; my $logger = $self->{logger}; # native mode (zlib) if ($self->{mode} eq 'natif') { return Compress::Zlib::compress($content); } elsif ($self->{mode} eq 'gzip'){ # gzip mode my ($fh, $filename) = tempfile( DIR => $self->{tmpdir} ); print $fh $content; close $fh; system ("gzip --best $filename > /dev/null"); # print "filename ".$filename."\n"; my $ret; open FILE, "<$filename.gz"; $ret .= $_ foreach (); close FILE; if ( ! unlink "$filename.gz" ) { $logger->debug("Failed to remove `$filename.gz'"); } return $ret; } elsif($self->{mode} eq 'deflated'){ # No compression available return $content; } } sub uncompress { my ($self,$data) = @_; my $logger = $self->{logger}; # Native mode if ($self->{mode} eq 'natif') { return Compress::Zlib::uncompress($data); } elsif($self->{mode} eq 'gzip'){ # Gzip mode my ($fh, $filename) = tempfile( DIR => $self->{tmpdir}, SUFFIX => '.gz' ); print $fh $data; close $fh; system ("gzip -d $filename"); my ($uncompressed_filename) = $filename =~ /(.*)\.gz$/; my $ret; open FILE, "<$uncompressed_filename"; $ret .= $_ foreach (); close FILE; if ( ! unlink "$uncompressed_filename" ) { $logger->debug("Failed to remove `$uncompressed_filename'"); } return $ret; } elsif($self->{mode} eq 'deflated'){ # No compression available return $data; } } 1; UnixAgent-2.8/lib/Ocsinventory/Logger.pm000066400000000000000000000044361372663377700203460ustar00rootroot00000000000000package Ocsinventory::Logger; # TODO use Log::Log4perl instead. use Carp; sub new { my (undef, $params) = @_; my $self = {}; bless $self; $self->{backend} = []; $self->{config} = $params->{config}; $self->{debug} = $self->{config}->{debug}?1:0; my @logger; if (exists ($self->{config}->{logger})) { @logger = split /,/, $self->{config}->{logger}; } else { # if no 'logger' parameter exist I use Stderr as default backend push @logger, 'Stderr'; } my @loadedMbackends; foreach (@logger) { my $backend = "Ocsinventory::LoggerBackend::".$_; eval ("require $backend"); # TODO deal with error if ($@) { print STDERR "Failed to load Logger backend: $backend ($@)\n"; next; } else { push @loadedMbackends, $_; } my $obj = new $backend ({ config => $self->{config}, }); push @{$self->{backend}}, $obj if $obj; } my $version = "Ocsinventory unified agent for UNIX, Linux and MacOSX "; $version .= exists ($self->{config}->{VERSION})?$self->{config}->{VERSION}:''; $self->debug($version."\n"); $self->debug("Log system initialised (@loadedMbackends)"); $self; } sub log { my ($self, $args) = @_; # levels: info, debug, warn, fault my $level = $args->{level}; my $message = $args->{message}; my $header = $self->{header}; return if ($level =~ /^debug$/ && !($self->{debug})); chomp($message); #Add a header to message if needed $message="$header $message" if $header; $level = 'info' unless $level; foreach (@{$self->{backend}}) { $_->addMsg ({ level => $level, message => $message }); } confess if $level =~ /^fault$/; # Die with a backtace } sub debug { my ($self, $msg) = @_; $self->log({ level => 'debug', message => $msg}); } sub info { my ($self, $msg) = @_; $self->log({ level => 'info', message => $msg}); } sub error { my ($self, $msg) = @_; $self->log({ level => 'error', message => $msg}); } sub fault { my ($self, $msg) = @_; $self->log({ level => 'fault', message => $msg}); } sub user { my ($self, $msg) = @_; $self->log({ level => 'user', message => $msg}); } 1; UnixAgent-2.8/lib/Ocsinventory/LoggerBackend/000077500000000000000000000000001372663377700212515ustar00rootroot00000000000000UnixAgent-2.8/lib/Ocsinventory/LoggerBackend/File.pm000066400000000000000000000011221372663377700224620ustar00rootroot00000000000000package Ocsinventory::LoggerBackend::File; use strict; sub new { my (undef, $params) = @_; my $self = {}; $self->{config} = $params->{config}; $self->{logfile} = $self->{config}->{logdir}."/".$self->{config}->{logfile}; bless $self; } sub addMsg { my ($self, $args) = @_; my $level = $args->{level}; my $message = $args->{message}; return if $message =~ /^$/; open FILE, ">>".$self->{config}->{logfile} or warn "Can't open ". "`".$self->{config}->{logfile}."'\n"; print FILE "[".localtime()."][$level] $message\n"; close FILE; } 1; UnixAgent-2.8/lib/Ocsinventory/LoggerBackend/Stderr.pm000066400000000000000000000011211372663377700230450ustar00rootroot00000000000000package Ocsinventory::LoggerBackend::Stderr; sub new { my (undef, $params) = @_; my $self = {}; $self->{config} = $params->{config}; bless $self; } sub addMsg { my ($self, $args) = @_; my $level = $args->{level}; my $message = $args->{message}; return if $message =~ /^$/; # if STDERR has been hijacked, I take its saved ref my $stderr; if (exists ($self->{config}->{savedstderr})) { $stderr = $self->{config}->{savedstderr}; } else { open ($stderr, ">&STDERR"); } print $stderr "[$level] $message\n"; } 1; UnixAgent-2.8/lib/Ocsinventory/LoggerBackend/Syslog.pm000066400000000000000000000010111372663377700230600ustar00rootroot00000000000000package Ocsinventory::LoggerBackend::Syslog; # Not tested yet! use Sys::Syslog qw( :DEFAULT setlogsock); sub new { my (undef, $params) = @_; my $self = {}; openlog("ocs-agent",'cons.pid', $params->{config}->{logfacility}); syslog('debug', 'syslog backend enabled'); bless $self; } sub addMsg { my (undef, $args) = @_; my $level = $args->{level}; my $message = $args->{message}; return if $message =~ /^$/; syslog('info', $message); } sub destroy { closelog(); } 1; UnixAgent-2.8/macosx/000077500000000000000000000000001372663377700146045ustar00rootroot00000000000000UnixAgent-2.8/macosx/README000066400000000000000000000043201372663377700154630ustar00rootroot00000000000000DESCRIPTION OS X [darwin] Readme This README will help you roll your own native OSX, OCSNG.app client for enterprise deployment. PREREQUISITES - XCode 6.4 - Darwin Perl dependencies [A tarball with all the PerlDep's you'll need for this to run in darwin-land, see create....cpan.pl script] - OCSNG.pmproj [Apple PackageMaker binrary settings file] - Iceberg [http://s.sudre.free.fr/Software/Iceberg.html] BUILDING/INSTALLING - Run the tools/macosx/scripts/create-darwin-perl-lib_fromCPAN.pl script which will create the ~/darwin-perl-lib directory. This directory will stash a built version of all the perl libraries needed to run this client (ie: no running CPAN on the hosts you're deploying this on) - READ THE SCRIPT BEFORE RUNNING, some CPAN configurations are needed prior to running - You'll need CPAN, Perl (the development libraries for perl), so Xcode Tools (just about a full install). - Open the tools/macosx/ocsng_app-xcode/OCSNG.xcodeproj project using Xcode 6.4 and build it (Choose menu "Product\Archive") - Export the created archive to folder tools/macosx/installer_gui/iceberg/ - OPen tools/macosx/installer_gui/iceberg/iceberg_project.packproj file using Iceberg and build it to create the final graphic installer COPYRIGHT See AUTHORS file. Ocsinventory-Agent is released under GNU GPL 2 licence. Portions of the Xcode project may fall under other, open licences (individual files will elaborate). Some of the Xcode project files are not core pieces of OCSNG and are to be treated as a supplement tool for building the agent for OSX deployment. NOTES - macosx tools was created by claimid.com/wesyoung and modified by OCS NG team for the 2.0 version. - Once installed, the agent should contact the server and upload an initial inventory, then go back to sleep. - OCS MacOSX agent is launched using LaunchD but you can click on /Applications/OCSNG.app to launch OCS agent manually. - You can take a look to OCS MacOSX logs in /var/logs/ocsng.log file (by default) - To uninstall the .app, use the uninstaller.sh script in /Application/OCSNG/Contents/Resources directory. This will kill the service, remove all the files (no restart required). - This package works on MacOSX 10.9+ on i386, ppc and x86_64 architectures. UnixAgent-2.8/macosx/deps/000077500000000000000000000000001372663377700155375ustar00rootroot00000000000000UnixAgent-2.8/macosx/deps/macos_perl_deps.tar.gz000066400000000000000000036136171372663377700220460ustar00rootroot000000000000000^{[G8|`W#$ ,p_dWgF0kIhFf?[͌@8NΞY=4uuN2L4m~ ‡?Կ7>nmMC?o1,) e$m`p{wrgG߇ys2-x<|p?Z?\_[ &?$ /"ac1a3/xoԦy?IY4 f)T _66~a$Nz0nl֟wgaQ2V￑VlGy!^l-Bel2pN"YߓTՖ6O']6=kCIn8cU1T7-xKl*p.WA]c^h}Ie(UY"z1|eFTQzT?aTIm~I&ՠ!*SWqv2wZ]$I_M0MM d }Y.ƣZ F0ldFO[=,mKjY7q{` V3ŇdŇh:'f2K/U,A 1 n5&Ux6zXq[IYa=pg.[j3aT_t_* ewwTeKnw e{tx;|Ԕ uCVg^ $tqU?& ו5=tv{;:]#R?9=lt,k\-w>\|݃&|#VWqs||t ֥B?vO8T8 ^)V8PT8ѴlH^=w+|kzf9L^Ю BRmQ ne]ߣk $n1@vcZW>^yƆlhhbc?~3(I x`_[( P*_̛Ll6Ҿ؝$ (Ӯ4$-P1~.*g CY7Jq j wW2޻뫛w` 4쐾xZ?7Jg{0ζGV^;g rpKy@weAju 2\Ҥe]JV?*MI~.s ;Ϸ_q>% 9qOc"iYjS=bDqU#KZt~L AMG_ﶃx@4FgY3LﲍSXpoc1oVEDltA"y/^kާσ3~@OXXOXKñp*`+;1L9!kxtMCU]W5=E4 LXqS+ko\Zd:z≞]>[]}# 1?AEIn !]e*E> %ʒ@ρzA#hx.djkuR,fJ5jAom]e΂k;߱a *a]Ʈ֚-{hNqلVC , 0^o"h r`?Lzhh!U!@^Dαfx[E% Z;L·VkIj?&_`Uell4GZtLd?{{J&Wqe8=7e?oh8[}!Q6?DU2d0-yqu{sy2}Իdnwwl!Pk/7)}ZmyR[a3O'?6T_ 0S w:}>Xn9EK5˻ ﳖCL݀4UwJBy$gj,0 CMxcjȁQZz?aß6|YZzū־JËhcj,Qm)?(J!-V( 3)U\ 5 nVR%~E*@_ ,.g5\Iֿ,\9OA(^Q[Ax۠HA]=U L6I<"xdFPSL*EhZ/3E< 4z/`ΰ(!slcƦꕞtӢsrSi|Oi~=l۳ӓ{B~U{U@k I/(s dOiQj~ƚלE4G D5D8|r`HKn~ $ Mss[[bU n>`м1›bD:Ѱ(S^$pix -ZvDefD}ɠd8oC2 $¡#`--n~ͻ7.ټxid;պk.Pp>5NRn;AJlll8ysl1\O+ά΂\SM?Q\r>,9qwC^fr nS7‚ ~sAeugk܍V\{H9;h/]LWz>>vIyYS~#Ίq7?N9o#g*G%\ά9>3'Z*ŭў2AP bt,V/Pho@ۨ'oݭ{/@`^tlvs {VQXiz7#KpE^4%" ? bvU\[\暳LI`L{ kˣ"o&~Y/Hoy=t6UwNQ6U[7#5MPj<g|EH^ή .0`g6JV5 T6=(b Da,]>'v};`XZnlu غ.; Miy]<=vgeKZld_е`})sz]֏+}jNsj|ѶX9y_#}̵Z]4n)0id/Mk}9d峾$* |w W.UInJ?ߧwSg{6E6 w*A7? m@ruQM(az㽠%Z[+zNA R5@9~uq[ `,9 P@7yL; x,idW8CdaAWxA0E12-|.?D"Ҁ&W+W¾t[ȝi& {0^U<qڛ`r 'iđ7d $%\o7@__K˯72P'_h'WL?˜$xB7A&"XnC`ghlTo:^ag h電,*,[e91xo&(Gf:i8xi3Lf>.@jpt.= @Z 6> 98Gꦖ/a>oO՛ @votA7V ɸhu)_@JژMD; x# [ī+6Iap##!Zᝬ똖vq͒ Zi@V#}D=4װ~F%Zf/Rt`QyeNƑ@`j<ՇM"L e7dG1Pz8~־vN!TLL&:P:e 䪸k hO/µK[LRn<}CvXFkml-|!Y1)V`A|RbWM|Z2aӡ0##VvV"Kz$~}O]Fo VvO'"bE2~$ӸXxv% MB9ЃDS=.ci8iʛx6=C6i<!o|4Q5^yWNA1F#ڥx7eD:CPIxuABq y{ j lfcCD"!#QKaMA>k  i98YETbFRbWQ4#/${+M. &=FL&4M/І@`9COЀ@zyh1Ux 2 8# Df!/Ԉ{բ!IktnDZДi2TVR!PR FF@D&F:P #+8Dc2'z>RrAڈn ̄*jmpqhP̮2Ky8z`JD5Faf5u;J)- O;Uv,* y6T J rӭ0)2>!9Hv2|U@Cqˤ]T]JFjeE[Ǩ'ys~5 ǣ54QUC80ާ|"9VU0  qzɏ0B2jz̅;6iF;9S9I*dlWG[VŰ~f*#Ռ0-CZ:8X:[?͐x=]yum8b-rp& hPj#mL]mfְb(1 ZX{+mPA22-]\fXDj%k+CDD]gDDƪs[Lt,f  (MFZY[Ȟ-3q'lT)'x)tM'FU>@}$LOF/rTٜ},T82 phNcRVpnVfC!2jr3y͂-~B S4_2?H31SzêL~ nrq6֝bޠMQ}oGHP2Z>|g iagS9EG|%O7w=s^sl\-ِ_2L2 ߲J ?91nʥip\pE3)2(IS=k&Zb*P#ޅø("i*"*Zvx} *6w&{_6`$uH*XD [6 !8rKăYN,aVz!ܓgL}v4Ko\bhVue lq1RmZ-Bx #ѶO|&\.w Ϳ'e|Gb<+)#hJ&f%ƒH(S?0ZX :&iFv<:ʆ5"ՎNg_]L3ÎXO_~i:&k.~:~qŽگa}(,fZN׆-Dx<aׇ/.=aȪF{&lQz 1bH+ RܓZiD4'p @XelV@0&&tךGzA4[aλ\_ 5Տ.MŎVEH}CSSG7J7N^v:K5O5*c8OwIxjUH lI(1`ӂ Wdž!ց Yñ>I!K,З(HJROHRYqʢuK]_Q:5y*A0d)((}%1#(Lm{F-mC$52sK_HYjk% "ga`6&{ in8̓\ġ]#$6*Td۩=bӭʊK,}`ǐDžU~UT#Qr %Sq?bY5 v_3EU2>քozo ĨېR4n4/!=4D|"Ԏ`:N?XlV#]ZuҞ%HZ̚IdCh7y$ TrY>BO_n+U9 ́nDtAen׈1ȩ@d}1|cDcNŃ7/ .lN`fs>ƴ/MUۄH0u;0bdJaj׫u }G%(ܝeN7AdhFuǵЊ04rL[HF @3 (uk"Vq, }kOk.i=qi9HuYH!0Ih 4'#'In62:&FOV=XH-:I$)֝/NafSkGwXs(C' p3ڹ\w 潢y~c͚MD#79%0j-V§@F]@lצj&D.wS:0ևJOF!1oíeCXeMa>px]^=QC<w:h¼͖wxʐ&90t?zs ~%_ PZ͆k<1pW!x:KG$N)7o6UG'G^.θ3c/Q&6+E9Sdw|K#?9ƟQ/ܑtE-r%e,͐qj@I׍kA^-%g]|64vhr=9G̢U#Ę I%`'N.$uE,uE|㊬7 0L'W@F@MXCAr1ų1 K91AFR/9c})bOLc( +'a *f41T<51 9`oVRH-mY\xa~) yn:b㭌n{*̱6)jHéZ`\سj F|x3ߺ97E! LA4ŰdGZ]VT$*oʦ{c =-`Xu"Wkdͪn)Bp z-Q;_k7Y=5XJ7:R).^G>+X9aYEX˵C>M<]-- (\d; 9!^(R@ g̵IdJrw"0s-nڣ!x{}-Ş;DnpGFap8NYk]󇼥t{%Y*6s.Ӻ=ȥN9XmljNQGљ;2hhG:u]f9r}Z5}KЕX^6MQb&eGi&w]8mjՕ]Z\eŜ Ƞ>ۢ7n< \ C3 /j$wpvֻL$n'r8goۊh![+YPӂ;=OYqh֡؈%#ѡX]"A(g"Y̹3 Aegd#͙U ( &othUHII6,2d.F8 4egY.xNw^)Oc$oY {~#iԳ:R_wwD<ى1C=!>tFHhHOE\ ϱOCu ͪY,&^~%;Ĵ2pb$%n؝ZgAs`I\!0 eY9"ذmDĢͭAI:c(E2"\qu[Foͅo'qFCA䗛W$?Y Eo/k",+|@u~ JG QWrEKhe+69d:IVP,jV dVC4(6huPn+(pC4@8P0F-!_k~_O^w0=Rtkt^υDqC,ydiU.y@A HbZQ$ `@C =@e!reb;3{zO@7޿B>Yӏ|> o&j/a֛0 Z;;+ӈE  {in N)3 R|2j)5,K-A ŝaNfj߹8t5殇 %s}VG0$tWprz4^HAQWk0A2H0hBc`2&FuX4;o&_Җ)4V 5th+Oforv>{80n^f9ͺ3tQPHǼ;敭]*i?b궊z~g0jh%u?*+[s;/ /d~`nAIYN@>ډ_Dߧ*n&s)۞.wbc?/:-l !SàI쨫 %-5Rk^(%%׹Ns|+QQYA@b/PjV P/)_VWW[pGkV}VWA}>30idb-%Z˟їyͣ=ʭ?j?mcyATk \ (yj;'?t_=C Yޡd\o%D~TZ,꾟bO/W lRuxya" kn9)gU襗]|}GW%`oRPyw9gVSѫEQcf~;[C=_R?FZu3)LRap1imFN0E)iìwy; '2d6Թ*X{Y6N09.2=`'o`nuU5/$JV O7P#Ѓ<*Vkz^-zW8%J 4Yk]eM^\0%\j ,^K=PO`UMVMΚӦ,&νo 1Yl @ĮC26#6 tञΝQƽHUaP'/R $[Gwht)zֹn'VH/R:3jmmo p wrmKI<⟳|>=QQ+ es %=(PfFW%(7"'E16D~<%lModˣO+ LQ}V"$v7 dlz|͌b:(GO|5zleӫY23)4d% (-{4EĊv)!&3KҜy{3G,ȑ^ݹi6&(5(WJsWvEX,I*0d]Nh'%<[t ?RHu-\ji>vŐ5O@"|\^ADՑF*%CǨ޲RU6_nV"r[-w:O0jsJ>O98^ ?K[r6U䌎.!/-lI zۙd5+@>Km^͝[rx5 Fb7VvO[mv0)y{d"DXQ|zPA5t,FcQu<9{pK4rWӉxK6}b֧IIǯ[ 3%p鴕'jN˒ߕ@Z>0jH)j29Ż)bEǛfB} 7}6(TSٍӘͥ9 ="gi hwi2)k[Z4kOi _0`}UW!vv6ѹ| 5*挄 Fjg7fKf[ f~{%EyT߰Rc:Yտ?.8,qqXMn`ۑ~aГV`?ԿK^j %(yrjO$L.OЮjˇ ~ZR?fJE9UMWEyϿtOT 8VMI Z?ptй!;wVIhbYzt8Zk.稵T;[*bs=`e45$?\vKkkmҳ O'UqfmG)qsL<[vci٥;.9>Xr27KZCsdթGU-d+uK,1rG&<b7>!uClijM驮Y ,pь"H @?6df0bp ;;[M(I.'HĈ+6J&N.Ci{/<da9O@Ʃעל6䤪2ALP_7y||jr7(xS'k^$0/Uy ӪT'a> f^?g28%5RH]eikR8*֨nF=L=gW;[ nۯEB# ,YwR|+2&keӠ$/Cw[C(C~3)LnΡeh@G=P/iCE$` E\tFF.NgO`a51BnChPPHlρ&3A 艣<ytx.,M# a<; 1Qn >6FVQ o-l6Ubom)UrѾFLmB+z M(9$jiq:Mq_ dՆ"uҷ~,O,N\3p;CKt$J_f;(-`q!Dd{|J'cv:Ĺp93aJ'!s:vq0f:^xV~ܒxֆ*q.A4Hl[`y7-LA{$a$LD#~% o~<бrZNɌf#?A+ib֭`105>ֱFL  ^K1Y`1ǘPKϬ#>hk7(_17ȹ %EJ1j_ 8 3ocvQ<~ ELVBQqzLJbr֚Xp8Q,*Ě^ARD* $͆ꢈb;ecz iB!v4)Gм$ˬblHddh݊2Q:ևue>Ցr˹:g4A:$L1^;iU"Nw"q@l R0>n@._@VCʒ#P3oU*9Y2ylzM299Q{IL T.HӍ+]߾L~n5 b fN80bE h%3&iC( |0&ißdcZ'm}@6_` `MQ91KU>I0 q6כqC I(`kSGJU nbJ[}(40%K7ŏ1" xq7 j;ߡ޴Mq ARQԁj :wP n.ΜXtV?Da(իN MUW0/clwOJC;{b;;Ξ1 fvh4 7m ;!yp8.! $KDHYl,++aƀ)/12/cG">&<5$=G, Bt``7#M=w7,"tTEC**\8`, &0 /P)Ą ck`Dk}rsbmCIw-*l""֌3H9CJ?"OƤڲn;2-WlH܆zEŴY{UUZ_I?tNwY,їg}DfZlʅ$]6,RlLJou"ks!2Tzpd `6X/f +Ӧ%FrfNcigq].QԂ!oUt01mÒ^.0 wN6o`KjP]eעHPsW,b BƠ?tm?uյG{|rGOQ@GՇ}wS1ON~V799DvsLx<?E>TrGi)Grsyt][ȝ>B"]u+cy.?1LFE5հ p#x!EUvnAw=Q6<=6Hb)oM|-X$9*ccZƮR nԒڝ`PBNץH5 F=ԔՍbVa+rHbeTGyhm0A>Mf yJ4> @JR^LK 鴚J(x~R bȀχtE(}X'e&I[5I˂ kf&se+0ޮ:D*0U2@IWBQi+z8awY} \66-HcԓôjH*`tI(C,{tpnm'!!"xSMl֗['k:vupڂԿ`(,uedLՓjӪTjZCFlLiśbN&,+O(Ic3 ``S*FTm^Va$E}X§UTlkE`~Ճ$WW^FLsm m<,a]yBszoZ/9,,<'øm~Z_u \BoJWc`mZ+Plx |l 83`[WW6P-`<┫E.BGCi#H7LhnA`)~b}|snU%]. c2I~r?o2p2⳹0br3ju䶈Qgήml[anOMRP,~l1w;K<$Xk[AuFO`ưpVGW \Hҍ!8lo#ݔϔ8f2%uN0쯭;쁮;}~·FO4 6 (=;_ju#+QD ,Po@a#hvj*M[qEub+MJdɕ[@UC0j Jsj)fkkê-#akf`?ء,"m >[y>^OOk7uUVD|OgAJyJj}P`Y벞 U`j׋t"Aon6t מl?5o'M#j|$ ?c$tb|P_^2͞菭J?a=dC ;w#Ke6CU+4bCY2^}R$R=lx)=ZiӄZJS]$~CP*AMGl눋oük$:XT6ܲc ?|F|c֖\Σa3*2u/;LSj6lHU i7/B2+[8KeR}nwDc "g˼f^fo0ܻ!`b}{}]O::yP?|g'щY0[%oZoѩaY {0PpiCgHiu&@Mmuy߳VE[gWK^9*{i 6s˩2VG3#L2IJ"_FỘ]ܱ ށ]*`~<`wy T/3_e9?eG#bw(ICH~348\Ŋ6QbeVwg%;aQɴp|X7oWÿl(õoU:5@W~em*~f+mmt؝eБ%玫1Fu?믘H:o+(ŦxDϓI|OwI0Ɯ Ύ8<=;zRՂU.jaRt,`4N8N,˩޹x*QAjTsIoJ( gT3&Y䄷Rw#Pnl'|sG|[hN^F "=}No %ŘBEf\5^VIz7_.HQ # q:q2C#Oj``h諭m$?w?>^Y|چ$R{|^?o_ד Pg7_~{͓O+WHeK_UAj@}WR| ~h,p7凍oˏ<mHj]7u_s0{362D9m?9i9h6Ag{{Ɯ6p@\338uc3}1OLSx5*?ޤDd|(r{ro2|PgB-$ G4)WږD g$#:& I|՗qAӲa!LrR;=[$35P`&ЪUYaBK >0JvIÝ,f94ǩ˸1'MK$ҍ٘D+^ir3=,H攠r\'U m6N:hH#ڑ zPh׊oʚtr/GILmxK`~-NЂȔG\x@۴/M!ƁIy^Yq O#(Lxiv\W[0^Q+!`d˙mgIO ?mkwi^MœAxVj4y;b䲷 )V/qv~׾&[mq f;D'I8fKNFE꠷W1akUSfQL(TurR>bt:,os=?~[qfn# =|Gۇs wy*t\6qs/*' QI:˯uGI\FFZ6,Usp,2x^[B֗,zDXloKҏΓχJQNG^%t$G]}#oPgFCjUz^:P3"scz4qtNcPG;ve@nd(M_FƇ"떽\Xx4Kz(ɩ›ewxcр?tw;40UaJ[)9t=Ω< 'p D^x&h "AI5: OYaxrs_cYt5"h},r6?=߬urDn\~ĄҦDF4$76},+GS9iL7;X Ys(N)E.a3АLpnVڴmx @`XJHГr~~^U>DdS0>0fH1yGL;:(;9z8A0g8v>øp9*j28Z n6ŰGqŮŕ~XcJk g)φCw9i9%ƬVs9.C|߄sIB?2vcHsýo"iG.ş[q}-s3uFE6sG:SbԢ,(XtoryC)!$ϯs~0|iUʈ3ȐhjA݈Z[,9$ —{Fα qjG~3 ၉pBP{93Tv:?o[4}ʿ%T+4 yYWonENg0RĭZPD*y^[is"m:f>olϒQs6hpl*>GU=H/y/u`c,ЭgMp>gO0x6qti sү:/ȩ6DO=MU͵<ܵzl. 8|> +9|}iG\ -ϑWsm ‘_~eMٰ|t=!>ϼO"]2/w>pX_R%; xCᶥ9:8z~,o;o.@. (_Hr{!>`Uz4,x[{EKLhpCV\} CF\t9h0!YSs)oA6p2`˄Yb_oȉ"P6G-b׻%vzYױ<DhJXLhNVG($$^/"L٪3|{qJy8EuC @;xu BzԆZm؅vNWR ˞\D3LVؘ ؑhK+Wd%%UFڥU &9\ZAiX`q|UJq)vlԠ-{F좩t@,>)`M[(GNveˑ\Fm/_"c9)x7nUeQ&@"eVs M ws깢BAH[LoK79*߼ÜR;.Ϛ^7^D:cT໴^65*vA2WX>Ѹc,2w6l`hv (t_D7˾<@_M/#ӓq, 1 rlV>#ک*iע _VF$I)={-p9DyBnQ2p~a=]5ğ:8?Zꃕ6K]e.H_c9гd'\y;LɻOىs 4lښNGA`/S|,1EӟN܄$Њ8CGdeE8~K2ᾗ )$h%LD&ГeXCS=h4*k^{9XvU9:47-nW`-\mIMހ]O%7X_h䊇 #Ԟ1_ͺӀuڦkP涎۔KϠijGK7t1Fg㮚 7 snyhŐc DQW|G.&\= 37/{QN$s%Ga> }Vj:&7=]ٴ:e,rg!>sM/H:JKr:aVq53,]#gj:&QC6lUHe 5J2 L\ȆuDz(ɜ\I%x[FhΦ:_RFf9񘮘}'yYbaB<|f7 \Ɖ{$Κe~]`3ɨ+wL%EK}9/7ƒAflX]f}B42SAS;$ [k7K7[|J`}T}ØJzUuV_aFMޘ@IE1Wf4h46" ZYMVbL۞hgC 1C r;WK:kq1 ,QBkx=>Tp$!R`74ߑc6;:}r֞8ц]LP(Tk!h:aeչXS0RiPƀjو j9D~yTw<(ϸhG[n ~c⍎C6C6,ׅf 7` \cq6`QmK rDٝֈ sޞ1TۚȤR RnC@bDxl4h  d\2Fyh w;.)'WgidDIDrmo{&( JXmRYK%㸌>eZ:g;|3zFVۥLN68*a fw, OW[Nz!n:;R,/=o3'ƥAFpB<\ΔE!39Ԫ=C Yu329 I]p8&Q@L2)RZ@BX@7wLԉbo p]ae9f;t3sg *u]]﷌- ,GxK@M΂rSR'5!u:Ϋ(w0g[w=Ҝ%,7X~Q6 uk3% G!tkWU5xтn$3j(e( < KDۄ@ߒZi(} KQuP:R莗\8vM&C4io6B3g/rU~)ԧ(F{nDi3q܃.mc>:YߴI]s[q.-Y*}#g "knp5ʨ|/Dvc^?:#dF$Wvテ m8t зWH{pWZ7d/%ͨ_on/ƍdb ЩOm6LQSǞNJPK;xN j,~:( [5ov}qu ж'譐b:  uԨm3fe`Q0wB  ݷĢStN&frf%Eq-c[)8= ?BӶ&g?ճyIA0^Nc/txU0n 'U|'p\!K/ ^#J߆%sm olέt/O3j^na=7n@c =$E OB ~^cWqNH{xTG{i^xe{i3p犆:J%|RRdħu!{K \ 9rx.'1_OD?U%z?ƽ8@KQ,m^$pJU AB޻{߼Y,R"sr <'dAh{y^/==fofZ]]]]U_ NKZȝihLp5iHkZȰ.":#i3؂C FJa߁{+M]eIӇt{;ԥ&g ؍^lX,Г1^ MGHKͲi.WZMˁ92KȥRrF?.jP//(JfҐ ;DBsVyiqE93 -/Dko GlM2Ւ Y6U dU~!Bن1୭SG#faɭ_WN&xAKVrOMS)OisE37rI4Ҷqw@e,3t@婶j[ ywvY5T{Q<<8;Qv쨩;b`D6Aߟj뱐aB m D%)M@W(\]͝^4!VG7?f+Ih>+V:PLI;t|z2Cdgz/~ɊmiwvQ!(9hc^*1g=N۲֓hȺ7k2#[no?9R~a'?I C᫝KxنiSaeaqJH'۳ho^?/m:IV]E8KIf?1å4wU¾hg\x73:%&='h!Jh2H?X#8^DQ3J7ɤď 7 &/f46WVj3jX)ʚ&OH ,,RZ%ON"!@JBVֻÃ~w9;>;m xB-PM(O|wow:dt7N.&a[yeg- eN;!#b-OnμGX /H+D'ÔOEf5*WwstVkcc#C>{={&~oyc63L4et"Y_wN>ɂYVOpy > /,jQM2d!⼃@!U@}˓КvJX~ 4 X*dz T?59_vv8}#ùxf*TD J%mp e׮,+R$CqB #ءYGpڢ,CT܌yz}>.ڲH $A4Wз 2|z9DsSΒw _JrPkW[Ҏ5MZ*0jƛpOd@f%2K_[ \qFtžJ|yD{#!u"MDzEeX\j]?VdS-Hv@YՑݜjLrpr29N4^W$:{cSA|k-cjlۣEۈ,u6A^]Kܷ5* {lN̠(Ifae&d&_<@ sl~-bPFWz̤UQi-[ `g<̣1>u&$Cl :r- \QID3޾1Xġyo|eNh}`y|AѭPECY[-T|E֮!uEdKo( à}vXy̜/n:tP juFW>`p{Ļ7ygg}brl:XK>~UoVQy.z5e2nM_fk&1a `pLWG(a;ã`z#y Fr8ˆx8;@4eaRk0qM0aos3pu[mUu|)nI<.&+o&&zITT0]:7YKqa&yakuS=xH7v2gk{\Ya8 ;L70|)dhC3ZuRJbC 񶦴3bVyU9tT;^I5C҂hz+Z`aZjz^NTU{ Z,A_+pQ}(c5ྪ ~]._Pu@~] ~\@._Я UpW<~௺y OH[._ uhp48En:5׹l6<J f/V!0ϋ@Xt3`#U[m;c}Å]=3ذiS  b "v6/ň͍yAbu9Qb*w@*ƒby} XEV+v]`Ŗb*].b` /Ut@].bhME HEpNUD1`BpP1OkȔ d2rL@\ S!S.p p{=\.p^ܝp|xrV-ȇ ÅC!!@>T<Ї\Qw>J6 a4y?\. ß?c?-g?}sYkmK|q&0DP}='<>7$ll[Dڙ{ kXZ@%JF(G 7G$#% 4iB7{ Jgu)-`8L2[źHҜ*^",y>|A+wx+:~Ɋ%4|iհeZQ)-fmbZ堟9du)N :6䧟0hH/ >[R3ZfOB{.grb DS\۲E2* Li< m8PtrG> S蕰Q3q-sl3f`[|.H/q<M:.P(vijc/;JKȩGꎚCY%Din{ k@5}zQ}c(ܦ;wvYGI {o7-T nDkXȧc \7 oK?9U%It=lk#ukΐ(Z@%is?m3``Zm2fz2&c׾7^,Q 63w_9rXɥAH [7%w Ml rj CW][R|U1Z,vf5sf mV)<߸]C=9oce}*|_s{:GkJWwaQMۨ4_kvE_By {ڞYYB)C! o '{;g;J=V IA=# '{[zq9;^)3KZz2tU,K @NL9 2$k;~ Z 6AUm~/d|P5":tʩn"UAXXu)3 acQVFnqby>u&vmxgb8hs*`SiMg(X l5솩+&{vNmTtPiJ9.9eE=Є9d&=5(kC\P͓p`60,}@3lZ{cL[{+af 7+/&'pUʗ:GFtB1# ~Nn(@k9+VPX/[jf<@`)?B!Zm23/GI5Uh,g<In{!)eѺtm̽'Q0ς{NaSȺG|9t0O!9U,X-{PXZN!8;[Ha *r q?*)3ge!69Q/ã[Us^Qcjt:}p.'5WaxL;?=_i/X?L<%JE :%q^h]њ!"8>;YhA#S;3ƿND8F . C4h t6anPS3acM4<`b5n`P>K*% BThl @v]8nYt@8 ' }짿ݬEٍ/eUhR.7ƱfՌU̪"&,×yv-ю977=%l,i GAټ[aDl}\P\H\sn]vC[yef޾M듻ң]ǎP gsSy8 kVŗe+¿̱Cu;%0Ab;6*! _@eO ׵:|ǻ)h>ٜI%Q@5i-y9_} uepvld `$=DRwAQiwыhtY֬KT<@%Zm?N@nXS!ooߜ.,y[O^=y˻K*7wGfNu6K {6(ޫ{wԅwoZPȩJUOy'y#ЕWry9( kbޤbHbP ĦD3kд''w1BmEiŗ?/Z[Id$]])מ˔k} ɮ ȭlJF%nL,Dۡ*Y#D:9~.\O`gCjXhoP[ԳAãZhl9*^4W ꁘOЎ sFO>|WHmU7#zY=ͫ=yj2OǘQFeFS:9;_w_X!kݴIxކ=)B{gJx3hpjf-`OL懺IJ89JUC}{wWɛGJ!'_jUVlZL C=5S!\=QXWKENfzC_%e4V,bx!_][1OD /*p'ŒGA#.BA+-!Z9^"3s>h4ӧ%ϲE jQ-.O i&ϟys~,O"J ;ic捻C(itIG#Zgv_Џ5m^e,9,N?'g4Oopny7OVW?蕖nf;UUHd8<i o(囮tX" $^xZxn 0j,ck^ řl~k[! zI 3CZ,d"@tc"ޤeA/2;HXaqj)IawL~j˅#=~hxob~R?o@u^e]W?;u~5==<pr|4N?$8 #=~ԍWzp~ 6h =Csi@MP,hv9]Q~ @ !kvN8IG+C<2n7B ^!`t,xEHШ%6uj$4:A~v1."^]:>6m_jYm~s\8)ølA^pa1Ӆ@aW7P xsR52D6 1T"HYVgz$SM*Ět$i` k0bԏջ3tc&](\lʉ' KcAW!ct(0D"P':4d8_I| So(̒Y7I2b'.0ҕ4~`oi_C[Ť`$VRC2J&MW"0%40; ɟ&eH7_D+qJe&YY-';9Y 2/jQni]qtvr6B./N1[JLz'-ҁp Se&X> W>b<̦c5y Ƹ)D0 ?vd"g`c;`] N+t&o酜s$!jV1 .p (Ζpq,I#o86j4Mk/6KH>õkR1؂-PE;"whrq=#ł1^"֧^n7pͦO zvNƧ`˜"@ӆ5qASúad1fE]L[IikVH9G܈\<\<\VϜB|yiG OPrZR*5RW 0j+٩w؋{g4jew+؇PLpxl&>:G$ )I2X7$l3D*ɻQcg]FfPV =rC!=Ky/N<0P:Zá^3Yt7p+%Oa^yIyLp!lΗpޅdvNظݘ`XwcqmtNv[Kփ$Is$ Q\Hnq4Jڔq 92.]).epLVhCr+P6b1O"bQG./NCnlڕاku'Hӭ&'d~|Ǥ oo{+H0nzv :.HWч<&pJ[bgbtlpG%Fǡ \jWD-]' &),T)nutzPp U_pTL!`0L >40<ĻT;A 0!o@H.TvQkW  Ⱦ)`vmN ]Ypv$3);Isp? WW5 8 h ICf(x On-@Yq͔+/(178C0vJRC#Czq"P!dRw)9n6%Z ח].DV57;fЂdT5c']H[ty!UjGLv ݦXU*D#:֢f↟[1nL/Ψj:%7МaC[Cm |6尿Zd#XiF`el tR؇6Cx!U?s^knƶv<˖%$B,6ǯ5eMr@Aܟ0پiM@*'FMk6ÿ brʶY&*9.`:h])j 3>K]AwH. 1pVгCB`Iu.XDN!bP9[نI`Vlo'#oGׄ9x3( +]mms17z\ iu([ KT74ObmAJJp X.ضӻ. ԃg$, ԪP[$W,x\z S91ʆb"-\d*}X1I*\9'; K>',I%FZ1+JNZcM0'W}4DP)Ķ0k (m ,DK&/M>q&:$kxnQf4chk{j$Lc*gWYrZWV 7dqKNZԓ l=hSwhIs(Fד^Iƙ- &Ɖtq6anZ{M7T"0E}ڶ5Ex;k g81ۤ3MiIJd\@j*rqV3r9XT!L%vM؁T1.@ סXc[i!) ? 8D1\pa)3]Ers 82\g-.'З`"y坿ֽxB%1\tHѴHFlxȜ|݆~W6!$)U3u07RebӾ~V#)J %iuՕkhsHdmT- SS 0"d7Iޒx C|-)JR5N[KIYok4߈k!q>/ 9^Y p <ؕ!f,̬L}lbt &! y.Q8/@f?4-RY5!/{Gfdn?Y>H;MM̅^W!ʹL[* @ TJJ3TeY)ᢂ2qwzJn F>WV ˓s+L?bi4\I NmrL5N!ʻL(^mt 9>;)ti,EIvʶ`OdF4ي:Ab[@rڐaX Lŕl038]8$)9:}͑fL幓笢92ٮUZGn<;ὲVJJPjL/l$Gu:FeIɴI3A5,-j*y(^r0y~ . SMX'Lߍ`3!׋c9#-M$.1崟Lŀ6k[hn+nVt_ Y8wgw`̸ں>R1py>Q @,Dl & >YX^j$鈳_BZ@UR2aMt6t(60<6qivzmHB4P8~aI .9Ɉf^0wr6zb7(>R< Fip#z}nhatA@cζƬ$6?vp4BhՊ J?/ybzfV=5ߵ\/]kd09Lہk%KmwW[ֽlJWno2V$EV/ 3Yf24<C\КQ(NlRpŠKP_5)GrCJ:VB*2U1X*]xf =YM~69lKϡt8 ,nV4,4xNXz$s,DIü.pJd Lpv3M^gmzyl4s3e"/SƺT9d,cn# d :@ZjMs":_ mQjߴ<. -s*+uᦇ_Yb^|,6̕hun83: 9rC+s/am?DT' &^!nXCVk%<v&S>{#3Pmc)spw(uR2 AT{n@RH` [ vt KnyC WVQߣ E:ciU4`-Q@oG; &򦢨H2aN3Qh@ueLS8f!oC¼{3w&it[Q.΋l<~h29T 8G/G6d(|3s 6?0*H,nv3P{{?- 'MzӃpߴr/9*ُ~p \)(%ZLNmnCDf >h|gpfq4\QF08qPݾ7jFI&4ޔdw:0˫h0&ML첡 b=KYӄlRB? >V.xrIS;кCHEgpJJIVֻÃ~w9;>; ۨKLd㓿 zu!n\^MZZ߬lBta 5K%A4Ŷ_"$xBd\L'[ Bҿ qIEH$hFA'O9C_ϜUV-6# u~/F*J qw`a RhWP{ !ˤ"S=Ŕy]^ZtO;o>˗= /{:;ht[U3Jq}oqLgC}!@0|/nL}32Kx:TNNg?p8GiJ=kf Q)8m;h&[5Djh$+T=\` v '9N1^≯2鐆BkˆˡJzzE)"ScCvk_Ĭe&ܛALW3*LC8lz"1R3:G!'3U(^6O*O'@(.5hHy1k|L5ꂋ2びd>R8M U/)i;d2ۯ9j3m~Eǜ*.H.qXG[(ѿ@ A#CE}}UU<&Uz ݼ{IwЯ8Gf}b~EA"_:G/82W9%Rx/v&BYecڲ->EʕدͨR̾M.^Gk3Mhʞ}=d ཉJwP5nCJ '9h~kUܲ7BdFS#$ ߏO:bOzq ^mRfUoQh;APuY_sȇpaxmgs[YzoX( RHmr/M(㹿E!HmѺ<3ޛHpeH" ~ʐwvOO6daU6N* t=.ͪtZxrǣ_A`2FJdP@sc/A>n s~5^RM&Y׏O~E~ 5Md?i37%$PzYJn(-2G@wI:ZUok7CK3@*r,)%KpbCt43%Ē ,^Rɏ6ʶ7ijtPڝhѱ7;0MY@UbH!`mͪ؜-7fl }X>?JbFgf#f@t3BasP Hu ]쮝b0Tz%ʙCqb'[SHnΡCb ֟  $ >x'%"Q`9%9U SAMƛdeydDDt<ұA3@άج_ %P0UgC, Meb^OCgO :seAwT0WxK/8**A>Q%.BZW QG R;! @U+%ڃ,H"ɭSnrbq3 p;܉~eo&:V|Zt\5$yh!ophzc &zc-[A}u(`@  oQaihD3tlYS΢Z+a2%q0XS37)ifЂdT5c'bC7 +w;2E J jNJ`~' $jnEW"Z2%F$qךN 껯/}B&=O(0ȔiA6kbmT OT/?44#K #4O˲,17ɆG%OH՛իl. H$r1.W[}vmU[mid XR"]MlJAa PW#Yhfh4̍1 UV*3ҬHeʸ\<^^p;7[2ѐ!sCSz 3g'؟KLE,7e?0,gW6tXnWꠕ(/RˆPX 2hh5y3q /Ar '.f ԗ65QY0u'f̀Ʉ$3$5%glx3DD7 B!2mRð5&,۲^AS߰bJv`FAlmfʬWjݫ?޺] -c1=13 a/vUՍa‡Ô$Gm_ڹCߐdG LTxqc& #]NF@:(oŢ! -}w@?೫?;}{'9D W].+ScVDA݌V6VV{}]vP \(*W-,#H,ܕhvƙuh撉VA.q3x2H$Q(#γM mR>+$0~C4y<&.W+˪x8f=֛͡K{KYYذU2(Ȩ#VNZrAmJbTOE"^.ozUx4ד/cP i:&B[}M{ϩ/KР EFI/@f{(/ȶ!&b-nCOЛ]N*jU*6b2W"$dqK)4$4Kl7$BX]zf 87Nop8FCQ͙F1J6D9֛J@uVs2;\X'G;!Pf]G3?YjlK)ң B2ǡ"%F u%uwRˠ~s\J\&Ll_A/@aܟC= Ki3yfF{$*X‘oې5kڵjfRܪmNhAm۵⻯fS46RE 8kl'k-;OQ&<~Ie:!"z3LH'ެ|aH;= DYlдYŮAН,Uw ;J,yL$s &J7)B/+OG̊X^ XޠCWס:QTYyCpn2No@֍yڨW[sX"c:י~RQ *p%yHwJc"rA53M]f._*Ú`ӽi i,EIvj:`WV =Tjl+p_iB7&29ót<@{ nc>̐LU(CYQ2 ԫyL܆\Wq@D(5 D]"0b`51R[Iб> OБ7.@횒$zH|'ZVg1:d\W^֒ 䃦dX1KUƉEFNr85uEؚBĄȦ+,55t6]w!&h+F.ʁrD# v*cA AIMT(X$d*izn!1 NGv"EUbޢ1ʲ tz:8\T"/Lfy{WU)ĘeS ~PUEhhXKMXL0= p-9dzgtmA {Nu4Ax)$fGg?km)0g!.s},ׂ-F ~LI"}iCQM&2ou9PN-uCiUqZٕ19aG2mVߟLrbE1jj:V69 KmmfPF bCuMjΕN'#?N-rz;\O |vx%9Ej}Vv m8MFZ#"sC$@ $GC3MĘs˽b!l8 nPn7Ef.-!v^ĩKuV6٭ `P0on G*qj'X5=oZ2 N߷L؏峻Ql "]X>‚t˘ŒPb 8ڛw7Du7\Zc3&!Z/\">({)?O A/R0C+¨SK_ m “fO==hy<;4XFɥ./Հ|z*@@7kb7xv aXkR R l E0!M'T1qM-HH}ɪ.\)u華FhIʀ:ui-ŀus_ZiQsXki:$$#BS[*mCuk2=뜝S*9laĉF:[XYQJ7=PxS85̮2mBq`QՇ>tuZe5F17ߒ$מ3{xV! q?+tD#xUߒa/} /"Jn>bXFȿ0NV1NP}rhގ#QA'^,O#H_eRǵz*A:h@3ޛHpe&0\h ߩ\+~gLm㑉bA+Sv@䥢:h* [bHT$5d!XȦY+`FVxCpy%Q%F8PK 17 .ƁF;$ #ë~)eXj }1yvMb.H,Mh6f wb=^/BF`Mt$4A 7MYԐU}CCR)c:n-CUn[l7_ ށoٰ \G2p0їVoVқx+hzK%Bt biUVM'*^=p <9^!![EF ݨGsKSKEsVHf"9kiFD*dvp2. d$ .MP2J`ۡR)|i[I)h8Q6AqS -rveW9F}#JpWJ@0xh#qlC kP(VTfB%g qk8h@R_C>ELJÃ&LDQ`lb`Z#˘)trْ1i~+-4eKa {| vn0DC c!`5Q#f rEbXnTe7iQun>Լc&9mΉ ;! h G52酹Jg[M|@:).Ҝ5LV~BWyv̻3QK¹p7Q=ONهh[i B3ONH^C-pqTh)a!!hvvv]-(6u͕ i`#pGń;?#9a':76h^btm!iPt4qYj]XVő"lhi1zI2i4b.rR._cmկ͌E`- ")TۋRfhb8uqwzn ֆq>V ÔsƯ3)7_p%)}!b .6{A5 F/3ͣr1,ãgǧ{ӝ6@i+3}Qk]r$;:i ۊFhtFO;B&[|6GKI▨cWifHMA=\V/z`wM|R a\s\ơߧD(538/ 8_ %LDj񠗙'ղ:V,\xfpk])ֱ`t[~o EVr3u9otm;1bQ';㇚LМPC A>r`nBa[%gHRʼnqH f#@uПH[M+U듡uVՐҳ91)} 4t#08hZF@L$n2e^T0+pc(I`f7`\bPsldl| FɐTNF&' ʛi6EA_-f nS`}h^-Ki[%$T%I!7 !xjÔmEV90n8rjK['ш$&ɴ[ɻ _KP/ gPOIpv=Pf1(ɤ8:hFGUd.5?Q8a 16tm`R< F|p#z}nfatA@c2yLc1?NڝR Dl^6iq.-hj(Ok"_XnJ(jfXrS8?+R t&ҕ[;̀)'odi$?klxl@K|c.b^,)'iP-wlaM *nH/z&)Y٨KDKW0:\C ;Ivq:_ P4_4[b1=w*hqbP'?FjI03pTd@YC, tʠ nX]w'DW]&Fh<ur(VB{# d ":@ZjWs"Պ_+LP.] -'V 'R:v'W֭༲Z 2<\?0Z}_ 6ɭح!{W  Bҿxh#-!lpBS";ۢ_Hw9<^5mUn&cj666B+>w]~7µg6ZϿ][ [k|_a1Qt+2NIY:/y;'=xX=kd%(x&!O:FuJMUU@B3/@o>e*`@㙿 JRd_B}RŚPz^q! oH_ٛr"] #<ȗe %fE(Za$X~Q-Aá38~#JW5ʞf0̬<: ⁛r[`M=@^ⵛ"NԢ}@iFݝ.y[^&R[d,$ߥ }6D%UB|2ՒD3IJZBr x`4X_ PԲ&H͂+9{\sϚZ< fެb_@( =ec`bt`!Xia8(kYhQ-F lX zW?b2UIHiF` !Ud^ 2nʡJ!+-Pw7 K_} a8?~'>Bkߓ7Oejsdž APPjAQ`糀Y,|řՍO1> ,g2^Y,|Z5(>y6!|t= Y,{=~ϡ뚣<#Y09%J)@8cqA ﶅwoѻ.>jAsY^x@D+aj<TEHJ% %CY ~! 0X]oWU_{zF#=4&M.;tV q4m~ʘu(?!~x}&IS>Oq*`T<@)} d٧@fOSLxE#IU D 7wvt ;qvA!'EtM3'~- 6UծS%tQ HERQTT HE>RQ2T  CP2T e.@ d i Ca@:+UP/T 0 0>Nf2Wu|\gCi] mTSOo'txC Ů)r\VrU(4W N4,r>.Bb}BL衇xr)>i/v&0~k@KSg% 1 ʥ c`txt4L8yxՅ1XtB53F95D񋔺Ƴ3|ͳͭͣ݃@lc ʡXy>e9ǀ"4^j 32 c2/Xk,x2q,ItDNӱx:QuD6N>6`SuTenqք;\S*Tmv, >XATƦ=/mN&44@h2.N^Rnٝ} bbo8"&SM-/;-MC6,8#:\m0Z[)8r'Qo4`h"px4ޚd/L5#8Rd9wkb| @ ZINNM84FWV(XYu2$l{ϼ_"`tE%Y6Sc?H2y#Lx_tcuΧg±쯏3f'8 &FS`9Fu8tQ`>p6Z09LNSܙ]H9RNÐrpy9dNH`+ s Ȝ2) s ȜVqcsc s썤? 9vN,ۗ\H:Y/w8b@Dx^z]̂F&AeNpSvf{a=;w:O0V'7?Hi σ;@b\K&XOh agI1{zfb+j<|y ħ)@|  /cOS8>p|?-| (ʇQ4"\R5+u>XGRV @9ʗ Z yfK(m5+J*ʕt>&e&տlgs"dT`2\R Հ"('2Wn~'[-ߪ}͆;v+aT[771;,>ֶw&o4+ޭخJQ3ȄTPBň6N5mT 0Tr900EGra$탽ҷ>niQ>FWtU{/^lj+Qm"QMFhY`wn[;0^Tow@L[b;b}7T 6)H[낊J_kɣ6@#V 䊴\̀Gc8ш}%3QKpYw##G;-맄Vt[m7[7<JP措,hl8F`#eN!}kU;J :%o-5ڶ0腣ZޠD5b È>*"Wtţ$ǡDB{7J,@;#vmEW !w]|Wwݟ |Bd/ ۪ =@+ =/uWyz^TMC 9z]*0 CYo 02 d60Hzlzq/_ Roi,hpZFr]]]O2tFOI٤x452%&~ ?'j{ɥQ)RxN?|v\;!B b$@GڽE?Kmu0m=y0i;/X P傇h`@QϟqE>铉l>xX5<*?ŧQd;"`!2BA!, F`@aCSǣͽ-tTmobSw"/@1z?j2;:H:,pGFF{x y؇ʏj([#YY#p{' =l芇Opn7QkHɄ OK{421)pt2 g%2Gn VOl#e`ɼr+6 [5k,pM"I9+^RJګӮ @9515B5qz2QsZƁ ̔ $34YMՌIܙKǦ|68|cKԠiVv FR;lc{ -i=fL<r|q[NC}yXkXWTҕ~r֭)~JYV:|δMִ3`{^{=@ ѡ `EZ0TFx֚?|4y,zXfw(1PKM Vv?7l@V"_qcB2I ͜7&a6/d_&cgJ2!f"qadvIoUL Λp6^lkjH~OB:Ni(x hUbhf!8g✓DUr3#5K,?f6)_|gC7O/Gٽ;Tb =H+aIUSP޸^-l#)ld 0Y6H VrFYU}%c;*Ҫk Be*=yRGr<&h}'L+goq{"^Яn8)P p0g8F`cF@!P^#1׫-4" D[ErDjs{Z(lV(˪6"8#>hJ5赹dp-Q"6;L jSj*1&g"Ӛ[qc1A 0=aYafZJkՌrU_ #xnB(]VɚIFӤh8 61 ӇS6Y6ִf.*H6bJcxd;GR_qO'nCp>:v[iW'g9Ϭ-5.7zMӠd%V7;J[CgUl\/7ER Y0!#~(ǩ(8pYi ᧤f;GxlAW:lѡxpmכ 1`y$=ф7aCO4\Fҙ]vPʍw)Pokɥy ptLn.vYDW}` <ҥ<۽csku=odtk3pìGeL `UA)t=5UΝJUtT:'kS7;sI2GctJR.Ke!i[9T72h6k8n(o'ڔU7T\ _\PO0GRK=_K;;bY؈ذ5'D Aʕ mM^UJ$CÜ0v >L r'["܄0}a:<|ۏNJV4Wnr3HXWE )Q}-2/d`da:*[ҬVW w i4Y}6O q&od&wMoKzL]glnF4tE-`d\dB+n?y60a6y@WR;{hUm)uLo2R>dk3u7.^%m0g_L\e`.B@< VUhdU1]e.Ӵԏ<`c}g}/m;"n࣮{/蚗If]3eL͜Tْqd>UadLRb>~$61ޒ܋%¹dNoaI\.}[xGL%_8 pl$?Ry+ۂ!(7L0z{$Ќ! (pŗ6!P o[c`rF.iҺJz#{:%- oCg`}.2 Y9u]vjimčrӁD׵+9oh%8ePeVHTɤorSIsq-t :!\*&MMLȔM+}rRU.mFt񦎞&M1(ѰbIN³yu1,|Q] )ș/lӌ^RO1iM9'ٸ8am":|TH5@]֋ ( ChO) MXSzX a˙.B+i0e~rB׀6j!XM"mD%JؤRWgZd[57n|nt6'z(2G3Չ{ez2rZ*S-Q*TXKN~xҎ!`R { ;uMo -ʬ'τ觖.y6?Ǭ;nD(;/.qK-@.SFno>_}5N؄n,Ľ f jW~H .\ itG5f`hbXInDk|U$p¤*8VE"ܐ,Ȍ"!Fw R_6&a]#yqu'N}!/v7 4V, Ǹ FeYo'gՙ9y [A3`,:aq3q/]z[L7E|?[qt/=wJ6)KvRGWGC=ᯰMXبg:gNSsPn` AS+Ǻ$آ-jm++[O߫m~ݖ5u2 zA>˴ޟ.иJX =a]oʸYrPio9)m{5?W<;W\> |cV UAuO ܭ̹̹ZMM- sC%){;! ES(L|sD(xpw9&D卆;^_$wTy";Bi6/0)AҨڌi<I 3Wl$Ӗ%Ax MJ%jFHWy Ő)R(5ϵ{{! gFu/fZiԆ j;%8]8I(LӸc9Lftpv2 Df%YfcqťYdȹD삀O_i8r?up9SqE!ƹN"M0BgΈی i:إ'e0%i%1&1մ۱֓pCBzYFR7gQtdyID0j$4DX:[M/L % F[ h|IN(@:[Β]QTQ#:kLfvGRۣzmЫ9ma+nlA}EN[lCxዀL≳}KA½zca~MA V/<d ލݛ303ޯ9PA7;?P}훫36)驋ԸͶcKR<\V Jɟ #bc^opu粐VVaje/Ѓ^ TWB.maYIVT;@n׽BX S *4n #L &R[Яb  IJ縒zJzݏsO]+Ǻi {\akjZuƗC|GUC)^ \űC9jCdϰ #bnԤx֠+xXMaf{JZtKRgcFqQ]QVq+`QEc.떯%ltf5,zLxgzQ]T{> a(2n(&%D mjJfjn=])j8Ҷnз2x@%4.&r)?ݨ?RzQl|(!=x>g JNs>.s/g_R?%D@ߔ$NeK03pHKwE1K ʥDN +YGMcOjY~Se^Pm#br5P:((u4L1U+Q4 Kw&䩒7|ePX0#[괓oPm>WTQscˌ61h*>F$ױU$[<."Nknj5,U7 )s$oA&29?p Y]G۹o5^}xm9o2> _ZZ6"aA"R8M UQ(ujrn r־|ڛڛ5b@ܔR4-́B6>D`c5'f3N'lp[ɦK9j?KD 1\WC)0ZD47M&6_zS* ;CCrc^Y;+OV֏?g Y]HqZ EKo. ւaG;A?q[Hc1@RJVIWiۢ}DUULm;7:62 Flv5'Xg>)fʞ<jĮHu 2ݞDw t҄2uy=t'\^)n^CKI'1zMJJ%p+v5Vcj:j@HWPÙ!O=o!%q+Yѽ ߳8vxQ-b͘dZ=u2Y,^ۙLzG&f1?zE5%snӑz=lO?#C)#<:64W4ٛV<'VE ag56͍]mt]Jە:lw#aދW[MI?&Vx`\ \̨&x =Y?<ەkP>[ASUզzn *C6uT˂m(+3`9~@4+}CրՒnJߎGRH,~N}g!lpjw 9au\! 3O"[GM;h1nYXnUP;d"6C`SwyG/w_zq|s~X 8W0n soG!W&b`sX<%bg4,:wZ~v|}hsiIclONvN-ju}l2n}9'G͜/6w'ѻqg/L0nEϽ Pu1!q4"Y pˏ~n/1tUTi= w~V+h֝_x'%M[AU]v*ËX){N ȩW}ҠS4j԰!@@0,3Qfb)'646{_ʁQ.8H[<Ƣd#{,m6Do!v3Bv>=X{|%P}Š j"II|à*HE6a/7q7TdٗI'((3UBKx@ qr mQYR E8RZr˚KcfY`Ц0 A%\ 9QRZ)QmdԭIc!mM'1IE4bR(] | DF(N{87hQ*|9CWh6Ի¯}Ʉe8"k`hXM'Ks{{s(¦o\?=Ҳ`xd`1MIp+x ;ch18'=I[=fA.!KIV{D_ ,xʨ&fUB˰LUmEt !*Qc{ݨUUTx d %i9qOF4i} ,$%h{k>&H:Z9H~AsY7,O5î62PD&%W;6O_~R0_"^(ؘ[ÖP옷^bY^6m _On{إRYi~Zˉ^NjX)jYnf]yv%rDKNJz%9XN!2@<1*\gji*Fdvg9OᔧNGwM;F}kgޯE qf H3zbv>U's4Zsz^r3q(m?!*B姶e tJ $X$:m7!`*rq1\r`O0 pXj8Ij8E5PhS@o<`QjddCZMW$ /{ڻH6H ?ȢG܉\EG=]__;f/c8;4͝ff|AlF麿elӂ h}>GJDD9^i@ov^g-RA-ox{^&LJ|f磆N/D!79__]d%R`2恟5B)6Wf:}EYh›z9RثwE%,7n>ID87aSJcRf}ޒX`6rN3I dQPwM4ldAhE ''5ELFe *Qj˱d9dqUdq !!SpґdQm͵63ࢊv"C3`U!ƲT{Ɠ'€ cMj)@"0hdjr4Fe'0`uŔL83FRObV SiF1Q z=) c42g4!ȠNd8֙~`s̚>:'ӸbЍB,(3?X\V14GA=PEx/pˎ wʺ% NRJnAk踇C"'jG"nTbULҔ \NNR]1hEq|\!xd%1A8(9Q$S;.PB+(v FSxV%_s r Ԟ6o*YO*;U$Ƃ` 2OIc) 4$i Q]گ΁u%8_^,ȭr3*xMT p#Q}#`}VqD`pPJ'Rb}KC$Pjǃ -M^!"mQ݅j s8lL+]ŗi+ٰ"< J|ۆFuvDJRWDe8D8PF)&n{`_kNaTэ.Pp'Y˪e]ڳFqU>ޭY?e<r̷P,s6gGj0uq 'd/$kx2~yJ*-wq4o[\J@^;r\.tm&5jR%E #(XqA#eGjb~$s5dO>~;nٱa~6٬;2W}M=ݹ@y9S9W٦]աvcCԑA\Rr+ISr-S#_n@V=!@U7\gsh? |?g'B*r2l|lҕ%Tg^J kV׉hijVK:Y RwnzlpqsWe]@? r;Ubh?Z'Kz\|K<Q C@ٳ0'ȝE3hL1s"\3a.]*bYs| ;39^ia3L B|un-mmd3pRk_wT,isg{Nh ¨:t:C<'C%icЀK_Ֆ8q!˂*}◔C5{~ $bː6!sqB\8ts(d`U(jGH ClJFޑKż$ln=wWEv V8 /ђ螒rsL^eX0üʡ6!Pq`=[:N)wts^ iWY~ׅ[d)dՔV=^fO|+,)/\L֦XWҵJǷQgIϛ\&ZwQ9X?ЈKzčPY{յ'p|R!(͜փٌIk|0rk}։fNl)Ìv^ޓF-ng [fMaf3l9fd8'MZACؒcuKw3^>/ ^KDZR 7 xf']2F ~ȧ!81aP8v1nk3LS""H9]9'j'krm5=r#x֎?o RW$~!'[T$sLqOZrYb{n+ΆjS,SؠaLW 1Sd9uy@#܅"჉|` hkZGk$ Ƥ&njG&7vwPxOoa@oEӎ/C7g 緣=^w"~K{ɖSɪ쿦b@0ɥ AaMPLk_!uuvbZ2=dpDMU;7tņK'ȟ5uj4eබw7=b}howWzS88_?׌I\v.3,\%g1$\t]sRk 7*ziսRbWQԥ Ľ UO'sn b)JEPA ګeWsR(K>i7Q"#@,Ҩ8A; Z#J2ҶNYS Q.1;M ʠR6R[{%L]&#::6n< TF=*)G| A!xkp8uY&CT!,lra"ţgyltHLփ&xGI`cqY.3̢"oT8/\l(.[:@;BFXx0+]b}E.iOw#+5 MO1lCIm#߶  HHM8)Կm Ҥ`4ZsM^Bk/qSJC^HXe,}!jTӏR,ik:p6H)-difpN)ҭxzoW"r x3fG0wr`~X&sĝ3Xb)Hr`"@Jߞ;ރ!ԃJfLhAohQHUgiX,&ԝ,D~\p@=/6 a ~s$hcLh,:zA[|A%i{J"S{]um-b-RCcSVw2>v;Eغkj~~lM{ocd{"s\܍OJ~Q!ctPRon<%%T咹V<5у .yAu[s?Ʌn`1:tօ=DfE wkOfxYA-AݽW2c K9uwy4俳񯖲O{iRMG' ,reb!<1l6*"/ε+.,:-`lp{0~G /*8wc>xRwЙN@E{UY{NR8щIgu#F[2K Cׅw0}JsFxF9㲙'm0" 68FʥDaD8ŕՋN=^۔tEaRWt/ , (JbS>G_el[F<]u&!"b$0Mdhɾln`VoYglF6tFV];M# ~bUq>$_0Oԭ8E;k\l:hx^Ӳd8bP3bUXj/8"bL_orߙ^JfT KqFX$=좢<Y6 Y"lCRJe<\UTK^,|?j];^{xlV ³3;BKbi>R+"#ʌ1>pj zBmf+Yf0j0XSPms*U4 vț~v:ZbWy=wW{[{_j8zlܫ;mcwгb/w6 Xlw &orbGoD[ɷ>$,ͅk:~ ɸ0-X;|9S1 $SSSzroTQiCE] b'2֩d_WVwA٬l<,-NrXhi{oqcXG#Y^KT.Q ;;~}0<]z99Sc1^~6}7kT= js K @<0 9h0v}@de> Yf{\ywfyw^KI^qty7H18IpHhMɐj{mJ\k M ;gR8m/?Z=l?Ai5}FQV\LWWWF'paSR6)%x?ºctqW$_ &G)Udz;_zԝ=<RmEM.q] sir_182I 'BL-E);Υ8{@/D; ^=X|poW+ o`lub}=؄3a|z6NU,Kqqm d#`\'ND?_M|Մ\>+$1lE,]\5<@J^>{K!,)_:Çl~?n,7͇oMh>j>~Ѹf?dS8+LvrwE>=zbPpuBzhy IXo޿jĕ|K8&X[y$Y j~ J0MYYmq֖행V%7~? R7>2nJߎGRHd@GW @>R2F:w&Ӂ䲇qCJ `@ߋ#ʯ8ۊ|l*;Gcdn8_G?9Mitx N|*KPO2CRuywm^um 6t}NvlyW#Li|t.2N]Տ&sC%GRfXϚEmgƋ-@ڂSTۇ0XҢ3mnǪ8 )O>ơ[}̛,N8z̛d'5)vY|%=_c}UOx*7|ƿ~κ0g4F4C+cfHdZwjT"*o|l-;qKxB \exeSwUuM]Yx-lM`v_-6 ?! <#AWD,WB7w͟b[Ƥz#G8AH ,F;%ElB̖&nܢhV DŎ48⯖xb@yWZba"ERz񬦲Tvg휫È+t0v?Ve`C6ݍ)fzqԫrZl׻bKUY:Ty%k(Ϳ/ͧde6 l7R.qJCOͤ,Df [+)xPn/*{b9y9BJZEAf@ɗ,s M_j惮b^ݸ%z.NJZw IZ0Py%yuC謁3v4:VN`[7ASMr坄rA97-9Kqr;' 9?.³(b~>F\+ٴϼYS}v= / Tg"?Q( sl^m!y(<:d3_ڝ֮*/ (/ &E~(/ g }_9U@`PO 6XÆH ö0?4OM4Fa Col g08}cQ c2FQ c-?j|<|,?>'3!?G>HHRgX!:lLhV1~:,'Y_$O J āGDC7rg!K3N1lYH+†O7蜏wQ8Ǜ{g =GiLл Μ'mP˸f-&Á5'J@!0*|x@d:u=7KfD L mVAV;[/3pߐ/=gBFҚ*PSM=p6`( Kh)57$%䱅9~)5R&\nQA* @$)i "Aq HfsNp$PmmyqPEQ!|`OaHA8وwPKz&Ŷڲ[cu.p8o) 콷mf[l( ap䊃p \CP5p k;5ВC5(y50 LCP40 LC4}L^@2-e !3`>C`ٮAM]śD]Bq!Gk ZHq\r-xą|f.ϟ''ue+V\V9@+% `wV( ġ X?VƠU(@ P? Tҷ`! Ǡ,6 &+#J;`o }gJU7ՀGX.}/4L Lb` p&(;UR'F[5|"G h]}z׀bJO!}";BEl"z[~E"|v>].g᳧&x<}_qFjl' Ok&!!ۯ6Nџ*q~8Y|3p鷈,%-q2zծ+XqiaʥT j#~HkkyW`KFͣGi_ͣG-<+dާ-Çؔ>Oo GMo=~X$po;@Wv̈|θӂw|@c&hࡸ?Y?<=8\=`- TSf x_Y+w@IOf=`aKa4}ˬj=vז|p+wTS ~ٝa4_r5X>ϱYPI(jݯ+fz٬wBnS̲Xo.xB.؞:tRG&gz?hY)x$D_١[80l%UW2N!_&A1_뇯6==*-TqQc(-aUXR`F} 8<}u`I6вBz F(9mʰk1Z3aer}p{}yf}*TM;{t*1C;ð71G0t8H9H;Pm <-V!#ӋRۻ*9"M&nGl4";j1\W*J `a]]AJv `rpAεltA` [X<̔h fs@0C~~yDMCթ>^WX9&'E߳,t= #t`{&d##r\Fuu@xUKg-8՘yM(@Hs5rEv4@LĀeL:3jF6ƪ~F[l_ A1r@SUӨ S?i WO d C_=8\VWZwjSͪWLyGmw #3tf N6󻍵Oޠs>ۍoC\@v҆(M4<[ ՟Q+huq.%aC/ǷZ>~U08P=1'2E@i7Aܽ`J-Nk)$B.a-?~%s޶=3Wq݁I7E@AalL].{p 3n_N O\Hح[v@YK,?n2rW#vA\!y@hBV-g0~~VrA3ǗY}DW\ͯy1<ǰc^|hk"wպJ3lG{RC P*hxף: ~_lpeYUn3Afcd\5TDU  j%{iM{ WVy\ %iܢT 8@Yb)Ć\$^BT:8;|%K&}ir';rxoV{㦻BV|2'%>^$HF;‚怨ǩ2oB2ޘ+s?>&-"Pj#(;NMV{V-Ȗ,cUP. l_~ijbj.ɭ ^xb{@{⵭גS @Ä!htt2M!Zkx%F!o )g2>veE>Bt1|u{%9bjbkY1g{}S J͔R&U$&g]sADNhҏ Fg]ȵD:jnm.IgzsK4&oIOaPc.;N8պHZRlC{fi?O]˒mr ^a;nQo'ȴQoocFdyB]/ԅQwgh#X䁹8MrZPZJ~)Z*9 Tt+ŒG s}MY|2): :isˋ?zx19bYL8\2ʤh'2@ % +ΚPg Ir>w̯+VxBՎ>ևHg,P. ^rNG/<~U{w8l;x~u#A2RAhSEEhin4i|;M@ikočN 7vuk'Vڦ ) Nl8lXzuk,ԒECĆ +7bۑd~ I :FW+,0y3!.s\7 o*Z+0 `S"^ j-3]fPymَ]]UF`5EA_=:aw) vIO5}:ҠǂpX,h $]l0[j[-odV":y;@n39 ̛.\n } M//prfܥu9dhg lޚ2O;X?40%0NoM1M ,#k*[Xfoʵ@|]G# O?@yq Id>-֯%5 #h^eI6Sj*"[֘R^y6DORD&7ӷsSM~$o^zn/MWwF˲vɄaE"Sxv衱LB qW %wk8ИvLdR:؄ǏҐ8\ eDT¨2Yńxy׊nB0oY rv ?Eue?gXxW@ 2 p|QeH[h I8-HiP>;w6Ǎ I &0ynXSwk95sy[ζԣ?Hw>Biw=,t)bR((?l;hО ˁs.gN"LEkij9PH_&uAӨELA9BE~T ;&Adݘ8BX'EFIP. g#]kS\6HdpK:92]#D|y iʖ7\X5g<^B:N$}ȿf7K-—ց^l/o tR}K ⚡L΂#XQIR\d8L0/HTQT-lmS %,ڤ͗?U6l7ĈIҤbw|/ihPFeBXߞ5SlF}rQjK7T71+-Ύ4BYQ@"=(2Ѩ1\qօʟ嗧G N晦 \"Ykm]"I lH\IM;|'Ɇpw! FUOB7kobPb;&; Q Xm鵴|DU *0UTU Rw?`< ʺ}!VI/'\Y?*`Ie#?'f_V#dK{?Æ |5w_(5EƲ´a}#.4GJ?RI.3ibع+ d\ Jp0R\!WC% cAh0@AyD%'GgOx<)(n*/B-^e֒(X\M`;}=,F}dWJ`o8:ڸfЅI֕b;f i@h4{L!bs=ǫqpˇ[&{1iÕ^|oG+,TKS>O$8ncM!.eݘ6Χqu׾|UFqh\^Dҗ ihL!tzt  ӓCLaIa!k` / 4'!Hؿ÷ܨ\gc S[< 5 ,^8Qbeni$.ͲF6(mŃ;J1WS ;64=;hzpx,I5rh%9>)*O$Wo"Xg"D`]u Wm-GZ.CsԏCќ5YT[>Sd֔2c]d{51F S%B/[T -7Ȳ+4mtt7'j?Ep0] cjU`}5gy "^M z[#B}labxȞ0oe/FN2Uh% {lf 4@ l&cwdjV9v47܂& ECYV)[.TRi[ ՒqJ,9Td;3WW#U3.9ݔ:PcFJuO`TV4]F)|ih-cwV4. H;LbA]ݬh mtbۈCڃaeI{s@'8Ca@ lH\ .WXZZ{z)DI]kelO.7GJLu_u }pw]A*\CΚu oLQ&gcZMt¯(,eyÉWHg ױE0_--EAufQ݀Y^]v6Ll'-{5 8ziCϔ"tSoPp-=źst ]/OL@n2Rn6eBANPUPv'6;;UPiҹP7WN*d% e&.<( +#Ӹx*|K)H>Z8rvtCp`fL! N#Ades-l\U׫5U>ip*{4lG2 bӇhYO2o!#< 0֗U:>$q:n^{S/@GU G7jAl{6 QCgBa{9m)9}@L|=~O?,˜R䟰ɧOn'؍pu J.:.Cn>`{Y'Qp ^z^uXVxNHgRi"k3W@2U3 U|)ՐQ2]P\֍db[ţ<1yuSnc'35Wqƣ66~dY& ]iD;QTyɎR1bp)z=7GLPNjh҅>_5]#hZrenϒBJS^Iw`IzS]"Hz]gjk@`C96Z"/>?2˂s`: G|%bku:#idxj.d8KȮdCAQIf$"\>q~Fؒ/hkx$#ob* @pb@ʌ48YKl"d3JȰˈ^ Z ] 3#b4~gg'\GэLKyD̤s⋚˻CiP ~!NObwP3g8f@X2_g$b2_K C~c(\E@|dC 5rml}`] !~Eo_*v_טꛙ]sĒdt{ޥF1ʎYM2v@=>+b]?@ bjqɰţ;!N9ofVP.q#DD&6zCfWLfvqbh#ŢF'tU@Fb8y's "yӂ6a342>09ZHP![Ӽ ^}HʉHMYpG)&gƆZW![ndF4e+FYҬ^PDОiϜ SG RFo[Q2KQnpYJS 揰YQ ;a #3qB}yrzme.o܊n?4 2xʗ)}m!"")p}u+pfB9]pߨfSO|x*3[u4%x|C(hBWð= m@nGf:?ޖ'I> 2"do-B 3@6rN t$F8Z"Zg7Oﴒ.L}DI"vZ!izJ_W癁,.,)w-B Y7;CbrdzRH|/33@4޺޼NNnN`erZ E.⻂o% (oBo,hJ)Hꔎɟ77x dHȮGCumb4kCmZ; pFp@3o{qxlYnN ›-x)c_jR3#L1 \"qtJh)[DE :=<o>iÞ"AbpƷq+: X%7SY ى2 dD67QoXaCEV_7J)Tw$M$pK^_;"v s o#<] V8P|Cۺ)JlY@;14#7|lLijuLp6@XVIZ-u&mp#2 r5]4n)P$A.Θ4(D-C& xlhq`0"4v5JL0ԉG:r.<~Tq ߒ[2-x$άAiEc%kC< C%ԣp7^vJ~"1k & -0 oa풏"^!B7 % j5^.+[ఽ}α i[IsP}E8RLsA]H3QEaM J7)& %!͚Ec ӭe G~bLKآU,ΑY_:hCOzrc bJ8>9:y넵2E '?e>C奥g|RLt)T 15xD&Ґ007Bg-)zu˕mnQ*%ɬQ&nO;~'nL}՗cp9 T%ADgw1# AG3z} glv4gKKf axu_=\WM`QYfEW ?$b0CcCߙJm h;'fdϒ|c`;rmQһ7\5Ev~Qht3] BJX8CE.zEňp5c^~,J#V]a lBl"%&nt1LS(_t؇ (=Qd$BEz '̽{/:*_0%2 \2FWܤ&{+%WK#'պHAl9Se 4WL?]^ Ѣk鹤%Eۧ@0C0UҜ`ї bI3C/$y=m-Lj@3Nh fȋZyy4S o)PC;?_ 6)6[KRDzM5-`4^=#WQ g6-1yf&TU^sb+hscZ͐DkYa7C[FR֜hd{Wz"շ+gY>crC| nFg^@jj UK AoI]x}^x=fEiCͼ J12 - A?fAmV\fȤF |R֔ M~4l`)w In2!6X`:Ȟ$ˇ֚"oB(:,5 [SȇH#-EctpvSf۱ ij3Y w jכ'qF8O)&$CB+f(WP[c/m2 mSt0b m?4N > gQ/lNliy9SRZ߶F;t86]8z&;1o2_.OKp ZVw [tآ+ OʇeB>$9! ˛@dG*'/ʝ\ۍ}gPOl g)|qC]ƹeͺjWcJxVWg\Var:@vDJ~)S)o۾n>(Oids$8vU5;TP\7چ'=hC,F8_r _ =oH}LيR߫^I/=Di(He=m15V#-nzN !Ùłm-.3JV*lGQاfYYoDƽ?A$M@_clr@ŀ6c2j{R+y{+נ$>,*~l.J'"6 1Vl"6 ת]{/ TniqgC~$-gQ"d8:]Pdd^(k<]*J3a{wV=,lp.AwA}s 5k iL.鸧@gQ/DF}޸Mt8.-dz ͆bS4SJw|ĉ0.pG\ &-ˤ퓂kZER;:`{HZix371`ֱ{Ae'fɣo+ T5hwTF7 g0L) HDsD^zN1Ĩqwϸ hg[26z*vPW򢌱l)qi5&-s%i;ɀ XCgFI߶_;F. tl%? ,Hy]>&`p7$9M8^Y"걺6Gfх0N~˫ÚJd]f|ڜz92DXYi a :)4 M\Z"<=X3BbttUe،DMCCXCmur1ce9 *C}T޷)}kT !i_C "7'cl=P#$)=R$4h3 JFICE L _tA?جp xA*ā&r!_Z aVa3C"fEɓ0R1t>U]#cpdE ~Y=(tAjl .PBq[D{ FA6(92=Q&Y P(v-=%4g!~(8qƛ׫0ge=1;ɧ>8ܹJSFo"Y!6wKnZp͊ٱ.(ȪY{AeSFjN^j%ד*ub$V*+W?JʋyǠ ^㬴Yo[RV&Y̴MNp~?6$~?- X|٤kZ;q/(]7u,=]6<O)L%1+Td{{$8}a2AH5Ҥm Ln4v멮wJe6j1[/{o ǿLӤ7g-}Y ,ƫav`ޚQ*"_oȬY @  <4`m>Qȼ+W-΁ԐI{{['P?ic߷1 Qn%_^x흃Pk] 󋑪ujEyw‡2a14NND{+UgF_5rv^plDۅ-~j4l] _G)?w~yZ~xX^VKˏǣSK_g v p0M*Mx/| 9zIL脈p{'VrePH|5yWOKĞo:;kϯӡ,;;G["u!B;`i["vbRWud(0: z{ݲ5osű111 1Y6=g XxF\ mVXΐ 5vt@ZnG /> 9/PIZvU͎]>s w7A / dωrE&A> PdٔcObY**1$5Zs[ճU7ʆı5b BB}򯦁:08JG`RA;G7[!6X#Z8AV#lPi\.J^yW!؍<ϛ#)˖[ MN$}ᬿbS=@4d8C\`<~d@ 0nYcy1>2((&qOdkw٠_UZAxݺOkX<;٥^!S {xJq-@EB~-l a:>Erl8W=[58V݁#(oFYI0x_!NCL!.OlvMTKPykf6;Cr m)i}Qӎ+bi) cDfC EE!Z}Byc2] Y Iv+qJUB8Dgq3<(橪IdR!馃iIN]8#mH49Y\"i碟i6^|H#اu4<#y9~Nf%4 !,TS]wimͣ X+5ƾ-k }b omyY=_RLRD{یdlaWUPX*FV[ hPwx$d#.@6F׌ke]DCL+uHIܻbO]hN{q~mtM?iyPhJ73&ĻęR N5@}nʜ;yYp|㸝p_`}iHC'5[RL0}B}r\aYeDK v70 kw+%fl*楂8 y u֓(pf a- jщf $S0]\/m^d5\5 6y*$' ܗs1.Xw0 w&VP$*t`Q?L/C[l{?"G(d01f)U[IԲe:7T,G]OncOr_{ w+[5(UeU25DW`ܔBp7"&z4'&iqlm !jij|i4$NB4 m^νaThDL!q8usCV\Y?S(aNSd`Os]qL9ed @3@G=5d{'ӰucWE|L)٫ O*:9aq7gAO0҂M2B X_N38{j;8> ]uzxff:JU>)$W~qQHC+8u,Dd(%FInMVp/l\GHP }S+3,>o,绥YN ɩqYIvAKwRON^oχGjSHFܤ~T74loQھ+0.A[!HSa*_4}A~[s{wbQ߃s$[WEEj\$|a 5O~r_n )~8-:dn0Mu 2ٴ<i7DoA.Bc޶š`uXC4/ͶQܺ)?q|'i۴1~ēkiOW5lol6_nq^W?S8X釓=؃`$D> ZT-'獥t螡:ET Fi*v=}RñKvnWK׷ Z`_x :ýT33EzŮ&$bsS: V&:4CH",Mt( G]ݪ\(ޝuo7s[֟;'G9( MXƒrdDli3c!"&}Jc #)|V{\4nOFE7 68V^nYC,;K4ISq~C&yKt6o%e6M$11G1i"c1,C3g@;/%ur LrV^U?D?")yÒO_9|SLS(9]26)rUxAL9j^kb<: \liqw/>ܤ4.Š!BX1v[ SVC_L^ɵXx `ujޛ~7e8gz˓P֔]iMHuS_tEpt1d2 %0ykLM{Y@M 9G P~lMPƀCQN9ebc!S30`,ol1)42&#ݶIFh(܄ߵyo`+"c6j۱].P6jM\Z&b ksp9m.t=Gq9O6N09NWubĴvp>0{v`{ ;h3@^]7]A lij"74`i""JS)r7DzЇR(>&*$N{&'.YI2#R#^G<`(^8ՑWF-2,Im<0ρ3j]ѯL{8FP!M!c ;QrЅJ` Ȣ!C#gLCs؊XKB՗S?KTv$)ŽNzs⊁8-1.\03F;㨑X ،ZyMPE=CfIO8!/V.mR`  y~09 1x4 pap-(G$,64{1wp{k چGK~6%ylOoީ>@XZ0Q1d'|{@rj9͛jc#pMBz>OohR)UTm 'PuQu+h&P/5;2_P0+L#?7JO'kj+?LlJlYH Mife%Ҍ=̴1ĦID34c& egI F΀>F672E>s 7Ku[UU=~]]SMaM8B&?2i)̅,דN'oog?@cY٧ b<<(GN䑢 %!Y]sT%^xya\{ȟpgGOd-e7vslT12)L Ͳ|@]&V-\][?C`u\3þ) Yd#[!.{r6Ь5 җ<^Kx)Զs<9>/,_1F"[-B۱ɄzmRjV*k=ln=",|r6_ ݧdޥqq`W1i/lgcdJ#:B`Ugf b€"tpeT4LN[X9A!휩MvL|Y>aT.|dSYu3BV$pX@bmh%D%5jps pY s;dxh_\+A]gFwWݿ}_[|}YWz?M}'R?5\WcJ?~+W|*1` ȉ{0cx l*6jN7RcJCf-cjs@-_XǎoXxv>}UXv0K 4Q  [{[ 5$gE\d7@l2.Cys" ٜUz;?WW5\~j^?^$WHExMPo\I=Vk18 "닧 ٝӬ70\_GhW>9!SQubw %[uk ~ʊR#`㺒&*?D FaexzDp(u qf:}WWUzzhO3L}~Q,2[4rKn& wX>4tI.C5h} -pFW V׋cPL}z`" \9AFЯaYzW~߳=o `lYۄn&d.{'-tՏ1vpy0?^rr\xt|zBǼ~s5D-S`w,[DT6bHHϪߺ@ØZVsvc>B&R6Eu"'&2ú3Rt]eqa cx,^f+U7a:h觤7Nc\)-N j#4%;|6?$zJX, t7np5Cq!η.?iK^NXb!s$zv p~;wDgՂw3clõ? 3vw*[*zOA-$v/FaB] hFb&[]vuM O ׽C SVx:36@0t5Y4GxlUtaIl>50+&p Sػz6kk[j5[%<85䱑3 a a2W@lg 0I` uB0-UP "ˀXyoZCs,-!S>$ƌS= f;5~E458NZp`qTm(K( @^b`(Jʟo'Kl>nã9GJtKڳk,XQ^U?S}z޲MǏ"3^ʿ8M8) DVx *@Ck8^DW棯ϲK|0H9%JFHaxHNE,F| ⓝLNI:+]N[ck[9j6"sn> +#F[):e;©-<"QwtoSdN[@WC2zBLYSȞYI %3] sa 0ݖ݂BNи;'hq"\Q`el;W`d 6Tֻ)d-a#ׯ{ZX_Dq ]d>%6GCZEQ 7Ria.ioFCq\HXs`'x>zC&Z`)[@>hfpm 6qܚ}le BD/4][Vާ7)+t4dGnW.:1Kahj>[q6>@˪-HԆ$rٲ>C!UzQx#"Ppb(3ӲKϺ^U6sNfE-&;ǜ \D'I_>͑G-ÍiD0rQmI#*YpBIPW^S<>KX,&TQ+@XYhb- ev 8tj0S0@~jaA1xVLf<քHK]cXC7u=\ A(i*:(- Պ ڇ.$-PiWا WĠGT >sFVB"Bs}⟉BWllZɡy8BE01g7rcD(H1&. 1d t 2qx(nX[8 !@C~=G஛mgkRx hRo r=IwЅ;iVG) Ϧ[noHK/ 6}DuPM՘7uJt7'B5]9G#zA .duG6f3ɸ!+[ Ta *0<9LclcZ^ZyT/AɀjY/dX*3u>ԾQD q: n.L@%Kal48"',|NcJԄ#^Dh[a;{ z y9: gb7㫌}5B:9|~^p ()A) F<]!)(>:BBT8b s Bkԉgt4gw_w_tە3\4kڌ;#I'5פF8<|u $lӯt;Xȥ8dl ƐL { _ .KHKN}֒~1`a!7Qk78wS ɚ  EsK^@n 9Aaٳc.87:'-U]]ŮWYDy0,sJC(LZs.5P}뗵CZ-%rՆ;L;O8?KΒRUla*DSf7}YX۪%\kjqu!*f8`)baAam%KxYatiQoiL-lY;p  -h<v3\bzͭ"%q:*u [)`7tD¨:">Ruin rbLȣb.l&B}>ȼCMSjwp?&)Fk3k"&Єf}4U<6vP4+Y=7&̘e dzC{p5 ᫈i 6껨#)k` 2@ ̀6۝N VIdl'D9w̏,_Y%z,C/NٕbQ֢̉ǾigD?Y6 IB 7f6j5P%ܗC5--YjggY95Xk#»d;c~ )GSp>_a:sʱMHÕ]ҝf(Ǧz7Ǿ2'`2"5ʆj5% aZl?CVt\h~&3"QlSr !vL0{ ͔Kmހ绣S -olK}J1Q; ys=HݽC,[BK](6w3磽SԐrɡsM} UlpWg;ЏmWN^>ߡA ^x_!e*b ZmlܩT"qu FđeLS׃W{/w^Az?=Ҡ a-)-zpRaEI!B(a 5D+_5ʭcnBE1%_)ot&$׵2T,$]"选¿FM (Ow~F_'[/ǭc͉mk"4?7G}i,E@N%#wŸ)0i&gq_kH5Q&(y?;?;$$K tVÕ˭_:8iüǞr{n^lȱs~[˒ׇaGR$^F،cVTm7eD>SP :-@G@ң[Zcj˒2eVJL3lHc 5qWTÕhҝ˫Բ-}zI4OPe|@oDrD5pXYEYlɂ g{?|]جRg 29l W4NWT-*B5KE,^^BzJF4uAYՇ s~;ȑF- ͙L Y^+ԥ< ::bG .w& V–p\+V,[Z冣*T4~,X 6gZϦ8&F|$$6.`6`t,\nš8S GBUс9xQ\,uR({z7Js¥ȯ~T?nQƓGJghgKdnMPTל?sqis r3Ѡ YܫH$,&"&Pτ OEM٪zzy*HHƳ*.W!_;]0I>J%.}#.<||@Gt@.C+dj;x&XL9'vl=%8Lj56D҂ g^Y?P@=&T7#T(g/jDB&,W.31T|*Gsp ӳ t[􉞽wF -/YdG&[V1|~B<^5%Q3fz Sհ? a@va|MJ+kf2u.#>1I5l*Z.ʧH~!`D9LI( Տ5p Z+ %CN3D{Ŏw/_(,oo`8e.,XIneݐNQ-hn(A Hї/2Bݕ{L99GM`4Ux,UM'/ZL'KZmÕVެJU.$L"_'GM}&$`7nZ$O:Y}*{# m~T^B(-3늯NՍKc+Y,Obm]5.aS0˒&L LԂDG{ZrBs/"FDbNG.EDlC3>8`ѓ pJYH /OdQց a }QOZ7g >H; J}J)ԇPw`MP>A-G< H!q5p-CZ[:6ڇ4$w捂 ~yE f0 o45v$݈QYDdN (D7D37zT EbIȏ"C#T&wyrJyT1 $\h13g,51M8^+MM}B.-~#ZMVM' Gs8U>mϳs`w'l7Z TKteI&5Zd,FN􁣘!wӃ4T[ 䂙BŝOңh!3\xKdCCA7ڜy%Jsyi`P@1fU/Uf+ӊzsGpwwۯw~>ɯv( ('\`xEv~~\Qq (s|_M;t_sн/ p;zc]KC] ?P6+W.ے|x%0z IjQ' :j7rJ֕*OoX7LS8XRoxU^Iy|c|2F?Do#vPkH-Uzp|ox+ࡣu zt;?n y@hRk6Gme5**뼇/"UaH^pEvnǩlRn^ Z.yWŇWl[И :œ})'E& λR&};UJ(u[=,s!ojmRb|er(^Zu$|_QH6LD)OC_`R0IP_CE !'A&x`VTFI a=j8IIReJ.Mc~uc0G "4u<^>b6yF#\'&_0=ݓ։Jb=$v  9Nެ:&,{`?tow 4YRυ]X}≪ ͪg*UhC\\ $A?dY7' g!es /fY~ Z+SF#^{xFIs  0zJr0pk4C1AC8`aO72{thߊ7;1DoLd#<6Hmm(29ӆ2 @F*b ᵧ19nIf% bX)*;֗;@OJo,$ @# הʮ $@Sfvܚ sVx6w= K%NDDE75#.Mz6L{A?;\8\ej5BjJ' &vdzVl׈xMwH4==Ee+/ ,I2.K{v#]s߀Ey9 {bz,OǪkL|f8v' _>Y@b}W6 5&I86P2POyzmWiT#d sH鮈7q*A3޶3Dnv>ؓ30 TP3dAwFeYGN*0JTqqҳ{8Dx/5tDвLLh롚E2 ;M3 #X繐N^4'TMo4TFDj2K\ e( yӐ>+ǥo%;׏zY z31͏{e(AEU?ǽ䖿fxBy%En=Kk5X:JyG4C}O9<׺E1P՟OՆvlCU&X6O1d׋> [6RG[UXwF®}G:K:nDOXVA.@ cv~?GYtp/ Ȃs}yLcu͗t^bi*xU5rp"9CQzdiϳ??(Jˢv⧿1ԧ0X0{LXܭyi8k ތ奭B.zhlMHoug)|stŭj>S'd^ -*Tڳ)Ow&TՏ*i.*W9]7Сyl4 G,ϊXam{d/R>ݤaDM?δ1#MqZȳae|7(Y*1\CR/~07^ypuŋÕO$OoWW;{})sH%AWi361@~{yz/vjm_RfVo PT|{zۺ 'Pb`=;m|s5ћ}׃u{ {vK9ϯ7^ΩwcaAf[.{yb&Ӕ˯Ϋ;{/jΏk7|ߛ}gsEԔ`~yj-ɬ)bSסg4?@'˝ޞã+ޮ{{ ~ |N.0fBU\ބNЕMڧ; >!*jbXՒKµh]YjeRB4Tԟh UYz-i^rCou\EyJ+40J(U~00qG7\F(㹕}<:Taǰ.n1yeaО~zQ}^=&}}=MnYϢ-`n=ElT/=ڮùHLH2X%EZ̫;7ȼzEm'P>Bg%B>T5MٳM@5[UY[ij W]>‹z X I;"'g?g=g/NEӿ Y}W⩐$t: S̗IvU o1%h$F+4h")lQ[툒"TUNXʩƨ |?N`%)g,p+2@o>:2| 0gc E'_07tq8;e гSzyg2Nu;-䗠lŮ7zc72s<(F4Y<:, '+5JƧg`Ѿ+Pon#iv:tG7h%ˠu30{ zVȠLDA)S_f˵JI}ﱙXeAb-V6ԋe'ރcG!PǢI@*+8SQl,?~!fTBa`ew1<Ԕj''yRXNC}ZH .E!.2:LS^ v7-hJnxU+pǮO>z$9ѡMb£ T>1yV˛ƭSKQK1nSZmF`]bewkMz:343k{F#m #7 _KmZ='6v,}1ζaC*˦sp$/Z;nx~ pÎ9 _j ("OQ"WA~@ KE : 6bG Ԇ/A&.QeZwH `{?d*)p7AlXtm[bkEKKK_?49kܲ?gTW;yCH|Bns;*huZMղ ɧ$>CX[aq+c+|&5G)pyinFϥvJmŽ{JS =6S,7oZ8/Z-9Юc"]/m(#\H?+ TU[\\kMq)hV>톖%6YpGTܙ7เPs^{T%{R H/#8)ԇ1YA -z@Kg $E0. V"Qp&s:etI rQߟ;>%ϯ`|'k'O~O<+J;Zl_|fvv֫=w|0AtۡQFU {;beov4흭nneU:ãae]\MYV|>-{i6v+{S-0at2Σ[zax%͡ՃoÚ.Y/Þ*Z2@tS]K)z(ЪQ+FSjjOc)Azx@Ʋjf@p>]U]T6o6Aj =ڗ5wLIi?C#W ӧEA"40=ǫeG~~'L $P|GulL1sX,oI ] `32ex8JGHQ~ʤuڝ̖l6j[{G{G6MA"n@o[OzîtZ$iw4'Q9SP{1]N/ѵ $N"Hc ϟFYܜLp_eytoq`)2zZ[TjTƪPTECZ[~UEtE*5E_̙ .Rx%#][i %F` *ĉj@ {=|$krFuCI@кEa©nUZXӵY .vM$*Iu'6jMZ{zc~ݬ,*`7AH(~({,?˔M @ 9|^ԭ^E7\C0[ʨutڼ1 ~7oj{G&VZcְ_qܩ%+qŊGlVܘX^Ů*S(\:ұ4fP{is#{fyuYiu6ufKJ:pU'd]*j ӿ'++po!gyZ\F{owՋ~juFW.5kwih ZQl6Fw+H̠Rj%1&,IV޿E qղ/d  a./֝X`0(~>"Zzz jEBs*6w;!׆[a@ITY֒fL3[Ckwwvɸbo?xOo)PUY@3 DUrDHWQ, wg/М 3?h+p-YTG ̊\[ygYӓdYl'+e{Yzj9'W+W -7[0i[s Z^O+Nʌ*1i)73/)ӹ-~UzSR^qu O>?=~xaWoG_/""[쓴aswgr?nz;lj]5,v zu"+{%ubڃn>-=$C;c~|+JB1 *lAu =2^k6ɛ݇jV7?-p|ߝWo^2[%L2| WvpBLY {1/q1+!3MfEIXgomlE7]yH/~??8y$^VWWՇǥ!0F??y-5'58k{gL_C-1lO6|59Y]rxh xu1bi!HT(t/..pKt$Rː42@h%k"zGxu(bUyynMJz oތ.=RFGQspy5x,?,RYy'yz :}ޮ۽#_Fm- -LQt58m|Ȟ#c~<1=arwg[ {Ly3>@]JE]kaCmVEv5%.vLk]hNo_/}ѣJt?Q>?ody /]?sk?<7yрiXvѤ * giQG˜)Fd.@+zwmDyeUd%WijQZuuɇaGUEzPN9(dي1y9=2nѕ*y>LkrO4JX0*X\.nu n/V(U_vib*[Ըibߏ_/h7EqDL3FTɱ=\0C_^~w+vYaC'Rdά_I1*Ps\Y[)Wyg nG%+&#\sG*-vZ@'."ٺ"Lwq"TMGyKɆBFN6bmR>W<=E/8}J椊'YgQݤbWofӴeD0sbbph.|&_csƧq:#ۆ)ctl} ,߬'nrNRj#lW jhBqTe!܏^fc G{o1$8eIx|dOA{ENgfKNqu6>e/ vXI44$”nG>\rIGYW&'_Jt\ +k/2%'@LgDi"QOϑC,h7C@::䨐fܴ_8 w[ѧV o  卙Ƽ.M#~ )*$âL}(_"Zc4D~049A12}+,DEa7N`yz8v1ʃeff$y hsWRTSD{A搭z`<^/pc@IҬby2;U}nJ>yCzs* <FI-ȗjMG5׸_=ESP_ȇDRsGTS99nsF UT,cm=\C"o5 5}Æ *Ʀ9*MYw֍Ѝ}Q7jEJhtn7acF2ᑫ:nRp޻_7ҭ;WBU;6wd{`>\w `tl6捻VkZxxuC㏝萵((7igTF}7aŰmA6*iRoA1["ԑ2fNi P+ }n? S/lt9,.0^ ir#e[^S& [p]ʡ;T(8F3\\Ǻep<TI-$"iE/̊'됎SeЄ&(weHp8\i xOF7CC1 4>gw^c_͡$_b GS6 tL'zlF2uQ3]JFV0v^A}6yy '^c`ѥBH⌠O<>fNi{mYtLt?BYʆh 㺌܅|D ov:zv7v~^^҇&27woC֩^s*zconj0[]X&b]a:jԌxsGF[*]}RRDrT7{o^gHX Ý-r$:RP[?g\wiv6\hLܕ]TMNNT[гvǧX>fD*WʈtKeҮLEWGqfcUi/ˆ)Bo^'RlYb2ŵu!-2@'db\}Z4~`ȝN>iIA"sViŀj>,._e۟ʹGWVkYBר,f}L~&n*s} aoxi~YZl-,W7>A@{i+ȐtA4d4%] tUKHv_)Ň{* ARåB>4Tq԰>H8oɡN^RQ$90E}Q* '湨_u:Wקraa ۅpMm4UZ<5uUX<.b+oDI |?7c&_tFhs4@~Nq0XnGAJ}k?o+~̛u L}SJ%E;UR'!9CKfnHU!ڷJQ$k삸 `0+%һDI\B|MUYcKܵZ峓#lGpl|o5^:.RjIjK&y4PܧS:${cMI4]Tb,JA&}H[r/]Dj,*%@˳qHf?}8C&wXA|osv5GK2էGko`:Nc4ҍxO”V?!&TBUG^/NǗ(E\mX@AUsb8&Iܒ~`YŀP7G{kuyaltC{=5 i(;>/^\\,b̗EddhȒ͆n=P>?(,4[i'h-̑dN!jr.Z6re2Vqq2CtRgk)XȻ򟿞_Qx#X4Ȩ Xa`W?.l8ʢ($r4[O pk6KJGRŎH0=^Z][`/ߢDLEfdON@[UCyR!D@4xM|Qrj`0QxCD$2T"#&4* QG8Z6(hF>R8ʒ4Sl6-x|Ͳ16ê6g()PhA O`ڽ X'7Sl;>:OQ `i-R tY$ )H$6pf~eMg8̀QBm[8+B:lݓXǡ"folv:h{TYE VM`3Lf^wXP{}=eۃSI3?ka%CG3KZ(-8`rThu)Q㉺0쟉(8J-&caK[7ƌs _ /K L~6&yb8$Ӥh֭8I1 ;_?EǤ~4{[;[7O–ot(bt72h;dXrk]osjP[&n)+? /64^l>ttx;8c8ܸ Ҧ֣d@j,}:0 )7RrB)H 1ᴦT܉p7nKK=]e!+hӺ*V*7 +Rsy]p|[SpoT$N K+'_mFVWVJq2cgvϛ1߼k[؃Fc1J9+;0\:Q. 24sc1r#V/fXJJ4 Pl?rk hs_›y>;'픬y%I8zs#֬py]9{xϹMwF4B Kzجvzng4Prpr#hm]nV8tOgP{E69n^Z6dYM]Ψu'Z "Et7;paϛR1J++s5dGӐ.p ǭ(5,P ){dm֣cO W,ҟLؠJQ`ڇH0 rR$ HWLQ:;w( kS՛ãho5cyY90Wmp(I:=g_=>6%<==S mctPs;2S1 /.^V4fIEerq:f|QM2q,+-rD bBR0#] }pm `5'7ޭԪݓ d&ܰ1+65BV}ɋ4GCp)вRޘ-P ޠKԟƣg"(sIh&` GMfIHJ=:\戴6."Cܭ`!QU< g4`"?@T4z $p1}!$H:lHn*i@Q:x,ɗǽ->vS~5cmUsAGΫA0a~5WT5z*u˩/}|8R9X~:b>ږֿp%jm($11]6|LR1'ܢ'R~|D-1BC8U1+NuNZVV%E6`PR gWPM~}e"F@B"u>8=5V7qPd>/F"ŧVx׭lG!RY"qV鞫G0syg*oȥ / [ּvM0,w@1n nʔm>_OaiQt*[zvA/rhZs0[5J)ge]hW\ܔ(X Vdzflu/~,v^K? :,o|;n=\LA!#oѷy#H2w|s9vjݣmF iJG;u֗2qĶ:8~gMaF?X2qVf^_EQzPd:ZV &ꊼR5GyҳKF7/P@ceԽz!0˶A.;e[F0Dž{Nmdx! _ h.$b&(wŧ^no'UF8dd[Gods*ʍUL~aP)GD Цj.IHw{r k) Uq3̹6f|Z [ H]M{!`N\LE]d@ RO'l0e+w;Vo6CӠXA _# o'DVfJ{K S+Ebai%]"VW`_A 6qZ5a :J}|o7v[AaZhnMvYOD_@6|:0.+;VnA4J%h@nt".Z [>JYG5V=xPM<ܲxⲴHB Ϩ@7 [ȊfUj<ԫj4f|gzgvt:8 oπ vhxM v!kF R YSn&T~t8$$I"/oۆ nҪ$ jxtLb=JN"UCŔ#I©9v/^V+ƚXO gH )Hf.JBCECwN{^egXc0X |q`K1޹<nŮ.|m'\&].oyAT7Ѫ*#.*vfC=Al*v>Jo'!Dc2 >'U,T'zDym9Y`fck`mg?FͿ]4%V)eC 7EU+S7ч vr Uo 0FVl1ztm5rN$aR6TҫJ[ͦ5hXQݍ%T 2gLtt1;3fl*.m&] (H,w%LHg"id@qaRB0La_C5ʏQ}E$E6P(&tP8vO)+ V-wk>orjy\h5trBL8zFV^iw(k?4smH6JRkو3w;}Jՠ15y&K1PZyLs{gjr+:%dP90)0#QVDq֑Hͥ?xcȭ+, n3S D>M W\~ [w#8rnH@B-(gGɥB4?waТ8u'@+xKT-S4Ǚ0Y[F%Fqi3l O"~bql ds+vWe*bO9/4fmütC\@@Ivp`5Րp*7?o8^8~V+b[9xjjVK:O_HQŜ5cQ4:5O.iB~$U~с{"›vh6L&n8Z.hy~ d%@$S a TӜodT W^I,gm(:m7́DR Cpꡟ)d7U)2ny9.73J_XԅIe'5?"LK{7#c!k8x$O]CPDxJ1:Ko1/.G -l,]5|:ѫ(sHqyzbt;4s:  FrPַdS S@mCYCޣ p(\O1X&մ0JWsBO0[?65KHtOp"J]9,a w0Ӛwpϊd)ڞ%ʸfQŀ {2ji鰰18+|ң?2w0w+ w>p][|لgmB7E-qb ;rc.Ma,:S*OP˱1@p4\SdS"Ia!1-iދ7suI[dQmQzG/yVc8i"p)PHZ6~h`(,Z&ee$߮HW/K{}1)lJWNt0H&ֆROLJV6biR =ՌH'e$lo-᨜Gnn^u.OD{(M*+N7J8Q\R6I2x[ĂK "/L3Y.[u+ pK}qe>vBQ Ft\9)E?,Y n60qV,,=-I;Dv9trY,x]jUw=GK+V VB'V>)" gDYYT? `:w *ǹ`J5̩k1*Z9~*]d8/b"alAEX6S n#| 'jQ"N qO>0TLs_YBfi-lp_jc22$ۑ%_.c9hpayS t.BZ̟Y),t! ˦]eB6햐D‘žb5A6Md1/h1Y:P3APrReOQ8Р&* ݶ Zhy<1~,|RoGu2i$[UYdK̬I)L/iǐ(-',?jڷkk %egyȠ4)N2Z LWI^qV¥J  &+_te2nm&+x (`w̆9=a;r$L#*iku~)k+;픲y4g{fk0ea͒kYiDZFZڈwVP[OK%XzBz1tb?i[Epti.Й3f*'1zmɁWN.ސR (icG%3u efT2!&- Z|):A*FqWZvm-&xRR:@CW?Hش8 bηF(A(q+.3l,yL6xk a841շLJBwaOyP.'"A-3D$$S f$V|4mkZb,v\ƃo#|N`ǙVV䚱rNFƊD|8'LY;ODֶv6`؎fQf[fribu4yB|pȮ"Qw[A75Φ1*԰"* mt&f%3Z_Ec2(cV[WbCtNR]ZIb3zL8T:$F s#46;e^me '@𛋄QtƤ'8QmY8Je㍲k,9MSn!aY><!$Ἆf,=R68pldl528% 0:&.p[ݚRv63rYnƖފ *)N77+\Ju1'dϱ@W.--u[<8tF~Qfk2GgcAx}ajY`΄;vrMM^1]=iiؤ;h>xwFFSi Y =gKMPzhI#{t3]9<oahG3sj=M%_t TV>5Q㋀onZ5fY×46s5Q``p՜bӸp4>YKDW9l5eB)~ТgեGMǖ˃4)HNA%g>V)D{i(ϓ0&WA y=$jF!N)-%.$NX&E>& qP-A |_|'4$=%qsE>z'ͲYQz;/~,nBݠq!yؐY&Ṗvhu@aSLI\1d_&I q^.і38dlm/,Ʀ^B"㬐8420%dfnOy젰мLԺ*̸d%hagbM0:sC {k8#@WN-ؤ 0K,1nhDte~ih\0 _I?>@cq>>W|4:߮.7- { 뜪s:okܮ#M:6X'1+J#x]ajHNNg;`W*cppOStxE x]{:|ZnX)m['Ҽsdv‚?u# ./7#b5"P6pFD%GH^Ą,ȕ[5ߑ+U8w3s@Sid3:[HmE9ROvP(\jI9(r60ͽܫ/Uov Yј1O4Ε ^ Čx|[. pOħ ?2ظjZi'm'#?PB b)9DV갼J'!VPs0 bwќ\ %?#^gLm D:pѠ~)ZJ@XO /z {6jw > Ӕˆ`Q؎ ՜ƕP9c}j5}5ϻ:K:NQ-6?휢ϝc'pGLUR8;dE9%u! 10ZI-[UY;"Q:bcEi/t}_r1iWnÎs Y٧uu+*_z!3ωc$ A;5G*$&ah{la e+āp ͢p{wcMvm&b ^hZ hp(>khSm5vXGQCjO9# ,>EԏzDbk i β x.йs:N|MDΡYJ۵j|HhAѥBjsg;v\a-B:.<6>3!h\$("i(t~"sS8Jp6a "^H&ݫY19>bAΦ=N辛͔g19^f_oR- ?+efqZݩFc`=nhʚ0, ;fcmV1L4(7f5lD"?шqT .d'(dH]T! ֣hC4Xy2=5'Jg18Z [72^]1&V!FWxVp–j͚MW_j^E~r]Z (9 mk&vkvu&&ư,*A٘Jm A ؝fJ8>pcѱ&JX+28nIBK4'7>IER[nشiVek p(-8WG1Qai2joY4Dh40y`:Y>C8K_yMEDQ% r8ӱԬFxլN}R9g.1#L-Yn8-e4tdl-%6 卜ɗJMLו%682 (E|ת9SC2%yEf*cӥcGH1yb2աhdn<1Aѐen<9baM 2O%CkHvE`\k4;-ɣ3QMc=]Չӧo0#%9= "-Y)|UrZ:؅n3g|)2OIԕ<0RX"6&T>^q/Bl5;J +I!G)*kF0Q7:3Ug֋|'V䎘F ikKN8S[T8LWVIǢBͤꂘX1*7\KLdTs5uP(Zu '}0zV ) bV9\!<6 44 cqc)X6hcǗX/qBX6oѥd=` ɒUPJ%k֊e,uawд t3:{'PEIhaf(AL&knmv&ΨU"gSXt`m+鴯Y$2-ޝu- Hc9Z43;6 d*F ۬xLK.(PIWS:ط6tFc—u]>b$Zg77{N)vzJ=)jJ CQJJ4') '1Lx2Ol )S1c@J=pQ'^#moi: ftFGgTؘ}6X Y$}$(c\maPި ʳ3iXSY؟it1Y@A0s=1I uLqoeSɻ&_kH㨐{ [wq ws)sD/G َiUeU %tZ*֨q/m^u_ &Nq9Y1UK}4dx) ;{&F'd&^?@="%H o*",~62<% u\*1t,j.2nB0ql['Ix~N6b7KU;^ ,pI)=O5N&e\N6jOA"=/:໏ueVа2s`j@mA){R*Y:l)bhJ Y}{a?eDƊ2h\Bܴ3wiUפhkޕ# _jfF" BHl A>A5&Rĵ - j7;LftSҭ d$7AdT*MmfQEs4#BK@qfc|ѥ|䊮I`^h\!e/1(=IS;\Kt-y 4>%WqzvG(LnKY<(2҄+4:l"x&zGbV9bWI+RiPe_a)\ s5M8B dxG6gi05jRƔCsT-nVN7*hT(R\JFE#&v;C w N J)9Se‡]+li4ԪprG13@xͼlW? :0+0ZOirG AHI&!%.'2㾄!bk%5`Ҕ6_%N ENX5N)2GVVD5c.i}5Ո9?Hox:8+!xQ`t%&?oIb _tˣhso;څ;l'\rX?ʟXfLayvR\E.-_; h9քWl4AZa`YQ/|` .MοÇ#wM^[}IՕOVWOά9q2.0lBk)nIƜqm H ( 'JlN:4~$xNFwsg pOl'yև;\E}:RE.0ZH/ /%NfS^T'W\Xu$(C@,IH|ٺ=l bX$ hW~J+IYĭkEGGӘOM7F7l]wl 5z@GN|砭m}6:W8 m_1 s{*YH^*bF #/zVßۥ_>o yYSYy˹&hAo +5 NEn3/P1y|&nvwtQd fX"׭E7aҮqb篴JY0zjJu?1gdPk-?ZPCCB~28j҂uxeMpz۶_/>#@$׷7^%|M|;pS}vM p3[έ-+jEQlGZCܵ)[']IUKxQr=gZ'5E]B 9 βzoUOFuK\^@Uzsuc[OX.F}LSf\28c&Z=DyY0mVNu}T7V{{~t :jw- g&VfqLPv|qVVGO%m-uD\Hqp~ a%i;H-Lίi7(Fu -Ϝxzx[gJIԥdî6Ej$sK<{[tɄBR c.lB[N-;^Y=jmi#"bt##>P(CKx(?*1D <# Dvpj D@x!TXdW |\(By\DE+28g*1-rb.Ëި-ظ"<_+v^|}>;譸.Krײ$(BCN&#w$I7ZR'Z(!ОY p0^u*}(sgSʞ#f]c8FH48Q;,b3isq[+Q<"eTOhڂ+ܵ9J%>ጣ8%d3&cgjņmALGqrԜojo7RFkUj_b״_'UKkE~Yq/l<ފ o[yp-G3嫲۽o_זvQdaWdEZ=eGsCEqet i8&`,Ԏ0]@2d#{e[5( QO)oZʹ+tKE`SqGKxjx-K+e(p3YRqh[%ZQrҵsuf?Y`QI\%JY 1d6cNDW{O,hi=+ )ajmW.I7_M-kwaβԯTBѝ]Ckg{<1]7LZT/.{i.Li>מn?m5qn+8]?/FqC2j_b;Ov5:;D`7IҞk@Nu)pgl㼕?A-}a4PE,Ġ8 b}mmj߲azK ,\-G _izV_sBg~^#BA`|[$ė%vэ~\r[1|X怾\ŒS ;*V[ 2'aElQι( Lcg,qxmt,;r0pDVԵ+Z ÷X<ϡa%`|8#"4*tgЙb :$%KHߊ,3xTsP&]&!!}mCKvQwsSY $o{CHuR~M`27WE!.s;(WzA-͙m.[,!)k7i&G+* \>9V^^u%# 6x#GF9% \_d^%⮯+҅ RHĵؒ]FE20[YLG4'/Q3dJށ%/4ۀE:\Uܮﲮ$sƉS12%w!z3֕jlSv%K(AGPf;Wr_h>TG=Xs<,n[{?\YO& H͆U_ ;‰n|A7a>Pľٌ#]5YjFbCݾR+ Ԕ@T0n8Uzޘ$V6K(JiLHh&E"ָPHh,uEgcж;CxhicՄPuk`/l`r/HaGw5@ MqG$)aie&U[K[dbeĝpC#[xdDg5.> ^+a#܆P *գ*ct`!"*<7I#KL\JW[ '; oB'$=FIþ%Rz0ߪKd=pסMaR[G7MVsC%Ө/dlAzXԯmMI6ٰCW ɫ3WnBd')o+o5# 4Yi TѼ,ִ'nȱ3 NvX֮JkGfݪ˃:VSyWR\RTdLĴ%ol$^2'[8?TH" C:^, *إl,'%- ȤujXZ4uL$p'K#m `ER4b`Q47$soA/hFn ǣ6 م`>doSlPuGjj]IVIjβjD߁$~=(8t:tJVsV;QۙD8†^V& B*5e ViLw}{Ț j/:mCO:Xed~|gwl& 5 6lh b75Ȯj˩TܙAgT<]\8g :3nEzt_,褫J ܦ; 7Ag8eYPW 79sզe&7`d,T@&.8CͤN<|i>S'Dh*Fc'j(hf gN!gFǧU9p!>r"N)M< *Sn2f҇ˠwxNA`\ud6R<FčQ:jq&$WUt]'g'u2J'o@s},Z] RI-x(8+$C4a'9-Xuq *|PiE4;9r* (O4-~|M(\ p֙På^G"r&tr8S'HJťb@P}ToA(`.M"}V mm|JFwBhfgrkcˀDqh`T)(S;+qp7OFkXW.ِ\EsEmDiEfY!u+(sr{A疉[m4iUmCF/[tv5:_fˋ҅v$lx%Ft񆾟^atP$-to `6Jo+x)$g(Np?xo/x?g",' 6RRcQRisiڃj+mz'Y闒 Eo1qAѵgmUhu}l\1%];{C*3DժA5ڙTI56F3tAٸ[s]#{\S|XxH3l6Eo*^Sut~'T(~ qEF*3N2utmér %*&*v ݓ)E2QjGxӁJIy1-ֿx'K4tudޫC)(A,Jx?]c2eee/-E$7G>ZS0'ZoTnOOQ~9=b׭ݏQ^kw)25}Ǥ1vi#0 '1&cin@>y{sx{jh[i\θRFuW~;9|`fSuz>/6bZe6l3ntNXca@v(tЋUޏMQA#E&ǘ}HSz9cc~w:F(]66U͗^QqP5KUd( .ܱ9\_ֆ銣^R^X3n4Z+B2Ք;OS|67I{]lUE9tKZ/dMOF11SP2e( ȘIouaS 9S6ite4HgoLNvM, ISaPba&m4 JLOD-cK'*WYiC;,? f:Ij^.X2G(IV\qd9( jb%+^¶ۨ1SgAHfc WH5#[[d@.15)۬60bTm2IGY;htH6UUv0 eᘃƴåCP zKWX'UN|i,F iz%vPm L Ԁ(Z8:ݟ݆&bOaAe6~{RY[j9T0+Zh5֋'4WMVWڪ46U|&dE f"AyYY5>Ѯ2lP: \S:;j_5P>U:](v$i7C Vf[X;5cgXlEL=79vyH]~yK Ǜ3#LinSd<= R_Ko߳xX{5ӱ\ X Lu³[!ׅAD#E2t 7=#`YyeI)FWz(KR[e'}[."țyED+eo5BKE03,.nhWueyS&F lk6?~mH淐Y j''ON}#hHdnS81j{ OyzY8? \&@0 l[8ݓ׻ǽjcr7hwd}et_pxȹã$4T8==ɽSgۗO^vw~8m{yWxgWGG{n#"+ʫǻ O:wU;nL~꧄{Gv{q@KzC!0Lu%hYUC(-UΎ]'?Ky=~|awg%>8~ =52/wmwO~~?jXr=*yK5 i {5ܶ[pft9`wEFYn|!ˈN+Ũ$'8ZО +ieB^'0viMh L5[ޫZnUϟmE1shU0`>b uc^H7DX'wq:AVYoȑI쨸nY&!ߟ8UE$(G&&h%NG5[-޶RE|8bOmUd6c' nEs>tM(O&cWgH*R}or'lVH7U^+ m $r tr2Xۚ0Avq/Mߔـ4H7e:Ƈ߲}Bc"ӮoX][-yֿm䜮{5%qw~vVO6QMR$`F;t=2TF51EiQ4UQP;ۋ hcoW<4dK@ Ur֬M?<*ݴp5't8(W5f%y%9|L(SZhտޥaĹK{sX5*NҾHKzM}$-o +]$8i*i\6M OM'BEΦb5}S/q_;hWeT36Lڵ,d-@:W: Աwk򪱘4a J5!+,_g8$+[JTw'[&Ȥ :(;V? e0_D.+ՠSu5ppQ ";u%~;|pgsJ :݂&;vQcxF MvƨVB0Sݚn/si]ɱ섧ҔvL]~駎&_'Sx_<` LoqʇSFvЪ@Q#FC*-ƂYULvh't8fKH˂i&RX'1@å*SDn:5ᦺɓpS Uyrw=WF[6<;;x-;|燵-twG:'o*VE-㦑ޒaKPCZ,8KFl^&b ORᆨW wkK R"\pw܇һ^jL68?I֦*(ҧMozS4+3 LfqE7+n!zJuC_8l;8D=t&wi%#3%uiJIN՘RA A )洒f)gי|*c`AUs_<_W4cAesFb]0?fX(tHU:yG옎?eDN^Z~AIfЫxAsv@CT \^Q[r5 } k1'yƭǸ,n"ÅhwIn'Nbj_8od;E]MP7$b 3 k';0 ;1W,)Wѩv7W;6CгF 4-{0ToJც_Ufhw:֍o)jvri; CbĖXFd1k"ga` 3)1\>MaJa&K^+f-?Ϝ 9 }E8t+Jp@a7 n+p<žt,XHe&[HFpfG煉t섇LU ({?P77ə얜_wa)::x+Ii?F![7G&G@[&b-l^jji^E]ʼn `a8ڙ:P|w2Dζ>;g|9|0qSŒڜgW^ęwjY0qhG`NH@pFQ ۰L%ۖ(N 1*3xcԸ86=iQv/w+AR*y&;Dr=zɵqkԮ,cvf^7rQlU,]x0ub6OAΧEg~xGa=pp \T~x.2t);"cɣ|*U\Wɠ EDφRݗgv{sBޞ?\փ7r8"0W)<8fq&5" G5iI6*("ƶwT7 [U@w,^>>h./B'"K\v,ZXŹ]d7B`,cF#!p,k3YYW8 br.Y{ǂ?YҀRD!m?:8>бZt}!&ܺXm= N%-5֔9MjT V jA;iٵu!{Jؤ&ΌlgQŲ]/pKM+19+`EZJAj`]/YMtø5gr(1sFh7-5hm@ц$pI&17yZIv FX7?%kr!˄ T9iC_ ,sN7yAdrDv2(vY.8}cqT6.Wz'ʫ=[{4V5, +ں3 :H&@A *ršLǶ$ r[NN ̑u0nF:tY.!e3vΟu 'N@vK* 6=7 $:aQ ѧmXH[撙/f;0g:[EJw_~(UDA^ŸUb9<89Qh# wH膉kBR͟?w5RiezGE 7i[x-0ݓ-uM8dV ƜZZJ WoiEҖ)t/kr\?o6D8<)Kn8z|vkD{>GNE9ǛW9cKFG+ 0$ jJϋCd; * Ԭn+xnLlD!A'#Sܴeg;:ka;d쬎V~ȢO{m UN~`XMC pW`^QAS f^VajAPj$Wcu Dw( NɢcG} 83\ p 7\RQm#<A$(=x SFo牣{Bh JY#e+L|lq&kF>zLE_#`God@:z&*çO]nPukr"TOak6"B-+H 6+!'aH'MFZ}I (~v 1ȌzP*@C>@dAw^Em'(<S NAפJ2I9|a>u v]KI6hZqvk)ep#r6ACL3O)r{յ_m֗C70?\_+~, 3!`mln`q`\>,' vG!|A,#8eMRR& #p nOp/8'9euB>:QnPV8$7XI:rDP3PKdc!oMߥ2+%rlX_')Є/J2)Z.UM<&tH NqtNֱI{ػLFXaVԶܴF{Q<2\-WMt'+m'^B-q%7 zg ]1%Ys˚:JYv^HR8K(e=DIR)Etm _j4⿬?|їs4Pa_(4|4;p{n:EyL60MiTXA' h Z҅ Wtț9ܞ\lyZŻ'l=,w6_ _W?wkYY93aX}_e s`q? =۴JEv!Q"܂/>Z,g(S8qV8 zCB=mJF"sM "wJ48e|Lq_WXmCNGO!㊴m4H-GgH; qʏs]xN ."ƃq)u6rӤ7jB;`Td]|9i+h?k^}/ ?itU4qawxw2t׸lS7f$hBșzSpjgdI xbw  ӱXST%LD VѯɐJtz0%$ht1cZ%ꌮDDqil(=~4P[Wl E'GH*涓Uq5\OZƾ*R8upLFe_PpV2%wTedvb,ZB`O75ݳv݊S/*CR  7ccLre _"#$3>b6qo۱bNҀ3! DW=.eIP~&bE/$ۅ  ~^C\75 7qs)rcLCH5P$~LMM"՗fJH$Ei"mtPJ +/ YՔcFM1Cfp _E'X&f#k7+]dT]m<Ӏ/s\i!p1#ݹ3El+ۿ߭wNzHNQ 2V?9T?ԏ9kZTچi)P 9ǹf#l(Z-G *2 v*0n> ѕX:IdabԹ%p)'!rwHQ-TYJݧ?M=upX~9Za=qW"O=/H?ڃσk_㙧S3P$L!-ن>Q+V 4 t?("#tKޮ.*ˏQ"@T#S\rq־Ȑ".?TE|?|Z6\KA< ͈j)?{9؞j dvCP??sb?(z:Iൗ}LR dR{!А}"C+J,RZvkt{!Bמ"x \"5{4/%mqqpU7[AM LG@{h ڶl!m/1aTۄRfЮy(u+ݰAAmmn۬&KNcp$F۲h 7B6z%,܄ϒ:1{zS:q_ْ| ~on1G/a d1avS|T ) '"2}}d8 |cZU,᫚֜2ef@Wu[P$j^HVF-:qi؊9Y ֙|G?FDK>UybRFKn,+*wrt.nuxö/@n9:(^VB##'OԼSJ>!Ȕ.$%6ϒѐ7j ®ݰgS7N;[) S s1]L/So>X-}EY#ֺdV#g?m,Mr\r [S8s{8#*1#DSqNM"ek `eIhx\̒)0wWP'cS4G0 ܰAM+h/o/mM ~qFۏu."hlQdV<~pFYf郢,͉OTF>-[oU|ۋ!Wk]}VSnw9׀"A?geIFJ D~hHHG)f9 F,t[3,Y]ai&*2]'`1tt:ZyT<@ VWV3g0s":@-ÆxmIj T͐Q7w=hu.cWt=N8&\uN 0x&I_M =TZ^i`KE\^:XHƃxpk >g鄊tNANyxܨd jQa@gW삫?nclDQ/j\$׎FRo#o~_?}nƇ1J@hC5P+@aTBZwU8|4)(Q ķM$Ao;瞜GV]Mgo2a }.p%$!YDMzjs['  I5 :%f;HFFKءRsRQu){t #$zyf&uI6bG\#6ܵhQa)1KP^ND6T%W:(ʜ;R>=VBSi מ]Z[k#RZIPIE0qh1VB\aP՜cg.&.ɺ:N|T*3nUr/%.U^*z ]QCh!o ھ(:K־cځsgUqۍ1&t>FtK7.l&jJRGBE%|׉=GNC-=тijFQ6 5BNsv1&+4٫HT1i/)6~/)|ML'Rb qݍe$L<{%SD.L}ޔ w )( C ^[]mh ε6|"9&6ᱡ:Mdty#&tX=oa.9OVVǣݎ"ԺK8r3s=Vg/=Ș+*\EWR,2rȉ_Fh2.}4f fcNbu&S~whGHG}wFejFF,s?z*]77$2-w/sjC&[CU5G ,E8 FIF3 U8q`^bY3uEy;F[NG^cשA&4_*y#z.^DIuK> Br׹ڂGJ b]_k\ cV䂤&b jjP'5P9шΠ=rV#m"8fq֌0TÇ\y~ ZV 6iPz۴܅j]dLUp\'ec]]j˗:I+CN!iry;= .^o^4rj"Z[ΒWz<oT;܊qtnӜ)+Yj1'^>!G,VK1EUA~sKsBA&c:z?8zl1n96u ǻ;'"{}TIX̫ inE%o(\Po TS3G 5A zN j/v?YI/ pv3?2ߛVF.áit׶VEw='jѰ;aƷT&4e6h>/ٻIlnɬw僻,f*DZi/WD!)?&ZJSmO6.'XeĜu7ejǹ pdA$C / 5w4,"5.%[E?"Q8|O4#R,BTbҬ ç05v>  !lH6#"KqRm{'e˺;' Rm\`ml? aZ~t?/JUWZȿFhY*2cGhǓhSƧpwӃ>^WӕeOWiQFNi 菳‘πrAC=bkkpuwa7E/: ^uǯQ1K+|,,<qqbz\XɴqژC9P<(gy_@I@#d2Aԍڙ!Q68 ѭ,|WOj!lZ5cw99>8><ݣã]ߕ |f=-)WjC@_HFө! "?G0PC M`OKtQjLd`6prl*@TgnjCn琲*,fk(N .LȃPet&v%ބ)~I T2}>\'Hp-3 Ć6oErHȖ&[2?қhʨa;Rv7*~>@=upxrsX*: %3.|wϒ5Z}]H@Sg.m4wًglٌ9FbRq.{nMWb3Mn݈asivn5Rkn~ܛZ [lVlӉN>AK"&>umՏi\bڹ> 4ۗKؗj1KeW1q{˛cfg F/z0itMPT i)u)>w?F>z%gyc&2_;Mr2EAD~Z每-hC6gO$O[4+?GܮF>O{3, r1`4>?thIΓEVE6 WfU $J:Jj7I\np]]]5#LTQ4hҔ-x.# :OeBLJ噇09{* ~΋Wqq@odzMQZ ;HM&]]|_S8Iko@Ǻ/.KDbbO7%'/]&&f[>q70drɹoE]_=t=a^p>J݌ynF.g~:jl-aRzit>-͜d+"FL._c_KLBOk\ۿ3NhSSEn+K7%/W6p|be*VS{vb-7\k kfWAWCE2({Ԏgq#]Σh ƙnxRz*psçsj{mV):viwE;qvtkI84W42CΜe]79I >G0# g9ȀL9Zi{ ҩA+փL&̹M`qcbFP2jrf`|-^HS5f"ה`pC^}HުIyӧu( S87鍱谔@aU2ܖ4E22=oiR,8Umx}ã}nl]ʶ`ԒFsbyV\șwq@A.U!'Y(>glWY@ S`Fz sYYtgLW,Ҩ9mUI}<~ݓtr\~BXs < f{,bw׾}-``rϦ☌ j3pK$/Š~a>%9gƴp#쟑1.ޤ/ -a¶ӎ#CKdV3lML+_2zV=,]8"HNQcղ GSb[N+#!yT.Oޅ.O[ego2  {f4?TI^>f^m5gS-Sk? bl XF{@xՄDx&:xgt*r%4`kTmZ-cr8Uz2MNTh踎 vc>c7do6 7] Y`IG~s(%k&Tg(\{W7tr_tpz} PPn1JK@!qFdt P鰙95SXI9ɹۥ:eV;'&zN>aigp7spB\75ﯚQ9W&4DSj6B%& bhAwGѻ.Éa lځj#}5sqw8P|~D{;V,zV,pD7 _p!}Z2(˗$+]}6ibPs6.I! +J+)lku%UhE5+ +MIA5U Oլv~zZYbCCMt&m+mЈ{ n ^|*t7ojDY(!e9W-|"]uRDžWtTFl%[l`$d8Γ D xj }[D!0#bjjhD#$*ʬT)^*6KUUPkUTҎec|om"XycNw"t雽WX Bzrdn:nwδ=uQ=rcT!L(:K4XZp?6 [( A%0-B13ա 2_ٽZ 3A$%Ms"%sPvX7^tj! t͉~CHa6bOt4Ӻg錣IwC_(_Vp+kAt^?+9 @I\-I;ښ=NCIy>d/VQO*/RN0^9aCq2EE]U@xՎ_J s\ksb8PWGnzXs@C^z;O'Er%=p+3u'Ba,зy/A\%m;v#I>{+q,9:F?| tf{jWJ8ԗ d q &_ά1p{ۅG .=\-|t }:1Q>cYe v aʡ,CC[Ba=3gXl=ԥCu;M+sW7IشX`si!yy-l.)g`8(<f)s}eFݣgTѶ#hkRA7P5#‰&&QHECMg&e7hZqAh-qGB }4E7MkrvmKmʁ*Ftt=LgCsp"aSt$.M@/F(BpL30J8%O,5p\cB\8Mzu\[Bo[,Ȃ1/q4##'DȻDC+ Uz8mNpWUev2`Iz@ȬK!jדUmַڭV(_8T %7` 2)93LB {Ö9,|cCpEpCJIZ.*לn xzlvcMdj*.jWSUVXc SJ9I\&e:ku7]j2&[j$Fh5C)!+NҌ`AǦmu\ RW.Ө2ON&L)tcѳ'n_C,h a3etnCF۶_zqs-f:RM.3tpM֔G'GuJܴR6 ]+-Fh>\힓Q3S;.dB榲[2LzA41X%QA"a$⼘lG!ċLE݄=Gwg Fs Z0FsSX$g1֕*̛/k 3O_^[m5}+k]*+PgnzqABˍ)`L[&'gw+pԌ0&dC4LFWL%19HHVšg8.e) ]) ɡw"6Iv D,@HҠa ;.v'YVѦJ0|a.Z 2CI6 WFud2!~A5CŊznk8Y8>~HT'k_S:ϸkuvf -_9g"YQzS{>Xtk)V3eUĺk.g,(6?H7AfH2/98ܓQl+s %kja&XR ~eǞ"R,\ʓ8T=_%OI'Vߚ^HQ5'pfwv^Cz3q8J w4]YW${i¬Xw_d$4H&f]l ON ģmrAQ !#fB ߂i&ރDCm Ea4H'jOO2oQ&k}| 4pV͖>kSMX819޸Ը | sG(Wš;ߝ=&AA?yk]js'eFb؊]_jLY-c2|5A)~ǒa`#Ci鎌SRZo:<ƎT58q_S<^['P Ba$XyJD‚IXm8ťuE/>IJv}4tNGye]VK-ň L]ޘ VCy6rK:Q C1-g-ykG:cIKZ:b) !e5Jitq>;O]]ȶ$Qye%gjo2Hg|cqI% z3=/jmrGxS0)l()W5N~r߫t}h*~B{lVSxbXzԊ dzԱ1cƟ]wQmpPٳ`yҒbr츬|߼ T,K|@P~3cWRs@;nny,?Y Mw|O@YV0yfcJkr6g;h8t03¿vͣ/xJ̄;FpE"d%||^xrAZ#(ea^ G̟{wwfM "~7`Je~OԽѻ$B dd*s㭘I_RkdHN%WQ&a9qQWI'dz$IE53_\~2GQ EX!iL_ ,c飘ن A a)x_ZiYF6e]o4 Nsp>9NhZprR)NA3FSdmeheқYzNjbL?:;V @Z UvR?;7W߬IUb:U ratWE"<2`VGrb|:tfG_6{/+lnĢ#Us|- U~NkڡU՗ڭ8QTM|6؍8bV2~)74.-9OOCVHn6#=F)[0,c()"|KV=:Q2O s{2(R ??1y{~kPp*ug?gۢ_ޥ9kK;vܙ[EH)|I @G @Q:TJyP/UVHttmO=|%^Zk?2+ V#*skrkB9۱W})w.IWXYSqm5v! l=D E>3!GYP< r,er=(\IDi6 v ['m4;־Y^{u]=Sw<>i~r -\{cVc k:c".#qz uoT;S/Ѷ%i0RrٍxQ+D%2`^K Dp.ՙ~@XLVs@/LE+l> 1M.ß>a6:?_y*:.y)BUdG?YjJī+ο??$w;wҝ?E2['O%}&+j PSm&Lݸwm_2X_=?>S>{q"MN1; 2o~?-6eҗw,[zpMǧ7{KK& CWBЈ/N?nAu D*$7vSM)xt2ŤōcӞ{cm e4֘DZJ،Tbn@5fx:L1(8Խ$_b*U=ʪ Q g w H1#dZUҕ6wumof|B]N=o3k`H- `,\ 88v _d1^R kCtۧ60%v&<#Yp.ޜƒu4E,#"ȣCZVQAGC "t x~].hy~օ!v hN~'Yvf@c8c-|z{Pcv֡siX>NFITQFowӣѰ#1¥SpNgHCإ@[,6!.}߬2n_2vVʉ%pW%[QnCg8'}=tia@8TmQ+Yr(W󏬼:"*C&Fp},,SD 9JjDb"{'' 7 OW>ћj' \c6ȓ*ecAj]a×+TZF=Mq ЂldcNS0x ,T#O϶"}R+6um|_[s6XC=jUtq[ ]~iw_x&B6EegUMv ȉS(I)^^DƬν k$v|lُϣVPdtaG#yX^i.m6ZmnS;y+nìND.1 vԷAo^ZlB nY[jhնI2`bV1٘:Aj *L+R3 bk?6p4"5ePfWWd8N&"%0{ J 4 US*B! ΠC:QoQ2Ȗ&6[+ꕐfbf& N@9Ir5 5bɓDE@гu- maMW1Zv2 ըqx8 vAGgLY#Y >n ]vS&K}6.>Gr'A"eF-;cIΈ"?tMXr4]> 66(z†p(qjħD)gN_Q`6GXѧO 6mL\Ea"+8aH.DS[3` ZDn@p!j[;)pZ$SI2t9^f;q#KVh&`-;(r{q.1f]f b31C#3\A((htKNGM12VI*E*ykvN`f1H ~V#/ɰ4 {Q3 A;9:gp/U]jNy! |0+带23OV]U LDz A] XzHʳC콤#Dd37rS;Wi#FCTKf_bGŠ2\E죠 ,W' q1Wdنَ7wwrJ$ЉTȐI*@$8;ӈ /+Y;b;.f킯Tn۴[0p-~l-DnO0$H/$NŁ|Y4+Yk5b*KI`X47Pndb yE%PW@h&()4VVx$7ډ/靺E,= GW%au ݖݳ Q1E6Hi[#3WV~.4M%h{ $NwUIbMlMzu S.VkZW &(EոOePɪYУ1qZn8e72/L'psֿSg'^~6v f|Kb+2^~#o&+ YhY;H,ɥ;Q"2tP !;PkImm=s˵Uٳ#7=zfSZU/@Efz Uci!hytQt;a7f]|ԔGj[V^\  E m: S]-}; f.6nAc\|h">@u6X7s n̍ VQR: bGS3wlA.#Dҧ}avIGURLm=\ #B-ŔA'ඡf&ˉ)|JNy ؘV^Ó7pl\ň=0} mmf9SW_{{zJ,ĕ7V{OT9m>$P`x25YMc`*zzǦ#0glUq )GxRx^b+bTnM@Xڴ湲6h+ -qeKq`Iq|9Ah+*҈nCzX{$XV.Py2*,’QAwL~2etwŪöRh;͂%eEuZj&dr$~ LY6ʱO _l,ŔXK $MՐv0hI"3,EB8!! -V&2@>ErlA#kUV9ebT躅H砀uh'g4f7\'spۆT?VdMW,?N h9#`/yits)P@pCCƒi[YFb%N "}𑮙 I J/zl  TF^Wct|zAlQjSD˄g6i`u$>ș͎ k I"7GȦt!%D]cĢ[\lueMzDvs i/me\=Ԥ1gXm7"OeR/rgnnRl8D)*xR E%cX v%' ǷqSWVo֑Hp`D{,r,1b8U>ʸ?6'NNqgmA ȑk^8jI7i&-zIɨ9GE$+OiO LJ#ƿ'K7VQ< ?ɕCCye .iDC<ͺemN2-^+wVspՂet,{.l|rit l!;JkGc]M$`t+/6_ZW6\Lv Ki,.Y ˕2c݀98j(#`U V|>ß-4Yޥ7NBDBr̗;4.Ҁ1 ("u*qH0UA\?DN8< v98dz0 B|U8-siH;t8.0 O+&J%#nAx>&X{@QS<`1/#Ũ"H()4N +*e2P'rǭť;wǍUP Fy\OctJq5{yB,q*MǠ?<-lst Ua@ܕ31 E7+PӲ[tR ,=%$%7բ#EQ Q9ט3^2rNq佶\M[g`KQDU~11#\DžQ>9􅋟aXS|eDθJߺۦW4ewM:#ͮe[{ȦJ@Xkɂ+wq1;+qJ‰l@kNl[-Jpr@VrE]~t>TɊ@MTF|XOF-!%v%A1+k9NjnNQjƆ] YH9$/79et@9-b"z̘\'wxk L4WC3b] ImkwN{3x}7 \鈉uSqּPx wE0‚B؊-u ҃YhFk2wT@yx6Wރp::{.AHs?2DXR٘bF鋑=ioh"K˙^rcoX6 +XU97eZ1KT1@@W<!B&?Wj.Qlm2O[[zdT̖0lKe~"u\Xm}HI{bZhYS]1t vc'ܻ͙F!47@G̥ ,6U,Y)pXhOӉ#&TҲ|[ˢY.;l>vş].Ҹrk( u$KNdO׿XZRxz^j=M^];9 08AIoP+cuRd#NL\iv">J=&e+NPwE5})gIy!m/C E{\-k-(.l]jb8u37'\B&U1Jn+Tx4܁‹TӒGUd5m@h/qVfv qs{ El]Z]ZX0_c5$\m^zXQ$,ޭ$n4Uu.06)j]^~ o`{"G3k`SD^cB<݄}D㨃VW.E9ukrU]o%J $>:7[;X)-eE0#ڱZ/4Ƥ08 \-tHBgi7$.0;)XC9s>9)>xM dɔ[JĂQ4J2:+(jZl"jЎvosͽoc; Wl_n xNꃅ-}Qn0$rA,r>t/en" Dm="s$Z_KO.VȢ2̭rLmlK _ofM%l#>]&$ _](Zw{k"sElj8fzghڣP!,j 2ˏ@VIqVЩ[lĄ^;_5z%|(.T@weHQ24U{QtB|X`lSi:@b?]1?28~g6F@̷.$2uVE^z߄{ݛ0mG?S<֟!(I!x}?{i=f/v'T uаn9\w`??{PM~HFCoq~v4;l yB'a^@N;PgHla&gCګvX՟.g\eYyڰh1tV35h0kqV 3'y63wѢ6ǩ|Ǵq7OLNjVkEm͞uҼ#8{-8(W!hYqڣ-=q/=?c({sc~g`lTH$1DnsOt 1W:~BN~=ͪN'JkC$J  Gtfh#N ~sJ( ;êRQ;g1# v}!>4!'cLpHOچ<~CFw~9n^a` Ew$8hvwgZ9G'ZlgXTHěI^ wq\'J[|-ׇΙg q &_Ѩfx Rhg/?ōϨbwQWf9W`@8?l+5~\w u7 RXBxb>aW}:$tax2Ymp<$#2@qqw!2 &__-~9˿ uTQfHaE.DXlc}ciX7``iqib`QOjDw1ˑ;*T bDuG?|P^pwrc|loecnW1֤A+&uy(U%L_h,Clqb?>UY58K,NP f;H޳F< }\냽%l_gMU}jNnGDžocD%9$Hox$F8IС$)Z,[Z+#_iA$%oj;<ҵh~nLI83ΔI xZi&¿j~=ue:iKtJ,-l~[H6;7SG?WZs}Rބ ̤})3%)'~ѧn,/K  TT|EHkimͭ"+a FxW\!;5VդqJދ^PrqeW?};+/mYBz83s:xf'p;aFuש'l~Ld6x~hjh#3E %;#AFK+\$'PJFO.9Z C)6|b *P-/{]߹UV UkaW~$)|U93bLj3{lD~SYtUJŒ^lO~N6>OFkj'S:TB4QX4¾~H_r0$SWu=CA\wx81. 1{Ԓޖ!B|}k`o /C@8kd  $77k!G' <'7>"` &􌣆UF zfwE8':ydXwQq ow(:“ xams3߾خ*C{BAD0.Rr"!Uy$9sL %fsj7RkMd'8}ټZ`H҆ ꤥ7O 54ElOcͦNݍwhX!0d Q)=x9 jn/ uih`(lư-4'쫬z?֧Z`Ж@o2˲ C81C]` ɅJ$g/k2G5h׸xMfq8Abqe56@dPe|~#N`3]:,k6+V|x{%QbL'<3SBZ\xW ?##F0!ꭋȘb<&©ĥwb,F6x4#,kc&hp@(2Dro{i Wh}jn(Rm[ [ԲoěِXvU23Tޣϟ>y`L{q -f>\=Ә0+;9o1IbG#4YʑҁY/b&ֵCc*Dżr GBc.kZRC#;:G*1ɷ;D4|aAhp<D=lG;zb)%@d0ӗ'TGu8Eq5K# aեph ظsЋ'0dzkx3"%[fZ4`V+B ,a)Vur% PR*rYNІ_.4WWB Ѕ6Mff:-͍''FIѴNMGA4MZ6!Ll@d$qhg/Jn.Z b q[dJ̉U!Kyt۩V8"0$nRf,Dr8{3r-!mw0J[*q0(A~vC΢$kd'+xvV~_Ãb3tLfp$Nfm^'!K.?A+)9Fg̹כ c5/;;ZY"Ii n%6stFh8:Wp+% x uBGjXv? qxG[NNNlѰjY_6.Ʃ,Re\}|/b$sĦ3,4\N RhE7Fܨ8:wvn<EjByĮc^[lK隒8K9FF.[@Bq81hF\xe*'S^_Y1+TlueU#! _a(˃}mcDkc;< 5fvimVieFq+AݷcO؈hFT=H‰Jv?=0ʦKȼ!GK&"$X0ʈ*~Xe%lA{*pڤA>ڻ>+iReRf)}4Nk-)}TļIܡ?ڑ[X$(<;ZK=a֪I'tk$qowd "+FrBd%e]/7k/7 ݬkhK?p^Tc`ϖM,K)i% "~=^G]ܻB香X*ۀw&Oy޺G[鉕W<'3r>oDfQ[\6\G?|Umnnu~!JݶD2 /4~ 7GWGAWY{P%<@ ;簾J."R~/uOPFu;uߨ@ M4Bd(@†=RpZun{Ǜnbj* sVl?{1#9?3Cx alloN;''y)Jg6QQ'DkJTK5I\J=k4oIC`K UI<`weqE94[YrLSڜ$9(RqlH~u|H9&.!b ⦁}z}‚B80b) $ ;3ЬPUKj9HS l_7B^*gqnQ(GNL6n3-G8(*8kL]sƮ:%x 0 R (N%^qJeYuX\`TcA02)!siX!'> B z̲ZBgcD EW;Z@+ CPۘ2..ŭބ E!<Yق&fm8,JsXTQ1B|ɚV1QU=(ep֡ϭSyðo#_[Ja6 ӴtCؽf#%?G)tԏGӮ<DM*`DA7㸟JҴcr0DO΄PHө?XH =ph#Ïg#UX)gダ6RBnnt<Ł++JrXV>`]@ev r.Q;iv:b` kSwtt5 gQ]:ym ȥ5ձSkq{aSR^LVktXBɖcCXOPc9BȐ&}o.V &=4q"gHYwwؓw x̪rUk\~hq-ZfTpvfjnt3ꄘ;>um61iÜ{#5I+8_QP'm눇fbzXҐhuݮ4v5;KnK[ r[V0.r!EpHS=1;Ӱr̼-*k yn'Ұ[$X3S/g |Jm/NY`8 'N5/S~1m^v#U 4Q: EkClJR RƙE^*'CӔi|-hiY(ApJ9iR9ºeiWBYSFz؋22xMbN%Qu 6HmœM[,8z$Q~ :twz:{Po1ݺrIɒMխ7%a@~>ʽTVT- 6-EPHM"zYe;>삨YݧYDkn0OkI5,c \Z9{VcYlK2*}7lHzΛ͎h1."/je,:>8ncA e'Hz H%xcC^#`HFyVVڼ1O&*U| #˃m5e,4 H0Nܞo! ^9Kj7tdPO- Ϧ=5˙:n+(`!* 5 5T"cjѥ<|T-KsO#0>4Txdl)Nlp-#! yAcC7CĦr܉{ڋBY< RA!x]k~qNʆQb8w>^Bӧxי!Є9Nmsخ㞘 Hub= TRPPm"%>VW:j#ŕä[B ݹ)rX/kGHñjxb -|@/4uYu~hbF #φ ;f|7n7J8YV, zGלZ C\ğݘ,U",bxVy변y~4M7ǂ1[У`^uFWRFaaя^kbt˂MPUzfjy[3BH˳EC)i$u_A-Ptjf8WLs+f0㨱,oE iLtjĔ}ص_^})%]LU < 8,2E\j"cQ fPEwE)`b;++^<,LBX{Y UǗyYx$\:4MrFNNR@um9M9){ftŐ>#v@FP ǃ q pՃ{˪NSq3ܶ$Xn/,bsb{艗=YYVwf~oFV6NMS5aJʘVP6S|a(~;}#l^Rv< Gp(HA+UgsA}eLy] X$7$r~BR9+eA+i" 4y'\*h™9W̫T|Q; E-\媠Ӑ{o]iվ2 Cv1)$D"0v_z(3qtRN/oC 1;{ẫ5C _{QFuȿʿAYoiL_0o֙쓸׺4H Yp |C$d"əD:q>ͫѫL']wG^QWG_+_ kQk5yi l@rC1raX0!^c1YQ1ݸ 1QՇU`DL!7]K4_#w9ߍ[s uȾq#ٸYx8: #tNƬ<[?Hnzp, Iz:Sf[cN# ͩq{9.E!)mѡCKG_bBDbt̳@hnsb`Xɺ]:^O[Az ]n" .@j~a_qwx?bbq Gp޺fc7>h}NivgoӲ2L AbťKտz(t ڷѭ?+jM΅I8dJXQ#ǀLjUɩWĩW;EmO4@kõ`%`06A-% GT/mz ~Q6oX|h$l_/vXGmP\BBc|^C7A>cM LV=jBL5㔨/]V> BSJj{[ߚBF_6k%%pujƜX9o]Ç13'V,>!:f6QrJT~GŠ E|;Đ8ХfI5=+7x5Lt)Q$Mx]C#G>D_-wC 1dT+C41ʇC\j=|< BHhPp15dVcw0gU:m+ Y=*Dy3QĜ Y5^=m`A_pkߞABPQلV:9W*7?,oJ*ONdT7 L3G*1Pu{i 0)L)v+]\܀1WO%2LHC䷗ Vzd^Pe$<'ej<<()fC@C5a\@}nF:Ňi9qRGsvvUq\GHpk_XH)Dp{[gjMeR/s2WIO)C?=cȣ350_YXN]$aٝW`'z1B|Lc%ɹV`RXz̲ "g \tj(q%<aWfѭ[ :T7꛻fvRCGUM[)9cXzvesl:@[)Hɥ/Vz nee#yL>X\yTlD)n3T>_ߝ+b\P2p5E{h{~haqL⎑l]Β7QA"-C>|,\bm*<0^!MGv6!l>ڡqsC';HU@οif_N) 9+1wxJo0bR(Zy8tl9z66SiŮDZDaJ*m&[PC OS* wJmਢj ñ5$NnDl=t&injpp6Ė< uZ&TMYNLeف%9%Ӆoz`n]^Z F܄4R*’haq֊78rM},[LTc)8К(W Apۗ+b%vi-^w|twA5Fp,b;]??2_MФ%&.}$S6 9* wsv>m~|˟RNj.1_>ƒ`n#,ݣX> Ie[䗬p,~Bklhwv$TUZiܴ+ Z3Z~\,&q?٬\7L6'!sstY dLg.VEFr܂x>S V^4_0/fـ}gnj#1:g?(K_Lc,ް Ӣd&sǷ C+f/+d[s}1֯߰FLvxC3Ĩ;n]e]9;gig_䷯Ʉ߁ZSxڛR9OeqX`'< >r98,x0VYxʰʭ111,e}%hAwqKT*X{N2>fo5uZaTr֦jIrA݉B=l% ;4gr,\II,q@[8g\'dELXȃ{'l0L*3LvE?`Y]os⽅σŻ |5?$ 㪵,%K>ܮjN̋no$ꩤ#GRb[L1-縧GB*Tyy?W_ntEtK]ʝM7}Q[)0uSRQhi*[U۠;9_2!eMUivfPINº[sz\倘q!pdҪHuƝ WhciO(2:6OwʪW&wXiT̹<4 x!m`F"]w&c pۑI 3QtNA\Yp@-.Mgǣu$[D.cZݴ!wC~iSĢtev2y#: Pgᐨv/υ6NX9"ia"jvӌ(fM՟|FM9zGa6DZ{ML-2D۾Oj$kZD.fqn.,ܐňk[q&ca©n{ u47 T(<,[LWs5]1]锿*?ШTރA>@#6 #YobU&p*31YZ1iOgY &Erj `InJmL57t~ntY@NQaqU` 9/П{w~,$SyzND+ևgͬi+䁐wo ds:wѫ;#xs&% A!%R܇[Zq¾Mv^cy][#H{y ݊[kN3n$ޕjk3G|)bnE;"Nm_J\xL&''i+#r\szњ]-BEauM40 dJuf֊; qZ.2Ń8=ueAk˙ŏ b86GI`zkK3zku'\Td-CCηC,H$|װ߃߾$d щ 5U8Şy涕Gi!H=̩Y2ٺG$^|rc(I$j$KO?Oaٸ'Zzb@:|`eum4j\qІrK,}{R%0_'ɀQpĚJrI*򒌙4n@a2gSp"Z6 H 7@Wvb!0 Z~չFb=zԫL@4k>=kEwsq,f`oƞ{A8{p^ًD닯qs2"km#-jkY0@տ>,P%2sX_4^Dc3{un[$!r[ HM!}c09ۗ6ǣNꂩEx#㜖{|8[5ۭ8f$γ T7O<3kf?xgv5Ć\FS7Hq:ZTo|2%VB8Ž6KÚq9qkau_vgxβm+fV#J^IYBhCC̠ӄ$aaO;i +ƹx-F"%-b!)WS ZY~K?B ]B#T vȢ;TK)!U4H|VtPâ=_H,1$a}ToˤwpuȠb[r }YPVĞ=fuZ/) vh06JYZunbRV\P* cpOI n5S݄,&a_~?w1X>D % Q4<)osi'h|b\d3ê/?X^mz??Ms[31bXӿXsc/??\%Jzb%y6z_T~R$(Utص7,DjuSy+(hʅ,IuXf =<{n[[xaD}/Y&R.nSa9X;H嗣Cr&+(yvT\( B&6<8:,MovfbDak:I\GSգ6W ʟWGk_Jtne=3D ܣkKpJz֧\"`߻pP>iNryZj!.=C[xgPVKYMq%@^tMwe~}+ ^2?Ov\~C\,2ݒoDl. mY6ħl{dVY;&JُcQ]W80oCv;2Fl)sb9؍BaC"4dbB|"teFaaS̚D9hJLպb-}q}vU ڄ wϥV4}c)=-YbSNKm|kf,iȖm N6t(،ܫ7f Xq{pY!+*YKN"vHX&]d`PTߴ,C;UT\p=53鍴ES۾^ 1n^K7X}mKt6rXjELXj7SsÄTi|^KfJr3ӀKIzs^k iL*m+E1^Q?G6jDU鉛O;]#$klkZֳÆ.g/xxhi JV)A;͛F̷l'oFc6Fݎ$moAkE5Cʞ+-l3?vDof:5uޙ*ij?+lQÔ6G2'ٙ7HkFr0܃D0P[[Pd^:1AZGoF6 ՌyM¾õc4p>B3_%.hهzC#G_7x6ꑴ;/RU~pBN{PF>:M.cאt6n2\Z$Q`b_s:dM[/+N4:`@Ÿp& K)?xTKF dB΅f?ms"O*OGtOO O'?#3?υr"u*@r̓k6ӄ3?_#Tlv[^;T_^#>{ͼԦ lڣfpv"9>#ލAe,qeUZ}v RSa|1`o''3=:?>a4΂{cƞ,+T<87v;L: ^GߠsmvT#?nQ޲ /[a-bTO)O|` OuVX_e#9PI,1LQ19  paiTm4Wh}Mm^Hl!6rYG#ѐ؅` ypbu@/k{7t}6Nn26Lf-I3W^P&爐m)H9\ z&&:[;'j48 w0[= lB$D;S1 И>K=6"B:quc#XJ_ҡIrd$bǪ닽\NkZåv1<&qB3[拍{N"ݷ{;_u-. ,4{:1v677^0:rYu|rwOhb=~Dh3H Se]aK&6W#ꎶ^KnDDYWOlբM%S=q9,9YRy+}^d]W0{%>'3\GG] ǘOЬ燇{ 90|J,P{\l930;:n7țedtPT+*y=ZyU9"N'?ՑiEfW?Hف1_|nITm턬@iCh',4<[51<)D?Pӗ2[&*{; \Mta DV(E?.qiRS'ӝqf3&TUP6ߨU-yv8]DR^d<@$es|`4onnllDdK5t+t(VC6tmA[Cc$lN nQ) } ׺ħ8(\vֈ}11Q@ Fa[iA8L^Ʌ,l^dX&nSBX3K7 'L c'>ZX<_8hOr۠(IkO6L(HB Tͼ]2@WJ I9X~cYc.VeG#TEa&h49Cjt,PR 3'xM4+ 0W54Qux4 YGk* e~޲ʂz+i^~o[vec Q  qW/jzנUU{,2ճѻS8h#YA tW/?л^\3?/?݆K?:ߡp;6~= u?ts>L^y2e0Lܭ&hp y_ާ9Ivw3tzӯ)D3ıuo>u{Gbnj²A/om7˯t9}g^BH"{oħanſu`Ǘ佾0 {m/|F6W[}= _i͛ATqT=j|wqp v~O1wk&rW\}APb_b;e/ d("W׹o ɺl]C_Gc9ڣw'>6 ˘ܡr-2uҸ:~z?۰esޫʌݩCx͑=O.<ϻBW%_hCunu='~J{jwW_NSoO`+9La(MԌx vdsyW)g8z8m{]WMJ矆\Q=Dguoقn.7 ns +}fyuָ DGg o~xSG>owbq)+8:X/ɺs9\wsHc_lS#7K}#Vr෇Ƣ%87lɝA?aߪ}e&v6}Z J[_}t]\O?}ˠ4 ]}C/0dMt[,Jn<ȠQt }||}ɂO[>N| qfI-\uFno}{Rİ;GP˟ӟg/BUemW|T_K\\e;˿+Vӟ_ez>{/~4O '(*[[15],`|o>.0*~bqHTVmKӳMˣ!߇U'y1_[޿z̗W~=r| 6TrBMzk0tN+;d9ѯ!P/NdzTm=2=ex?ƻK/k| J4EwocïŨ%S}uu1?~UQ[_].Mcy[ǜ3/޳tx]=Eƣ~z'>:OJo`7Aҍ׊A5oie6>x9sޤ_.\. &;~|\ĒQXf;_͏9sF3wn?_-?_MWKb_TAUOQ|:_ޟlП7t>>_:~^jys?}bN{Ý jt9xO'c:?Ɇ#ﴶC/gW#_^S^כ@*+ϗgOT7W6?^%V!g];WfZ^?bZU\pj+|QG|<_n7gK_/yރCW>һz3 pmp۳K_GAhVx}v.uS]_aa"˯! ?џW{Jہ[!woCAܚwlVOt|Tˣ_?!M}w> l_4Y ^X`rū돯|y60Y<}_:ooS_O= , <}_`h<6M2_zaB- ⮋Qgzt cf1NNaqloAԶpu_>_ӮBQDD͓ϯH!YTӒX;pvDBbXR"jcVq2AHmN! 5Hq YlVvGtahb}S($8ۨKp \XMK[C5MiOi4TG,J0"ZlmҚ$-zX[YA/yVLnmxF$9ɤA+3@@=q[Fi! I%'/kv3 1hܟM 59ȜU1qKܤk:kJ~996!v9kZhN P RULpW4۱U **2cLY&gS;*7S6[cǸ86Vp0u̅Rد(K 3,t2$61C*MHsP kf_IR=Ĵd 14V(t6vH^C A~qs388]sKz 7Mq,%:sەSu׆AqEQ=CU{\9i#t:!%|3urXN>},Z+Q]W4zkºӶad&fRl?V\y˚1]x #|;5.y L5mbK/Ox˨Al'03\ 'PqE|Q[Im3<[z-OP}Ȅva>Rb~/?Ǡ {h<-?F3} k i΀G; S|t|M*zOτ3QXZBmZH –wTkx_mm_Xat ,.L ܂87r=%f3mdzc9dGyNʊdF+bIzu*xՕ\-$p (dj&I3! 樁 )X8Skb(^[M$=$I j9K>Bp)F콿[8\Cp=FϗTԔtKv!Zvglf~=sƻIw(!߯{h!3 CZiΈݒ Eh::(} 0jTiz;d\9ŬhjvyL&'w:5/bt'ΫdY(4"B䒥7>s1&.֍^I0Ε2*w0VjKmp5KZ#xHnY@]B[rߨ{YtR93 g;Oь@LTy. ["d(+yZ֬>C ߺ1pp*SB/A:[X1W.)fLs{B2f z.e䥳-wXզLYReƓqbLX94`[;%vqa9P3kg'GF4 $!޸vH41*.>^*+ىxvDs1?_Ļ\CNK j ޑnN=!U|;Tى֣c e{`kznnAYF3s]!g6A!yoZ–[!@ZTثEQO^P=sPχԌӯ%4K].P!tm %]s=U@֡0qIdieʎj01 P]r47;g$_w4t.ƜϦ-P_|-~/#/'3bXg$//$/:R1?$b,qث)+ӥ9\&tE EmDDq(^r.E%]@깚F5:5dyZe1y8dw!B"@J{.ܵ w6 DvJN8'b(WRڌWY*J|/YIGcBd#3.ᰞK;;ٛA t31^X 1{ӨZ(2K`"PZbIs~Pi8i9N1/irȘeb΀ $[V!$4\˃fl#bZe;';.#}v)f W_;u~˧㞓0ò>y$e/6KlSZQ|9 H9793o{QdDSGEFS/(@<ۆ|dz~bUmwӘR Ҋ^jm/zz/So+>-=(D0 YaI\0IBJآǎnjXjEWxzƐ'.S e檾AH NW@b :hz06kM4DCZoUVU&$I]yOt)OFXof~'!s7w')cg+_UF$0@.󄆍 k\1@W\z&N ^+֯d v҅9C i[zxpM*3-xtF,-r'dAE㰮U\ /Lods=lSw[)õP\-ɢ0o aQTf<'WKp87~D48`<:dlҲfZQ5BvGVT6,J(!QvvtV0ˁCa ==F`1t:\1#F7mP g/(&Ia׺+%áoRhL2h}u\51jJ{$ 7!Q,"1óL։_NM$6A<GCS_α> mpkTgU$,Lh-(%Muۢfi> #^98> NBzFPR9dG4z5C =5Ÿg䕽k[/,0B3ɔ[?tQ Nf^$1x$ZwXsINaxfI.RYmeV%=ݺxvy fu2$<{Dvװ񛬲xa'w`$?h߰̀%$o!=[ve=𬬪2ڣM~̛-.&w|Hz}|3ؾsW|~gT!aibL蹕,%lzAu1Q5u{ޡӰQ2hڣ\If>r>m z(X#]9emdT,wY=͢DszӍRes=nUOzk*3J8bg,֊^W:01QqbRV;Lؓ*vFMΤNqlQ2|Ό!LNRښf,.peGSZDl;qP׳&z[*Q*:,>lSّAKfNd-nϮT4>Ɩ|áYhGm;PCJe\"e7z[S`:]W!=pu -ۈ[hqOjN5QJ#Ӛ1g YszKF E)Ŋ{Vtp&r#pb{+=R D;w|5Vndܗ+#ժ eWyEui?lJALy컑7Ҝv1NiӝV7sbo?Si0Blƛ' ~ ,>cz7#נ\I]S,a0GX,NΛ%Be悪.^yuhgJ1,Dc8 Z}OkK5f 8q^5f[<|P;͚ GY㯏)V܈~wFf: 7!6 ,F((Jц' ލaEbǩY/e{7?g&݈4y0Բ^JT,x5MhؐPoTՇ4=Kj?}R=t/=0 JhJmw2@p5U5ˍ(!´b׿$ @/T(*ԧվMߚ"f [njo@eQD]ԩvo5"g &o9hH(2~XUV&UT+zL`E4waz1gUOK S8H]LpZsi!g8+ ' t(Uy\XJaB  f^>Zx^B_. Gٳ-6|Ö# QgЏ΋\zXI>Kybu]T/Ǫbto{E8.,qq3BE2ҤG s{2IꤚhtnŒ#^kg:V'xǑ YQRq pvk,]1MF;sHymR0r7"jW3%j2s`4TWHlGZ=|oh-N۝z;l-NуJ+Cs[O;$>:*$zڼ> 7iFik_2MIc*ApJmkxӣkx-`mM2gg*PM=$l*|+Z2_Lvճ #aŭ\ub1He!i6d:xYO`>Eh(ni Kyy*m.("GTxPp8 -U#BT  =sRWMf+yXr 'G~1'(Ug_mugNsZ1쫮=^zf>>6FީM Ὴ@٩ =Oo6v3@;T;7!Z] <%ʈvmUzd dt,:o(]qiv4NŻf6FbA-to2e)>t O'`uT m?rѸ,zX#oڥ,!8ZUVf|mH6ӌF-BxWjpH&GB>S,֖3T7KMhΘ/^r*XCb SG(X]1&:Xy&D>\@Uܓ破Kkn+4H:u=ehOx ,6̑8@Phe.CO,"k_$! Uf)Z5fճST1d;ascEEgw˘f{`^2^▝}i<E*yQ7ҙGI^"Tsٙ.ճÑ;I9ˬvE VE@[PFd2Ҭ9X'#Kh ZU$xoR𜤳=hS 8b ]VA3qyQ;[G9zZ q+`3%j0Mac'#002$-@!rRFqzF~v5j~Fd^L9ϱTŠK$90?]KILEVwpcQ .L76j {/{d/p XrNq5a H@v%^׋l}⒅sɶXlC͆ |? ngkh,$Q"̴xN^"f! f=n:(HxM×&W h9sB>a/:oخ0Ȭx,(%?U^4qQ5{ u ǖqƻq1k9'{CNi? ɲn;BI~An=Yl¡S֑U cTH\O-L|C2|^b.EǴvԂye3MV=z Ui&a]ZY M;„)-@#Lڊ$ZP3ԃHr,Ir,xGKl:6yT. 6\ q¨aeKW['3$$Esp8 Uam/] Iǽ`EnSxVΊrܜ~^Foߔ4eeQbJoK4g%/LFgyk qy+ijBⅅ |Ph bxSna<ѧ9+0DGb(NL*: C,lY*cA4X^*մB$4,Ld1c#>*@)`{ڞNNI'So|BOYpQZlU»LWEh$d"怙{pZVZ=O "ӐlF' F 7E3U:H|i}@{d SMGM6C> ^ q,n՝:SՆ$z:QzQfiY$NzYΩfv~\Eۯ_ ţ$_z1$ӝnK fŠ yEtwc~dL=OFbER@=Sĝ%epT8L dizw0N϶8૞2YBw=eğhĐi{@z4x?~:kX'PMLW F,pʒl$nx@f ޠOZi\k|D1qN zSf,-g6 [rN|2úϬTkW۝tx>YrULp&*յ9(AYBm7 sB vw] ;UXza4sA2Is46Jy2A幛-7꯷uAp1ZfKQr$֥ IK y[+&a V=P7Iښ6Z:Xc.?8}c KUch,UCҖB]EI#d#zԶ p,乂NәYd:`"3knŪ'}{[Jޠ+r/8,#E-ɐNMGYt,5fn[3*)n.;H=l.1xeVgj2ɖ@ SlSF; aJ<Ƥ!t!4ͤ]@O~(0wfol9 =fq985] F \Nߒ`h.=YC(2 uS؇a\ԛF 5w$K|q_iMcum!YWLӺW(S 4njQLPnOT"xMpDnYhg𾢳bA.t0d]^%x۷H:&~-K^ڈ|YOgHxC ~%oq/W!eu>G6ז[oGcb5MJWS]*Z-PBuTV򆵦HT!NPBo6*gp!oH& ;PaG|Ti1;Y*7)3}QŌ&m&~0lp&A-6S(](lbI( :? QWABj<[v?l,rgFt 瀙#$^7Y.=D}_ Dnkl4]͢)4້>veSlqVz?lj\RElߝ:;NR≀Rz rdCrY7z^p;XE@8Sd3FnD[@ٛ.IV `>=ş㜊h2ysΡ@'=BwyNg۱[ʀN\u\B"OLjr#IUNS`gƦ]2{g婌m_A06՚lfZ HWLl7]#"4'Zgm1Pk_ Fh,b\Zj/gO)Hۤ;t m~^ΟP&[a4'H6_'aDZe8+.UfAŐEԎA=^JQ@:3jhg-a= eC_sX<a+#xv=ǭNy wޞB|Hvu\7u9)X: oVGX1?-VnS5 j<] zd8!3&Ŷ"xҁfX1D8mLE"`- h1b38RGq+O9/~~]$4%;<lX%*_eq]놙vWArz)%PxeAp# HO>WII`<)iNd.bvr=C& 5zrlma}pPuÞh.7Oo#RAñS_}7nȸvGtٿoO/O;vw3_/jE]+eavWg\$yZ{>M:KBe&[_lUvKxmO c1A/7,oNϓ?S-7 %G+tO@Eթ`sI QBF߈wMh8IRa$(R51F}3<+/X iќ'IpN\dA#竩u2؟nѴι3TXp,xpAKxg]"XE>p]LT,Oqׯgr!$ڋH,dfu\&ܡT|#4bllWѓm-pJ1&a'UǑX<\AX{\ ;ҽkI=to3#>!Àb-扇tr8Y+Znvg%0([nc&N=QeW #Y'њ`Ġ9iKg_;m@-&tKƚ۴\lEd`w\s=mڌ){ݮipl}[zlfhp62o|8 ]_R?"dΎX#OMv-@~ fkKyaȈnvlRtOU;G{[m:t" AR+Jq@.xs麝uև{V~IzH7$pSBZn92uuZ1&79͉ $z@݌N/vھQU  Pfd͢^F;p/2A2׾8Tƴ eu C ^?ʆxR$ ,]r"yUPR2PCt-_|+ $.™B%̬ca,Wh%&@0mdCW7 P 0p)fe:d3T;˦P[QT7:Vs.geR;hjO&y .Sp9rcwnOR̜fY"kkT`IʡE* !4# > {Z^*8B 7mЮ8~$d#&->P*^\o֏K a9!Fy|/T[p va]庣qz0b0.e>%4r,͙%r|S+iKr_S4@CrwEr@ġB({(,G~y 'mqwq졈 ԆWGJ7Uis BG.92'<cocgҘ C)./w\?3ck|1B z#L5׺o҇g ]qs'zm ρDj"5ѧw/ypC2aW[Ӧ?T5;8\\_ ev"Oz2?X8< |.-:(/8aĵjQӪz& (W+'#Fi\s{^?D})K^xV iQ0OZؘz=\Nf?3r=\腃Y]5H7KSi'P@ֽU]<:&$45,]fa);rVhr|2K=#\J\cD"/i9?43>g^&zNE+~^_(;GX)S{צ H[n^J$g\#?mϻ0 ~Ŀ?b__0OgZu9>ԘL{8t*t5;]OD~H;?g>L_/5OzuU̷!kr}0/jIY# [KR7>O$bոZEk2$8R҈d7qk1@ӄQ85S8c:n qV-mGx ۫\Z/)Y9ǹ*$6 L0BI4J]B|VNDE܀jk !$~ttCt{ RC64gt]>[/,BdBP^ҼW/yTԡy? yY [LNS?V(EzXn+}4blfw 9<;/Kشg \ĦE why C՛%E m&YܽP{H`.g)+nMJ鏥Li헎DJ,*>Pc^nn[}m6ǘ]SG u| |ZFN _n7~!c%kt+bqyl^L ޛNrYna-!{hcQs0>9\pa[iBN΃mFޱ^N@Rԁs .tC)=#*lzG5#~vx}BDS߹z8 i&*SD۾kh+ꮛb/]<@jyqg˴=-Z\)U_.[*϶)2D%A"YĪ0;oBTV=CN{&-q,glpjg5uN؏< ^bmTpʚLBϰe촀O'&Y~l-rnaaV{ZF%]Ak#4JԾi:gP-Lپw_v ׿E!E y)p%GpNP{rC_-1YW.˺;B2&lVgUչ 3ꍶzo}msrlQSylɼ`"m;2ǭztNq䏏1vge@He7~S28Pfwy톅Vfk.׊\GC?Qg]=,j}Ŏ_+EVk~N0wlӿ^rEٍ}Gԃ1bݹ<|w1bU N霶]%t$cB3AI&Ea~k~-4ǫOw߾/ m_n=D+u.r")М<@TQVa!A^XuAB&KdšōOf(wʘn9Hφꇓv8$"RSSNATAilisΙYM(+vf .'cj8\}NV8DiyF3Znj ]MҚW/ 3GWbdiN5< -G\c7=9pphEmT?y q#A?eU몮ǣ|<% ?WU~?FJayݞ2]K('as~P̞÷O XmZA45?X^XV|-{AϻXc/<4HC><xէ FWgg]=} t)vhPoP3#D1 RI+O^~1-)tɛ'zx]&{$e O}Rs8 -l 74K 5sY8Bn8KPlEz_-PT6$ːHΫd&DZE;>U\O >Kr7|;7N]#P9E"BVd/hnhɜ8I.z-te FN f2ӛyC, ͇W1`X jbiIcYkH+Z̖= {HCcT ڙKI {ck-۴LOXXLHF#;swyp&[hPWB‡Ld%WKTQ VO>' 2~XU˩jzƕv_ɔ0ʠzlf2;=C>ĪK`˸5)ܕ3/\G+7@yI]7N$*a4KڍH͑wώyj=>|F\ԭWq[v2L'4T:Hg A7O%$;,cʎ M+ƿoL>oQ(U`9zd!X<~bqJ_"\#h s*mxնǁ^o4| Jt^ d:=k(>4K4! /^RzF|w IG=wƹc~}>>xO_$B)!q̵+=$]dZ:YZg:,DI՝(BGHu)sV҃INnv@?p?0tʙ Ci2>arcb́:X/ xG.-2$y8QXT{OD>NU=50?6{C2_I/]y>qp[˼# ]Ma;vL2dL*3$*HH-h^ҍ$s ~c_Rz;7x;U[L3.2 {2uQTcH ?b liVֲ>wA)M$'ylLGDn3NI4%ڐpc4»vcq8wQg"[F5ɰNN'kYD̈́bCӼΤ /v-eKLNI :5luZ#ԿPx|]x>[d*#ŽO9rgVJv||>EaO7z, ~:vuxd59 |]d(|4}s/ƒ`BIgx':,eN2 M/YKDdz38"ߕ>AD!b9AD,mxaE;qDf1\8 J.eGFj`N1MEQwJ" _׬)$YVH ;00`?l鞴p uR'͗u*.;>ΤmĴ̘^{-Er6$[r&c󁲮J xPs =jC$,]<]gF1w!\x)e">_0۳%\|ፍ ;v0_P% ?uW+Mr!ZE[+TEҿx`&r|\tZs\~~^sw`)( ]3ޙJ "0iFL  Oo+I"s9 '=CIy7L5\)PK:2ҎuRNJ62XzϪ.ߝ%N ^q"G'5ݨYL@6@SESe#b{zۥ$c ({T1VETE/㭌@.q'b+/R)ۃrt`n9;^8Vˑ5}ެ+HKDsy*o?{7-|REňW# V{~-ܶ !ߪ9o?I42vq IZ oViZ'WO6 #3 Bb:A(/7R@RNcLf=FTw0Se7kOr/c{'c;4_45#R> (kA5M飌V97E,|{8یOR~?b<+13S^,N@|3v?'t9QyA.ZsŕlhzeXN"[/`/%p.<x;Azw,a%TCS!rWm^3wEf[44"`~uk26!i'ruol%Y㎾PYbuX3eu+#3+n&-urO`T=i(6z9oT[&#]Ia\BvP ?O]rj֏dž]*yKVNΑ?icHq/ehgY9UcOނ)=K?8X9ڮ?XV'"OH_>M9e zMs{9w2 ?;t/JP ;%pe$7OᑙI"sJQ =obۚ6(X!WyW9%7x/#;93!)%cN7b+g ;,(5Nrx0׬n[^P瀩X: yΖcP٬</DPN-8;,=O4S ӳrKq(n%^Dʯ^9=kgΓ1(xhy@Fzݲ RY^M2f3Ԩ+:Sޠ)ABgD0xC[;x^_xIqNcné%Q9R('fKjhg+"O^!P.,USSXF^-'OӺjTI.=R:}}zF+sVÀƯaX1 <}:2WZRD? J̄ݵ $üZجgD)>O@ i6WBzǵN5]ߊ]5"#wf?=W~ps.7RHLd7wU. 8Q[rBs뻿)?w-rM?-?'Ts3&sloUVsѺRnNÄ63%5Y/6;55?s{]qA򮩽w|F542Ո?NnYI mVErzA–&&\n&m%Sz`+@XКZ$n`&/{$+/9*3-.t9=ɻwNB J<8pM/sA.A%G$pVc홏e!ߍή~ʸ`~p/Z9?RZAt \F0D^hpoUY.]veYI@)i-=Vڤ5\d([_e*L.MUȆ',@֢~Fy4 @7`D øJݻu6{]i іsk^d_"!jlĸxiL>"hgrE㸃./&3l}L=D MQ~}-;Ѓwuqړn0n\UTȳ*]ofBk H_z,cmHW!|__g?ls⳴lc??a"9i>Qhc{n? I bZ]飘2b.DY=D8WiLʂ3*7^(q_lռbn4bHȫKht gӞ#6 Ont7.@0e?C煿郓`1W՜,BUaLxΝ'iiLG h>Cbe҄wY[='M)ok/KQg8wWU -V[\vbXN".q/= jkD2t۝e=/~4„0PD_-[dxX = 醌huAҷr"h\gažY"\f]΄ڽ=z`ΝUvaF //`yoFs {ϭ~^+CsFM.aONd6 EW@ ]U>A2z2x=9n|nΔ_P7LS{\ U_ 2uUZИbgҞ2Up>=Oٓs΃F63q8t/ON;{|ԩʖ]t՚+.ÆYq¯PM Wl "?SGM~)CiVeE0m8<|n GX$Z\w,w1꺠h`$qyN͇gӞsn"X=t Zs5#r91]aG0Y~3ۏ_cq Гjhx|/g(ݸO_G1[1I_ SyMfpwZSdSDyyaOo{kG6#xw'*߭NB'jη@>Ýo/R(qSkCc y~x1`cpwayw_tiFR6٧ yhKOD/u2`@cþ^|)6Ֆ񝇃(oZΟblz%⾚ kS"jI*bKƻ-hӢz@]aFz6Vtϼ#7X9czl{QkON;L7dB@^HzٜGW)wg5a[V] \璡4wz.p TӋyu*&?gka-R}ЅW %љ* O؅~m}t*qymR"7T*M#EDWv!?simkDu,͒VLn}nT'A#mE" =I8BiSW͈ z"+7E@m̫]t\U y`+eო 6^h^M 6[ÅX3K`S6́O bRvvǕ/`LN]~n;-+#xm<#8Cp>o aQuc?>4lB-`ѲOِO}F'8ak/u O_aUo4cdDJh 2o4ӈ椫|$|k~kѭy9y@&1Sh?m5t]I_ޥBC8_f;66+*+Cϝh|F|oג Tםm>iŕ*Kҟ^>?}OoFE Z?/V[(]N^/ĬVnKr+O*|Ft-4ZlSg.wwm+ ~oZ{qT͞}`p\\2W [}UFa9KZMM~HHy[$1WC`S>AlFmpAͱL3`,~)qh3BNWs$6[ߡc4(^ϋ~OScE[ߺ2~ek}rmꏝ_~ lil1,)_3upAum zr*fl i{i"%3-vX~A`$%O|,C8Db\aIFU3h,!  y'D26J)a^ %~X?2\&  GhY1-\ =h\'^\i |(3cջ$o;ȥffɆ>1k,Ωb̽c4G~]O95=X{*?xb`=ujH;S0aY*|Nya 7 e&+sд1!Z[ܠ!>5Hv;xcOHJlun[ W۔UÉP. 6 ߯ck LGۮ% T.bUls5\J"u*yUwT"F6C_8ټlz${ڔ(]kVLWL#!LMC pʏ;yhi"$w˨s@W\fjs(Rt{䏬v@WaOE\$ AHb 0jKIT>@Suf2j#KAy@@W^VӌXH:96նt'oqpf9廅|z,z 3y@dPȜn+g%yv&*h; #$9=v[SmBIV XI3GّܵJ?ep +h‰p/[4; lD8lա2\+3[$^@վƒ!5!eٺx▨I#k h? XƳo<=i@h- sIeK]8?+4ÿsUpǘAsW[\㲅d]Z3l#qdZ7Ƴ\2E-ם.tGd$%g)ĈP`54ag(.W Y${`10r+ =/΃S^g{dJtkx<MQMHiU`C8Vh4:|/KF+e㒿a_KѲ:K*:eUstIb,36@΂^/ʭ<'/;q7'/]liUg uKl=%Y%5%a$%t:VVr>bHuhBzk~K}JvEӟ ;Ød~$KdǦfZڒ:v9}9& V0%ǁk" WFXYz0 W:5)ȉv!Ɣ-qk!3͘l׳nTjAe܀J!ZǥK+Yq{xs>+5 yq`aށ=e,D5 ṶUУXHO +:Vް:%8DU/cJ/\5EHk;B>9X”'LԊ^5Cz2y"t,v{]5sZM-w7wsX'|sUW=NLKqp%v.Ew"'==+}I_SIVGçv?:)?J=pYi/5?]&܏a^F Er@Y_#a臕Z0QDk,vghhf?[◴n@jlELD#Uri XK;r*O0T)}nWc`spN|dɝ(Q}yNX,'+ +gčalָTv.pz./mf3eKrĩ/Mx=|udԼ<>jFi CI3 jwt a%|lit%HV^I/A/EjM+0.UJKXf"xo6ѼKYk~둧!Kͨb$?8ͦoa{H:`[$aZIŲR]ּB>ɦȹxD8Dbwq5d{ <8*g=*oޭ pz3\r{[{ozM0E[&f@WGO?S J{ؽǎoqU m'W~`(fdLHy,=ʳC2?^kߖזss%,^bO>$;"K~R?XJu6U¤ȩKci+_cz֠u k2՘C-#z&J>I^X; 1v QrSN[<`bd iܭ!g7Q_O/D37=j<{/FXL/S(\ľ\YZN*;iҢ1&5r8,KV $ތبL0jI?~"mDȸk50T17og}~?;# 9AׁdGSMco'н\T{eTzFYPܶsrOX\읳~Gč J ϗĠCVR\M ʾ: v [4Η5<2Ws\ulzr.:0djtE 9 \'V귋'LvEA pb.og  ez ^[]pq-VN/piud[3 tJ#0d?%Gt$v/24nC| uvU-$I>ˀ.^DG^>G7RO[V_ \*#fj/N;Ki8jZ0ْ&WAjtT1xAj^4ݝO͊[m׵6odVP8]i;u n^AZxbuK{lr1VBf@2\WG@Tp}㟱Mk>08"Ħ:`6kGVҭbH)ƃSPuhۿ Z %NLE*W`v%ҿ/:owpČNeoTTV'.tϽf(N /%clف]s.*u6^!w(4K@]QŨl9v]Lo ]V"αVk2Tܩս8@P|b OJ?٬JV}gbγD=-KDŽY>`j;׻C;UGU58^ER$)V&(6zulZ󖔥e_-Țk\NQ~"$UfY؁+jBcv{W~2j)/6 `\c_U,t Y53s:Rlhs2y-b^CwTd~ 9{ ,qn̉'gE\y'Z / ڇ^G@ P|}e[!h_Sg58j3NQ1| *fI0OsP)])QH,0z}Q<Q>v9Lb&9c E} ;#NT%{+>5>^P@ݔY~-2!/3ޯ2ˎDh_YK}gV+Ƿ_g臎O|v *tQ %OqsRz7|s 8`\oo*g֓䖑 y[Y9}oI;|^Ns}q'|\3G 6"eRq|t ' U&~f,Ѓcv=b/ͺMB^RJ&i fLUZOAuV&w6JS(gm{OπuPErCr:[ߠRz`'w^:Fp4!6Y(QLTrRGv~&UfBco VLeiջk\ZFXkV  ԽR/`Lheȍ/ͼ]S4>4넭j.f*O]mjvʂuJM$~ܓm(l<+}P?7][ύAJmJ  0#EЁw|2/.VDZX#zSxQ}۴hi~Vf?]<8PNiI&Z߬ɟӚahU2HIcp渒@ӖDYk%rǝy[5ѷ@N SN~/?!ԟHI`X&i Be%)|Yo xQAuf΢M[#f^Bt9M5' rVӊ;tXM1vu@WnW1Y̺~Zdż ZsqUi׋(cm˻ysghqas=mjwҎ ]=+c眛.(҇($K T}ƣ;.sL/Z>B'޼ރkNC]Tշ~+:ه}ůL=Z?JT>a:)zw_{P-1з+|\`>'~j gW<4q %`Mn;FkO\POY%ϵt`vG Z5Eҡ+ ^΢vd(`*>E=bhOT`2p!!"鳮/"怜>a~vunGܿj],hjD,q㖰9jqlq+:OD2? ~*s/wW *pN V.l U)D< Ip(]s<_)IuC?d=apQ%\3aE+02Pg,ih*zsxPYI7?-*꽽_R CuFTP9!A]%+pNjЍ0DִȈ0DRvW ӈP_ƫX[X? %kQyp,rOok E]v+k +gRӨ E4kB vWs_Zا4/  .Dw*>#p1TP gM;DeԷx/o E~ GڞF$_j~Y( y-?K3' p.췌N);7_g6qK|=!ƗTՊr; q`f}^蛈rG_n٘E6nvTXZ3\lGBݒt^I3neg2Utx5­ma$krOFʕǮqv&6~"y3 ҡ8/ }JgB]{<AX<-rv [J/+Lp6kfqB(aN/ 2~{OMyKAUWQAk*$΂kQt #v&xMPW?t[:;&xXr֝6_&l~Qp}e+E^VpY'i&dPݷ%Y:5tlqIz_ C&:}{;dذձ_eMJ[ͅRP Ҥ#bQ bEth^<:{~c6xmdf,-8 =qb. Dn.\W`Z 8o.'\ A@^x}4lk2wXf PO qz}$Eנm"~hdpOZRߔ|OBUi~A'%څP{/#@v D X QQEjoLߦ"@X}>D0S8?r!&:#njMC9/a32'/ vJ%U%+й@hy|>[Y.O^|\3bhg_vJd TŒw"Hi7R{B#1.2hvdnAxSA&:zW&lޫg9Ewإ [,#Vig>@Enrrw}yױłP*.&lR(ā'}]jц9l>[,N :`nXDJ͠ &t3%K8"&UhL$Ŗ8ѯ\"bgr%9v(cwn!m5{g|mÛ11ٳ()E 180>Pp"ޠOEFJMݿzW5? ̱9Ӷ~d~H`x[n[o-;?|\! @^;M5]ӳ5}ݣDm yN=朦kXW恀vMD՟,QU\Y!.XjA{nby1 SuW 1θZPլs>͵8 o\¬ D~^~s)CЃW(6 HfCsnW-X,ϐ!uRgmJU7' 8{VУ-\Xc 3dBLMEHHLfr8c*x0B\m\c$Av%\zk2=V=MC8A~y 3(S-`XN=4}9G|?!'G#Oo015cБqd<'Lu VHs'@T P{'$bQ=L SL ϱ9$o iWag59przMb?~EAtxHYg%|5fb+F]K4~]0_Hw - ^>N=U?=ǝ}db{W?whU%=1nfўt_CsJp:_c^me1lTPbyw|y?.I^^;J;Y xc!;|XнD_Ӳf5>=1𱏿XAQz%a'5](({ۃe攋vl,b$&O8U_%e1(T__]7{ , ˭.$/39gUs2}Cf6ʠBZ1IܩLPeRU okW[]݄vZ)w"|/j pnm a2} MΫS|x3 oHFv 4=_fBP'g<Y-= JS]0P,fQ;4 !^oߘĿ5ZGH~M2mzwI K#}~9>Jl}q;iaow?Ϡ_aɼS_\w_Q2W4kt|8y2+> fR [t`CĞ}K+R2UYr{Y}; OZUlvq b^ElmsyJk./ =@pHyX@{#\|z kO(lJ]mk:hbˆ=kWa/:Eާt6]Q^~K1i(5:"h'>z̅Ԯ88u=+óB׀$+apg ?2)YP[QDZds[1e}# G8NK yLI[v[IIbҮS*q]#A;S*gD$.YEjO^Wr L5CՕXzqt6geƼV)Ӝc\}?g GW%f#>pn)Nl`Tuu>=]2~!Lݴ lw@G~R*ο|7V(PxEl5% \;~8I"T[`,DgWOğZa!w _WDmOz)eΪ:N\:y ? H,xjS.7/t5~Gr9?ĵ:&7b.FxZحyZ*wVPN]Qv֜G >jnN^(mk םx6t6=.-]6N\ƣkRmk អy/VDEqhLɄ-"~ǯ(PۢJ1'0ՐE QU$O:lZzxPlk u^<|~i]4,R;#'ͬ5`"uI5̽j1WGgA'\6Se?Ӵ~ij"4K:$k,{{LƉ_~L&%eZZM.#:?*Hml Nݟ54a[ڗʪU^1ue77kO_/g`gIe\ᬷбӝL=JjM%L).Z f@% hnWQHogɈҹF;'"Yk q3F%OLCҒ`Z:Z!>@-Oz-gUgP9lPg}O"< 8/F4ܒ`?OnC dy,TI_)Olhiw V$~EG~&6srew%4>=1I;.wIc)_z EP~v ݎ_jV a`kη=*$%iHHM>?6co5/9B?s]eqlwu*F5I1/_JQ`0X3<rsryA<^vCx9ڰ4cѦ?yxh3 曲8\ui@S )LVs~F6e'6&`|u|7mFܴpXv~,o+RbLsx}9woYث+:-z:fHW삇MBvɺ쥫#hPˍ_Ҍg]\ܜr xti"y~l_$47p'YiqPgd J6 9e^n~M%gR6C-uDCQTU&b4+s N,bHNh4-bՃx=F v7[YNJWQ!ƾiZ O W,T& !b+5)]i_- -u>+:S}C4.kAD%G8ꄌRgR>C37ʵN_|3r$hF*.Hx _3Q`*C͡>9<>YXS=|aDpչm2TS8Mp6]NukAN0ֿd;DW'v{`p_A3e'} :p{U!:_s=8ə|%z tl8"zJ q)5%Hսguv$g\QʆZ.p M̪keHz *C|c3IÀmgzkwhf&5"" ŽY1}''<[T6m(}Zz=\yQ[tbC $$+y&4܀w Z=+(휳\PqBF-NMc;.]XOE~Fzeg7uBMQ[0o|y'XR>pU3xKAܧ0.r@B2/)m Klcy@75bV&:ke~r|P4_-ڛ/lOxвKxNt:3J"VJ .2*eG!BYPI-O I` eqF ٶzGInR6uجm_J]nT* WCIQ ؁T1O-,k$ɱɰ7>Q*SkqۻkZmIoem`Fc򟠋*pGD{N'r)i^- cߣwpj A⢦U@vp(T#qN$Ƴx <>%N5V<&;!5D2iX`sT䃂YM.0q)JD4Ȋ0pc[ l¤:D6w,ѩsY<^ъ=DꚇF)B<â{Gz" H%/ K&:|pry!\rծwJ?;A4.hRrWxz1{i3 ]1i!C+H!mr™UQ/AAƬ HQ䕖mNT&k'wF{2Kˡm0Y?xr48RϚ-*t/^/ag:'M6FtM?e&o&=>exw~!*F^y@zegA̽Q-h/fy*3RάoA*;\k$Oa^á0@}+i.AH$djcI?T1ѼR F,cMƑy5.t|R)#bFХz*-מJr&|O9d k (ZQ,৙Ehy [zek/(t"Ϋ(nN>_cN JDۉ) LmsAH ѦG(!qYx|~ eK&*َY|5 a̷`]Vؘ41NOTޤI}fO?]kKB$0&YBݾݿ*v[\/ ;_zwWR>^7m]5~F{ւǙkr1C_ D1ϣ[Вx +Ǚ`x?MHn`:kƠʟB4zUDiگdzRJFqP1 DAD+nwiQ$k;qc0&:&T2B>5AK!\=;BUfe\E2mH yUE:N^v28<ܒ 1qV<9eIX; LO,\^;A3g?f6KfR;Vz'ׯzӦפrӪN; k1M%Ulu!nHcvE,OhbIedG4·[WT̓O-sުh?3f 7ل+IKo~39:X ^XlV!^(obEF"+ېR9ȍ <ix\"LgD,D`eK֑yK1;)ux0+tٱ+s4 tjLX=adN76Q>ڕkڼwܷzQ@/L?j_iMnz}H-~UH f6=^>>`}|[b]Užtk q4qog(}<8NN6<#៧< D>UP) { ƣԊ>'F 'nڳ;Գ|n>]=&P O|N}o;2 SK8ȉa8:VN@#pAQ&˳&G~G[2}!ICG"~;I.ךW_ RȺQY; {|0 4Y^bO}a/JB[j+h4 7v۾<{8N`\'_ωv v~ɨ/;s߱3S<pPtHOۇWg`1yygwֻODivٰOEV*8Q]BYæ4O o (fS(9Tyz.Ò(ZIUi.xkaP\am>UG+V|@SEF;hn=lyyP`Ov[fv8`x =t\J^vȤ[Og HKiPI Ud&&x*bL&P,}-f&:kyFPKCj -pntK;:~K"n]iɑ GS/d'oAk;-y]5 X[1K@Bw#n#W-i7 \h$Zkס {?>[6=r2:hLuԗyl7gk* >bYzdJQ $=?xsxX=Z&zIuR!< Q៰8#GMx,) ~l_gmE;OEoULw#w3r1/Elػ pi>Ztw׆I QƐQπ{F#LةbǺ:SA=2޲$qo1pH5'[2IOX83WBz8{J%k4xY9I̺5㔌_U0׍>`D])$SB؜Cg&Ob#~.ike6@/?Kjs_z[:O췮7}=pMQ\yp(@O=Aq?0vXW?`?gEb?"QLX_î-?QYu &VaT1> 58ߥc?~/]5BAݞJp`6WH :]a4(Z jQƉV 2 6ex'9l:㣜5q*!q%TtXB 79e0%TC`%c.y' ~IJzO~emN$01y0E]rwcio\LA4H7DvpB4v, &V@Bʄx*kدgQ[ХyriOjfr ˚l0:՚l Z*nC9Cط&Vbex̰8&ʌAܜ Lj˕fx:/U5c{ !YI&-;!Yj>=w(bpYDKeb vA'J2xُ8gqs1WkQD/w_'S0*DTBXx`[*$~^,w>ɽ^!V> HHbk'cg$ Jx-&ZPW5R!د'TӁ]1D7C+@#޾@d'߽'p~y?c]ocTI?m`;3lWTI/Hyrk _'W-N](]]|ʷ O`5,GE/9?,GE߲7y|9z<ѻo?߲7y?ٛh15ve\GWɓ^10jj1WS7RSOr bs4Z>y M&ՙ.sJ;!|0-z4uȯKvsz~|7.ʎC_եJq1Bu$ܗ{if}hv,}w5Wx_f&Z!S?? D("IYT1j'+:^vZeެ{28)ܬ0ˁOvF6]R:on!)l;H_xT21:EAbx pqoC耵A%${$kϋoY|7}Z,/ {b(c:DN~g;0'f0n^)n5e=zͭ0!"b29 Iu W qb,>|l;n|Y"1]S$<)dnla' B+%D^r42['G;dffV>$pR0_f/arEݳ5ƇGf0y"U$00dI~ХګW]2yt`҇CyWyjk*; :69R&g6Ћ׬ \LN66d)}f&AĴ xQ9m6Y^# 1wj*'RpWfm]sgy>`tdcX])G,X~s<`AJ߹~k~R~dmf}j\>-35 nt~f\G_F$VΞÜy^w^de@yxE)|Y/Q˽{->*k/\%Dm5j!4/=eA^'VZEN覇>fQb\YGȂi`HktiJKX0rqV-k֙gvQb_ 5dB˄Dc 5$IGM] ٹ+'CjV8|{!IO^~נzCw0FTN!g!{1(WŮ?B|BP^PԺmFh0*՞S+d^(Q%xZ_Kp{>!bIQic'XbuDZݰ}{W^p/,ڙ?q|B[B lpul{8% |lU$.Tz|tմrٜ<ǔgv.E3b&5b'YEL8D o6 Ōf~`0&ޢg$'i%q8M_$owϲA EMoQ7Q˳nud<-w֖HAD%B4-, ]νc(iߑGE( i[eOz/"~(])m>͞!*LlhK64 mXz<\3`e:a_ 7eSQeYd B1~*|ܙ+.*\挙2((soT7`_;)ŵ.5Z!.J!'lozr91}c{F6|Zy2&6u6?W"^mKd%9UBۇaLsNK–H)]1jv;/}\dW:NUMf^^\C4 ΐ`=bX۵s;R/C*ZMn3r}*{:7Lu_Vb1uL2y@0a*\sNy3A#j/1@"kJ@\q|z]@3ɮ.ZJ]Q,A w̙k</-Ri!(/z*{ D..3%@:mj0!{ J۰bRf`OO3 U*O Ǫ$icl'aH$dwTXfLC7 >:ϛ3~C% F@zXG $o F|&(YQVPџ[O@"ڧLTn?"qwt^ʟ BY0HrZ%X<@#< xw`-[T*djL=R]Ohnt%.ϳ |Mo D ]v }Uf&*>t4r2jW0s%d.?f,VZU]@ňsCum=- e 27>-sdڷ_u]OF@T۟'ߜG7 "M^i9K) j-=0 N xI{@'3LtwЖ .Ls]{MӶ`zmm%T"BSa`ƂpMܞ[Θ[{jOŗ_@vIPZM,d3?AYY"41 &/C" *@.ixVmw9|4r5MktnvBãB}8vN:0<%-R2[q\1QGv~'2]`Į?XI?矓Cd<^mlDms50X.9Rxm.za!GonWq]tjV9F$jw!Rup-"V4j:&;]ľN9Q .M8eTNbK'^BN];mg[o{nl͉Ǫ?HNꪛTjrqUZ!(s ΦULng< I$aAԊfĂ@Џx1 aP~F};$o0#$gu"$߉Y* 'm~dERߐ̠λ%~w2W~>mZu:OHwg'R D% i[em,+/@]g\o\^[}ZJ/Lgo0?Q?"m@NiJ fabrk@REa*ڦ-XJ+8$GYμfV2My ݫ1R$ז'r[3Frɧ0V+"tk5j[MUm2lDQ^ۓ4ۆNʳː˜mO!ݶ n1$tV ՞}G헥qZU,AHqڹeNE_38ߩ|uS@+UY& 9ۼjf)>o'ۆ4 0t k֎/Iuy;#%5$FW.i \rez`w뫆PK'}絴[sf !QZm3;?$/KIi_y I.AeOٵҬ!l#1<,omYם6UJpL$D 6t@Q7Zߏm7dC |dZ}I/bVGn"0z쫁74faa!3 lc|Ѐˁ&СM7ܟsz)vlӿ+2r+D!Re' PTjU֐ućEώ.@iօ3DŽlvNΠ#"xC̮hǚvyn\7'M*fҤF ,4O:8M<{ &e72FX\J9{f j005u<> 0<S+VٗvC}y#$MqKO[U-؎2`E<ڷzc$,t({m8Vg_]ߦp7~#y7.W%*|u/ᓷN f0?J-o!c |Xol =߳W(>zm.<ٯOy\le/{_" IqanA͕_N+%eUx*Iـ~eRyȽ#(N{K%sؙOg$W (T KI~*`^9#^ #zi+նzv/ep.HU_wȵN$#LEV=ۚq @̮) TW"=TqHA`U8b$X^KqpS=sHi$vI`_Qb*/ί<Ը(J)38C }M%K3N0WQ.D=Ėhi#v%"e?b,̮ -Q l:k,(x',X(S٦<? Olҋzk2">MaD3ܟ*X⽲W쒜bܣ63)zFp Y]=8xУ:b4EAƍ$#^۲ma} &'nC7N=݃W 8[ ]ArJ<7L΁t{bɃ !Xf=63}qjdk!.52u(<Ì TS : )L~ٛzz˾{N4*xWg̜W#XH^ c0h!$mHDKpvog3zR~ d P9Hnޡw ߡ3Ԏc+ |0\m$|#_""=d ?vB\lqTo˭N'+OYxG:cAG;ah oŤѬcTb`!0 2S9=!}=ˉKZU#x]_}ʯ'W>\nu nɭLiۜ䚊JMdd)ܫI=s[ሿT ':l)P:9׽/>(и݂^,7]}5p镪0 BhTSq*E!{n4[ɑG&֣& pա:[|6zh.k6&?Y<csO.<=rlSwjd\;ji(ModDf]i 'd/w[ dWRm.-I1}H"9{LE'0yGG )̝$ 36c(ǻp+ ~*GA(6 ,q06awځ'wmD濻XXs G ρHc  E6v˂fEvaaTKmξě/YkVcqXٲR};Kկj(o(^yү?dlْ 9zяe"Twvq?Jwӻp)y؛_W[ПL Vā. %o}sInMd2Yfm!t'їyPQ#g!}`s>~V+E&)[=4P@6a%v0>(:xDԬ+[7g}cPI1.M?Ep'^wރUj /[7nNuvUdsC kVV2 ]VClȯg5~O,5$Ykfj\vQk8Ygh9@B'j4cd 2 8W?J@#Jt8@a!$cY*4Eݣd']GƋQu9DU>#:?eU~7$z +v7!5 ▮PAw*=TdOtmZ9:R/rj ,ܻoP^g06 [K+֖̓܄=0Dc=;ȿiyR8yJ"NyD2;kõi͹_-Xzu<<*B)/-.AWDbUMDiV&ʻ|ґ OIhv̒5E뱯)<ݯU'w:d{x|dЉkSM{7}Sf-,A;I<|۾γ(]^Ntnx;yYp$vFUGEkl pWYKy\23@) iJ~!`yȝD[v sa/$AL)50iaU`)UɧLGc$xuW,ʕMWg0c@A C_bݹ))C Н}=F(u#!Xw^yZ!vV%tT]lupL6|V\IAzy`M$68Qz ˜AE16wtD$9xBbPd1E}f,9r9Ls}+5NF4Ψ.I5`g'VD8_R1hfQIW \qG) Ɏ~'[} +# ^|6,)``g$a7_E9ņMiLO*>.Z00)YXBxecr},Ϫ$͟hY(rX~fٓ#?ՎUd:a3Fl*vZfWJmDIO $FZp ׵ }_k%47dEkSC} ,+ 3g#8Xg}y^}dL|h?/u[z_m>L*Q-f Hy-)gګlI,zχ,D8oVB:"5QaNVP\3zMD%pϮ",z4xu .,rxk!vPi$_Ξg9Bj$)8dhRk2-Ю";ų(W28V {cF&C|]P7@I>)vb=k>urSgQyR L>8VdImiJ^%sn'0v@93 ZBQ„C%:2Sd7)Msb%tQ!e/ p8,a:P˞V K?ba{+"Bq~I¤j 5Bkⅳ xlW<@Q#Tae<ŽGn ?0eQAۆJRy2I\坿*; Cހw;#L'وg/pl]~*F$5Jc \%( Q$^|>,"JJvw*_+^VV/jt\|At2 nehλT.tr$)-V€-]b,[ :Wln*mi ke 牪݉Tb[z8,vDRKtff㒽X0$U>08ikٌupbFD-\HK۶ww+d9H[>x,n.dFi3'\6n͢xUA7z[>={Sb^/΁ն< K1Q An/~vodzDljz8oU-S%xV>Ku0,0ҫCOMTq`]")8{;,QQZxݒsEfmq۹$a[g(^;sdR扸n>pƲe_e\]! /WT.0Ks¸fWЃgL%DoTۏz=T$Fߒh4̼Օ簦LR#XCZ_+O̺ _|= 9-10?lj?Qc\ii<[a$uy$ Ȋ^Is}4.>"t}j@Y6+ PpVq lgL`Pz S}+1P*DWX^AE=a 0Y +sI Jkq"Kc؀sGTK-Y): BgB՘_I8.@ WCLؘ&pwuO}4+ۗdj6P)ȩ6h )MqG_g8(un}@}ThNhPl@!Bj-̚]-^p›=HVČuwU1) T1W00K@R/!I歠sg S'>{\S3@sּ$s_nBOdz_;N/toiċ/qcd=[ihw+Պ~/U_mq1p2n1;]׷J;[6kor5 U/TY~:_ESX x؇K0TTMkzZuҶY#B=1?wۅNkf^#Ocrfcuݻ#t:a<-Ƥ>0dUɦM=3.>CBQ5AUJ@XYVd*2OBJRGE58>J &uX6yy<$N ůW殟eػ^NJ, 1Q=Zץ}af-hBA0 f'6hs&rŊM% 6 ⧞ncK5Ug]ʹu`-HR$P;~!hi2<5ĝA<_ETckz ]^^ztcw5_?B>swy)|Ri({%=rr}B gĥh=7Mr;M:JO)IcqqRqTf~_Ļ _zQ(cuI"KzR^<}>2d%eJoٟ:qfQŷsMHfZCe/u"O.qM Tk-ֳ%gH"_@|08v}9+Nt~|zGuf2'JDGm r(N.)P&)³mjףJSz?d2TNY_*ª -tonV;S"T/;_@:4GiTyC:L}(-?[wrރm?uDo~VOFdK2<+BW*.†tnlYU'Y`s[͵9h63vVLq%!ʞU'fS16b&Po Ghu:jq܆89s#<^6'@Vf [P+-t_E/5)UˤA?c恡 6!$~:tm\oi^pMqSN&Ј]Bn帚 ͽkㅳ&^8\g<*B G^ع>Q8b>¦ Mæl{^nLDޘ0|JLBuEBЪW|͍+^7=T]·p{wI:}3̈~\?Ir5mM均1Frͅ7 s8@NMwܸ2}%2 ^ m $ةmFW#1tmns0p2 HD[DN4)բn?G!7U}UwlU ry\SIAfbV 1\c-QQ@ ؽgB2`p]*l %e_X7-i?0'|W=ZDeΒ. &ױ tt:4rfܸ1 xZ'8-E}b#I`;spgJ+=WM ^Q0)'u-C_god%+@֟xxY4/)ZvZV!Io'j!JO) E#}o$SZl]ZE};Hˠx1HdP|Pt7POy~6Q!iEa 3\ԬU!koJJfٻ`eZ J_jX Sz> opVD5٬zn{@OrJ=;+<4cgȩ%^$|\2|+"-I縬U28*"C |>Pѱ+9?q]o45w {hಟvwYkc0l9 *S6U$W{E'($[J]R s/-,a1'35U$>'¢[)>ԏq>h:У9aK"1s>dg4]/F%+jHj&aTܑyDfg5@kiA)z&8тa=V\R}#N.Byv"8aER*L S@ b "]Q0ޗP /֌݅ͺ=r_Eߠz 84`)ky Nonrxna`Bő{ǹy((%˱|Hk/A \>CAQN>l|LladK=񣋠Dȓ'`@!X#uAa(dVfS@ٵ-$>kūƾsfo.-vL_d>ϫn,W+? ݾoEb-Xig|z,[%{&~j}Y#/˻!DKm@l_ roJzfY=՜K`.onY2}~j^9}_h д [K,4NhkF/Bs`>a_5ib!tM)ΖQ,P5uerCx:. H c􈋕Ia-]d!awh.<.9ZbwD9,aRf FBۄx OTR& txQ4 w x&>,*P ߉!aiΥ~ GپJ. m6MuPsaN6*Q[F6~=hd5Q$x ~/:ϱ3 =(v -C~-z {cF{\֗TזNc#?`ߝ@8kw{YGA8)be^ʑh ,)O2@$2N#2=o PkZF~V lFw_ >eulC/gP5j7W$gT?ړ0/w +vH2NcLjl3ԥ]V /*M*b@nXSMpC%IKCWP87g 7$ VL;_JCk5u{vȤ-CN#FKD-V7/D-a!׵2@8%y Ljŏ׫ݠ _\AUZöqdWz* *u |f;I;c|HAES]|n D[,X|7F! <9)üzfVY*6WVs>X 1{<s46tV?Q_|j_-ZWjwMgS<q;)ß3VSTI ٜ~_䕚*+_%2(i+`XZ/P+Y"3'$٫\,Q EtUsTH={reG:4=Yu%Q?oΠE]| }bIrVW4|0ۃ.d4*Ҷơ. x:BTCY]\c^+n K@ϬB?*[w\S:a~W0{Q-`nyw|k8iN 5xf:`5l1cL"K^TV3墸|wX\&;x 7ĉc-ܧ^ -4><٣d56h:mk[gR=+OD 41A֤?<} ٜ@81V69iOQ$P-K<ϸb4ӡboسzMn1Op(I2.ǭbzk+f'o!fޅN}EO|[L߀قSDi5F}օC37ʺ6||4_{t|WmƧUnNZ?[?PikGСo\Ԃ/=W[}7럓U;RQcFP6 P:zAYy oBJG%{(m닭r?t3z͖ra[0A] ䷕;нّk]*&jb#UŦ".WwUͰJW{Iv#d9QDbO񨻼UE Vz7XSҞB;Qk|!IdD aBgZO3I7'-Dœ09ooH3:7-?&4jܶ#>+:(Nd"i'yeft =>ztH/1GACwD3<"\h {皦e pG蟅]] Ȭ@$Mn2Ah]=bPYnO*cſ:>^< L-p>׮6;`5 Y-ICC?꠳4w/t< WYL8+PPd'Sw65jOk_#WRRGjx?%mo3MLuF T:s.5{doݥwWk. : w'| v/UKLiyyIPkz97'3 ]ivej-X5Mcn36}cW ˏXzܶkonףsU^Ӡ-%Ο Pۜ>_{}qpmi>n$6]o_xB4p[u?mY~Ð_M^~tU>lc< 5Ͱj݇S&w=`!}#kRWΙo&؞6Y*mTY 2RW0f,ʈ7qvSvXzN=zzKۺw)̹Q{>LQFSA§A>aNIChp=иF帮^IKh=ėZ:vZ t֭%䠧VKlѲP{ٳKJ%vʲ{ GG,4̉vxIrZA4F q@:#fHe>Vݩ pu}`俆s]|eݯǽu՟kٰaC3T[yz/Z%@wX,iMt1gmsTcLMoi7ha)T/TQO8Z @L64F4^62A^7芘{D븯˫*t XvϢ x3n TK4]e%ݡVpsIܬO J8*XYTpM3r{~`>9÷7E5 b苭'U V}e?`THpb]!$s`t []>Q7x`jT|mJe Vm'M8et+p.pbֶ١PE,/.Y4$忤ni~˗~ 0?iq۟0iYfle kfwuف7ˏɎaswvm~;y2jRG(23db_1ޢ8OG ~}ĮfmerhR?|B|1[5.u)CWdw2|˖/zGU3v׽euRQ*!qN9O Uq!"rFY0Sγ#^p)o{1/ .'&wgD ٸ%\7.L'!q] 띵Ⱥ˛A^%5 (oNy|FVdϸADuh~w#NaVk:+1Ӄ̬gԬ[xFԓ&yuLcEDcO*Ĉ)Z%uà+('@/q1yҩQO fr,7'u9>,` B;ȦS~P:>ze=w0?fhe2N%Jp5R.q-+V)Q9> 'vX8njb콶r>x^ 6}w Kq7{"Obj.wv$pDLsd@T`P^v}3ƫ ,Sr:y+Av(1ȧ0d*k%yynmԻ't z %*_t༩It _=s]8W=o1`PGs{2a,jHƏb=a%1ໃ]z?YzKF5ߗ8{P+h)siXcF)y%ā8{tT,YXDf6LS_XX]$MY1I{SrQHػ_'%/ g(!+.%=nR zthz5JvWc$5U.Ucc8&ABbM=6tw&l2<)H|WmfmrxX]) D_5/y̋(ݡ{0ϐK4>(X,cOGeZ5-J D]OuΥbu.qvi.WB#$Ҽo;wH0_A&18;0y.df .K|Q ~ z5eឦӛ͈ajhH-cЄR!{fȚ駼GƎPF&LD=|y\wA[K@<LD= *}7hp lB@O\֜kSYM{j ftZw"yT u~u{K5(._?(ϛ*< rlYO3$f'E<6 [Zr m.^1u'şH Z ף^~ 1m|J0 :MDEQb9H d{HFHa<3 (g vmIf"e+^eExE&Zw4R &d<*), KP{ pmtʕnJ cJBMu)ώȺVr[KB ux|bPض]BF[4sfp` t;2gDȘuVi. Kl@eMT,%NgdRjVtfO);ݠx姂V+٣40+,Y>OPF28*&X;gt;g-O^|զ[&,n6#X5_a!|L;֨ WeOF[޼Sƭv4Η)oOBK 6vA#"ܳ\U;V%۰"SL}7^4"/ r-Ϲ::'YÞ[Vp*u \ܶ"us^jѷ{RwԢC]kPURu.{k 7͵4Juobߐ櫟e.,o.|fޛNRmC;XknkX)0-i}+ñ*zݿDžB,$iX^`{:HO!s˅O[{@ Qc֬vkɚ ^~E+WLخm<9@CL jk!p}7m)`z¡E~˺~9 4 xA.Nmq~OdPפsPƀWgYw K E&% 8u:<DjChD&_6VKJ\Fy4b4v XwOk!w? pX~rv6]UŴgacT |/W׻\+nj[H"~ 9G|m[6i Fl)4-r1N\*PuoǤҮ샲[:؈鯔屇8=HJNci6*]).M .[Yc|Eůھu><Jλ'gI刋<@Ƽ/=.j,@ &IhpgD-+|89B7\-1G7_?vӧy8*(t&iq?zhŴGN2V 8,oX)Mc;j\OX V[kuJ,}VaɮtoO'|iԦbѐ]Z?[Gs*t_pWoKՙ.iN?~ҏPXIVz.^_9M mHV8"@Q%UgʕZ!Ĩ#bH"]Xqrk/-an*flvK:44Sn%ې4Sp ATpKB0$ ~GNw,ji[ۦH"ZKYneon/no)ᥧ0O@eK5-?w<[uOk:NSG ;9c AA<eYugUq  >X1aLfb", |(HyBv I;x㉳P2?iZS]goU8=-CT`:wEjeM!c8\s."+698膮@vJ1!MlH R&"؅7_c| Ay鏹JN:.^':uҗx]vS(8gMMGϲ%JrUjX{sT UPj I`7dl.8C.%?pUVb+KEۡW/6rʩzV#PxN8e0?l=b%^X5i(rRK>kZ_ORxhq9 x(1&) m E`saxD[Yc-9:;܀S ] zBsC!+U }iTMҹфYIA Љ(cj[W.г}[ ]A%z[t`m3JJ`bmD!7  (PG!ċEő<?=Jh=OQ{s?#-k ^&; M$pOY|6FHkb-7?J:SaH0nJE&+g|"/q%0;@{Z$Y3ۇw*!W4d,y8i(`L)!I,,/7m"!"U1fD!7E\q(޵Jy3yӖ*oo|YkՑaV4Pfʞb.vm$-&Pn-duȩGZ( nN'%7xd8 sDz:UQ[;噜)-12p$L7{5g7kEXm,9\а]**J +uc}S0E!$QzN#Ts/1w]mV΁<.k(F?n[€\͝ *Q kbi$& !C6ϢPz FH>`G gS!'Ӯ\^yMs\Q _=TP|~OQR|DLYNdỲإKhD0J^4LJHpE 5,MO *3n^|?SDLZ `zHۉfmdɿ>=>gco7}K_m[F@j{>6-]@?j0nhgꝦFwFg8^5M1_J֯!kG hf}sko7o_ύQ:4Fih.J~ʹȺhS(6A~Ԃ8URL31mgJ+6txک^R>ERa+@f UHaY7{rg#(:+=G^YsyEmѧzG$pJ/d~Ѹ]'52~BL8O(*,.3fke {cIDߑ紾W"B bHCõ4*HC~ut0'QZ xx>\}兵X0.2BA)jS6{Agcק!OH3@%FAo2T,,^`nfҡ'|dy )NIIx*쐅/ٲ͋$ĭsҋ8lMW@/::- &lY_AZ*>Ù߃K0v5\&,B!H~uI 83ef$5kZ P0U4P8D,[ # #a7 ϦG#aE Zj‘Mq6 bhw{y 1~j$en07&0%d.=vοIouKx!? :?Hs}-mK.})&'[>wז?0?3Gz/4ni>FNħo֫AGG'f$oXBQ.<0}{{Hb%ZCEDhK%8UGf%IcGLbmsר& w<S"x[6J&X4epE4<$I{C*@syʸ}4UDwS{uQ*[dХw6V}/IK&~Nuz=[9P=|]^$|OK9'*1f2| OWԌ&"C`A顎/U)w.+%(V Wb6选j6d:Jxw$(2TEg/.vHv#^m|>wV>?rv+/9n#Dh'4(= 5rп|q_|o4cP\gي\1gyfv 7m;*VEp?ƕ`3k]S\33[,{hWJٹW(}Z ͒>IajRuYXiϦhRZ?n:elV7W#Np|F<2ڞT<"YARPQ7uzpQup;`#ߴe\1Ir H!XCHk{oGWXio_WZf1v2zb9_fQ)/N\hqj-7pLk[ypd[NL昏I/&竪R6 3"~uzƝ=jqF~%B3ݵȕ E=XvsE̩jK@\uCe~)gpzqf S#v%|f(kvv!yk:Vl1mm `zgOiIT5I4I"QRHĂ]&㥢v:}6dި{Kp|_dWZ>1oӾ1mwu.(}{GdkpϯXb bAi< _|=wx[s9kH`F>Ĩ8M Jz;5̏JK=%Fɑշ?N;k%^ CNFD/^ P/gMzRAeJ-*Φ]ksdOp8P`!0d!P+.g^Z)8rQS y^ѻ*9Ss+Κ+d;7{7ޞ|>ߣfژ/0};Ԍ$~JZ,'_G0V ;ַL[f_7Pޝ׃A3ʯD9}~2),,vѢ ic~Q3 5NοZ_hqZ@\QovY|kl9~}F?JoD1{:ZR%Sx{#ud>d/ ͇r,hyIg_Vvt!ՐSf#'A2Kuy{9(GLT _8n °r eq_UhR .Dg[ EѴU.󐉖d{|l []3J G }*Pp ~~p~TGO}/J} ȯ!&(Ȍ}2;3~G g1t÷\h.!)UjzQqr3tY^*-0Ma7g{G5"A*j|(rv,CeEńw 1 Tr u1Mt><$*̝ĔҚP yO^g 1FctHX.}ZAѓ9z9=|2GZiu>FucG½L9w //<|.ɴݬySYHN,|~)[&E_ ig>](VqUi|>No0t-x׿i߷mȿyY-_k&zO볯۔־]C6#~m| 8ZTV<^jZ5d{\q bHP2SdA'w#n[DԂXΉl> "|&NE?|3vVG^ r.R 6in<(D_TRWPѮ)s "$'&ov,] Hm1VF\L>ЋlPa=}vl2U-Z!;Gl8~$y1!Oe9@~SjJ6Sqp.obO>C\Mq.1xCeE&CG7^q98>:xy3(U)RDR'gempRe%CafVݼ /%$'|41y.T:}FKoNq"ugx"Y]hx -/rݏ\ s  Km Eマ͝|K!]RY;aT @֏ wY!X>"}YW{ه'~kYxʂ&ZF`9ec 7UMpHo[ kByp#{'i@:[gB҉J@Gxsd>4Iq0za _9;%QᾜQ &[ %&РU\g\@>fؓQC R*?ޤ]9Ƕ| ށqC{O,ig~z>>/V4ٞA*눨 Ât^sdqVQ\R`hDc)Rg.zgeALFϾx '5G|W;P_3VK+E- ,Єt4sCfGw$Ƒ\I׷PAy w[C"Yot`{-?6mo8FCˉiQ` ;H ẫOHFTZ/¾nU/ZOк&LB{ gDO`CTp3t6}\.s7t;.Ce7O~ru'^j"-C` Fpg*q߱GŃGYC>Tlg(3~F9)Q8{ʵEXtc[$πFtv9bz~36z*%{A+28X!p aD Y󙎌~Eqg;kCWh`?֪ݍuՂ N2gم'8ăI%<6ȗek waoV4]e(؂,>%QL%L~q;#3ݚ;E +-|~lK@^ߛ ^\qLAИeFS"J[ F;&B%谉xT|\ *)?^tmyK<:s. ) ^yoqUݗ[N*/t9S<>U>.7Q#-Veľfw`KI %p I-Bz`? j ͚ u|be>LXUtcHR ˙\b9$9~&G@X[!6/_rvqtg2fgIFt*^ |Ud<3܈ ~R7oI؛m|˯B hETա Doϧ7ai-]Q?)lP|f"$(1.PޞPy]EOfsAiv Yx, =#zh^E6 ZhM=E/Ng:O:*zv?ԶI_jwN#Ic/MHsUڞ?ˬmQĦ`vWA3U6w[;/m1Mxfm7|fj?qBDm 07Go:@/#Z-?24ldep>hY Tm Ki V` t=M ؚ}X:_[,ZI6"L,y썴?>VUPB#Tb>v<{OIt@513(Hp"5SCej^J#N$RM^N2mpbt|ިpRB}-hG5>"+7HQ:o2HA) র{:K ~MHT/l e3Zl`H^Th9ke2CjކMRM3<olCCt tJ#WnTz'J I 1;]Y`[aC[Ե2ܢ{yܿ5f}e=spy/kcoB ^Ր]Hj>[qDr/,11ud·0f}ϞI2u0ZbLg}ȯhɀRClNT^:k-5dئ?*KIܢGU>~#YK<_] ZT oB!?h:?گ+YGnGjEcWRw/tHq,,iGj;YhB_*3ڜ~Oe-GxQߔ<]̯ϯvƟEQi0%TTpJ7)k2_qNC>U7/slJ=)@TA`~nׅ+RvuWT>1߾:d+??Sy[׈&~亾Yh2WWG*8Am,P;z4'D1>RN1,BoJ6o?&ũpㄢ7)e>SFqT*ɯIm$i5 4 { _!z](ak%l/S6-_Ϲ\3 ݽfR+$BՏl_ PFs$'U}04Ybc IV|PŽ/\&I?{>YPR3wII;/Yd]K/lnbnBշO=GM== .tIL)\F"㕍@cx1l2bݩk-l-ǣ{҃@܅;ZʽDKer}w-9vu|>oIN!ZbC^ Dގrk`\cJNp{x*tkyӔTIHdd1jvCP|AҀ{D 50PWL&,zĒk`bX,15n'?ᾥ&?K޿/ſ.MK+4sW_BJ|h8\#ay\QZśVzjR] s6ʬkּ/>ol1!v2g4WPm($?-d-7|U,6:8vQv:Xyq0ֻSLVʚX Sxu/DqG~d=UX^^'D)`B|i>&w W^qõ576P'gKeEzj`b7X|S Q;[Ƒj Ni'vG,ˀ]@pł0 W^/!%ƐY!7 vU%E>"I| s<&T- '? ::t^L#0JFOv-ڛ Ĥ 4}6k{ t F>%B3[闎kP{ԕlJ"$EMy\IS1>mV~zQ̎RGp%+ ygQ8Jg}TX˻PQ gEl12[ߴuj?wd]!%>f[@  |d Xi4^Qpߟg32(U,_f[s| J1hy@;o1QAXc{>Yi!FES`#˶c0 w9dS8~!nD1N]w_VK{vj;_ZoM3H"S{OveJQ-:f/h=xf#%|BR3>oU 9?`uy'L]t5!bWf\e?W(B/";|^dN傦ݸ.^H$J*Pr pP Uz5hۈ?B 0SIOzvcvOΠ]LlUuV $w-|VG|{Yv{@`bkKG|$( yBGh1JRF̲is - I<{TGJ wa_ bolĀ;1o[{0Ip7]J՟tȐNGf8! Y9p6)h_JWqR_C>c)V5F)y]Ѽ ֑sY25yۍk. "bY^k/XLvm5;LCݻݞeL-)mmb{#3ԾUFTzuI[w)O vp9?6ZVgk*fq'(7i |}h sV }y,D<(wg/EPj/'3xM7ຑ}.eʮ 1V/Σ߇iX/||K^PKSРۡWuB= rف| |eBЈl1-$~h/Jl*M}@xutP5[x4Yűh8+оw%[7ymygޟ?=t<aԒY77|b!{bӤb\IuoEgIxg:D-kjH 7y]6G#gőy30Z. \m|N E7:LswWRm >_.{\dPWxR8, pۧ~S#PWǩ,sQ5%Hï 7Pv7o )FT!^.qDf;K1*E䲏g9cD#wȴ{?V4mTw y}zB i_ +JtQAJ JŽperX=" }DړroɄ4oRutg2ؕ?;^ݦI(nZyuA{@Ҍ 3kUчn,G7 p{s۹TDFwlYH~BI&T[*T$tytwJs\4QR}5p0&j&rۡ~4fǤE JzS/WyOj|-ܝB?~4}0/[C&VyO'x ̄XwZj+'x0QޘUodM:uϚ}zk)jٍ;R M"a'}!y8??;I@`VM4cbN NU)jxl䬳k K[`}ŠQ]nliG,?bф|e:`@ȵ_CD:zdWT WQ/:W[u  +ˍ^ in ga2Ge0~5QO:V6YARŹue?Ϸiui/ۀ@d /l>346U-VŠ~3SbQw O5&Ƽ1@=_O]!lPQϝ7E?vLo 8;J3dPث=Tcv^q0;@Ni4O)Lʵz2/So?p&ap,yO E 3OF8V#2 2 H"}R8~*yx􈣦\Df&_DNȢ( 4-AiJcʊ 46oZC`H4؏\&m{\\v;cb$lJ*Cq"YӒe6M8uy,ٗ|li=#ߍ2ӆyțXx.sis)ӺL׬WEQ*{?1*M$7iG [r' 5ϰ)g鳫N԰P\G;wtkTZvd1>ܷ{%)7%VTKs",xdgTvD!m!iW֜x!nC{jy_&nQ_6aZ s̃GH86_up%v,M(5^YAk="lv(D˜6g|9|}QYSHmzf)xy< ӥ*"%+*PArB2سv}c]O$Wk)(#^ҷpl0GyzsyDrCA)1.v LԴr?xwyT mg=-Y1b5 kDo)}9gxg{cԯ 1Dm!Rt0IL8= Olkȫ! Mw/[sԟjvNܗ8;'=j-npO޴\,1Ǥ^S8;N:e2`8!{ۍ%ïMXFŖ+YD&* 6RlޯU z@tQy^1U{B3Py4%،"ǰƩ} dE| /w`1]\a 񋅎֕̂r T Mx")[ M)=ٛwa5&oK#lb9v,gHM3VW蒌u HS=p. LԚ)zף?Bd*/o`[6n} !mZϩ/+.HhE~hͺ3*kvH *u} Q}C wDd̑RbHSxNfT ĺ?عfƒ(aى #(?mV.X& < Ăͻn'/w]_ "'b"!=}*"8X^D]mT'\F>М/uCW C&6Ֆ$D5S{w#d7f/I[-t;5 ʇNLfCs( pnI^4 _6A}^E ne$RS'fA)udl( >zO+moC}MuBAD"SB|͚Z'OVK0m>V>nDe  WSi>_Zg0V1VdžFvjNBfn{sq&& i(u O!Ŷ7Xu'dDz\Ck)wWX. hkg=Rޞ~TZ z֛wbvAnz(1Ӌ-X#D쏂?f0BJzty6 :Q( bËkM[A?Ӄ`-K8@1flX`َGùte Q=ΥVS8 G O;b~_x\ipK*bq(#{Scݯ?l]*"Vl5[s]4bAaeBwIE(fK@M-mdT;'TJ8?.Sb.a!,FU_SY5'@rs[ě]9@,wHI!<푁*7y\bӷ2_dfO1& "DdÄA_̏\Tmk5E@fıl_qS=]Y.6L.; ܫ&SM͂S -n&97bQw܉ܛ.Nqc|ˍ?Ҍסr @I{* ߣ̊H̖ #|!3l c[rZ7۫8 xOVB_u, @ t\~*]I?6*x9IVMs(۾] H q\=lI{^Oޏx(.Ƀ ]n(ZUٕR u"-B735v=;Pq~3,14-\ы` |thf?nrIx6C'`G.-vRM|ʥVz"p_BU=CS3ͣz2tR P}O'\CA1= ,i_76|2lN@Hxc~&ScƄO.').`XEWTf&8Ze=!_;_ʥ4~R)ʥQ\mYCS>7,ݩ4MZ.#|곗 Bq{;-ZUۛ9M~Su;/- :+lY 0-AhoJHP`n:Q)n,:ry=ՏiӇ7>tCw,t?6AY6(Yp yNL80r^Q"o}B(87iYMڮ0_iqFKl!o-c@bkm[EsǨ{OhGY[$~/?׬oM">{3f UwpOQ }G Ik~}KqN~/MSD_jZ#_LIzw*K;5k+G#@]/w2U2}ݟaI~Qr?wY躾1.\QeSV*_/J6OhǞ("l[6@Qeڟ[8kK{0͊lNljYt@y&hKLXh-f`᝺nR|^yq/ǺGLVH^5)^=Q<<ݥ[u%`,Mسgc#yytk^ vfg`WRك.r:Q%/)0&e W";>mHĠկ6W_UնS++Z0à9`0o b(gxdJ5f P :6c`>̆lAukj2 szޜ^EbqF"LqBC.;>ECTe`ImэXҕ\E![;5]^+DS/S5(^A޻͕ 0-!]npT2QDOLZ:Wwe1i/㥜uy'Bժqtzz KD~PO'XAx0ېFZ&_GhКdW eW ܂fj[tUnS5sڱVb;vXٗum⨜y JR0Rf r>Q& 櫥Qvα k5q Lk-WqE{7ņ^XuchN+ "''9HlsR8zVܭ,WR&n!t;zDq5N-b 'dOBoݫn@Mf3t$[fkW.,z`s$awBUe`Ll_=-T֏stߴJ|pB/rQ4;㽊D,ܖ\'.ִ4X޽B.Ѩɠa[KU`>eP}x;1!v<v_ikݴV U}3h>MmB+l\>$bZcLa$q*ѾbPYe@7<dۓ(B1$b&Q3Pn{\D|X53K3+At"+ޝaPz"Oi4my,nMdnJc: 2Qyڂv>lt(gH31mxخ=xGeXw$uvbjUw+Ė7S?|H2 Ё֙:FHyv7&aI|b=.Ƕa{br&Z qJW.| %{D4[ytQ%='/qqsc /UΗ&6W:VWnVwFO [ X6? '47.Q'X&邂75./h5/; yO:fG 7fVgkU|5q|Bʖ QY/= u`~w\=ۅNo $5dHe̤W@8?;/o_yX`P9s銎'd @딌tB:Zw!Mo"apQ ifڪiudU ѽץ)5 7Cx =Ջb" 8B,X XS.Ko Mq42`e* `^)r{m)*OKE#1Rq.:~xw5Gɴ|"0=[9%"zX1$xj*Ģ(αnd$a;='OZX"Jcoą $q{\mچgS|Q#*2_ 0^Äj5yUϢ [cf= is D=oI ي1"C!A-Fv+̥YOѴ{GFop@Aœ/DSvGv[= Y8wiEmsAjVeh 0 q=G6=8sEWz ڱ,Gfzܶ;4|3s|/Pa\%]%T_4aupw2ksiu:)rxvҪuJ2s3.%&!*9^/gS;̡p ¡ f!"Dz!MS[վV'l=#vنwOu4Zb-0B7Nӏ;kCB}5,2P|35Af`y ,0uxq }MR+*kHBG%]"Q & 4=׋Q .fCQs)iȔ8f# -X*Gm{OlX\}3yrXiTr(iC/hq ӡ{Q,P{ e9Z DRy_!Eث35|fT(Iiҟj@V oL őU{c6WByj|JJ xGstC$k\l~`}gV:luQQ^4vmp[Ӥ Ƣ[z.e?]L^i?ﷆBy)_u/Wp8ɮ֮z/#ޯ㻢]pAsеttOEfN.ѥDNN](Ֆĩ PX9 ) {1=~O)y2T%x Ffd˫r; p3v2@~+hyxu &>33Pp4eNRw_B :XHɞ)4'ٌd.:o:-hNmeF]Iw/7P#f kyE]l.ulHqztsdc}l՛ZCFI^ner#[{}e\1r@.ԮxoPVIFeq-I XVLo_RZ[Ehfn Z=4B3`+^u"HI>٩yzDd Ԫ#uxR&pAR{yW 0?wU2[YK]5 ع+iT1B-PCJh5Lʽ]s7'Rϲg;ܨjCxՔwmL]U2FkE?|)<8]4u9|zI:~ԭ*c\ PO?˛_~m{2S9ï>Tk_: >5tȄӒC6=7I9U0fċ[Fm8ua0EP+ 5"o&{$f\ȴ¬}.~wMqMuVol '/i~*[j(tq䵂ْ!*PKPA%.+\>ŒǓ;MpǪ?\8@IJOq[nr(xsܐma/W4K:xy/DRΜo/t@Wҧo?:eur5-:*n?vBf2?6Xkt hd|*mYDZ!@&LǸe_I |W*lB8oii}50< &D&Nh-W߼q@SzeK8}7}z]jh6א^7ܫ`a!~20>qOY)\ pTIfm~%KtCʜ%pOa:wNٖXi|qH|w0~ԵܩWhV6f~O 4&%J4Og`.y X]HPTw+(cєr OSSs7,B~F>/ܦF}25IMW se#o2ϒQdQO&&X%O߇a:+Oxh^cbN,SVZnq܆S tenR-mQw>Q&}yIk[ل$ ,# S&c&El%0т4BL\*f+o4-uya݄=A;1$ع86Nʹd^>g9N\|ʭgɟ2Z4׌  eOwS{?3w~A{t?Gl_ѝ9[^*p2K K}ZvlӚ*քE0 x?:UYo4½7{ uѶ}NLo0#tߢP[B@bGvuqGQhSB [h:>`@ljgMW"8z^Xў4=#zgE pl`N;0'Hqb%MVN"4'JyB78ƨp!Klqf/P\<΃3^eӧ!yVrnT*c ?Mgai ]9kX2Fbgz%u4Ҭy:#edGVfyA z_*QXC&:$Y0WwV~t%on}Ϫ)E'tCUy`}vf[%J<J0qpRnQxR[ssB#]YDlTE!d>_Pa0@*&gB"Gc9 ebx XJI?*|V=Ww׍(ere؁!bja/=<\/twވ旣g3u"+1Iエ1,ş]Zh !k%ϒkGM1;EٓE:4$R5Cm\F\ 5P̔,GrqaË/=^O$ r&wz gW j ^jRU$W.n'vfD<-8Y;+/ ( [-C0 `[na} & %nq0v|ݝ],hKMNZ*cӹe֓ցBEDdrU4]L`r(Xr&rBׇOJ!>TE \t<>krBv{Q4ziAƸm"T~ϑĪ tIz-2|Q(heYOufJ[NH%mV'r,vw Yu{C!+E#Gl,`0={lQ?0 p=NM#"eeޯX?"zJ?%J2mrGN ^| +I]HQonS<1 :7iy*rz&HJmJgp 俬ϧ?eIQ0-\9x3Ql&_(:@4  A_E|ݗYw׿.֘_k~8~D_7Fu@gDcp!c-sHt{vP靃N {&F`e<1X g4WO^O*W=qz Uʮu&bQ!s[AKޮW_^Y؈r+zY7CSk]ۻ`\FfUy* Z@pCxQ;ijI༿i;j:At)a7cNɢY]Wm v 31 T95 @HqϠ_zDilW̝+,֯%=Ѵ.o3`{oT"@9>-Q;@=6՛[ Ȱgb^gC+&nY}ʊ@`wЪFtzB@A"˗|'e;fu6kn8Cǔ'9)^OnѶl&;.$5DE-:z^2T8էȠ,;> T kJ۸S:o<^ޔ;>׌61:J+hiiOdr.%Qhgގ0=XCtiyj taU[MGbvzΖ:U&L; f]n~cf)QߙHC[ClܬFx(y1H{Ux%ᒕ B1t~`؆xxVQ@'-NS="2%9,|@6ӿ:$w'&W?uM6gMr7Cp%BK6LPNIL4 Z?mGk7|+xdZht5$e˧!o~3Js=mthErP2PѱJ LuNĬWSpIX;^Tpیv#>3=iZ4AKRwy5>RޑJnx7}Dy> ǶkyTfaODޕa @*Gd S: yNoq‡ *9ꓻ`?YQD*eHH:>mT{A~rN.Qktm-y!_L^8F.f,G& EG #PrE[fV  ƠJ@'y1VyIgqK$h/̢1yk*W"ؖb7?us5 HrbN5NVKx?0CT%Z@ K‡P$b2T1a(+BZ@ڈ!,@_\?&Ys"QuLFyOVP*Q;U~%z+q +|$: %BWs T,kR+'ɯ1*^ޢ=Z5``aswr \הEG/澫.0<)N" #4]'qpHT<_]8fwh8]y":mA`ݽc3/<4 X |a,WƲSXj{,'z%]xn63KJ9LxYH`Soae'bύZvgh'~qn}ZT5\o~AY5<}]d*@c/݆+wnK&zڧ 5jTcEHc2|VE,W|16_lwzFտz,/^4fZ~l`k~> o=[`/,W bPpfF$yjS֤\{b6O34Cu5|q,M%2r),Mn>kOǵ|$`SV6hIc[$xEy"񾸌pPJkސRcliϢ| 4J3#pd{L6f|w. ܌hxQAx` 6xƮ.IL8:.CMvQO/ʥ6(W7兎w凞j&& X"ө3"^Tk]4,:M_zѯXvi9&o>6K0˗|j邹(ڳFEm_-)UVS-GWN #+*TYE`/#&' v"?i1ox87Eu />Oa`N2蝳ϊ (EC5N ;l޳yc͟:C~}K9`]Mb,o9(ka[&̊WCkےme I#I!;yta&-{&~QSw}NB}GFz'"$pe.z2e?LA0NV^-TlYQ.:lw*ߥb8K 7+=Ӂ.Ȫ'q)AȫzZ'?Z%t~H3ZD w!MKTĵ|DE\}Ast`X>4IuC.  ҹTon,{L!0WQ=aɈ6<'tԖȕ t쏼?%VI(}O51\x殂H460/^0Sڒzq=S%e*I.͜˜Te;  q, ?$ͅwWKGj~Y(d*z~RY* j)r )_Oي6WD.S@/X(4_-hF{[EKi.5B:}[1xS;q;^@+􂾿d _7O&<Îo ۛ$=݂sVs^HCz}D@j w uV|ᑑY3>眧Oy_|Espf=KECX'oq,Bu *=q01y:QQwb}lq[M3kAGr 'Vv1P,+13ͧh: v&_g,.C8}A-go V }|!k> ݃fI8⫈g*?< rRğxXO*$*Vg=\[?w\kBz~XM!4ipv\8ΐODHDnFLʝY9U=ʍn?tȘ$pqXSH8$\1XUMHV3-WlOT4;2E*`v3Z64E\顽$ߪ F#ʐC+(-|Kw4ItAܔ& fR3H(S{(M1mSx!Dn%JLݑGc駄enbkD 3:Zbz7vNPY 'N7lZ ՝K?6oϻUGC.ajZp߻_ *Pe&2S1v/*KGMymco3{%1jKŮƤۇ$_)L ߿Ps؞*\bԖ1f v~ [ho 07)lZҜ_'_%`EX0忧~m6UȊ֜E#ݯmLT]x_*Fݶ!ARRep؇s k=Tu8G_#iZ\/vA׾KXI~s_ h'~%K.*r=yjO.#= .J{K%nA9*YB9ŷv# Xi!0e*s~KZ$Ԭza kbj 7NJ[@S~LÛߔ4>ft" )+ qZ0O [Hbweb)_&XZx-v`ؤ [oD@ HQR>nPSґӗPq$^:7;}a74" m3Si=VQb3^Ϗ[~kq$U]5vs`٩ySaBr+ `TKߵ9LGih/|G/3Lǡb\e׊`h3SePш(!N~Rji6#~|4|LQ5Wm[-AxAa.7弻9fbq H51c=Q;@ݩA+3DyS9d/>84.fT]5}Iq_ m` W*(\QiG. aIPdHO.PiGA*;q)]tצ{qb&URAIw{%~W*hOa9Ο~k/J|-x~mmw!o/??RAQ=Ty](M6Z}›_ŊU< ȈY`JT/H}֛3L;=ꀠ6[=M`iz~{c"Z}<=[g硅Q߯N4+3$P7%M3ҕCt;aNCϹ&`ԼEO]f$DoB}W(^mښ!rUBN kcmf_I;H_|VV> WE҉gRn ppB9#dA=~5,)shA{.}p6ռAWcYTbH[D"D' b>O #ޝ2/n~VnJ'"O/Y<#<_-6yYu1w .%^b'-/;U#.Z=/kT:b-ŭ) fe|ZKVpònѠLB_ ژj-!{diC<Iiώ֛el6K>oOMCBbJU4+A Nkc/~ ȗM$z -=}exJdR6g;x&'a?r mݽd7 dbcWˣ=iTП.e!OIh!ҳ-LV}5" >dqgŰ$8e0'z]^ _V@j/x^e4q_bJ>z/XzHju H2D絺YZ #\Si>_r(#r: c'2wbS$,.pK×\ΏjC¿6|ه+0&5a?wsKVbNmpP?HA\=-$K4}^5˽U&5z¯?ƬY}@Km/3/`mS &/oA,=QPmiwno?\˦H8Rk~MN[,H"EdSg0_]5&vs C2z$ Pˢ EtC]Ds/gVO5 1uףf>]?;^.5o*X> V> 0W 5*46XzzwŊ8:HJզչr<>*j VS$!朔Ks4Nј@gE򔷐)v HKG kI3,ISWxP=QX8ܖFN` rs.VQM" v?4Ukby@C~q!K2Z2-hSe$#C8NJQÙqmSJ( uRN_j;-RU!ɐ؅/"vgBX/V0T~†)[Ceīi%MUYDM7zm;f|~D~OTC~ަgo̞%p-/c};oL&v]4f,plO*axDd+uFnL%<]VMƈXHe.ss0BWEں& sX xG. OAN q?锈R!Bi3afdFoXA#k @Nh+4$ǭ%&B_$[$) (熽GR1훖a'`sg8ɞ@tt.^?AӍ̐-,!?08eޘ^9msgáȣܣDi[T9[F_<Q 7u^L}sV@9 j@eF#qxs`cAo:Rap>e^u~. wGa\ACE:61;BzҎF~DD߽lBY?K%B4 $fgV؊{nIgfjj46pcPP)>b,)nx|=Y2Z}䔆$LCX./<A@yEGMy氇B&KvQ>JHj q/CynZ>oOU@ɶ郂#y4,1/ j{sh1~'o1^_N]F&LձprǾw02[?{ "g׷&`7Kl }@||}u\_Sھb)Te_OWn:u\o&ిaҥyl);SfC{Rsuc~0+.:r|^c}eQ`a R+'<0qb)V\HH!~_$4~>O~-JܒL.QBُ3*Xco'T /qo3S0AcmÑK Λ~-EiZC5HXm 7ipXBT5wIg>ZS6!M-Yꈍ_ 1 B42abű"r =5)GlG~~4cR®=6F&9œ'ҽ &!Xv˨9>NكԘH+G?SvĊLXk#QQ_ZSx,TzDVt*2#D5s}9Q5| !A_ ~ѷgԤ~W[#'Z# -;-_ɄY-3Pp䡽-Դ#6GiEw-BZx112XZZX̾"/3EƐ!8/aK IMp>?5ʎ}B Ad7:^ĽEK'AO.Y1 w%/^kθ:m mwY0͎j_lx h(C"Bg+Dϯŷܔ؉U|Vq >wCF>UP)i^›-&nZ5<)\z?`,p;dHz1v^9Ħi܄#uꆑi4VT{ OyIH4W=}w}Q !Hg4 ?Ǚ?Zts[ғTNդ-xS"|2Z ?ʴ_LHlDea4 .DW}}.^x:JD5xۭ?z/vRm|,Mwn_ۀo뿾v~wnuPHn\ࠦl`ܣж59u]e9GG=}*>K(7en 2[p`i@Źh3LVm򒴘Faha֝{2<*Ap^2Ld[5žǏ]G 4ƏAJŜE:P;̩mBߢ5wgjy5t ߈蓉g)cIVZ KM?f#di@;X S:vU}N*y-Iv%ZO&ndp1 d11=uau.[;a@x?Wm[ύO!0fJϊfxcR = >;VfXBye0 wp=pM2LBMZ8hVcѼQۻ)Q5~l ŽN,^ÃP-KH;2,i =ܚ-ale/ h|؟"FpHx" Ddj bWrUE\t+a|QR, V3*U<ҍDS姁uo EvyyxN%y7v\CDFu/9Y G6:ϸ tG d}G34Tx헨x ex#0@d.I²SGof7[zefʁ)jrFP[~om}w|U}*BT6(W,0ݿ7 70_j_Ao"~$l-3^U媁|0?9d\s3xȹs"A!7|}.R;#?B(l87/q~#VMj\ydksQ'D|`fwS{=O1ޝ8:Ok3;C*\:;ܴK|<جn960\ol$"I[/bECK[GKŬ\ڰ+ DZ4D3nǯb/$=Ck; TyŅۘpӜ2'l)eg ]%SGxu'Ca}C{ K > OiT(^+.ӯ ?VKGle_ٴWl_(q3f/kH"[+Dߖy*HzrJ%;=Aȁ| Q{,JgT^?>o0K2{߹y{5MvRљ` Em%#BD vLiƹ C⃍na>yil_wy=J%gηfy抧Pe&Y'z۳D&vC MAil@=Lq@e-Wt!B3͜8ކjs>/Yf[\9U'2d}cBYnbE?y^{p/d||ݽwn1}waU: l'n:zo+G{*%y!f e 6+Cv Jv,]a *HxOp4㾥3vνΠ\+n.O]+M{\>c:oNJ]4eoN`./3o"'gɲW nC5S?-O#6%J ACWXbsO3Lp5P"3w', Y1,rA Y \drW;6QdO]#qsIdU˭BO}_v}痼V* =jJg 58['\aw):j VZ b3'EұYӃ\] 5>r;aB$dZcp0hC lx+͂kfEfq D"Mmqh)jyḧ́t;ٲ;ؔa-ޡhoFRQ>CH͈};n¹dšRCK:#Rwng Ǧ6*\y~foon`4Cm4ؤg%[K$/+tAcEQρՎ[g%>XbL6d< 2kd},V¼/@92KIJ Ybz{nI5EoߚN0ߪT4Δʝ G=&O-C 4K5)&M-Zp}D/r5eWc CfuST[dɌ8 }hghOW44/HZ_˿m6jk!#%wz_G)??† Ѽ071vsg^3'Y;¿A+xg@!0HD  .5aEny~NPDНǎ3Q%m=jeWQrȆۓA# t߿HtLοkp2ȂF\HkcP}8RCyt$WfrI/A: IۓXckSZD~|(+:ƤsٶSm׼$)ETd|mfw۷GgW_I)\0?}-1k<,!2Zjf%I*F ?"fԘ:<$H}{`WZ&᧌:8a 0:z==wyۅds%Fh Ӑ܆.;Pa;T+5!!pyc+&mCB?_Y[)K."P0,"|Q˳3.=@_ ob~a'Vi;Si4qjw>7=0c Ve'if\˔t祈=O.k!.ui_I+f!gZe z ?~{o i,Ì*o-]o wpZG-cĎ5M~/۝m+O˨CIG`ڸ&Q0"J{\6m$b̺}>ٱx|pclּ ED(k1<[L.l+kAKti!6y }cKz{b4y"kqJ[@IvKw8F053w(PRU) -Sò]}O)P`։s7Y=AME-xáSu; HMvBXa~~CR ʃ YJ{:-ɳwƧZnM9* PgQ޳Xc۰݉w[!ǰ+EsƄoN?l\9H6<좔Y *m>p.IXX\'+;/w9>zZ{ ɇ ޏΉE ]&j+a3f~vgMF7{͇|RmVKg`XK8D4cePNz)1كpNžٓ6q=KX#} .ck֤{ClH`)ǿq\?;V6oU4 `(XHɸZgODnG"殄sI.,Ewݢy8g媝9*1e7{IB4n_aC/fփ} TmJ U+{m7yk!µ|d!VsԒn&z~[i5]0g εE!\/0[Bg~'⏒An3fB^}Ls%m)Mq^sx*" iF#}vf~V0dg.0A{"Lp .EFؾ{8>DpK@r0aQ.$^kC!˴8Zv0XSbKz7F@ EZl|>*3LŔ1`qRA::Y+u`bq;6=M"fiu gj?Y7H.:U"Agx%q3둶UTϨw{? hW6xpˑ; igtb@d) վ>k%?"WP \>5 P0/}q]ut_VͥsP:4cm;X"zP{Y|1苋ŃI7`wǸ"x s:&3yӬ><,{ARdDNUs=[q .e)=~|GypauRltWiMᏩ7  ]ml6 [w|c`ĩ6"!zt_I_18Tv }&PWA߸_#r7#e.~ Ӥ*d':o]t%qSJ',nM͇CY{$SdetYc${z+a7$Uk%usbKj"Iu%Z]{%]u+T"X]q`/%K;kæ KwTQNO4yPnIkj_%~,^-} `15!_A= s `.zRF1\K`O3ю@xh rK?;!:ƶ+(@N?Ek-J̓dmS"K0ՙj9*&io+K[/[6ļ=%#;&Oy?fש3E(kƪ~?mif *3Je|oMY-]_,fH!Xu&*,ȮxG$Ώ;HbQk,K Z1YC9*!lg5dvL_޻ –F,_YCʕ];cw0^7x$T+dq ȱ޹Ei2mPK4<f+-ߴMf^Sw .X6#8]9wm}C)RpheEF+pOmHڈȲ8Ek|QC ,'*T)[d#< b^w{Fn9j1:.Vc;24QZQy(amYDl/b)}YEcsDWf @OwlPBȏ<~"P:݌h!"c<8Np\v-e@ݠM7ZDs؅)䰝m0:TGf,KO!pQ8>W<!>nh 6|! b>_xH`q >ý*8 k=1}IKPY\K标x,]Qc_8F5YE )G#} a%m{,Iyr|HQ𾃤bu/_ɶ\|| }r4H01:OrBp&2G6C+-n_.QxT8Yһ">Ol=*UE`Yx0bds)`E=[8O'؋&0E .=!T4rI4D106aa1_"v 5UHуjЈ`bW/ NdT6tm_ѿ[vӿe9Eho_1Z+FrN?hɁw7U蠵ySH1A}lDNf0ʨD!e%&Zu\+}Yh:m|e" ,â"zLv{$`'MB4]JIȧ}d6iW)Wo$_Vﱕ\1s4<#UnrNn;?lsŗA P^bh] Fpا1]f{Gv=: 05ͩJ:;UG=|1>R'+~H7dz5%3(Ϫ׆K|v/ޟM-G2L8*8A~ o[ nwvT@1|~W^ebP-/T3M/k×Dkӫ}WD1g ѦǣITݐ i1HeێتEgʗvAX^Sɝn~Ѓ[sIsF`oY:;884sWV^tMACTMFBU4CIL9rOyll -8Z¯ b)=A5zt%|ߜDLnޛw;%yo)䜊h2S< U .15}"ٟ}@%gW۟C\?#,4AS4&#+twv\M_Aoh$Y{r %aA v@~ ~m5t[)_OyT=z}Kۈ>uW=SyS/rNw1%]Yj%0!o'5zj+^!.<ΎL({A}p?GP;NG m*Ch J}pjb6QiӌKrߪ@, tڣ8GG^5h&,zC'+2'Ǥpv2d#ʣilx.~$bm1_LRr[?hfB(7ڤ9=9;&قqp@'^ 6 113ʤY MBO_ukVP`n1isQhq%|jo{T+ -YS*+p}ˏP o9l#w!ZD2@YVЗ7P$H0ܻ4܈!0#=}ۻ fwヾGK2lO5 ȹ1/|2{kc6SC!҅\G${"Uz2p?Zgmp;<;yyYϓ^P;dM"83ow ,`!$TVj^B"\@ HdԞNj4׭e$ lSP5& pMQ>mڦLYemR697BJSaCӤ(wH"/Z&%1%ycmwV풓]%\ܓ, g7 n›?yV]\-q""맬Tn@/ZDQa,U7qWvդqf\1O{<#bH o2[G42ܖ֡mZ|x$uEqKsN9ʮ܄W23Gx|2ZAN12'O,.vh-4m/JFtdLVyveƜR>Z g%J<& X|G|SlJxѷ%w-&*6ـzd/a^.Jiš.Iv5NӢ w*.caOP\=Rb;ӋgtOz5Jdҝ?^6'tW ҝ gW5^/*OnK; c<Ϗ3dGɿ\bФU.\zTBc㠛p l~Pv|3ynb}|ő)ʶ^=B$n- d{| BEKvUZPi6\^ *5i}(_'MOVe/v_~ΰ81XL&_2e<=~ئYzl:n*:R"z<@ Bi|Q4'Oy&U/T8BAib496 p=fkKWw䁟s.]׺>sz ]$D%\Ukn= 7aΰcӜH|?sQ+#'s;۱ Z84&S͸zz?q\\ -6ΐ?zb?q3]|t/mϔ}݈mlmfв/:$(d*?[|a};tk$y=Ax?w!$$|G]|,/.@ݠeZ=ޒF>(_ {9+~}z1\+rV',D Ww#8zzu( QkdDɛpъ(/x(:FX$Өt?^o9f ]$Lj]dYa8^!;g$ Y[Fu#%9F/="^meLW^B9\Lǽ6y@XddL{G ]O{^|]2QSܐر)/rwٙfŇܥT '뛬LdE,¤y#t h݋_mB \[O@-MS*4Ȯ<"fDx?ZPꈏ7O`\M `-$ԹCr^TMD s-78 #yYz!\2VG|lj2o3& jq?v+i5Vi.bSxcmy 6E6 M~DVDV)Ehߘ^'2_ `ٽH+]񽃝I2wu3jngΑ ;摌ʌrMB异:MQ +ʕןB[WM@N<Æ=1v̯JTvGvd xkMCZt3"sؑ\cRxl۟MjRA_n1K/ꓤ]}h+~Y~!7Mme}Fz5aն:t1Q&QGg)_l x-*-vc5]/k*\DȻLQVx|%fҤ AoEE/'t^{N'kCvXOܔ,Ro2zt0ĥSˇX\~O< k=貕׸_oX-msQxàt7 i^/BV"ӴD-ؘs ő(I,8hHnaܠ{5zX۽x: u& Nz+5gjdyx=A|xnj}ޮWvTZq>837󝲈S{BF{I0\q"\77w0cD)tb/%F$_"]/@vk $~GMS^-pPM;dIua@[8oF/q[PA6苪 (ɓp!HBǙ:+><|;B[x?BW]LY%.E%nctAh!l:ptL j.B.ҝD!% iV9S9ZLt{| ?%ZH{'S R9!޷m4ӂͰQvv>L րH: L4[s+-h&zNk0gEc|7H!=#~jȿ8rx31C®lr fhEt8ID:\4vCC2gQ3SĶv.FU?0V;-Hߥ6PQ*{܅j-R2ۄ y>nţiSH'ɦ=]CGsGֵ?06F ~Tu;FuLKHjzIae&k|/naE*sDiwTG GNTb3*=vqm:*K.dΛ;K ח;W!*iRCF$׀rq[Q :L3_jBɕ;AeIM&A/A婫S`)Ӄ;h _U^|3LƆy4I..kθ6(z F[sSޑj@G{QgΩ_ >gw$w): Y}{̧xr4(Cۻ 9maUh3{k\#BA9H`m*`Q\bƓ^XȪAro!~A?F|.6&uX\`S.\ >7ޮ1Vk{R9:R8r~FQ֖%U"P>.7+=bkP^`4{m#DӼ{ Q76E1E|u.&Q1)KE˃9• p`6^m+TPTf a Mx0%kliiq2,'g%`][&Bd:Wc#Oj?Ttվ^ MP/Gy5"yjyoTYf,tqV+^OF{?5!)wvJg?M>Zx}E4)HJ(y T4@F8&?(MC&0}2uT: ^&UilR⏎K0ݦBt<=kԪC*j;Hohf"C*ޗgsʢԠIPwt 7F2g"5P]#HrpܘYO' u~UxZ1`0m1]ĒMTD\;0t`FW{{|?(ۏ|).YvIIz Bnf6|">?|34x!Tc甈<xIsWH ?V3SQh+;i1IJaEhqXG ,0*qRnS7?+D[P,8o;|'\ε!gF%uΒf@IѴXwsO˟)j||}p&?e uE*?M>%B|˰,/*ڙwW⚷04-#hK~*6b*t.zsਸ਼Ȋ9t I"VjV|øxBwQUԮ;ǜ{Nnv&}т[ăG-{jz^_&AZ5/`tDT< >kxjre*ݙ4#,tƭ`p$C5?p]6\ A(p1IjjNҖz86}0"oyy/+/A>sZyC$24B8AC4eea4oYd,=H"o@Hm&" EgΛй '^uaOq,Ydt7a7(l~{ b{\ܶ<ʌ0Y4x]3}$]I $8v?/OZvͲ t8^[G~k_u'u+ ]ň&.*I̠P=)mp%8Nfj/va؂9qa^ZdvHTqh8M}e7]+U馒-j,fBnltȫ%1c)C(|՜+*-[Gn&TrيAZ<ŞN]ha(6$T#"HvAAfyP*$L" &*acn@W `"50*õ}Y3pB^x)g؇|.M#,szԛX@Dv ըfEK|"V^BDzN 6ގ:_a[$@GJ6#!G 7I_z\qJrxa0$e e^>.L{7j3Ж;U A\0Nͩs{ =ePps}uLrg{LB OWiMuڒ {f\򱇬5RnJH dK,fNgn.,]kۆq# $z+8wqJE6XΨz0:̰ttJ07i;3{/OYoϲ\xEۏ>K@obk&'2 Byvkqzsx5IWOm*!<7Ty.d<3eC7)]It(i)vF\zc tyC%}y`}$xY*`t';wxwQa3-y)mꕱu/MrM/E]CYU28ìy䁥 DLp͗§i,'z 8+JWV+C qG3uus=VվӝuGf--dR=]Œ-MhmUmnYޓMM]',qPx:]dR41eR[royDl.O6͹Ԕ2`vDqOvGgOrYDֺ 6"'j 3yC/xă..m<%s`oqI" 5cf_㋣& OZHDX"6;ԣUSxI},MGtQdUzDnw7#Pd4v{ܘ_(JOplĸrOxC-;FoU5Y .br5E㆑Œw?WM_42`RcIa q= >K}v+P=Q|vx{m_=šlvrUm?\z%ds"d #d 4g@ssPi;SB&Jj-v)ɬH 燉qb[<눪,Ն_/|7>.982ˤ'<c4*2\UJ}=۩j|>8#Xls!R,6t~sO`} ޮ>V, p" #PcFWu&sS#JQtO m wQSa9b*\'''=I⛡wQF17.ا)]Z]urn|@hqԓx" @l$&< 9N6 u1R,oyTl$9(v~&:Mz69>' !4N YcҽJw&嵾=kyBR y|p&})y,I]kRP)DDM\62rO;Mݪٻ˶i)h]\&.ۡ _?ѫt7w% *2EUfImu:;BuI fx@#~ OvDא!r$b77!P;D^o,uFnP@ݺ~j#?o~anJݺ;HV.<(b'8] ņA>G#Ey6ޔ1J**ޕMLkbhM{EaǝNܺ,n9̀ r}j. I2x{vf+;sEd]eťs"3І9hl|>6jii:vZWs#'p-HYڏ9H;eHn0)EPjQN X+94{1[cP?=?]pw@QǍrn-թz0R[K|I \q5(O F1K0Ł$dDF 6jyAw}\ r!zG뱅T3aiXJꙧwƲ=MI&yJ$Sc2'@8L! h);$1ÔYFm3ܣ[ S(kPx4rt ~$O/@= 5`ΎlLZoMDJ ugߧ$3KÌMA Y#o2s4;Gc\jAȍSOGs< {?^Kfva9tοxh۞pAo?uGK!J-'^CٙzxM]wr>wy|D*). ىT. mmb5^1\Y?\[1g(RiQ=|ߕ~Nagn1}Y^>û>={ ^A~we(p~R,~O'g]0Bn`G=_^}׮se?оb4]PN//?AĿ| ]mG-2M _O Ң",W^zϺw^/~?}W|ϗ*B 7oCw yպ~Ϝ83iy_[C]ՆVPgo+ɖ"w>o6~7,c]K炀oڰ҅?*LI1?MkTJ|7]VީWnttM=ޛ~m"P9xyo}'QUmw_t^~}k2]NuQNIϡ6WD½iO߿|\:%*|ޯż湲, 4 ֝ݿ :o??ˏ˲n։F{uwa~}?IַR"?[{ |.ki~Z=RuJk6ho Y$ZcY!J~{&`Z<jOAоlo?1nE(~?asҿIE}}/ wn^򥊢o@{~/K/O(@\^82UB;u<\vݳ >25ͥ?gYeyC]o!2_aɮe>P|ZFUKy~ۺ?D~,T})^6۟^Z٦^x+⹵^ ٭[jMݳ胐ۇ{_?V!ZvU~%L#VΩ\~W>:+iZ.rq2C_xZ\yG/Xt)'9>#XjZ}YW+R|?w?Y`ŏWn)Cm,]U._ kxH a^HIW@lxӽWYc(pi̚\8__EFEpXVWMx<^$fN: eT] 2yЯ}ŷw/v BhCtݢa^iYE.{}+=%BͲk[p7 Ȝ{ ΋*zA_궊yT욻e<>,}ɕ?0?,tC#iϿ]jNw{3>oOtFKA?#ܣ73]"],]j߭]/}r0 g\ݛL |:|߁W s,J}Z?,_WoS)ȏ{79o֟8(?牟wOGX`ӡ$>xm~m޾T N~^\}k?/;F]z?|Ħ" 3.1,~=)g]i"> .?esA//ߌz1VnY>4_b\T5-pZif$e|(Ws=/YpBbY?_Jҵՙ4 Xj! HC[OQ~"~X߮-컏obOGC7oXiϿ/_ /|׿n~נ;&W'"=?,4цkSp +B^|l|@vb&:O4~C;iBoh|NsK|2|s4#,E]*cwU^ekW2'[1A>8u/\VeLdMi;v /x /uݗ7~Yɭ6d)Ƙ,R, xˆX`pWA`Bh$0|[~Coٽw#tWWWWWWUWWc3@9, ^H(Ό$c*-`D8OJ~`Qx<5cT Ca̩p0* )d|˳>lߓ &h#lV'x MNp?鴲\w'VfE %PMةEwN=1{|rѲ >w;WUߐHDI˭’ $28[jIq8/gdkc' T}n4P^JOFaxq*^pZn^H}8}o NN1DP-my fQoFc}FG~П ">+E$n_kd@ P Jg FIi#k:z|:L;[KGMnڋ/fU`W&>gt7!aΦ4 Ar¸\W PJ`*ך.ILq#-v '"k,r80ebX_W-JNFr>75zoR|C;9z4.P /'&^ )"@oJl]ZCj^"`:OMhHAo2E%c~B*z_[F$=E Leb0{O: %R9zq0Ld]ĸ0Nq"4,άpOiif-LhPt[`#U: [3NKρ-Й7_OFT83 43+ʘ~كcd#Z -_eER+)DQk+}B(Q#x+Itdak:+JrkP=E捬ƀa5P+⛥/ alZ ܸ fj5!L ^ v" ͍; |zLѷȤ3n:ЊcW ~٥Bm>e1i[d2PW8"prd/Úm!|@6!)_?FDBJ" ꥵ6/w4(dxpOd[άBv˴+!fQ4a`XU{Ja+[%wwSq$5$3Ȯa1qe62|zf84&`2ZhL yLٻ?EZ7Et &k)#фP WF:^/ @} PuLВg%ar{^ZMESW`*j8o* Ǔm&Rcxe%<8Va|f)*j9rq&-ZĿQ#GBu^KAr?hjE <б^58P&ND BhTxEǁ j&<ǰ_ѧ!#ysy]2Afœ 4ylS9 6]X:rsv* P^B>~FU"gQUb\P)(j>7˼8Bw<~2!lHAHF-j#@Ѫ$@KpMdJ+"H.JuDP5t"1Lш2R_1w@%6hUe-Jt ^^EGEMROh8ɹu]H:R su􋧓-m`kIXPð 1k_~"\*CDAm/km0)):ođƃq @ sVqH;H*b'\ь,)#;yGR-`4S{W"IQ2 d0@qp zi;Sأir$Y0df $tNh5Fvc &BYriF)^qDI)뢋m5Od(fQ--wBEh"| "w-LڳGaE1!Oz"2R1JЃYѻ FU`2+\Rm3T6k]$UUK$ih0VDgJupʱX0S/svϸ+T«Һ5L4V6yVDס%VIIyJne32.Vú '4?AV$Ĕ=B33BxH8FO@Mz5}zJJ腆F ױ*Ҕ8OopET>8jՇZ`lFS6Q!ՂciM)S3#K)a-\:'G WGg<[hnPߋ`.8c`%ϩH=0^vٲCOrCq6׬AeᤫTT"/33ᗆL?2!J-(1>Qol1pb"hfEn.7jm›*aiɡ'YY@WzX e!ʈ'0v&D]jTtǰ.ҷ "Q{q^JqdP鹫DMCCsH5QAB[zʺE0P4j gԋÀ˴ LxM$$+<#jDëSJB)%PFA:j))DRLQ: Xmвvx>Oe/Ah]"B}V+qԫ9Q{fwi Z; sa9'l>k9{?Gގ3Oz5XMs{wvJA`!; Is'QUUflZpuvR'Qp9hx,$^0;aW9כ|)dKH'jD,`Ncrs(SU!#4T &!YGS'& &@j!"j/h!Xݝ: ɛw%^5}{ Şk訽9~k;G/{:"%.ЏýK+mh loF«ݓ3x_:', ~;;=lQgă;;.`o' ::xK/'m|xt8W^uM"f| 0UozougU|w,^hu  PaDlpA߶ +$=-Sc(WZ1(dyvj}.a470/'8o_h=+k0s*&o5V^jɡ#܅黇I<)KtRH4txKT'V7}E>oGR7~Cl$;?3|Rx (?bwO5@d݂= ɥƓf__o~ iv~QD EXd?s|RPY(_Mi~rZ;ӧJP8CH Ca_!AÕC|l}B+&G_ry3yRX"g Rpޢi>f@l"4W6Y:L}t~icV[^in#p5RiiN#ՒI^^1rk2|@4WzC?+4toZ/B=em08AVX~P~.V)sJS_7\WZ΃Q.t~}Ն[o~?m2BzkA4;@xFiv{n߈4 |h*fN$` A.0x7gM=o}]ÇM$цA^xI;LFNei:Un͟n ļ5L 3$S|vey];[/b'cvٴI;@*P-Noa/FH1xIZ{)SF-UvA@^{6Db]|\2NRʋ`ƳR?aEʩ/j&[7M~] yBHO6T3qWJ%E)tr0 Nh}2<y<= ѱ3D\ v 9xR{;\1D UXA(%14e^EFܥ3I1&t}aP칢Pn L#f =sE SGш¶8-p?{\.Ei,t9r0FCIEXc з@\7BpOug xM%=UZ\ezSn L7h"6ij࿲P^`Lk nAF`7 AiҔДIU03w0K_ՑzTGϛ8xGG\+?!ͦ-*s*%S.J<$-Y-R7MF>j@&7  |̉/͙•{XCeS([{ehFʘg:+41:_8[}+GP DgMc8O$~GC"Gos5ᥱ52_(2YF㳼X?xW'V.%P!25.~ 9Ȓbd*#]H~]֝U h1m]^PV^hFoi0P-<|;qB",U]4`IkSE`_C~8'v__+ΜB+"&Kq~ۙ_4h Usww*FbDgشl62NhRC{OWYaG1SYhD56_YA##<SlK:\y0cL0p"tn^x( ^_&8)y1y cMT\u\ =Qv[eac74EMl@9OM5,׉5ƼFZ+rGkPO5o͗jneQ|F":̑[޶0g6i.U ]3;vzdE >(0mН$DHu@{z*$& ]\@eZRsq09nK>Z 9ZwDKv?ƸL:/z*+Q^To|ŭF*p$q`?:cSpKScG54mRtŞg&7Dd-j$'T5EsCDkjR6?lu15r`0Mܗz9|┙;R'-~yj<g*g6llxT[ZƝ,ٴl5P;+/ɂ3Z~ۀ*0aqkF 3cA•Ţ>z#kp̾K0caV| wW?+,2w`tCY.-òHzwY{?Wj>`YʴCuoP~bdoq^x]sENeʼnvFv'L^tg5ڸS|/1Rw&eLbDPQM2y|Ʀ5]b]fnT*XT#S ;ʂ m}|`Acڏ{G4k9-&4>Z6nZDCx"$ fҀޯ&'ܤ5s1wHgG' !*Szsf:|XAjVت ء}Jݧ_)ㄤ{m퉡]asbS{7;ncu6ύ-J.Ϸf(<{pu;RsIėhkȩ3׶ ˕ oњC٢ܷ,V9t]JY)DT2.)`h:3*k4Y3*RJrY˄sZ̔@ foD}x:S>F{Zrdzg \黙>G^}I`ゔXx;C~7oI5ڙOH~ccZtRkk}FSi~Iݭ qP@cm,z ө{hbgȸ07B,a֝199[3Wjs;\<= N4V*6*`*:#v)`gQPsBYFMZ-GY>V/i.M|8Յo h.p ș6 R>m^1y"i{\KX~B#,,yayz|35=+dӱawm:$o[kavI-mm椅(60nEd_som9G{Gyz^>{GJapg f08M18%?e|t_8ws|~S~ha:[k3{ ?~\ U催yb {NKA]O{ʗ)`ty~|'iP:,C5^e-Ufܟ.,ZEQ8 xV^j'&NӰI˯X#FW)H6RU &UoVs{-^;O~QV4-ZFZU3{L*O_ܟ>(9O?dѤ:Xhl״E N+!9'''jE̠S~>x$z-{OW,GSsJraʺ\d*pj0E7as&?H¾"CGҼ[I/B͐t$,@c ȟ(}_a9U&̻7MIg_92l!Adү28{!3uW+䛀ח[C: M-Gaqw>Lk$uN[ 6=Β}eRժ=sc3KfxkA5f.A xoV<QyϛOh~g8yՠۚ#2U+u=iESn(ӑ}5 >{٧ I* K$1]+BxKֈGU ^*D̮._| uL]rcՓgo//zlkQCI8{x ^c[/?;!ona/H_u 4aQ6'.}'G8B#4P9,I9i]la h^zV`%B upx`k@Yسq'r >g/A氂~ts3kvlWzkzOZU:7|x2#E*-@, =Z@/S)s)1:|r g_F`iu4Tl%r?;1ϕ2Դ1~^&^\)q C|f V\K<`)ޜ7r?uY7j~s,8+w0۝EYHU\Yٵ\C_6M#;x}/1e6wsR. ϪG3sV5cVqi6t+5<<']1VsҪ& *hw۵C7Ck*ճ'wCb{,q׿]#qiŽ hE8j~ÙT0s烠k!ñePǏ\W<]YyCi:uw0YTa1 jgկˑ Ir67',z $B1&Z_}[2b2ycai?)6 CL>V2^KZ,[8gagz^[|\3[w;%3ET[VQY7 UZ.c`C-ZK(ͨYVV9=}x4jF :22i>,%\ Na; C rjBKwUp,X:TͿPH]?cۄ 9C((%nnz<@+ЯB_Vo {xU Kqt$geT`ƮFtK3n(O龱 bS/uU 0Vf\IOuAv^Ga&Tڕ K$M<Ҹv;F0 )1)TM* PJv>]=R}L #P0=Yee7> Alo CX+ K:KILpqPAdHI $[^XKfefrUJb*@o:r1]5G$e);2,*aڈߙ7f+kquR ]APiɸl;efD՞ڢQy#ǹ,^of?% )zhsN% Gc3F5D^Dn*:Ǘa̍ӾP~Dj  KÀ4ʫWu#5}LE$){eR%˹hqS*}QF;m8i0򾠩\٫WA ( [K|fj YY4ǖ[A@fE^%^ ]~sJt<'h}v1'1 LwEw͋HxS]FxTjpT\K+27X(rΫhl w{^=TF3BGh\M"y7Us=u|o[JyI~Z|hM 5z~4{[k5>dtiֻ. W-v.V|OGk! @)՘P6%e;(itͽH+̪nw%? :8F)ֽ3CVy}ax Zw8R(lEB&o`G~KjQ{ O"{kBBLiFR02M(sK6 }(=}xonaه7TdLxl1kͅ\8Q \劽Pi-竱K]NRH.9ƏD &ejFgX0*gz{aJgߘm,75?9Ѝ~bhSt%#n%gL/g T =}#,TWr7_% fBm\{1y:_/oYD&֨)Gׯez8Шu{'o=5b[ߞTMoix[<=Kf?\3) ϔzLՑ&\đ Gb&kOͬW*:})ו8ޤ<>iJ R;##ʢNSd 'gH3Hӈ7u?+bv\5-`0rB#!KA L/" ^z-ǪPzTU?&{2#'onЯ=ˤK军/; '!^43qeMe;fKϲy9?^˙Ӹjk}jn W+]A{UuqP7{օ. d{K9E4E;V\XJ:@hϚyK 2xU+TZ rgSk6U 5nug tSr^MOv' ~&RBKDm4?/\26,#ZaF7m5ܭM3yY437 7pC7LrGb RΟ1FvaEbG%"~ڴZp౟vՇgv7gjXHul^`y_>lMqx+ќt86SmZ 44B[i2|hZפGĴQy,er?)gvj,عx;^b3yM(a;#%<a%z?۪V~y9AU򋮽:'ׁhuØzYѳ|t[YX0ziݽOij|%/Vd}c T6h8@= \Vo^SkBik&FqO?x~͔L631gZ"2Z!VX6aB)Sp r.^+TlZn8~fIQ؋SӋ^ izQt/l̰ 9s@aLܞ! F( ݇>|nQRwDwJPϥ ;Qĥ[2ΒPAJ3-{\v6eFfEF,ξΙwj]ks4A܏ǧxwajUN=b 01VPe5Yل蹫+]`}4?IE-BEbkSom6צ s/Uyd3/YS?kއ/| Sl.;<H:JQCGC2<'<*Vt> jAH"\:ӊP[ɭ.RJ~3'txъn!ǫ[3:[zYO-fZi~-ƲZhPaA- C0-9f/эv-3x_OM80KVh^Y~nhفZ. $0#$!F۞*KvwK2yks?ɥ~sluoeobٌ~'F|'>7A ~ڃ=sD_ &nJfA0wTvDh<+d/}~l=c֢m9eI^ #8ŀ3#džބ0S\CA]~э`">?at U-/<}.`Tz$g!>֗VS{c|ṯSF; >`b5fy|W*GP)o[2" S3>c$(ӤFOiDN#{Q3M>MF"$p).WScf ,mȑٳzvxʏ`/H';HgP#Nub#8}?ә*ߖ)zCÇ6.#J,ѵl`K/aX#/ڛ^~L|BY8h]i_䶓(*`eXDRiZT[[C?*Mpr$,,Y7 5E@ȏ%l2>)$㿤Բe]d$):??TΘ tg#Ľ gC,f3\q!~tlM =޺+3S:YQ=y~hJ ;s4l% hXR'?kV&0TC'$۸?niɳjNC1A4u.4PLl _}<u1"*vdݎ=R +F_n.Tբk˼Jxd`Q8^^>y0S"6E$FRM+w 憓RKMy0G":^h!snGAp)tr3 -I^1-OS!A5/;;G'G.Iv*ꃔ:{8q4M"} 9̲٧O̽)E_1B$$\N.P%(ôX'z LN^P$(AzaG;޵8:j JJJa E j3c̠5 nsR;8t^zѫNGJ4"3VR[O8'dC7, ZV}F7h[ S։k(kZ#AġBǔxDİ 4NE$܌վT )ԥe}h?AFC\)$(+vFO{FX֮*ħҵv i(ՖZpcӨ%ͤA؅J۲{6e3Ou-ݛX#n9;z;u#ö`|i P߲,$!(7$s6鴣]H\ۂڭmjz%!q6QΩh=pһDһFFU&[\⩑6n2v5Ur4D=='sF LS|ÍwlV8\I_ 0S/%q"xtPT:2.1 L5:>QɇۭDGʍA>D! Ѭ{ OAzYns'7[v~f74` T8sekvb>uzc^pl5yStWR{ gapij&u*EK*^I^"K 򥪲m tds K49_+4#_^T<2IDmH;*2*nFdݼp#?[r'>EY4wk@\Z˄g.43I$g9 .)kB"%EkmǛw0-/hu,8$bq%R;4Iê7bJɚQI.42eR랭${qL7T/k@ PՋZHrPPg9"Kg4[z3(!P\tvA xrIGKT)oD|C8L#m-=;q?^@Qm4h7L0a>7y,j^{4 ъQ‰bF̹YByhe䩢2s]^}t n@(*ײD*WkOqGhhL E !$GLC'gwݲ*YO u;4f;ܤ#S8yAh1 B7xPOnJP-RcHM Esl/d8i#;o42(s<ܹ*K<=q}b+~ϫpaV_ OܔfXy]; UoARs|{sk;wLd24'iTlYӱnGjmoco+i[-ZٴOBu|8)iN#`!ˁ|B4Riu<&n(kKW-frދAZ~NIplʐ[(l?&*[Zt88SNnW.Pr>Sevdf7jo"S2Top[k->;ÉcǡD!7Mp.;S>q^xm[Og`j S8vܧ"N Y`*Ò33U'Ҵe8o82őj;Kmޝ)/PLKs0"9w sgZfn͸FNs.];_ lVngn%žtLAj҂AʬV/+H}qJ ʘM%RN1ݝ_B-q*tVXz鎷y%o \Ԗ^osAK1ğZLRFag`~M@ٛOXoϼ)23$#+dJw-'t67Đ5ٽ'Uw:u-GAwS8+:VETEd@j%F/:oy8dKydZI^*ힳr~j ќT-hj(IyNĭuG:lWy،Q<_xJL&q)7W1 x)eͻ'+v˲P8>1&~k*Grܗ Q7Gc3lzZzK̷jj9/8)@VLsQ$3ӴG߽VLD W:Dž8@)0L4ߞ'X@gBeI@L(}oQ[)gug쥻JҢ@{)"8!ӨpՎdeX_{zXۃ8? ;瘋P~^uS6Q-oX,d=vP}vitCj؃pSѨ!v^{ *:izoG$D=~nw~&O5Ac]`DOf.'ϵI37iS:\UvN^xN|('ֽq!h:0N:'I x(O-(x8qxM'C~rZ;SP w&FkRN.a5 mexl乸 I jx5l{̀%^AE< c0z w{3F !{\$O `] ͵Je{8!S>:hŤi6 ᾞ4]}l~9p/t]\L&u= A=/f*/&><Q؋@L3#jA/8z0=:][l`5R,ʰf4+ ݕ'OS23?w5Zg#HiiC5ttO#kOanjjIEfR[W"T FmZv])/4[59:|>z/wwGJ -it@?RjueQ58o}5|u4轌{rK–jλ6|DI}pfe.0Dlf v.+5* ÊUn3t$)kǽّ5𓯥0_ X8 <49QL\m|(sgeg)FYB+E~ i-l/s9lDftXҮ&n}:ߪ7$r0>ϤӛJ :] IZ3I}*Nρ#޴x( |d{N8Ku̲SYj?!ͳ٬{6~e.M&>'ޟDQi ^ha굏GhwΗTܸLΣbfn{}̛HNl :PȠV<ArR,Y;VB4 RI'f牢A+9\G șj$)h;yspG4NK]SKPuE'1(0M(P㠠v0U._׋q4 `ߦk{ &{>C"wd;S}tYx۰׃qJQ8}.yJ쇓7''o9HꪇZԿW5_YW>o/c&` x2;;7%NxV-_:GǠpbMVqԛwȿ>+0h&`3>? u=NR M aLhj8} WS*/Upy*wϴ'Vo i=^g|O>D6>Y^cyC ԏUopHit2#&b|!짏s-n +eY9z"ĬxP-^ y uHC4RF6h: ' q8a #]{-lcΧDniG?$2M {pZA[0@܏>p0\)nF#YTãV$$ŠMt T"v~lWHȡiz閤HF$e=譞Jk6$q {L ^kuŬ&_#U4ԧ]P+\PQ0|4|CspԎLyP)ZG.ozc^ ϔZ;/rD"@i}J0C/mW2!GYײ:De,]zl*q4 o)2wDZI3Ҕ_FJt^,A쬼煪[b7v][íC|vl梖VwB\~HZ P,[#rBCFi-:E{i 0#G_㙽[J-R#=kfy*uZ}i]L6 hAK/[OԗItBʾC Ut7 S'r|)r5W9E˧JD$e2IyqHaPwE"mU) #Xlk/s3TI 0@^ Af}0.*Q]P hx9wDzP{MkIwil9PsAMqtqtnw2#W,\{)``::!)7<7\+f9Dge42j>޴+däe)خ5HMn p1fXbf H`ɔ+4huujm2hlq'X^VIq*9 zdzzD7Hg ØJ%Us=J[1%Ҭ۔8c6~yI烔 _qOZE(^r|+6ޫf ev̩E]@Nz9rQ$` $("7l ow`Wʒ!6Xި3-*V=gl0“p^gWw4DzXlXx:ϜzC ,5/(kIx@Uŏt.i}r' IJU1s8+ £&e)[}H,`LΆȈl)] XqM]lbU~70o#M=Iã\!X6,zoh3ּܻůk_+`cSAo?_覹q'NTMIۆb85KcH˘J8RHje'UUYbs<q/>XT8\ggB:&pC}{;vVsxf]\<,f`Am!l LV$TZ7kPt^(8E{ɍ$:fWXgZ3HYa˒T* 6['JRuKPqi$ Q" Y몧f(dtE 5s8_!~ ?1k? JhAN5т`on`|/_BSԪ\Cvkxy ̮bbnpx^N<.Z89.'h˼ H&WpVmӫQ~ʬ#ҫmpJeVyRD S}scceײ$:|ZH RklScmė*DP-ͮ, "gCA2DbR":!#&!0g8 ~2_#:0Q`.nDAH -?YcO8|fs@Ŋl-t$Rg z Z˴/Z6;V+1u,rY5_eQZVJDY`; s' `*] ANCNh5'w"Coi^Ճšm4]AEg6s@eddC"uX݆pO 7'138`iLQQPӛo`i8QYeh#-̣4Zbt3b3c ,8h("@Kجa|z03::M6w0ϳ=3=Y[ےX͝}P惲I꽴`[^64q>x_-JxnnUL&(_QBVcEV") X/l8 Ǿf)os[uoc J>ޛ6A6һW dS*e>DR΅|zcCS:$MD`T֘Ru9~}UH-%5v;}kvw:7&ה^s>n.*ך K=w3w塗Z4k"ۿe.(8T{)T 6p<9hU6bi5d^uISv;/]<>>9jB?1=Rgv?ee?_㓓eRS@4g_*Jl.s>o>QSޢYՑ+YXmP5a QuJ8mxOߜk1yo(&'Lo,+>H[Lj[A UZ^ulBN)M5U1ȇ1\`ǜ6Y 3&c\bV.8P;Ԑq@ 䈴ONhɣpkRshcf"햠%UiWMMf_ȿoRfތ@1"'q$ Sc?n'%}wp|T؜qx uoum.L$\ilwķ`K( 7G'OMP#w G}-!:uuHE^V~yuEZ3v aoV,L^I$; KΤZܳ?V< a0NbJdmPl/oşݗCfk1pdeϽv w ?A<~]={ APzTzkoGZrvrwpECa|\˥*B z )Pg^QEWjr0A,ǒձP0.=sh=Gm_ģ#̳Z]_wa]|koޯoϴ^&SC R2wsjwvO~C_wWG^ۣK'wwGg!"&%gSCmnvex !9mO,buJs뺡n0dB+g V x.ٲOHFzDx eVak]^9+yizGxg7vVRS;FL򪷺,7=/Rזקxi_M bx=S_i29KU.UaӣlkLY=04ioEBjB/p.'7;: ?9n-AȪ`̋qxYozyU.EuMU4N3{o7,U=Lۧ9EAc9'vA , ٕRqW'!iUh``x9WYgO@V'ML fdֺ$ ?O`gܡ=q2§?$ӳ(嘕2܂Ug8?>A&F̓fɊaUZox0! dbyzyKzA_N<Ś n|v .TAަQ0셙AB7ufL'0 ir&<6'LcF*ht׳'4_e^m4W9hW9mW9m4?7W^Ɠe&]ͻX4#͒Js(:f0Z%vo5J"UHrq{j(G/&! )#xH@5yu9G{C1GYOsȳldt}NYr}:@EūUJq㛖 *LZY}MkWh cLJz7w %(ر_d.@g=<j.V /Խ_8܎]ʧC,R-G(g1cنÕS8$O6_Ԡzaŝ.y Q¹BDN&5 6LCaOTaIͨpb/bH oj+gv[х>_" L OpzؓUՇU nZ3Bxbt CZM†M%z@09g`pܶ>4L%pGzChfP܇-476㰶=l1J~E rׂZoۂ; 7U ZXtnm$ˢ_ ΋$"R53mZ3sH 4Eqʼn;mO+ 祮 ZCUYUYYYYYyIeZBnʴˏ*+O T_jאuz7ake^ {߾GS[ɽRrfrc{6r\ܻQ۝ͱ@27VSth 4nB-0̩c`K>zDhV 0-;K KjŗXJkp۷zyH0K5o%w>Gs[6:k:tZRmZ TKKukܞ/="Nt_ZbΗlai*<84̗p䥴}ziŖ}:4sVo w*> ,K[x4 fzI$/Uηx-}K˵i+δerݖ54"r72&>WQM,>c?/Ogrj̘,?'ʣf BJNsh>48.ga7jiL &,&>㨲2/\+66Wj3VM|xdӬRexj_5bW3՚ӥشVYcq];]14l)X}LN^u$qg-'Մ#uW-4-ͭY 9>wk۱EŻK Y0OGma`ޢ|V{>3{Kf(j8zEU( ܭC{`f6B,O%>)o^ۖ78uj1-is7ucY.ovWv[ 1~q-ĵkrUn] w~IƆ-#4ȯm}e6?~wGy' nQt*߿[fc:ݩ.7$1*~eAh淨 CF׵E|5gn1/ސB7eD?b nn\fCnhWѬ&":wuUNky#!b,oJ/uEnzTi kiyN+f&-b 5f0!A71lz"䵒&_yWʠD?)wBR!GoHuQ,ՋxԢǗGUMI`ʺgý{~B"-;Kj j,"uZ14;~rs,HE% LFMrFaEqD(KkоUEv&Vӫs]0㔺LRWɸ"W}Y1kM5]wIH5@ѻʼni7+cEJ"qhZ0)OTMAcP#8bګ?~\Mcr+iPJƆ}>*N! m-Jغ JEJqd9(=)~b)Jܴ[}ݺD9}ԥOAQDKc)r7p?JN&!c;KۢI ɵ 1Q~,Y{E!&^`e)-,CXӡ[#hֶs'OD30{rxbPe- NاSo-e!5Lnh6ap?iUaFjd]`[LAu䊷Y V Cd*>w~l›3R_tKTI(,^Tflp o*F'ۥ$Oi51\"# zS.-ipvnmSgΓ[4P$. nb'STiE?{y=LIj 8Ι>O)IA,"a !lח#o`ա9F~Q3LG@FFPYkB7) QuDOg) vԷtp¾\\cʷ1Cڎ<jZ;M%/qG.6 ֛xb< *<&t2P)hvksmڡ63 76ʔ$Bfӂgf6 T/o\*"3T/tj*p\ӦYl>NX6 oK>/ΧR*P",Cow˷oF+gQvy_OlZhX}g0"/F* Q8v9-Uz6EԸsXwsTwPjLgK jUa~5զ0}ǽ7DgWY)Rz ѵer6K;n=1rdrw %ETMx6:|&rܺem˵IȽSVl\#ŽK[SsNf؝8"x $l}_r-h 2?=B/BL1D`R"YĕNM.Եzc1YOa:t[I4!(w48cYV[At=-0&.;QJw7]yّi!"z=eѨryY'o<\Ew*+4sO㢰l.i٤1MRa^-tfa?e~LU wя8}A]g3Vk'"z#}N-CNYs|b^ɢ(O h'P+KK&W.3kP#195_z0\:Q5ճb\DHѨhDf;kmb>nIOqX8{R㦘~"z}DFQbA(4ed)/} ^鯼3{׹:auZTճ^)5I 5,/Wͦz}B0.?bxP(T׏n?b(%f@"r6<~7ԆUJ[ Hu/"͂|ZkT"~{–E ݳd} W/Hń(p\;ʼn3Ȟ03`:)l^nv1aQ yޕ: fSM1SrWЍɜvs~Н 88dg= ]ʟo$ӤOb ΩW0G`0Gڬm1t_(8mHw9IO\qxglNR0hly#8J́,( ݃ID|Ұ,?<9RawIkv3( d@Kg4,z/:iE"/3|ÚhgVa33c9XJ 2yWS ^oz 9HyRpo@@aÞ@[54&RѤ}aL 4>4SΝy_%5ČDbFՀy3Ha #z7Z ֛VhƘI2tU$P!KQ %)Aڥ VKH{AN,_ޔ+뭉4Ó>N{t'̀6#]ȵ2_n~:Y<9 `l4+^6*Z><)p“V\,檺BP[ &J40GxTT'v#JPypQm0.CABBX6ʊN賥R/ DÌDssM'~EJE!re^ɷoޡvB}QuHLEdQP7xY-"QNd1kzN8ʆib&?'MǦ' :MO7%՚l†>^c/[ϘV -*b6ٹiEiٔL(fE`/ZHVi0FXFXKx?xk:KkI^nVPUٺ7GփF CV*ǗP7PlTt7ly ٠5D1m丑qMHd:GN!䴼?֬"|1lf[u+}y+xbEåel6a7!3"Qƽ⾞Y*Q9vKUs/{oP^J-?RN8[8Xk^DMjYVZ>Pv~1_i-fYgUO%j./,DO X6`$^q7H+Kt7K4@:Jhׅg ! n2\43 [j*hZ9.}ga _{idY~؏[>ѩА$\DEԚD;${},i+Wuд.W,M` Ө.DX7-v/>|gz8݀ tLۂKKJnG>yA<5OA 'T7=gȍb/w6'z WIxRZ^hWĵ׳xnu4TP/f8::k6t ?)ʱ Trol.#K v`Ak$z[uJ઺K[NxV,mZF! a!0 ;CG1.f=짖-^9;@OVЇME?f%0ZÞͭ\R_g*LOM!X7^(n#?Zmo$t;$ 뀔:d°N0.Cπ8e8NiAyX-;0|]T#"EVR*hhz1RUw"tP=+SBh\wְ\e-u.G< 7?4b#\)÷sdHu_6K@xM88Ab*_m0 J&=651j6+t/t@0Yd߽Lԇ/CN^u|8qCA Ж^x#ms?qj!9|i\CVڸ/ 㑗Zmh%$>#tg)r_ns#j6wȎƌoq3ZYb=w}FfQ*8+ϗeEf) 025 r>շh 8SMl !tYПp("eX:3 )2>%str0";fc1 A0V22Kd2?{S4x#{rwaWDylnvw ԉexuYmf2" YFhe`, ݮP'qZ~A$ thOD*bG#mZPťINmI<{BSP4df(PF !ہ“ :y_W0"_5^ⷡ1MFk".+`hzí|"l|'6>3A Tft .!-rv8zͽ.^H%O L'r=S/"9 uv@ Eg5J8]gvsz.уB%/DCw GT?  3_ Catd@| Y@ܻ] d[Cj ":4A-HH;KpoNS# GXfi2Dgup=B<1#-@]<$f lБ 1VRʰw=,qQ9 _ioSe21+9S&1{7s##w)P5)o轉sas\P5)1p> Tт= KIuHW_AJO";*h/&d ,&/ U}N(o\GBHWG)ʇ0hq|P:+|s2Fm++Kw{|τb3`u' ɨW旛%of^9LeX- EmSgQhg˻5Hۓ?Qg {pJDuf8d(+/8!FbB#fWۿ43xjuEGu~Br;LkysNw.Jgt-E*2bxWj1O%f[S7=Yjc%./Lk3z˨oÖW KIGMEkKg`32Ʋn 2}߯Rv"k㥇(FMF[b۟R>H?*˘qAƊGt /L:"o8T`³+6hz %䨰>a9^#fCz~Mw^+mڀF' $MSϮ5.q8:YO wỒr608O^i@ Ry*%- i(V2MrRk'y =$Zv2@ ,͚gY\)$ 7 ۢ*wfY[- `WhFMzYO}{DOV6.p'oo1<~@/oߍl&7^pFN@.qQy|)C+ $1 E:`3z ~^ {|wr Y."̜X`*:!Xo:WLih%iՏ=(oYs!.-h$쭫ۤz9!p4oHU$O.ocvf0F,sɡDW^8)t'#7$-=pd\^ H>RۢZb8фą{*3^%o1Pjb(~#О$` b!c3܀PfyKv`y stMįvQ4tvD70Ug<.6/ "2%C>R|WqT$Hs` J iIlħa)VD "VŐ ^ʇFa\@QLIbjJ^bF*G` ^)(#qPJq2e{| _ݬy'݇Fa<(c[^ta €͑v?OF20Cvɳ$^C7D:YFgZ';fwq,_ $yדe5 6 Eq -U='Ֆʉ8n|";cs.r m5ʒ a"Yٚ CgmۻMޡFsOQVjPZe'c'(fhn% .0TfxU*ڐyzGo=vwɘV n)%*{.8$Pltb Jp`4n@'b?Y&䋠2`P>4[%e۸Dc$߄}edRUfL;8&] qyK5a}4x#c=XRv*z ($tXO1Upum.q<}fk=Ck3Hşr!p y!ʆ˜#, ;CVk N HK\["YfA$>Sv9<4#ۤD؍bzc=vm,2<9H5 3fY5Cf^4V1lk-,e1Saf$[c$ݐ_$3m+)1^Ys0T˩QYj#RYy(L$YK5,!8+:U[ p19TYg /|꾠 <{\yƙːJ#9 XUYskU{}ԏ oRmax@#-~*?APok%_^/Ԗ?J;'!4Q4yv:sYWL ëHB$r#Q(DW(B("la#7hbLehC^#u剐IarH h~ )gĕ.dV q1.ݮo0/}8Doa /u"8:QAףgtoiKbeNC#pgEŴdMƘs|4D!Kp]=oUk(:N gOlH5nA _G[w8 g@yZKcT_[":h`L?( 4;z{uã&N;_MxQo۠M=c' ^["#)2Ə6j8R\Q03f;;}Щ _ &?ڢUAHGP^6z(uHFz}67GOɽbAdf3O1n:+|A߭VL|/Q /,>).,vWӤ_S/Ij[h:DZJBcF[e| >)VE4tE䟅i"l:w[SB'LMI39;Exfjddqt;L1TXmyoHEr`z*4iӳF*-v Q[D /nİUB C\p-Ox;H$(3OkҔLEkj\IWv6L5'qzi l a(\4% %ǁq^{opV$Qa{$..RHhJMnbOJu:TN8&Z ﷾8pu5&-W4!|PVe_;J(g>|O&_ex}GKk×{d(h/G϶_k؛W{{/ZODcJI Sfgʓ䞏Dl<+i -IUiuhP4~YsL`ȼAB@;a>l_pD~dWmIuN-/Q+}nZ36VcU1SD",hq"ǚXPo0/gky5wNT 0qCyw7o"uز`ҧan0hi[qI kiɶi~7ZiH4xO5\-2-x@KHnQvT`7U w(>K7؆9:C V-J @fp7qx8[r&^8̨4q!@cscud" 2DII2MXd)<;$. %KwNSpJEoً~#ǹ,xs"(΄-ƃÖ-6/ae`Z4rZ"W6=-F 'CM&oP9eNt_SEcF>2 $v2RKjo{!/m |j֌>(_!0N})~-ͫ__!/ڣGޣ^$p\3@Kt0nT6T1SQs_̢MjsL饪5%tG (a/K)~:궗76K# :v5xT ^={=ʣ5+5vp1t> /Le^n;moa(ez<8/l6GW:|j {k62&؆r#NZU9sQr8,=|yggW(:1=۽|:);T>qhI$$Զr稻`ʰ^s &双hqjංrTC)%gb0NKIN Ɣu "qxPE^UqI>3u=7^delVKc յ/Tmz8xfwҝǏ2\ҙO]ɀ~Ui0:Q$i*lɥt@at8Eh`02 N=e`$) . NG>ɤʜ}a:~GCca-yw*(Y*@ެB1 #]SY( 26fo{cTTȧmj͎pH`}FAwՔ53I25[QOiH߱勚h"í JT$1TZNIۆeq`1tS7Ɍoy|3G1{Q@n39Z]E좌į#A|F4I]NJ-ފrXrϘ3ɱN c ;!^3Kb}TԀQhq{C 1B"L-*'BtRNVnOxs '\aF}6;l[2hF#ZP\Yt$ʡ#sn$Ry:M1M(1c2!\*Y e}}h`z)[ewⅉHSYv\u#G+q1 -M aZ>'%f('q2-=؋"QO邓DidJvڰ"Trv@ri]b`a^)Emz=HR(A+$OyTQ`#S.4s? '@_VI ?I޶^K|RP/ A}Ocԋ'c A?Kwmů}g{7U5X3CTP} /g##&“2nKɢ!ʕJI7 ~6;矆]i vT kOF SJݦe d^ :ģ"):&"0]jg(-ߋ }GuQy:׺7"Bw>G Ѐ "Ѳe!?`a$*Jg&j;VƅOD qIsǍqdD#U{ =8"|s͜'0KT%cxV;%#T^!7i6^4b|@ݢ7)BjV0 BS-'*)Z0`)?BUƳo__{wiC!x(Pn$iX88 ۀHNtf0jMzl|n=PELBGת|f6k*};ݞ2$U b٭(8@2Hve+ЭI>_Al`YL2Nxx4ū)s!_S!̓ u~#]WmƠ"!3W.tI;#ѫ紨45S#G k,Ԕ!E@eL %Q+,ԫRqpɉqf&ݮA;_.?[DAg[?m<|x|j aL׈Q+8 ]J)CmA8' 2 ZmYn%UT\zP`CayCտksFQE˛-ͨK(OT!ل ?.k3iwNɃWGAw_ߦ`3]dFxa\mqFmP>`{m68ư`D"L>lZUi6[8\Crɿ':;YDDQ iB:l%"N"ɒ%ŹH?vq~ h{c 㭽W;i5tսKGHI Bv@6C46$!H>>9)aVU,&,Z2oN!@S WĹgXcnFF&}5OdT*7odngIuA'7 O<쯄E()WGsfYRcknglBC޺%ՌĬxu^LAFZhwZzK7*3|{6,;%LQ7T 'Z*&Sʝ!Pzu{?lѼ+1Uj9 UK7XvΎL@:OIQOfo$"G̽{l*evlG+ ܰ]H/MlϘDR#r>H}J5;$EU씾j셧UK?xrGL!8,8T{}*t.][ttjBcTJdZuaiL6xY@-(NY̧x[u<mT UjNš5!Шbo^M 4g v?_ssu9NTU_9,?:I_QA"`;kgX&n 5*kʖVGdӃm>n`ݗkH۸=D̯+^~(PB=F~^& N3t-p4fhöJe+\o%k*pJyؖm܋)~x̷r9ym=UAtGѮh@AAvY:S21Ȅ%UNs~ʩ6T1Ci״\д9%:%@@ M R.!>G3`cCK"[+&c)R`ƒrX+YʕP2yY*CgP,g7|DydP*f p5tbv:8 !lН2ed!# zȵJHB|}zlOg'H^qIlD UqhEp8 `LWɨG!Y+{H'vT6T WTwkJ(7"@37/ }[*U\BjPo)SWZ65\!y`lc2\ 8\qq*qj!qw;$w<&gbԠfk| -{ީw\mY޾PL9{ Pw[HD5jϏ9/cM` = f"ֈE0[z'!F2;S㘢ȫ@g]T&AX9מ@;3: ,m 0 MU7N:2zyQn]\]Ԁ%Ipi,XTޖ`B_;Dql`3qX$p{DIG:j )|y͍:s(ƀf&DFȱv֞exW!uN>1ӻbӡ5VǰJ.t** 1y@椨YW|Fx +r7V(L vfAk9O-룯OUkd(B }`#sU9Tk82ќRSiLRnJ6OG3Ě{z߾w# w1fkv!W>oVXY,HY9 O3NЇfWtmO]SF~KY;X;eb+|L̻?Sog>g5w߿M@zgA jWo6\K#Gdqo?ﵤR|ݒ?.W?+ww8+^iGSⓒ>ժY>)i7U%y]]J=YgW[b$Ơ";+ /0`_dgP!L@^OŜ~XO 8)nDt338BI~q{T[= *;`0}^Ƅx-}*! NJTzl"@m9@RRs[8e1%pIM&'y4gei\&>)|@;>7ԡ,1rf"2Q-Lȶ/LԄSéT[NwH;.cR̷#/W'\pDTdwH7dfJԄ;rI'  K/|ꌸ΋^SE5_LI-֏_zm>Hy|k0X-Y^\c|я:a$_<>Ta~/~F-k.ϲv 7h5bA!:9I2-/\g1@ bAT{vHGu1[!=^D6X ]g)Mz,,ԛnOP]Epލ# ªɨ+,ɰ貏M1W#q2 l$`4;O)MTv^T u##tz#gOpYM$Go<DZ_f;њ 8ˊg-Mm"hѷgvtC59rN8i''҉B-K^gQZ$ɳ =!'| 3sɱ#h3n nx8;Ts8הPveX' Dc4N#i OhĨT};c%PClzU-*`pzHz2d3pIS {+~ N#]2AZVBI~jCJ FVdz"$ٗT9˜O!;~T2/^titNVH&尛-7$)xF֏bRۏ!3hgvt3rR@[L_b]ZKt Ð|A=] %ka`RYnPtr>SM( ="m$3$issEwx60d&=7j5ox&ٕJ2 Y@Ξ+ϑ~iLB kz0}39`TKt%C@7zމ~^VW=h?7 '"!:%1Ű E;;k(43:y`E ^8 `|/*Ly_tBH,:0ʷ߼{xpۗgH:ޕ8Fs,y{oH|ER\eqN 3Wwq$E"%">yS8ʕJ&L.@43W#>J ?7Ax|C=2XdL mGFU7WáS2 nr\B$:BD_S/Iΐ]Ԗ}Cz\ ?AZFW'%K.ZYЇNvJrksu+Rvk[O' FU]2ȶnBĜl'Ow*g-VUPYRLnɽxFDEgp6QeVqC_GF XFuj%u'A뙑/-,FB쑶=9@ ǩH5T ɼY32d$2:Ѓ\Eb3ުC1r1qI'b|,ԋ[N{:YM{ M# E<5TvyezCeA7^Y${N{d)L+-/u-脃.;nV$w4R|W)+WDG~6tZ/L> gC=4 & M4^bhu`qܖMW|r3_~ZEqz`J-,x+rO2sTi5xTnضkZS/kϫ+?yGsnsk4QM=e}BҀz,ЇUKNvC>St^99=|40Gs‹|{RGɟp5n{šv|wo?KˉKw?Z/ ^!7+ }tdKv8PӑjQ!E'">=8K&?,5g0w(y1_K]>mG|ڮo՗Ҹ[C4P$E꼫-*+ujٹ&Sc#BQzoy{6B.X\ ADuuX,QNniLv \@a?( @8ʵN(7,JEd*Ճ ^Qzf,-=/-ErCg{20tfS,CfI4((.p򕮪KO(i+@xhқ5]xKE%"7S̫.ϳ)b}ϖrكC +{Џ,[u)Vg%HpŹ]-J$BpV"BN=4bJ+ދ SlpгhȺxR3rW|,Xc6M#K g4 c2<܄K_A4/x C( 4X@hL޻5e=11|9o%p#BBc[\l.ץ$RٖLɘr/f^LL/0?emR) |({}嘅<|L;h"C zrlp/I=4ɉqlQNqo x#5E/ԡ8~&x z_҈ApOP:g.f (-5pmǨ@`'_6oI;ENVg6.L̇2 ېhSɫky *}LSba=Y#Wd"!ЬFwwtc|ΐW=:@Uvsu6EpTZ[>:!1EF NCn0X87oB֙ C^52x*0 (<9Z)DkwF%ʹav{e,P$s.Wh +0/9vy9^RT0 \ kf<_Ik(\`Fg\!踲9#-YftichpT) a4@# EZ*&rxWEk ǭq #:'֟K/(sʽԠAu fXchGbĩ AܳKi BAQ|^<(}]Z2 餎bjO4!2:=RA g}MZZ߻&W+@Vf ֶ^(H0u,Ph 0Tj DXAPCz!98G_f{E5Ep}oj,V\Sm*ۮyU=Uˎ_7Pﴃ׌5#F>'@&05F?Ӱ!?wOӳ>F(޾O3>ڨVm~|A#U^oz=|Q[o7dAÝI##oaoվ\_/&Ɋ.ϓ,O$WO~|zt| ]IOSQ}ZpSSgL?xB47vB6eFRC1+YP=|T-k3v7C"n rTRP[ŦhGd"`L:\`$4AUO6Mf^Bͅ eA} ޝaT-'HSNuY ^9=lbRQ|TLh9PC@2u8ܙҽP7aޡlذʠK+\]߄GhU-h:<%Dݹ`6KAewnʹ>c^hִlH*'XNXswX<` k&;@MGSz5pnp)EjRNӁ6)@*ԫ$[۽bEMe^Jzl{N*J4%A7g~ Tg#A6͠"yUye} 5Nآ d_E;ƛ ?3_tZESEIv3ӊ3zY4Jjh`;ҳz͓5#o| 3ϐTfԴ)[I Fiil~:5 9{baL.)ZD4BBYЫVFzَw~Lz%^`/GQ9ffU*6HW#t=T<{FfbBqyIuT]NqWL\a8l%g>wFip .T@apxDwGjSv ѢO?6qtwTMmK8Q>q# j_1X>R?!P= j}%dOm_~F->EJW~c}1g>S/sŴR&J88# ԓbcRhL3㣃CZ=??`HVŷiܩ*Fh HݺTJ`H0P=h*U`]KXSpba8*(oJqOiX׉?7(@coNĪh}a"=fZ+Rw6X`6I`ʁƴDf=JIhm = U^nIዙ2%|(-L8 GdD%BWXsN;޻c8)&WԾ9HR~R_#s2tׁ4!sLZf )*[G`}m-)@}Q Qfy|C՗Akw)a7T aESƤqY_= Y\PFf>a7H?6*.qFq =JC&'X]INNYv+.82&s)^䕪\ 豌FBLGSq7G/qΊ)!7iK٢խ_WB)%j.^+r7lk =}ƽG;4/Ṋ QtW Dov_?89&& (|8]\R qdMc:ô ScS9sƆIQjd5 :iXňsߙ?jnlnnoyfVA/<+qKʂpI; 7Z"d6kp'PV%EzV,7kz=,hL`@`XxǍ=cpEDrCM"Yzh, ^R:3moԓFBģy ǎwT* Λ:&]N.Gޢϖ,:"X.(͞'qpq(t^a?A㢈4pdfpKݟ$!PG[G0)#T/DW}[Seٟ}s3oJ~~)5F{R9)%ws+"(m]Ljj_QǞyc C :yu8DHq20QT.JzyR^@ɭ?BUBw [aSXQA")HϏPҝ 8|t8Cwlj"ZN}MV"ݳJ4AVLF}tx,7 pPxz˝7~L.Z/?}xؾ{o/?ۯ;޵߽pUǏvOz£۠U)7~Gɇ_;? ѯ;o.ݿxai@ADS4Zdb蘡Cr1&~ZQ;Q0͓# ڶATJ*j I6p!IYlB) ՉtɺƳB@f߯0~A\z<JZDcHte":᝟lrsg6j ?b4VeOE] a+3V[VKºMՍߛgWU+wЍo?!៦7k MK\ߏji^_||L?X\WA 5U^_DkUG7Vtk9fnN(o-؏%,Mn.);lH{?P[jdd>NV1^4N>_^|bg.P `;D"znlT(E@w d%8Rvխ9~(h];\2g̋nV6FH*įJluK؝lz+q[NC.noqkqGüח-M>G@ U[; NQ0/Ծ?%629рpqJ Q qCO#;3"8KmgQW$U<(xXTluV%*H?PX/<L4`ԴR] L *<}FOqV8|YgaHg**_|&\!|cʻyA5ыe^.8V&S.C5k(0b*+bCJy D@3f,h8xW,< 6Ps83&n:Jݢ'%%glUTqs9ʹ3E̴4٫L4}=F4r/-,7oq" Pv;| *Sq_~^]; I/A Z7bpREt\U´pwq0wA*Jc<ыm Ptid]bwBvw/6~k=2>*ƒ"G=PI=XT~XX?pѝ?BV֠H<GRtr>+ RNeA|؍橤 &9^4Rpt(!T5&rW+t͢-o`E53xNͿ nj޸\9}gkldGFvla0ET U-K%YƔ܌el8 be.6c 27jT .5O9=WV5QFC?N{+cHǥoqOӔ7`}$+ +`_e..6lW/8W@&犜}U_X|`7QzTVo0NBT˸d'v`^Mv;q *Q,J j db,)obۮu C`k삆jEp8Z7^Y Mqƈq9X&R-E%UYq!OfL|fD,Wn}!D)x"T^T+C_ζhI{ka \b$Kc6EB8Gik[eE):WM,=^Z & knZ)Gˑ5d3-z3*u_Va` ng/zΚK#YsFEH 4gZ gs~+ΒL)G7MCBRGw`d(]Po!l9M(N[0Vh2)r:Fk,__N7A'mhx^ΏV!,9G ث[#L hl> +!' ϻʋ,z^hk5ľR2WIȭ](ur[b]yewf@sPG`qdPIpћbx;TqPgL4`cY]|ˆYBpp|lhjiO?͍9A4e1IH!\n9&`N\j3OKk !hRU$C?1g[aHw] EU0%)4 X-,L>2\q¯箞얽:Ngʺ i*Dnjdc XinD򟯜{H7E[$7>Ɔ=Bɵə`S.FV+a:G/0YT=RZ><{2no.0eRUP62M@q*5ucO hNBzќ]9ʜ\ì >Yw֌/*PyS[ ֦ \ eJs\f\0{cW8CL 8)9IeA^m+RE;V"a\n`5Vr-g! 4'NC)ACȀ&*ĕ ^9>xsU_tog@"@.?r@̝Tqk`$͓cSI0@ENYK h-Za1ʼn8p[I؎dR-L'wۂСK%#ce2^N/3Uo}RCĘ[g>ӫdJMP,c,Le`|yޘ 9.gxI$7qHM;@apkbLDдzjB^f`_}s_#ю)S+mڗYb0+%?U <E&BE,Oi3¤˰J"-*bàw?kjoM> HvPmGXXZxcM>h$ `a|>ieL;7/ͫe,]A GM ?G\Yϛ3z4X=SK1Yyوh48_rrDB[R]eDNTr5>Ru5͊e0$[gHѫaM4 0fy()y`Cv~jVLA ۭM&(dE rh褮Rz}u4 36PT7Z  NX}Ӌ>|%` _?iiaFM>b6>+bnp֚Ħ5h  WGQS`ջ*  GV.G{_.Ä`Ynoɡ>#q֛TL襘g85'qW(KFB۟G0~gR;Ir1-I@DDp :Wjx2ngB0ݿf`}|7mwe^_#_ 7_䓃} UiOB "L ˱4? ںP1QUY!y3IL izޯY ?XLYCf2QڎcFrvuT7objM9<]VPQ֊W:#R V~T, cn׷ j* um:v~(A+!6Xb# 'RV%\Ofq&4(O$E!?gW( QsS= D@ *p(:[LU~jN'QGΜ:3.YzŊfMJu&eLȜM2DR\*Y u:/D<&Ns4$ hm!Wr5%+xT{@E;~Ч0!:cಆfWe =r7npS GVgH)ޣ L"4\zZ$z<`p)Gր'+#҂+x+LF20=ɣ?eTyHIJz++ "yM]8W~Ē#\B C5TBWbGF gh˺V$.J Ŝ1WpߞR?&@C()LE\0N'fe^/I\x[ž޾W~m${7oɡ3 U ϯx2 JC?"gLa3Ri s˖#{RY oCg!>9ZQ)( ZPJBUQ{qkwgtPFXdY_w%G3733@ܤذ{~c NnS̴e: (񢁴X/.27['$OQҦۢ]}t 9:%6~$ӶKҍNskkw=Rl&? 2/KdqQu䊩WC@q_n"45FcotuE:y0Nm Ўd~? +g-]@Io'|TeF&YXC-X~}wޭ<5جt4iG woDKjKX7>΂UblۅbHNoUJ/CUVR5kfy'ٸIĆ%'QzmlM%\;c ch^4(fb4Q;<4t\yD.54ס٢zLSQ꽑 Gd]T ҙ> ET *5QŪ4o L4r{qS*Kϡ:/C/5mTNM ;5$TB'v|ޣ8fre%- 4 *}k:=lRC27&!G=; Idg`+3@Fg`km4z2@j1p(]=<6&}X0doN e[&Kc[޵t Y9^Cׂ\zp s~Uy&Q1W2K "MApXJPh+*-MsOɉQL+?jxw|Kv!i> ia# cacԺhUK!?@̎0Bd3a1 Mf$1+NRԑJ}0cJc:ApN6.܉zͪ[ g/W " gf#gw:s51F97kx=@Nj9npC4 '(PSYaEDHYYW6p6;Z7_/ Q_Hu K=#ud7FRcPLrYei<5$ O"sFGdgJ :O J߻u,T ,KO~Umfmu?eXA -v>OFpKXQ41nR{8ep#E [sPmBӾ<n`AP"׊O{a[ڞNc72y\0 Yguot a0o)5=c-- L s;̨YOpG[T=IrԚmlۮf^uvᣔevj ,] kO\tQ(GDr:7M*rWc;kSci\3lJ/lC=T%;i _e.C2 Rݡ6xp%j7X)`;TRL>§l{+wqs~ḗIYuɆIc&TDXuIyTm%ų!^8N-[IWy݈&ӏ}ҾEfeE}/ܾ}{+e_˒4Ȟ;4++K WLA$m4$c?L#t3L.7'TBCFI %$M`|VAIQ"$5PN+4d9+5M_IoQme4`hdIuNYeB$8an)z@iDn%($|b꣭O҂oyUR>%ZAei,\jVT ii0oLzxز.%#I0 #Dn)r~$і1)g@ dߊneb0lnK_M`E-a`׺45!5 LouȞx0仌uL{Xz#Mvl[45xߌ}&) .`~ژ$0D=jddDs_\f 2EeG-1l&lВv5 YS0<%̰>o*A>vL~U s !;l+9uq)+P_x,p=``'/. ?B#; :\Y|Rk\"4z:k6v6ټj-UJ0I+  1mg}Q">l0w~~^AZwruIcHV,. {EC0%zhЏ_~Ewx)8۞&!$4*k:Vs@_슂3>> f&IQrTxÄn:;1^?t69Ay*eX/m1 0v}?'iirN5;xyEJi&<ڥgu t2Lj`~aDA@1ex7_8:(SQ`Xv^q88p'@qm峘rdYj~6<=).D%$@Hxݨg0$t$=Ɍ@|aw=L1HqJf*@$I>^OiQuB6XTun[_8gπ!KxtaN\~>A:#x p38p-;$ '0q`E"B;WW):1*8+SM{u=gia)k1zT2,QA+5D|*m,0ۉLeMOVw vA*<8'1הFvig̦ۅUkyfj}Fއs1Yf,Ўkc&t\h]%qΣn7Т2BCʺ@8_0l\j x?Y$Ozcwd}%l~ O7 B[(vZZC Dt廲4Vn`M&9²¬3 (t{ 6Eé(i']c՝T8l^28셿 Ҳxo3>q l o}B#ezi"Om^+5fGt*lpXLE, ߽h.y[W71{!I-Qx( q ! =vT0D$@]US<4tva++h쯨"S?Bk킵_s|IQsӥqNG,IQJ19vٸ=P=h@4BUV<+3HF˨ :qY#0# 5n>{f4 ΅̈:ˏUv7Jrf6;F:Ce7jS^^ZRu$6MY &<Օk:Re B& grq_r8@DZ FC<)FRqf ww1qhC~ΜOi7DA<@AuZ2 8 ւr&reJށ8y^ Dk xD.nIA'yZG_(B `yīrkݧr J+Q|]c.(1'dtRQ7>CEP4bWm@p~u5vOA\q=J-}Vw*`1 eP+ :OF5(P+*[a2 IKZ|7sAi{CJ˂Ns"` #mSp/#zL cuàz\Q#+! /FK-n^h { ^ RJeNJY>M IH93Z3&15Zn* 9$zzQ]D9C{eOJU#hk 27j.anX䢱MeyS0.@HEmťEViQe?{Fex!x٣D03s1yVtLG^ /8Ɓh-dehŊ%/ m#Od$s;@a0{J%{~?N.zSw$QRTDB=u!6yoeRU-D-2к>đ`4öreo"?fYK -/6i!~? ɧF`Rȡ`dQj%Fn" Xd3[^l[9I&h9Chڝ-l!>,]Бl^1}磩Y9!A"*6iv )5}X8 E(IpH)_\!5O ky5AΫ1V4 ,7NS>XHP!=.8L@`+LI<wѰeeaN-dd\E6Gk:̑r*Qit[ #F xc"eBםV ,.AΨv gC7=sp#2[;[7]!Ϩ PWkruj8Ĥ$I(EPzHt)UZ>!r(){JL=6 %.dJH箅UQ!#e7IQS6 iSudICp 7 `C2Pb6Ek+4"ٛ͸֔&/]KHw^H? .@u3k4(҂ 5q~i rMxJZ+)c%D=e ECO)qꝈt4VJ SYCsU{@FJydWbrф #5$8/_&"9 ^~1ܬ+>[ k µ<=Eˣ|06ৱnƔv/xЄ3F5 Ä,eqv)dOȄ=V% a+B d{UL}U=unr1S)]_hfǡps}RvH䡧0:Aws]xQx2u}:'3h Ƌ6KU`.6+ґjDU:#`u0-z,*K`Bȣ[ ֎t!ƓNH\/FAj]p8i8{]K{8Rm܉$3c,[MR`Ƀ @ߓY-*;s:rh$m01xc)/NђP~4Ё?ڠ?47:LK%&cF.U;4t~a@9cdfdmĩS;B+[BCIi "U*t(Wbw|z/k ۨ}hx|BKw9BMCu'; +p:Xi'>.!H& }]nK <mm"fC܋CLiܺ&v''lUaVpz*W:&6fq}-t,^O]ʗ g΅;3 9DžR̥OT& }+Y?k3K-c8r\_NK 6ǯn#AKBSW]x9v)ID)c+hqPP G25h|WPG@vQɐगnDe"k&eN8$JтwPᑾWac5;<'$iȆSzmIJ.$kzx{DcjDm]IHnv !a\b:[E%:>gDܚn졩1r{:쑠SƌD NԀȫ(NyHU{LC[O_i;g:⽶4/hA)"QٻlpΨꍼM` Oh8VB;,B4-.zƜ RN8z ]U &R]);.`.uK(v֖Nyrf&mie t]NstIcN^\_xH,7Ej5W K?RYRc*<{uG(W1/?A#40#NYR6Dox9LăFvTE/A8jA y7HT$@<"&CF ,l}%L[:(kgfbgo#*BȾUsKԁ--ܷF!(<(d-2BLPW[϶77^xX()d(ِ v*k*ڠX+ˤ}K+e..^`xzIm1:BŇs|PPÎZ6cĵ"Q7d,h,O:u}xd!Xpɀ(K/"B񖰜FX!'\\ /b?򄭤oH_mm.vق|dKɄ>dpmӋp_2 8"jB}?/ސ3~Bq.%e71EtEk$N=G"i$%3_@3c7=)JQhl"G&} RВN|w\i|>ĶftdHVƬ‚sKZ ,eM{=e SFŸjA=woiWrmd3reKDF=I8\uw;4;S}U{YmC]q Tcؓawzhcg:hϖ e!pC5j^s)qVv30H7ovKxH5ƲDB" _\ ;L쇽( Eك G%9lv\gy82#C, Q3=RCL?a٢L%7j % qtъ< "׷W1ˠ90?k3a.9RO(`货Zp-A/4hu^bžZIa\ SX]g N5ab}k3|_i_wgO~XDW`={ι^JNG]f+?BgUQh>tфͤFI())=|ЫQaSXN-ˋ^S%~kbe\҈pD$$Yc ›OfyϞ&{*8~p|d'X?YBڃr PfItQb=8_p11Փ׎N6Q M{? ȷo.1qu5dS9ILxBʺx*M6!AhF\arʉl#y6Nӡ13,thq@8DcK̏M $JAƃJ0'ֈ$q|Z1}جQEf-;X 18\2aEj5f MmȈ\yA*CǶX4r0*_x9f{1+e䚭6ZH4v3fNUbgtejP=.$ں +0Maͧ7_֥z]ONpKZn*}vorR_ޘTUyi_DFw]7kBbֳe+&z[Y@b*4}Y,|9$dI4& h$VfJc'UOI< ?-LJTlMرSE/S87LNR Av*$0u< ÎB !mN4PdILY GiѢ[rZT**惡$iuG 5V`8*ҟT0Y}:k~ 'I^^&+G4|1&&6{U1o=O:)YQ/%UZ,uOYV?|#wCFyRE#c |M7ZTj^^۾iΣaxceXBr;'I{eԫ{hX[ Y>V)N)v'%6zZyI&:ʜ9aDr86ZMqw.J갮C_tk wcG zI8#9g7VЎ\FbZ$7 ͠@ڋf[Od’t2O8~zo=q).Rw{rwz}blc+GE,L< U'gbŘ&6vg|~}9>峰py [_RamqT[X_ r~h|CL*NN&'|p6~07->Z:J{}z,-- pObm, E1[@k\Rϭ3<ôO_ol70n*J bPGlc]Prm_qkDr{ʷVovizK3%lڥۿJ4;{MKRBd>nAF3[/6XLE#yqCC0%x]~vziuN1G$zUr3LP0<\CMZ[>K}s$ef?30K0pMmbNtV2YYCIO1(Aŷ7|c8痓x$JG;ܴe>Q`S#EɒĞ 4~Ba-S$f$q :˸mZ4h5}׮]mVaL4+x.H!,\ YSԂe94SAq׷v QlgH_AW9H|oӂu/Mn`JGG׻qR+x S(z:޵mmG?\>-U5hLư0HHS[WU:UڂF҂F.?nc]x[}W}Htp\\Qm58rvO׸~٦Goܭ<@*gI#Vw t} gt9.zbU;h@\5J sPo㨫pVydXRIU C pQ!CǯgYҔ:W:Kg>kHwT/$C&Q^֎c~(6S#S(l 01*ZSF;Q0 wpYv">cާ؁ s;1Jh)FPmbd!B>-\0Cks+W=TYѼhE(:zZ)#: Ns^d!D QCQi"@Ҧ̸ݕR`\?*Q7Hʜ%מ)-ү0> ]X^%{}t\)}swvm;XJ;XdK+)X qB+]"%vƆT;șPSn,Eʟ2NJsL.!'HrГW@v5Wdl7kjq_,iPYQBv`.jGӦTj/VdKk4Aߒڤ}8R3>B+ (k2bZbbL3D YГ'G2cO:sFqn62d!kYɮ%6\L_kf 8~ fĻ ͯ\[ 枲}3͛澸=BVh}鐱`: m H AeQu71 b]N0@U`B}b:|3 -=("ɸa"SL_u[fY&-;t.h R`2YqpL>#d&LqQ?;qM9C4ѡ*] 38k#є{ ( uYf{t-}΃ L?=ad12G%m\R9$0TASX5%0mK41Nʀ]oClrzq-2i(hڿѳl_RK5ڕ{ؓPe4-Q=B; ;}Թ jPan:yҗsO$/dN6Zd"P>9a'3gfx(tko}B߶kjPt 愑(_ 5Y#$嫲4'Z0])L~ଙ(Y>e5T!s$RY H"`ۖj39 zҔ:f*R?v?0)njޅDAIK晍0 &sZ:Lp\H-C(Q kWy }+^fQ:~0k"l?Tf,xXrBt,er~&ۦFʮ0Α;= K)b#9҅ ^tPHLلcn& \Э\zl4ΔF>GC`cÈ!' +SǞm FdaƖQeeT{ck^o4 vP0&osվM}7bډkA@fm+*1j&3ʞ\!pV8dm:pCcUtdR}$0ϛ믃c9ڒ #+-e}ɐq@i_k@UO08i愦rvuR-W_/Gp^Dz~9{nZ;.]?cH)U6sE*DzocuܙNdM; JCgPV_!4fBU̖\Ki~Zae`hϪxZ=ab6=$¤ pz葀(L"jY.0ۖWl]6FLUA_2iF$ e5):xo99 ;4ʈ5,##eλhVl `}s ,ꔢY4 jNQ]ǐt`/BP^4!ܷEO85Bjd;#S y9siQd]Qv( ) cӻa9،׀ bAL"VS|,9op1^+^Y< ͢c& WQ >zI%A:Ŀ!Ȇ0ڪk⥗Up2FIc|00bT-|\b8)~\jcDXF/s;_V7YO)_@w?xp޾I;)APi/Oɀo1H5=}iq9-XB(>)k111ퟟVS,z\̚SX'dq9ܡZz |"Zezq8P  }W;{Oez$Yv/dfgR-FWqy0c]\WI`r✔bFkR)pq/\. 3ϪMJ0}LI鐕y`t6uǝ/l_w͖ sa\YY6R&3?IzN1aɊtcCnoD7ج~("Ͱn|>޼ j%m53/hpVQg\Q+;jjpglћ2[{ANihtePis 2E/_a:*G!n prf)[pf"Κ/ ezfQk{||/Oen _[^Vm>۳k#Om`$Dx-r~4^y`{D`ϯm}T\XMT XH;ˎ>#_Oѫ>qcx+}D c" 5^Rf=|3(<8+T_|C `8@*}@V˻FV\[!) UWh ﵾ{iQkt i-q}-<}} \(‚mOk>`6|kdY"\K^<9 9U=,c}_I3si` &ɞxHYtzQ4=eo> lQW$ 4Ծ˽WI;>-ڋ ֊j8V.Gi@nP=BӃy@@E3oܱlsF_:;mQt2P_܃KLH[pQt)Yi(mo[환+"dtd?hY[Tl2 "4 |mAxR9p }~V,?wgt6zɹ[O6Gjz,d=xBÞ0@P~{r=xEi%Hg s*O1p&I-Xh1!E}t?z醹hӿynysZϞK͸. e6F_tݏ [[BuQe2|L~%FfY\70u[[)w49^ p_7A%S>p ٢#kW*9=)C>;'n{qYU~iN.qc#r~>_0*a,u9/6+$/T7#?ntPvg@`3k}PqHom=*džzֶOc~\\9 fwq`݃4 V[J6 s{]#ȏkDbgBP_K*SA ו=ș$HnB56Ryq{dEÁC 7$\Gr{*e2jƽ5AaFL;5ern劈@Ww0ʣ$ةJqMk3*%CaXwxj|9cxҝ$XEᤰRO`?y=P'ۃE>)tvn{\6ply[2y3KM+/qPC]A( )R *ܹ}|)ðݏbW1蕅~}G@7!e3i>_ O?JO?m|OI^n2.ww \pޟ5%v$)';ӧ~ ]lGCcNnPJK.H<,a`n.144,<lː/U6q{Ӂ@r{ YK]fn 蝭Kx.L7'ZvUu <[Rz%T7ÓL'ѿ3?mIE25fF2?~ s=)Tfya G 3ٲIPPG!GFE)pH<U"g~>bsMrc ; 1mb]` Z,R4o\ap)9:;V^V]#C͟?8?SjQ'lJi|dSr+ޡ8֌8o\烎T\\@_ { 9>rD?65[YD_)}7Hl>md1 MHƹ`R3 ʐ='!9F"Ka]fI ^IHwɺI|> /tt|54VP!I3y30)]ChYeHK'Kfaѽod:NV@BO %u;g9› >8NVPK3xzzL@Zj4'ㇺxt-CzWm0ߧk,E/g^5Uْ68C'IUlx0 zN~aT|PaUc6SeG_, P:WO=0 1kMZwUxV-i^*Ix[F]u|rY^ E*%Q3VgrNEtH]R~3{FYebKJJ)Ht,XRj P} Jh -ѥ$plU'NM+"!c)ڽG00׊Ĺbܝqwvf$;!nSP.W.̲Kjui^hQrV:{ɳS9?aC&rg4byMղIα,^H}9g=0MY $viAAِw|nSƗ~rlAon8L\[߷D#6K۰̲ͧ[A;h͙.kuB}YT Ύ!5dadmg2ARtJ6ѝZNY0,{|UwXIh0[D2%h&< o0,1B?`B'uk`Jedߘ"LL}q 3jG;?p\+ ld{.mzltoeb3~+U%B\$#qW_a6|?T`#1t&t\݅-v [Yu{r t/+gAlM8ƙc֪69@ՐxJ:~$ U\^XX}MyGPi`C[]s߀N_+ =SEiUjɺha-։UǑJ"HF.䀭VOMVkN`"꨺1j$ .~QOɈooxO,_#"Q>x ef@[4 Yxl4@&W>s&"N{)/§짬Οhoާ>mtm+}+~mxdw8|d c8==vVm_q5ӄ7Tqw( Ax@}{Axy;|ữ2}3Tz'F7QdכF~M]u:3#-~(32D?*(q8EA#CEmQTLg m,ii qY!KܷnE9*OAq 5?ۺj1 h1HfI* }fMx_YM xa_k|Me $G6N⣽"NJ֕ՔsÖӓ,Ρa ,QXF`=!fe e&ְQ6)as5HC-y\ 5{gջˡ󺴮1:xXq/Y7|Z8+/a$aO܊5͹[e~@4.xBr"F c20tϭYFzJCѱ99Jkq}㷔Šo 鹺 ^U}(rS`Uhm|j$,oߋYt 7Fꎝ YfƲfvHI&ˑ~e t$舕h:*r]mncm͍m<1{^~^~=&"yCB^('"1&{8.mSo2" V#b_h\2zv?k?Bb D]K/ZtǿmOP$S&N2Sk#}Q0wr̀O9*{7K=h<\ lwF8 }w*k>?X,e5Ysc9P@()5jXIs..`7j`C-(~o6tU7lt*p)!ql8ɯ(laՉ+h+|@̈]JS!I #&wZ"Kvhpwl_<G ;gXTɝV{R3m.zo74Ks|:-NtnE{!]lH勊9a1toRJo%,wYF"_h5tެK :wU ֱR!A[noeY&_C;T< 8<]˅I7? n}W\ L M(-dǺ29knt*z-el-$nrYzE[4WdMƆ{%ҫ 4/J2t4\{8)s(4.}l$9O0O?qXo# zfH݊3+_qNV XۊrK .)M8&K[u¦4)4H9XEVLt>Mҋ?Bnp(P魴V->!.n [X`6"NG)o B/Q.oa']2CXGiC=I!:F"@"kW;hKg'oIfT 0/; HJITa0~:HA(` >Xv Վ`=y`em77F<j8)a kYJ`?} A ˇLe:QN7g@NU8bs>kʹ![#Z3K[㢎?Sw͎oa@l=e~ "%;ّ*?B$cZNQ艛N! j`QGտM|Ay5-YEԚk!1%]t2 ׂ?^9LɛN[XG\ g,;J8Juz38ge>cYQy<#)Vw;, ʺݐC2U]BbHܭ XꢋVus*aNc&m>QYtP kenIp7u$Y`%rIk{v{ZCf|sF]+]QҨ.B:`1]< F~BachC5T+du*4 ˣ`$rf27r[Μ;t|z3Zb1K79G%zO|{~*h\"SO9r9%7+Um"ݶ H]:Q oyp8L mt݆ 9tB0 & 'dLIٌzm#dނu`DQrai)/+Th\pe;cDh﹢U#,^W@6)JFxx]Hd텓65>z2=d1,褘3ZsI.<]0潎eΫPnX,„Uא(>.kiϭ|z3.k_lL> .#}o G#h'Gc1B. ec'6#F/4nvE۳ữo/.:?;kJkNzYay3s(k]cDD-6n4QR*!H@f5UEhF((79y<#eQ`UެN>awAt:>ɲJ&mB?~n<a =_%fsx\N~8TYZrOOo?_6Sc:$_^Kv O۾WCifw㊽=Lp0DL2(ڙ!3 R^ab6PVu9:/2f2뢅Cj}Fez}9<|YW匉.!/1*@ՍVj؇@khiohD59d;a[2U xF2 [ġ3ѷC- y 3gGzv/kJ}pf{0+ҕiUQab9tYtAۿKY媞)e[%\`0 ')\hKw`d"iJ~)@̢8ŤDbCkaɭ{m'qL|ŘKY6zH1j2( Bsrmw\UMO1x7xiA_dcptØ3m@ c''%`}yHt4_xE?ڂ ٠ & FI)$!jMJNd.~@QcMsW ԸnE`1)|z[2b@! o57weu]"@M-< 2"42&.nj.qQ{YFz*+qx|_xmN\k숿)_p uJ%h]O dqJ=j<L'EӖ(.F;ܬϬ?ځɒBU:>H0ۈי) TxDA\ ^0+`1E?9Bw_~nX7i0|iu^RH yd>P~csQ;p$,]#^)|)N7 |&%otB r8s*d\daFX9- Tن dpY5bHr:HUCQ {Jfj*sYV"NOdvIs'nǸ4_MSURu;I8Ƣ ǀǒ!搭k}yl0cF n,W_ u*BnެKNv/lk5v[!jؼIYT:ֶi#:A[5>[v8|ZVڭӴ7cZWOrVJ]3duZ4&2^@:/Uz]Lh]۠X;j-}ց&%oPVT*V#v<@myȆּaZN`/ O'!Ͳw##!*Rqݧ^m}XInHBgpYۙOpCEV3V{m#9WߐDZ9 |/(sm ?> ШR߈N]KXlQotZRV~JyEf6 %[ހ&IaMyVkrt!=8h! u6KeZiҭ{yKMxV7a !GA;Cl6/2ꌱt `g L$A$Eq# j~=LK4l)m> Ժmj3(W~9tlM)C9 tpMp%rP{o]Y0斫%p'k-1ܛf[nǕsRuf0 vMѳeIOO@ ×M}OUԘ#mqUm"V1 6:;-CVr9lk}*b\L8sO40xs$nv¹0wz5G( Bðl5j I*I1C,\3Yֈmg ,,~_&{eRwu~BZr'*Ҟ~8V[qdtS3k}R6y_bVE~V*/:YōxY38xY#qÃ't'Qpk">}s؜%#GQָK"CC0 7YZ1B 3CQJ3 !p@ }VT.P{䖝DMYAL\{ j˄ɟM7moFk4(sg jk׳#upAAXVs e=!B LoPu!]7wM.509Ni-UOiH1:"; `h]pXHțyF q +#Z+~]N*#߭+x]h#/F`-X:NoDcȱՋ!'O܀- g=Fuυ\㺤Z-xqgMm#LúFݮk4R*p-(Ҧs^sHn4~y^q\gNWU j7`NH-5 9prB]]/<,7m [ѹA[\T]ꆛ~MCJaz>*6/ݭ֞jMJ|~;B4yoQ]݊KXn]sYmvLuݠΊWW_w W Wkפ\rϻ3IOyI#ӨOiȌż͠%%RfS`FS!p$^U7OABU s{_-Sn,"sʥԕhxskJuCL=cf F˜Pjŋ2Kt{o w]\Ԫlj4ҬJԳ*D\owS~݁bk'mLqq>rִƴiʠktZW5ZklxǦC-g(p|=FѹUR_g7RHtm1DNDtXѓ֖Ha%y*}eЛpv-Si7?ײh!-ݿ}uͣSHF^kyGkp]`Q3ݔٴizj):]k<:x)$;LsIv1 &xm@Pͽ@ݖ֭fU8.4'QJ&[ķ 䒔È޵;$ 7x^Pyh3ˎԱ´(USh^1 cͼkV9(QC1# q>/3:%}9"*`וn+5%Y{x=tL͍7HQ zpS/8 ,vA.'_Y?i-cLf@ABN?Lw\CG`kg 9,Q}T(^pc_6ЊX uhp]dΜl-0Κg։/%km_^ז=Lb N1>_Auv7r4rk^"ѝrM8Dz_e]!">/6; 8O7;"\͠;t~D('@\.H1\OǺWw^ͻ^d\*L^؅&RwTϝ' lxa#<Ͱ@hl4z7p Xap >VN*,bO9 x|]"Z.8:w9I8Mj(޴%7FGg4 O/igyX>0}qrpA?)ɝtΫӧ~$gl#U@ұD_~x ds5ZMB?唀8v򆧔 Qn ?Cj!Ts"sq,_?HlS@ܓN):ٍS-afG{%9RdEQOSSs domnpXVO7!F7G ) 3G ~`Idcd>cw㸘N)Hn Hݴ?;:FIRXBB车"WQ"j2k>4\k\Sgn@Azf. bQLY>Ǹb W0X;" :K cI-;`G{7R݌r W0oj$ b(x):g[c{?p:kͭxR6?& 7`aCfq:Oڈ(6P7iƞMZZ5w;^6hEBm4M>s{s~YNGMD׈ҏˏ`2 ϧ8yٴ-?FS=OWt ft;Xu L6TG{'W}y1ōTk|*8V5Y$["|2,}PtL<| g'P'QJ\xhYKjl^ч\w2.,B!(ZP}A ,OI/(:Pqѧ}@skT(jqCڭyAOV#Ws eNB$윀 @ vj 9OCPQ"c` $g!s%%i1Z+cjk*. O+d,; _hW;,lOp{RԿeH2 $FGZ{pe4\y71OzMaadRl&gC9tȖerPD<"z~AI*s,B+͒"+ g{$FB=i>'a8 -RY,5!`IQtX}P$:DP x@0e[!ͧrv=Ys J@o˅_f OOS-mynoۇg4l,Oy1n;ap5Q4=լ>T@Ž=R~%Qyt}aqvsmI?Xғa%aAFP+Jy*xJ%$aZerȩjT#&iQy=( e_5lƧ ;6p晶b@3M&!a찃cZ`EzyQW :; 2)du3_@1 7&,Nhʜ^J`I=+{ŎP8ūF FYdj=T-0"P=:3 Nbc&([<.[`u=O)2SUQ zzddFICPT>yVak]@_)eziYJNgYI 3j њ)Yݗϟ7k#/=reS /v^쁘{- 'ZfzdS!B=F;?Ue(+(٘c[EeW:MyPMTny8z̚WǯlcMSX#%XJ:G  I_q'9R?<,[糄,::Kk"uwnIy;wFT!tj;,T15qnmIϒO@|︖t#-A,dzzM$~`&L N-~%+g\)#7cU?<}dw_r@UcLPDo#Jr%3I])1afO$2JFJ([.$SR6&)H±L+cz1bhh$!(e8U:aץ=w~Yf^vu.y,e YVŔD5< *kd~GD8FS..'Ό)ffeHCMzLMzpMC$oE@*'NL5jsQJ^(s$=Kf>"B}z | ȼEu4K/"c O 6%xbp5d(=uO0 SϝYCrq9d?R4|O8Y2#,p,9DG |Q L0?[VK҆Ȏ~ FNGu1/ݖi2$/X^k;S ,,$-͂?c "pHďXZoXr+oV^q]ctQ@1i EV ,~pNnjw^+VOw=񃧆}`asi\8|$EIZOj4mQIb~^ )'i4j\(c%f78MV<8Uz-:c7M24p hz^<:Ű7C:[άB.h&]fI~tDvDSrQ &N;Zz‡Eye]=Ӷ*g^i Xj<{!2g{0LT  ~1 8kk8.NA&f9lrzy2eqpCխ2)3b pq/lj\p$rZx =HAM~pIvMe1FaBVKjK8AURNHك!o!gL?A;t,"c7~EgwII5x5IJY!1gt|>hC{OϷԠi!)ǪnPC6rNDZrgY =26wnD&89:%]["dp䊺x+-_(N^޻cW (m"jL[NSA`7L<[6vIc 0Ԇ.=!i.' su3Z!dOgE.6?_;J TrYFVM>%suVk\H݇k)O]*ଠ<专/^1D4 ٫ZE,n`k|*7%1^ :$NsIśM)TOdDh[QU9T©uMp}N4 GQyRI 5Nj 5VZu{(ffVp'z9t4 UV_E.\o_pcz >Lt d XqQA`aQD7\LrQOV>#Z\y!U,P$Ӗ= U+`ѩT-PNs}aK'"uq2WwhxlKU)&ҌlلN4y3'aR03@@QP?Vٗ.;"#p>YI~s=f$3Dn q28('"Gҙ bꗬ+g'ShJw4O=ާ/Jzvo* xGBόAT)ڍ91fYE[unn,b,?tȘ^#6 bm[qn̴|Ꮥ 0Ž&H-+6-6KBQ6#]F,5# vgm ƹ A_y߈wh\AhMW#/q"di(nkJ>ÂBd *OiihHWΡy\:༌30*Bܷn (SI "{^AEG٩ }_<5KVjk!hH3z :}8"Dwcsy}oOi^sW;>2ǀ9[NXZ)F* 5bNR1]Tީ;YIw! *Q)\+ʌ?;ۛG۰'w7ށՏ)`Lssn,h2ecv)-v}^ ץT[DfcDៗfvVWEFQq' o](pm8^c!w^'{lCeSoM+2ծ;w/10\AQ#-j8vhsgd[*t:OQ8by d/HXFr~*\Ik}$z#Mg܈$“?Q|o .,qYBayh/ Ux?Q7F0<`\ G+J LY;fO:e- Z*ebyTⱡ!kc;W9o3LJfmfQyq>%B!fe1{o//v=|Yu>R#꿖2ŦWrtޱ>ljI2]ht ӑ5qτ@ZBr$G<+͙:7.)-9mKB._=s6A%v>I;~Tg)ƽHsE7b߁E =y=Q oF!h𥸊hɲ Jjw,5wP(/)g0}oF^M9m$8BU^a>trȝ7; =`72{K>A$v\^XMp\✀$kQ N1I7P|8吖A}z 2>5`tRāS@Lj#ė:D۪*)͍WqD.p8!"q<_P'ʐ`/SY4<񉣥^ϨF4%4V˘}˸秇S h.$K}ƆWAܟ*J:r&Ed1 E{a P2H#,-xDᢹzYmS4jC7aC]3QmJw ,(@@ ?nT]Ϫ]NЄfobӽ^ԧ>T=ݞ1# eokluex1:"}2%lf={yJjn.m4USmbo;{/5X)`\茣ݢur8;7 }vDi5.%c4,1e\'|D5L\8R⇙?(p#uqhFSĵju8EG@+Yqј;8gda#o3vxf2|9c xFjXr _\#t1SIbɹԪ‰TM'"r~I},I9mfvF5m$v:.@U߷O`GMtw;6wPBةq}iqyoatqV_/T|p*ߥTENihk<.>+G䚵!ćBo0>XˁէDb e]^ҟm?f2|?3R8MJ IZqvv6S( ~.6ij*zTd]~4m3ihEJĮ[8A@{,`qZ.k{I\0 UB6s@=EbVM3M ,6]숃hc |pB6`h]Z}rf'as3_5nxfdll|}Ag\&C;׏0-x kVr&@E2}y_O!gf.l g =[x\}7vI SF{ V04폏3pt'I`o (Zc\2J_.qGoсqhǕ 5AvH;}o6-P9u켽Oz ;o9\?p6DʬEvAbT;?$Pst1{υҠ.?:)9(&UBxHFóׁBIVs`K-DіMtPN(t +V=vSu^ $êZw[dD31M Vɶ`,Er'6 e#xs"2[`jE1NxlFFSD7 xزS='_kaf!0_`M,b:\~8E]-0ۮ':g6 J5G:I$i(iتV^c'7 enFQ=AIČ/yA=,?u|#/a9c|!؋$uȮt[\d"r5 8[%M+7KxO;Y?0U0nNʖrLXx#\ o-za7`+~!F0yCʈ.d DwEch^63S @@$ ]WB`'{j r1jfNؙWrTcU OZ_QNL[WHʓ"ơwΦi8Y<|>B{l#P_7 W'u0%9F4rfS䵎x7r59Rǂ@8v-]x![m7oK`OdD(&PSbkٛUt)I,Oy*.~>.03ɑ\8vr#U3Wl{+B[3G#hb&>-nz̉h#`IݤJu*!< 8D y](pZnMj\FY)hm5Y{EQ>&#+riBy?|\-DliCgm-Vp{ThVDAi`tFF`(JcJVfyJ 7clj|r䄈ALiۤ%-ô S7y{6|Ոt3]tfFv 2-p,,ToO&>(vJniPr}E>Z=0OK2)OV%/8"bkUix:njk I|"- n:5 C[k-Q { _1G8`0~F's 'jtu/˫R7/`heǞeqPw)FJy|!-UojVf7sEll+.Oӡu(тL'&ld!-O'md] u]tAHW$b.̇7Or?3~O.;/hjs|])(-hIm-#ϯ$q9Q>QgBtwuboهbVRFTp9KQ3&r?`.`OAE9'iD.JE@j5 uAU` {uPs-2FDV:g:ev$ѠCr!l6o_)7DgM"csU{Qto!@1 d`J;M1C9K v:A9oԟ%;-cʉ N ܚ/9*}לF rY&*W\&'߂MhJbJP$Xֆvxjb&R6 (MhnCj7'fwtjwj=۩ȠÜ"T5rv+ՙ Tq&Q@Ѩ]F6i!=Z=ÂR=r~i`)cJ De)Fp8~㧚l^V1LFr+/Yk^MeNٱ )yz M$ؠ.CQdB!a!"/-*Gr&h@xW8=䗈rT2of)aBV?2I4մz:"Tj+w:Ȼ3f8`& ٚ\XiSI 21kOdā`OT9S9-Sĺ0z|)hP{)f⢮$ ̒>m=Wp{6fCmBV_^+^Gi:לRʒ -#cJ Q9%,Dk6i #{msr`5 &Gr*ч ! kC{Eхex>)k!j(oDYsd4Ox52+&ONt[16&Е>VF{gPQPZ߁7.doAvMW@Qf&pF in=VTHF%p>7Oo>BfrHb)v0ilP)u=z[WEeR%`6jpUk ѹZ=,y1SldW%c Hn]Rl!u Y t;LĊE^"ΒT Yw!V4 ˅p\'[rleк(Z9"zf4$SHW" sv-!MA&oW,g{7MG?t 9WpuEEu3vDdL#I)  ~ɣojTcŝq-pНajLHNiyĀ.Ks#;T>z x9X\0f9|9 1)0`x./4KOPRN`C~88$\P# !$^|\Ϣ]|CwkMtiK:v % OqO\ˣ#zBdӄglO=J di{?^ӥLjLEG ~:٪2=ʏā8>C@sL~JYaąB8_x$J1g>,i Z2[i,w?9U\2Q"QG6H_nNI u+kio6/dvjg5Z}渁0,}_2T*ZbPd`;ruxz5ᝮ0dp|9H ۽D qNp^e:``H0x<2 (+ sZ^KHUA =HT'#UTJ΃%$WZUbG@HѻŇ^P?#؂wc2̈́a\F(vR [IR86]U6X[;JRj(qtm#IOͪZYURJ^O$A.}n,"2YRuϜuf32{*ʰizpᖘ#ihvlqMjCekm*I 2OUj?q m|7v/>Wi N#J\Y?0.Jo8CE+ޮdGxQ $\?W]w:ZAftVq&봭_w rS9@X1&Df'QڴjWV"] Ii-0 q>bjFBi{?}Xrq`Gչr؋NN:}^MWbf",.aTqqs>Myۃ^m\:!B4skNT’ʸb3\Ml] '.kKKQ]\ȫk/ZQ: ;J ,)Rb:SL,qL&)7HQR3Ngcv~ɘte޼Ի KV/HFVt[--:k D:)[Y'^99=y7u-j{[ɫ~$DR[xv 'GJ"^u3X Xـ^Y/`} 3EjZXksުl 1krA;Morejy:-zZYB^Af:X0ꘀtA!6"bZ%o m߷}[NlÚ%k4 9Fbf}2FZ)¦0j )ꚉڧup]Ě6樶r#B;hDr4y1XێeL1!^J`?/%4 CgS.|Omw{}\44ʢYTFIE.aLszf@d4(U";̄DiXtw,E2RHRcՁ)J)MVXu =yW0GqDy10L[os'p@/URni CYPζ l0_89*hY/TjŘ m2ۯD[߉}:[YT琈h"$ZV 87Oez@&}`\M%Q7Fin*Y-=noD=dgH@n}m?dLmMW|")7WU\wGm?Y;ijߢx^ :ql ׀o] IzF~Klڀlth8X#}O ,E QXвG}'}鞎^`M+vӟ_ܩQ z,:2:moQOZGiUZyY-E]7W9gHy.,> 2l^iEvV zq|gC{vgW'O;K28$-'%y_~" )7OE?9iDbRۤ7_/َz==C3 0Of[=ø楗a: y/۾ǥ뛭߼oPD(x4}=3н{ >֒^_=#KRrS7k󓆰(℟t"j`b]R?,ה0W^(N`Qx{[Tjǥf59ɖ6-%Ndu&.k-jFy^"36 ƶ@nV2 ˂k3AHү&V[hdTeATt3a@MK*ʹ,DLt̾.uԗpK:Sq6;8f E5tQTߤ QQʲ/V&Y<_OEygZF &i!>6` !ȇhpRX7*V/k߇Ϊ2gQ`i|v:kj aO{{}XZ~Z5jD ҠwXnW~UߛZ +O_b>_Y<쭊' QH{Te-'h4>ܮ6o nu8bTQH(T"~~|U'UY?a6TZ; \PK+u> XƂU)d/)qj&ƵOQo@JT!>84%PQLV<]^VZQmhCuP-#0 cBì|]}B8٭?dp:~-f(^KMƟxKJճ/Sp3/7՗p/-~mXWaƣ0'dnNOjn6Y+52D An{w;ҜjV^_jv@;f15ed`Ve닳 Cb=6Cz86.@3xE^yfS|A= V >]8> ;px*fӞB ֐_l?'Ewo_Nw'@x[u*=uSeyIpIszᅌ8wd6ޱ㓋7gTKlR$u▍ ܅$%ZҖ|*P}X4J9V1T],VR bYHt /AĚDT˙A#KVOY"+~׋ڀLoo|1k!UJ0OF:gmn^l بڔ[9a\+pQ!:.f5 ,vBgks\mދB r| mlC9\nN[(PdeH<(c|ɛzmdkhr[/TЂgX])։26jىW]njSA1z(7XK%ysԯblesO87Yئ%c3ǐG,dS`-dL 6o*uK j\$&kk 5C8Hqy0$(CH ( ڗ [R_7/փlP :$ $kŀM&?iDqȩ^}8w&bU ȪNwyN79)ɲѶ ƫ5V}|iV(6*W1:-q}O 䱗9>po qiΣ޿)V'87]K&hiwY>/wYۗ^fJd:EEr 4uvJ=,.w_/OWcfKxsz>0qCixz&{n}k9\%Ą.LP5Biu:0z1 4oo0W,%X#ꝐZ'͙ Wf❑GLڏ^>K JuaFx5F K_2 KGU[@=T9n# 14/W7 MRG婭S?>>Gogk#AP/B rj~^ ䷝\)gC”˷e9539LRlIwЮցh`t1onvwIT)aW[o;PzP#l)j=ǩ۟K=#9#h>}ӛ˿wEûv$sth>tzqz纽'pwDu#4m|ޢgdL7{p~G@93*qf ue8g}KPFvu>/EwNo+hΥZ+jE EK`3h~D9e3s]!8m-X-8"XUhpz +ޢ⹇ +n/pFxFE3}"8cwq!EDAE.-wGLڡsu97h.[4.];woEv7͡m.%W-pzG9v. )+B*Uo ~>rZ*l 9#%oKah?[8ږ:ep-{~@H[,Hg;w]x/n///]%@rx Oط%8#I?>}Ds?c U,u(uAtK ޱ aT85GQObi4H#p,$QJ:)"-΢a&h 9E *IG .fEң*QUϤ*{HHD@:MILȢ8}Iq" )l[/rN@%#qqEwHi?GD@BGC`'=#8|.ŖT6w/ݽg>< ( u:A+ȕRw RzMi+ǡ.ձo|U_I ĞxUҊBY8n\“־ h7YGb%v%[?=RWPpOiN _ҤKң0W>q==w? }iSsJ!(̙t}4 '璤t%AuIi/S"\BWI?MؑTA |.J6AHwk!55Ǟӕܱtҫ{l4>7K@ؗc!v7SqdK8nJKj郐.aLOS9'OSlؕcS~aKSaٷqGF-|o=مB[8и@-H t|W{shͅB\{$ h' ;}$V7i$VBlR7W$!%~}&y%#,w$LAz!}dI^iH!zR/q S!.dzH}!"o et`Ai^MA ;S4(RdX(Jf[RMs_Lw K.Ln4Hakv1<.J SӅ@uLCAs,)9RqЫwHធC69{J7( `[OC92ak<#JH="I9r2zb."rReUj 2&Lb%tHn䃐kdD3"<ŝۖQaTDk}ÌgZmI(wĎ g7IYJ'8QC9PC.Ld|C~`C\(I bׁS@im HChbWTn%C"J"Āu5ݹ p9 >'VOA&B|Ԥ\)f"]9U %]fp 'yXiяo-He9()AR'[:ޫzCڦ=>V}DmQ)lcLb!>1Ar%]ݮAkpҖyIAț1&m6MkRtȲ}:\uR$ ٕ )IZb9 -- 1S;C6vW;rN;>A!T8ehSyI:RI45̋sR4ZL96 V<:0/mS2:՝v\PQ{̱.*dH,'.;* qhT8bz!ҹp,s}ڝ1D1DJQˤ*JgT|䁐9tHK^0RKݓ=Ȣt`v\Ig]iJ}@Nr,>q Pf2&ug/i ^&?uWR@OB~ X#φ7U&ŬYO wi}3[!zR@T`_ek)2hޙe2c'sԞAV8dnp*۫[R"pu/~)S%v/mEٍK{z' (&)Jd\2s!޸$'K;ʰw]A\Q}~!!HC|Y{hU.Ӄ87\Lm\j-7H ӅGf Y d{•$|򀜄+pNW̅+'r{W<<q@y65"*瞖Uw|䮄p٢3f qآtQ&3$(?.}7yn}=ܥDwiqsW%.M?#*mG#(!#( R-\Gz.S]TU^pH&:S|$n̽u42j1uG2cՍҎ 5'NsKҔfQ*C)2.X{R&W˶41|TmyvTRRm7~eh)3LbP s`8-!ep~?'];t2cG@)W-dPV'F EX r){An_Ah+\;` :\hIEHNVAuP]Lq1QpHj B&3:DV4d4w"`>'ѓ2,}$ }dR2JBmTb+{dZLRjZ*I;Hx{RˁnBq_>ƮloʘPURBT[ޗ>zN;FOdkOFX>B2##LҗT7qիPb_ W:JJUe j_U$C\$MJlZŶ3hgJ#ikܓR?$t PU AaqT)ԗ %rHou b}U\vo_euB9]Y \ݗ9_RtrH Xt 1ғn7|WRu(\ L@$-# n=WЗT~j2 6w-= KݐzBR] AN6l!Rkj.15 ?aU ޶I  I"`(()KJ]5@Eǧ.Br'lːtJܖ,_(|[A2Qu+.daGE؉ &M̅aC̕!LaZ wGPJ&Ws-99LM2elIٞy:LDIݹ0g,yƜʠ\eD;K窧ړ&Ahcm-wGs+vCsm' /ޓQADc%MFЬMJ'Fx:+]7JkSF=UCi|ݳaF=y[Y#m}|E y_Tê8-dbPx9F㿿|mSKSIs,̡yг3O qs8RywU;a &|xr(gTcT~lp%Vr;]1{PW]ݮ?wpW'/Ϭ(vH+^-sncB,Ⱦwm*\3kO\how=8kNs^`7!޷L38yR&XZڡݕd.{9tWz{ݝ4CkVzG@ >qraRˡ \&B_{oK-ܫK_OV2 3tdT<|S(cL 10*\UeB#F~a`& 3U0 9 G ۖ+FFijyu'}i)8z$ =ZjV7TKoKs7S$ʼn.uxyRa TwbX快 4Įp}!IWtR,RL@Uc.* v"/dF/#SWT=*.uD:HC}~!Zwd\<2UEG ?TH54 Jg4dbHLZxNteo7leM訅 xobM\|ck_Z h^C_LFF ց8(Z祬}JkP \X@NK]lLprն1J'˵꟰h@}HR v62npX2}|k*dvk{رmX6SMĪ 8*+ؗ6؉`zb+@;~Hޓ _QԒQe镎'D[Ow $1sD޶JFIAteU1Y>bLOYYwtkj5%] :B?se*ϊ6.%ˀbQhA JT]K l E2C+ K'E'%,2.O΢ANdkvKhXk)۹}W͚to{v<2a:uw5rrW? =K{ d~@lj?pc#Q/S B.z\ۄB&u oqzKi--cuFszؒk򅈩[ləނ~\دNo%91]9Ŗpzؒ) bK^9e[\NoY%-6[:obK-C-F[lɅmͲrҥ[>a[;9-No%?8eh[lɏNoALNoqrzWybKpdߜvK7SMޛ~L7@^bӏd;2^iAw;q֜$㶋ܝUuʼnmᶋSmtʙ|/ؿ%]鶋K?..G]p㟜v7g>G|Y9t ګۑΌiَW/Y2/Vp s/׹u8iO*.g|)>wS9|_p_߹}]9uyqt_e;bs,Opn!~__wy_Vs~_׹t b޺)u//_׍_ϏnY/OnA_wns ou;^=wo*N}#ХeՁ4u~BfO-zRf ͺ]`i;¤vu9BjuuR'>!JMxhޢa%fȾ) #]WT,Wi)qGf~`=u_GYVlmyUXtELOMӗc]Z)&IWcyvjŢey^C6sE sIWK^hX5SBQ$ySJ:dWZdώp3UK λTJ *ήB Og3ï go\ć^{ة [@.QzN4 : ζ$+ISg5r/"Dqis+(kZf{.zt碗S\ s/+vC/ 7 rO}V[^މZD*|W=c!QROy>VN-lwUSZ1nGZ7|I=!=ؐ[|ģ+KcWWviv{%!Js\-$m"=|K ex8ZA5,Ēae)jϢy[?XYfL0 B2 aӨpYTwlv<~~=@0t8l;l`QƦ_OK4| ;OͰ7$ÕCZ{h8]SՖx8gy&j7~eVӤD pL(< qXn>zv>ٳvn-P wN^{ǿa~|b.7Oݘ?wvvB/nmNwkQB}?#y^`= Ѩ< 'O<zKeUz˫xK!/h/'Fe2,^4r/QxF+WAz4&gU/ÒoiC(Y>ZFxg"q_$o8 On#OjdsOlcT`#7AGHdp;Kw1o0'p!.;ųgxoU"3Cj7GqL2'7'#6p(Z 4V^$$Q!"0OqF(7#}f;YPE,EUÉaЅ6|`UQIEc(E1 yzL|wOeeЮ$iryppq^5Il 4ѧ{ew7WHCa36~2Ga2f }FXf$M>7qQzwpfi.B ѝă { R n~C5ax^ qL`38{q" CA*x h*D?7萮(O>Ɇb?ma%Y x[f&ee>He%)`p`JKǀ)ރڅ"tE7pX棸5-_+┖XNy&pCF|-lǁ;b"* p%+?oTrx cD5@8ÇI[-)Vtfb&@ f E]Rs q=I ' [ű!Vp]Кj^etEӁ`>ω"c %A Psk@3/rx"2fL#8Cl[< H{G V̌۰ZD`u\ӗgZ ،d R 5W*Mʬ#"ߞYA bKﯪ3+gªa)A]{ H" [^D s:!lԜM}ExFNޙ.H{?Hc-ĿƒlHzs%4PɟY: Ct`g쀆{ cn<$(tl2J+rgiuK=B2NCC &d :,m[b4'pK^[%1\[ a⿌g&㉥TyMbb"Q@A? 0W!-KeBrI?(? Y@hI `G: 2 ';cPWsaifk{Y{u9@LB[m'#h*bh@6Yw-=7G7qP,9l# 6۳=bP\ @]Kt3 @ j e3rֻy@#^Ǎ(݁T 90Zx%#PgGIȚQ|1CIXlH!9=wPSh͙$a_-&Ia8!ы{M OW'k1؈{xEkQf-R\9Vؓ7sAo6,쁊FT DJym}oMf]ho_] EL&YG@庳Qet48w,B)kn[hӌ-3 H1Sg>Z@>>E$]g1#mh4"hRۆx VocU'O@ +kOJ\_R241YcrnnGO~uw֙!6[>ͣSIej@ $n 3 I f"CiP_^/qHc"0T2_Jq bl[;x9,yMR0Rλ?Gr3]wmm|ȥXuzc7# h?^dCc,A@vccZRlג92g 8s5%ܓ 1=*6hBw}1+%,% 0ͥ ?//<>F%N봤‚;^ˢ !^ƌN`l:W)%69TV,ȳG^!Sp@\mf!/n#$!&=0(GO𵐄Rh ).UՓ<,F˼;m∈͇65cUĖ 2h].쑆_7i$lO-*V{3I473sB6JML:U%<ڤ LdznS:XDe 9`@#!%,Akq⍙B({e1YYC$ΕW:yjJ4ȯU6-YDHr`}7jHo0TM$H4`nt`eӰ<#FqLWo"f2uK)đ+A{&>QB Z}6;*v-k j@mоma9@'V j" pp:>U = aCY7fAh]>Z%F`7FNYGԝc0>RJ;)(xZ PyTB AZVmmד''smFս-q9 p oV{GkS9(z<~<܅KYN@כO"5Z%-ib YHh͈ƿ >LAnswAKRM$OF S,y XnAB9E$fSԾ2zw%Q1|cy akn+88fFDMkj{c4Gh2oxEUUhUvB+Gc-380ռ~jtuTM(YH#᭝Z19ܗVcqu\^r#EYyCik,<58j"[/ΎD,c75+KFhK7ihzc݀s1-O l.m_Hyb`r*ƫZ[& 0Ϊ$VbZ!F0rKDJth> Tn ifTO4آaK{סDh;B_g-4Yt_`O(E]Yk5ўuPN` %޵>H9U gfBz6~ϸ惰ޥH:!G&'hGSf9]e6| hf~_<K;Ư9lZ΀zK+pY 5s."-h1$7kUVo0HxX0?PR YN ^w2:D52{XhxrAi*c|ti$Srk)> (5a$h2F,a6}Zk,M5YxV8f`|+IڠRL[&f#*>E_Ė4k`"cDmvp V0FM HA'q>XZG$I԰!sD?Ls`3[3+g0?1Oj f/0lʀ7}MhWB7re0\Ѫ5{vL28O0@-Mz0kv$ŷMĺq.;Gh~70DGu(&5! f= Җ|ZѩHG͉]QzKGwɇRSt)H ,E}f "C0hڦSUD%guq EO5yecV~ ;֊A?ɨ³ζ*>Ԫ φWBEvG(.oJaxZPwps kf8x"Ŭw63$ >eTTG  N*jMTƒQټ#u.2۸$:5ȉ&LpbݖЇJ?RTa> Mm ; -FG E `m iĚ_q?/jhA[{=Zyxra&F֚3="-$I6L)H)&s x!MlVA _m"j9FN3|aru͡CQP(ݞ%%;C>2 nF)~I-("PDGG֨k# d)j/k6%.e}KW 4D FQB >4AsO42N `>Dx┘mMq(rbPBQc7Q1IM`bAk`SN8QtE #boE;S"i [mƵ&;5*=h:ZL`$w.wj}U|ԇd%vT>u@A=qui][k>x<AИǙiu#c%L{&ɑHvc 'O9ZSڰO]OAWnGSR^-k)p,J0ٖo4Nhcc.,)[>b|J|"۳O&bM'v`fgcNAg18.̀5l$M."( q3 f4zy߆GGHqXZh 5|L8}*[>F]8u\LQjqBa5D)u|m}eabMg=Ƃذ 1‡Y*ޖi.&9`464:s/ly96y#jgՍO —I+/\eŃ[|Y3c"Z,n](z18x(XIqH.QB8̂ Q5ʚQ1E}(]o1$k_-ѣh'r/l|hHCgt3@π$Z}+I=5bW(>]=1_,B NmHԘTkBRt9 cFM3T OJ^ v 7lRX6SGpm(EEX"{[/,3 Q2JXFiO>e}jV~iCxĺZ,+ 83HVJVq#%$g5@-^'ZsXaA1uE(BM%#"xd`$S(8:/ȝN '@D*r1raSbU=kZ#%e2m V""j3Zykg_a|ڼDЕ[S6+I},Ц(6ܲIGϳj *XlDQk%S͵_O2 H\l7hkIhFk+ݦb-ݱ-1cleإ"aPY47EMւ?o_}ax xsJSbiv$Ucd. laq=:9B7ݔ4΄^6^gĪSk3JīmXZ[XOeaҀ/)6V%C@O Ald5`42JӼ9  jX#'paSvԜ=CԦEdpJߒuN +kWS%y.pUT^ΨTFkobR-&7^GCHR% ^""%?pQQpUxcN8VGS PmE)W1&*rڷdTȆp4](b0_0~Y+:N1 D?ƪ@r2 lF[4F/1';qD  %E MSִ6r1@`۔JD*P}0VPv.Ef(FV{:;&VsaBl?',㔂y xzP;h_4"<'4- 7YiBO5<[q/\)-(d3L.5F£1ס)0!iHZZpk2 e6Af ;sK,&ߖZpAT q><:O* <L$и$m| N$.$RTu=j H#R9{x-2K-k! _Q|C>5 R,8A+"E.hzZ] ?H}AnsXCaK:?#WUMU*99nP#/ń(wɳ b3fPb0l'yR66EXjqB |/k i -k b1M"?|7nɋw"Yy جnz+Q9m>b&pɴ6c̢i.V'Ϝ:8 u+bt7>D$Qc[;tG=$@vSo$:\>*ٰl ՙ&"l1oSŜ *q a4r~$H[j&:0^\g9DPG^*0fʝհ7XpY2}E6knxf#icTWu 86?*੯OckG'ɶ4F< T)m WXdg &J؜^_B|^j;?)َ]j==榸"E1 3g=CkvLlR NاUW ᒩ8VubJy>VV>}?-PO8нNˋGu#힜(%i&pdi|+Y=hPѽ7j252Wv8Qe$Ix_vBuRs V#+.FҤ' 68wm™F$jU0Cu(3w1:Cߒ/禨0"KfgM1::7 >#K v:7N"]k9Ioˆ+-a .OA$럍_XI2 p<] =_>&a yy2DfaД39Q+L5<6q6u25#D]38CV/؆\e^,GU_B _u+ KuR V;Ɛ DPAZva@KȌW7+ѕ^`vgD@:u pw~.iGɀ V Nk*9fv!k{ѣYh.x#|@\ZCzJZ2"Sqފ;IE%4r'ISC~^hb9]b֒,!Q.+miqZ!=N1LMGܢ>X+j @4#mo߾9_ךa10Yϖ u@D"bKVOhm*BDVI.0DYJ4\I6`\P3ҫJ:5AG up'p]5[5I5>h}&8G ѳ#F3A˅%gq#`DvPlTmirrHXj  512e{V~`U/d[nd3dL{ij݈Ed6?R̄]ݖC$03]Cumfz8J>zz9_{z[l qlA%|? _{m=9%Ģ *K]Z(kR=O;9B-s/z&Of TL\Lq6Rϥd2n*%2kGTgW_shƣW(2irG%}لRݙgF҈GV$:oäs.lb{Oo`;s VEMO2j(VYWâUm!HdyDM0r=Vjڰ^3Ah#l*Bv]ʉ|+ji~TlJ%MmV&WPJ*Z:a=]Q MHniogBEtRg` iLRXSa΋\_2_7[7R=[Gb&H>:_[|Hx 櫢.Ìƶ5qmMčQT9Obh{dފAze;_~~yf kd$sйRJ/DI`{-`ai9Yt/bM #:9X`he-@QG]p)Ք/AU+\lHw}} ߙqg4 Yn80-Bkl acJ%djQ?k8Ĩ٥]dnf&lBgWV֌Ld~A6#fMBeP]w5B*]5;|\* ⯶,xkVX6AТA!hu(0|G ֎6we-:$ O+ߣu'D!1뉽Ő}t[.6b yI ڶ5\-?@fA~FŮ ˡU e1;DMm)8MLmP6ϯ k|WVm)jO:rP,ՒXeTsa4& v fwEl^eQrkΊ RArXh)js1U+p9EUNbKQC*3BIlx^M'󸉭uaEqT0de '{8q{Fhysua_ơW4c_mU^$ ~ufBg-Nsd %. è ɓ 84> & /"k-e ?#G/1.gyXnnPlTWUvMHvvviX &zњ$nFG}LH1 3aׯOnPMюcl^ n3[Іc*qa4W)` -w]eQ! qdBipe#K$Տ Jzx >O݊&^95'0{nztd6s;OEn82jX.j:Nj1 X(08Ki'a _qKS:"Gvk6Zf09+H)F{79aj>^s/\YhiBRl DnԠ 爸goߜk*ys=R]0*R/ iEis&{ X=;`x~:t `&Q@MӖ9w^K^U3ͩ``sZp{VpȯVͱ Z4O}oBhdx9ObF~@5sS쵀\ ɑleC7t8S|nf{O[3xۑlP5|O͏tde'ws6~y,x=1T߮ok>Tw@UwZ4hЂ@ۦ ^ X؎=(A.g. a`R^UDMT(>NbMhō"la 7a-h~7%~NRLV-8m& DP'TTm5'ېe Lďд-'" 'Ajad򓖬(p#Ԍ~O"aK-Q9ި1<"_7&)n9\XRF. Ư;Ch1j-1ٕ5)7e_^=n[H#+ͅ>oh(?uXZd^S5+{]y2,\4aO*sTlNIy^6=ѿ} +\A^Mg wp܀`Ѵn ˨k=.&qD^ץ'?lФ $1r/?<ݭwgEȴb+PSiy.O6|ɛWcT~:E.‡>? k3}opV8+4B8CPT>|~Ls 8r@ccX cuBn0)+f7<ÖP/pwckkf^^* G>Ona?Ǜ&;fc[ȑE+:1y?f|7ٙX_c7'q ,[/~AHxw-JRT*Ui3ܒ,kt(=143}f0rӟGϑ3VK4  4{@Fo~y L%*USK-moo-iLJkߝ MV^!v~ +w!aŕySX}rsp^-e(\u9dE쎨ґ .Į0E%d_qr0O`3>K9i!{(_PD |d,A"Bń;6R+wv䤅;S;}RF^*({ ;Wĉ Y& J᝝fe}(Rk8qHLH9M h?5H{ 6/SE5oԺǵMŦ?JCuB7!0 [lvH/1IXS5҆rvC6d>IE' *h9ٚITLqbXJB"*Ģ`avXTo979r5ƳܟPS>@hX|,>)`ܦ!AWc G`0 7ȵ1„.jM ]X;ȀЯLu ݅Z;FF([̏vA^n'W|Ͽ^XUy H6+@*Eڹu['Dj'FZI`މ qg2xS.H%kuQ "Ia E1Z'F&7 =G杓8y*-2 iǴKQ~Mb]$5xf6 G)pӗ//Y5Ԓ5D»@璙{#gF>DYUxwgӸ5ơ@%]:aޥhacQK4v}9x ۦqݾ%[ǍtZs2Nޕt͂3LC1pPB l>zfEtDɵ)9pt,U"bKӥWK; lǃL֫%<+K\}ʝa2ا_2ߛ]~"qvJh̭j̜;K6xlJQ.toIBtΑ4Er!H.orqRwif5֗_eOe;ְמ6?pan.dD SSv˔% \uRuTEz(-JJ q}迚m-Ğ Q%$zg1bm9D{=EDnOO$~CR-ҕiW`Vu R΀4 6B4 d3w:ߙӳ{*nۧ tR *c-Smj*_H|P'g@uSźR`bkX|Bfɳvggb[yբ}Bɞ1IRMSYL3+i>R!ɜ#l&se"ln)R>}lC,KCK/Ry~* -?I>gg$ɞR֝4^U#<:;b6uNDST\hlKcWJQXfxNb- z jbv䡐M.' _k躖*W܁bL/7[:\hZ{#~ij&g"kf48.ƼeC Ҿ4Dʽ--g?Їxa+ ,]v[l] B87|lh\i9}6A0Rzf4#ZS`C&mƏذ2lfӉFĘJ7CNzj[T4j?wq4&E[ߦ4i]\t_o inc#NTS~gO=9댛ݬ<R)EU ]bB[Y*(iMȊ(N*$F,*I]HNB_&"agiˋƅ8PUۋ4EL$xZȑGNf2_ Np J=LQw*"H0r.:S1$m{ш¡*hL$3CL81Lѽ)> p S %*͌Axf*w3jgQxWQ]Jb!`_r]J0!jt!T~ 㱈PS1A!8d<59dN vʚIf %Lrr6]-xu1H;c@=' JG7L 4ӗx|s^8V-*Ə{f9R>}DKvl"#Q72FdZh.]Ɗ=nMmr ,2 J!K?P3S3Jί^sks??]\?WM|ЊO^06I7lŶgb}q1ᬝ60R \\t>,5 ,.,%$ g=~I(%{&_ZN dLl{#̱s3`NØZ^M2y>AO%N*ò$rtkJ_y>.~D8N9?%DO)A+jH *3i&$`l}Iʬ<PLqɡ e`FV,0LL@~ҟjr8'7 TZ$@-xF)g1I(W'-@ J8 =Hh|L9ԀpKpB@@?.b.,+]/a%6Xhվ>Q6X;"Xv ί~ŔG:YuNS t!| @/N(0\~%u IEIqRRu!"CN^7e?r_Kk˛__[^{|Чͩ1A`o.t{ui:&>+W1ޭ.p.hH) x$ o$L*iQhg[?oyG1={cA.7zhk⬽] m0~J~X/~}f29@`+);qNY U `;x~}8^O{v0`e`ӞQ}.jz,t%ku\F1QMfBMǃRoդ"Q$=4"vL vIG S"t#J"YC=vV,-k]G+arF̼舘b͵;XGUŖ. &^=7J~qԜan _p[IHsmPyAuXeZTB0>,p7+f yRU"^OV}c&bAZMEݯ3vRO1餩^;dʎlI'<R%BbQ5:2& ~_q~#Pg?Ub$L][>37vrGs^A"c&Xe6hdB*z))G$RSgOAIZ# xb ~.3Zzo xFRM#L]w%_$7#ÓuI qT94#d-y?A5/"Ҕ;V{ 2LȧsV+> {PPP~'P$3wI6[gܜd^"̒إd*U*9r S29rY݆)ɛz+:Cj)*3i4&T~4ݪ9b .Y+ Z#/N B<ܯ`0-7W򘸃(ω03NkXGבFE*0}?M F3Jgf蹡qDntiIAI(bqzM ~(8DIFP. G\]3Z K^9I {Zƒt>h%*j%&g%N e61B!/ڰ2\;K!&oSIB B7Fĝwp/(SVUjJ9yT<:ST-{s.': jD>J-s@$P~^Q7K8%:.2-eϻu7,tRS[2n;mȡ1:?7wB;S:/OŜSkْsb0_P҂F"cz2,.x% DRRV fĘA!<1-G) 8YnRz)!BUͅm!-:~4Gߊ_;7sĩi5ȑ/ƝϩrV*g/}QOǟ-/D6K?'/r=W=Pm:"1>ԁ]N4jpn?:@$pm+^[_ͣ P$C[/EzZ/[a_ brk\9_*!cN*&8BM7 zO'e?煱 A_=(A%DS9ynjr -tDL_U-S$G䅏$xL(1=vǔB,Sw&4.a 2qwk{, \OL&mP_ _3xvŨK vw1rN#iG } m{`R"C!y(H|+ lY2拰a|aMwt#:| Z@$ᾂЌp8vGh4݉Dum0HѠwosH1z n٨'&$.m\ڃasb*3m):{#,_q뇮=`oL< ~~Ol&WWW#㿱ZZ1:,kF4CFH^Z8B+'V]Bg'5jAjm/jY 5vO/g3ߜLNOT9TZF]U5XN˰ %~(s؂1tKJ*ף bO>MKlb Y}")ɉJlW&Y}tv픤dNdWxqrɀmWqkK}z|빌zeY^ȰR;E'|xہ?E6,C*S@FGPmf*qQ8\L2FՈ+="F f(tAn{"uR sNGG:qoP?,+gaEΙQ)8dNMn2q́;y R%>wj@]{co!0 P:,={=ZN \uWk#Ric-8N_DZ7Lϖ.rYZN~0(;_%C,\R%%E_r67<{V/)>ոfvJ+ #6#*^"wP"l^9eô=h9=g󬓇K χ4'0_oue6>=s}mr:!m`ȿf:(},FAթX-+%xM=g uR۪II EA՘}Gx=JZ`.t2_@ckȰԴ=_U VkqX],MH"FASÇͳ3- hrW| ?Jkz7}ŷx_/V|"XY$;C_( =zm_Pe(*X䳴d6g6;UJz!f#4IaRjHd.k _g^`A* %6cnRP|:u @nߦobZK*\/-P'mUT$F5\U6B\kbaL٫q<##"zD | Ub"a" 5_cVw}8}}Y~^G&yc,տz S)s=1pg\ar \xx[!2 Hka- *\\|XNտdɎ[)L@‘; Dݏ! -)Z)WҼ<kq햱K哓%P-J\H$cvLXc"XgU |սx ݎggTWdSBJHimT$s"cV#pXSpS5 [q,<;5ro傣K9og<1]楩YfyeIZqnIyEѺH#huu?<5{1%0\m)+>~H{4j{nėi^~rQRSktLI:'?4kѵ; 2Ӕ+ SagIGXm>~UvFu$#໕գZFKmqҨ?;9[mBb1ۆ5Sf}cD&Wm*fGq*O2ӷ 1&+TzBN'pYTh^(dDd1h{©0f_/3mӶcJP13a=13I1Xa̠DxAcVXٜrL8ˬuM 3M1u]09+0[&ϸ5i"4f!vyBspZFyHū^YMrGx8U7mԪ%ТF7-i֜4BQCii@f ?hkO쑘&xK#&; Ú76xr,p'7&Hi zTM$Hԇ p8;S,uD7*6`(:Ma$oX'!"0|2s}:EgƨI{H〯g3XM 5[]ziIA0BAЌ`OqWgHMn}LJLD?I'7y)kK$9DlvP#*u)-39o .^غyP1;7WGl,LXm%S퀦{i.٤3).s/Mmc>@ {ũ+֚[ bSᑬͥiS>h@aMztJ9M'5&dgFOWK~EGAưI"wЃjN:Rq93qt98PʪA-SS>8Y}1t6òFe|A"6oKj$L߲  Q3=Zk,5 lJ J|peJ󯦻!}|7|+Tf`E.]=n o1 76 k則=KTV&tb)ki9{see{|ڵWΎOov)Uzqԁr) k'A byH,/W];X|_9^[<76 ZoYW3יQZN:☈JimQP$H[$߂xdVM}EǸZ[]+|]kZXi!tdJYXokUo 5+S@4z5c?d=;DWQ!\Sjp Y_ލiu:fG(3MЇpC83nma;[7|| rSߡo7fyl+ճl~Mۀ*olMxJQæyrܶWkpcQY|V֌?3k?|Z]_ٌZ^i,MVSzk%.wTtiX%6ݹѴ:z n )(%mB-;FξKM{TX5fĪ8iLrX:yB; MG gz6!podmz=1 5Xr}7ʪjazT[a5uo,+):=&R!lzR A0="V5sySTo+ዧGnw?) 2 bvQVj&ANb*o[X}4Ĕ~\xgQ nkav>ܛqySy7xMO^;U f\N#6~~`vjGǍ9K)R 6W"Ϲu|ywkw5U|yy~m"/7"/^Mm]N[1ϑ}yY/./o4ViQL>T6uiϼ3ܢ»X;&p8 Bx"!B+;Ϟ98 eM6vvx5`ɚ1y_A7UK0i̡l@%YĔ `Hvx͌FMɚP'.pG`wvN_շ}Ķe:`j7q80R(gq&4fog?(OsψԘ-R!̉(m~UD#,RY_yI@^nIxd{,7aAEYٮiN1tEnj7̳heDMDt^81Tg$IJHF͢;oPKY?]ktAHTAó;E[BX# quffgڜl+`В_~WMI,:e';`X0iWURCiX_8`Ɏ[]eZ#FtHE6@z d|5C%Xw%\[a6sReW5?~%+ν1#QTN8=dHA{SQx0` Yr&cSLydAz#|GO <մyڻDvl< ;c)FrԊJ NIj bIFq9- 2.\Ÿng!X FREnj6lLfa=XmHk3#O= =:r!\Fz^|(6}IS}xzCNo"|)I3c)Ɯ3q`X:U7{[KzՓ2<ߟ=>Pk%^<,˃?nɃ ES}$.VK`uM=vim+TZ+M)UVA* @uRڤb+hAQ\ڐҙխrpu"ok,ʫ(VUjՄS8U)][+R][-W䁴V᭭bRl]b׶?l*{RX񃚂 [vh}U0Z_o_]BuzmWB+Rocm(X^Y=7oPm(6{Q[5Fu{Yl]^u!|{Kުζ0vYc[sTj&(nAYu\R\20+ cV^ʫYyuE=X !ʫ[)#^n°u|ZVD,oV-=S, 1ˊ=g{={O5#-I 25`&j8{n{%)H'$S$)B@eդٞО)ۖvU`[=(gۺ>K=%k`K=eUe{{)(YVQ2"Dʊ!*ᵊⵊЬ!|^Ti*[F*4!ME"LSQLS(NT RveUUŪbUXU]].VGUգ OUMUdښԯ׶Ty&7Ջ-y`pSM[m[om}vE,V;(L(u/LUVnyMJm)K˛ʦe˥=!`,VV*WDaW]*W aO ˞ ˞cOޚP(=ޚR\gm)ZPSkP*1 AE\YVzW .$(IEP+Ujd·",SQVՊB"V rUN+WUqU\ \]7DՔݨ&{ښ*gkJԄj-6rJs/"yF;́*O[g?g_k 1Ȣ׷B?{ji%狋B`t^ F8;7}tE3ǕF#dvnGczq~&W;(:#vvB2j$OSKCItV~gin;/xgO2)Z)zw3C}T`t@nIJA;#%tK.pZu% 'U9;NW[Ǎ@kY!Db<7ꫢhpo0 CQ -I3^er)rf~gKr)=e+'Glc%хa] `_ T`yGTWMWQ>ȉ]7ht&, !Jrh g@\@4'iUj<qѹw0IG1봶+ gП8&/hNnSBPp^p4`֌ǥEgv3 ouZNgtR_4'"t[RٵH5/^J%+5l4X3B݄w+ƌk"$ D0mdҞTH'ohHCTc%Lt\_3£taQމŒ^aWeLy`E2e^41L6V~r(1 {|S>{k[-&䄌 E.Ifyiҙ,m#u5WXY|fQH׸$2꠵윸} /qy;>}vT{9FR޴Ncz283EGQDhmg5rrv:eT S+CmȥE?{,^8hP t{ue:J*ʟzx_F̐Im3| :)u/$cC;" hDʾVWh/ƌſ~)jFyW1 G͕|ƌ0kk?{|ƌ??wwbzlVVW776W7gޑavCxӞ{.b1w?zùyLRtλ]7 ?t=w% ȵNi{{} RBpQSOn(蔰?K4xZx1p1=sk:C(A5|4ti^gkح^ݬx8 qZ mHݹtɮ7WJ]2nG&W]QI ]cڨT127ԓmSU zF`9JJӂ {2ewZ.EXMTÖ6.PX-<HpjiCwWW@T(%DΥwЬKt9 Hy j] 'L c>dgŨaۖ]h,)mPT4`SQRkV6Վ˿`Qs\m#xn?|{PAc(/}>98fV/{bV޽{8yW?5k_'Zُj.OQ=;9jԢ4b (H_WT ]nC=7ApKF\m@/oks}AY0u([9&J:Y*a۬>Ez ߏ5qcRqWÁ7}R("C|z.jV@2w^ 2L~ IOAϣ%4X*>QUs<[A:B GsfU岪ͧEVXI_G֎> SKxCD~VbS'de IIftp]@gI>acdEI0 8:';W$-%u (%j RŹ a1^w!d_"s/'ss`,f Wa>wP^魬}ZCsCqV%'o(/0`*yPTh6P\=TSB0˕NO]c/DʪolAA{=rhJrdW.͞"-ߖ+~Hk髦?̓CZH9oT@V{|W>c{OtJYpZփ~ ?WMP51kruh5[#Xwĥ 1f#79warD{~jB@-B;?P0 2 I>,:S N  iZ ؄i4%s'+hv83 T^vsJI\ufXqK0KgE K k 1Y21>d:quj{ \|qTq[DFM8ֵ*tFCy +,r@u4 |Ed3Uyh-48Geu aE5p/Go"5:D&6)jYy qr|A ^BG0tEF/} ]y4y;0rX>HN'҇5bǗIjӼwGݏ[ݏŹ$#pfJ`$󱋦"N<7[!(($1$9q}qG]i Wζ?\n҃bӰI`LOy}MOfbݜTɛ'MGs4E/wn>Hco=|A+,y甫)`ᯮ <誝9e.LzP^@- DG Djk^lH}!5a{{ÃPÝSDzCRkx5-ŔAtBq]!$9=m/%dZ.YR h^%*y $ p8 QÀV].45ACu00g߿};7o-{ӌt &ByB+s^nBrzn#%d5IF@e)aww& 3z'!,Cwz cQă"O? pdaFJEr([~60eEoApaq$LMDFG6(9Ei)Ɛ)Dt]8hFT>Gbq;Oܭ;4vĉz䒃'&r@%0t#JnA\ܸdjq]Y|c(*D_dH{sAR,j,žd[ʹK|^5ӖA%Ejbw"2XMjJZPq"5?,]S,j )2)ҝ)f@bhiĢٸw|$Ҕ::{#- x+'CZ+izJd3eAdh>3AX35[1PC;x:wyqZ??fd\'EO&TR4"BRߙRB&wZJ4{b>M v ii:%R?xNH:1Hlpu2'}dk`ߠm(&IUN*vP9<o%N{<zR+8x{Ҩ=:* 7)C Rlg^6/\>fY!Kuo_1Z:x]U+E@W:6)E\j ]_YΩ!!"iho%z [2xz$cҽ-`v Sf̩~uN[b'uTe<)x, 9hL jhGفN>iѡ"}%;G>j} I2&FZ8'Of EgW~P8i겣xXK|"o@Z/ a04/n_#P8m䗹߽mUy-SÍ!m&Iұ 0`_[& o)OV[ҋE'aL_勎yׅ$G q$y^tl}0Z-sz6KҀl@AX@Ⱥλ>lZ4ys;ҰE *5;_Bv;%wQETyG-r29e“'\N"^LGvⰖ BU ( kni_Me開H9vGѧw.H2s7*6MB偍4L,u StQxh&fxgfI䛐_|LJ+pꨆ+p܁)0c!k>B"8(AՀ>y TL%. DM~L H?,;/ pL lڤR(W7 ɯC=&LGWR Ƀ̌gN'@<;VG 4~ ":.ˠ.ŷNк PQLzbΖ\W-C<9| jeV_5T3 }88l4jgu3_HCs\w]=3>NJE@ E> /,~s5GtFEΧT!!t~K}=FZTrDWvqugz-daѫn{̓q&ֹj.*]aciLQ\YY\gI;uNt1s@.0 ?^*2<ޔR>x.'O +u$hYRNmɅO6nu0gV[hzmw: w^kC9Io{Q^c|t]W̬mH",,({q% #{˗64rd,5~턯76G4xt:ӈ]+?&O {lNMA:-#}FD9 O%YJ{1ϋnTdjx 辷E, f$YЉOMHTeuGT&,nGY iJv8y3qD.o\~;˝=h|݊1҂6Q` A9w,cQB.['jKz^᧶"y;#u-HS0 ,SaYʚwCW1:#ҒCQ.f?oeq{l e] bN8abw̸"/chCa7U~ɒ->fdB]$)͚2,[⪟j%hgȤ Le{aQ`1lAF[MLz&O;滨GUVN"ڸ+W>L*Bw:+Y{[Zt^8o+Y?KW&WD?]ּ x!S26i m&0Ww Bё:pп. _u+'OԒ-^Bam8\t s@fFy o!")+ ` +`hK(fɎ㬬 IlK%eZQbNiB7MFEgsQVOy{nfmd ߇cŚPs)mqGԴm: 5e|(<$jmxJmChFz<)Bɯ_DzP#FS;>q޵*di|BBO3PrX+WãoV|eK=QD=rIPOͰ}Z8'Mw=酹hdS{ W8{bo™*9)/i~4$'"6]*%&ơcLh*XVol!zވ'x Hu 'oh&q4p(}eݤSՔqNqAv "3x=\ዩ{짵uP[|B/>#Cw])ʹj\6n]4=NO0=t\oyb'(OMw# AρޣkFm9Ql%T]*({+Ez/`à,Ez3DӯYϺO(ZoG60K K0C8=pgX3\& XmuM! 5cM'ΈL5@@4&rx |wP߀{ 5@4`u$`Xp|qj0cƞpȍBUĶ>0| L5L[:5 IE^V*`1]`= V/`eߨ{&jec.BgĦRxKq@ X`117)ϭfmP;j3;rSR|) !.4hw#||.?՝/+@Wzvc-1`o?tz#]8r]\r`Bq\X(ܱ) ߀]Z=KkϢ@7vo=Tz;F)%*ܩg{37h]NIMaӚ:&uiA`@ސ(C8̇kNˋgMA.<׵ǚakBꞰězwނ|+CCyKѬvPL|ٴc-F%__` J"}G>d?g{hO$w^Y󪰩4V0ɯ\ % hD2IrX:-Ќ0{⻪H]F)Cb]ec yp [t$-ILa}PC>fcl> O#'*A}V}e8tH #P zEU43 c=Lϰ<9I ˕`mgPL\nqu)`sރ[v$[>^u8su 7_pVCXN*յ/q)Nɥ]c Â7 n@wǥNlJTFsAqn?4mLϤE}՜» B~dHRdmg0F+PpFo)j6;~b0> ըC7OAh&l0iaSꁥvE'8==s57=APYa1݂}8}!RA"/ !X5q(~7l=2I< A}@49MIroF*눹Y㸀"j5AkM5+ X5O ^\RꂌE(#秈2Ww.si Ya/gVΈGjՃ:(95j*Wސb (s~ϴ:*aJw`ezt1ڃ*6 #; k ⎛. `6LDM->٢|$wf$.^R&T'JZąEw?kʣJa@MC&?XcFH{Kj"M)3 "zŽpw/y}Xe"EheJ2*Qf%ZFEVϬݷk?)N F#E>,N~%@̨($l1)8:. L,3z{|jrB"^aH[w¤;$>A^O .N/ 4vmT" 8KaY`(팝8p?] zVk ½[&Fى::aȁCYeKIP Œ`%G$#W> Օ)dZ5u{9rWLB:SG1~C4KNOL2soU`Q~ͪ9G a]1 ih7b"S0r '"c$Y^M^7Rɭ0cP:NΣht*GIp9݀s}v|d1Ǡ:dvPiF +VY|\ =!AkhLcnj&qrai~q/ZKz6gdn=Vb1yjKE1W b,4!3=Bk?|=89̒LP NdR&H ~ n|`a^}J99$h"e@)z/#P*P F9=JRbfU>"ڌp?y#rG:<` 5P?^]^Ŕ&VEӊ7FFx:'/zAI ^Y220f7c'$͘#N<ǔןR12'4?߉k.?W]O@={r7u/Jjc+N&&c"]%\We)r2R4!4RSzi83'RMҮhi)m!p6'ل}q>t䘍uOf{R63IC 3 Dr}ٞ'߶;F?8tik(ΗdU(z$b"J78 c%<d xzGm_@[߿Uql^řYFϑ`ضjU1 Y#@v02Fq|x:yÁa(Ɣ+>/| ǒc.cВ#HIxLp!F6V ;)a0t'Lעηsm9f7Wro_ߥtc | *9)X+8okOQN$e@A":5R=dzgUu[dw:tw=O:uΩ'Q|~qL==H&]S}߄]N)@{Ouhz'x[7O=~g.?C̑٬qU2qZ1o$x[Fh=mn~؀.h]&ZqggFۓyP^;p{=T{%ζCkh)hK-maIa6#jꆡ\sogyooҫ}:V&y[ `sJF}M5C>>K%7D\Aչ- XJܟe_!{,SL}ذFLkt4f @!|IN^X\CG#ZXHV+PAL2[IUj%WC+g \N7n=>kC ?SyuJ{ZTuY+a g6ݏM˳}9 vR(-*x2xFEHYJ+ $T L~gK@``:r`|^0ӑ*n8\-˂k]&54iG}賮圂ӆs`]):w(ٟ17Www<}հht,Dov:kx8lqvXXV+U@uS6Qs;~VBѯ"QuE]/!"B.)sd $iy v>&ueN?RX߫+io>%ZM%3.OZρ4Ii`9f=Hw ɏ|{a(ʼM?5O{o0:|^0{axl2]݇& 6Y;}wMRPE-Aa>*鳺l5~̿D06P8N9M3Ւ4nƧ(#3eS 8<ڌHYAiON|X5G'9@_6ed( C$=W&'QՒ,0f6viwwZ{#YarokmY_.W5#=>8j ~flMaL\8&7*}A ҄lj5.m﵏Kd˺XV[{mxQ"XZzm+#{1e~dKXlN'{Ǚ/ 'T? `vP@29 UVܠJY<߶3nfޞ \ }]eAǹrl8ygBnkkE:5]36w%޳6}\D gm\N㙟iYmŻ؅T)0H+s=1&\L,0;GڿPt.NѬ` I!a]W+&Ag#;}@Z J\!'76LasJQ072S̃ʡ{l0~g̻:`l9IcL)ۣhDR"E~P6F#\b*h$>j<PN %9tyVXygM3~v9޼ p*I !c:I _z_*YA g\a\Dxb`ėڐ gRE"$hY`Dg֋3g5Anލ"").B^MƨR qF96G/vk+mitfvLX;ƸOc֥ehp=kMR\Ft*& iE%b7m::mY׷\ u.Zm dۜ7m\P= ]io<"W1: ć3ҐaaiB[mvM( U_?!%-*~ҢjP`"Y8=n@ Bц_ih2 LTz+"*=P|0}Ikom`q`kb ߍZs4vEm+).h|P5 P Mѐ,[Smm+o>NH/-'Z{<Up0)) !hcyD=:"ōQEߺυTS44bL2+r`k>;Tx-ǬXyEYAtk[WI "pH Z C;؈LQ9'7gzۦ\P@ӛQX^*DP, W&")`F=Hr†tYIE[[GýN}@# "\4h`>hŦ  v H3O{V)h#..<7Q!'Ռ{7%a  0{E-zlFRD4lu\?7H xzU` 53tiEcxzHG5DȄ/N|4 |ɝ]KUcAiƀE=F} P(Np3iWhۺ'ܵ Ug{YNWe$%߉X`0?n {I5`9vU*yle K䯚n`GwQ`!˃+Tcf^xp!QcC7I` bs`! Rvap^nT"\h9 1-;Q1 J0~A5vR<G;Ƕx#ذNti|`p#g1؅p^?ThG;}RpjK֑># |vô=BRRLʖ*MR*3ӔCYCt<7ͺ ).,f(fnK#?M҈Qw:.C2ZH+u~I/{Bkꁓ-kQ- 3r d9E3 Nq0F:*QďOVwD$ x'X' c.FO( q1)YP 4,'zxD4WQ(zxߤEmlD֏ry<6&*=\a vNfHHRpO$  #$:r8g )uXMa439Ϻ (!An-_8~؞ X,-1Q]TpB sE?Bm]TB_ލgibɔSZ1mF?7}1Hp]tAB)kB](eF. ج816N/>\b[A&>7(ĞˊdVnLCTC1$93;'->#\ 0Dqk|1I٘@5r| e՞^MRdټy<1R0 $AB2:.R}4(R0A)j:•胴qOq&: L_&oF;.H3f\gN)AtL*`UOXɰ47ebRV͚\OXlW {f\^NP¿{е=IkM1S8*|2 gĪVr*+F&xB덇a";KszDmPyge|39ӌLvmNC(CMұ? nte!xҀ'lc,`Z2Fm2BZ:ĩ@|HZx_1OD%) 99Co`Gg2%e_C[Y6-yPx]>BLܓwL& 'W$rFZH#4Pp:V(QBHznDVWުx)Z2.| ceUA8ՒL[qxOp[]/:9N}`/R(ѰxXR@xDŽ-!Cs U|)fŢ(f`QxAhAM=[ /{#- d# Pb[yH}0D'dž?{ wP b)(^BzCGyZh&PvMԷ pǪf]Q3A %}-5nU]ZBNU`ХWIa.Uu~S@J,pNtƃڑ?4=[ C,1x/ YOa\+)‡ e u4=>dDyNYްAfutёaSxXdS `553DcV(^[L!90 _7M>m?9=򄾤5(wcn@d4HFlZI~gW!ػ=ˍmC!<N/4,| $|W} lS.kK:P>W 7RC;rw 2EIv6JjNթOtY ?#ܞr@9mP=Y /-1@{$0d<"W*8a$O:ڞ޼@mA¹e=i7V~V ?+zͫ6fC2/)r aOQ{;>*$[^rAwc jei|>9I`[ctzX"D(&Qj뚤pr!7U~䖪mqQ8!EѷGZW,؀dX8]9F ;,*:ւ/Zh2AiTy %^Xi|ͤpnG$ŏ4 e[gn}|0H pIܗt2^Oƾo.PC7Kzy˺7i/ ePD%ϖ!VjV*v+tDlf]r.?vaԄ h P^ K&ܪh-n*[b P6x8] @\U!_H]pdI& D $4V*o^.bg%iGc֘b!Aa0Pg-LٌJnI"|!7||OYb3}<1I泚b Jh]z3@:}>[[~lFp ѻN<3ڱF_?LרWhW5Ӽ0 3Ђ}" Y 0ogɷv# dp4$Ҟ03, "i.Lڽ}~ BSc2 %=|hZAgV! 璍 rmثwOZ ]ݢ5wS6t}zEj?k'^t&0cV ѭ #A^E0)ȷxG 8 ZUf"G 3D[C|HLlV'.b\~YW2?[ -'(j1,رC<98?~Xg4#;R9-0i=0F6.A#a70K<P=v`vHwJĉZMk"Wx$":J5"b8 1x7+AsW?:]&wphvdH KFnΦg 8۩B-@2$Bn_jF0ޗ/3Sݥ,J dtlzVGrװS(A&#MYs7G2#sh) tq#|*mt`ҿ~u./Pǵᯩlyx _8M2jwe( f{BVOPE( "'CvcID;-h7&m{]:^ J*V-$\CZG^,tgѭ-%ڞe]B~ADm2u I/ZWgK< x6l}Ni_݂>V|h>4~Nq 562mC]NH hh%N\wlCVI=' qx ˮsitՃ${@gdy!6:rp IupWrwaH5R;t=Eahڏ zI >go+QFglo1_.aEAY37R{ʓ?1<2,:KTZեpETxA(AK$KE؈%-g>οjD qo|Ko xkvr 67\Hl桑Z0* Ys҈ӤLd`)5F#'>]l䌽)sMB{36mJ7Ԥ;CAYo]N۩4H̋>9|q{yfC3Aaa)rgg5@ S/,ԓ`&RO00Mb r+FB<Ɇ. A0qE~4MrUƉ'3+vVF pGiNBV8U Q͊g癎}2ߦjwXqYx9T k Q&#͗õxYU(W 2"rnGώ G{vIOC$}S,tFx:c=д$5 Y/, fz*3P B3uTF/gReIǀ"v׮vku9Bjp0ӴmY@A!|w~E:+ U3aPSRzp|&k ia=K)QZ (/ DAg+]^=wxv7b$Bm*x hhEkN[Cu5ީNMw^.-4FyՑbVIlrLIjs@L*{Ҫ ?<>|lrkkʊ}d-ufd" ݤ^b=8rC$vfiHmf$sн/w+aq4F1hb- JS6]V3Ȫ ǔ;Bl>d}8>N iE!U׈ِZURڴO8ŞG>%]SعJk*㱍Cck8IE<&Zn)P #ah:ɩu8ɡ' *f.;5by~goӯ1m) ЫWfM{4i C@JD 4P4YDG&F GEy#5phS<ՙg)ëz%ptqǯ+ Hbr&T)01cx1T7@tgQ4@Z 6tL\>$m0:,(qyћf Ob?ϊ'~0;CL=Nh(L"PJ4h-e~S 6;toO՘&fn?ߋcؿaa|A{4 ixLB@xk sIk+k]Iy%7ܺ >}F&@j:IטXbS,T4:x;F+ K 1~«_u׬u^!MV#d7"kC|l7rG&=ϘuRu|3&8XrwR/['ǯt~vqk#)'vtCZI&WS\\|sϦگhmclnC^,R{mP} UGh7 gm[bV`FP/>)#Z5"ؗ5 Cn7S1R>cD+ffxRG:Nk&쬞/pzIykٵM24@L/#a|qaswͦh~㿘G-~s錣Hlq :7oמ}lZ^{6Kzu6p*Tyi*{e@R\Sٶ} #v/-ǘFgUT3?L_ ƾX`p/jXtX5 ~R!M[øgp]҈<*?\Ʒ_Wk ѥ?𝃣֖}Ժ‰h 6ުRuj<^neِ+4J0{?NiF(>{% ,|  Nc4 ,?٠*͑Y댶 Vr."BKЌd?M?.w-uÃqe|/?8vRRէ؈]b{r"kNm2)yAC|9=NsP0E MƬ*KAW:&HG)z]3HQlC0d Bէ^*&belr<侁\SL |ݒ@c|MA"UBU#,SS5옣+flsͼ5ls?Rװyc;xT56cl9P@Z؁xŒy+|MISe 'Ȫ(>p%=}uuT5ᄶ_tJzg0${"Rq=Q|]ۙK0) AxD"UL< s9_, _n`T˴[`lb'Z6fYw%P ސ`>EJݥ}uܩ;ޔ#\1:}UI;?w=?/e1LZ?zBy.cE70Ѐ=Inms4 ߙoh@r;kT{BRz:=[@|٠*huƔ~_}lwl]S)$7- ob\<x}ST \+d+mc=0 =F!JM:*͎Lؕ@DKt4#`Q S~i}o2xK}8ҙn (|NAOj3;o=9FbMbbdPGf#8C ShDVM"kn^{׳vdFƺB͇zH,pt5LwNff&Ogs-01|؟qftwA)9X"RA|ĆOiYP5 ѼFt8+ M:g6NavT8 լz.6k47GZ_U+UAz|]}ǃKvz` !m9r׌Cv3;OY)ƈE6$f&OC)yjMk{{O{O}(Y|y -xpQy#~ XY Ua"U:<초;= {|QiC~=8y_&Pfvˏ8b^gWѺۍN6cdָO (頹TyYӬܨYAJ{jVb Y[jX'X^ PBȚ6*l ((t{([=5۾PNxB9L}<ވ0}NkW''F< '',Lm‘~&@ |=QN~@nb0._dTg5\cW-?r+O``fn;-v(g`ͦbkm;[Fu˲ai3Kzr8}uwjrv۽(_=aj>y6aܾx~w^5^#pOWޫ݃`!k_`rܛッ睗"ݓWI[ yڭ݃_W/L[{_w{mx*hv`@ R=89i~luZ˰_/jkK;zσw%;$CNu<bDujnԺQ ( vFG! 5M5j]F^5/fь> si'mzf-lCeJ)=Mac"]_C@{mu1dVmZ>.qa׭.q0g :O?}I/ؽ?cukHqJ׼-~}k3o jG[jd̾*b K0`|.ڂv[8b,KEl;z~TYf/Ʉ%> |ɩM=E"2o.6,6PtVMs!I`^f|y>xm(.Vq蟂Dڝ>㣓c48ɪ9 k`cN]$!EO&6Af?_8&Ő-2)`lʹ+iKd)#"15$$G#let6&0v@9'2h \tHJ2d/W)M P2\^T ^m2dY=jnަ^Bi|t{>~u D$QU\:QǑyI4T?yp8b bThKTS3a3=ZiL{;?t_ǔ*i ]Mepl5\\Mʽ8ʡH2"UTH3`u7qGXُ:ߥ6rae«^(U][pÅ3/ߔ:qd~+g-2[6UVN'{ Ke><4d42mKwl`ɟFc ChpaC^踜"KRͳsJ9]^SWq2?X@ļ0F3LEsx!qńwK3 ƀ+Jdڻ`&Z'ODjQ )mVj+ǩ7>J1YK$.5Osa|>הDpK6tCQ"Ԋ^Pz 6Co]+x # f_WJa Y@ M1(Y+z/^;% r ~-{VIr嗊Bƃvjn CX5BrM #Ǣ,~P`I>l蠫;4t-ĒÓ[5P` WM yw|Qϰlz$.eЂL9P pmp{L;W=D&M !ˈGosh@aT8Hd`bS">Xm4/4;o'B^xz 2QIm ᮋB1Kl6q`/% ̼M*Ɓ{uc^N -+L|MQ{7>|+d~I掴Xb˳/IGxL`'8nMovatNy09o5d(sdp8kbDpHJ}cl *?޷`8z/1BC/'q>5y)ϣ?ErS&G9ē;eH񌜀28AA[ݵwΦ=M,Kkc d1 %W89% Jg"IQQ'ڸH&~1#܈8 .Z^eЕP ug%ȶH0|;&QH\ т)?(~:)gyVS6U# K~fWl/ݭ[̩0i\jvPF^]`!NBcdg譿n 28ۭ 6!g?DzfT>f@su:Hk& 9"~-u:V^;b)%7n}\1o s2E}2@XzYV3`Tk@`V40r DUg\0Qˆ:.:ƿc7,yFI91f=~dIF*ivRL>d 3;N1; /ōol3uwO/8u~z숕{oscA>]?篶8ġy7,O'y.v߁u;W% tKqxv_s}*Z -p>LNaw9 XN;=zݾ6&cί SX&q lPs*0ùk1eZi#_{m]&+@_?֥ǪI[{k1*z<"~W?s~opbۺaqFo](sy3\sFodF3wDyW JJCX`P`(VζZҌ9u&qdE. h!51@̻p yhs [ *;תpO:5[r{L:T^~]6_[ kjڿFJ9f?v lw U$A1cmev9j0~O(4:3<N1beXAI]-~rN 8jwe2śF6֕C5@Jl8eJb+R&gFHnVV4$^PT@i)-i5Dv!E3+ :Fy=Mg6g@P0"0sn5lP!hYdՓ aSh&&t0b:[QR$MobOIA4k\4쌋&ώi4Ǵ|ľWт/=XOE=NIdc!,m7})QtbÏwINAP 5/@%K 9qLF4L~V@x(79$!1pT^{MM _p7 ~G)Kr;GO$?5/Q2\2 p CFН%@S'83ےܓ9*eP4Jjn fdTiNz4U;u kNDyF:m1eHJp(DŽ`r$G:97{[o8vLxX?-AK Dq3ßLV1kם[[p*g a~D;at'rD;cY}(*~U&fzK; btE-9O gs'okk2ajzFw, vR3r Uj }u}Nׇ ^q Wk WUo)koQ{kZu^$)Fph:ٕ `Z#,:Exҡ4 VH^Fޡи | Gz{|{ xs >' ǙY5u ca]]6V.94ߦ'\y^ņJlecyg[= ʜMaNh?=G i7MXdhWebh*|zDج0MxёYݓ,"1cžIE{ EŌX&(sƃ,μQT1Rs&J$$*?Mg&U09'k0S3ZK B[!) ,şYd# :ʗרS0266ךMeUGMCHLM@H-"x-Y (> !lZh/8A7 |s34&6Mk5clҷ9=k]l,,Dn3DFLzNa*H48G0@E-цѳw<!#>B,?v7-q!RͥBdl-q!?o8@uVFǩ;3}Q&t͔ғ1fs`';ǰ_6-1+rm#EC]zZ)U~*p*WJ~TVY1ReQ^~G5+7~&+7 Z\,~nm[^d. >Ӫ+ Ƌqs-=y^qu %Z XPv'hrKzu[?敕hAG;lu۽^I;xISǭׇe`@vkrЏڇ{-UXM퟼nuvzmVJFOJZG K~q͕ϓ\pk{j^\"4Wm Z|YϟZG5RzY 0̓v¶{d<|ɟ~>nw{ k^+1>,)t^ҷ) w.7(K/-F^B2qv;]w^7|nIxdvgu\T^Ó;/`atHpu gsXI׷/l1йRTEat;{el=p\RPP`{qpUV{ HVE2dzGwXZ樽cyvLy;_fySM%/); 62v_`sxc![JNݩd.wv;GO$My9+zkPl ~E @˿3n0\I6X @9] 7X`;{;i.odCu*/)ϡ wӮ7φ$_x;_xb|z/oi4O3ҒIǓGcNe^Βad n;Nn;Nĝps' 7# RۜOe ~WgF#EFr{Fgw6w#-ݿtx^y=,LGdf(]7X/3u7("2^CvݧϧfQPnp릀9B47=,HӀ1&1t.ݐ^ Th0|A(]ҥu2O=WAJaJ#O#؍{2bU R#&jdNqԸSj)5wJ;ƝRwJ;ƝRs z&m:!O$i`)| Zq%+/©BxI-]/o?eru9cNY.I?q$kJ}sݥ랝f B]PVǂ;*~(h?{_n >^ٺYS$QdY9W-_fǣ{_L[Lҿ k.gڹwLTA+u控Ȼӧf/#TbH,!`3n [Ag *3SBqrnƅ@'>LGdte*T񳡮ȃڦ[[O |rR.ٴKs/ /if 톳pkkw>P} :/^b`OmA1hAS)겵-@*w (:2dcBHtI HQ(55aSa6 9Sx<5t˨d79``xc}IB>葚ğ"= `L#541> ǃddBDY ) 2Vn4%GYcuHڐ|UƤ9> ܏<b2:R0HMI< ]SvF'&E> Յ&pƒh|>|%=e>doHn[j {N+Nʮ濑ZVKum%w@5`.ҵKOLbyEXӡ-DY5&/y摁m"lPlA>5Ѹ㲉|ChR |{trmk",(=O؍9N㨹E{3,j,d@hk5IUhԲ9w2ɐbz%gR _371/7}<]sI"`CxhӯK {}=Ŭl}W%TvM"v[YrSY RL @/iHA(J]DH$g- x EH?z<lRy 0 ܈ frfLSVbR 7ucSe9b}(o!<,Z#ml,}& >XwUuvQ0hCOè"+-3!-,G K(Vbw` a/.#2k:';%i=g^V#2 Ϫ) Zu"4+6IM|Lъ6AuE>c(vȩ̧c(AW]VQD*^R7HB1s&>TxL<8bߜX;Okv)ǺJ~=H\(1ԩ=F!}DW x,(/1I3I["  ד?zy0*+4hX\D4,r-J.>!7nDKF` PѨJ64מ@kC\lOL}L$狧 U |rcG"Tc<=mn>TlGTw ::ftWv05y\|V#Q,VUq^J!PO?WH 1 %g3["a U.' U\ w# =9R$ $;$]3/05vf k*z%W4%L$kkx`B U K JAHrxQ@a<*nX:>5 ZDөi.-9><\x)J˜,<tIhх W`08biR%xI*B&h~#eYMZHʲZÐl&r *sD]k ?ހh0@qI|qIQƲGOb[ Rj!"Y_4$ΝjS40l(]͟C3lR r12=}yjMbؒ& wRԤZ2Ծ8{(-$=B<l;>ji3C[ls)MGc(Ƙ"hSbpVc%S_Or6L"ZdrOD |rOf<ʆ!d`sa~&Uqs}۷|o!v\c`y$ ;K.p'5cd {D݋2fm'VtIUF/Ϻ6 :81FCOՀϲy뵮s3?"tɭ|WOĈ;7P5 |Y<7_ϛ~a3\n | jcq:JĂ(Ay>S_(}T#(cZȆf(5VqȪe(N g67p8F+7*_B-/J:NĿ-"z$hQŎE-9Bx.OcfًQt*KcMqu|Q7H?_Cls,H+w99@A.@^8ii2RRz TeE:%$I*:T̞!'@\(4ʲ~>eY.ƮQ4nZFXLSU'x\ouNdTxL]$4 M@K1~&AtL2lZxd|ZLKL1P22&:2].MTiv<ţXk`Mb$ywЀi SKn\ زԨ=DkBXƒ~D0™fӓ دS@I҅ 3 dp Tl(b'ܬr4IiT?Վ/XBD%\5Bܜgs:$NTˇt*%yxiS^p؄x)4d ǹbkT/]qh%( I(^] I$<42=aP q>O#RV2Y(lSllŔS^$uf˾t*k:IqvzP p1%bmtތq3a.8;F̹G ҘrʗYä~Tz'A [?~Fٵr쐰ۛcˣ q?& CldXj{&((őyX$va(f+l3[)rd :7MuuV,|Jy9 g$JQFf49<)*]U6:+_U% u C\0˯\kx -YQjk汒ᬥ30gZC8: Dx8 ;R 쭨+UiwZDo Nԡ ( s^E%W }%#8x6[- .Ow?wk?596ネ㍇_Yr9iraƖ7XyLߩ(9Aҧ\J{80(ǵF~#K9#oJYh8ηqH4bǥ4|d_?=3ݔmcQn?C~e. 4pEgzc`FG{qy`7.F1v~{Eqa(~{b, y찳r6y-U;4׭;24xp# u9:'G;!u˒X9\^$Ȣ8X~gf`i4 Dzt_, s\?;yZ'QqLpwC _FURc9,YE °(ꤖTA8TQZLY(.De$H}>~~QZC؉#MսwTQR3@xp^Ϙ^Pf(dÛs R Deȟ:5kr#i|wvǩqjwZvG5ռ;unw펺Q;vGunw펺Q;ϦnzVgm6+Y٪wBZ-BB{G= 7+7dk?Ξ-w h?9=+5V`2d'"%?[? wˬFs_̣/3q[oI?nš=˼˦WLoM^8^a&! ;(L^yZ=2!;ô)ir6 61Tr0X+tNF >W.lyg/L٘(yʹ/\SFSusEפ5iԡk~kaJ:p𱘨 ȬDJ@2Ѝp+3f*dH[a/ve `a: M#E30MkRWOb}ӵedfK' w0!kM rLZ3YXCrOQ iMQ_- p%-Aߝq-ϕlˉ):p¸mV~V) Xy,1ߪڏ}W0im+1H|)S/Xy)2`Q݂3ErMVpx4v\#8;RN_bYlʤl`*CYV mrճM 'CxvЙx̆(sC7j3vcRuA&Z+7%݆Sd+ʣ +ۆ7J(V y ZǾ4EoT/JemIPS2k}T ]9鈍>pa "\m@j>gh_7`PZVժ)ۜ'c)}CojlV6kZLIѠ3hFr]@L%rAk'LD&Ӧ:PtGpXQθ)0Hk DfD&twNEчF5k¦SS '\ ,0MY*iؚHA)51ePI01 ϸf.Gs~9slYp#QJSA1atrrCx\h"7a l/tKu{=lP$ s*~@Բ`5 Z@И*ZW@ՔN"Hq^kLda_(('8MVz- %fG*35F?剀Le(=`'0TO ˀ(:?=<+{ ˷ ;]sYU:RGٱXK]7PY%f5Ȥ3]Bh`M#ʧ4!ϭ6#uN5Fo"o(73!HW 'k@a74 X Uu@UgKspzp T-ODlo8k2Ll2^4VD<HBnIlg9Dkid3I5[ڷͰ"C_(%$3RBHq3 --˵~``e!>#^2|T<Z+H+sh:ْcw$K.YriM=JmsSC-A9E/>p$g %b辱=p,Va?(='`Zeź O>D|Pc Vh* J&UƴD_6[Pwi S+D)%(JjFKhk5V_膆A^󄩕WIH2%4Ep(p̰ C05Fu  IfUDR_LS\LR&1ЄEVvEC!v11АMYuIЬ*SM}czB]W=mN|,Ri^*{VgXB%I%ahw2VəhR[=j5;޼(z#q\E( eHr$D]c5C[OxOI !IjhĚqd@9!B˰`Si^28*Ez/݆"i麲}uJ9F'8AЊ`G9VoW𝡺`?u,8p ؁C_`$¤Q80^K'3jHcd,߲V|txC>+ԨFr;AþFYVP9n`Em2s8?%ĴpD-(D bN.}3 izX ᫤<6#::H 2ss Yqjh往9b/A8LK;H֤S6YNOwMDFQ^A=0ySP\B"42 x(`$N &TQ##`(ʚ)2G(<\6Sc)&>F;m<-m$ I?1W>eSO>vV88rNqPshE23,L ՈM)u 4qlYu)T*,Lafs,QЀqMvp>0H- ܾ /Ar;%jHr9劧Ln Sm RqUk ֋w&OtR5q~EBxHj&xD5,Hޘ ^h4J 3NzWjfdM9X'/)Dg%bU-IW&i]Ӣ} *U5` 8-%laO6,6H%<[R5L}͏1؉ %JJ,%L'e)FRi+^퐻UYmG7{N3QXl=DJh#lQŽErWhnIu|`'G&>O!ǾCPp&(]}4h<$qP%@7Y:';nT-tD$Ib*>۰BG)2LWd1p9ߞ`¿($¬QKO6 dX+ąk)>;1ΧϜ3 tp:2L;'s'R<'| xLgaP),*_ri>ixDdF 8z!̼d1+#;P kZݢ",gBH"1Q>tS&NOIն) ҚOjƸ¡FQ8849! ڂyƣtLEHy.B!PYgPRBFYo"go:2xKaM11g|,4og"فǪBth¤᜙A*1^[c_*ADĔfA5ɢ7= k胳17fHo w01Z#P5f~<M3kJ#mDw x<6J\cky TS$wf_ LfJ 4Ě축-PTcIWO$:(iF$*4* 1-_׆#CLf㤥JZTZfa8M ֛,(M:pɸ4 XHhqqYJ59jc(Yڴ~”8Ӆ2gF*@|GȰV5Ţţ*h7&78og ^A5n`$Ҝ J&SB/K';2;M$fd厴\dblcT YB 21R*t61@[b~\>PnԚԎl:ZjR jU$tU R&ZLTSk'Q.F H@)l~ ܼ 8.r( K$X2%춠qLEQ"&,0i#\,Ou'Mcb9ap6#w{kL2whjZ3'4v3pmm"ŷ+*Apѷ.Nq$OP_I~13ZG&syhj9x~[D lX'?8B#K_t[aiwgkF2z/ F#bcSo3PGp¢"T%֔J8%Tw)NZN3kv̞ܳ6bݦ TfFnބ\/+@MA)Ҭ)EС 2-1,`TNQObfS@FM[ruŊ.mcN> pt^S$D8UPSDI%m&It_l$E3&_Qb6#@2ݧ_NW"&Yx-<)RU3T!K %tش@Inw_6μHT`|P:/[ky$DGH21V!Tk> (gʒ@iZe9A񙪗{Xm+ #EH'_!tCovD $^+Z XՄh,0Py|5. k7\mFr:N#,)GĘxfBkP3M/IȲ)Jc:w+"=Pi9E[v|F*d&Ás~ EF%6NPIfvq,tgjVuG*A8kFRUa3R&Y8f6aDQ`7L]Li?a*$F½ 0/=j+£ NZL*j?ZIGKogd$CaѪ\HTFxlns؄Ƚ&'PhҔg^C?H-Aq/j2@- n}xzÈu`+*h¦QZkk Sr'"YC4[הˑոdj]dZz K\Urյ5ew0 Kb؆ԁ)O;+jh%dlTQmJʨ g:BZ%ZRQl҈lY' ùUSٲe/X &]ߖO(gZo8j'KSSMXlN5MέW`iQFP W7wMĶڅ;Bj-V1j@C9E}wКÂY>q™Z9- qkqD9ublv6!#1ˠкIl|5Ekyk,D7gI& Z51?| q Fg+x_Qhm(ױ0eZm É=L<QwU VG&uFON-k-(|7iV0M$%,!5SI$CF6  *$TK*//aȲN2*t:H3rEgRRRlFfgUt S$^S9)f {(5-.{m6ilǭIAFʷ%Kކ'ϔP1{ Z >٧?N+y}ǻa݋,,ˡ@MA HXrfQwcyS-UZƌc4ᓂzŒυ8 fP՟rߤa!4X[ln"i(|b dC>MtC۪՛sH ÏH|2{)b4!_Tm-C-eI0+To]&:um+N/N+q.2Td羆82ƜOKf5z(t0twZV_u#:ZBSDoj%ZoK$x2$GwB>Ča .S4ⓆzDDx0~Sm :b@}x3&]KLE@i1VԷuWz%֫U]+Zۚu|C׶޲DTW6_UM\CY-0$Xj~~~^d7hA2=!WQm0DmxVvyHԕj$nbn#wHqՒ&Zd+졽z56PzS\WUfqM5Q?UgC_f<76}xXT8z7vY ~Odo {|c/8kV\n*uâ6OQEmnrC̎,[]UyE2aݖ9Jcy2|c $P۾UUVJcv*/p(#jd79kvdQKG¬"2ql Ii`Tq>ڕR5ՠDFඋJmmԥ=6-;wޖK ˅-R z:Gt~xٶB%pvʩE/s<(77\Go}JYI-X8?$SG9"%7%r¹f{'We3U2[zW6GGp4̇eOV%+O@v֩3%,<)2Ѷoʓ97̉˜HNd9D%TEv+ $sR0_rqbl6ݫWƷUZl)[XXJdiP_푾>(p$fvsZj+49چ1#vJNOj 4ƞ-h-n1YatPQk)J2S"\8fvd5 ,6ȼ0=v&^)GWg IOR=I8Es}Dl,t9>er-aa96 <$nߟ7z!O'|e„)F bg4vo,J } .C!fx˝*p\:У,o6[0aS)Dhn K.asu&KudÚƞMK2gK#rbūI+o #( 41Ns4ͩ%KDorJEXmOç 'Z3oKGBͅчsy\4-7Xau-v'7/䋜v MaMqmpĭʥq Y|l7>͊;[Y}3ך .6h[G(I.4;}"{k APpH{Ut+LvӸ& (OAM3Sz+ORUM7G0?V ?EH&UD7FЙTɡY5U"-~Q >baR$vw0qyI3!gq[Y1J"#M8v;RFȝvyEw=ePAhIu9O,j&!$u3w(# ベb\oP;j:s; %W u\S$ZX.Z^4:hLMB֎Bg9;Kat+S`s:?AϛT/$0[s ))Mf얋v ~y-oG֠c^ g'թEʉ۩e,,KIe^J%QW}sf]%OI&(2=O z~;x&۹'Z)Ұ%\Vy6lJy'JryҚ0p܌F2Ln1ҵY;,(z ^%se t> zphX_#V 5r&xcUz7`hTH !XZ79,_oBXU8%a9m4V͛;Ȥ/Fm&*z{V׻͈l UQzNU+ڻ_bNHINP"C%<2'nf_@Nqt=8U-Svy6>!$vgܢFhkM=%cU(I|xų^MxaP~O~Tm.A]A&_aa'SeZw[+zi5nhHԫU.B jO7鴤0.!XW}pV,v-6HeWܩQ&* :3'vg|gkb[5!`̸ ԊZCל0ZL͢S,M(!:ɮ6WOLd|\ Sz)heg_viv u9Nmcum ݛNKYExK52H?1ehhkH3Mܳ)[:8BN!Wŷgx(;)ڨu}'p=g 5ZVz5-N}1|e{k3=ݩ/B-k%ta1|B6&E"'uϲf/Ja 544EO^.]?20@ T_Y[>"OkeAGُ?RATܮKH: EJ mU2.a#ئpTEn -2V;Cxˡ^'P(vcdjg$ h\FTz,oM'R4bnQ"xQժ^ SDuTBN_1hc^/qv4M&;/\]b LaUOqO!""_e׾p25k MmE%K Tܮqw&:<6(6KVIrlS5EM[v״՛V(P %Y=;x(S7yzu S[u% )\e6f-ΘZ3OX)*J?=x-r"] RQNg% ȫdh2  4>V0Q-oD5Rl*5ߏEM@ƃ0 PaY\2HCFĺ08u,: ~2+Y4~E皵Rug0\d6h]OOLXcYdW)nնkb TdQHiԮj* kyB71:7&L͙=*ؙBݖǖBGlRt}ӭsҧwɤwɑ!<ԙ",$1v2 F2. DuE5. 1Fe՚aVc/E2'@8tZ&XYDA3+ yјo}AYrMO$vryKZ'X̢\ rˋ&w$]^j.-Y,N-_b*'ʿpi畷)姞R^9tH'/|4("?NF"iJ$L`bi"L#3Rh2I,πrSR\--%,85[DEY)js5<\͚kfgo&լ]s5;UYjVƕ,0(Y˝Yʝ~fWHij5553̊>/林k]"/V*/~EZM8(͢S,,l9.nCZ8-5g56&CW)G 13s4K}EiUS(vu2VqE-,"8{ ih=14J&a_%,1YSS.Dc4J.1+$4)3miM v= ݄}e $ñ(iZT\M4%QDcu,P*1EΠf;eL9֖&3w>65NtO^Oa+EKrW0%R+@Ԙp`0<; )(5"Wr!%.-HSd⑬ WQ\1*SU.&FT y `}JO+ZQ 6D\P݂*\0]6ͽ7kU~Y C~J޸NSk8`VΠfAuc-e͐FA~R,N$;-m qYpcCASy2:Y|9BbR}ekL9D̓fb g-ֶPz`6 E|ǙHvV-Pr(Z&gEn6H$ a'2ղ lbT(&w0< l2^CގJ")u5u㘹Ye&U6FvUKM/jo:[ۮvCG\x5gu3}f:J cdV&qONl7py~z+sfURoZ>$ 3ex,֮noS_yu8" |lY H c)b+K93WXQ.?ӆGѡ'lZBTŖFG]ue$@ЎLט0NΕ!؃_Y K3ҕL:32&RNg'`>EWelz2Y?yo39}f %Rgin^6E9 tqq!UN5#&-IYw=dUc) "?A^={<g*sA^wp.dh"'#"$-4s!'bl0AU9b%3^x;eC5sQNOEKv23W@'@:*|c_zf QT--t}0Í]D-IՉK 0^VT\ˡQq&ӽ킔H}`c|wLϘ#i4E0q3c9TUqol< oyƀ[X5/W;tk>)%T&QL#X]] #QZ8,]-׉wr r0F~#< 6ORDY\o4 b^i[l2AUc#xM"Һj+" XB3M[+TҚ®&JV $mue{'l@8e/K_+FtvQɢo,k Dt:E_zbFЁ8|IPxZˈ1VMҢQK{Ӟ Q10?!4ϋIjJH$VC5 IxV[](7oa\do~E덋.׍ ^їs~yU@WP?Q=?{upojz}UIN ŋ\Eƒ{ty/stj39&sz Z/Dj4 k G (DDʥ>xLF\*]fORI4:?e6ڐ߁Q9ZkEnU1κuGCOpCC7kcFc dW ef$l\K `V[\Mbh XG-@"<я@]ѧyPHxɄa4^c`P :A\sLD#{$1&20 h >_r HMAə[өV6@q]G_{|8nCVAgN6 _-ԩiiS>9 ZQ|'z61n&vG߹"< @)g}_17؁卲 +k1ڲM5>YVy:(Z5Tպ%Ia3Yb(o`ڤ~Νj۲9F 5 {]cMްg&JcvMV։}pUOLPB$5w-kN\SHK&Hb{"? ar;`Ty@|@i, 7riyKPhr\Y^N- ,q#Vx (C*xGA[ jX x>>'C1!MTᒙŤ3};ϦFX5D XEd\~HJ7rQ1 `mIe:AfQ{ fA1-wsd9)r7 beQ#k2L)S.(YDz:Ѹ/m2=[# fy<4M $]D2Z>&zN -gg" 0N9}l$ a^Ӱ|69ӦXST"JN Pԩb,7iXX[tU>>/H^k}Vއ%4>O+iC&j&1]N lmFѶƠ+Eb̿0|< //1N/ȏ|iBX@X|vO==k\]e;Q}Ѐp ^qA}Eq^Nf<  XB*r)RN딶&YUUs& :f42 [U8}8>\*Q}+YM:&Ц{gͿjRrN<]SsںSMq.=C#1yY*~v.uXq%):FTVfɵX+_r[bjKƊcRjI6:˗ PeSj4ssꛧH)=3~l~^mDU.: z*b+Z4>}%ë5?M9S)Q3ϛt' 9䷀IR9ɐ 4a,I`I/lru:^IzN&IIRJ˲<wq+OI(L>ok/N ~#@ n.2VJ%F0$&O}A)= pMgƊ.YIڔL]_yr\ZmuoeѸ϶5jղ0;dD Tb;{`kmpzMM^ m?o:Uq&k"qX2CSj*FCVtv;q~Mf5Ԇ=[~nzzG/1jzG7Uיԇ~7gԿaous)7'Sծ] :6E,/Ο@ =wW~v \iIQ D>22T'=6#-sNHoɢv#vsW˜Lߒz%'kim%5?p\x&eCl`u\~¿OmŚ}tj"ԯNLկtR7rI#9?8.RX::Z ˹y6pW9Tis2=sG_^Nzqs"|qbs65v[:¸gy=fb8dE˱=Gef^V'ctMZ9W"!MH:B(8D2,t50t笈yQ"u\8 Mʸ SpF+:ŖAmgx=7f2yH ZZաvM[ԥ5=5Ox1r,=b/\ MI?9,Xt{!~/k:*,('Cy S wK ˡt(rWB9YP^l(r@9yP·rBe69PBC JJ5P@ BR c ZC. P.r)(K,J#ˠe%f(@P *(WCY e 6(P: % J7uPCe#k@酲 f(a([DA9eJV(CP0\ Jl)(i((۠dPPC2 e (;2Z(a- SqEa]tX>塭[a+:YsXcXamuXKpA\8;wQ5 CPAy7By7Cy By#P(.((Ay/A7(P>P>P>q(P$A8O@$P>P9((_Pi(_(_5(_ (߄| ʷ|x 忠|<P~GP~ 'P~ gP~P~ 忡 ʯo?A3@_(B+A;:3{'/袩7ђE' ?<ٚNya~^X?/ ya~^X?/ ya~^X?/ ya~^X?/ ya~^X?/ ya~^X?/ ? (~ha-0~X#?k0^?~g6>~X?k5za~X?kuz ~X/?3r y^?/ y^?/]/ ž8?cp/5x,C{f ϫ_!~S~=\_ϟ?"?&TĹ}zP@Nuq!W|= @5t++pA? X \/.Wlj@| c.W@\+`+p@7+\=+p_{ C\W{p\ܫ@<k'^7y=8_g'_S<xΩލ`~!8,暫:jٚM_'isP>&*3_LwbБ QB ߱5sUsco`|0emʠ AU]Vut[ˠۚ_2A emˠ AUSVMt[5OFmt[emՖAUWV]t[uememem՗AU_V}t[ ˠZX2Ah^4#Y*<'&y*=^,ɞxNo_y<{^9Jϙc|xy 4dTyo|s[*ZʇV*[|W~pG*hT>Qd+?QOU~3{3gy_}kzZ^;Uހ;߻xkuX/~^[]]]]]{R2ro2 owٻ{Jo*56o?2++g?ǿȿ_/~ʶϾe]OD΋6wtly{?<*~o[}tλ87n;{o[6[w:v}M~_-ߋP=;ןvsI-m뿷COͳw7d}[t=̺okUw~{~tCѾ׮sS?w?~ǎ,~wLJ=rR֝s_ǡs߹u+31? z$0\mw/{oWÏ=mwq+aîy?m D12m;km_3/bOpס-wcΛgy;ԿuvOg}gd7^㽏'~3ZϽkU/-}/KKk|H&_7w8zzo{7L~Gzxigb\6xЇv r-_uCG_wWou݃pg-^zI{nyκПmmk{w|u=}f]_͝d'm׶[Pϗ;ovt_0Ozc[0|4xӃgBi_tKsp5{/=-ukwqw+O mg7^sj'zm~kßz!.'7CL:9=veOt0'o}9wmpi-k1ֳH}u}{b=Ԑ}(x9>嗢:gF~!yuqsZ>~F詮Kz>s?v`yre2af4Wcw8|Ֆ-[7n:dc_f_3wY5m]ޚý+ț v캮㓝?ZŦ̋ihyS{?7%|۟>tׅwiqQǡ7̣#?uϧ=_^;9ޱc{W]q􆶅[}k{޽#wnxGo޵wfIv7Cτoycc!M:;}Ԭ=k4=>6=rk/qwg>89{7 K:d^o>7޼hkxiG]=ئm~$\wIe]u/z9}mM쎋~ן;_-|r׌^o:0rP>]xMk[&;_B~uFiݷ_ {z6ܾǛ~ϛG7|3﮾oF_Rsgޕ\2<<8K=_v}|9߳U{*k{u޼ȁ=u8Ƕ۝o:Ys7XH]lZߟ?\{uҮ}NJ#lyeg[-?2u]k2t'^:?6ް7uʶ;B>ySzO6z{rI;{;65:]{뀧6opϻÉ5cˇ)ß}輱mƾ3>0б{ck߷~Mp1xO5yٞE`lx`goKϭGV?o=orKjwG7xv~#;ǽFn=m=_gց n{POz{Dž6 2K># c-۶4ڟ Ý]77otѻ<b`]ב=1׮~|-n^wՇG?u'׶GNj)Y{6% Pffffafif4$iF#" -l$f 33熙o9g?cjꜮsOu}+LuYVO{!S,绍0+yRi[cP'.f/ѯJu# S()۬.Yg`ph=Āg4&@JTU#5a]]8HRl I&=S~Թ5֓_ %Qvbw6ɊT  ,<="Mb$W;eKsL p>_)Wn3E qc[9]DEϑCC:Xx,fhQéΙppCȪ_yaS;4>)OO2GҔ3zN>Zh=+4# Qɺ6$ I-paImRn Hޔ9ʶ#%ÿ]0(E{M3aQWRKu5M&sɊ.FO%:@7JvD 2a`_\[+˽djץKeS@߱?&e5a\gPbq q+m>KA\1BsB;CۚF=˱u=7kk\~Jd$lk ~q 9γ|PBMR Mש8(yיruqMϮO!uY-`&r2VG!A*dgωo3_nj^:`9~~@>kHTCY3?y/GIta,,K琈n@Dgb8vR~UƂI*=$z$3 i Q3R}JNrr>L跧x#< ]y7w9۞%%U7o2 z;̯mbq8/iXE[fe`=gL*P/>ōh׊٪ ,>Hɟ:ackghhq (_K$UVjt7i >eCm3J7;NPb78h^%ox/*E{;ͳlu(Pz^4g)N {HDlKȎz xz3B`b[I)l K=F_eD;PQCE9M?RVNx*S?v[k @ PдX{6 k/Hg4o%=X̳w͊ֈ>ɛh؞?0Zu#c_@N>Z eN{dlI|AUt0s;Nu{P"2`vTo$ vH>OF")u:wc- d Z/uXf@3P@4N>Dϒt7^,HwjrxaQ2m9r^u!iP|m8h\6i-X6pn!n-Ui;6{>^em$$lV2m}Gꋦѵ4~{#s+>ɟccrB SJAXACb0X42yJt;xJ4nFˆ#MY5bkA9ܐƍ$uʌ%iO<-"tww_|S$DFBM@;2*cpf[[>ߖyz4sڳ37АMX*FWl}^Rh|d{ YB yNsr9}m}S-w{U_&vO1[ <1 PP]bV{~Ip0VV?fy+889%ti[lYcgˉ} a_Z˼k]&娕Tx T.u3I@wWVMLPQ/7JID[0w@PHhIJ%*>TjL@.' א$b ٞ<zVyWbؾwrKVk K_!D06>3 tH:O 䀬}Q2Y9j`ћ,Se?W^9 |RH˘YdaZj6@a }wDG>:ѽp{j^u}mNO"dkSYUpO+KUONU` ;5Ura{F)IT<T(i:wFA00Z212F13&12 >ԌҐǨbT3216063aeafed˸xŸ¬20EL ǜŴ28`*f>Sf&6̻̳k̛ G@;j2;0?]o)P "!4@ʀ NUx<^߀O`][-`;+8'AAT*Pz@#` b0 .*p5n7[=x'7ՇZ@P?h4 1ClHY %d  A Ch- @BwГW= }cbաưZڱư&ff0ZWY0K ڰ,Jֱ6ar6K^g%~_^^ AQl;Φylmdv;fc/bog/eafg`fd/aef_c?f?4`bfbg?LH998b  H8{='ʩ88nN 9+9! ]a-#en n+o/n{7. rGpGqqp\w0WUqn[čsrqn^^}ƣqyuyuxy yymx8xxxycx 8dy/6V6...;M|?oPC L~__ɿ_?¿ĿKPCPOD^LS0@0P0L0F0~Q@( p* R! *0s`` Wp]pCSYTAXWN8YBL[WxJxPGPh𼨟hhhhhqDBH$)EYD2a]EDEDD'DEEDODDwDEފ>>kkLjNJgb3EFFcb8S狋]ĻG{ſů$1 I}IKIkXY^TBMNVF2_Iy,JB'Y$$$$%'$g$$%W%7%IK>vp[)0lqXς) ۫vYB|>Wm|~߇;#iH]DHSA !C!~ćd!Q$#! )EJ d-@!_wmt3튢h[ mEۣ-h/1*D*Ԇ"\t&P:ՠjTz\)GZ&Z.Gsvz ݂EGѭ5l~F`4#Kú?wXC6 zcsIxl6MŦcf̆1&Ԙcr̈!caV%+ʰ(a v;vb23!}`o x = Cap| a\pWN܇Gp7^I2Nj .?*oA^6_綠5u7') (] eJ[ogz^?zީzBYX~~~nhmhoh::&@Pj(0731l7l63526\752v05ʍcHq|#ר1ƍ?cqq_^E eY=KS'O7SCSS{S@08x$dL<d1M>2EMCæ{o/@csks=ss+sG`s_sOD3̬fUf`0Sfn>nl>keo~l~mcYdi[zZYp,,E`b[EjQY%ReYn9i9gl~ggyhyjynymyoykygjBSiTMՈjHS^j<5Z@ͥP"j&%")52(+M( "*ʨJj):HmQ[=vj7:C.Rש7iSo{ꃵuuuuuuUl[1+nUXVjjfXVo [sy֤Zj-nnn^^ޱ޷>>lacmKuͲ m &mY6-Ӗg˱ڪllvvvَݰݲ=h,WF~322,ΌX⌭2g\8q*rތG2Nfxq#Wڙ2f?sr&D2LV=3+3Yz^u3wdQaw;8;;f8(aq8tJGڑp9rC(urpvslquvUUU5555555evq] ɥp\LU芸D*wts-vmusqvOp-rwrmwU6n~޻k빻;뻻g 8HX4h0_n-qsݰ[3*t;~+Ν#pIw]5&믬Yd1,0g!Yh"KEfedYPV,(*2,kqMY;e=ǘu$hɬ+Yg=z![-O-Ogggg=B= coooO$>|OSԾA>}j_ooПo3mAڿȟwC7)BĿ1W -P%P>0-ſ'0&X#  - 2030 dFN@uzL`WF|@hj``````4Nɮ=%p0? jE`(XDDpg\pG|JvqV[v߳kewn=${R'd+WedDz^}8h٫/g~2n7fZ:!Z(-GinaPЈФиPPPBB!F!]Hb!UfhQ:  O^ m   77 }} 7 ] 7 w w   OO CaAauvT6}T .\^ / o o  __ _  ? GDEGE:EzFEGDGEFEDG:F!"6#-#H4R)YYYYyM66vNPtftvF5Q<hYtqpL`F軜{/;ћ9 rj紋i$uN9rL3%g~33'#sM>ǒrr r s99ebSbbcc&|H,rcy3Vwmm;;{{[3^nƹ sT3rmKjs\oniܽ;sȽ{:f}3N^?y:575odސysfɛм~y+|\xP +jQԼ(vQQEFu-hJT4HTEpo*E"w(W*'KK(^^xw{O?*>S|Jŷ?.~d&%mIqNJHHdn$YL%W%'7&7%7$$InOHMJH,HJ5L^I~KjꤚZڦzƦ&&ff)4%K)t1NS`ʙTN*J*R+RRSS[RRGSSRRϩO%K)QҵdtɄ%̒y%}Xb)1*Y_䟒%JW}Vgկu۪[VwP=zn5TͮV#h5VMT՚jUTm.^<Xd-cik5Ѷ׸^6m}5ni=MB9qh;ih+iv-*-;-I'-?䥭t͚i֧LKN;v&Tچ5kJ^'nz 7Ge:Jgsҹt~ ].J(ɟ?^ða }x._'hw_?7OOϡϣ}hw$7m?0  M}v^^ހv^ވvvvvގފތ[;;ѻѻ{NчGG'ѧgg...Ү./|:ΧsBanЮnn5Kt]E7ut_MuvA3.vvF?KkkҞӞӞ7wwW7GGOOϦϤ}}}_Ot]@Et #t9]JNFIA/Ӎt5Lӕk[tnnQΨhhɘ̘˜ΘB!e(JA12Y\FbT23v013n0n2130101>0>1~1~30i4ff}ff3fKf+fkf[ P&ǜȜ̜ʜ͜Üǜτl&g"L)S0uL#`f2L2}3Ȍ03`0 EYƬbV3711w0w1w30230023O0O1O301/2o11023214z@h@G ÀH`20 fs`<@  PZq y@H@!P$r"`v{!0p 8 5p <Ogs  |~i`-6X6`5lv;`o8Hp 8  <" $@7`bp- qx^;1|~?_ :T 5C-VP FB >$AP&|PB1*P *ʠ h Z-Cmvh' CGit ]nBczBg Jccg5`5e5gagu`ubufdfaeg ` d a cdgM`MdMegc X"ƒ, K22YnbYyBVUuuuuuuuuu]ݜݎݕݛ݇ݏ=======dl-cldZmagl?;#\v>dWWWײױ7wwwOϰϲ__߰?ph:&.!%?gg$gggGq`82x9>N6'9N!,,l\\\˹ƹɹyyíɭímmmmmmmϝĝ̝ƝΝɝÝ]er\r1.Εr FKq 7ƸRn[ŭ..nnn^>>>>>}£jjZ:zzF&&&ff ΓHiy:gyfGlL9ynxEWƫUxռyż5=cӼs+ۼ;G'WOϼ_߼?4~:.>!=3 7 ,>>2>W3N~C0?c\~JBEeM3ZfS]=}C#3%D L Z^`P S89 OP (Ղ%債u ͂m݂CÂん3ۂ;Gׂ7w/B0]@PHL\I]C[GO8P8D8]8C8K8[8_9BX(ʅP+ B-&¤TX!V   7 7 7 w w  oo  __ ? ? h"hhhhhhqEH!҉"%rD^Q@-D QPT$JVVֈ֊֋66vvΈΉ]]}7www BXbR+ZAlSb!v]8,qZPHXLJIEUS|B|J|Q|[.%i(i&/.!%-*!+ $*&)-H@@2WHP &%2J$-ɒx%~IXH %EbI\R-Y(Y.Y- ".!9$9&9%9/9+&.'y$y.*pCn ;]Apx<σx \`1 Xa u9p^/W5Fx3 §SY| _owH R4B"HWA#Ad2 L@&! d6GDHB"zĄX @ q#$#ID!ˑd ـlD#cqr 9\@.">y8C8B\p-͸wx2|߆Y ~/i4]ZOZ_PD\JFWO:P:R:J:V:^:E:U:M:]:S:W:OʐBR-KERjZQjR SfI}Ҁ4$J"iTZ&..^^^^ޒޓ>~~~~ՕՓ55uuu MM͓1e dlP&e"CeL*2!sɂ,.Ke%RYRV-[XLBFYGWOvXvBvRvJvZvVv^vAvE쏜.Oבוד77www%/ &%#䐜-G䨜vKQyX^"///ooo___ߕ!hD:QK4$͈D+#щJt#=^D_џ@ "CXb41A$ `b?q8D'Ngse&qxFG$^ɚdmٜlKv Dr9M'$!uK<2N擅d,!KrrDn%w=7r?yuPR Ջԋ++kk;{{Շԇ'ԧW7OOկ_454隚F&fΚ^ޚ>AᚑQ444s54 4L akFQkƢj24&ք4MXҔh*4՚ M-3s ˚[{4/555zFڦv^>R;H;X;T;V;^;IZDiZRNOk Eڤ6-ѮҮnnמԞ՞^>>>׾Ѿ~~tNn޺aQqٺ9y:A:::N3:.WW+--׭խmmםԝѝ՝{{O77Էҷѷӷ׏ҏӏ3ҳ<@/Kz^wz>s1}>/I}ZPTL\BN^AU~fiemhhhmbnlamkofnmckg`860 2ܠ1 jp!Pd(6$ )CܰİڰѰŰppppppppݘfL742676066v2v1746151N104253F3 b#lD cc CƘXf,7.4.27n0n2n64370626^2^5^702~56LMuLuMMMLMM=LMM#LcLcMSLSML3L X&k&؄&Imҙ&f09LNS)`rMyBSiiiiii鷹9\\\<<<zJ^Sow7+ZÚfMֱֳֶ6666vvvveokl?{ 8HHKkKHKKHK;KӥnR@:T:\:Y:E:]:C:Gt)Sʖr<)_#͓IRUҐt4.MH҅ҥҕUҵu ]=#ңcғsҋK;һGgw'g7w)$#k$k& $"*KezzɆȆF˦Ȧʦff2 h2L$˕d2BevCeUjY@Ee1|R2 :FV~AQq%5M-=C3sK[Zr<]SW_>PȇȇGGGɧȧʧgȉr*r-EO||||||bbP R QUWLPLTLWD[WCK?X?D?J?Y?E?U?M?[ңX=IO׳Q1qiE%U5 m=}3sK[{7 dM"u ͬ--]]uuuuuuuuuuueZVbͶҭ,+ʷZK2ªk&K˭ۭ{ǭ''g׭oom:ƶ&ֶ6vN4[[O[/`dljieg`djfiCp6-FmƳۊl%r[MnSؔ6fs<*[-jْyEMͶ- K˶+綗O6D`S9li`pp,8N\AH) dPJP J@(ԀZA;= A0 &%2p5n;0x<ς E2x ߀'׶ױ77www71I)ivo'ةvg/R̮:nN^e {11111111ہv`xAvP4Au|Бu:CP;8|#:bmCÎc3K'׎7wώ/șD8;[8:;:\gȩqFtz^g3L:9;W8W:8;7989w8:9;8:;O;:/8/:/;:8:;_88w::9?8R]HWmWWCWsW+WW+ݕr s wptuMpMtvu\hEs] qq]WU*u\r¥w\6sU"+JVV66vθκ.n^޸޺>^SܵuMmm]itw7w{{{{{{{{{{ƺqn&)nyEM}SwOܯoݟ?=y{^{x>x~z ommmmmmMfz3ݼ=Cüý#ccӽ3h/KR^{EBoW{^5y^z~o&󽋽K+k;;{W׼Oϼ//oo_߽?|)TWWWWݗ|YaQ1q IɾiY>(>c>Or|"_W$>OS>Ol>|>_%}| }|K|K}+|k|}}[}};|;}|{|{}|}||}G|G}'|'}|}..nnn^^ ?ݟOcX?O~?ן/Kr_U~_~NWC?ͿпؿԿ¿ѿɿٿݿ̿*V^UUMVjSնkՀUWeU ]5jl䪩U3fUͩ"VQU*N**0JejcQvUǫՋU^Yzs]{W>V}W_V}V;:2~A.@% *2h>`7D@20(8,:&!=p UnixAgent-2.8/macosx/setup_plugins/config_plugin_installer/config/ConfigInstallerPane.h000066400000000000000000000013161372663377700317130ustar00rootroot00000000000000// // MyInstallerPane.h // config // // Created by Gilles Dubois on 02/02/2020. // Copyright © 2020 Gilles Dubois. All rights reserved. // #import @interface ConfigInstallerPane : InstallerPane { IBOutlet NSTextField *server; IBOutlet NSTextField *tag; IBOutlet NSTextField *logfile; IBOutlet NSTextField *cacertfile; IBOutlet NSButton *debugmode; IBOutlet NSButton *lazymode; IBOutlet NSButton *download; IBOutlet NSButton *ssl; IBOutlet NSPopUpButton *protocolist; NSFileManager *filemgr; NSString *tmpCfgFilePath; NSString *tmpModulesFilePath; NSString *tmpServerdirFilePath; NSString *tmpCacertFilePath; } @end UnixAgent-2.8/macosx/setup_plugins/config_plugin_installer/config/ConfigInstallerPane.m000066400000000000000000000246021372663377700317230ustar00rootroot00000000000000// // MyInstallerPane.m // config // // Created by Gilles Dubois on 02/02/2020. // Copyright © 2020 Gilles Dubois. All rights reserved. // #import "ConfigInstallerPane.h" @implementation ConfigInstallerPane - (NSString *)title { return [[NSBundle bundleForClass:[self class]] localizedStringForKey:@"PaneTitle" value:nil table:nil]; } - (NSArray *) protocols { return [NSArray arrayWithObjects:@"http", @"https", nil]; } - (void)didEnterPane:(InstallerSectionDirection)dir { NSAlert *cfgFileExistsWrn; NSString *tmpPath = @"/tmp/ocs_installer"; filemgr = [ NSFileManager defaultManager]; tmpCfgFilePath = @"/tmp/ocs_installer/ocsinventory-agent.cfg"; tmpModulesFilePath = @"/tmp/ocs_installer/modules.conf"; tmpServerdirFilePath = @"/tmp/ocs_installer/serverdir"; tmpCacertFilePath = @"/tmp/ocs_installer/cacert.pem"; //Checking if temp directory exists if ([filemgr fileExistsAtPath:tmpPath]) { [filemgr removeItemAtPath:tmpCfgFilePath error:nil]; [filemgr removeItemAtPath:tmpModulesFilePath error:nil]; [filemgr removeItemAtPath:tmpServerdirFilePath error:nil]; [filemgr removeItemAtPath:tmpCacertFilePath error:nil]; } else { [filemgr createDirectoryAtPath:tmpPath withIntermediateDirectories:true attributes:nil error:nil]; } if ([filemgr fileExistsAtPath:@"/etc/ocsinventory-agent/ocsinventory-agent.cfg"]) { //We display a warning dialog cfgFileExistsWrn = [[NSAlert alloc] init]; [cfgFileExistsWrn setMessageText:NSLocalizedStringFromTableInBundle(@"Already_conf_warn",nil,[NSBundle bundleForClass:[self class]], @"Warning about already existing cofiguration file")]; [cfgFileExistsWrn setInformativeText:NSLocalizedStringFromTableInBundle(@"Already_conf_warn_comment",nil,[NSBundle bundleForClass:[self class]], @"Warning about already existing configuration file comment")]; [cfgFileExistsWrn addButtonWithTitle:NSLocalizedStringFromTableInBundle(@"Yes",nil,[NSBundle bundleForClass:[self class]], @"Yes button")]; [cfgFileExistsWrn addButtonWithTitle:NSLocalizedStringFromTableInBundle(@"No",nil,[NSBundle bundleForClass:[self class]], @"No button")]; [cfgFileExistsWrn setAlertStyle:NSAlertStyleInformational]; if ([cfgFileExistsWrn runModal] != NSAlertFirstButtonReturn) { // No button was clicked, we don't display config pane [self gotoNextPane]; } } // fill defaults values [server setStringValue:@"ocsinventory-ng"]; [logfile setStringValue:@"/var/log/ocsng.log"]; [debugmode setState:0]; [lazymode setState:0]; [download setState:1]; [ssl setState:1]; //Defaults for protocol droping list [protocolist removeAllItems]; [protocolist addItemWithTitle: @"http://"]; [protocolist addItemWithTitle: @"https://"]; [protocolist selectItemWithTitle: @"https://"]; } - (IBAction)chooseCacertFile:(id)sender { NSOpenPanel *panel = [NSOpenPanel openPanel]; NSArray* fileTypes = [[NSArray alloc] initWithObjects:@"pem",@"PEM",@"crt",@"CRT",nil]; //Configuration for the browse panel [panel setCanChooseDirectories:NO]; [panel setCanChooseFiles:YES]; [panel setAllowsMultipleSelection:NO]; [panel setAllowedFileTypes:fileTypes]; // Get panel return value NSInteger clicked = [panel runModal]; // If OK clicked only if (clicked == NSModalResponseOK) { for (NSURL *url in [panel URLs]) { // do something with the url here. NSString *path = url.path; [cacertfile setStringValue:path]; } } } - (IBAction) chooseProtocol:(id)sender { NSString *protocol = [protocolist titleOfSelectedItem]; //We show the selected protocol [protocolist setTitle:protocol]; } - (BOOL)shouldExitPane:(InstallerSectionDirection)Direction { NSMutableString *ocsAgentCfgContent; NSMutableString *modulesCfgContent; NSString *serverDir; NSMutableString *protocolName; NSAlert *srvConfigWrn; NSAlert *caCertWrn; NSString *protocol = [protocolist titleOfSelectedItem]; // check the direction of movement if (Direction == InstallerDirectionForward) { if ( [[server stringValue] length] > 0) { ocsAgentCfgContent = [@"server=" mutableCopy]; //Adding server value to the mutable string [ocsAgentCfgContent appendString:protocol]; [ocsAgentCfgContent appendString:[server objectValue]]; [ocsAgentCfgContent appendString:@"/ocsinventory"]; [ocsAgentCfgContent appendString:@"\n"]; //if tag filled if ( [[tag stringValue] length] > 0) { [ocsAgentCfgContent appendString:@"tag="]; [ocsAgentCfgContent appendString:[tag objectValue]]; [ocsAgentCfgContent appendString:@"\n"]; } //if logfile filled if ( [[logfile stringValue] length] > 0) { [ocsAgentCfgContent appendString:@"logfile="]; [ocsAgentCfgContent appendString:[logfile objectValue]]; [ocsAgentCfgContent appendString:@"\n"]; } //if debugmode checked if ([debugmode state] == 1) { [ocsAgentCfgContent appendString:@"debug=1\n"]; } else { [ocsAgentCfgContent appendString:@"debug=0\n"]; } //if lazymode checked if ([lazymode state] == 1) { [ocsAgentCfgContent appendString:@"lazy=1\n"]; } else { [ocsAgentCfgContent appendString:@"lazy=0\n"]; } //if ssl checked if ([ssl state] == 1) { [ocsAgentCfgContent appendString:@"ssl=1\n"]; } else { [ocsAgentCfgContent appendString:@"ssl=0\n"]; } //Writing to ocsinventory agent configuration file [ocsAgentCfgContent writeToFile:tmpCfgFilePath atomically: YES encoding:NSUTF8StringEncoding error:NULL]; modulesCfgContent = [@"# this list of module will be load by the at run time\n" @"# to check its syntax do:\n" @"# #perl modules.conf\n" @"# You must have NO error. Else the content will be ignored\n" @"# This mechanism goal it to keep compatibility with 'plugin'\n" @"# created for the previous linux_agent.\n" @"# The new unified_agent have its own extension system that allow\n" @"# user to add new information easily.\n" @"\n" @"#use Ocsinventory::Agent::Modules::Example;\n" mutableCopy]; //if download checked if ( [download state] == 1) { [modulesCfgContent appendString:@"use Ocsinventory::Agent::Modules::Download;\n" @"\n" @"# DO NOT REMOVE THE 1;\n" @"1;" ]; } else { [modulesCfgContent appendString:@"#use Ocsinventory::Agent::Modules::Download;\n" @"\n" @"# DO NOT REMOVE THE 1;\n" @"1;" ]; } //Writing to modules configuration file [modulesCfgContent writeToFile:tmpModulesFilePath atomically: YES encoding:NSUTF8StringEncoding error:NULL]; //We have to copy cacert.pem if is asked by user if ( [[cacertfile stringValue] length] > 0) { protocolName = [protocol mutableCopy]; [protocolName replaceOccurrencesOfString:@"/" withString:@"" options:NSCaseInsensitiveSearch range:NSMakeRange(0, [protocolName length])]; serverDir = [NSString stringWithFormat:@"/var/lib/ocsinventory-agent/%@__%@_ocsinventory", protocolName, [server objectValue]]; [serverDir writeToFile:tmpServerdirFilePath atomically: YES encoding:NSUTF8StringEncoding error:NULL]; [filemgr copyItemAtPath:[cacertfile objectValue] toPath:tmpCacertFilePath error:nil]; } if ( [download state] == 1 && [ssl state] == 1 && [[cacertfile stringValue] length] == 0 ) { //We display a warning dialog caCertWrn = [[NSAlert alloc] init]; [caCertWrn addButtonWithTitle:@"OK"]; [caCertWrn setMessageText:NSLocalizedStringFromTableInBundle(@"Missing_cert_warn",nil,[NSBundle bundleForClass:[self class]], @"Warning about missing certificate file")]; [caCertWrn setInformativeText:NSLocalizedStringFromTableInBundle(@"Missing_cert_warn_comment",nil,[NSBundle bundleForClass:[self class]], @"Warning about missing certificate file comment")]; [caCertWrn setAlertStyle:NSAlertStyleInformational]; [caCertWrn runModal]; // display the warning dialog } } else { //We display a warning dialog srvConfigWrn = [[NSAlert alloc] init]; [srvConfigWrn addButtonWithTitle:@"OK"]; [srvConfigWrn setMessageText:NSLocalizedStringFromTableInBundle(@"Invalid_srv_addr",nil,[NSBundle bundleForClass:[self class]], @"Warning about invalid server address")]; [srvConfigWrn setInformativeText:NSLocalizedStringFromTableInBundle(@"Invalid_srv_addr_comment",nil,[NSBundle bundleForClass:[self class]], @"Warning about invalid server address comment")]; [srvConfigWrn setAlertStyle:NSAlertStyleInformational]; [srvConfigWrn runModal]; [self gotoPreviousPane]; } } return (YES); } @end UnixAgent-2.8/macosx/setup_plugins/config_plugin_installer/config/Info.plist000066400000000000000000000017771372663377700276360ustar00rootroot00000000000000 CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString 1.0 CFBundleVersion 1 InstallerSectionTitle config NSHumanReadableCopyright Copyright © 2020 OCS Inventory. All rights reserved. NSMainNibFile ConfigInstallerPane NSPrincipalClass InstallerSection UnixAgent-2.8/macosx/setup_plugins/config_plugin_installer/config/InstallerSections.plist000066400000000000000000000007631372663377700324020ustar00rootroot00000000000000 SectionOrder Introduction ReadMe License config.bundle Target PackageSelection Install UnixAgent-2.8/macosx/setup_plugins/config_plugin_installer/config/en.lproj/000077500000000000000000000000001372663377700274015ustar00rootroot00000000000000ConfigInstallerPane.strings000066400000000000000000000027451372663377700346340ustar00rootroot00000000000000UnixAgent-2.8/macosx/setup_plugins/config_plugin_installer/config/en.lproj /* Class = "NSButtonCell"; title = "SSL check"; ObjectID = "0JY-Jz-90N"; */ "0JY-Jz-90N.title" = "SSL check"; /* Class = "NSTextFieldCell"; title = "ocsinventory-ng"; ObjectID = "0Sw-Bb-gYo"; */ "0Sw-Bb-gYo.title" = "ocsinventory-ng"; /* Class = "NSButtonCell"; title = "Debug mode"; ObjectID = "31X-X1-h1b"; */ "31X-X1-h1b.title" = "Debug mode"; /* Class = "NSMenuItem"; title = "http://"; ObjectID = "3w5-Xc-SgN"; */ "3w5-Xc-SgN.title" = "http://"; /* Class = "NSTextFieldCell"; title = "Log File path :"; ObjectID = "Bqz-yE-1gz"; */ "Bqz-yE-1gz.title" = "Log File path :"; /* Class = "NSTextFieldCell"; title = "TAG Value (optional) :"; ObjectID = "CJY-Du-ySH"; */ "CJY-Du-ySH.title" = "TAG Value (optional) :"; /* Class = "NSTextFieldCell"; title = "/ocsinventory"; ObjectID = "DIf-zY-Upa"; */ "DIf-zY-Upa.title" = "/ocsinventory"; /* Class = "NSButtonCell"; title = "Deployment feature"; ObjectID = "Fz6-ny-C1b"; */ "Fz6-ny-C1b.title" = "Deployment feature"; /* Class = "NSButtonCell"; title = "Browse"; ObjectID = "MAB-ch-ni8"; */ "MAB-ch-ni8.title" = "Browse"; /* Class = "NSTextFieldCell"; title = "Certificate File (needed by 'Deployment feature')"; ObjectID = "UvL-Ff-Y6G"; */ "UvL-Ff-Y6G.title" = "Certificate File (needed by 'Deployment feature')"; /* Class = "NSButtonCell"; title = "Lazy mode"; ObjectID = "gFK-QK-e24"; */ "gFK-QK-e24.title" = "Lazy mode"; /* Class = "NSTextFieldCell"; title = "OCS Server URL"; ObjectID = "w48-wL-2Wx"; */ "w48-wL-2Wx.title" = "OCS Server URL";∂ UnixAgent-2.8/macosx/setup_plugins/config_plugin_installer/config/en.lproj/InfoPlist.strings000066400000000000000000000000601372663377700327170ustar00rootroot00000000000000InstallerSectionTitle = "Agent configuration"; UnixAgent-2.8/macosx/setup_plugins/config_plugin_installer/config/en.lproj/Localizable.strings000066400000000000000000000020271372663377700332360ustar00rootroot00000000000000/* Localized versions of Info.plist keys */ "PaneTitle" = "OCSInventory Agent Config"; //Yes button "Yes" = "Yes"; //No button "No" = "No"; //Warning about already existing cofiguration file "Already_conf_warn" = "OCS agent configuration file seems to already exists. Do you want to launch OCS Inventory NG agent configuration?"; //Warning about already existing cofiguration file comment "Already_conf_warn_comment" = "The previous /etc/ocsinventory-agent/ocsinventory-agent.cfg file will be erased"; //Warning about missing certificate file "Missing_cert_warn" = "You have enabled Download feature and SSL certicate check but you don't specify a certificate file"; //Warning about missing certificate file comment "Missing_cert_warn_comment" = "If you don't specifiy a certificate file, Download feature won't work"; //Warning about invalid server address "Invalid_srv_addr" = "Invalid OCS server address"; //Warning about invalid server address comment "Invalid_srv_addr_comment" = "Please check and re-enter your OCS server address"; UnixAgent-2.8/macosx/setup_plugins/daemonconfig_plugin_install/000077500000000000000000000000001372663377700252425ustar00rootroot00000000000000UnixAgent-2.8/macosx/setup_plugins/daemonconfig_plugin_install/daemonconfig.xcodeproj/000077500000000000000000000000001372663377700316675ustar00rootroot00000000000000project.pbxproj000066400000000000000000000306521372663377700346720ustar00rootroot00000000000000UnixAgent-2.8/macosx/setup_plugins/daemonconfig_plugin_install/daemonconfig.xcodeproj// !$*UTF8*$! { archiveVersion = 1; classes = { }; objectVersion = 50; objects = { /* Begin PBXBuildFile section */ 4315F1EA23E730CD0047BEE1 /* DaemonConfigPane.m in Sources */ = {isa = PBXBuildFile; fileRef = 4315F1E923E730CD0047BEE1 /* DaemonConfigPane.m */; }; 4315F1ED23E730CD0047BEE1 /* DaemonConfigPane.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4315F1EB23E730CD0047BEE1 /* DaemonConfigPane.xib */; }; 4315F1F023E730CD0047BEE1 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 4315F1EE23E730CD0047BEE1 /* Localizable.strings */; }; 4315F1F223E730CD0047BEE1 /* InstallerSections.plist in Resources */ = {isa = PBXBuildFile; fileRef = 4315F1F123E730CD0047BEE1 /* InstallerSections.plist */; }; 4315F1F623E730CD0047BEE1 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 4315F1F423E730CD0047BEE1 /* InfoPlist.strings */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ 4315F1E523E730CD0047BEE1 /* daemonconfig.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = daemonconfig.bundle; sourceTree = BUILT_PRODUCTS_DIR; }; 4315F1E823E730CD0047BEE1 /* DaemonConfigPane.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DaemonConfigPane.h; sourceTree = ""; }; 4315F1E923E730CD0047BEE1 /* DaemonConfigPane.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = DaemonConfigPane.m; sourceTree = ""; }; 4315F1EC23E730CD0047BEE1 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/DaemonConfigPane.xib; sourceTree = ""; }; 4315F1EF23E730CD0047BEE1 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = ""; }; 4315F1F123E730CD0047BEE1 /* InstallerSections.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = InstallerSections.plist; sourceTree = ""; }; 4315F1F323E730CD0047BEE1 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 4315F1F523E730CD0047BEE1 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 4315F1FD23E732200047BEE1 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/DaemonConfigPane.strings; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ 4315F1E223E730CD0047BEE1 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ 4315F1DC23E730CD0047BEE1 = { isa = PBXGroup; children = ( 4315F1E723E730CD0047BEE1 /* daemonconfig */, 4315F1E623E730CD0047BEE1 /* Products */, ); sourceTree = ""; }; 4315F1E623E730CD0047BEE1 /* Products */ = { isa = PBXGroup; children = ( 4315F1E523E730CD0047BEE1 /* daemonconfig.bundle */, ); name = Products; sourceTree = ""; }; 4315F1E723E730CD0047BEE1 /* daemonconfig */ = { isa = PBXGroup; children = ( 4315F1E823E730CD0047BEE1 /* DaemonConfigPane.h */, 4315F1E923E730CD0047BEE1 /* DaemonConfigPane.m */, 4315F1EB23E730CD0047BEE1 /* DaemonConfigPane.xib */, 4315F1EE23E730CD0047BEE1 /* Localizable.strings */, 4315F1F123E730CD0047BEE1 /* InstallerSections.plist */, 4315F1F323E730CD0047BEE1 /* Info.plist */, 4315F1F423E730CD0047BEE1 /* InfoPlist.strings */, ); path = daemonconfig; sourceTree = ""; }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ 4315F1E423E730CD0047BEE1 /* daemonconfig */ = { isa = PBXNativeTarget; buildConfigurationList = 4315F1F923E730CD0047BEE1 /* Build configuration list for PBXNativeTarget "daemonconfig" */; buildPhases = ( 4315F1E123E730CD0047BEE1 /* Sources */, 4315F1E223E730CD0047BEE1 /* Frameworks */, 4315F1E323E730CD0047BEE1 /* Resources */, ); buildRules = ( ); dependencies = ( ); name = daemonconfig; productName = daemonconfig; productReference = 4315F1E523E730CD0047BEE1 /* daemonconfig.bundle */; productType = "com.apple.product-type.bundle"; }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ 4315F1DD23E730CD0047BEE1 /* Project object */ = { isa = PBXProject; attributes = { LastUpgradeCheck = 1130; ORGANIZATIONNAME = "Gilles Dubois"; TargetAttributes = { 4315F1E423E730CD0047BEE1 = { CreatedOnToolsVersion = 11.3.1; }; }; }; buildConfigurationList = 4315F1E023E730CD0047BEE1 /* Build configuration list for PBXProject "daemonconfig" */; compatibilityVersion = "Xcode 9.3"; developmentRegion = en; hasScannedForEncodings = 0; knownRegions = ( en, Base, ); mainGroup = 4315F1DC23E730CD0047BEE1; productRefGroup = 4315F1E623E730CD0047BEE1 /* Products */; projectDirPath = ""; projectRoot = ""; targets = ( 4315F1E423E730CD0047BEE1 /* daemonconfig */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ 4315F1E323E730CD0047BEE1 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( 4315F1ED23E730CD0047BEE1 /* DaemonConfigPane.xib in Resources */, 4315F1F623E730CD0047BEE1 /* InfoPlist.strings in Resources */, 4315F1F023E730CD0047BEE1 /* Localizable.strings in Resources */, 4315F1F223E730CD0047BEE1 /* InstallerSections.plist in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXResourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ 4315F1E123E730CD0047BEE1 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 4315F1EA23E730CD0047BEE1 /* DaemonConfigPane.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin PBXVariantGroup section */ 4315F1EB23E730CD0047BEE1 /* DaemonConfigPane.xib */ = { isa = PBXVariantGroup; children = ( 4315F1EC23E730CD0047BEE1 /* Base */, 4315F1FD23E732200047BEE1 /* en */, ); name = DaemonConfigPane.xib; sourceTree = ""; }; 4315F1EE23E730CD0047BEE1 /* Localizable.strings */ = { isa = PBXVariantGroup; children = ( 4315F1EF23E730CD0047BEE1 /* en */, ); name = Localizable.strings; sourceTree = ""; }; 4315F1F423E730CD0047BEE1 /* InfoPlist.strings */ = { isa = PBXVariantGroup; children = ( 4315F1F523E730CD0047BEE1 /* en */, ); name = InfoPlist.strings; sourceTree = ""; }; /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ 4315F1F723E730CD0047BEE1 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_ENABLE_OBJC_WEAK = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; MACOSX_DEPLOYMENT_TARGET = 10.15; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = macosx; }; name = Debug; }; 4315F1F823E730CD0047BEE1 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_ENABLE_OBJC_WEAK = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; MACOSX_DEPLOYMENT_TARGET = 10.15; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; SDKROOT = macosx; }; name = Release; }; 4315F1FA23E730CD0047BEE1 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; DEVELOPMENT_TEAM = KHDBNPH65U; INFOPLIST_FILE = daemonconfig/Info.plist; INSTALL_PATH = "$(HOME)/Library/Bundles"; PRODUCT_BUNDLE_IDENTIFIER = org.ocsinventory.agent.daemonconfig; PRODUCT_NAME = "$(TARGET_NAME)"; WRAPPER_EXTENSION = bundle; }; name = Debug; }; 4315F1FB23E730CD0047BEE1 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; DEVELOPMENT_TEAM = KHDBNPH65U; INFOPLIST_FILE = daemonconfig/Info.plist; INSTALL_PATH = "$(HOME)/Library/Bundles"; PRODUCT_BUNDLE_IDENTIFIER = org.ocsinventory.agent.daemonconfig; PRODUCT_NAME = "$(TARGET_NAME)"; WRAPPER_EXTENSION = bundle; }; name = Release; }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ 4315F1E023E730CD0047BEE1 /* Build configuration list for PBXProject "daemonconfig" */ = { isa = XCConfigurationList; buildConfigurations = ( 4315F1F723E730CD0047BEE1 /* Debug */, 4315F1F823E730CD0047BEE1 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 4315F1F923E730CD0047BEE1 /* Build configuration list for PBXNativeTarget "daemonconfig" */ = { isa = XCConfigurationList; buildConfigurations = ( 4315F1FA23E730CD0047BEE1 /* Debug */, 4315F1FB23E730CD0047BEE1 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; rootObject = 4315F1DD23E730CD0047BEE1 /* Project object */; } UnixAgent-2.8/macosx/setup_plugins/daemonconfig_plugin_install/daemonconfig/000077500000000000000000000000001372663377700276735ustar00rootroot00000000000000UnixAgent-2.8/macosx/setup_plugins/daemonconfig_plugin_install/daemonconfig/Base.lproj/000077500000000000000000000000001372663377700316725ustar00rootroot00000000000000DaemonConfigPane.xib000066400000000000000000000160731372663377700354630ustar00rootroot00000000000000UnixAgent-2.8/macosx/setup_plugins/daemonconfig_plugin_install/daemonconfig/Base.lproj UnixAgent-2.8/macosx/setup_plugins/daemonconfig_plugin_install/daemonconfig/DaemonConfigPane.h000066400000000000000000000007101372663377700331770ustar00rootroot00000000000000// // MyInstallerPane.h // daemonconfig // // Created by OCSInventory on 02/02/2020. // Copyright © 2020 OCSInventory. All rights reserved. // #import @interface DaemonConfigPane : InstallerPane { IBOutlet NSTextField *periodicity; IBOutlet NSButton *now; IBOutlet NSButton *startup; NSFileManager *filemgr; NSString *tmpLaunchdFilePath; NSString *tmpNowFilePath; } @end UnixAgent-2.8/macosx/setup_plugins/daemonconfig_plugin_install/daemonconfig/DaemonConfigPane.m000066400000000000000000000102641372663377700332110ustar00rootroot00000000000000// // MyInstallerPane.m // daemonconfig // // Created by OCSInventory on 02/02/2020. // Copyright © 2020 OCSInventory. All rights reserved. // #import "DaemonConfigPane.h" @implementation DaemonConfigPane - (NSString *)title { return [[NSBundle bundleForClass:[self class]] localizedStringForKey:@"PaneTitle" value:nil table:nil]; } - (void)didEnterPane:(InstallerSectionDirection)dir { NSString *tmpPath = @"/tmp/ocs_installer"; filemgr = [ NSFileManager defaultManager]; tmpLaunchdFilePath =@"/tmp/ocs_installer/org.ocsng.agent.plist"; tmpNowFilePath = @"/tmp/ocs_installer/now"; //Checking if temp directory exists if ([filemgr fileExistsAtPath:tmpPath]) { [filemgr removeItemAtPath:tmpLaunchdFilePath error:nil]; [filemgr removeItemAtPath:tmpNowFilePath error:nil]; } else { [filemgr createDirectoryAtPath:tmpPath withIntermediateDirectories:true attributes:nil error:nil]; } // fill defaults values [periodicity setStringValue:@"5"]; [startup setState:1]; [now setState:1]; } - (BOOL)shouldExitPane:(InstallerSectionDirection)Direction { NSMutableString *launchdCfgFile; NSAlert *periodicityValueWrn; //Creating org.ocsng.agent.plist file for launchd //TODO: use XML parser instead of writing the XML as a simple text file ? launchdCfgFile = [@"\n" @"\n" @"\n" @"\n" @"\tLabel\n" @"\torg.ocsng.agent\n" @"\tProgramArguments\n" @"\t\t\n" @"\t\t\t/Applications/OCSNG.app/Contents/MacOS/OCSNG\n" @"\t\t\n" mutableCopy]; if ([startup state] == 1) { [launchdCfgFile appendString:@"\tRunAtLoad\n" @"\t\n" ]; } if ( [[periodicity stringValue] length] > 0) { //We convert string to numeric value and check if it is integer NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init]; NSNumber *convert = [formatter numberFromString:[periodicity stringValue]]; if (convert) { int hours = [convert intValue]; int seconds = hours * 3600; [launchdCfgFile appendString:@"\tStartInterval\n" @"\t" ]; [launchdCfgFile appendString:[NSString stringWithFormat:@"%d", seconds]]; [launchdCfgFile appendString:@"\n"]; } else { //We display a warn message and we go back to pane periodicityValueWrn = [[NSAlert alloc] init]; [periodicityValueWrn addButtonWithTitle:NSLocalizedString(@"OK", @"OK")]; [periodicityValueWrn setMessageText:NSLocalizedStringFromTableInBundle(@"Periodicity_warn",nil,[NSBundle bundleForClass:[self class]], @"Peridocity warn")]; [periodicityValueWrn setInformativeText:NSLocalizedStringFromTableInBundle(@"Periodicity_warn_comment",nil,[NSBundle bundleForClass:[self class]], @"Periodicity warn comment")]; [periodicityValueWrn setAlertStyle:NSAlertStyleInformational]; [periodicityValueWrn runModal]; [self gotoPreviousPane]; } } [launchdCfgFile appendString:@"\n" @"" ]; //Writing org.ocsng.agent.plist file [launchdCfgFile writeToFile:tmpLaunchdFilePath atomically: YES encoding:NSUTF8StringEncoding error:NULL]; //Check if we launch agent after install if ([now state] == 1) { [filemgr createFileAtPath:tmpNowFilePath contents:nil attributes:nil]; } return (YES); } @end UnixAgent-2.8/macosx/setup_plugins/daemonconfig_plugin_install/daemonconfig/Info.plist000066400000000000000000000020021372663377700316350ustar00rootroot00000000000000 CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString 1.0 CFBundleVersion 1 InstallerSectionTitle daemonconfig NSHumanReadableCopyright Copyright © 2020 OCS Inventory. All rights reserved. NSMainNibFile DaemonConfigPane NSPrincipalClass InstallerSection UnixAgent-2.8/macosx/setup_plugins/daemonconfig_plugin_install/daemonconfig/InstallerSections.plist000066400000000000000000000007711372663377700344220ustar00rootroot00000000000000 SectionOrder Introduction ReadMe License daemonconfig.bundle Target PackageSelection Install UnixAgent-2.8/macosx/setup_plugins/daemonconfig_plugin_install/daemonconfig/en.lproj/000077500000000000000000000000001372663377700314225ustar00rootroot00000000000000DaemonConfigPane.strings000066400000000000000000000012141372663377700361110ustar00rootroot00000000000000UnixAgent-2.8/macosx/setup_plugins/daemonconfig_plugin_install/daemonconfig/en.lproj /* Class = "NSTextFieldCell"; title = "Launch OCS agent every"; ObjectID = "CR7-Av-TyG"; */ "CR7-Av-TyG.title" = "Launch OCS agent every"; /* Class = "NSTextFieldCell"; title = "5"; ObjectID = "Kd5-vS-SZ8"; */ "Kd5-vS-SZ8.title" = "5"; /* Class = "NSTextFieldCell"; title = "hour(s)"; ObjectID = "L5X-oH-TrN"; */ "L5X-oH-TrN.title" = "hour(s)"; /* Class = "NSButtonCell"; title = "Launch OCS Agent at daemon start"; ObjectID = "dlF-LS-rTI"; */ "dlF-LS-rTI.title" = "Launch OCS Agent at daemon start"; /* Class = "NSButtonCell"; title = "Launch daemon after install"; ObjectID = "kI2-ox-p1X"; */ "kI2-ox-p1X.title" = "Launch daemon after install"; InfoPlist.strings000066400000000000000000000000611372663377700346620ustar00rootroot00000000000000UnixAgent-2.8/macosx/setup_plugins/daemonconfig_plugin_install/daemonconfig/en.lprojInstallerSectionTitle = "Daemon configuration"; Localizable.strings000066400000000000000000000003651372663377700352030ustar00rootroot00000000000000UnixAgent-2.8/macosx/setup_plugins/daemonconfig_plugin_install/daemonconfig/en.lproj/* Localized versions of Info.plist keys */ "PaneTitle" = "OCS agent daemon options"; //Peridocity warn "Periodicity_warn"="Invalid periodicity value"; //Periodicity warn comment "Periodicity_warn_comment"="Please enter a valid number value"; UnixAgent-2.8/memconf000077500000000000000000014057011372663377700146740ustar00rootroot00000000000000#!/usr/bin/env perl # # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! # MODIFY THE LOCATION TO THE FULL PATH TO PERL ABOVE IF NECESSARY # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! # # @(#) memconf - Identify sizes of memory modules installed on a # @(#) Solaris, Linux, FreeBSD or HP-UX workstation or server. # @(#) Micron Technology, Inc. - Tom Schmidt 16-Nov-2017 V3.14 # # Maintained by Tom Schmidt (tschmidt@micron.com) # # Check http://sourceforge.net/projects/memconf/ or my website at # http://www.4schmidts.com/unix.html to get the latest version of memconf. # # If memconf does not recognize a system, then please run 'memconf -D' to # have it automatically E-mail me the information I need to enhanced to # recognize it. If the unrecognized system is a Sun clone, please also send # any hardware documentation on the memory layout that you may have. # # Usage: memconf [ -v | -D | -h ] [explorer_dir] # -v verbose mode # -D E-mail results to memconf maintainer # -h print help # explorer_dir Sun/Oracle Explorer output directory # # memconf reports the size of each SIMM/DIMM memory module installed in a # system. It also reports the system type and any empty memory sockets. # In verbose mode, it also reports the following information if available: # - banner name, model and CPU/system frequencies # - address range and bank numbers for each module # # memconf is free software; you can redistribute it and/or modify it under # the terms of the GNU General Public License as published by the Free # Software Foundation; either version 2 of the License, or (at your option) # any later version. # # Original version based on SunManagers SUMMARY by Howard Modell # (h.modell@ieee.org) on 29-Jan-1997. # # Tested to work on 32-bit and 64-bit kernels on: # - Solaris 10 6/06 or later on x86 with /usr/platform/i86pc/sbin/prtdiag # - Linux on SPARC with sparc-utils and /dev/openprom # - Linux on x86 and x86_64 with kernel-utils or pmtools for dmidecode # - FreeBSD on x86 and x86_64 with dmidecode # - Most HP-UX systems with SysMgmtPlus (cprop) or Support Tools Manager (cstm) # - Solaris (SunOS 4.X or 5.X) on the following SPARC systems # - sun4c Sun SS1, SS2, IPC, IPX, ELC with Open Boot PROM V2.X # - sun4m Sun 4/6x0, SS4, SS5, SS10, SS20, LX/ZX, Classic, Voyager, JavaEngine1 # - sun4d Sun SPARCserver-1000, 1000E, SPARCcenter-2000, 2000E # - sun4u Sun Ultra 1, 2, 5, 10, 30, 60, 450 # - sun4u Sun Ultra 80, Ultra Enterprise 420R, and Netra t1400/1405. # - sun4u Sun Ultra Enterprise 220R, 250, 450 # - sun4u Sun Ultra Enterprise 3000, 3500, 4000/5000, 4500/5500, 6000, 6500 # - sun4u1 Sun Ultra Enterprise 10000 # - sun4u Sun StorEdge N8400 and N8600 Filer # - sun4u Sun SPARCengine Ultra AX, AXi, AXmp, AXmp+, AXe # - sun4u Sun SPARCengine CP 1400, CP 1500, CP2140 # - sun4u Sun Netra t1 100/105, t1120/1125, ft1800, X1, T1 200, AX1105-500, 120 # - sun4u Sun Netra 20 (Netra T4) # - sun4u Sun Netra ct800 # - sun4u Sun Blade 100, 150, 1000, 1500, 2000, 2500 # - sun4u Sun Fire 280R # - sun4u Sun Fire 3800, 4800, 4810, 6800 # - sun4u Sun Fire V100, V120, V210, V240, V250, V440 # - sun4u Sun Netra 210, 240, 440 # - sun4u Sun Fire V125, V215, V245, V445 # - sun4u Sun Fire V480, V490, V880, V880z, V890 # - sun4u Sun Fire 12000, 15000, E20K, E25K # - sun4u Sun Fire V1280, Netra 1280 (Netra T12) # - sun4u Sun Fire E2900, E4900, E6900 # - sun4u Sun Fire B100s Blade Server # - sun4u Sun Ultra 25 Workstation # - sun4u Sun Ultra 45 Workstation # - sun4u Sun/Fujitsu Siemens SPARC Enterprise M3000, M4000, M5000, M8000, # and M9000 Server # - sun4v Sun Fire T2000, T1000, Netra T2000 # - sun4v Sun Blade T6300, T6320, T6340 # - sun4v Sun SPARC Enterprise T2000, T1000 Server # - sun4v Sun SPARC Enterprise T5120, T5140, T5220, T5240 Server, Netra T5220 # - sun4v Sun SPARC Enterprise T5440 Server, Netra T5440 # - sun4v Oracle SPARC T3-1, T3-1B, T3-2, T4-1, T4-2, T4-4, T5-2, T5-4, T7-4 # - sun4v Oracle SPARC S7-2, S7-2L # - sun4v Fujitsu SPARC M10-1, M10-4 # - sun4m Tatung COMPstation 5, 10, 20AL, 20S and 20SL clones # - sun4m transtec SPARCstation 20I clone # - sun4m Rave Axil-255 SPARCstation 5 clone # - sun4m Rave Axil-245, 311 and 320 clones (no verbose output) # - sun4u AXUS Ultra 250 # - sun4u Tatung COMPstation U2, U60 and U80D clones # - Force Computers SPARC clones (no verbose output) # - Tadpole SPARCbook 3 and RDI PowerLite-170 (no verbose output) # - Tadpole VoyagerIIi # - Tadpole (Cycle) 3200 CycleQUAD Ultra 2 upgrade motherboard # - Tadpole (Cycle) UP-520-IIi SPARCstation 5/20 upgrade motherboard # - Tadpole SPARCle # - Auspex 7000/650 (no verbose output) # - Fujitsu S-4/10H, S-4/20L and S-4/20H clones (no verbose output) # - Fujitsu GP7000, GP7000F # - Fujitsu Siemens PrimePower 200, 400, 600, 800, 1000, 2000 # - Fujitsu Siemens PrimePower 250, 450, 650, 850 # - Fujitsu Siemens PrimePower 900, 1500, 2500, HPC2500 # - Twinhead TWINstation 5G, 20G # - Detects VSIMMs for SX graphics on SS10SX/SS20 (1st VSIMM only) # - Detects Prestoserve NVSIMMs on SS10/SS20/SS1000/SC2000 # # Untested systems that should work: # - sun4c Sun SS1+ with Open Boot PROM V2.X # - sun4m Tatung COMPstation 20A clone # - sun4u Sun Netra ct400, ct410, ct810 # - sun4u Sun SPARCengine CP2040, CP2060, CP2080, CP2160 # - sun4v Sun Netra CP3260 # - sun4v Oracle SPARC T3-1BA, T3-4, T4-1B, T4-2B, T5-8, T5-1B, T7-1, T7-2 # - sun4v Oracle SPARC M5-32, M6-32, M7-8, M7-16 # - sun4v Oracle Netra SPARC T3 systems # - sun4v Fujitsu SPARC M10-4S # - May not work properly on Sun clones # # Won't work on: # - SPARC systems without /dev/openprom # - sun4c Sun SS1, SS1+, SLC, IPC with Open Boot PROM V1.X (no 'memory' lines # in devinfo/prtconf output) # - sun4 kernel architecture, and sun3 and older systems # - Perl 5.001 is known to have problems with hex number conversions # - Does not detect unused VSIMMs (another FB installed) or second VSIMM # # To Do list and Revision History can be found on the maintainers web site at # http://www.4schmidts.com/unix.html # Uncomment for debugging (perl 5 only) #use diagnostics; $^W=1; # Enables -w warning switch, put here for SunOS4 compatibility. $starttime=(times)[0]; $version="V3.14"; $version_date="16-Nov-2017"; $URL="http://sourceforge.net/projects/memconf/"; $newpath="/usr/sbin:/sbin:/bin:/usr/bin:/usr/ucb:/usr/local/bin:/var/local/bin"; $ENV{PATH}=(defined($ENV{PATH})) ? "$newpath:$ENV{PATH}" : $newpath; # Force C locale so that output is in English $ENV{LC_ALL}="C"; $_=$]; ($PERL_VERSION_MAJOR)=/(\d).*/; if ($PERL_VERSION_MAJOR < 5) { ($PERL_VERS)=/(\d\.\d)/; ($PERL_PATCH)=/(\d*)$/; $PERL_PATCH="0$PERL_PATCH" if ($PERL_PATCH < 10); $PERL_VERSION="$PERL_VERS$PERL_PATCH"; } else { ($PERL_VERSION)=/(\d\.\d{3}).*/; } $uname="/usr/bin/uname"; $uname="/bin/uname" if (-x '/bin/uname'); $running_on=""; if (-x $uname) { $os=&mychomp(`$uname`); $os="FreeBSD-based $os" if ($os ne "FreeBSD" && -f '/etc/freebsd-update.conf'); $running_on=$os; $hostname=&mychomp(`$uname -n`); if ($os eq "AIX") { $machine=&mychomp(`$uname -M`); # oslevel command can return stderr output, so use uname instead $osmajor=&mychomp(`$uname -v`); $osminor=&mychomp(`$uname -r`); $osrel="$osmajor.$osminor"; $kernver=""; $platform=&mychomp(`$uname -p`); } else { $machine=&mychomp(`$uname -m`); $osrel=&mychomp(`$uname -r`); $kernver=&mychomp(`$uname -v`); $platform=$machine; } } else { $hostname=""; $machine=""; $os="this unsupported"; $osrel=""; $kernver=""; } $osrelease=""; $prtdiag_cmd=""; $prtdiag_exec=""; $have_prtdiag_data=0; $prtdiag_checked=0; $prtdiag_memory=0; $prtfru_cmd=""; $have_prtfru_data=0; $have_prtfru_details=0; $missing_prtfru_details=" "; $prtpicl_cmd=""; $have_prtpicl_data=0; $psrinfo_cmd=""; $have_psrinfo_data=0; $use_psrinfo_data=1; $psrinfo_checked=0; $virtinfo_cmd=""; $have_virtinfo_data=0; $virtinfoLDOMcontrolfound=0; $cfgadm_cmd=""; $have_cfgadm_data=0; $ipmitool_cmd=""; $have_ipmitool_data=0; $ipmi_cpucnt=0; $ipmi_cputype=""; @ipmi_mem=(""); $ipmi_memory=0; $smbios_cmd=""; $have_smbios_data=0; @smbios_mem=(""); $smbios_memory=0; $kstat_cmd=""; $have_kstat_data=0; @kstat_brand=(); @kstat_MHz=(); $kstat_cpubanner=""; @kstat_core_id=(""); @kstat_core=(""); @kstat_ncore_per_chip=(""); @kstat_ncpu_per_chip=(""); $kstat_checked=0; $ldm_cmd=""; $have_ldm_data=0; $ldm_memory=0; $free_cmd=""; $free_checked=""; $have_free_data=0; $meminfo_cmd=""; $have_meminfo_data=0; $modprobe_eeprom_cmd=""; $decodedimms_cmd=""; $decodedimms_checked=""; $have_decodedimms_data=0; @reorder_decodedimms=(); $topology_cmd=""; @topology_header=(); @topology_data=(); $topology_mfg=""; $maxmembusspeed=""; $foundspeed=0; $mixedspeeds=0; $have_x86_devname=0; $manufacturer=""; $systemmanufacturer=""; $boardmanufacturer=""; $baseboard=""; $biosvendor=""; if (-d '/usr/platform') { $platform=&mychomp(`$uname -i`); if (-x "/usr/platform/$platform/sbin/prtdiag") { $prtdiag_cmd="/usr/platform/$platform/sbin/prtdiag"; } elsif (-x "/usr/platform/$machine/sbin/prtdiag") { $prtdiag_cmd="/usr/platform/$machine/sbin/prtdiag"; } elsif (-x '/usr/sbin/prtdiag') { $prtdiag_cmd="/usr/sbin/prtdiag"; } } elsif (-x '/usr/kvm/prtdiag') { $platform=$machine; $prtdiag_cmd='/usr/kvm/prtdiag'; } elsif (-x '/usr/sbin/prtdiag') { $platform=&mychomp(`$uname -i`); $prtdiag_cmd="/usr/sbin/prtdiag"; } if ($prtdiag_cmd) { if (-x $prtdiag_cmd) { $prtdiag_exec="$prtdiag_cmd"; } } $buffer=""; $filename=""; $installed_memory=0; $failed_memory=0; $spare_memory=0; $failing_memory=0; $memory_error_logged=0; $failed_fru=""; $ultra=0; $simmbanks=0; $bankcnt=0; $slot0=0; $smallestsimm=16777216; $largestsimm=0; $found8mb=0; $found16mb=0; $found32mb=0; $found10bit=0; $found11bit=0; $foundbank1or3=0; $sxmem=0; $nvmem=0; $nvmem1=0; $nvmem2=0; $memtype="SIMM"; $sockettype="socket"; $verbose=0; $debug=0; $recognized=1; $untested=1; $untested_type=""; $perlhexbug=0; $exitstatus=0; $meg=1048576; @socketstr=(""); @socketlabelstr=(""); @orderstr=(""); @groupstr=(""); @bankstr=(""); @banksstr=(""); $bankname="banks"; @bytestr=(""); @slotstr=(""); $simmrangex=0; $simmrange=1; $showrange=1; $start1x=""; $stop1x=""; @simmsizes=(0,16777216); @simmsizesfound=(); @memorylines=(""); $socket=""; $socketlabel=""; $order=""; $group=""; $slotnum=""; $bank=""; $dualbank=0; $byte=""; $gotmemory=""; $gotmodule=""; $gotmodulenames=""; $gotcpunames=""; $gotcpuboards=""; $slotname0=""; @boards_cpu=""; @boards_mem=""; $empty_banks=""; $banks_used=""; $nvsimm_banks=""; $boardslot_cpu=" "; $boardslot_cpus=" "; @boardslot_cpus=(); $boardslot_mem=" "; $boardslot_mems=" "; @boardslot_mems=(); $boardfound_cpu=0; $boardfound_mem=0; $prtdiag_has_mem=0; $prtdiag_banktable_has_dimms=0; $prtdiag_failed=0; $prtconf_warn=""; $flag_cpu=0; $flag_mem=0; $flag_rewrite_prtdiag_mem=0; $format_cpu=0; $format_mem=0; $foundname=0; $sockets_used=""; $sockets_empty=""; $sortslots=1; $devtype=""; $interleave=0; $stacked=0; $freq=0; $sysfreq=0; $cpufreq=0; $cputype=""; $cputype_prtconf=""; $cputype_psrinfo=""; $cpuinfo_cputype=""; @cpucnt=(); $cpucntfrom=""; $cpucntflag=0; $cpuinfo_cpucnt=0; $have_cpuinfo_data=0; $cpuinfo_coreidcnt=0; $cpuinfo_cpucores=0; @cpuinfo_physicalid=(); $cpuinfo_physicalidcnt=0; $cpuinfo_siblings=0; $cpuinfo_checked=0; $xm_info_cmd=""; $have_xm_info_data=0; $xen_ncpu=0; $xen_nr_nodes=0; $xen_sockets_per_node=0; $xen_cores_per_socket=0; $foundGenuineIntel=0; @diagcpucnt=(); $diagthreadcnt=0; $psrcpucnt=0; $foundpsrinfocpu=0; $ncpu=0; # remains 0 if using prtdiag output only $ndcpu=0; # prtdiag cpu count $npcpu=0; # physical cpu count $nvcpu=0; # virtual cpu count $necpu=0; # empty cpu socket count $threadcnt=0; $corecnt=1; $hyperthread=0; $hyperthreadcapable=0; $header_shown=0; $romver=""; $romvernum=""; $SUNWexplo=0; $banner=""; $bannermore=""; $cpubanner=""; $diagbanner=""; $model=""; $systemmodel=""; $boardmodel=""; $modelmore=""; $model_checked=0; $BSD=0; # Initially assume SunOS 5.X $config_cmd="/usr/sbin/prtconf -vp"; $config_command="prtconf"; $config_permission=0; $permission_error=""; $dmidecode_error=""; $freephys=0; $isX86=0; $HPUX=0; $devname=""; # Sun internal development code name $familypn=""; # Sun family part number (system code) $clone=0; $totmem=0; $latest_dmidecode_ver="2.12"; $minimum_dmidecode_ver="2.8"; $dmidecode_ver="0"; $dmidecodeURL="http://www.nongnu.org/dmidecode/"; $have_dmidecode=0; $cpuarr=-1; $memarr=-1; $release=""; $waitshown=0; $totalmemshown=0; $vmshown=0; $controlLDOMshown=0; $helpers_defined=0; $picl_foundmemory=0; @picl_mem_pn=(); @picl_mem_bank=(); @picl_mem_dimm=(); if (-x '/usr/bin/id') { $uid=&mychomp(`/usr/bin/id`); $uid=~s/uid=//; $uid=~s/\(.*//; } else { $uid=0; # assume super-user } $empty_memory_printed=0; @filelist=(); # # Parse options # foreach $name (@ARGV) { if ($name eq "-v") { # verbose mode $verbose=1; } elsif ($name eq "-d") { # more verbose debug mode $verbose=2; } elsif ($name eq "-debug") { # most verbose debug mode $debug=1; } elsif ($name eq "-debugtime") { # most verbose debug mode with timestamps $debug=2; } elsif ($name eq "-D") { # E-mail information of system to maintainer $verbose=3; open(MAILFILE, ">/tmp/memconf.output") || die "can't open /tmp/memconf.output: $!"; print MAILFILE "Output from 'memconf -d' on $hostname\n"; print MAILFILE "----------------------------------------------------\n"; close(MAILFILE); *STDERR = *STDOUT; # Redirect stderr to stdout open(STDOUT, "| tee -a /tmp/memconf.output") || die "can't open /tmp/memconf.output: $!"; print "Gathering memconf data to E-mail to maintainer. This may take a few minutes.\nPlease wait...\n"; } elsif (-f "$name/sysconfig/prtconf-vp.out") { # Sun/Oracle Explorer output $SUNWexplo=1; # Special case for regression testing Sun/Oracle Explorer data $os="SunOS"; open(FILE, "<$name/sysconfig/prtconf-vp.out"); @config=; close(FILE); if (-f "$name/sysconfig/prtdiag-v.out") { open(FILE, "<$name/sysconfig/prtdiag-v.out"); @prtdiag=; $have_prtdiag_data=1; $prtdiag_cmd="/usr/platform/$platform/sbin/prtdiag"; $prtdiag_exec="$prtdiag_cmd"; close(FILE); } if (-f "$name/fru/prtfru_-x.out") { open(FILE, "<$name/fru/prtfru_-x.out"); @prtfru=; $have_prtfru_data=1; $prtfru_cmd='/usr/sbin/prtfru'; close(FILE); } if (-f "$name/sysconfig/prtpicl-v.out") { open(FILE, "<$name/sysconfig/prtpicl-v.out"); @prtpicl=; $have_prtpicl_data=1; $prtpicl_cmd='/usr/sbin/prtpicl'; close(FILE); } if (-f "$name/sysconfig/psrinfo-v.out") { open(FILE, "<$name/sysconfig/psrinfo-v.out"); @psrinfo=; $have_psrinfo_data=1; $psrinfo_cmd='/usr/sbin/psrinfo'; close(FILE); } # Sun/Oracle Explorer does not include "psrinfo -p" or # "psrinfo -p -v" data yet. # Is virtinfo output available in Oracle Explorer? if (-f "$name/sysconfig/cfgadm-alv.out") { open(FILE, "<$name/sysconfig/cfgadm-alv.out"); @cfgadm=; $have_cfgadm_data=1; $cfgadm_cmd='/usr/sbin/cfgadm'; close(FILE); } if (-f "$name/sysconfig/uname-a.out") { open(FILE, "<$name/sysconfig/uname-a.out"); $uname=&mychomp(); close(FILE); @unamearr=split(/\s/, $uname); $hostname=$unamearr[1]; $machine=$unamearr[4]; $osrel=$unamearr[2]; $platform=$unamearr[6]; $prtdiag_cmd="/usr/platform/$platform/sbin/prtdiag"; $prtdiag_exec="$prtdiag_cmd"; } else { if ($config[0] =~ /System Configuration:/) { @machinearr=split(/\s+/, $config[0]); $machine=$machinearr[4]; } $osrel=""; $hostname=""; } if (-f "$name/sysconfig/prtconf-V.out") { open(FILE, "<$name/sysconfig/prtconf-V.out"); $romver=&mychomp(); close(FILE); } $filename="$name"; } elsif (-f $name) { # Regression test file with prtconf/dmidecode output open(FILE, "<$name"); @config=; close(FILE); # Regression test file may also have prtdiag, etc. @prtdiag=@config; @prtfru=@config; $have_prtfru_data=1; @prtpicl=@config; $have_prtpicl_data=1; @psrinfo=@config; $have_psrinfo_data=1; @virtinfo=@config; $have_virtinfo_data=1; @cfgadm=@config; $have_cfgadm_data=1; @ipmitool=@config; $have_ipmitool_data=1; @ldm=@config; $have_ldm_data=1; @cpuinfo=@config; $have_cpuinfo_data=1; @meminfo=@config; $have_meminfo_data=1; @free=@config; $have_free_data=1; @xm_info=@config; $have_xm_info_data=1; @decodedimms=@config; @smbios=@config; $have_smbios_data=1; @kstat=@config; $have_kstat_data=1; @machinfo=@config; $hostname=""; $osrel=""; # Check test file to determine OS and machine for ($val=0; $val <= $#config; $val++) { if ($config[$val]) { if ($config[$val] =~ /System Configuration:/) { @machinearr=split(/\s+/, $config[$val]); $machine=$machinearr[4]; $machine="" if (! defined($machine)); $platform=$machine; # Special case for regression testing SunOS prtconf files $os="SunOS"; last; } elsif ($config[$val] =~ / dmidecode |DMI .* present/) { $have_dmidecode=1; if ($config[$val] =~ / dmidecode /) { $dmidecode_ver=&mychomp($config[$val]); $dmidecode_ver=~s/.* dmidecode //; } $machine=""; $platform=""; # Special case for regression testing Linux dmidecode files $os="Linux"; last; } } } $filename="$name"; } else { &show_help; } } &pdebug("starting"); print "memconf: $version $version_date $URL\n" if (-t STDOUT || $verbose); &find_helpers; if (! $filename && -r '/proc/cpuinfo') { open(FILE, "/proc/cpuinfo"); @cpuinfo=; close(FILE); $have_cpuinfo_data=1; } if (! $filename && $xm_info_cmd) { @xm_info=&run("$xm_info_cmd"); $have_xm_info_data=1; } # Check cpuinfo now on unsupported machines (arm, mips, etc.) &check_cpuinfo if (! $filename && $machine !~ /.86|ia64|amd64|sparc/); &check_free; &check_dmidecode if ($have_dmidecode); if (! $filename) { if ($os eq "HP-UX") { &hpux_check; if (-x '/opt/propplus/bin/cprop') { &hpux_cprop; } elsif (-x '/usr/sbin/cstm') { &hpux_cstm; } else { &show_header; &show_supported; } } elsif ($os =~ /Linux|FreeBSD/) { &linux_distro if (! $release); if ($machine =~ /arm/i) { if (-f '/etc/Alt-F' && -f '/tmp/board') { # NAS model open(FILE, "

p%p-p3p+p;4:6-X+vv v3݂YYAT$AJ0;H `^(X%AiPT5Am`8 & +[;/oơ&V6N.PPPЀ eƅf!\"!j(; B0*  m m m m   = = == } 7 ww w w g{{CC#ã£c3sè0!L Sô0= p4'ËkÛû{W7·/o_??#"20(,<&%Ɉtt dEFEFDG&FDfEfGDPl!E呕Ց5M͑mݑ=}Ñӑ#"#"##7"w""##O#/""##_#"?"P4%EDzцF&f6юNѴhhhhVtHthtxtdtTtltFtvtN%EQZDyQAT͉EhQL[Կ"L/,?@  ̝3)+ Z+1bYEw0dȐOo`00 H5lАAፔ4k2x(e<4Ks5i?;=jk `j kԁ S>LMfnCF0ajj"jrśôi S7 L[v0aj2;wj S@ &6LO05}aSSV`8K 3 f8LMHQ0aɚ3&o&n2LMTi0ajr:ĝ 3f.LM18aH0dX*L6 Àfa8055w FSS"\<|B,bRrH`jre0rLM F ߬z0.?xk]YoSk` RxTz5Z3|NgMflHu*\o5k^}0<~SkQc05'`jO9>gaM?k/5~&: x<5up]{zԚ{105a^y}¼y[s?} ok_aj2'Z5QgiY7>lX {լ9]7^ ?`C!?`C!?`C!?`CHa 0Fc0vxa|0~a0AL&a0Zռ3?ӁSCK;ş<P?/#f{®D?oϮ)P&(jlZ!1XDʄ`~ ZF#5F]FhOh쁠t5%|:a?19/FÿQ& 4~F@ 4Fտ85h<4j^t5wjuFkFfSu6]-_5ک]Ɨ_5:_LMթovtFFK_GѨh7С_n)?LMHAivJ)R4Hi(qJ)-RZJi&mJ)R:L:Ý8A|H !ByP>TBEP1TBeP9TUBbHI!$RAjh! 2AfA drAny!䇪j("PAq(%StMIKIOH=%3GJϔ^;7_J HjA&w Q ݇?@HM6P :132!zZ̴vi:uAV@kh44A Ph4&@Sj5NYrgsuf2d 1DŽiӲC ݁B!Tj,QGg2Og<9?s^2wZ=t??wQ/a9Ò0dK?~!#%742ukQ+n'!clF猡}3Mz(쑗gA͡PKjACP7; zBP/ B4 eAC0h84 +$h24 MC3,h64 4C 2DPw&`*0 f`.8"@  6@ ((ʁ @ 9 P@ =` 0  7oB`X,ˁJ`X F`lہN`Ap8ǁIp8 Ep\ׁMpJw=>x<O39x ^o;=|JBx>QFADFDQD G$I<|oEň%e:zF&fV6vN.n^>A!aQ1d3dsd dKd+dkd* -=#3 +2 @vCvGf"{ {"{!{# "!# wĿ7$BAEbÐÑ##ccSSӐӑ33ss($ogdl,]fN2gl2cfnY}3GgL+sxΙ@ffI9ݹy݅Esv߽{aKv/^NsytA0] AY3Zeedj3 5, Ej#[V߬YYbYD+˝u0k_=KJgkzS^4x%4xY,U~p'Ȁd隱~胊d# {9y<JC'9w(S(/~{ sKiQfE胊uq(-4s03H)B㘙w ٩ۜa%+ѕ%U&VGQȷ=Q)E <# @D| a.;u]sS7PNhOr<RvDd~gShCBaōj7ixg@7V0M>Y0}a kl+Ç؋Nz} k r 4݋`OqWiRjTX}xGJ`gAve&+uUҲnpw ܮg#ś$ ,>Yw8G\AQRvnQo9: MDEG_SfmݕZD19J˜1 ~i^RoR#* ҟpQ+Gw:[/N;nQfQ3\#œ9bRp9ط6 6\}xJK"[ KWɿ i_d! wrQ^&.ϷElneo`.MHߐ xQEZ^_l5.fʈqv E袺Eg4[3TH܎yƜ>XqA{dj)UK5Зq|xd }湳a`_ySM):Vva6bY'yDD]sNc1Cm T OJavN뤻s^It JQaS~Z;U6+YfV9< X")LW:1:v#լLDc &/V bjE=UOP𸌆Ax=ǽk_f9oGQKQ+P+Q}{էE10.$O\k‡GN3V.Lji=&t,}/$On|y)*9m%9XiRus/Ze1qͱSxrgd;ⲌJ#,s&*ٚ|C,)ȳ ]?BnVY]⽁pD7?@^LW0 `7Q='HLčKM)O2qspr;.S, m%-V$lv{{=9_ )v2>Tzu,&뇃)4? (Iߨgi|[ VOTњ"R֍ڻ7fhq>  -QU(1~a&a\@5YȖ.zP1B;[K~#&DK^@U4xx̔2 s Ǚ rF k ' ? ss' X} s+-xUmU;SNZЮѮtn}:ʱwt,p9J^ ApJ|4[LG\|Ǒf%agFf~'x%qv\ke;!8 Oٝ6sE(}Qt*0D Z &cKx}10+NQ IA[_^TD=R \*pú]?ɽDMc>v#yReT.HXhBCZfq^Vr̡GW)FcApm'j#QebOoNtx KO>/Uxe7EP7W ^i`pEuu= #']<B4 }./23` .X#%x"s!(_Qд|ll򋪽v-2\P:W#?Qvi83xIE' vUyAO6JH{fr' 0 +BsAh ٶ"Mqݎg)EqS&9Y.&0q "8U[mm{gqOg9+}_,=HDrgeOyq2!y#U+)kӄZ>q Y8XWvB5I=WsNRN= @ loA7ڋFc'& =|j{ڞ³2z2JQ&߬xqwadSf--η@1_SՊqS鵄`:s'«EU4e/52Uj9򰉾>f +&> ?88ԖCݝ=^ޔޜށid;k^9xa]a#aXY5ohBkQ"J#T)C*(+FjKFia}vǀq. vX0j"ciIZs#"N)\Y.˼[iAܗ/D_f{m!GG7fnҞpP9r·Y$]eL#U~im98ʵ EmG!(cu(P,TdgB\{R%$뙙CJ@ Giܱx&y fvw3rQ+(-p. \f7 ,6/6%*؃a{,'`BUX.M>vYYeWun-æ~N`?`#y/kX;XeܫEI_nPWFx67z-zMntڜ9C N-l+:_L/E'*5,R\Q?Ҵ,rv~H=*]K4(͑Di \S#7j%k"#n+4s]pH`L% 8Қ%&Fz:fú,;3;D)=/X펭πCuĿ,L\ 7=_uEضjD>a )z^K b?sɹ^%6#o,5O!! x Qwh%$/U;c'j?tr5NJot<$lP^ )}L oP˿*ƃp7= òJ&¬;]1OV 8ڋ׶Gyc#ٱ=A>20:V+PV>k#psqQrdB7R'= jSՁLJ,II%;ocw~+~Br3_YBF*4 CT&;3Օn`"s觃G)+&=AeQѓ?[=7+S{Ӊ`wc^V 9OJ "4 +lOы mKO+\itn9s1+] ASb3 BiO ;{'_T39ggm+EŅђң,|D1SAPT83MH4WSӴ}@`N.Qjћp]$Hg߉ŏgY ce2 OG \ pU""ϊ}?,BҋG#31Ԓ55b&%?;ިFVJ\v~堏a5s?r2&$x* z+w*::ʸ<?Rz@BMfMAZ^V|@XC^o 2>pA*E$)W8btH4M~Ux%=&' hOj{{bfrL[^/Byhd$q|6LqJQ3υ7;V%c(I[Ō'LQdc}"X FiJ1zQ)INvgO3 "MTٌ5/+ ~eå׼<W>x,ܙ\wdzjWvEuB#.9vx4Afz^CL>ZdɿR1TR_JŏG^6:TULQgGUj{?GV^^ŵ*r9 !c杩<$;{g_ BzIkh1 ov`mbKEEe=t]DN)B}#ǔyBOŇ&2)9UXlum\bVԙܨW0TAY-*@-RڔTo- Oe,g5D0hP*;e$]˔,25W1hj#' =cٽYUgd[zJ> w O)bkQQg7׌wO$'&jXpnW`u_-c# K-[ cg\G}F8q$,RXUxFQG9>Uvn=p i~x:e)hHH"O>(o0P ~ػ +}%$vOP {" Os2:\3arpDR&rE⾦rQT{E5}%S,Yy+]=jX,h.I]f$׃=܆ٚvE/@}V(:sLG"MlK F+zyG;zm[c;X+qUJAJc-ެjXŧXNeüY{x#KBVY.g$zoZ]+&Ɓ/#Xl "=]]+:ʇ$X/!,1p⤶FYTTjYTRm̭ko}r6,\ZUKFjS3l:{GPp\o`*0VhNj(ܫ1Y[u1υUXo_#Nۖz"TҊ:{3ֻޓ{)^n0x*8[ĢXEJ4_ 7NfN2Vcұ'i]IUNbG= EUg1}!QDY'>bDMXV 1Qv:vv1!-O`+\_ku?{6Sܭtrꃶߏ0)Zw|ۘ=yUV7-xMժ-= ̨0 4?qPW}V4/Fb|>SNnJZ_/ 55 555 EBQPzɑ-XQ.TDC-@Em@mFFBDFG]FBDF}FGg4 @bF t.E64 :,wCLL/L+LL&6&S33]1 L6)H1ZLclĬl\<ļǼ||Ǧbka`[c[a;`ӱñc8,˕bEX-VOu`mX7֋cBb2r :zZ&.!1u3~yCZzp#qhlG*pr9qU8gyKKp+qp;qpppqpqB/qwpqq_p_u*G[;#SQm3sL|.Kz|?@"p[G++K7B*a,a?a aa73Ep* .PJJ>% F`&!, l%,"$$%,% ',$&$\!<$<"6%" "$|##$N stT"H& f0QKXCI& jh .#ZK׈7HIm??H_I(6iii0iI|@R)d&iI i&-"&m&m$'$# %%&%']&"}% 2\\ܐܘܒ܎܆x܉܃<<"&O ɹd+C֐md?yyy!y9y-0<>!=3NRfSJRpDFIRVPSnQvPRVSQSR.SRPRnPPnS^SQRS֢66vYLͤ*MPT6UD-RT5fWP>ޠ:Wײ3f7]?CCes#;wgޟ+~GO/eNkDkHkC;mmm2m*m K#Ҳi4K+*iR&i!f-m]N{@{DGE{H{N{CD{OMKGoLoIOg{GG'ҧQt<CGJ".^EWw7wҷwӏЯҟп_2g֌ :+#9#сўю1craazFaladcbgc\b\g1# 7ۇ; ps(.ҸlnWsm\5s \{{{ q/propOrsspcFWܷZz܏< oo. \<-oOxI&^>ryyOy{yyyxxxmCu-=mM"~1_G ~"2X_ZЏM!h'$-.&+"*.&Q9[0C@sS `QARBEp@pXOpPpRpNp]pUpGpWVT&l DʅCÄChLD!S"a% KUڄFaHnn^^>>~~5u   M M1ElUE6QhH)9Dvb|IEZM\db{E]e[Zjb[r75 Cz P2$d]{osw=sF{7ﰯoeogbfqsfrq&spr0g3gϡsT#p9+og;GYۂFqqs.p97M9'989#0WD+ n_nngnOn<0WUq\5r";&q\7k򸛸븟spq"<^. eB5^^n}}ƽϋnu>~ËM5Iy#yj,xyy </g--x;xxyxykxxgxyxx_^yUQ+1Eg|<'|*_|ƷsEB~)5=#3NaqGoO݂Ƃ6.^' x WP"0 JY@&|/_  6 v >\<\|-\ ) -$!&l-l* aP# ;l+Q;QppJxQxGx^[ H4XI$EE=E|R@C4M4VEDE*Q]Ms"hhRʼ}Wai3iKii_ @ittttttt4M*fI-R! HM҃Sҳ[қW-ddn!~DD\ KdD)d:Vlll[5by\,Od9^>ENs9]Γ+Yy|[3w0ThhhhhX (f*\CVBZT\VEDQXXدج8تإئةب888VB7(w*3see3e2NLPRW&))g)g+g*4%UISr\%OV TTzIiU:9DZXHSSRuW%zFFfU_EP1UFUJS Ǫ=]#TTWTUߪި[kz43yjڮ֫KV*zaq9nN!1#}%[ M#MkM+M'@d E!k58 F5nMfy<*:fvͧGfڎN8mIMR4-\+jSjAJg c!AU{D{L{R{Z{^;]] ]nnn`&::.S'Љt"].WW+:.CW;ۧ;;ۢ;{oo!F6t?{{G'z~Oӓ }zާ______߬ߤߨ_߮ߥ߫?߯?U:NDLBkagljdaiR p1 ݐop`(5|jXgXbj8beX5ذpŰPi``jcfxmxf3+>uVrV&Y Y3XYFdɚ5*56EggixY,}.j8e2f9\Y@/+? +UUfmkao\`Fgӌd#1rlh1ڍV0z cĸĸ޸ɸݸq[NUSCokdgkiBL&fd&IbR4&hlS)TbZ֘...4ǘ{s33ƜifYnfd KKdsyyyyyyyySQIEgK*ks%mid4 L-i KlacYLʢdYr-jKee幥ʚoZ^[^YYZXc,#íC1Vuuu5Zb]e.=yVm[ZeVue]a}akcz^5hkda}fkfKYwFg7 mmm6Ʒl66&il#ll4v[ms>aۗEEv{dnk{=9=;{Al\){i3۟^-..:ۑ]e4tϳg_;}%=$:О`lOO/X;ζgK+9vczAaQgOj95Cp~~q@1fWXp$(8G ;ԎCHup"ށq>}?vq?i}}9iN9sZtȉZ;g@Ĝ9Sr r9srRr99r G#1r<9y9`NqNgggggAzpGQ{=/[kk5u5!|Hʇ5M|$')+|Rg}&y}+|}}[}|wh} CIg~_bjz*V}_o/ZH#0;P@@~48$0E*zN {?.OS7__=Ϳ j)\жMQA˂ F-R.^@( H@I@U`(H/d BG0XXTX.,\Qpm wPxd ,Rxn`|opppHpjp~TAR0#HҠ , CUM -ۂۃǃG'] WB͂烯BPPPPPPPPPPPRhLhBhbhzhfhvhjhN!V>2CPvH2!{(' BeBKBC[BBCW"BϴC?/jQԴhtQQEf!E"yhUE,:Pta7m;w+^ܫ8x` )Q,W*F/-^Wz?.i/KJZD*T2dTɌ%K%Kp% J%%Z Q-J֖l(Ytə/JΕ\+^rvɽ'%ߔ|[iɏ%Kv,\ڣ4gibiҾJ.R:tzRDRx)4T^_j-KC KWn)[zt{ӥgJϖ.Uz\ͲJ~W֮mYLYe .- .RX֫,,lVвe(e2e~٣c}S-oX޿w=ʧ+o]>|R3IrT9_.-w;W˵%KWo*?X|GO._~?)[ѹKE EPapVTx*e++UXV8UqsW*U\QqAEdE?Vx]meO*UWX9]W+)JV%RPɫTUJ+e ӆprJfq5vi8*J|xzM  1DF ' 0;r&R,@@^@E1PݨGv2GFl\j-ú+a=L]YꑪpU˴M&xLMus:~)SB ab;#3d`ZeLTONf?!_dP)n5yju5ZDkC=(gbYV;8V k0;JeZdbB&V~l{ˉL眮jTqox|̚xw_ & @,$ B0(\#<-|)|&|##"Ƌ%ђFlLbbU}ҍݲ^Ue*.Qٗ۲F4K^ReBYj&z:^ W3ZMRUǪNU5U]43U]*fO _f[4zmmK6&gzdow6r~nָwW%=y^UV;]ի*]oFnae 606090>;F'~U}7_'^Wwo/O_8Z˂{aՕ~аидЂ" RUX\Q/XrTQ*-n,Q)Ut8xI|f4^/W+UxMVNQ}~F\ l++jg\п?X/?;گ/[mZROϔ 6Q[/_\n[0Q "g{g(W6sTdj?DE(Fx|l#<~@MT+??G83X]X]9dm+5udEW"s>FC̡o62?G^lT??G3^T'U``okz^ |{^#003 X6XoryhDt|MXX7S X9 `8G` ??BVjF_ |Yy`m?[?l#[?CP?CP?CP?CP?C .  WCе( >>'>`v!`;N/Gr};گ>>?Aj? `0? E' `0? `0? ȃ`0? `0? `0? `0? `0? `0? ' `0? ܗ`շpOGU_Q`"1c_}Hd"|Q_Q Qs?ϑ)5w?DxS?D";<H]\|cH?@nCj?@;"s\!?GxQ5CS^=c39M6rGr8WʤRM],S"Y+'Jdq,4N&2dL8{989Jq⨿pewN;ƎP`9cT\,ʹt@T@i";XdOŲ"+DL&8vp /ci пwq*U^Id΃34LDs#"^D"D'XJ^"**5N” dt)W"A0\9#B1C!`h $ ?f`K*Fz_ĻGc#acK4Ed}wq܍_ LD;20F-J9{V(q͐ޕS2C'M>Xq ݛa9U.\8)z$"U>#1RΫ_tX$K\0Ă#KRTF,e&PWQTJtHΔ8ȪpRA` 9> Ȃa2k)9qpfJ#3$E d ڠ̡C|;bVdāqV0j&"X` T)t[ ;Ig i$C%3:6vB-8haPd&\W޳$\EҚw?EX-`-rqx:22`U3b`x0O2#lWRܚ1cb ΉpYr9%cT5Yl1$RSH? ? 5?cHi0u"<: o u_$gY܀O'f5f ̡A~+ȯC??r~Ga>\_SC$*GC4!?Dhhp C4W]o!?Dhp C4_Oēڿɣ'a#FE9>OW>7x?C]ڢ3U>ց(ޟ9޿aK?]gm_k+=F4 [Ɵ|h=FL:8Y{XO1:g_`=F3g1Ϫ=Fu3FK[1ZM=FumLhFu1=F{}1:ct^{Nct?Zc/F{%׾/ݾ=F!=Fܠ:xT{յHg:xP{^kV>wb`ܩ=F%K=F:Q{@=nuqJk18C:ƅc$ݱ#9Cƹc ˯=pt1Fk1[{QcnV'j1&cc\L`|V{cLY{uqǘ<)QRA A! ! !1XHHSH3HsH HKH+HkHH[H;H{HHGH'HgHHWH7HwHH$ I !}! ! ! !C IdP0pH(hX8xD$dT4t L,l\<| !(`!8H $ 7MJjnNX 3ѐOո01Mur\aë#ÄpFImU2UIIM'TOLjS=zrRӤfS&5OjQ=zz5:=\PMΨ&u5[Rq#ↆظqI㉧7'nJ<ջa#%.Lܕs踉IWsV/Wϫ_MTSM _A~lLJ`'P'մjz5YJ/² {v&a@ {O=1x_| >//JHL 6"<> ,Kj Y YCcռjʆvjآayüB6(@QQt}CDs%њhKN':ļDObN;ѕ8>qx^] !  &Ll1QXO%JʼnDR"/x+v;DYeUuMm]}CcS<%O3xv<'3WRbR>I}bć=ý‰>~A!prxhxXxxxDxdxTxtxLxlxJxjxZxzxFxfxVxvxNxnx^x~xAFaTƄa\8%N P?4͇@ AhZ-@Kerh t9tt%t#tt3t t+c'mO;;{{GA&G'7Ln89&96Irf͓[E[&Jn&mr;&wJ%kr={&JNL'ormp8§3v)jn!(t)f oo F݄πφ$x|j2LN ^F@P %18q5nӌg4Mmh VfA$<b>^aI1qA4%DPT!15P=f f6ffacaN="`c$)LnKnG>@kLIG30s)s;.;vcv_~/ ZKґqYR ]#ˁww/#p]9ywP3PQ. UzE/DWb1 101s1s0T #ƈ0;0O0w010bb``^b| .1uKu}`|2^Wp+q|ƃH HP'G;;bi˘؃؃tIA+AKhdDzM_StTPUS$)C9Jrr[e-sXn\{c\x1|)#20cvfVg"MPsPP3QQT&* H0l lSl,%6  ö66Bͱ Sn\K:,5)oԁCR;;GGmx5ފ75x LH%'!"T5H IJ.OnABH֜֔֌ֲ:Zs$!19;==3:A{A URP\",+L862E֦a&e1y̷_XZXzXD%wNvw]`<|(|bHE@"P шi,bw2ĚBKHLBDHE =ߐ$M # 34!_ E>I~J55F т4MIsф47MOˢih2Z&DBZ>O301G3^l8FQl";MbadSv*?-* fSd J~.vI4#( mm?m;,2m5 9qg]iiGh'i[ihih_ҾbNd.gdVڲڰ vXV#v3v.dg2`Cl1[6],`k*J=,>ot<<ll|!&8(.'XWS```KP' Hܒb@ hl)[ʕ^~%\RBV)[-[(W+J6~3 ][DdQgZVWF1mԴ̴شѴȴڴҴŴʴ|\mifl)[ZvY*---k,,-,K,,-Lt7''ooocBU)5898)8.8=85= u=3ӈ_!!>GDG\BB\C|JEP~B4= ==== }}} aJ0k{+G۰a7c`cwaWaEkj!Ǯn.?#,9 S.N=.5ã<__ҡң \Gńe(" . #^$ԍHA2>"Ud'9&dEiMF$RSRP$FIVSGaЦЮchohQoiohOi?ҞѪi/ 3XA8VVV_V2Gv)s#Og[ؗwاٷWgll,&IRT.}n(DvLCIvRWYY1HPWKKj]P:)+(/U1&jU#uu[uSu3Llͬxg4g5ǵFY־ !3446`fV/MwMLLM'L7MMLLwLW/, V5rrr ܵ6XZ *cz]ǥL4='66>&l!#l%l'l#ˆ("$>&%&~M|@CFEƷAդdr'(>NaREHRRBɥP>O/gfa31i,4k>kk %-'333L`98989( 333ӟ3ӆӑ3z  z z B!d B/ .H. B-La3iFFJVR.{,}+!ZvMUd(t^[qHqDIYKS]_Mܠ<<<ꡊSU=T'GGEՉA8uP NP4dMФj5w4555456S{QPJ2:b qC[CKC;CgCWC3C'CX#X`OK>%}N:+>9}|:-==}f\ppppClLlDČF 3gth*_FیN2dtȸEMIFE1i+i7yy9, s|r\L (Frr.O9DAJBI@9O9LNFD9BLBM_H_N҃etM/gW]t+ΧNz1}} =@MtKе f 3Sqd&12f)s 48+b8,z݅c,sr%g#g9'rrrZ+8E (S7G/44L3d& C S C ckyy92222ƚgY5uGwYW[V5.:j.<^NtvAg3Ǖ{A.Oggggggy.;Ęw9ﺯ/—kk[==O??,tyAEPT%AyPT7׋AKV(**v #sbiBE6-E 4} }}YL8=΍+,2*\΁YqqpMF\΅[+Nm6$^iIiii^U)tcz 4}9AF$% |AKlBLΘ1+-iii2i)tt<,$$"ܤl|LAJI|GyMyAPRS~P!ִ9%t4}/!(0d]D~~9&Kct%ke~Ib4&gY"%g)YbeeTjV݃ݍS9Ϲ͹->,68$59(Wy͟˟/;OCECDEXQh-+%z4Q/QH$$-Ɗ&\N".."rfΙ323Gf2JKmRl,Q6\O>V_>L OwU$*z+ RTߢB3XLXDh"ڐ6K!uhV@7OСeipAjXAbls&&)ی3c(3<|3,t>A/mͬ7j?>bٚZOXZYFۚ`+Fsvs5gsss ǹ)nƺ n{{{{;CX<=;==<<;<{=[lufsO^={)LM}y^F}}C}# |c|5LOzb- 9~a~a0/s`v JЉ袆E}]aѳV8YqnAEnEnBnFBFA~܁\<6Uh:6f: =)m%M!a]֩mHiԴ4l?m~0mn- 6Nߗ~4D];7Oߔ4ȭx:jgj ljsj+j1NON]@HNCmFmHE%00&2331&02Z0221F23:02JVb9XNVecrPnN_Uq)\,WMZs.Kbs Y|)/ [bzEE>QhHSh((*-mɄg39Lb 9?IʜLed3ddby''I)Ir '* NxxR/ϕהU_RTtFS TDSQTߪ!uڣvj:_mh5F6PKUYm.ԩt{uHooo54lFkƕƥSn3423.o֘f%2fll6e6mmj۸6md'W6ƎFu4t:s΋+ ΫΛcγ2m7-u,7-q;z7ݽНv 4-pk:D7C=.1gMC7s>}<*;6yޘ͕My>oY>[C&[;~?H LLL *0<0' 0#0&0)^X,  'k* ||!E-Z)-j]ԴMы~ۢ,{Xal^٦2y-.Kc%yiS)C mE[0ɘHJ)mSĤ4Ki1}J)-q?vLmHJ姹4iiD|L0//&( 7 w w׉͈ [D I8R* K%9<,!o΢NΣ4*JSӨ Z22 2C@1، !Cǔ21b~ZZ*qWp _psKpwpWsp?~=]Ÿß/&&n+Olj["艸8YH>/Gwww+j/@v( >/\TpeeK`iDl҇C?u(] -.nZSd}Ɇ{SJ(yqsQ0=1*vh:Fٔ28e\ʘ)RKSRS)#S$**6K[^HIMh=)1[#C7DQQ@$*:*6y69 y+UIeSE *jST O͢.y5Rjum034 &cl`,c3 +:ZjF c `j:jF^O^^;-/׆}k>Us[&DaffC'LdYj1j1BK''̙zn'<ڵ׻Pbbaph JA2e`4r@2 TRW,W9U jڪkl.>"mOmWm7mVCH. OwO/w''GטV֛6NOXY>YZ~ZY^Yn[YZnXX[ 6Mg[[‘wwdi54j~@͡Pw+ Ղ aL\KR}M|}|}-}Go u+-$x/x'$(*: 0x+"x?$ U;;;wD:FG:GDzFF:D:EzDQYTFu1 6 +68|@?_?P|} bB@*ޘiii9wП\\\n;ɾMMr`VnUk+)!,,A7CA@7AD+зKb%8"N38N8.Nq %'!%&z;J#lf<<<899'9;98788G989{988{jqv!Q68HhQ$DDSE,S4G4C4\D:IM\eFp.烛{gTuz:T4 4 ô#Ouu]naq888Ǹtttt||Z*MuݭuMl;{{oF原:N͆LH ),H +y!~'j[7?__4~ O  O  ,,j>ذX<%o[bhbP[W_hhhh[3,<"y9(4*0<8ENQRT: GǤGG2M2323]3232۲?ss||||||µ¥Pe/3+zHg\gEq }\pppp F&ϥfg`e>ad a \<<:.u]T&r*D7EDVQJSk7$uk{.x >_oA; >/ow7'NJ׊WO{*JONT\;];Y;WBQBNJLZVUCIPݰ̰ˆ756741}5703321?05_7߶NNNNδNM}+JU#}ݎ=gκN*!7d*Tr ->>o/GNx| >777η*(:6>P/%14 N N?߂?Cós3ó#S###"%:Ψ=6*(VU$% Mbvh&$ rB %0'O*?V~$>-y%!)5?u1==%3<[=7&2":?&?(-)*.ܬ_9ppd |||nmmzZy]y}CTXSKGMSi{5-tB_[ۭ۫۩ehdXcdYF񰹟cZiVi-m3mm?:qqY: Aǡuh;~ ?|ߧ@@@ *T3L ü0'Lc""pVV%D201&*.NdKWϕ_N>HJ^OLIV祑tizGf|fBf\f`fIQvFV+˝ˣ~5-]557BxH8D*BYU-mks6 =C_ޚކwp>Z`R fH20=@ 0ֆ%acXD#h >&q?q>q7q0q,q+q;q% q:q-(q5VrSaoW irzWfZfVUmaYiJfޗgyQ^RRDaS7rV&.#DzۆۂۖKJ>^ȇ(LZkikogOPtKyzdmlGeF,R֯AjdjTjHofi)ىٳ9L]1G~m~S@~[!_x[ٶRɫǢNmK b_n)G *Ưi%UohfvS@߯=*: '"̲e貒Ը8br*fU _1&1rXRTY;Eª{%na @1 $B`X,ˁJ`X F`lہN`Ap8ǁIp8 Ep\ׁMpCxR%Ogsxow{| Z Z"#Z!Z# "!#: #==}}b0bb(bb8111 11111111 1111 1111 1111Q@1E"v[+ E"MHW/2LE"Kb siRgq3C?PdtUqc4\ܨx`q@ctɯRIv|b bJ_}F)I c*~^|vJ[d7e EMQ4;I?ΪBIZV_:߰OvB6BA/lQY+#dMd7ds$z}I%MJv+\:ԏFKDh"Z:)Fbޥihn?vt52,¢8,&b,rrGGG'JHKJ$ R2[̑̕+4&fUXWk3jlhivڝ3gfh:%%]ݑ8$ 9 Y #$9 I@@EN@2%J.YSZ], F0f/iiSq$f73? ? ?? ?_BEH\JLS0q!1J87/%DPGS%A)ޣգ5h>Z楅5z~~~~Q5bYaVUƂY edYcYXJ;??Ocs3T<>?G|NVN%b[D$ (JK*$^nأuFņ3QNt㑽h!,:? ${'%Ef$ HE>CE"di@:zdY,CqY#ezzO!%CK .UZ~xi0L x1bcp1Ä0 a`6A/ŋ  «,o!6 N#n& %!n "'n!"$^!'&##n"%\r\NJAYCYLOLYKYNYE,,,)K([((Kii-hmEt I-;nj!UƨhhhhhhhjZ:Z:ZZ;W5555}C| ?̏|?|5?J~eb*#(IH^I^JHKH.IVKJJIHvHJH^K>H.HnK6I.#'$%G%$%g%%+ir'bCb)> =67 +&9#35y9e.*$fUSPnPSRNPP.R.QRQPPRQӺҺѺӺЊhhi i9"zm@:a`b`J1Qʘ 32&2&3"TcXYSXg Yٍ5X/Yٍ XX_-X?-Y?Y︓S+{y:zF:F?wow_7O77_OoO_O{bxttttt!m+-m'm*&(\6҉.:nҺ&Jz:&fIYJRT)eGgʗʻ'ʇ*HuJu@uLuX]EYIRWuTGuPuDMuRJF3P3C3SLBk!t5u_??tOuM5Mu5 s s S g W gvxTTl4l7;,5,u,m[׶77_߳?_߲__?vuvu9;8j;9/F;_:8?9_9;?8?8:89PGQ{wBE?_;<܏܋^]]Lb$:Y,FuBDF5GuCO/ȯ֨.^AFh @@BFC)aJJJh%l ti'5)#/ymym0 ؈8ԖԊ44ԒԘԚTԉ4,!/#&Ԡ(+_{Wj5wZZor *P:@3 _I /Έ3<(g)̨`YmYYM8vT4)GQ9>Ial&gIl4{$ϞȞɝ͝====ͣff΂vY!19````X0U0LQLBS[0P0O0ZCE_^_{\Q^D\L]TRVNMK]_M?\?H[?POUG?TW?؀1 HPj(1 / o / w ƠoLMLSsSMScSS=S#S]S33A2CNF6VΖfƖ6i6lKⶃ}VQώjA. ઒<ɮbW{W_WXFINP$:KJI4D%Ȥ0i# 7!'16vv mmmmKIѓJex{;g7['{C\d[ػjvbd fG2Z]װ1ʪgCl9{1ydGm, *RLFREUZAqY (+vB`IA@0_,&AL8"⠤ttttL-]%}.} *"$&=&'+"#},%-)$=!-}-}'!,= =+=.=' (-*=-}()h(h-h @?**j)+ɿɿ(+Q4RZ&YiSuTVV5UQSQU5VuRyU_TTuuoumu5/_uu}'u G֜\М }I)y9mD^ԍ ՍЍ ԗgg{QoDAl`v~#2c444LCMmL}MMMLLLCL#MLe9i^dngi22222222ƶ*ly[vvvvvvvv>>>199999ĩvE]\]!ѥr-v]Uʸ42. k+಺ֺkZ]k\ZWC<{=[Bssسós̳ݳѳsʳɳӳsг۳[y˽˽ +Yo̻[M{y3ޜ7]] zްc 5h . YB!+t =7?|-|'|;|+|5|/|?Zmm}}}}}}1R4}}}=}}=)7{ʽIsR'I07%J#ҏ3)TU*CP" DQyU(MG_*mVڴtq2l M.&^l.ƱlkÖc`>*%%t""t'&$ t ' %L KHEI@OCd֒H$#i!@ғ̤%Ur'H.RD R /ȧ'ɗ'g( (uu ULDC@NESXPhj uu0HLEEIKB::66N//dglgb<`ab`|`cbd|f6g|cbag`avd6ae"Yeu3g샜<# 23ɾþ;>ľƾ>>>>>~ǾʾsE\p 7-ppq/T>̓L<;O3D<%!%+x%x!x/l,"*x)x$"l.l"(/-8%# 6 [ ~ ~ [  n > k . [ {GLj'NJ)qF\.-~' (de3ded^X84KO6A6IFddCesdehY @M&QdL`YoCeddTƕeNd%2l_IEI1HS1P1X]CM1DY[1Z^9GIRz>G )f*@M5X5TK5D5@S]5\@=P_ $MNU=@=X]5S }m]#Um6+ѽ3=WOK H/B@Oӳ jʠ4ȍkƌiiiii4D0M3/4 , ha[J-8 " -R "X0m[mml\϶6߶vՎ#(%lGxxD8:9'851}gfG_/&#cۮǮk3+ϮƮ;ZU::zn:zz:znyyyyyyyy9yޫm}=-]ޭ r_ڗG~/s =ڃ;{ۃC= ] ]  ] ]] ]   ? ?? ?    ?Պ!buߣ?ccbc5c5b'Fbxxxxxxxxxxx8"+OC(6:^3ުT*GpҚV~җt%cɃw)IJkKxR^*voAFEAAB@mBC@CG@GDGmAmC_-1KL%fAM)9I m>%!s^l{{{{ {{{߂PJ8$aa$` *HȄq6AAE:J:D:IAFZOLZGK:FI:BJG:ADB:MNS:SRT6u6KUR%TU@SYw4$666vvvvv>99ُ9/ss s:sÜz؇/9M88u9]8EUʙiii89898889=88O999]9 7νr^y^O" ‘b!KNNx!QhJC\;^8L(N©B $T G)B-",cSē3œĹ ?ſ_d91YDOV)KdeeeGddeeqV:iRYA-5YFe!b^F9 YJFH1CQ( b`) B`*&+)9 @)JB_1U1OAR"!ePSFaXdhDl,Tluƫ'jX=Y=]=OQWUQt4:KVX[CUGK]MDSEZY[nautCWH::geޭ/Cz~ޥ73z>7b0[[ Ɨ&c&IiT&Inb&m`d^kZ<%dY ,.Y%n6M`ؖږؖnnٻ:8C8P:hB1tvtrNuNtNvNswOpZq\7=q݀{&n[B4h0=ŭwqOsq]wqrOvpr(w{ 1C=pc27 #<_+<7\7kzxOzO{xxozoxOy _wwwwį{6??;n;j1868'8; r'BS!AHp( P4  == == } } TTԌԎԉ-N XXXXXXXX,gK@|tiqW|`|v|z\đqFƙqy|pgQqe8^ŇWWsx2%S3o)UJҧFU/ uٕ9rŋO o%U3GM m#E+;[C={yRt%1:9\G# QB!86  0!F'K0ttttttttt#WI!!MuRT C5RTOQT+L Q T@#JihiWighhiihSS } ?7sT0Uf)Sɔ0L542L.s Sd2q>^~~y2Qs%Gűp4g)8N)Aql  G!rWŝ[ϫ#݄[DžgI:*.aL˄!=µ½CK¬p0!\!\ , S¨ppxxx }k=d@.X ہ65X%s+࿠J]Np,8\ 65ee_Q`/p4lv]") HTD&GPSʔ\PMQSUs,JPkJ5_-ThV:ږڦzm:άtNLgׁ:Υߠ_ߤ__W %UņorC!aH!jgm=ˍ+oL^So)d r 2KܦiiikeaYfj9`YdYaog9l[XYXNZNYZ[]JR6NUۋT;sx.9;^^tpqprqtoworwvpgy2NBw;Ͻֽ}ŝvoquw_u_r_ptsaa-aa a//7+ wrurmrMrc 8u!5A-ΧVPPMH4#&>}}3t1 u̅L_U3ss-s5g`.`l>f>e>ijiyayjjoaaybbyoygyckVV^^^^ٞ؞9vcQp;:2,u8Qb'*@jPTjuAP? tutt_CPGh 7 t?u?ssu@] yXU`6́u}X` LK`&L0 "t 62sa$l50 B/WWWW׷зطĿٿտǿпÿ=8>8/ > ^> > Ur.ppppppppppppppHHQM]K{UuTG(?* A1OsĜ1w????????????X#MU+הK.N.L^LLI"pʛ::nސiiiii999999ݘ}}}9E49yN$*~T[5_;_{||<*\l\}tX}p*IqJ w'#&'%  "!&%'w% 7'7!"&#w!w"G]FL]G]C]A]N@]M]KD4 =====ϡb˙Ia&~)措genc9W9W88g999>AMGuPk.w DD|@4^DIEZYDcDDD"G!E("'Š扊EX1F/ $5$Ipx4,'r\W+^p<Ok :a^6>~I% QYn5. Me^YP U<_%QqUbHmSge긺\@S_c֎Վڝ'.[t utLUgXljiabfl\ojczhzjmlzlazfndzaz`ezifk`dj>g>omfjmmm`lbmnmd`mimgfomlmemhmaa-MlfѶ.qw,uqlwlvtsrlrlplu,s|pb8'A 14*M8$M Ȑ*dB|!D0xp8 a Ë`182>_'_O{﯒^;3 ƃǐ$$ - -   O O »#FFGDFEFDEQCDĆƆ%bX,EuDDDDĀDDDDDİ?DĨDDDDDDD]o/Q|oRSRMRT*Uz)t2o223223/23O۳{;_?߳_sCss5g9s\<sU.N>6n&oS k W ?*UCD@wC|%pA\q.p%Yrrwrr/rO @&{;OϘw8o999/98ϸ{wA%EOT)ʉ "XE"hh(&"HdjI] >o >)++)>())T* T+Q jzZMMSM3Mc[;E;S;K;CX\YRAU*utuu ?jFl Fdcgoinl`fkinddoh\\\\\::::4=::::: XXNMlV߱qqqqqԱIv١ *ChdCY 3@FH0kC x oww ᾡIdjZ@ 4 t 44 4 t4 "2`Y{ KèȔ(FƲ\,-c 'KH%MJ#!MDs!O`% dB%L f`' {8A,?Zx[k뒫R]RSmRSmSԂTEʧ..ާ'ggdzdegffdedgL:( OGSk{[KgwOWFvOOwzWnf.[+r%9Onan~nm~h~R7?0?(?8?2T~~Z~r~J~|~D~b~s~@_BucE+Ub*Ҹ \ q<"hRyyy|Vqonnvv6ViF_y5' *Ҫ7whZhk)ZEiKx-IT[Jw@CP԰ڰH7w015w1w60w446w30VeYVe[Vo-mm}}kUqIwҠMht:m6C!h/t:C-O |~ w#| U: ~>3c=#=c`&B?jaJfa\arfaa[[[[[؜&≭\"%%‰Bbisv>w^uu>q^syyyyyyyS)tw44qs^Kb4/ыxwG1~'~l`J@Pu*VԯX]bMŪ( ʃ$!B4 !C##"#kGgעgGOFFWDEG/F_DG/EEOGEGWU]MNMKJ;z?)sbkfVv'IIlrorwrgrOjfjFjJjijYCu$9Sc8]n>iiii-,s's+ (s/*s1k̵̥̍:gr'W49WΟ 9ANS9^Ι9[N9w[Tyrf#f f>a(%ee?- 5%6 >-7'k KX0@P dHh(D$YKY+rQnPPRTQ=WTVQRіhk{j{i;z_Q' u",Ll 4 d2YM3`Z[ڸ6 j8: ]\]]<=<=m=-=m /ۻO$?bm!|†!\,\9%1)02%Vkkkkkk#Vkkkk_cccunUݩ؞ؙ&IFܟ< )|jnjN >>>iiimmmmmRŹ\2̅sss\62-ȥs ssչExninYu:S~Xq|i~@yRGG! f7fa&a 5&QP "*-)%&., k/7)۪Aځixc&or*;-֛v>Nn"WoWW󓧓gWy^_u~}EV` DBȴ؄ؘXظXilTOlD_lblPêU{w.IJKOOOMONOJ;z?=!}*:6.&3:vvv95+?w4widٙ ٩Q!Iٱ١q[ks۹+˹?rr7VO Uq 1^FGHk XY%8ด -mrܮ/8&tvMtru rqz{xxU^W~V> 1CȮ=b9q(q8YƤ.,"²s,>;7 }}Ƚ=}=Ƚͽ=ʽɽ{{{{^}l:N)y4/K00՟BRJҤ$)U]q]P}I;RvoJ6kgggg? V\dOdw@Lx)irRed9Yv%g5s߫VVש]]P]~}U=?%?=+*E6A;A{A[A)]CR}E}U;3 MiSҔ1ww]]3\3Zk꽀?O1QL+%͊ՍU7nQݼzAyM^.RA[14r0ib2M*lyVYݪe%Re{{y&Ĝ0? _YZNiүEM ĢE%Eu* ꗶ*m TZ~i҆J6)mZڬ9аE_^t..bNq=&XhpѐnCV‚E@m4 ӣvɉ3%K)YP2dSƒ%ƔV---Z?>Ŷb{qŽ Vw;bqAqQT{uiňb~CÊַ[[KhZ6@[P7=@/7 @)0 À`$0 x&)T`0f9\`  4e???Knn #XaUa0Q,L 3\auap~E .-\Vp 7n)Zs; w*]po .6)Mnɫ-ݡ*/5Ɨ&f!@ K-5/!ᑺ^6v |RڍBi|#zfyǥ/ȷyw@ R#v@k֯vZ1"FU3 ωCSw[ rv-p𭨷EI|碍Uԥ r |*a3=cp4Xު_~I>Tæs&JB#%,S?Y }3`oT".zx-VJF࡟*O[M4D r|KL}|Ӳsl7'*+$h+{tcnu{-~m,= C]\>!zs^9ж=/~82u r{s 7wڇig-gY2lzZ*UUJ*<_#۠66и1LnD6QN2^pF~etSȥ¶BҬI` ސ]`s:x29y/$3b(!KH0WF3+_|Rj|T}T!ze) ׁL6GG$', K5BJV_f=;HOwE2ߠ%5K3eU t>|=BvCЫqv]l@**btesed/-m¦ 7V8{0v;=ڃX]0N1Tk1mй9TJ |-UW?= KI:W::LEwBGę./&!ne/1ظmMR.<*DAut4/ E=$DsT4_֏SU*+YB;YR֍3|15Ls{l)_=~KvȅlB3Owe%)$XDP$IP:Ωyc z)vIgFG[׉[fдHZu# >p/x>̈*$:ݲZ#7!nb+} XC$&dMcdg =- ,w\I$'TB#gfƗ ( y2~PQ}HB,`amBDFG5G5A{pB"!Ccl'?SQ ck &{ GMN)>"x8rk ;vFqвβl}\105|<,LZ8>S UwAr'Q Ơfc&F9jyTI}Tٜz-\v=KLBc^a=eeT.()wwqM @ac:$ 0kj`Ѹ6F^ [ }cw@.'5F,֚Z+h,ՏgLl/,oN,QIM_5UP"b6iCcс\bf~=܇AM\|/\? g.3FdV$Ybp)Ǖ UG4fU?"t4Ԍ|{??0 ^nO& $?t,#` i35ؓ';e5-,C9bj!Li>?* Ae^YRG'!,߁8l9"9"bp+جlX;R9x<,v uE|& ٰ/ѾAO1}g'{*`T, Rqx (>`xk(.!AD}AA.ݧ=alg>o}n{{epPƏD}P(|r%Jo¹($n(gzDNUڑ {E$Cg*?{W/j}[?BY'xEo@0UߍHwʈ;Yљ>a_w o57|+Wrr+ę]7EQOу0m\-:ĦdGCt:#PUw!+p#/ƕ-QQUА5,+}s2(K~wJvCc#w[uˊ7 O)i@z ^FVQnWwՒCm++}BD]~D!NPف8 53"}L^y\ᶨQX\8TS ~4<96!R]%,Xsf'yKL#?@R{қ&l !-)X0Wo^o/;L xWZ'ܟzށ݊V336`V R4+uWKI_]Ϸ:Qek kېn{g0s[r r.Hr#ά_cfm^n:F9ā5auH=1퐌,j&u4f.N\X+]UAm-F{ې0DŽi"cyyV#Ldg}[agL`)S'})7I.jmfgCF!q:X60c!"+&Hר^WwZYN}QxvolQ~-t:!UN,s OKmSup!o}/yCHQwr^ oLR6uVC؁ ԀO@ ېVae3 9{!D,C(GG[QV[Qx[R'kf"3wBT`tm\.*eyMx'Cߢip\&c3 tJhqsś b~~>͐5PS"Q3q?*JWj1qN8Qu wl3|5}S-"#WM8=RNw ;Po(ۙCB+587MNBN]{It;`d4A5 aTJ%+!ہVoyhJRlW^_ St3 c U$?uٟSΝŽUtE,e_(HZ?K# Rs>5 L6 UҪ+SKF&ejQ&C;G0I@IP62ݫ 8/ݷ[ȧ?ꬼgÑY. QB=b dK}1~fx ͙7=TKFby}!  4 =E x]Z2zYxqB G9嫐ծ   =3]~АL!,46| m&\I>W -nV֤VCߒo2*YXDuP6rҲ#;2)&p'wԏ,dʨlÝ3MI}UjR7L?!,%\I *JI63KY=jI)FûwA"~BFB^'acE8fx!D6SN\2Ms> )%[$_2ƱyJsꁷu#}]K_ . O*7j"+fego{`g؜ 'FRb99kS֜%IK9맇r9gec3o/!z>t@K8<=o5ګ#zO"u`YBr xi [&/'6tK elH,aYӶxTwOem]4'?XL.wXhS0"qwCMHe)8my^Lė4e_-5,&i:uX˰\֥Ͻ l3M_( !} !c! !b8ւTCMӐSC#_! !!eR(Jb3*&z(*F ^ކ^^^>>ujC;AúzAC_šfp ah 6V0 KÜͰcM˰[O?55m#\K>>υtG8· s{!xWUM -c;.4)9wD-DCD+DDOD(111AF|CfQ!*"ZZXX؅؂؏8q q(q#r$1)5;r rrr$r"r:r-rr2!vH=R!ȥ%ȵȭȃ//OϑQ5PPQPQcQPQQQTDQT9J*QzB9Pa u u j9jj1jj !)93zz"&1h,z$zN-uh:֣M$m@+nr5am! EL+Lw7LG' + bƂacbf f-f+f3ff? fi9̯O mmmmm>``'bXvփaX/6݄]]]===kkk댓98`✸7Wwz>1# }>>> :Ns(=NHc_;g" IqQz~шѓQQϘĀ2 XP11B /#x8¸88x8lʬlll0%LìbFK+.5yaQNkc[}]j}KV?{;gV6'VwV_P0pHLfcXd%ciX6ceXy*Ϭ#C묫;#gcgewbCSٳؓd6ds\6MgKvd{vcgogcabboc_f_caO`?b?ebiiΙ!sk6[[[e| b~_wmM[sk_]m-m2]##T7/3S0^MhfEJP-X׬? v N.n ~<=z–VŽŸ݅d!ZH6a0- 3B+ +a!kn›µ =—«D]=DE}ED#EEDCD-DD QT"((<9Eĭ D[DGEDDGDnN΋>.~21E<^],]SģOb@Y K&IKL  $:FbX$ AV"$ ND$$l&"bvJm%+ג҆ҦҎT:^:X 2)ittttt&Hח~+T޾U.s1PrGyU忖o/S~Xw/\GO倬T6X6F6V6A6Q6]6G)d&Mfellll||D>^Cȱr+5r\/o?R,TVH% b+&) B`( ¤+gwO/oF&ʖ.~ʱʩyYJrLS2@)Rj*KV*>WiSƔieNDHy@IyPE[MKAyJy\y^yUy_yK] _U5ooU UUU]U=UEnbOR LtQSTtWSUP%UT*FePYTvGWUqUTRUUUTU;TTTUUTwUUUk{RwQ{;GGg\@MPfIU~uD=_]^ުޮޫޥޭީ>>U}M}C}_BUHBCS jƠIkE-us#=]Ú5544u髽vj)2-ZfO.ѮԮnn^>kZ.EZnnnnn:^>:ΣKtI]\Bn=S3K k{GW:6^E?LK?\ sJ=KsR}^s>gi__I~~j(05Կ054ֿ7t741t50535L1 PD̀3P L2 J6,61,42,0,7l2l4l05l76360\170ˌ14137|614v2660N3106N03N7ʍ#(3rb#0F^#2Z"Qn*8B: 6c޸xxxxT4TTlnbƘFFiic"0& o*3iM|d0Mv%1d6yL^STi )n 2yy!fnFQfbfc֘mfn9f6i":FvZV6S򆥎eeeeaY, µ-2Ԣh-Fⰸ,NK-kajuCUM!5ek}KkkGkokw@뜸::ފ-_Vee[VcY-VuʺغJF+[{۬;ǬWWXYo[X[?[Xjjjۚz>Dކle6 6krڦlJ*[޶Ӷvvvvھ>nnۮڇه'Gaivv=m_im -v]ioڗ9ZڟOۿ9 W uwoŎ"nHg1Yp8cC9x~C8;;:򎫎Sk#ˎn9p3\5shŹqF>rsf9άS49c3γKΛ·OϮ:bWWkkB(.u-rpt]V:!z1Ow*E-Szn.p>'GǸKܽT7ŭquC 7ux7p= yͽ}½۽}6~ٽ}Ƚ}}Ľ}Ӛ{{xZ{=<<=<==cn;C=}sP??ˏe~%~5M?St`t`R`B`f`nz@t[p|@0 Iz/koρ/*jW4[ѴqE:&n^}}==% !*2VkCĦ1j#cҘ2ce1CU*w*VJVj~eUkvU^}SU'.U]\unê{n^qh|N\'qRgeqa"We mcSyKOZ:z&扦6}Qq񉩉鉙ɉY b`& .|B(Oh΄!aM?JĢĦđ/yhv}ddOnqIhrNR$")OLKnHnMJLI>M>KZZڥ:~JƥƧ&f`9)x BdjIjMjmjWvzfJ\yEuMKcFiv^}ozDzZzrzbz ǧyiBiVi~zMz}zWz_L\BbVv^~QeYE]uCKN]Ck8=Sfe xQd{&g|f~fyfsf_xf{HL\|~^AbnvtMuUe[fede[d/>RTEQ}mEEQKDBBkKR$+٦hiii)2LPI'}|~#̜﹮}m瞸O'ommk~[}حN:{ܭOn\UPEA\TФqA5 zt/[b S  -SSN 6*WJW@F˂\(j +|pqۅ+ -\[pMaA}tB`crDž ~RYW .|wՃ_ o,vw*=9*]SԪ{рE/M,T\V4(hzќE닶m{M)þq'Og&gNT|fG_?yv}bcP̙YtgӲsf؝`:ut{$?=JjN\w@fr^zv{ļܼA#'<#;/;,v3;=uNtsw4w:wc)?,JYyTiUΛNsǎ7q@P>KOi=}flXR3r&L(8@{Zr;3;'5ArXӬȕ#D!G)s|;9'5:%;+7}JjNw 9?oZvNz^٩ß/='5|٩,vONH]ry\䬩as#ɞ~htdi@jÓçrӳr䧤s9aa_LS00p4wIg'+liĶV8aޣOȘ)&6!$5+7?X9aSɓ3RUųיsݽ4f=d>-';ӝ:7=7/5}mn gEvROՃaa椦94cp8${tb&XfOHϝbShRq^z~fx+<;9=DܦM{R9S 4thF4ڄD1Vܙ)/Ϙ߼Xׇqf=9Ω;|M3id0..a9y?bH}zÕm{CD" '9{fjֽԒw/ ?&{ +\.φSjnM"oY*Eim2WF|]tHt,FOsӳRR&z}#=@L ;[$@Z&&xۺfM r/.Y$ 399y9aŹ졶䜰rrtÊFx_?9 p w"ܹΑa„Ռ=(=%';7;-/4sfFj{gқH:-/˔{~ g795)hֽXETkOl.Nj#i^|P/'8o52RZݛp5-ӊ'Wَ~8*bfdнZN);'uj87$wwߕͰ*%"3vvlfԜxkLv>";?'%,Tb)-Թy brF)y&%%9a2c{)a.faOȜi"kvrFN79y!G9mݩ;<}Z=)#=9{Ј癔b'o:x|Мs%=)/Qb}ذq\뚕Mb/_D2t?(歕;{t()᠟\Ea“1,ͺu+]\;4DnLJHI$'䥇iQFk"AΞ}L¢Sa)sK(M 93JrJ^dX+'*?hp0LHTc ,~oԹəU2=ZC ')X78\=KLm5oZq0 a;GwFfv86?C #GNѫY)۳"I]\ݡOZryKa2#7#\KySƖOfp  p|'O}#;:}jֽvD) [ɹM)MRQfŽZD0}ѾBCsgfg{7@U)LKK7'_H3WC1 2:2(_F=Pt [ s[3[?/-Ws% sgac }ؾ/|SY )HWR; jY&4?Bַܿre/ps̔^o{7+OK/?A},?iKҶ~%25lB _EhSpt?& ߨR<+Msq0QNϚ='$F:_3KΏYXG{m5mF=MɛH`ÂuϟJ{z\w8.#s{Sa{˃_=]޶ ob??kžV HzFz޼u2%;~ۋj?:뿑9#>_uGFcz_?kߟwoZ~xv7(cWSX$`^vT1ˎcˎQ*;F̲cTj`|_v'rj1gʎQO/;F_ƲcTYvkǨφ{ʎQ?aeǨݧu{G`(eǨ?K'gc˂iznK~b 0*?S\'iWʢG. znnlpQc7ie#5Y6$a,r%![>ʕ4-7JOJa1|-eh20>/;g]1↕c?ˎle1/;FJY?b<ҲcJ0BY?araiehYvܲc<ŨTCyѩ=qm+7 c{쵋G`,0Nc{<G`ct|쵋G`0SG`~C!W@KA!a]#]\]Ƹƺƹ^uwMpMtMr%&R\S\4T4Wkk+Õreffr\Pß?~Q1q Idd?՟OOg3Yl?ן_m{U5u []=~?~E_~ _OO/_w-m]( @%I2 TO5Z3@mP F@c  h 4Z-x xDW;=t݀@ /K `00 F#QRc8U`<0L&ST Lҁ f9`.0,ooˀ `% X `#! l "`v{G>`?p@4,< " *L | #g18%p8 | Ng9|$w`Ct1`,|q`Sl[x v`{ZJ{@p8 GW1Xp8 S4p*8fY`68 s<0  Ebp \.W+Uj}p \~7Mfp , "pw=^#p<AAADA A$A AdA@TA hhGg18x< ~ O߀g9[z zZ-CK[2h9Z VCkuh#! m Bmv@;]nh@~@`PpHXH$HTHt(} >>@Gϡcq Kt:Δ,t:].BЏ*t  ݀nBC.å W+•'p4\ W5p-6\ ? ׃ Fpc pyMp % n m '>-nw;p+ _p//C0x8< ~ _'Ip2<Np<p gLxyp><υBx^/߂wJx>^7-p\w=^x? (L,,, l?‡R?/I+k|>w%2#| TJg|߄o?;]8rHy$ yTD*!HURE GKC#_ _"') r9|G. KeG r\G~A~En 7ߐ[]$rhy4 VB+hUZ}Dkugh9!mƠhyԃơMfhsmF6hEQmv@;h큾&=^ho퇾GїA`t:GG/#Qht :G'dt2NAS4t*:fhDg9h.:EBt].EѷJ]=tUIZt݀nD[-BwнG> J$JQeQQQ QUQ j&A z=~E?C?GW)4 z=^DG/??.V*`JXe,=UŪaձX.,V5bƘb&ÚbͰX % kcm̋%b>-ku:bX+ ^X/7^cK l06 Æc#l,6%c, M2L,r|l66`ac El{{[+ [bl#! یmbX!Vvbl/ۏR a0`(a8F`$Fa4`,a<&`"&a2`*afb6`ا(v ;}Ncg9G#Qh| >'<$wT|Ogxg9x.9\|>_/%oo; |%. _|#! ߌox ߎw=^|?8C8#8c888󸀋+kx7pqCaS~ ?ǿO'Si ~?_Ŀÿ/+O5: +~owxpDQHT"$*D)*QNIV&*SdUYI"kuȺd=>ـ|lX;٘t1d,ل|#d %ٚ'ې L$}d;=فHv";Bv% dٓE&}~dr9|D&Capr29E&_!ǐcqxr9D&2L#trAfYd69E搹dO&sy|r:\DA.&K7ɷermr||\E&'אkuzrDn&dA$w{ȽG>r? 0II ɒɓ))  M"m!Ay>Qǩ//I+Q7,u:O].RQS*3uNJݠnRQS]<E?AW+t*]Nנkҵgt.]~nD7t K7tsݒnMmK'>=ݙBwtݓEz =L(z4 =K'dz2BiTzNOgYL:Υ|z6=GϧЯ Ebz ~~^F/ߦߡW+wUj}z ^G@7Mfz . 颒z'MO4HC4B4F4IS4C4GPJ^%ZuڠMڢmڡA}>B?//I+ }>GK/KeG }F_o7[]:ĸrLy&Td*1O2h STgfj05Z3LmSg01 FLc&e03&i4c3-L+5ϴa/L;=Ӂtb:3]L&b0}~̋Lf3 f2ÙHf3ˌc3L23Ia0L3d0YL630lf3,`^/Yļ,f0KeJ]f5>Yˬc>`3̇&f30䋘mvff0{}~20(1C2C3 2#2223`LaA(9s9Μ`bN30g E{s\e~b~f1יms ( [Vf*SlU[}dkϰuغl=>ۀ}m6bn6eϳ6m6c-ؖl+5϶aX/ضl;=ہvalۋaKv(;ΎbGcر8v<;Nbl Nggl&fas|v6;g Ebv }}]dcW5Rv#!nal![nc;؝.v7gd!a1g d)eyVd%VfVe56ڬُك!0 ){=~~c'ؓW)4 {=˞ceϳ؋w%2#{^c7؛o-6{ˆr\y.U*qOrh W{jsu\=>׀k5s1\,ׄ{pq\Sׂkŵ6\9ׁuzp/pI\Oח{ ^sø%Fp#Qhn 7ǽʍ&pIdn ʥqSi\:7erY\67UJ>|n67s ׸׹" n1[ʽɽ-sp+{*n5[˭>s܇&n3p\vr=^n;A!a1q I©839s 1w;>pqsǸܗ $5w;}Ýro"=w]r?q?s׸/ܯ &w( _G|-_w1|,߄-|+>o'>]I|ߙw|O/ߏCap~2?ŏ_ǔˏ_'I|2?O|?Ƨ|gL~y|>?kB~_/w{j}~ _o?[/w;~?yyGyxgxxxWyoo?Gg18%?͟Og9[<_/??WO5:w (-T ՄB PK- B9T/4 n!F!Nh*4 -Bk!^h#$^!Q mvB{QTJE*t =$K- @a0X"  #(a0V'*&IB0YHR4a.LfB%d 3YB+ la0W' EaLX)+'V k FCaP  E6aC){}~ PpH8A$AA4A!%؂#!pD8* _ ')pF8+ w%pE*\kuWpS]%wXN,/>!V+OhXM.kJʋ:b]YX_l 6b+6=bTl&6[-Vbk1^l#&^1Qmvb{Q$v]nbw${}~bq8P$q8^ N')b&Nb)fb8[#Ņ"qD\*%.o+ĕ*qN@\/n7-V@,mvqS%{}~!1 )9Q%QQ5Q!%ڢ#ŏŃ!xD!Og9|Q^$_Wku|K-!ߑ!R^R*(JJe%ZNtV(ݔJ%IRz+}J?e2X U)Õ(x(c8e2ALRJLWf(Jd+%WWf+sy|eA)הו" eDY,S+o+(+jeVYW6**P٦Pv*=^er@PDALB!JFaNQYQUєb(b+T*'ʧrLR9TRVN)3Yr^\TW.)+UrCRn+wZN-FԊj%IVQO5Z3jmZW6P5Vm>z8Bmƫ OmW;NjgUvW{/IjO[S;OP/u:BRGcԱ8Uu:A&uZj_NS 5KVg9jVsy|uP}C].UTRJ]=uZ]Uש FuYݪE6uCݩQT!VU1TiU9WUT%UVUU5UWڪՏՃ!zD=~~S__'ԓ)zF=W/K'z]EURwՐVN+EiOhZ%-ZUӪkOk5ZVO5jƚ[b&ZTkZixyĒi>Nku:jZM^ВZ/W맽hAkC0m6B{YFkhc8Um6AMҒZ6EKҴtmei,-Wm@[-kK[2mB[Vkkk:mAۨ}m6k[ZVi۴mKۭjiͯA!aQ1q IZ@34S4[svP;>>ՎhGϴϵcqvRZ;ij EvYA]~~֮i׵Mwv[C~ZHwz^AW+z)^Mkgz^O_R^o?7uMt7՛zKѽzzGYw{/IzO[@%}>XՇH}>ZE D}OS4}Ogzg9z>[ "}D_/ӗo+{*}F_&}E/ "}]ߡw=^#}_?u@uHuDGuLuB'uJgtVtAuIuEWuM@) -=OO#Q3s~\BR?ԿҿOKo~I_ѯ ~[C DTT T <T T T T  <hhhhpb&@\iEeu >& $|v΁I^~!aQqW)@Z`j =0=0# d9ف9yEŁ%o  XX !)9%P( vvvv> @ @8 Krl@ %@0p0p8p$p4yXxWg...}Rrjnn( mT1ՌF Qxƨm1F#6bXg45-Fk$퍎Fgn0z>F_` 4^2!pc1xc5F1H1F1՘fӍFe4r\#7fsucXl,1ooˌ ]cxXc5&c(0 "ca4 Ѐ  ѐ 0 ˰ Jrg6>5Gύcq Kq8e6oqɸlh\1?J_7~1~5n7[m2]f9eV4+hYլfV76k5ZfY|lh62fcƙMf lmƛmDhv2;]f3i2}~fs9j1ǚslN6S)ffN5fifLsc暳9V_5h XCapk5e^Xcq֫xk5њd%[kjYSiV5ݚaeXVmXV5ۚcͳXY[ EMmkZmoZklmZ6keX{}~  0 (8K$KJ}ghf,2-ru:d>>XGc u:mYK_.ZY[֏uͺnbݰnZY[]+dQv%ImW%%wQn;QB p׎vu?~0ᙄ O&TNNTBՄj NB\]7c'NMmݾoBgBzƽݤflJɱ]{]*U=={}ۀ lFll&lҦlflllіlmض?ڇ3}2T.T>z"T!T1T)dr(:T%TjZzPPP3ڡ:gCBC BυܡPlI'jjjjjjj %Đ/6.>!1)9%t!-=#B()3+;'7/bh@h`РАаЈˡQѡWBcBcCBƇ٧}޾`go_/WkuW}Ӿe߶wS)D9OΩTt*9N5Sérj;uN=yi4r;n'Ɖu8;RqNSirZ;N':is;N'ts;=$qzD7ww% `P0pޑQWcc㼯z{'x'z'y))Toww7;;Ûfy39\o7;;;;;߻uB"%ޥ7oyy{]]}wy p:!0g3rF;8c8g3Iq8N3IwJ3p2,'ۙrr\'wf;sZ!jcԇQ6GmUUU-j{Ψ]QD(j_/GFaQxEFQQtFqQ|%FIQrEQ(#ʌl#g9ȁA!ʡaQќRwGᘎ؎C'3ss9trvN93Ys޹НKeGsٹ\w~un87ߜߝ[ms ]r JhSiϳġ|[[[{8|O[[[ &' J߻c>wҷϷw}wԧlW># fggs`~pvpNp~pAE7KKo . .]w++ \\\ >!1apSpspK X, n n,%+;'7Qp_p@` A$ $d 2A6f*qn!w;æC괥.u`i$m*Ikkqtf}Y빙;*Si2MSLg]7_珹}wۚ33?珥%2222R`bjfnaie)LL\s .ɥ4qoroqosprqsprqsprqs_p_r=^\oחq@n7+pC͵7Suu:mIkҙ&h5L 2&Ą0n"L61>M-m]=~^5261537}0ghdlbjfbMM?L?LM@39 p08 #p,8N')Tp8@3f4_e|Novf~2?`ifin9r%r`!C-Ya9rh1c-Y`9rd)S-YNqOsprqs/p/r/q/s^^^^\1+J2m n,7M&rn*70SssRɘ9' .K p%h Wk:p# w>x<yA@tA }@>A`0(CP0 #Qc80L$0LS403,0<怹``X `XV;.`7 !0pV5`v='8x  a@8DQbX D HRT H2L 9@.@!P%@)P $X V)4x< /Ke x 2P6-V l;N Tԁ4 0H4Ȁ}MV?6x #1|>_/W-~?/WȂOp\.+Upz@ 4@ 94@ @+v5@ =`@/`@`PpHh-6p #1x </+5x '3 ̠@ CCh4A Dh4̀fA9 ̓C bh Z h%d VCk:h=m@[۠h' B t: xd @d9@G!G rA.yp,8c98989Iɜ)iYٜ988\|B"bR2rߜ?XrVqVspl8k9898989[8[989;8;989{8{9898989G8<yC>( P( ! @P<%BIP2Bi CP&eCǡ(ʇ B*JR **J jSi t:].B@W HCbB2H5BMP3) % A*:.H inH =dP/d pHh-6t ݃C~}Zz=Aϡп+ z}>B+ f9<yx < (x4<Dx<O3,x6</‹%Rx^[«:x=o7[6x; w{>x?|Cã`k`{> ;` va~? pGpp')p*p&|΅.O•p\§:4|> _Wku,` ,enfVJm n;N pu6F6 0(8L$ܯ 07[m|߇Gc~ ?#¿\    YƊƉƋ&&&&ff戸e"@R^AY]tHtDd/rE"(V'JE,Q(O/*JE'DuӢs󢫢k"A$)DJQH%jE="Q"F@PD\BWY=~02 B#Capd2F $d22LC#3Yld.үG Ebd DV!5ZdوlB6#[6d;ىBdهG CaCkE쐣#C\7@</A$ F#GՏ[?~Fׯ_S~s=[;{ C1Iyu/շwի{ h=VOߩP[=[Ll.*&!% +ū;Ļ{{ŇG<^|T*v{=^b8@(qH!H H<$"IH2"Hd!Ǒ$C_)FJR )G*IB9!3Yr\B.# W~@DH="F)"CH#҄4#-Q"HBڑBԈF#Ĉ"&q8Q$NgŅb]!A1$FĨo__߈?6 i0aYau- v4lհ@uk[o!!!!dC]A٠jj7 n 4hxCço3#)L̐̔,$v{Q⌀!7[mrG!39򲟻Wk y|B _o|G~ D!Pt:yt:FǠ8t<:NB'Sitt:Fsѿy(.@t)L&I$K$YBIDR&Hj%us k^"4HQ$QHTV$F *$O@T:T:L:B:Rj!'/"*.!)'JKIIWKHIK7HKwHwKK6R{I*II4i4W'-I˥jiRRzGz]J]EסЍ&t ݆nGw;]^t?z=F<Ԫ;CУ#C]PW uG=P/A}Q>h hFQh4Ƣqh<&)h*fhGs\4G B-FKR -G+җRVCKƑ MMMM͑m9\eYL(%ɲdٲzDjEOui z=G/+5:zGh*A;9ڌ*V UhډjnTP=ڋPPEPQCozGS}DE_oЏ'3wF`f96q@yn|uw5Mh4izӌ&nM7-iV6nZ cC0l86`Xl6M&a)Tl6fa6ø|l[-Ɩ`Kerolf`kulۂK"6l'ۇ`Cl0[sb\0w|0_aX c!Mۛv4jݴP#MMMMnMMM^M7]jtFI$ojljjjkR57u54MP҄6aM}M-6Oh`a+b߱O| LJH|> D|>OŧL|>\|>_/+!J2ZLRf)9~?ípkp{?;N3~ wpwĽpo~?Џă`\xGx.ģ<<O“<3l8x^fi6ml۔ms-m[ݶmmMm۶mmݶm_ہ#mVmmmNm^m>mܶ¶ҶKmWDmm-m]m=m6hƶl2S P U SPTRQUMPMTMRMVMQMWPTRVqUU UUUjjjjjjjjZRerUBUꤪ /‹Ox^)4~?/?*~ \p9ވ7x ފxƻ\p=ދ888֏qpg-6~Gc_7[,]UUSW]R]Q]UITR\ըjRT.U R!*T(Ug;}Paڹڷo?~ݺݩݹݷ========d{M{m{]vIl﴿l[YA#;FuXtL1cv=;w:;:;;utxvxu?/7@pb(1N cqxb"1BL%ӉY_D\KpBb XNM V*b5XK#6[mvbE%~{*Aq8B+š!l ;žp L#\Wp'<O‹&|_OD!HHHH(((((ځv`dqǓ;;v9szΙ;wtiiySҩ;Nya....ϮҮ]]w]%jtɻT]]]]].mv]}]7nw" BaD8ADQ&bX"'D"H%҉ "&9yD>Q@Dq8ITUD-q8M! EqB\'DD$D!!MD3B(Vh':NPz0 0AAw=zS箯]LQU['gggg穹ej@RV^AY]_}@}H}X}DmvP;]վj_T8uP].VO+ukjZnW jPMuLьԌҌьLL,,,,'&qM!xJ<#/Ŀ+-@G|$>_}#X;Mȁ$D&r$9M!-ȱ8r<9HN_LN! r9C%"\r>\H."Kȥ2r97ȕ%\M!ג4+4+5՚k^5M&\#$i5tM&OS֜Ҝ\\\Ո4FME<<<ѼҼּѼ|||ӰfCu={B)3u/-NN.}~G/_v[nϲ\On 7r+A$w{Ƚ>r?y!K_|K#?Og dO-ŴO@PXTZFV^IEUSK[Gg3 ՍYf踺Ee庿unnnnnnnnnnZgt:7N Et$].W+NNuuK˺+k:Nk)tJ]Ku:PP{{{A&Pf95H SCapj5M,8j<5BMQөT.95M͡RQ(.5Z@-Q%RjZAJʒZEPkuj#JmvP;]j/OR(eMRv=@c FSM^^X/=G?H?T?R?A?Q?Y?U?G?W/U5u-#z+Vo;NzW>@q$}>Egs<}X_/ӟWZ9yE%e?z^/7Uv}KF=OWDB`f07p C )_ʏ(JQTIEQ1T,O%PT2BRiT:AeRǩ|B*J2NP'JjZUGPgsyuDC˵UuAzJL5PJJ(9H5QT T+Fvꤺ(5JK(00000005,3,7047l6l77061 !ΐ`H32 نCPd8a8m8k8ojP =4n>~~͌ `H(X2jhot2z>F1(4&syBcXcLh+ښ裴#L]h7ڝ=i~iڗ~tD:H:cX:D:NSTߙ5NgYq:Υ|.K2Oҕt]Mе)>C/Ke }n[p?x@G t=A_ hsUx`#*@jA=hQ94,)Th:4Be|!AP NBPt ]A!zC 9Px$< ρ\x +U]OZJh9H7t [iNwНt5t7MA4L#4J4AS4Mѷ.}O?я39~EGJY;Ma̙@f3 e1ÙHf3X0 v]a@8p4'Yp6p|%2,a5~ _Og+ f3 C d,2@ \dYJd=b8 N+$ G"!!H!rHy@#g'jrбt9]G73Idf3bf3sy ,`2Ke `V2*f- la2ۘf'e3Cac[Ǝq`1.+Ƹ=oƗc& fBP&`"(&ab8&I`&Ic2L&f39L>SF5j: AQ!&%2zhڂ*.TԈ((R.}Fߠ6 jl=ێva=afcyaK²\v]$cMX+º> -erW-6|web)cʙ sdZ9Üe1 L;/Yx.^':~ R\+qމw܀qN} ?3œH "Fф1D f9\b>XL,#b=Dl&=DLYD!QDDQMu9*qAP=0F%c5xO|"~?99In'w'KadO&dAydYD $yO _ošR# Dj2BmvS#eC9QΔ+I* B(!MQITMPTUJ] )©>&uK=R/'3bi3ڜCi z,=@Ogsh.^Oo7=~}>BDt NGB:Φ ">A髴Ji&iI?/g'1c8Xf 3a1rf5Ylfv35c3GGƉqf</Ƈ3 gL̤3LSȔ2L s9m*z5k{}ӣÎ]r[3H؜q;똛~Ɛ%j(MvB{go* Iךhi;ܩ9{{ާ԰^숸 C$M;d/qdY9򜖸==%Z8V ۳'湊-no?Ym4y-=z <'=HJg.Q0g呺}<NV^뼶z766r:1'r5r!傣 k$OU5Y/ks %$Z^A納w !>:uc<$ ;VDV,j[.1)ӽ֣+K ~a~m~Br³? / {o ^'O'"mbڶ陕~%K'V<XةV;6.>{=vH^^>'lI?4|=vO^8su~+?CZ346%a[ꉴiK2e|]ۘXRWwڿx7S~$l/\w{G_~Po3XNUS6۳.nO==C?\opbᅪCu;X&/+zQʫ8Tם| ;Kk/[ WϧZgj oSoO7ץmuAHMhᄋϩ`Q4N:1-ǷW 4[_ vR803eBLrjڰ2g.XUtlܷS4sqުsU74OON{*}dߧ:ᬋc|B|8Xdv7Xǡ}"tǮPsR b6{ܙ oܞm輒5'p/3, r9d{6{v@_`ten )2dJ0^s/76X:>==ZnJnj;b^i~j;i VVmbl p}.=n>xi|lS@OGFV> v\@(uaKXH2}ڮycvcJ,89{{= :&Αy{u}Gj߇Q3]=Z8)BT@O|gⓔSiN<|?/AaĬc񼐄t] dKُ`p?dVXR*V4SOy+տ"/A+[:zkXzWFmҰQUn# 1p9^_XrZs!oFKº|`yvq[#_~fᒋn־O˂'JڕR {rgO )$ (gumǹ6-><`@c@z$q4yFX>^2 jYg~kP|mЭK;Y_]t l{O>3~iwNRo3yyɟ²ޖ,(WqЦvŐ\,$m=Z{e=\[Z=gD֦i{KgRzY/+{ooO>%"y]ޕ <vs Ι3}B$3-fnHBMO_yǭou5pY?KN-<[wlw[acb6%HY=+o}œCy|c`cȎк1aBhn\pjw+*M 7YQģkwd֫-V`s tOܑ2bj1]WyWC߄w$Aj|"3/}XNgD+/99_bJQ5)nY)qNRo0(8U܋)3m.e( ;rl3Op3Y˲n*_n oRayAU Y}7'R33f*q49+~ k–ǥ-̯<\e1is=I[cQp";'3uPmXF\z63,sr&lY`yuݧ +M}g/8x??47 %>v UE1oc*(wAV]Ss}oTƨ +t{%2y?t 6E̍햲7cVU O{9]=g=v&+~ &yx4'* :Va@͡c%Eg.Zukg(|+OXQ'OrfXغ|WFu $H:2==?cmvVɫJFmdw]7v ކ9E+I84Grv{Ca61IE2iwSY9t}G6V_X&M4CuxaɥTZ-eqd=ӝ9ojგeG*VXOGII9+hxD`ޕEUj64 xۑ =p\'o_PJѸ+'|T۹{\-i(ͷ{١l]]cfm ІˣͣƄ% k4i`~Є'K3__Z2j5egaRqT|Iz| yCl(Tsn2^7\".,z3r#ouQ0s9ױ~1Xˑk$mK]nn^=&Zs  ZK_ݩQfsɶ:ɝC=x]DL%%K!*TWg\<&{zk봀7Ѻn;c92|R+d0 lpMqqeT|_Rf)arW ʦVW>e_$nq >1-J!QɫL.ͩ֜wW;ţ6ZmJo?oXW.]9nݗzx Nyâ =3^2yrrdQYq}||wJKWA6d]m5#pꍞ}:*, Fg_ c q6{Jnװq -ֈl׏Nv:z|sϏ6A^N["Gv|'JS܏y Uprrг2"##gGgC:e;pS7{z:x0)4{bhrh24c\vC^j~E'gs':/7/ʿT` w-KWfXʻik!eE})2"Yh.-v'JqH.p|Zǥqe'9% p ,]12Tަ+=o T.u2ҍ?3$/-;."υ߽-fyD-bcnǚ' ҎEϕ&> 0(qC2J^]d:u#>І"%1S&>HZ<'yCCW**m*oRΊq{%M),T4tK/QY]r\ [ְ.쩺/l{=͞'v"{ɟ`/GB #&g9VL_{%Bu^s:^go)<"X@`cڰa§ ]X1$R*V!߳fYYTV6vZ/al=( !ξ{|ۜK$-rVQ5ڂwjZf~*[NNǦ<<*zG|ÑQmbrKugdF+zCȏ2pNZ_mĘTuJ>tYµỎ˟~K˩f!>Qׄ⪒_Jypc{ y mŶmOmX˝+o[]_j`gXm],VȻX0(w->Kkᑽeh 'hs=}[XIu`t( `'nې[*i9}oAHNсtpj?Q懊X蹘x-W#2 /<lv=c^X%ңXY0q0qF_rݜ܆FLqos+#Rئ?ʌS׏70&\dw@fPYjYX0)2+2.bΌ)VOOSzr=gr@^~Ţ%K+7SF^ȑr .6@TBMsH{{Ļ:t*n nB1j^ ?C;4UPnAA}|¦szoo5O!Ɏ??){[44fs^gh;ğvnQ?۱OTNXeVq(?TYj4 ąU#˷A(PC˜w~tx?VC'pR:+t7zcd:PӔkU,^gO=`q4WC)\%qh9wsb{ut䡼Lm3`DEtfGZ5!tLJAyAU0ah$!["oc y[MC( s=Mtu9V'!c$c%ŪgF f/t텡ŝ6࡞b𶈍Rb>͸˾9BHl]Bcm>EhT2ls]s]7'ABZ|=mlJ\¥8FCuS%m*7h!C4f&}=Ͼ~UR+Y48e^ا2Z;/W=N*Ugj9J[U̿_&e:P  3 5l/ p <.2,R,WWLPQ>RP45/Qf%Z`kbs:v; |CuCODENjK뗒Jeu4 En0dUi=ܞ%`J4?&U-`$vn)ݖ->MՈnjEu;J+ץVGYIV-V(utNqi`Aht!F9@$įT4yuE_IY|/[lg]b_ѡ` T8$ySOe:C/DTX%MSmjTDzFc h :gZ)*+&lW uc+a.5of~Ch6 a$O`_7D6qx(*-֙VgKvP89;3upyd= ??^L@.AMv^/\>vZڢ0=G7jsyOr^Z0hDş)g` ^ W>0,7\pv]ey9[<tB#.Q(-.>Ŏ{tSa)qe-u%ϻ .%&o(5ux;"z!Ő0/%'3rHCѬqPe憞`tJI Js/idlyBxi9;(lC JpXT%G9-13^HgJ}q;7-Xdj^IEe\ siӘoy!Aج`n6_-jD-T +'p[;*X4%g,kih|{B^O6J#7ݾ !mRCM[av$VP1YvU9W$UBzgHBZ:Xr53 r&H)ت#jvʔme#XOǙ dU^ywf -:zL&"<'eљ d2_yH7ڳ9j^鄯 4'!ƳZz* E@9Ei CmD9ğD@:~&\Me?j^vJ0Js(syPGt{|CpE4e$ ^,+Fhc} 17U$9z#VSn9.bh˵۴u?Y! ,Wg$:!W0PiT3BP12w` WOUJ,իff90} _?@:th2r ovCMHOOL$??Qo໢S vf"rp&Ӛ3迿՛Ձ SLCF0a4iLKV0aiLGN0atL2LO^0?LL0a Avt !0Ca>fL&HQ0a3fDI0aL3fLY0a̅`0, C!`0* Àa°`0. aS #`0 % F jat0zd7˜`0+ q¸`0/ dd„``0000(LL1<L)LL9LL%LL5|0 a,Ye.|Fb-dlj!C] '?_~w3O%ߟѤοſ`BƮhڥ2q3IFq-d|_hy~j12j!3ZRj!hն2tq3Zp-d<63j!\U ZB2τ#}f-dj!gtBؼ2q3:Zȸ'BZ]3wW2\])I$!>&v7E`׿vԁo?-"w.6_fx Vn?;26~FߟV 93zN:w)%3X3zu K-d\BFQ-dT2VFƵ!CߟZBƭ[ 0[ ~0W Zml+f[kaտf[ka5f[ja5f[ka5pg ֠Zm Zm Zm0ka^ Zml+f[0ʨ֐Zm Y|l&P4pm) hZ@-ht:@+ @ Hz}@?  `(0 2(`40 $`20 L3,`60 @:M !L$!M"L&M!aL%aM#L'MD Ld%9D('D$M%%X4Q(OT$*U x9"dP@`lpb@H Pj@h 0fX`pnx@ y@ B D":`DDsSsKGX Vq+X `=>6%0ɩ;%wMhh%F'& &l6Mf`slh\>$p]SD))C{O=X) |_-|M*J*NTK*M*K*OHLJN iaҢ%IK%S%mHژ)isҖ~Iښ-i{ҎIv''ioI%N-%5 -=#3 +;*JCG @ D B { D2PCPCQPXpT&j$jj4j j,jj00۪T᳀c;I1pOKʲu+ x r~粶J%3JH_z.3:[&W#j#nD5O5ھrHWĆ @7=#{-/ 防ec'5]HK]kSϽ/-,Dh4i~w*{WW3lۡVbgUoRG"J-عj4>~RdVRHE#cğ [+J;e?i+{Cq)7WW'?TQZ_"a7sW*~Uhj:>t4)WwH;4c*6ND=kY|>Ͻ7T=EߎE1fst\[8RU? z&ǢԈo[OUs4r>}6ƞۀQf lQh#_xyT=+>#8{߷+kxY~:{t2rƙqOZN GVN$f8ǔ4eKbj+nj{&&f{DCr!]O[YKĉEq~R6:˻-&#ɔ,m܊3¤ȳ%yRI,[+ɲ2fj6NGhx(GN#^)P۪.QIaV&ѫJRe .5]=d~"VPҨaz*b,W7?;:JS MwM4=/=>~H`$Z8&,=[$gleׯ01ap?o[֪PFA,x-$!P!vVS.%(#N:ηNػr CÛ ݩh^9`XZL yGٟV9jġAhDH"dGlo/vD8n?JDT!Vzȇۥrr z(J R>Wqx1qә_{ {~kg;# =MQ䁘Q{`]`Y,z cL CYDQ\j(VjCO`ׄ.U6/ɱNDƵN!OyT,p\W](n$Tm"M,wvNy/e }[ OV>B"zO\2'#və%nnj\&O܂RvUxO]eK~EiSp&/6leĊ6-H#~ꢊɾH#j A&{7_k/S8UNEҝrY@8 @"t3 L8`v@@xCCKĪ<-E;L{L _KhEhN%cɋN:Τ232?,,? #ǝ+]B<:ɢbTzLV)jc)ۢwrsvt<@._VI?|5j)o)\-Z%σCУn(G5t(/ru]Gj9OnWOδu|tvr9 BҐ(F!b>Pz :tJpg&{)vvYZG!}'ynv}LE #QEP ڃFc'yUM|W"?Җme9*).l z>$J5u-O`W 7Z`l˼1Fc& Mάg:G eU݋ 0`{InF}љ`<fQQS@I, ͼ,'ݲr/3s9oB=BcBoѥE"{1VUZ5B!2! 29_\1I9EQo[Ie_sk! >] LmbZ2:1{?͖6:]y3`WRSѺ<ߍs;l 3JO P飭qSড়HkEkRnlpX~H2z?ƀsbj@HE+|TˉaMt ]h,h&FjgjBQ}k cTE)_=-XA7TPT}S BLOW>9quM=Qxyg@5P7՟}=-B(\Oyә_lO \ }!ZSAAb9X4k}sgPֱPI1tr=NFCWØ G()8ƷH;bvM#F-nDZ"} HK)}K4FJ(KcBEoO:hz|:J̣cg aymrfk~+bq7J32#lSе`sYݪ|魸"G"xmLLTIK~)0^t$uГė w{;7>9@Fh[Z.\|  V7Vɟ=8a(V1[֟m DDFF/-h/ Nx4w-|V4kȩDV5N] Mz}Bu5.BLZ&fY-벤ZFV~$81?}\%@P+ k%%;%7MTjeF7^3;qŁ~Pj O+hI)f*X\ie4$7*/ 2nU7g7)to05$e̪z{J?N0ԈSL"Eͨ3"KAh.I<·ϖ7PF3,܌U00c ec|iOnއX!_D Oշ<ÀV_e`2h234|B;f-siMs}kW߰dڴ_7sܳ`"IP t_¿P^odNn=@?`W59k7c:YWſ|_,:VO} FV^SMhitKWeG,zLQYb;Cq?|s b7b ЭCGCZ);B\WFTprs{CMF{[%)#Y*-#F6&LL9c{8[~0]`~1[!MF}ZdDL}Jt4߱eNo V@e1Us%GP.zRt*b\sntc3}_6=pzxz"I_b#vK=N5V'*:4 $~\;mmf…f4a12_7_QaD`Lb@dV$y;OmEe-1kXj 1?k{EפMm;3Gry= G1gycg(J"nDпlL샲 F -QYs#`b3ы݉Yyl۱qHE,۵蟹*,\zbӟ %^N}h͒qD:*1eO{ }8r2:Dam:-%<яrbIHFc7bW¤J&7/Ein3m"(% uH)e:Ǖ=;r_l x3B0 V. 6/~ CeU-CޠD \R/j Ҡth84MHA ZA|hZ 6A?C'݀A7FhDL4=mB eh;Z֠h5: vDCDD_B_EF_ABCtŴŤaR1]1=10_/0011I"aHƂ`*0AfFQ&> }3]sL[[; ;;;;;>þľ~špMpmqq}piA!84n n6n#d8N8'.7Wrp?Vv hE ]܃g[7w8>1  ?OOO:gb/Yx)^E툷x>_ 3~u299P0000000ЏЍ FBM `'x&B!dV~#,'"#,%&$\"'< %|!<'<#G'9ADq*D$3CLb9CXG D8 ++ăěk{sį/.8 "a7ICIIL$ &)H2RC  IHkI?6v~#$&%]$=')AFې;{G3y4yMs\K.&/$o"/%$''"#!4&_ ߥ4tt(=)b簣l|v9}}}p88-989.vޜQg"G1s؜Yi>g2GQp*<9r8?q89[98g9/988[8s99-ymmΝÝ˝ĝs#h\9Us\-er\#fsWsq+!n{{{w?w;=}}ϭ&__y!)- ;'/72xCxy<Os|\W+xx~]>Y>SS9]ΖsU{_//˗WW777ߔ!*#1E/KAT2OPx B++Y.EAuZnvU eeʱLe'0ekeS%_Y(iJ,P)ʸrr q#AejJҩتq^*ʤꡚT?nLORU:EuVKNu@QuNu^UZڧZnCQU=^ZzPWSQ}PgmjګjZj@USԛKԋKԇ+7ϩ/_jik44u4-_5]4M7MGM `5|MHNJZUIVsSsLs]sYHEUI+9Z%i@ЖhkWk/jiwkhhiOjoi>Ծ~Ƶ ]3]K]]_@Ѝ֍эMMQtKyuٺ"]LXnnn.iooOՏCzKz^5zިm';{7 Ӽ!Uѐae aa4Af0\<|O w  /  (cqqqqqqnfFQlFd2f Ɛ133VˌK[[;'Ggw7_ gSKc񍩉)Ӕb4Ff&k$&If&Ig2,&crLySTl*7U֛6N.Θnnd 6}27470?Sͽ]#̙fYbfmvs9j^ho^oټyyy%ٚfj),Y,layhbbykm`mmmed`Ule[iVoY֐ӂֵ֕Mm#և?wm mlmlɶV-6666Fʹqmv ie%o+ޛ[އ'W__]_=__c_3_K_{_?__oo>x>O>s}EUվ۾37?]7]g#T`G____{ \r@SI@RCuY %  (i1AZ 05Uk`Xh5 p9p"#p%p*7p(p!(3 vv  |N{oFJ̜8N w9"[heeѶd13Cw: ft@:$uCg=sΜuϝgJRU{&[ZYYX28-,bKؒ<,iRe[NZv[YvY[XXYn[>ZXZZZ>YX]uuQZheXK֐{jnnn`lk}j}age}ikck`kdֿlmmͭmMllSlcml([ưm m6dmƶ mKm9ɶvڶvv>zmm탽=>>>>>>ݎSt{]h7ګYnoK&{'K2F&aeu GG=g[1Ár t rLstLpq|X`:;CP99%Վ ͎ݎ}ێ;ǎ?gg+g3gWgw'99Y9g;:NS,qZ&ٹʹp.wp&;8r|yyy+52kkkk *ps]Ů"p\epո.+ +^.pcw[VnᶸnxIw:>fzv !C//O ~ u出zƇF&!fH*CCkCBЮеГУНЉppp0"0*<&<(<:+<><- 0=,WaU. Uac:b"H8#ȪȺȞȮ)O3+ˑۑ#"Câӣ 肨*Jң(#ʋJ'FOE۱+я1dAQmEueCsOl` MM͎͍͌M͋Qc'ƋqcXeL1cL\1_KVVľmmݎCh[ƛſOώ ¸$^"8&.)+=#'$$ \ba%u{[; '^'$J'[&'$;'%&g%'&g$'' E$)H$IN,)L {w$ML>O||+ )%3BFffЩE6ENSTm*b\jqjUjk`TjWX\Bbԃ7שWvfF6&idzhks#ҳӓEif4Lӏ/ү233LL̆LLLL̴̔ -Cp2 &CH3-CFfeՙ͙#C=ݙcs3722f~yUd5YC֘g]Yw6dLvyvuvgvMv]====}}}}}+9%0H#>+78797?9FcxҜ('ȩrҜ2ɥsʎ)rveza;ݨwޭz7aU3&-q_ݰ5հazu@XvDA‹z˿k"!#6 N!3?!N#6""!H$>!1 ).8$Y$ H H*d[ /i)|u8`wo >>|:|*||O8v^ ;;;^GŽÛ[NNNN;;AWχ~Q1qI 9Y K p |! NEp* 9M m-~ ^r8~ ~ ~~.݁Jn`?p8>xCxcxscxSxKSs3xWxGx[xg;xwxO{Q`/`/aCG''gg^_c`8NipٰOϰbex%\%2umMUUp- /W,_ЬMAς}  *Z0(]0`Ẑ9؂j_PV /Ph <тXA`C n*_s'/ ^QK CC#ЍMmѝCLHhX8dTt\<B4]&hErt%ZV5h-ڀB&mA;NEAtF tEЛ;л{{чG''ѧg?ϡ/o_ߠ?A  1 1M00-00m110]101=0~33333 33 33Sbp<`&0FTb&`Zc81^1!LŤ0iL,,,ŬllǜŜ\\\<ax )5-+'# |1gx^5*|-ކ>O3%e5[;;GW7ww+l[إWa /U8pF9 х’BN!PX(.,/V k -BG0P) sK W,\]p]M; w.SxXŸ /|Veυ_ A''4"4&4#4' ' $ " &!L L$L"L#!#',"`XPD(& L!#D/G!L',##l& "&#$&!%\ \$\"\#\'"%< <%'F&ĖV6D88888888888888&D&E,!&>!&>'F|O@ZړHޤ>$ii i0i(ii$iii2i ii6i!i G*!qI$>IHIR$#I !iI:TE2jInR#%HIR!eI9Rttttttt+1)7+;{ҟ/$ #ɍȍI?{{}C#S ɋh2L 3,2\Jd=\C6md;AvdG(9C^L^B^J^A^MDL>BK|,<"2*&gSf6vi^ޔ>a222222)J1FSMR EJQP EGS\7K R"%GYFYIYGYO@HBAMK9D9L9B9A9Errrr !1wKk[ʇ"XYQEm(]ԧ_QECE-ZX)"ыEܢ"qH[+*rBEѢDQ([+Z\heڢMEm+YhOс#ENJN+Yt~ѣgE+z_V /nTܱxTq݋{WFfdK+?012606261v203N0N2N33.0.2.1.32~f<`{cمl2e"]ɖl5[6&mc;~va'Iv}}}}}}}}}}OGNcNN+NN;N'NN'Ӈ ќI)4qBNC8 9b#8c8~N$8)N,|YYY99999999Ϲ¹yyyy¹Hn#ncnnKn[n;nngnWnnOn>/ww(w8w@0B0J0V0A0Y0E0K0[0O0_P  A@ UV`KAV, ($*'/8 8&8)8!8#8/,"*-#x(x,x!x%x-x#,"'D  [ [ [ ; {   G 'g  qB, RPX.*a$c”0'\,\*^JZVN^QSKO_xXxDxRxFxUxS߅)/j,j.j!j%j#,)+'/,*)-#/ "/Z Z$BpBET,"H""H#҉,"&r¢(&ҢhhhG1Os ˢۢǢEoDoHqCqq qKqkq[qq_q?qQxxxxxx$b+.Kb$8,cxxxxxxs9Yޣ<_1'O,Y>|nrl9_^XN*%r~\Wn(W+__|K.?^~TOgϕ?/ %$M$$%$$]$]%}%$%$ddddd-Jp$H$4 ]’H Jl%qK<$( I’$)IKKVHVJVIK6H6JIKJJKNHNInJJHJ^II>J>KT*W4hXѼcE^Ea*VX1bf܊y+TV*h NBTQ^PVTU+,֊pE"ZW*UPbS֊*.T\\qj+>U"*+T6lZ٬eeʼAC*U+V9rv *1JReQ%^ɬWj*k*-Jwe2Y\\rC͕[*wW@>P>H>X>D>T>Lȇɧgggɱr$K_qyB9bU5{''g7wO/o?AEEEEGEbbbbbbbbbbbb@Q$]PEB*t  R_TEBV,U,SlUVPTRQSQUS\SVSWxxx]RZQ SS"HeCe#ee3eKee[e{eegeWe7eweeo%JW9@9D9B9R9Zrrrrrrrrrrr(J+˕eR4*-Jң(Sʴ2)+*W.S.WPTRQSSRUTVQU^VPW|||||Zڨکګ::UUCTCUTTUcTTTUUTUUT* "H*bGUD T%SUZAU2***ZZZZڠڤڦگ::zULBJZV/u}uucusu ukuwu/uzzPVUPTQU/TqjfYjrV]v}:^Ψzzzzzzzzzzgg7?40{'_jP@LJEMCSAiihhkFiFk&h&ihfjfifkkhPCkRMFj4FҸ4nM@҄5MTפ4i*j M=5G45'4445W575w4w554445i^k|" Mʹ]=Côvv;8xL,\B-AKRT-M2\mVkZJ[5i-Z֩uiڀ6jk׮nnӞԞў^>>>׾о־kktuttStSutst:x2@'ItRLҙuWtQ]J--׭mmmmm;;;{{{{{SQIYU#H}}c}S}3} }K}g}W}'zzYzT_z^ zަ~~~~~~~~'9%e5 MwaaaaaaaaaaakH@5 \CA`0 ZPm0LZ`5 .1 QC̐1d + + k [ ; ?~25\3ܨ~5<3<7fxmxgxohTըUUUUuʫWտjpՐaU#TMY5jNUA WEbTJUª*IJ]UUeV٪U@U*^Te'VOT=zJsոj|uq5VͪfWsռjqueUUXuzIkUo[}`gUߪWK'/~YS`MÚF5Mj״iYӺmM5kzɫSӷfpfT蚱5jL\3ff SëT(j5oM&[fe5;kv՜\Ś5Wj\_[5jQcͧF18G'gqFidK|cQlUFo4-FeƸ1e7OOo6>4>7026137ihbM0˔ooaeoaiemZ`*0MXD51MlSIlt&Tc2jMf09M^S6EMqSҔ2-6-1}oZfZiZeZmZcZohljamko:`:f:obioz`zhzbzfV mXۨImڮk{U_;vHZvdk'NQ;vNڂZl-XKUjkkjMZk6XktmvEյkk=X{dj/ީ>}VڏpsssKsks{suaqY9Efkƙfb.2SL35 ,7+jl0s2GY *j&Vn>~A3sKgW7O_,,KCK3K K+K7KKeghdfiecbmA[0g[jYiaYJ,"h,ZbT[jqX\g Y▌%gYlYjYnYijnaikgo9`rrrrֲrrrr7 "ͭ-m]=cY['Z'YZ[g[qVh%YVfeZY+ʱYEVUaUZUVc Xָ5iM[XWXWZWYY7YXZYwXwZwYXZY[Z/X/ZXYoZo[[>>ڭ_lH[}[C[S[ [K[+[[[;[g[[O[/[o[P0p8xD$dT ,"Fl&Uڤ6fYlVf9l.淅l[%lYbuMmCS+۶{_lmlm^idp;>>GG'ڧgg X;NEvag92{]ckq{Ҟ9b*n>~A)iO K[Ww#8;F8F;9;&;:;f9f;9(r;v ̡ph:ap8vD)Gڑs,v,wltlulslwpu\v\q\u\s\woooooooooooop>G}4e|}K||}+||};}}}|||}?..~=={{{_Ϗ77wwO/i?_+ro.')bRrFfVv>~aQq 5u m=#E{sK+[W?FVvN.n*@R( XN4 6 Kp@ "x XXXXXX81p8p4p)p9p-p#p3p70(4,"[_/AXD[;;{QaA 828:8&]p\p|pbprpjpzpFpvpNp~pQ b %H ҂ + `yP*ʠ*j>hVAG`0LseUۃ;{{?OO ^ ^ ^ ^ %(8$"{Uc ZڅڇzzzP~Q19y!L…!R* C7T* B$T B2 Bա1d Cΐ+ BP$BВeUB[CBCCCBGBGCBC'CBCgB?.nn~ =} }+%  #͍--=C##ãS“3³s Ä0%L 3¬0; pyX Kfh¨h"UsqG<o$Fr%Ց"k#[###"""'"'###"#"7"7#w"w#"##FG{D}hwqщIiQ\0J(+ZGuQ}*Z5FMڨ9h2ˢˣ+[iף7wwO/bbXXXXXXX~wlxldlZlFl~ b9V+c1A<&)c:bձ#EcX"ecئضخ؁ءؑةؙO ˱k;[cc/ccocb>ƛ;Ǜ[;Ļ{}C@|D|d|tqq|')xIyqA\!.>15#3;'~ chDL/G_'%&%Z'':$:&$&%z&}##Sss9AI' z`&RL"Xؘؔ؜ؖؕ؝ؗ888xxxxxxxD$ɦfVɼd~wO_rHrhrdrtrLdA,LwɏO/I0KSR2U?(84,<"*&!95-ZZ")R8EOR7KS0%JS)YJR)M:U2,)kʖr)Wʓp*ʤթMͩ=Ck;{Gǩg穗?RR>>4,]/42:!)9%-#.HӘ4>]&4-MO3tYZi~<]iUZ5&!14S/:1)-=#3,dFdFfFeg&ffe&egfddg #Δd #TdUFg2sƚqf<o& e"h&gddfg6eevefdggNfNe.gdfenffegegfg~ϼymmmmmmmfuY}&kfYK֖f}h6MeeUٵ ٍ-٭mc+{ه߲g_e_gdêz9DqeUuM]CcsKkg.?7707(7,7<7"7*767.7>717)7%7-7#737+7;7'r)Gh9z+ˉs9I"W9mΐ@. 碹X.[[>S%U\gX! !*aE aXRW:lV9[)+/ Jʾ"-gQ yG>j80fycFϹ?B&gI[J$80?d|}?tZ]z~!@4hgnSf!zյ<+ D[~!:@t'sW!z5ȃQ׀7D]?[D_~u}@1bD]/aui5bH~ɣ!@8b< zN Qo ~ܳ fĆ9b> z!0Xx~" , À`B zhU! Qu} Bb^ J ^PA@h!tu- U(5 = + %     itC@!n?D" %|(v?u@s]Ǻ~; >@C P~Ⱥ-! i4DA Q(HC! i4DA QH(Q(HGt]t]# 鈂tDA: Qu:΁∄r 9 $OH(P!BB9r ir !$H(P!!BB9 鎄j <    ij  !$TCHHH_$TGHP!DBCBuj $TOHu5_}e!pi5r5vԘ~1&?@}o@ !A!A!A!A!A!A!A!Ah@!L@X!l\t@8!\м@x!|@ 49@D!bqD"@d!rUރ y?jO/=OwNמ0~`+Y D@` `Sc'= au65?FS!+鿱Q7'fwFh@v l\vnoѤo6M;6v-5#7-G~}|6ZvnMnoю6w;ظ6:DFGܷ`̷v]fozF ~U+Z"`>mmCڦК9m o[Cض=~];C֮n),d RP@1XJ 2P*@%ՠԂ:P*ȯZ Z@+4o @700` 0 4`Z1VyJ9Z%V}a_`+) N'S/W dD>h|k l :ԼyNyuv@{p8 ,i@#1h 4-@+54 l{>wzߩy#FB@$l){>M<ʾ GFCEGC-A-FmAmFC͛o4ߚo7?^ao ]'w?(=נ< //l?z [m`;=v;ͅz`op 8 @Gp,87Lp8BpXA q , $d4`:0 fs<`>X, 4 $ P"40&J6(@ *) P*@ h-Z X+`p. x/@!` X,V+Uj` X6Mf` lv;]n`Cap8N'Si p8.Ke p\n7[mptx<'Sx^7[o3 @!DAD1D@$)DAd9beU[[;;{{GG''mmpddGd'dgddWd7dwddOd2BECG@DBFAE+@G@DBFbcc!!#' '"'A'# "!#g g"g!g# "!# "! u U  55 5G!P-QmQ]QQQ#QPP Pyan*F)-6iƭqmI*I c.eF a8k{9>[ϽM˨zv9gϞ{NcZ' LBou`!-j4-io>4P47Z;.GLAIЛW ( I`^11Crظٻ=P9ע^ضN7P ,u)d I; ƨTL1{IEOI(c_.< y00j m!uTevʿZظh<7 b9bz  H{\|䗴U )# ]"n4Nj1#Gc [Ped'YFb\/p(uǾ$%2SSzG3EX>W+PWFfy|vY h.4NDOLx(_Q8j[AE{vֈDY\|*D]C7C78q|&)7Rn<#Vr!GJ[*DO3Ʊj w"'E% @;IP@6422-74^K?+ґ䠹;x{^٩Iٯ ̭ȯSPPxd\zş?_9q7~U lYhFyC=[@zλ̯݇}c$'S9=&1gQTh ڋ"NrJP k9%=?D&;O&l$ps_q&eXGjRR,`y6o@ÆykpSc.Ƹ꼒0r6͜n]ka r91vr)s&{ }aWtSh'ZNJ3zSO]L繭s~uAS` k1 = = 3"Ǣaa*p\rMr/Nz@<,6>4$jk;.b<{=b6qėF T~W~FDf 6XSC0\o^j4qKk_f='f@k$%~Cu⺊-_eeRBgu4Fj38,8Uhhc'J[|IFI$9-7)C/PKz[vY;ڏ, ~A oaI0{u!ICR.j jj53ߵt3R/K Э0bj %ޘ}B0E@H?mE #$W*[GUC4uƘS6=ёxBdlVNZn@q0vAw?؍fV$Ɗ A6E5AqP6GpPlYxʱ+S ヴ,qX.GBɨbF"" 6BA8f#6G"'H\D|+·t{e\ K|kjJZIةpVh9p{b|sEPuI%/D$Q(tҏ ˻osFJu6Ӈ CRh9%}^ZcX]M>TxED,U-2l4M0N!bP&KYbkn0`iTm{$oFj^IB}6:2j2t r5PPw\Gxm$d,l8rh L~;5yLiIAS1;ERbjIncVg(]?g3gk@bOحAώe'ۘ{&Pq̩X}&>heXNKp<3i?tZRN+<|b!9҅8Y.di.[fjnfM.k,3 M9*ڀ~DY;{7{:B0UWѳ)j>Q։xbpnl &*uK79s=cdĒ Ad )p<7u=9ʙĹExZ$Iĩ?SP.Q! 6kj홙W$]@?ppiAItC|MRcRagj [m*N\R5K5*'u1oZ<N]r˟(U=K$@#X{|_#й_R=BUߘU6O5F.KaKM] no-FF)h|l{`gF&#@IMKzBq񒹍u;{Z@65WG2m{fw׬80~Њ U(70n5368gmME)R;#6@^WnU\uv\\ )nYv ʘNQe4+M.vE  8f&YTRmG-u̧(" GQp0s_b\i",0瓡a#anďȕ)e4-dz~ < ƕrdג{sh>qDDv=gzjw\lϼ\Շ%È6 9`^X>L$0?L Kma'```a`GagaG`a7}-=u`aO]}`oauص8Ocn5U}Sk{55-]cHDk#B0!,‰"D"b>b!bb1b5b%bbf.^9t 6.xyY99 9 CNGA&!H4#H҈4 3ld*ҁ{xG.A.EnB܆<yy y3.21ws T]Tb4) =;*55 55558"(-JR,j;Էe3KשPP娻 ANh(ڋVt*Z: D>t:zz>z[No[ЛЧ771M0-ow/W1c01 LfbpјaLƄ^qa0:L&SYc Y.%Nyu lK3lk[l , O]QcxæcMXv6~]]]ݎ݄݆݁݊{{{ .[55µŵuAqpq0pF[ww w;oo9x +2bEF:2.qQ/3KW78BSBwфc N x@% & %02l1k*nB9B>L>EF@>K>GJB.'&F~H~L~@~B~N~KEOI( (()})))S( $ OAP@QEER,#EqP J)OGY@YJD9EyENyNyH@]MvR+*M}CMc)TUEPgSgRRiT&u*U@S T35zjRm"jfSW먗ǩk(?POZRRbO/ih]ihihi}hiihihihSii2h4>MNZ*BKh Z-@ˠ- i.v3mm7mmQC;HIF{J{I{Bc -]CSP:ΠT:[Nz=COЭ\/ n }="^FC=CFoFMF,>w11ّcY c1Ce8e qqq񔱓ٚ9Yقً9lld3L% c1s22M̳c]=̍̇[+%kS#K h t=@`80F+ s<@R),2`1# lvc9 pn,4 ! $w$965nO e}nn?n{nwnWnⒸj.qE1\9w̥q.==D,^n~sqy5܋r^M^n?{Wי{ג{kkkȓFԼY<:cxyx>^&oƛLo[[[»;ʻ[;_'5%9u~h(y{YiD>OD>OoV~&?/______1~EEA," ̂"A# >NCqf/] e- s3_]s##Äͅ a)Lja0O|]h &(< ,^*'(ډ"h//R抺Ɗ Q'hEH/+Qt\Y\SJtBtR}+.*O7$~=O=O=b,6bX(b8Koī_#^/-^$$>)M|B|ZP|O|NR_@RLRCDVA^,tt L $ I$[\PDNZLrI_rBr&Mjv@*&ՑJ&bSWԼKRI]%XR/z+ש/R+M}C㥓3sx\&H i4 /^^JC[SzHzLzUzYzEB DF'(k-$.MAe2'$2L!ɴeede[e7ddubyOsPX9F>INS$9W.3h>j>c>m||||RRRRgidijimkomfl!XKbaVTXg[YR-*ڒfɴd[[,-K,W,,,,O,-/9ZWֺ3֡!1Vu5jZYˬkwk5?XeVui]`}bkac=d}ce=mk`f}fgl}dkdfX7FZ_ل~dͦmKm"Ƶʹ m>ݶvvжvvĶͶv>>ΰ )5sa]v=^d՞a/iv}}}Ez\zuӻO>)}.NSsҿN_(ݝI_<}g{H~;Kg4ϨQ+UF_de Ϙ1*c\Fό3 uFR4Cd2 FQ'c~FY%cy[3Ne,ؙ:cO3e\v4q4x4㙣q1G3GkG+G7GWHGo8tTAptav9J C8l2Gc#c'JN i gMkG㑳3999999ڙ:N:yNST9ӜVr8_9:s.q.wrnpnv<<||jjj"%t \teq\ \_o]߹ ]_vκnUT[..ιۻ[۸!a^>)$7 u'n;wS-w&ǝvwggg'zxqz'ӓ=NE͞U՞e=<=kKMa}x}g|f9}^rJ9Ms;P`l?֏3~ooo___2{@vfl\lfvBv^9@vNvQvr?fi2gzΠv9rt3"g\)`sV,Y>T/997rNȹs$s[ȭ[/i#r̝͝K̥sɹ쾹\E*אM5,yyܼ@^~^AEE޼y-۔1o}ޖ}y;;w"T+y7SIX`N@ ȁ% H@f ?    t 6  [[{''gSARdYAXL j>hjAw  <[ >^ > $a]GOȟ˟KSEWߙ#w; 4/hYжkA=  L(X0 `F`NYT)|[`YK ..8Zp^ÂG (lRXja gN-\8pb!pn!WH)Bn!WpE­ /+}Qu雲zeZu-P6lv ](Qhe2vW*)ʊ{|9q>&[5iBsi|d lDCG ? 4* QйY& 8؄HO) WR&@&@d.+:Su۠A \Ow}? ;z?5 OE !&l]oLD  {.  ҫ (VB3ӽ7ft̒X(W@9W,AX\L>B0C"%W* I4AhR"!2@eQWOn!LD0i3&ȺA&Lz:db? J 'OA'H"N @޵OO13=1+ؽ B4auGaA\Ġan;dmZU>!HH%g{ #(xw`$L 9&,Q?W`ju>tmJJ= UtGSE50CߪdA7JA44\|ƴxV.wqcϠ~H@*/H!)Th7000bf;"۸殺$o4{ @DS 2 @84"LC. 룕tpA 2pX Dp"f J4r)lW4$"s$"EOw :31d=0ս8yxwpʰT6"QT, )*c@$c rq0!»Hz\RsFW $ ~/W_O͡\Y?dB\ v +?l'tq H  `H@' Re)fF̏d\_5Ey~zsUW=]ɏr4X"pS +bRB>=Xz0)+}z!=K &DK, }&DƀԃA5gC4ØC!:bEJFUHARQx047p7L > Hew'06ޟ{=ȹ'0(HA 2ES%̘6D% ʷX$6Q[tB +j|nCLQjpI0LBMeRFtTS2GUOC"@Ld+W T~ nr?xP|t;Df@ {F? >:P:J%W>+8,thR%}Ar!M.1 R\X>%I S7,!vp3a7hJhX#'v/(H$ 96]#[Q±2rb4;YYš9d!5TjZHtR0P핈e2.xs2,XB'w\iJ,Cb6 tnp29xBc.(t s҈ )?\C5=K.\ˠ @) AA@a*UI`bFUh&\ZLRBt/#\ٌ#KǫTA2H,e%©h.bpP"FU9l*Ӱr@ QC<%ݳ=< "cHY%3+3$D [URL^%DžW } #|$8dX!`.D !Sh RXޕRاnCOWD" U>=()$ٿ/iP2 {w|LaQCQNZ$eVB.f_) 5xF5"2]V/9kߘ!__? Wm!FEs b}Cubh?@>;Đ/}h@ ?_Igrs`rOriK`jÇ b}߮__Ͼ1' #h?_I+$1ZTWC( ->KҤW{G 2:dAaܧgg4 P PHA_2$VBH5p&j1Ȥjfq\9g*MV>(,EA؀VS )U7/`$΋je(Dзä4Z@C"U "d`4yuϘ-99x9#? ::a%j-g3g\44|u4@. \UwYO*ӈ#\V-pZQͼz˸N1(N&T3+"|!=zj iug2 b.3PȤ1&qhR)Q3,\̆}1vlU*_@GJ_j_+rp8\8\8p}>?A2b藟'-Ig=?ÿ|?iySCG~yjX6dg1 q(bjGkOp/WuSw/ 4!Ah2+@M %}ㆌ8w?dvD5j/߶`ojFCGw֋Q ?M:11|;ӧfL GFD?uPWQ#cU֎1UR'Ed1~"WHUcG c~Fү 'K"F_j~"UOpE,'}fJ*B>WyXU[BOR"tΌ鉕A ʇ{ϧ*n(.X{UZ bXȶTIY7xTL'm^11O wsy:S&qą?ck;~0&"wۨ<15ۃ#rn:bSC?1\OBu Ҿ/s 17':%:LbҮ`sHT7MpNrcgg|¯e$aXJʎJVS0S(x{`̉nCL9 &!Y!:w'!: $0څC /I6)SV#m 7{<&MpIpO&d.TJHt3F)B =ӝ7;+1?1#v]Zk.~ BRsO\C2Fv SnU%]xuBl{>~9VD'"pxGlng^#ܰJ.anYp *q+"#}9sDpEVcc%"8Gp9!kѺJ\NnZ%Ik:_ɇNv~9{{7~r~s8/)7XP#:u9# NϱQmjIچCG4%S|п{QamC:IV̆7*##u+** MjDt{؍1!1 CBs6 EI{f4=XT; 9>Tv ScC:t-ܞ*-G 4Њ+k_Ŋ.Q-li <~U#ox}8VzM؋jFYl&Ǻ}"".ʝv n|ܤ(6b;@ Oj.cNnvFtH~mw_r}k4mkJ0 yƘѬخ2-xEhZܠ!wz4ռ!sGF3,bWA5T)ɜvşTE;;FߦuUyO4*~cDq|߼m()j!ѭN'Ė/f :,#PйX8Ɠ-fhuXqG\N۪S"<եm xڇ1'ޝ6Eysd~C(2#Q&W(MHPIr*('/m |cB6pxS}%ŸǺCX5pA뚘*uby6!ZM{zY;=C?`ꭈUǷ8[hq Ӛ&#Sno3C눔?V2$=. h.7#VVamn5]XSW*;'S΄"(R?'K}ԟ׭Iw[EMP ŝ3p&=|Ghlc*gH¢絊wHm.-#1J"CN*>NgUi\B1(eXg ֡ ͜V ٝ8ά3h HI-6aM: @K$ѰV5PE5"ժmݵjuߵTѶ.U[V6Ws$77yޜΜ3g;̥':;Yֳ%O vn"S )gU\B9 مF'[o\^zźa)NZܘxj)754p3C1%ῸaH=uw37CܣP>Nf3i.^$.η"qM_$Еnq8 '!<䭨U!ʸX9؄ iK ү`/OS/KkxKp[98?p/ yQeT9 t77ñiT8J2y?.վGXÑ&oX覺Rx~pG cc:DD4u=G,QҸ{(%Rwjx/tth/xN''mxT8uZ': pOT38[XAb WhGצW;]?4^aעpٟ/*na֞9'[wf~!WgG{6n,\>eHi(_a$Lˋ8E#9WɉOġ+4[LKq8ǘhgGr1ofrVߡ4 VhK ꟦upǥ5 <5_:)պߓ6Dc=?DnD鳭#W|V puuT Z8)/l G G6~+m-ln,MckSOm P[~M;96d/8ڶuwmak;jcԂ8B҄],1*ck aZcա?yd *3ruP2[ETR4u%J7zx AGDE W5{i]5{~hƨ/pP$m> 2Ҵ>W.cMÃJn5< xqM=PBFdt)bzGp.:'OʵGv$) mR +1|ʥ;^J%%LčP5{@N.3H6'mI!rzRHƄ:KzkJ ?;i 5վǒe~_GItyE[P;n7[6>=T;֣^_9?>axv Uj85`||mLJ_6 x>ْ xmyőG2Tcd#b{'ȑ.C,{;Ahٸu}Z~f2{jiD75"[>,ǾT;)?KXVPqP9|cu1eZslp7 ӱXdiYVK aC\E\=*3璨hfp ~/~߯u|7]-|?'ބ%wl| ]'{{|o]+w#p|;>xa"W>xWa&o#o5ޥZ|U;w |rrwa,+]Yis2 !u|Y|L^:@#ce px7|'_=\tu6 *i1_΂|/|0t736|K0 _*"W `}|w|˃< p5!DW4aBhxg>(C+EDX(~LU߷/7_5^)cF%Td+ E*Ϗ^1MQ߾QIɉ5 5b 1ʢ"eYDJȆfqBU~z E35Yfi*";?[C/R +ӧ @>qO!j>VVB!X T,7W%Sin: @JODE !I'DJLY\R$.2P)JŨJu>Y 9K ?H Y ݰՎ GgFX\ \=86Hn^<,IP8W}d%+YJVd%+YJVr}N܉i;rS2r7Q=B')^[rcO۞rRiʽD7(6Q.|Q#ITͥ-ٔ+-rP>=Jݩt[JVd%+YJV&| r&H*#O" RxʴEZV"XYN^N o"AUP( Y(KS*P!@!&!RXTAPPp|"$P$80IX1KJRd*3>JNLfQd`.QgyEe.҃ iԺ%tEFQAĕh\Fu1q1B.b2d*CdeQ" ڈP( 3|EjA&-Kq]Ȣ.U껪H>OVX8z2z&C| 6 b5CDd0t,A xICܣ(Ttm4yiVf4y٩ xWJo<׿q=^lƼC0~IQwᷮp8vJx(nF(X!yh+B]JƊ@PE)Ҩa܂LܮKeд\ٸ+N71I{PX$WۘbsU0v` 4xFAPY"q!ָxsհ%6[8G9\anҟiHHH3 i@Y_LFu#:_NQ|'?I~WBH>DwJ o T/ן jZ?2 >gj_0 Kc |/?fY ~ fIpTO +۔cIN_(dcI t_Bȯ;odǔ2 i~@f.xL]``[p&6 /ûpVf{tu ȳ4;SLӆ6=Y&yN]p(a ߼r9}]79p)kA.@ _+U5'sI_gZ\a-JJt iz4_7-VևW chagqzҎc,Wq@q)XTUrtf@c,.Ɍk1W_ezвb,k*bLH$Cp/ b,B#ɟXB4Ãc&4~~`!B[5sRc!WG}V*9KV#lô5B54 &vHZ@seԦW_콱98{?峡W1KĤ&~ٍcx?Pw&JE[$<Ө^]/>@j%S^JZR|G';Ʉ9ǧ/_>&a;6*8ڐQ̙v(^mS߭Fl.ޱTߦّWluSoͺ{\77;\T5>zչ0XT+0ZO*̆jI'Ӗy~ɸ~/*>C:˖\Tf݄Rex]ZU":*OVq,6RP",J*vpR6n${7{ D(O wA*СԠ>UP){AD%!V)rŢPq>1^N4V28Z*?!D$epNIٙZJ$`$% P="Vw!iq9iןwNY)te/\Lx/7?qݩ_vy6KU3ArI/ʛ\Gc~N<4p6v*+s]R\g]&O*}qջӹk>?gÏm\g}9vc ᰍn <ӎ+] 8Q}gma͠;^3ԍ5N҅!sfw[Ώs":puL?ݾӯ+Z3}h"gԼ>E!rޟ(ApDt!8s=d~d8g#/aƥsD [Ytv׏rj}4&}xQ8tD=Vu[e?|oPɓ)A}i *jD+.;6{gS5}v2;_dN!W6C>{vbE3.evu}I٥0b"IKDG6˳=ؿ@4A-le~JСV Qe N y*P*Ԑi2P\BJEXuh:Z њ9%Oiz6@P ժ&e ` i4SSkԁ;oYK4YCueucz=bz<ՅK.,>Jsmoק&Ix.ir:TA#\k/fgv^DmZ4߰/ ~9گO7UOp;vA4EIMqΙ!:UҸ&YwB&?ksD%AGK{ԭ_ ̔I+}Zu?&l|Zr _mME~hD_&Yk%s)`" GLcE#ޢ^"d`RA=ĭE^d\AhfQ6k拓D77LwFAyG'Py)q}t=ӿ~}b߭goyJJ8cs? Ma Ǻy4Y>iʙX|in]]A U-K>k0sx 2~yZuz9Myt y;kE-}>cg}crAFl~qNϹ=m\u3m-޼y?=x+U21>GY7[_WNQju"Wh t;c븋m}&r4rla2Y\T07`2ưn0Bi@c8s9@QOQU]WuGZ[ٗ3^ę="OԷ' suR>Z<7NtKOX8Y}x}~Wnǣct^=r**oëZo܅vz[ڳXZ{Ro1mE@NK#% $C5at=ʮ`yώ#v=ۊ1\/W8Ċ1c5-;_QXQvl1ze+X݌Y VdKrԆb_qWGE<$#G'D aW2X. J&eIB#((:Wkql@ꠄBԚer,%LפlH&Aiv9iYJuJ ZcwONw~҄4Qzde1C##{\%DE!8 {^wHEN쳙|{;,{~lqbN~4){OǓ]Gʡ{+ܶoE#^<)YA޽/o2^㔯eE$,n}r[KaiW]3gL=;w;7,S34beق[΋P}Lq\_/9KO, &NM.+YJVd%+YJVd%+YJVd%+YJVd%+YJVd%+YJVd%+YJVOʢ)VyŹ\U*7HY)N JWe(QB)(RrID„""P@qH8T, % EB?j8yxCtX]D也z!D&á}\Ej,ЬɈGv ]L]L*-!eR[*5uУ6TyB} JφJ X _>]74(ES2R2B"INJE,y B^#~wH_J YҴ8%Ť&)G-Ud~xٚAR֣VaȐku)TΟcNJ)R((]/L 7rZ~Iߣu!Tx2I7a6bM۴aM5`~ܽ 9^4)'!N0:ևk8> Ŕi/`J'/2N冓rcH9vgv SR/)>ޕ!=rJRn]w0O\&)'C^n)C%՚tS1%;%ew1Z^nU9S"5a+"WN?ES=-ՎP8x#z_ĠL$<G2V2N2^w𤕷eڧhP>@t'bS㓧ur *g >9-G;FTQ.OIjOCU5cw\!)ұ?]5D5S\;@_E5)( nt "CtMt]0g+lmPiRV}AD3%C*ȯD;!{!F9!|{*W"8SYI0+V0S xr0V3onFm'(u1WRUeSj7JeS4Q-CgC:L66%N<ЉLC'R R۶I*TuڇeRZ/,)`ƂCAP`e3ddZɾ&;L%Nв9 $sXh r*m= } A _j FMNHS#i"ɵt kzdP ToBѐ%u * >,n8XaY#h';Wb޾CQdM1Vr!Z uܿYg!|!S Ӊ~s1xnp#s rOzH꾏z2+PI_ r8xAU ҫp4@?=)XHT82L@2dl,j-AaKf}qڶUyT?xPZ,`Etbb|PhgS#y(8aS  BmUv&))@ B Af=iiUO؛7PaI7mK=͠r?cw3%"\:xl P۷3рGCݨDn>(Aq<*ۙIPy 4  =Lnw2г,\}hCdjO>! gM #X*]"J@L=┢DWoYfCBBb4}H+jYf?HFլB0 mٛ*.f pB|d$":1I0zc7}G'rtx*R R2X-⒤ihbx#85KHZ(K,$ϹPavl6O73\TEzR|$82An#Aԇ.rczEaU, >+{ *.28,*,#$y *Nfpc&JIgIWlS ߙ'G&'L #U sP cPƶ.,\k6hцpY߷g&D=-7~o쳇| yoYfCNdh  g%l%  y•Tu#ʹZaۨgzv2FsfZUe֐h0Jk^ H9kh2[M:ሯYԡU?5T d8SvV'N%z,Qd|ʭ1bB&C9'ח.y-WJGu|`)h*_kt/5Hd5Q{%wIs޴Li8RVÇQO"i Gsrj'}x]GiW|G{7L:/fEthpVsfek77+ѵ_GQ碸jLa$|mzAcǓtuD#67Q.:7lnEW Ak(WgT؄W2zm=C2όsҍCv3Q_M r]Pz @u~L3/ot`OAm'F"taenv?;;nKwi/ g r][.k` NqLm[/_ŭd5CH!i F."LCz/>݃]}\$EAI6q6Ǩl\e51HE^S(l숅X\B!`dж #qi7&Q6=vڼXҚNGid(^BnYdBi?S6mC;|&7eڱqHy/SJ EOu[3cfDteDiQ1 "%D!"-q"Fxqif"bۈ7 tD<2Aۀ^LDf w A"b$?zYvC3ZCa%8lכz 8\O#4748{20t(4Nt=F )AaAR {'zMaܕpnT Nyp2WT6H𰄄4$x^~v.niHD 7 "1!֝n&Ӻ17w"- ;f] w,/v37DtTeS*'q #wIp3"܀ktD k4Dˆ؅EliY 4p)4ۭY,\ÍduN2wA?KP>ke$9xrȢM+Ρ+=5~\ 4Ej ָcfW p՘ rjזTHUg\2\ڄ44B|+̀]p EG H^z8V{ }6%.iMq&k6n"cT8^''C tͅzyiSVsP"{Ls٨=mD]AA^y.F{RX'˿6.-6tI`ɞ4{)hɞ ўXi"hɞY΁nO4˙fOhOžqtOg=:ў[̅fO2Klr2'?gS{rwR'==vW`O{hݞ:<'=582IİTi-XN )8ՉiO}p3GlOZ$izA+{SG plFGK&M04m kc- ,dp1͢- CZ G='s@I6 c6Q~̕K'j:ƁV&+#\W[ +# ؄$@lko\H2/cWVGW{Wo M Uݰ WG$:ڷLVѷ2kI[B_۠oo }_k }۽ >>;*ބtA; oD)h[gѷoD؀|:MGcn27@_U%ѷƶEkK#߈>e}[ԣmKd6mk }lh˴m }`%ǵ5CmQqF>jQAAϥDH~Mjc*Sͳˆ I6o<'k_|d^8~d <x-Ϧ5 μ75<#,X^K x7% 6p-υKLl }\|1ϗkV\s{gwCC}9&#"w2LM0Зi}$Y,RӍ.,zGm̝EG*d)a@(t8;Nq͍D_8|OD|O> X|==߳}"{>{kK]|+ ݳt [~ |b (?ΚD} >[! eO~:A>_AYNf>xZ۝P&5P˚ q7Qd}_w|?:|ij(m_Vo>2.UJ0mKGDY\".%6:QEBKI0KKcQ(0%)Z$cK &JJV$%KQђ(EJd-F2d1d4z">%9!>8^?,:N1R'Ib*+eQ"ŐXCyPqCd1I踘d)C^Cd 8F|2֒H%KdGR-,NEKM)HD >X!DKRH\6&:jXh?d"-GT2"^X4>66 2;,)V8B 1a IBBt\BNRţj%%%R֐a,ڤDf$I"\28Z>X=*)R}C>Z9@BA @>2~ O *[~H\xF x#㣐||DN*`I #̨9#G NbPIST|BDȈX *A"ģcR$!Z1<%>9GeHޘ4A?(MV86zdH"I#'&NG~^B/e2kGîB01agb$$q(= də/6 $ $#cQiu"R 9* >I&iDIXw uI߾&}¯Egt"SQ䪔[FR:-K FH֨,LTt+!aa*/;mMrQ}UE5df TjaZ_*%te53ɗQ|11o($'{I>]sP$;!sx3~xZߜ ?Od _g3 k--˔d > xI |%_a3|3wc@ ئbp87: 'ùp1ڄӇG){<$9 3 >;pBߦo&/C= ۓ8BЧ_kqj5T[N'R)i6mZ0-L&IȘ<%a2O-&f+~_q˨ u_ΜaǏ5O6KkڞGl.g1m[>:ew 8;k#fij:(Y.EySc\xh>׉znOeeKKlOvI/z|:w'>\'lm/'n8!_ ||V@ݕAg~q|sӳ'||ଭ?tkաqکBp6dY72q:1?`tߖ_DN]Qwbu5"XkoMZ䌚Gb5sR3DnsE66SHn q#g'ϏLle;̸pDwz<{ΎYXbQNmϟľ/  QǪnh M<dEAؗ *B L+eYIĝW~fy[?>v=NߵWt)b4r+mw=fL?f^`]?-vE0_HK8>GEm7|es'\By 4N)Hګ!o ~)HlߢΟye4"UpP#4"EaPQH8BD>)?1 ˪WܪilXc/}ElK/zvD2khpV6sB?"=}xϿX'en8ahhR\*%3Cf#kuk 7xNֹ>WT} %+CUN^x<4 ֻEJfo& hh,c!G ];iui8|Ҕ37 [ܺnݫ[>Yy7J}*)aqc e3O^,Y;rNZۿ'vٿw֊[|E:Pms{ڸ%+f[y3n{VDyegc4}?ճnBe+.ꇵEF }v~q4+Lh"d `ӏand {% a,ahҀ&p?s8 #Wq<ÏjT/5 g3{lEx tvˏ~8Lm>=. \{yC#wR={&Tz2gomyQ|*|xGEǖνzTLUWчW >V?)g[bm6 V4GJIhEkäN{]U!6G@{cb_ iܹ¹$K}zh._3{ фwDlر1[`u3g+Xm{F ,R}Ł"_*UoJ޾GtSsC-LH,E }pCE%G 䲤d!+86 AuPBQA!j29Rk}Q6v4{Uـ,:K*ోHWj 34a!jqt,h D FQiQ!"?1"؏;9y`^O_R{;;VnG ?,GҖDOoUێTN~7F/JW?}=8}oM/WgM/\wvgK6JWçKϭ}\^Lo.Zƻ_K f-yI󶟓 NG:_vJԂ^cƔ ]-@WSؗnz ._lr9wJPw&2,C5n|v燝z<W$͸zK{{C~fďé_|T}_OeVd%+YJVd%+YJVd%+YJVd%+YJVd%+YJVd%+YJVdG,@WUrŚ | S|LTDᡡBpn'!P(X,#`B(O4@Z,BEU$22OC!J] .<šnuU4U:^:7 :WQP$ JN " ; uU iPjT ًim_/Hh!a  j;?t{jq~zWXX l>lfz~-A0O>AGT<ݕM Erd yuP >@L}swҍ,c4ˇFR,Kͧo.>A5Qx2!}ԙjOA,S^OlS/G(oWҕx:Na=Qd"2>.&\(sE)&vؒ>:(Π\\,rP*겼Ԃ\EE}Y4^.^p F>ǧoSeqâdD |tY](%y(A h8/88qZ>N->;dC<]ްM A'l:5aT+:^"N?EUPҎq9dbE"i;qŸ&m.-> Q6.Mk \knM͸:V> %ornؚ@Y& ${T'B|R0NPE$1ʺo+3pgE)iRV}5e޺>H8܏\x(a+b$s)tl Trca(-z-)-/ކS 5dJCJA*JӘ eZH#APW<&`M]pv"6HDE Y,.D@LBkU@}oVj{U\^ťkmݪ5Zŕ̽Y}y9gΜ93ssL[ғxVA,wP\l$?75f؜kasHkZHA/0+Y~}-GOyc8LQ(Qw0Q^aQHFJ,  ru3Xhh,s#ڂᱬiIϰ¸ z"2ẠgV'G!fso‘X K,o+,/C'KJҴB~d!rڌTyĥTP\pQqR\cKL&R6zS\KR5u5$5B/1WGND+7DiZG(.sl&pM.4W9ݖZD9˷h(I[\b41<~筭A*TtsK veLPK{.>c|ng_+Ni`6{|_\$FBhOwɇly+!U ruEeȁxIbXLZ Pru& 2ChNO!i=rDT*THnTLT<[& ۡD<"u4|[) E 9apaC}}Я*O>e90)>ŤHcca<.9c$gKcq.!&#ІeH$8;4 cӥi$,!b3ǧC1F'S|ɃǦKo)9%fx+-Q;cXZb°8#d)=3᝘H;iaX`X`X`X(ߵSiVS\*JWQT TzJzיX`X`X`XgދhiDWH'+9'q;EV撟gcu+ 9BiaR kUQ"(PJ˔<99Ei#ˁfD+4-3M:PMWd9y@JVCri^L4]tʂbivI*'_3x<&Rd i\,/ȁLTT)rJGbp$)ET6jƙۋ^σp8s;q3:0m <\ Wz3.f#x./g"%?o\ 5m8_>D~w 8pPa]3hh0^ Ƌu_3yf7nҴi֙k^A5;-3* e*i̳+vSG?CzdA$n5+8N3)ޠCPuIiyymUVs Y5At[^5mk6_EUYGv.+^e FXO[r#4]>S}+b1WQ4 AѢC}.O85ũMՉ헔꺫o$iϯncwaU]/G,^̸ڪªhx=\n92B'}턶ֽ,MY @t& J@p0w5w# 3lĠeûͼ`{ ];j,HXXnĺϟ$$M+ nAaUzWJM9v*m9Jpo+;X;Y}|wGʬO¯zqeԜ[yg^#E'z8\pv ?O~q[aQ qU{9|ySN&ΔΞP춬eLDp<]חT^\Ynó{15mJv$]N{8{F^ѩ돞T+v?mGʧQ'|qJOjk;69rma%-KRgw| yjG<0\, #& oZ7lRׄf{c+g4yGqWI}¿n[RlNٰLl߸vM}]u ? 9yse9&]lOƼ,?rü]ضe+N97z JJwDqswƞ/gD ߾.?G|·zE_vr2+(f[^+M21Uv;ǚY!sjμ;,a0`ښZ<ܸ4?nGʥ埬L=fӊ։ Vw[I8dۉ^\oa3c]Ugwj'=Wsҫ_{ޝ;n<+ &ǻ՛)um-q"V5{`NȄ'է4 z6atn}N'zhtG)yige\XxwMZ1uuN} cGҲ9 CwLbι7_4XRV)\7q_=/Nڳ~_ǕL/_) a0zDp[(QBt Ĵ2\IؑhHh}w%enbQz͙ȵ[:nl87g{t܀{{f >Sqp9^=sUX1N.3'wCW,8Wu{Oy@~͊Cuj nzݻ~\+R??+n:+^轁Cjέrٖuζ'aB; 9F>dSB0'ȇ01鬉7Y=W>ӇZ_Jb83XMpfI99[ؙ?)ʿjlUz>|؃9[ʇ{]}=/Խz#7fXluSUƣWšy+-^ܾ3rHn՞9B,z޺쇝&ttHX,nyZG:s#.h..NW:mϚUgmXk{_=r:aFʗWuwOwk2qi-,.?VX>KZccDfPWnU4v;n13KE^0~-Iۛ7]/tgo:۰mAcoQ믯Us;%UQT(  bd2DxE KM/('MAXW@P8A$1-]dx Q()EY)AP\UjH7RQs rTmm"'+˔red`(S(d-!3,U>X84wd\ߑV[) / *|AcdUQp A(gzoB${e&ra{dۮZէj닃?~;^^E-t έI;NEy <݇߸tҪ}mVTꠉr*1~[v'k޹=nI͗S=acNTt&Om;hV~\X[kFe(woC-gq(c._< L=b , , , , , , , , , , , , ,?2S@QY P^./ Jb҆mPH Q.  DapPwu(Sd lw|m)7#󟮐s䰣.Q *ޢ7Ϳ(41a(Ź A<~f7 fW0D! .,Ô1z /( d9*@ hȊJmEm۽d-?ZF]V[(6z e`vG{8.l#` -9Z:xTnBs(܂c@*U+ )3IW:q\stCTTN W٭5%O2_^X*Wwُ?rwlS-=I7 HR((kC^ (sc1+-(_bBަ p C;YŤHci}Л2p3R$4h%ύfl !KcPЋz}J eReeQvIThS^>We1^*R)l{ϧ<&@?X$qDz.St1~-\p )>h:E?4b ڃhAxJ7#MuaLِT;7tZ(z:go|[|ۢ"y)|NduFΜ2"s*eqeYin`pX`n%"R"Al%?/˓LvVõQ3VTɋ6؝k$><(|hY , , ,? bwbFdĤk'կE7%j*tlh֣Dm3p\}L߉b8ubUZ"j2SpՙI3:[V ATM^t,h7Auf>Q!=Οqtcpu|Vl?&ktpNzgb¡g;V>>:+W`*Q ybv_$j?@uc(u?@o@~Hm%H E'H~^uL,w%B ۞@r" 4 InKzZHL"DB8 ɦt3DAT/gvFBBd<7vk7qQINy H=j@l&+QyUn t nFչKy쨗&h''G 1ؑIE/:1jwuDb%_7~-eK$qZJL6<gi &x@ĵPu֋Eg3>f͠nތ<ko׶ĚYӡJmJ&$k& om}X>>8m!hUu0lpnX}ko07تuu5YШ<*紈1#yu|DʒjogFV)Ѽ_qp*CHԤ4:Qn9h`ǣ gB8.oRƿ-5ڱTk uT[g0Sf%j9|,Vns?׏$)t`(/h0ߞn*Hj IjbVIĚc0_SIqlAوmB=L=4񴔡0٠v--GùбECӣ6Gfq]*q]ƖݠfZ/:ue+5+/U;eEi bM|E6AH5l GjGWKT_RMQQ~[E;#4IS+B 5Gр>Fld2UMf氹X@^2GXxΖtl6Mܣ|`?L  iA ͗hdtͶD}dМz5 \3%?Q&%kGdv^ [cQ} c4IvqcjZIW&~Uىxvei*k4-*a5G[4v 5Oye2_W/HױI4M`xs"Q&׮Abbt>l 17{!/^cE %pmqk!#!nK͖pgOñ%݆=!x k#cdŌf!ކ\dRmִF"VD8HUiXkk+*?G:5ņoO+x(m %x筱k}IXβbلXB7_>#}\ƺ_֐놿@~=_ :{=ݒʸbd}T[h!9QdZkU5Uكs"^W}%NPDc v[&u7)+J@$cދFi^]I %XA+M#VVux"mƔ m3Y)6,)JD *ObΒ'³t%E ݂AqSk~%Ղj='~=>l^fВtBdIء{M({5]s;ne;@Epihru_5E$Ajڝ, 8=mj u8@i. b\9}j!M0 0{u5&0}X}Q _<r&T{ BɎbYS`#+AfIFhJ5)ZIXtӯ$g9.2kIH.;kyga.Fu;c<:2'(J퀯bJ f__3az^+|.r=ܑ_+Q"GK-^2pI$Ms$T86UV!UYyy U[ αzL gqXg3|g,鰞kx`D6nɋ"#mo>$o3`ak0Y{`^ h}8Ѿ@v=DjT.ډ<_"hs> ¶H\d#QDlnr'57"Q_"XR)n6h WGWd%AMbVA aM|cYOqS%᜕.({|= Q}jEF 9C9#>G@|AσYCY9S9Gs&>1<s6>x| \\ |Vs9>W<t|<h&GAM7r!5É(&+6; F_7wCCeAn&A]́\)VC>44r! ;:i.w\(B Or9s\%>W@:YGZ}L6ir]\Pr@Mr@ U3G !7r r W9OQ @B FAMA8"*8,1M<,>ONOIE)zA1C.Ft @Dqyjȃ<,NqTrNɩI(JUA.HG9BV+)F\(Qݕ)Ij u\WɊt>8X|@q# )?()PIK rST JG~JQ JT(/+de -!@)rE~²ނfD,g^o WZH%b)z(1MD"iO֠Xr&+FJ'ج xKrY!JMJ"~oї9@QD( oׯYVšRp||8rRP&Mr%60"]fv+i -z+nѠLo< rPɕ8u+TP90h( ,]8 S<\࠿}<v#L }Y`X`X`X`TJQ?IԍJ7Si4t*KT)T:JS*]G_Q.*=D'*FQ#*UQJTAC*uTCtJt T9 , , ,{q~i)*_!( ę-Md99ye2E.g~tnea.+/IRpc9 ,A(ʥe|DWX4AZXTш,(MV(e] \**UՏ敃R,GH˥YSI1GZ(/HH( EѺ"P_IKJT9t͐$ H^SZ \*٠ ;<"Q*i4L*9CYY1*)`i!Y`x2)B_Mj}N+t2`UgɗWX-+dm`1ʷt9.Pl+CTqKQwL騅%yxtE|9gKȴH:tZ][8נaJSTJ9cPX\)6)Tj'Ҍɏc4ɯu +?8s9fdo~!x6}7%|Ti7 (޷B+h>e /`k~_fx+ qwcp |c;xc/ nAi \+۲-^32/ V-̌;ca1 |8/`țgyy^~ ߛ]9da,t9dJv=?Fc+:` K  {T'#w7 }9d/ o(5= 8y=1q`2aF<$c77oj g #rч,X N^"C1Of}/br+vL%2O$ޟ .(w#-kgcG(+--mΨ26"NRoZxU {/sdIr6l|vƨ,)ͱI~/<wt׌^^zy뙰'm;T۷u7|=oKwT\߽yڦ3K67̙L)Ly>X{}׻NwPҚןU0瓟fVhE#6gqSpG[F;92s},40~*.5ϮQ;|!umc̞]ix۟N9S<=׊jp:6fr3sׂcȄjvpV;yW<jP,\ T#[NhcianH9 bd sE݅>@lAh~_? ɞ" vh/>!}CE:iu3tv=)\ ~F%a5p\HUsDUs5Ojuxnb#rWos}yDžr#'ڭ?}9edu^. ʾ똫(R [hFs>'&Kou7WW[1Ă;}߹{Onw~:>;кKx-YB 4Evjm܆5E싼:6;k6X+뢟OٰӪƮޗ#Kejyf\wmVaWB4|.LvB[K^Ǡ| : %B 8;PɃ6bвf^A0F ݄ӝ{5$,,yhb]`OYC7 a*U=fT&OLp.G(dXLfrT ;]ܮlyfyҮ_|r_{5nUr1r8R'Ww;vT.hJǏY7-z_x⃙9O':G[Opyn/~.;V֩QsW *L)=;mY˘%‹y~/݆gcjڔ?Hp޽띣S=V<j7O<.N*{9vl*s KR?[V>{fk)/ya048,X* G!$L,K޴o.hm )Vh_$㮦ӡY}%i؜a3'/ؾqޛ=wxŻv4tr?{3;)r87MٞyIYy umVNs03%o7''7 =_>^~^}}Å]~:9`{͏mt TI&eWP̶7JV?db'1#v51B՜ywym<ȕyc&/_,_=y諹)g,{˿[&Wx5C`^͵F9:8ZpU=ivlyª d9rU~R39S~;$?o+y(@ (ȫU(X-LP ʔF `K{,S%/טŒ.,L>ح}>7.[w8rr'+Cϯubhg#l=$vbk#[L=}Wٝ kϕ\o>*?'(wg{ǎ.O ;{?ndyʪqGG}uK. '2}+kM[2I?#/=.QvJ~!|Y/Sqp9^=sUX1N.3'wCW,8Wu{Oy@~͊Cuj nzݻ~\+R??+n:+^轁Cjέrٖuζ'aB; 9F>dSB0'ȇ01鬉7Y=W>ӇZ_Jb83XMpfI99[ؙ?)ʿjlUz>|؃9[ʇ{]}=/Խz#7fXluSUƣWšy+-^ܾ3rHn՞9B,z޺쇝&ttHX,nyZG:s#.h..NW:mϚUgmXk{_=r:aFʗWuwOwk2qi-,.?VX>KZccDfPWnU4v;n13KE^c'uVwF}xaȌ ls(ن On# {\}}-qȨBl(P%#E>8 +jmg\r,@!(gAXW@P8A$1-]dx Q()EY)AP\UjH7RQs rTmm"'+˔red`(S(d?L\yNE;ٽ&*O 12( @[ G| `⋅}p}Qi83>랟~6aUm&2*\}JK7le3;NL3kW9uh+G{u^VhWϏ䞷4ldȼ|,GqYx9v~j햇S.*?V0J8S|iRVh Ʈy+ߋ,˒Hy*{8W}Y77[uݚBS[j'/~TpLR;?lv , , , , , , , , , , , , , 2kR@QY tLUDm]d͍|SB0<4T)pBBE>"@'DPTHSn9HGm_'/V[̸1A(; HU`A۷aHŹ A<!A<00( ;#c,- _P(rTJL)PXۊ֋oZ}X>`?{epaC}`R尗ÑJ3M(5[P%EJ:`Rhj1^^Hs!m['{ F-s82>0~p8 nŖ읝Be"!lNM.9t)հH{MO1sw4% -v *S*8Q [[hP\,~7Z=zmX/R2l;|S'$z31, , , , Ěkqm=:3@883[1ČɈIOKTe buFXKohp5s'p8X}L2* וW):Dd|ʫ3q 5buf>&bҲN6 o{e6aZo,(:_QRGXG1 "N…cmX^&?&V_i ~HĒk+Y i"ާ!11Y1ccYz2 ܖGdگHӴ<P!Kחg _اCm4_&;G > '$|_F{F945;Hd|ikq;ށѮͷm!|qNۻboRj¾8;ibiQ} aТ 6ˍ'lzЙ7. >oDbW߽A߇60MM |垌a\N "|-/23a%|a>G7ٗѮ/wu%|3佌ބes4߻ gLxWӓ!IR^ yY4&|6 ya47dة=5+%| y)9Ð&|Մot_F?>ل~ "[D~~|> >_QoT4+Zߋe4ëhB2q\ :7ESM V4+|h 0e rG\ ]`ï]ՏmM Q+ڹ(W}Q+ؿA_<kZk'ZRR5Qc[ 8ޱv{ڋ5fM#r5H496w5Funx?b&7-w7Լϝ'XԴg]״ޭiIזy!ǂ&PMkTTZ[_;c]2?3?.0k{QDm8A7W51\b$nĺih^i `֌aS'>PԂ?9mE5\sfʭ"Iu>#tRBԓPtM73D5-Yfyyz SSM@7yG M&o$}:gpm>qQ\n&`R38Any>ҪɊ]( ctRQRm@ R\E)+!Q{LE"[r7| `9hP̯#ŵ<(fCuQ;@2Gq]F$$\ju\c%\ {&S@qe~5:ҟt׈"'9-!ϤӨd̟hJGx]<QTq ] .P.TݏUW6&-)(kZ)1 Q;IL-'q^%e >WbQ2o0yHH7j啽&^_|ȸRHmCfМ9B.r(t#2] 7r<@rF}A=njoT}9[*͓:z]o?@^8 ]y" xaBy? фj$Wl(G q f$P-pGCCM+m1*lP-3Y>f¤L#_z_+Q©'J{5Dm2Wp'#eڅD QXCeEs9n cБRpVpx9,[-CK٥#瀂0.gNN5891>b *DV?@1aX+JX5 a]0ۿQS(>,Qpa\(CҦlDSA8.Lo*GBTu=2Ph 1I]x̚5}fٵ1^c y}~H4a񃏁ڝ n 5j?}}%>?!$}. ͑`jbG8„V!*-;$iB9BՍii6F/M[jQ!:K]bRA-09D,ȎRC `aGڛ:#3 14`ڀv~̂u(`C nclȄ%6MzQt{mz`"K6>ypO7SlDdUdRxBb] n_(@u"UT<:8Eh"9uLT?B+bxn1/E^͊s~!^9cZ[~JbMcs7e'dyM}uu։굫Vf \HېpZڢ {n5O-?zQu~>%λ c$WAxjkvg Zd/=0Kdk4„VcyBtu+bF4h@P 4hpRT.0hM1 Mw-S_>莡+MQ@rr8kHKbM k@E41-̠Õ#5vB?3.3I\AxQ}L +(P_h0:}DvY59xENNE g`TBUG܌/[,46#ܷ#/zp:}09@w( 0yiooZ+GFCB'Dю_rG6 r]u^f }po#)Ԋ s;&zD\{I# "PeTXg@;p1;jFX<)ZOGX7[܉\Q^XY|nK| 64}B9"Xo}k>| a|^`#l/"y0r^࣋rf0%>o9~J B>xk* J{ fSMsț oݓySE{uQC&V_QK %J;Ԭ_DF<_ !yF䈿zA.~/ jDKH4!7D ;C )Ш|z^ԘXEq{a^'^ n''vB'z"O6xrl\J-9b`rSwӄ?}ݥߦғ= cnt)bR]J .=# o{rψZK 8O [)_# QM/-UH1JPI}xnETF7 nApf^ 2`?/:+)T44P۷o2z YQԒ7Fo8Ffͯ4h&9|YWÖPڌsK~m-jBUV̊_Y2pv~6C^wI"Ǧ?t|wY˅|5ws={/5?Uۇ@ec?BY0 |(Fv |&j! 9Yʴ "12ah cvߪ{7˺h]4 0P!~؁1>@5kA,ǸNReHkaw="[R; p+" RsVR?NV-ΩS93֮խbYt`zޣ(-\srAG؊ZlQzx2,;Uv:t@VQ`@;y퇰ٻvtZK㈬4~F$]5ȿx-{- ya&8t59]1ѰJtC^!hhYyAʆz~^rDw&rT>Xj:E 'hh'jG5YOj=39Xmb{7:qX- qX6@{lWo6;F͜6MGv۽1uRgqeVCt/r7_6WDoD^%:70Ǖj8-HiyZX\ +ږfVZm>H5 gY~GY(n-~R$X`U {=S`XDblGNXHh][s Wʖ07HeRF}l[oJ$̰KF[mi46O(#|[`ku'Mvi6h0hx.l XDtӊ2#HbL1hZ)l y @C{ybX?G,z <^8 O%Eǎ {G^GG*t?gtFs#2_Ek~o-t:t}t1?Azt/Ïc7xѝBwtwBwgtwA6;+wF9= Z {uuspK c` ~ع>ܑcWa ؜0&NvF03m:[ c9%0Y!1x6Ͽ%Xe˜ Q[cji;al(}ciw` ~;ocs1i0G$-ƠJeY(?#M ۠'=0Ā퇱H0vN ca=[ cj[c`CDŽ퇱A0cca, 2`LcE06VX,Yv(]XێڏjcC0 y { cO2ڻ0n˜]1Bq!îdN^d`]H{dH! a;2@,2Րa|5PFӃoK2ɒ4) /QSjJQdgjG(#Wk!4EjJEo^@/. fiFY4yJT]TejĊ,ꀰֳ`'UkV˳rZ#T٩r4켬F${4g,Z!OB.ܟS嚸lOxSAA`! :.7M M,j.GJ'JMhhӔĸpAb4 11aH#gٺQq1Ѡ1Hd :2Ah0:V`YL9rUprQ'P0-e+d80?E,MI'Rs2dY5Ts<Ԝ>9סE.PCnBpIr<+ENAUZ`|@yBg,\r8r8x9f"2F~2Ai5FIL;ilS8.XU-&,WqYMDggy*4T=’!GND Q<㑑〄dYrY %-HxL" (A(|x;*gMK OXx:P?(GDبXT&SdOIg*5r ki† ${-*Ѹg,%MA5 z*p)p~@_ՕNnI&ɆڑI${Bۉ5v+A;ܙ ="EP@P@P@P@]p+V12 /M2KOȐ2lGɰa%X2C22"|2E2\MR ?$cz>/O&Û]}H $ P2%1d(#,2Aɰ ϑU2 ( ( (栵11C%b&M%I# څJ$F.IIKHU2bA Cs%Ɋ,\E,@rTH\!"I2j QR0,M\ ili:LᘥHՒ4U&r&S\}jT띪΃YTZ*OʒŏTJҲPZYn@Y M4KÍJ3KAiJxɤ i*}>]S3iu1}!]-͕KYM f_jLϕ(r6Vi0}Y҄ciԿLc ZfTit5]eO"ڐ,.U*r*";KAOCDV)nА x<3EY&>Y$U&ɧY6قM‡0$=cMAoK LS!\[2 ꫳT5Ne)hS o_@#t5"l 'rL ($j X.N!$@;rɄzCz >{':JU6ʂOg$QAh2#h.T)üHċlzM\OY$5ȫ5L r%!z婤J%P'n p% !c."Xg[cm5c}}m-m>Bbg6mg2MFIlv;8X8F?FA BC0Y4&ѝIM8?׽TxאIĿq'xIa$ y$$>㿓ӁGc|!ۇ`8ka9ߪmqI(H l?c2G`- C1."93z3H!wa#1α'x/K\${{:`\527+ x 1߯qx'-BnW P <O," |ik,= ?}nw[!p |mϴY_X;-c_ L=mYbE~E~> =gG,-ȷa0Z* |OZXԧd?Ls{_g8pX|M_8 á7\p 3b _B BN8\±p( p+ \PW08P7\pƃ >N .C{!H-4$ӽ|g3YYr8|f[3ߧ5ޡYm,vcaV_6^Vv\[-+{,͕]U۩fQ ΩAA'00Y)l{7`xƧխ͍qWcizcsijˢ߫6)݉a[b܏4:瑀`>.H o[kv+F7GEQkXBz5ռ[̤ݽŌ7[QIL^zoM^ {YK-B/Gkt֦iKW~=j슰Ck<\Ȼp9li[RI̟kj1I6 vLZr@P;}s'QYlv9mB $?^ҥoja D'͞:~_|_Rx;x{W{_=w/8ҥlX|r}}i։FA;F3fKښmi[H#i};־l짭hv334mek?q&g04”pt΢?Y͠tZOAlG2ϑkoHdڶ'r[CġV#JumpJWhs4i*ׁ1ڶtpJ;x\?@ ?ޘ|LP upVCupGҁʉWf7`΢h1&@}F|gO}`L;!hi/ =}JY +Wcwu=6+ɿTҕ.6ZWrdG}yfS_QA9uS}~8>u5m9׻z h]b[fI87;?8kz\)sF-Yχ~fms\G,#wflL]}Ή9nw5CBm?sxO L"}UBgrn3Po76dm qeĶȆLpfv`Hձh#V19|{n݋0]jE\W˼Bz55 z0=#MQ{{}oKzy2,To~~6,wEm%'vC#e jNMZ޺z[]ɪN"Kac)jNvR5 ɊGQ[=j?n?}r؊IY;8OOoVB~;,A\ꇝ{/MA;7?f; {v\iu%7k,O<7{_^+L!N]$;9χiw&W7N]ܷ|MⓞϢMɵp=| ڸ9\i [O?inr5ӹ:ng(Y)rMBI18\fo`h@Lɔ9ҔRy&98 x dq Y2A HZ> e6-fTIS4$S#5.`3W\3oţsyܘ=JJ,9ц |AW?'c.g UvwTT9x/Gmc?c5wz?rlu5ق_zzΎ_%O?~ޫ5 '2{჉5Tz򔊯tr)Ǘ m+'i*9#>I_k{4Kc:[Kȴ Y5eCƟUE(AK/ǭ^5@vVq?vG 1mښϦ|PsrU.ϯ{A}3'<(-V/xN?9~܇;p<.=YOwZ_7Jz療XqY{'>o!>uwU]By޽FwiĎ^ϙ~Z&J<()/SMk*{lF4dtܹ#i L?f2j7x /ݐV>ҝONQ%0˘Y1-@r4a}aLF ,3Ù?^yqpRT;Ec7-9!nڶ+9Km|qb?珎e]k妮*QwcDyi#ܮ:GZh>[ۏyn]iSȾ?{jJ@{:ZŎu;جxdt.;({jyC8712[X_&pY]\W+S^q%4zڟ.oy`aRpϢ5xhA2$?3CojϋƑg 䖘03m`1z%'$'61L, yz{#Ey{G$DpbŢ-vY;V,aKbtT"E3>$]^08E&U!RJ #!2F #1q>8w~hxRL\ ԌAΛ$ &yA *!?b">9!6{b;kFX0]4NJ17υ^v~PvW>~; ( ( ( ( ( ( ( ( ( ( ( ( (_2*O?_虙QxdsM7&oo|HԚlMr90C?=yn{:AH$ +8q%% R,#N'LfMnR^,f&X3nƗ*Pj|Mجl`mM yW `dhvq%/xAZ^JvY6[R-,,GQ} c&.IK\=Iy찼 WKKKj]T. "סPv# 466Pr]?Զ>]L%mLi!mk@ BN,^9\s-]Ό,6!m֨  %x^0AJ'Cx3vPwP: !]|lCjx$1.=qL$aM>bpg@$,1um uմC (#GX,]PM- sX?ZXW3 S<`X\׆g  \ma=74k苆OU;d><^&nH } oEmwt@~+4ƪd0daZx֘c>1ۊi a m1xv)c?IuvkY u< Ƃi06hdZ8] ?R$$ĉт68#A+KDѢPX`OE bA~t$.& QABI(> p?R =$I|Lp܏!(ab HNTQt>?Bf$͏?:&A4)"1D?0٠(X8QQsؘ84x|T<~jB?4.D@b(S\/^p}x``3`/ܹ\CQ9Y+P8Ͳs2)l%P "֘^9z]Y۱qMIM73&96EC%p`(~$R('khccV> Z ɷR^pQlxQ0tBA|Lb\5iP1тQLd?.ȵB (Q84E W ᱣgX!G},MiDKnӓ+ڣqeECZlIӪ5L&ٛo>7ONG$VQT BOG7ֻh8xWW4-s=dx o p8]$٘ ( ( ( (? ڷ2X&$ˈ _qbzNI\KS!no|>$˦+?Yh |>n/Y: ܖfĸU` C 1|>vG򡪠:~5!M{eZqjԳ)+J?AfzX)F& hG[RJ5WS%AF/>FǦh tSs ;\8t{'}fJvT̐{v]^zhYI5ߕHG{xye,!{r zGؽ)Vj>s]K:lNJv%mvWOB.=hse}glږ}vR%皚tzLMôӦ\>P** lj¼؅[암BIBX[o? ZRq8͝ikopV4;ܙt液8[H3t aJVrvb:sgџfit:' Ih6#ȵe$2mym!ց+exDǶpb\(s4i*ׁ1ڶtq9|nx<Ǐ77ȏ7c+;z5uPt29'^Jm;fI,Y4S9{ZZ8>}1]v+9dt^؇;HV{'x"SeNSDJWؼk]ɑW'2M}kD}O9]s__z遠wm=& trȺ~R+sWsKTݶd=2w;qd[ԎUۛ1u"9'_  ݷe=x⭪?-j2U A#hk ˹[@4Z \j6-=N\[V[Sv  B".n0ف#W¢_ [98=`v/+vs_=N/ id n$zrl4F흗GЋQ,E ?h啢ʰv4RI\ɻۻ^Яݷ)8r؍W_#1Zr֎CH=ǟM.|a᤬1 /󱪳O֟_6e/'cu,wM}{n./:;}uUhvq_UxfznvyC}ZRұ6sޱΎrY#V)}/ qg1֒#4"p~>> GN =>=2ބbϺ/Fv^{695i{znuw':,c~h9Ix 3$+y0*GoP߫m_Ugc+'Ŧg<=i'[k_ԧsիvu4O L,t,Ks!Օ߬02>/~U~{X08=v _{LRğ;椻c>m\ݐ:A_t1sv5yOzN?6h$ע6ívY4hn, LpuRd64n#n?Cu[x@L\=Nf9;4i 5'0rNrGUQJUSs2j4%E`IG,,p%_*T%hL%〵L]P rf)o4sXJQ y&Xũ _=wp?V<=Ǎ9ܣ˲AmXрxzs2_ ~ߐ^ew_AE-qHor6:l]s~wi#^vYW[y-qn<.\bZ?]ip.cn>_Kլz?{&O:q;yvG4fYL[\6T8m[_ȎOrzAUdou_ëjlo{~+ڶ/l5'7_ʾ{d'?sσ2owO}8>2ۓtuQuîw)en}r -._wW%-k~Fu_Xhd΃Ȍk:d"hdACFgP9oȝk1V. pMk&{ i{au/4͟d\l E .G1odb8s9Uw>ߛNj,L53Zę=v3В▫Nm;0`2|񻞣g@k'&?|XfڵVnu?FD?'ښX>ߡwy:fҗLxώn3/O;OA*Y[+}eɏ:e-5lhVxZWy|ܢ]/`yue ;Gwb59*<{⳵׏,՝6<'UZ/͊ώGvKQ27yS/la|7ʮEu5Ϟs4r9L7wʚ%XSs룙z+bfn7<0) giYΠw!ony^An C=݆ v0:VQ£+NlbXqFHĊE  [q:6Bw*[ Y <L#s`f2Ef}H`p,MNC!*FC9adxRt&'/Z#&*5ÆbF t$a7 RP !ިPnUv:钽/ /cX#v_6B_:(= m.p}SO9mdo= wnzawf)GM>Dq))$׍n"Vy#7?\iᾆ ][%0=?ژ'*EO3M{Uϵ*ΐ[ɝ5e^15y=/=E0.!z5`>sg@fQ@P@P@P@P@P@P@P@P@P@P@P@P@P`2*O剿䙙QxdsM7Q%oM%ooc^r~~lj<0p}q P@Z#Uϥ4G&Mj&ߴq0_!Zx)+uX?`@∲d|N F.oYY9U//o𗜡HW3tg"CΑhQdʁ2}x;K9GIS^~2@ߒ7Z?@ \v귱[L hҔtk_ Z#-V$o%Vo/^VygdH3iR˔fv(hxu/ߢp}O@hx=w0EzSQ*Fn0cV'ߖԮż?6½'EIo#?xD xJUj]qP'"S{?oe_r5XslUπZn_/e,BvxCou?/`efj&vrf^!Hߜ.[fJVdy˲2 f4?Y%564͟mp09qukCD4y34b?o@ o95@&?6y3:C#,tkc) ^L S\;%{=|߹Ġw%1=[: e=y>ט|g> J u>\s9Y 3hNT3EKʜ,KY }zEbߍV^?ZG 5rU K|VPlD#9QMS-DBPNOJԆś@ld%ːx\|A [|zj9'0ol!3᭻~ @m?he}7y u^,p9k AuFI )q D(R϶8s7iJ$jM(d)Uэ8̈́EIJʊ<80f뗢֨C99 s.NȚmE^8\j[0hWOKc4=]gLHRMS\0SSL-qHy2״3cC3o0p=2uAfrvDQ5)ϕaM a:|H$GMqsy ,7g IZm %LhL PoB$G,.}ͅ5ǙBSY3$T CMc+4 .4 h ߙ MK,GK3׫%(iI+]r6N(o˾u wطPtՆޏ0qp#R4/GS&KV&h6TSFfY $E#XqGZcӟa\&,RMEA2{P!t*ˡ cC _=ۑPaKX־ A셽]m-, RZ 2{x%Ԟ^>I&#W`~- HK.|L ݝ zlES()8dxiR(O )Dtz!Caz1t,÷bOs.5PWXt5???/l#>]&<9XWdO͒gI8CohhŽpm# bL2Tu-j0QE&Ffp R2!l;CWBr(cA!"z)P2 -4Hf K qi>'Lzz\l4YDÚ ?e8#6:Wai12F b/MtbWlPI %$MD{שg,v^@hس>G ]Ԏ(/"'$سP%{Il9T^"kn +5#L%pI9Qrp=^P+a1’J ha ef 7gw\ouG| KW Kh ,v=ǘ:vM*p{u(v=/$n]̨4:$ U-V:Ťaq407&@Ih+ } "fBsŪ Ja4ܟZ-Ձ,ɬT} c[R1 >5ѷƢfO"EgD2@хVEWDgEsLD3v0ߘHp=dQxu@zwL;irHBw4!,sN 3?mik$[ʬUNViZ>Y[/iе%Ёܛ]|ģOyWĥpjf_N ѵ? t+DmO㉩4J,TIs-̿}h cv]L2Dw~Fc2z@M9eYze80v(@aU}q`E,&6Dzn+dq`|FcILC .!/L4Xrq+Sy+#sq@j}Al']oGS ]29 :;W \mŋR]*λrt@``eڂ,R7A1X 01!y u6?%4} 3Q6#\I_?ȕM/$VL 9#0)&o4$Lsaz~ 1-02L a3-52]1-mifZmdڈV74372`0B1fEL{LiO3L1Sc9ȴ3U5Ln频i f badc0mL:#G遑i)fz ؊&bfZ´u#xh8j6?h+<UZM+$QYDlrmLP6ZT6Y_gq`q@}~@Gxߤ~}lA>qycɁ7]W~Zt@Ik0)Ls Z|<ӊ`JDBUD<<0ѽ 1L&db2BoC Ux2Ǻ 5ejðt҆*ዽMIךG!ν30UpvÍSin9*(k 7SbՄeÖ=eYy\˸KX Kw̬":3ff$.tf^/\O2_ -ՉKA`euq'/Q=M;NCwA6u>Ȩ:tX8f*e1*t@3oQQvYu(Ur] EK#ܝ7ګd[8Kf_7T68??)$ث'Jfg=*]ߡVt;wGaYvZw2DD?DxW$; MݡwiXhQ S;{BӅ_4.zxF a1(dcU9݊mT68]x[/?B[w#=ۭ-rMdxvk.7sIk%]ܯ5ɣ.^0˙rfp[ors[I* ʛtrB.[ޤoCئZwqxdn5Zwﶶŗlmŧm}՚_btqMl5s\v-a8E6qo\|ӷwWl6)YK]3 ̫q=niCL$Mcz̕d-t*ɝY,Co >Zd&hIbWg#_k}-9h%Q%ڂG~^1}d~^X2>X /\'ϑp^& #DحSI~OvC}lgSJ}}Oǟת?+o+ (oǗ<'u0{8LJ,j;ww/7{3{m/޴fWui3*jgR=kK_{_󬚊zFRgmyßy+XyQ[U2Bޗr*n#ψ*eV[<#WOv*~a?=j**QM39G챩=2ZۿJd*>GRn{UTݶTn{Tj*iIW◨'햩%RK{Mm0vSqE-x.?-Ww*'H=>OTq.Q줙@n2?˦%S;U|KD Սũ]3٥Tplcq&5%XN;)*7g,](0c ;3osoڝ.u"Rs w"VG_F=h 4H⢬%JeRV;ʼnzSX-Q(ذ/xS$w B5mo^$;hV[HglUSq[mxﭢ$$hBn7T|*~9"w7-ܢ--T|{T5߶YRORT?{RlE߷O1˩xfQ3UMXoj\c6*?Qtf5٦O,xFɠ lSoU\,OU"3IRUMMT|&{T&5?ARzlxU?7Tx V*^$g*FE _AT񂍢xV* ɮఊn"ݽAMWoYD$fBGl6T*^quΌ"?=!'UOROأPSK* [*^LU< SJŋE~\xBU|㢊xVUurX3S[TEofpBgT*N"ӖkUӔzIůSWKRRMQYT5\gKKwZ'S)kTDTq]r/]UDUZQkcpnUŻբ_vx.*үרx*~`WL\Pklx_-V_w(P7u-535XTvXX#H]jQ-2ّj3k'DlE2/׊aբn[tSĵ.7ufCfejlgWS`* źU@j =R&T˷S;f?\X; +cy=>)+^nXPr.&"6onU]Rw(_pe$|Wv,0U4#ӣVqVqD^ 3/cɉc?D$Xֺ$+muN:DT=Jv%#iso EJȬP ԒԿף;nѦgA.>`%|p#`eG&@7tR-B¶:*3ni[?\NߪofW-?-ODϺSW' K[~Gٝ^gC΀DNPX7t݅g"4#zȮU~LW;_}UV v_n>f[6s%>0U 4+f<e8N ]) sXA0SYoDMrl䃆H`HXG8Z@0 Fc ed>B8=f5yt$c$}֊ۖ|b&iFhR7`ok?>lab[zRzY%}RBdy= DOFcji>xEe2/Ń`?KA$l9wgɁC7i T+$[hO_6E#^mys(1mE LW&F~_Y)ZH;e9mA)(YH\O[U+|e]bm̫+"9#݋;*xza  > }3Q7:),Yh鴌 -_w|,s D:1!˩ tX ]~ױ 9O4 2]^ Au`%vwl`yZD]O-@>n35lxoe6F'Mih۩/3._&Qe }:+~mHf9EFyD}u/ ttTPMU]Q93J[P ^S9c锇JFͱ t|x,4A}+d  Dxf1Aj ,}-QHbrisk)cbkp|޹$$87`yǖOl ӉAy4g4+0)ӓ?rmLȵ)ci~j{,gV \cK`X%&f_ ÷E-Ti) ȅÿⷺU[]a[݀\wtܷ.a²I%%z+G]@/=N*tRQ@ hR{Ԛ hRY& 9X"wK8Q%貔%K4] '> c7,ef(x+e(+P!&"ԗs:,PU@U#T@PK:m_&1*A9 dRJZm;Җf4zjx, 3t`1NsC4#s|7WAkՒf:q1_>??}h+C3 S# iQ`v-sq2.0FM2 OW@ *?cĺ_@m%fm.yY_Y=_v懚|"5v 9t" pgNGheV{J DIi V́v9 DTMi |{}Dߐ+}hʹh{mwO&A\g\jS Q՚.XZo7Cs8f#MFps.3ᦨ|_XS5T5g[!zkdYφGN*TWʥ+?LYhk'Xz5W _18c'jzkPC;:B#@ B)B.|fuP:<B" v`UBhm5\ S?ZߞX\~Y]op6<,)OMIѦۖlN7ȇD!h@xL@JsE]H/‹6ni{`qO!lc7AOޛMGgsI))rlAclֹk/> 2PĆ6zoF--"ݗB4xE{=_'F|x(pa)L,6;`#Qi}d`oH1x`3 A‰\2DYoYvh~ڊecY"%2a`zm WH5VT%|2lg *5fYk[Ё7xu;71pBg2?[%V,q9K`_Oƣ> [nCUğŦ- TF9PC3K ƜЗH}YcTXe*T' cߣQxݩY@ Pe!,h#l% ,\ȋ2z L{^tUg DE7DWV/R˚S\nS!2r/_t=K`/e@v__tY"A/?̠";VE7TE 螘N39PapT^EwtkH㲌OSWqJW3UnC*C-/ߓI*nKůSMuⅩV*~]T7TIUVCR_*&W+)vTH"ToSE7L>HU6U|gLۤlXMd9Sei:"UuE3՞[ɯJ;V泌hgYaIy h`?$/C y|KCS_Xli)n=kߙGꓑlWPXgST'Ş:D'#δQgoδ6TF3e2 FG[i;U@Qݗ@3喚3Δv)Yn:Z% K3 ǖs'hRKf2=CUF131 R̰!3*xIGa?dd'aa 76 hrA4aqNΡϡ02'iHE<%P޽vz5#PH&%+dUCG6t3veҨy-IYdK篓[-$J@$5\ 5E|~Kg4MAtN[:LN_bKg$;Ƹj0LE ^3WH*Ҩt(*J5"cQsO8״@eU4sb>|>oOC];^zl`'|Mdv:>tv)x-XPq0+7Yh?iRz6w) '%HCȕ#p%"P[u:S9u3Ъ?qʡ/'H*K0"%P%@ J-@[&P5EZ{WDHRxIgp8sʰ6i(o a%V&NqJ!>&@{tKZXu99RƵR-'$eL[ڲd̢ı4mۥ$CZDge: K'dZy9K9Z[^nrY'%/?,Z4%yeUA^A^Co]FZZYf4i {_oK̎uىV~#c6zvcfvK-80m+gvl}̗0{Ut{}l'lMƬ&E R0VDW{ f*xcdѶ<5V0y?k ^&<}?6زKpStwS"?ŃZsvO \*"2:7DԹv.πo f1CJPuHQs]5)ƿSȠ#t(g NL&3S 㭙ltU{OT[0=᭍^R?D5@w4:T6&OisOc'jS3r5aUkV$##-G& .7 u@LmQg282]AQAdS$;r t[֛;x?:zt`с¹e ʋX)p#ߠu#t<"NLcIsуUJ"?p"} '#!!2C3鸁'^2 $~3 6 'LDQ㤲n#`.)A}uq}_KGĠݖZ粎Eq+C"GH32cN&YZ7- ˟b_Eh?:ifO46Ħ l֚L %}>@S8T /\"ƈvGYEtcD;1F#ZuX 1фLUVvFvʚ({G n &ϣ %ő(D/ ~B5~$5EO3~X_GUw=ϕE]FƝ,?; Sh8[%VhSBB B^ !﮶kպRa JW &(!NBH!~M/X &|Q1fGb*MAtS0"v 6U,kϣ\o.DE{ HmDeX',&p=C0fh][ep-V|4g#i3DDӮ-;ZٵY-Ҁ TVtma-cߵyn0˩(g_faFӆ }|Io}?!fr}Z0‘1J,ٌ( L"O颣O(ybyFgҜM_OEdsQ/E\NH.pI64b e}lLy,dב|fͤl e@\6%>[ gZƣ@4TV;tTV a"V0f9 _ÙAp軧0˛Dk ^ZR Y9o6eCӥS;r/_DK{K?XZNaһ'_J8AK# ⻧t|cYs:)uR0 :B텡4|Y:I19wO19wO9Xd6kfq",US%&.ࡵ>BJ+#-鄖-eǵmj>jzo4&Gyښ^t͇bR ФZZ!(Z+p;KPS+NTpP a;T! %ԮD̎ J%ֿC%"pP~K X} N r*/ #8j}PӃօ% "T!Qo,ADt-)pO#}FdDj3PZks6,MRꟼXOL=YA`YhxTt`i.k*z{_e?D@ʖWR(Zl eQ:Nj熳My 2|*耹ҁ4|0~d۬1W)P*:2.kc f2EYM^#TGVoE{2Td{C53絑Q@Wz3 Ѧ+BdY =^,(B6) uz23THME8-!ӊ}v=x2]ĝ z )G:賟D KӽlոIIqYƥ PiX=T+O/0ZÉ s`KfP9|WH=e#Vu陞8膱gePYuk =&e JlF-sjdTP u~TP{X 8=TZ[ުwx7 c})3TFڤҵ;1Biaӹ|QOl5_5|oّeD?z3 bA (rU𱯛7AiLNG8Wk ZDS 2VO%d:&oUݥb?G@ wjc:],'#Un*d`ϑő9Bd:w5ܹ^ZFNDn 2CfȹnR2[7(?Yn\fK*%*֛ot~U]5*W`Wc+_(_Fyf%8puJ<6z? EMuB~ {kZޢ%$·(C؜}i]tvL::S?jŃj>^P٘샖C͚Tvr*?˃G3YI%{%Mԓ5ɋN$&˝ig|߿uQmq*$ۅ l4_EV}pJozq6*, um6|R}Xdp%X1J=ƕ.g2<`P'nIo\)ru'Mr`J7Ю-r,Q14W՝kNr)]M_mΊ}QeDs5J_#ɈOUz34d)|Cs>uVTY*cl -OA՟s}IAQ*h%?I8k:٪d2L){,oi#[X+$bDuTJ?d3ӹFodOS;*dUŤNyS"xvKRҷSOleۑ+o`- ^ ~T+=qOX5y b| A)v(G5N{t{cuFDI%{ ?XWvDc5z-ֺFݢ mf{ImUK C5oo *x+Mvw}(sTIN$1T>l52BTu*%*YAK~UI+XFL&G<~Vɕs*(͜$ Kׇ}p{7ikd)xL_%˱7e D۲ZfwKC_pxv^|PҙƹVk)A<]ym>Cdu!Aq}B/ͽDۦ<˅Ancg0pӚͣ8vl9.k8e2WVZ [?+n09?98xv j 醹ԍ#ʵȏm(+ΣMt/uc!Ŗd4Je'tڛ"sؿ802$htCДDgQ)'a~ 3UgJfͧCsCl Ѝ 7ϕ5=fHgD 5̲P Bo<]K7]slmQ Av6ZsTdXZ0$P ΡcZŽJBGXWMW?AaD$souF-Rs4Ԛj]UPw`!=]E/2sgO7W\mׁǗ#4^4 Rshas_͡3ᚧJk^N5x/j>.o沲CQk5/iPZiNCLҚu'qkqU+ieS  PkR[ϴ{kkIE-lM{$EZMG};%ɸskgޠ5UZ+mJaEJTO[aEN)@0ͽ|I%jsC]+GC^aӑpP:mo ,PGR5$`Q Kc^F,2{LUWd7Cg?M[0K잠y*{벲lԧiNU姵姴ZC_l]^E_@)Di8 #L,鐡=3m)M|KIojAK%Z4$Zhj5Z1 PXco/epUkiTJUHjڋR"JVf9+իL.L/82 cu0RqAd0ҳhFl`sdc nv~`Ax4e ގ>+{o`3 m"$ e!JzھWhZfyi]IIӮ^_$&Eξ2Ḿ,.a%SƨhmosFD4/o=CvpБ3&Vɨ 8B5Fќ`Y]BAy|A89o۹e¯fDiv7'5e؋4!-@ߜsjSn,4eZ')Fr鹦Moooh\K +$%]%9-$&Md;^m&zokFxfb _Ljhtj36⚉+e܌oL4'yf|{mګM ?/T}ğ Hp7^IJ:7+o*lESN ΍4̦l»MV % ۚLWs A""$ &nB@Dމ&eDޓM߄JfM#&Vׄސ&5!Βx*J$JAZkF2w' G5QSmpV(F7vPAOPQRxl~PF"/0y;gRc |.4KTG]<6Ziw ؟5M DRoA^Sj&_*䛅`a#Qef5EB#tf;[f}-_l@ŏĽ, W$Էzl_J[6`J ќ%XPm p>I/էi*[ 6xϭ0DԹ xRdžLD %^ZWHRo2U1YP{@(78W(i k{ߎ#[F0װ6 ;9lmHo ,?G"aiPO`bg-w]{)+xГdՉoDYY\_Pv12>_D"L8o#@e $m5L IyyE"Hlv.r.+'˻d)hoΜ{0&&G':걙#ҕ_]h}'aq~ Ulxn6Lv, $ՠ77,D]48$2LSϢIZ8e7*ԾCo8UQ"z4 !,ר0sOF1( bE=BIn]֑X~Wbe*xp*Roie0xOMb4b'&j45MES^djU)?C8KGQ-I{x6X͛`i, %Y~=@5]  j99>Tgs`ԢjbQo$| n4Kp4@*>dRRf6+z ST7un7l~&7~_G:in!@9r" >5ӓjrj BT;A+G֢cD|:3MliJ;@#M,jęfUkDWI6r:]\`5XL.|;T mK)ˌ謚p Sm%Umjh[2mKudԴֶjȴR ^*/RR+P1_kQbkHW,L@R-1_ݿWTzZ7EB ﺂ7U!}x:!?Q$K%!Lf ޫ.^"eBXC=[fh5LSU QVc{u)iusϯTʼn#4MH/k5bK*|GXCOroZbmXס!ц|\UR @YrO_MhoJx^Vaj<Ւmi’TSkՏ߫2 |VvFh$GT[Ma"0k& Yaj:xx/yy LSoE'Clu߮+*/IyWrhcf5rN%n?0a`­le~揹]9n9F%WdWq{2V#iۻ5_5_ukfk&u6_k.<|]+u%__7|݆;_wn|}_>|}__׃2__7(q|=_C|=| _|_Kz_ՂWg|_^z_;*$R)[R=C-.2/HAO%eCLK߇1A& >!nP `Ր.PB'<%AJA  E UPJ;B ZA B<-J8i2࠭LD&@$pz,BǼe;+ПK=G!0^P8uZ#RR6bZ!B`>/ JL!J'Cg.!i Uji@9ނP]}!9@- Rǖ}ZS&J /!4B 4B%Z  W!tB = !TBm! BZ  <Ah# &C]з|*C!B]!Bm!Ch!Bh B(@|ڠ|e g%̀ЇZ:!BhS B#!B!B B@!X@h"yNPkEA( B 4B 4B#fnFs0;sH]&EG3*63K٧NXc)جR W=֐6x}lxt1$ǦNN~0ր#S466-!Ei+idZ} 'fػBK2d iw?=."Ɣ" Ɇy H7v$ -6=Fx(䬤NvHn0D%gٓ2"=0/Cwu/!zlA Fg%s 6;"6U=J.UǧOOKO9#V#333', %aLQ!R)4gsmONL' ]L3Ӎ6 RAYcQOO: LODX68= ǻ&B ,&e&Lz:%dScfw ԧ{RĬX1 #--APQdeƦSqωOLϪCr3.6.ELEb n^\ c_2¢@$@2S!019-!0@ɜtf f`|1%3Y)z*Fݩu: GmBeSP JIfGq]A((K&ӉINzqhxDw`ngZe&Q=`hs`Gj$)՛aZ|rZbR6Hc)*u ̚-ӑu LЧ$ `vLcSRcS ybS__Y11QA|Q Ya\^O͜T#-8= qƏҩVD$@ XH<&D<&=4zBb 6edfrLQ|r )'ZxQqSqhFcQ;]!Lh/ts5Z=^7&2BhCpxR +.~tnj mI Ic.#jYH!Y@\HHhpF0~LH`2'(+MqBh*+kN $?Z|b|>GK%I7Uj 0 ^m ח3a Axnuf xQ;zWтxF @>%xK^]WrFQ ߃={߃={_ {zL}GzF3@}m $H2L]DnU.7ޕzE=}./U }JG齄#_-פފzE=}./U }JG齄#_{O w>އ8zޓ=2z_K[}7@E~ߧ_%! zO ={߃=WeV´00fTT!)3f~0z43f163AX;0a^JzlLa-93Sbbgħc!"ӟ{OGܣ xԐdJg`G)q]d3fó^gY@Yfz̘t朅Y1FFL>ƐO'$4؄y1\QI\լ$e{-=55= *k.M͜Id1=3}Dxqc+gi9c&Gi?Oƌ?$)R>ĥ(?%(N ΊbdŧH9YyY t\82 W"ueT^fcHuKOeY+=5.=)NJt4eqɳBYLjz!6׾yqPcb}~Z?5X=M7V $JY8U$'&EGxbObHpAN0GiSk3جKQ(ơ.!6"3 \ IXH|"}j $i(ޡ%>}E &Ȓ17x8EC87guhc9r $Ox lyY2T =jPVfLt4mfZ4k,@YD q'(,~"xZcT}j|<$f9>6&MY%CDtit酻Wm11!]h#|^s?t4{='}.I%r/0}_ٻg||{-?}s}?Y'?KUsM#38aoyo>y~U[_=櫎 7)=)\ZRZ/py |@[(|T! G8mz Aw¿v" T%nIa8()7RxA?MZC)nA J _?"e I`M@ ?7C)75S$Aፓ {>Jj5h}M%po όpXo8Z H W~5&A)LSiT^:{(J&7'|!p\7v>[S}aBM+ܟ‹Aamx p3)GṌ:/ '  lK>A' 9gm#SH댟C@/)\C_'p[ ߡp ?FH :NN1 vizʗg> Qg >"p![}B^NafeN hC>%8O@ I^`R/SU]k>NDi Wuy `.-Fm8kk]YGx\3M7)>~+/9>wo)>_r|> >~[o9>wƋ(>~?Ag0R)xJO*濫3_P_PM`{h f)lP|3|/9>> )>P|ۋu >gP`_?>S|KgP|ۋ?oR|ۋKUz`{m:sB~< l3WW`Dl>>g0g?(>~5j? f;;l>@((y-gl}3^3^|6oҀߤ7)g0_?0B?SA?SA/Q|3 |y3/)>g ?D>jOw+w+zjg0__gt`(l3(}l}3l=3/.agC '?)g ߢX>3W< l=p-l|)6fLl=^g0ÿg M |J**}`g̞ f)#2ã B(+fP|3a<3)>>N< b_*g*O fyſXIx}oP|̞۫.g0(E3`o ^g0S_B}O`?Aݘ3**3Ug07*oTٻR|3XX}f fĺ/03{Z\x|Fo#mc(mSmpMu4^ Is?{( x~L)ZoS/+ szV PpNSpު)"|RP7p5o9BwW8*\_QG L+ *PQqíp'* J? |]æ<\wV:So=~^gʪ d+wdU?dd+cc_c»ض[?#uXgX,V:W \ ﯕݼ}en ^6=z+rk{7w]OAW3W[/ " nmpöZ>wq؋ֶ]f+tSY|c{7oػՆǫʇRUߕ92Wѵ㪘IcU1N4d d;=U( ;4  lUa;ql%.ۤKl%]l%Hmᨷ_hd?=*YTP***Nla; Њ'\EvȅTV3TVG]期&J6ɸKZd.9'*ij6ȎFq ]zG j=)ðUbR>s1bҲ(?dq# >籅S-& 1tw2>IqHe|9zE@L*?&9&[7|.1xY,%`)>Q4 ^,9! H )h`KO &q䔄`%tC:M>a^FR0֗`R.$ /&a&a&a&a&a&a&a&a7&a̺9'91NvJEܩk~>%8hHsI3^uҥGpGUt#$0]t3$$K׮!!].n/ʟJ&W%KL /G%ef 7Vp 2yԪcѬYTz|!=.ui %gλKzxjgqmfٝ^gd IMκAokn>0{F'CA 2]acPaUNFQq$T"sB9A381+3MbSЈNM_7Hԧnv%i^<ҾM-ovc&(Ɍw?]`=*)h<jsHn=P7UA;5 h׵kמ]B{*߭{ϐ?OJNC#$}p!:t(ghT;*RC':v>19E9)UAcGA^qczp3h9Jc陞H41Yh ]!egblQHser掛|\ ΃DAVFJs\E}}`^s s Ϟ ,(>}dubnU7:a_q8c_qC)9j_qEl n}% 1+{yTNj#iuā<8Gsun{K6ӱ"ճg9nqW8aq#8hq3שfqEę] tt2Q,"#ju"2QW-"UK;nq/Iճs7um}Opf F<Y(qgA8jq!ImrE<؝33w"XN,&rosw"r7:ZDB=#9G-"Q"-"":YDAq ;bqkEĹ읶 7tlXDIsE D][ 1{yTNj-"iEā<8Gsuf{Kq"Su%U%:E\e%F\u 8\8E; ?pQ!uZF\,&ufrOY\N ˉzK{ÆSKvI͸O律a[[HydN{-*M\؟cvua?{֕RrM_u[Hۊg6|u!G-+cWuѮ^$Uţ[ѫ;:hQ6uٜ\x^ NRn{dwWqAr/H~auu*^7uu$S'bKWuֶq/7tu${W-'5tQ58EqÉKd7D ÉK1?NaYAP'*8"l2أ3J\GQls/mgrs%1\M4 *! G7@QxR]UN22S}~:S߮' K'$ж؇8 ~8y{`2NA 0/Ğ "NTqb 'zq T. EPHBQׅCE_qI k)8RJk%N|6bxDq7Ȼ8 W/NH1 )&8!' D#bi'O'ĉ'K\m@=$owqR7 _PR[JJiBL9> =/?҄ %?K`KpqHr?U [r(ՓI_`#`K;7t< FDEaP ׍ Bڪ *F<Ӈ Z}Yk h-<];QnDDw"RhzO/ " 43Bm}@'`)&ԃϏB JU$F B}$$:'AP95$Qu]8T$Z%+萂+L43v_jz )WO&y!q<]bRqB)NA4 &NHmqhqĉ'K\m@=$oq NWRLq֧҃h>K'ak@?$O}y{DT$O}d߳dqS_!8S_a1ͧB⨈.*u-|P?tHaʼnO}@̧\mPaS_*N<k9fLj 1 ̙9x5tl87{ޢs tk`ၓ6 ֪"1:U|c @j{"&2gU/> ȪB dj,#YU`2aU*V5ȪXj:y +9w1yiUU%U!塭jM 3рۤ|jHi%TV5 Ԫ VD$U3*l DƬ*C?ajh3Vbp3W:̪Qx lU@Q84eUdP Q;UE!mf-H#qqqV7 찬 Ԫ VD$U3*l DƬ*C?ajh3Vbp3W:̪Qx lU@Q84eUdP Q;UE!mf-H#qqqV7 찬VG0ȪMM% V|jUIJ"ZU ȪpV"cVơ0V5P DALY18+fU(תBZUĪVtUm!ȘU%q'U mƪQSV pJYU R*ȠU5 ǣ* jU8eO TBePJTШGe,R@pld*N ۧF&T7+*UǪAZU ƪRVdUm!ȜUq'U mȪP SVrJYU R*ȤU5 ǣƬ* kU8n;@tj^U^ƪBZUĪVtUm!ȘU%q'U mƪQSV pJYU R*ȠU5 ǣ* jU8VG0ȪMM% V͵PVD$U%*gU,`[ 2fUIl cUE@Ĕҁ`V£T`J2hU()J'ZU0* ɘl3Vn@ ͼČ a`deUan;@tj^Usj U%@*kUI( JgYU YU~X@f*1egt U(تҁ ZUpN [e[Y.0DA.ѥ㰺{.H [Kӥytp.4 Rե$.#t)+@t) A/Atid#HbhpT:JIX KU]_RC}!Rq]=Kt@Y1]KG K u) KIP]J"R:LP"dJDJ6K$)7It)EcNecQKCԥ`CR)fBad1Vw}VK! ~PKAt8. ҥ>{~dti^.v{E9]Kt]JR" B"@ 3Ơ4`] %!NQ4I*K$,ԥS0Zѥ0.Ӱ(V̈4S|H#Ƿʼ˷(] b/:]'K!u\.~# 6K= @ti]K)]JR Hpt cƠ04H]#AN!4I*Kq$,֥d$Zҥd0.Ұ(\4#|`#Ƿʼ˷@]`/:,]9K=ǁu\.# 6K! t)[,ڕQћR>'IX$)GJ23l)+?L2(W7J3(s/zhĊ({%2\|h:4\ ۅFB2ыPƠ0F4H%#ALJ!4)fEq$,db$ZRd0Ұ(܎3#|`#Ƿʼ˷@I`/:,O9#J=ǁM\*w# 6gK!@ti5]K)]JR Hpt cƠ04H]#AN!4I*Kq$,֥d$Zҥd0.Ұ(\4#|`#Ƿʼ˷@]`/:,]9K=ǁu\.# 6K!u˙\]Kt]JR" B"@ 3Ơ4`] %!NQ4I*K$,ԥS0Zѥ0.Ӱ(V̈4S|H#Ƿʼ˷(] b/:]'K!u\.~# 6K= @tp64 TR ե.%#t),@t)A/atid3GBhT2LHX K<uI64K`P]aQ8.iF:- Foyחoe}_uXsFzRϹ(]/o-=GlNC@ҊJ.4 Rե$.#t)+@t) A/Atid#HbhpT:JIX KR5rRcTUF>NelS\*ˤr|<*/͢r*[ˠ)w}z8Eu)sArli4di3 ]FmL# |iϝ}|ngpW?~FwGwC?yn~>7󺗟ۭ~#?y.~~7spp >ܼonoۏ}7r~3bK)_򍐥|+CU)'R: yLiR Y}oG8R`F K!?8EQ_{uQ,"(Cb73j09<%f]\eQB=!Pi9 +C=ǂ\<U1AejB˞ueOGPnwP>wBQ6wIRfwy`V]Nu2(FeTTew=]Ō.PY>U]_JR&w9:,O]4}eTw{6gKø˞MQc-l{>s|nz6ֳٍlgu[=TzԳ g~;ap7ar3={YJNz73mEMC-A ?ʸ@$HJ@PԅH02$41(Q `RMN<(+ $aQ'FXҐ!(EvEdʝ*PY>U]_IRC}!yRqQ=kJT@Y1[K@$H]J@RTH0ӥҥ$4ѥR `vMR<(] $aQ'.ӥFXҐ.!u)EкEdJPY>U]_RC}!Rq]=Kt@Y1]KGK u) KIP]J"R:LP"dJDJ6K$)7It)EcNecQKCԥ`CR)fBad1Vw}VK! ~PKAt8. ҥ>{~dti^..- |+%T)`JQ !@MJ$4`0ޑBA3R h^R("(ǐ5ơ&( F08 #Pa-1-+Ȉ" xCIP?i@'B}ar͈P샒@MheOЈḋ2.(#$I)ﲇ(ﲇpA1| uIĮb[e[Y$]t˓]4w|`swً .4RRU)%D)k<4),>H F)0#d Łp(VqQh iȍj ájh1 2ěaYF..۲(!򞀏t4 cA._Hz*טG<>m4( ԄFiT F!8F1@|(O 1<>mKrQ̊Q :?mǩP7FD*f̝qѰY>U]_JR6JH F)0#d Łp(VqQh iȍj ájh1 2ěaYF..۲(!򞀏t4 cA._Hz*טGC|R  % T( BI$JGP VLP^@F(0)&t֋ỷQl,jiHnLâph;"2aZ(,F*/$)!<8(5sAg YzϏ,ؘ-͋ѥ $P]JR VRH@ӥtӥ4ѥAR bv NR<0]#aQ'.%ԥ&XҔ.%Au)EDdL0Y>U]_RC}aRq]9K=t@Y9]Kogrqi0,])-Ji S R "xhRY} 8R$yF AK8AP$f8҈p(CհbdƘCjp9<%f]\eEQ B=ϡPi# )C}B\<U!A|K}@ {X7#p6wCP.VcD|_=1)ee(Nu2(FYm=SQn7U̘;c!1}|̻|+ ,ž́ay0Oؔ=2olΖ.{.$P]]D..{NdLr> F2JӥGpA].{8Bu)D*fL>$Foyחoe]dKy8. .{߁xk]~0K u) KIP]J"R:LP"dJDJ6K$)7It)EcNecQKCԥ`CR)fBad1Vw}VK! ~PKAt8. ҥ>{~dti^.bK e)%J)PUJR2LIcJRȢ#$ lđ@3R n^JA R"a(ǜ5ơ( F0 SVa-1-+Έ"" xIzNPiX9Br|GFnB#W|\(Ȇӡ}(#!Dy9QnREyQbeFyQ~rG?zR"H9HR.& ٓ,J2Ҩ]id- EeK@u)K)X]J!R2NQ"dLRFI6Kq$)8I%t)EcPdcQKS եXR1f`d1Vw}VK ~PK=at8.ҥs~dti>.E"ARBDѥt.`E Ȕ.%1%. lDIS nJAR :au)ǜ.5Ƣt) K4, ֥("S" Vb2,NB IzRqX]=K}­ȂҼ]Z]E"ARBDѥt.`E Ȕ.%1%. lDIS nJAR :au)ǜ.5Ƣt) K4, ֥("S" Vb2,NB IzRqX]=K}­ȂҼ]:- |+CU)cJ0QJ'@:)MJ! 4HGH!0y)%Hq գdsv$Brd.pZL3#xXm"ǶĬ˶8#@'9$9 bC=aeX 75&B=h<ݕ򁪔0(E nj&EGI,؀#Eg ԼHEBQ);jC!QNa8T +Fa@f!<6 c[be[V D>Ґ2G,ąIQ j(BIJ"P ȈpN6~"c^ơ0n4P; DALP18*H( VG֪YUp dcV5?ĪV`cU@*bUIXJBYU:ΪX@d̪8ƪ6cU()+8s*GVdЪQNSVN`[U1fB1yhU! z˪zXUy`=eU}&ݦwYռ cU@jJ?R>Pd̦8@(T$i*R<*RpAST| 5>BFĮbƬa0}|̻|+ L>9ȁaYp?6{ؙ>2LlΗê@(PaJ"SVP@Δ΀Ӧ$6͘S bX@0y DQ*>FxӔAA*Gd̯kP y@ƅf^bT00ҩ0>{XzFUx dsR5/ªV bU *aUiPJCXU̪"XAdʪ8Ī6bU()+7s*GVdΪQNCV@hC[U)f1ygU1 zɪȃXUyX#dU&ݦ蒍Y Z X@(PJ"XU֪P@V΀-$6XU bʊ\@0 DQ*UFxӔUA*GVdL+P y@ƅf^bZU00ò0V{تzFYUx dsV5/Īsj U%@*kUI( JgYU YU~X@f*1egt U(تҁ ZUp VG֪YUp dcV5?ĪVPVD$U%*gU,`[ 2fUIl cUE@Ĕҁ`V£T`J2hU()J'ZU0* ɘl3Vn@ ͼČ a`deUan;@tj^UZƪBZUĪVtUm!ȘU%q'U mƪQSV pJYU R*ȠU5 ǣ* jU8NdNR8H6dNq(*9c%)G dҟQNcLUXKT9f€1yR zMzTyh9fT%0K6(U1 0.N5ҨR>K%L*<,*,> F)05d9Łp(֚q9Sh iȗ ájhS 2όaZF..۲(!򞀏琬45cA>_Iz*ט G#܌iBIJP F`6U} S>Ơ F4P% $LJ14)eE$,tsb(ZRt0Ӱ(ڎL33|X #Ƿʼ˷8I a/:$O="JaM\*w# 6fK"غ4v[?vյ 73-4lXuuW+ʡUeCUWUJzE  bhvuxܽqO/>9rZUuWUVVdտQ{nSΝ˚e3޷lbW/mf`k_Ĉװ.~w֯ybO9?aↅy3ڌy^o4/O3fyzơ_> pW6lh0~|?_ʬWTv/tr׫ڍ?^DNgϻ> VqdƏ<9۳K~#>u9?^\0h-ίj5\8ofeU(?̙/zؑa Z}O>v#GGO㿿]AUy뿺?KeW9G ̾榛n@UG*+*Î\OrixdHMcì%#go6~А݅ sո˚fkojUKѦ~kf.x. &-09 `U vzihwݡ7 ݮ`d4~Y/ok3kK۹giyͿPx5.9DKf]pl̅5m>!޵ιio8~V QK⑳Ӽ9~qn.0#ɝyK4Mf6!C_4"Z<Vz.o'U=qx_n!ϱ>vב^pܙ!'=j=k.: /ks[0Sx]l}%`g=Vdq{9ӧ.y5L]а1K] eogiwv}v͢Egz}6eTzj/`Zglg\euxn'W_WF1["WHAh7gCAlsXX6~Xffl_WqD;G>!]WbY E]w]vC&Xg.zkw 1}a@ |o٬bXx+]O񼂎Kn^0ss]O 7~^.d=MOoI//8D9sϑ#?G~9sȏ5󯆂o]2)LĢ'il}A,f]\W+?4ُě*rʎbq@2q25W\^s%k/&Yiwƞ^o~&ז}ي*lS<.)r~~zfxD-^zI[|eU5WL@CĨ")ٱW?62 V+/If R&}Ƃ׵W7k7u-9?`[أr%Xک_Z%Y-ۖ:>i2X5%cO$ڴ+!x4>Kizn}{]S-:--^j#ŏutѩ9-su?LJbnopJWgZ8^Hx<֪cu۪R-xQ[nݢnqTo;-[j1i1WjS-wZ\[-J[l-N>?բӢn^E}śoUmO:-?-oLitT۝-tVZ\崘[L-ߩ#guߥZ8-[ -fM=nNuIXnņZsZ-v|!բiQ[[ܷ1tūEbSE(bnqS-oxgj7b?R-rZ<[<[bO?-[ bAݢKW;-lI8i1JX[ܰ-ʼnR{->Z,-z-:-[|]T;-VSuZ{E)*Ԣ҇{rX,4B6Vk͹J.$X8?>v$ _v/Ї.Q7%}Kj뒣޽VQ#.Y*2>m []b{|гG8p@NYoy~Z;ǸVbJc}'w"+x}A7&'6uŭ}eɩc]bO?ֺ\L٤ڵ? Rk?I< V-=gȾnz]<ٱݵpk8iUjOmzjWM㝊XQQ N.Z^<ܴj45yF;y^~=:׼hهjſ˟'+n=A~zxxx^b/^^|xXQQqǫ.?~{ {ԋooҋo?g/>^w{o1V{⾙?er_n/y&{Z<^<^|n}zl{ ŢEK:22J/]֊'iR^qhm=.#{VE"=n:X>3$OoL(?ڵe+b^8]kԘ-=޴sѷ'4qtjMNQh$Qxkv|B1 eOfT!xeljUWnh6Y?ZهVX;YqGlj@uޤڐo%^TaܥVԎ\m\o7L4knk~.UTA,׎`}9ƞɏ>;Eƨ[ΎNWr닚wMV{?w]`[{FI֧[KevcK.1sSmU GjS4w>3jvO8zlCOԃ[OT#1:A>Պ%Y}hE=u]]s>m=>:aũCfY ¢?[g4ytm]lD׍œa5bt0)Vkj^ 6 ==g=Ĩɕ8l׮iP77Ca] j=r֜Ck<ʇ9ɪgj<ݼy!`F9(ROVڪ;qчn o65>ѿuSuB 'k{팗³LtwϱnkȂ؅VuYR9ʩ∬xϒ}#)c8"h¦Y_JB.YαK%~/<'VjU>=İ-+j1WԘUmHOiӍDOSM '8W#To6\sŭ&}]Ů ͱE!)ym+._8*qeqd:ĕpUd}nWr{~cd!WVSZV,T HuA3 =>"GЁa* Z3"Iexs@ٚ2rf;F3cRC b}F8%JUiE=~ꗌD:K=j;&V>oz8kO*puo:6"}K-'{C?&X=ٝԢ Ͳ<(/Yr]O-mRݴFĊP3QVjJn/0w<"_zlirmϕj_rT]h^O4I4lh^*IJy]9Rtgk7篝TQĺ$ؔn ^PXma j{&ŇNv%C=}k"NF[3nK|f%vizP=eKvTjSNwrN3 Q qoh(yYWQ"S )i/ljTBUw36hTS׾Y<糩}hﮈb CMPsSJ27dWNIjSήtäJflʙRhU:4*ev\)3:檜6a":6  )ؔ^7,sS>L甥6NY<[N)̹)]tE wm#*d226#6wXWWXWH _gY3$ YWB)S!8!?tLfI\!\!w*W䌐rLv)OLv.s_Di!sLs+d+d%_/w:feՕg~GX]*TR9U\s꘽NLt2fA2ġG:&5q֖e$˫ɹ,S$sg,39WNYTsO.F=wLY5$g,'!2iJ*(]$=0$QKQMCrlorMEQȨ5jH:1Fv9TROtOF8FzpqD%Qd}5kp88FIIʤ7jY6rlTZDTq2a5}[5b]k8+]\QblgNyepK..wH =9usx=_xcrsH+O6~:RnlL.m-k-8]=%u匿So*Z*9#k߾Y"oqQ7VU3=eou =o{@\E<m'_֢㘜U'Nn%/խb& ߋnhc^ tNY[uxK}FB6iYIuϭTyڷ$ΓqDNWgfؙ4I̧gN"A#;axH3<{qΨhΨډ6;LyKѲz/F:'*AѯɥQ_SWXrYRO2UG=j5o(j(X)φҬiɃɻh$$UUTM\GK|.6UL7.;b;+#eĦxѹJ+J}@ U8`5TcFV>kU_&߱Q=~9zHM2jxbwN:}$%,~YXtAj0M,Dow6+^.N2[#GUrf)[KykݮrwZNjx+tΒ+.V4ꑫ3ΉO>'2Pv.U5wgR藱-. nT/fU$nPbׯU*ps{8ZZ*/躜,w+. 1~G|z˔ f'-OגV3*ƽk}@$FZUsE`me˭vf4N5]uT.c=V7U5VL.|X]9T_4e. HҏYl/͞oOSoJZ;صa}2gk6[4}QMQL>ķioVSq+įz[z.uU0ǺT8 YTRgr(xX,g{{Պ^Qs1}hWRtC,'-CQO :U k u^Vo7-3!5h0pXC_WSoPO{W۫P^Rq9%sΔ9-VIgwq8Ӧͻ|oԫb[r>LU\f`\>Lq\C>z.[C2#<*b.L{.${sw\fQ[5TLa\Fx^ώ9D'G!zN{q}5{W6cKzgOm{;upӹĄ{NJ/tCXONz[]x꩙ody.^Kk3Kkk% ~Kݫ^}]b}tė'#J]}uò'lKGD͟^r|i*=a5N(c۾ղAC:Sֻc+N>rfD+"6E:bl#~" "6#5: -qVXw}Tsҹ$}T9S^:_?>2K3lOWē(Сza{o]5]ʟ~y*QEvg (ژj_=**1TǫNVM kEuX4y֒'_R8xgMWz#?EKԢrMr'uMKuMıoPq~8iɦXMRȽZ>}PΐjTWu UeڎbKoE?lKLn'Fgb_k7>GBJwu_IƩ;%ǖ_xrg4{gqz7}^9jss< ,;D]vV[}e=VKYg^T;uﵯi@vEMǏO}.hs 'g^teF_S(ǫ K65v#Ѹ+BYv{xz¬imGx3zN o>OVmNIzٽq굹9W4ǹ/s]}r\/WbL=a^ yɍ(lSk-qcիGdxTME_ Ik ϺD+Lj=rsIzV<*= T9[=妈P zX u3K2Wo󁋫KcS;6sg|E.>S.W{ʚlTz:PTzngȾtDI~8ycr_TY+5;Y+xcW^RX|}!^%},W{-թj⼖<&u11\/1V^s'uy[=ӯ#yy4W]=S+\׳uE)N9P J\Wޓjhף vQbjwgAƕ Tף6@;8Q*= R:Uwh5+t/=c*B{ԓؙ:F ] :lrv%'W;ѨgtS{LQ΀D=K{(?=2p]Eaý>iسo@M*Ѧ^}]׾iD2KH~/M:Ⱥb7c/.e \IR+A/Ԯ@\'c㺦up8ױJ[E'R NrUP쪔"])u\xt*+js\TӴ_W(8*HWLm˔vj"qն?nwuE8A7Zk'#z&ҏw'ҩ7ZZ{zO̙tjJ0\ɀ qt&> 1J}M/^(RjyzLZY}MHb/O`ҩ|E,.֝?œD}h~HWgkq' 3N[;e=:lQO]sLֵt{u +Nz>ɮ8|P^y6 i* /+UW^h¬qryS K\/vN;_u{u<,TsMO[Oʕ'bH'6۽s P*Uҷ=)G:.VL(-Tgb|(?)Y)W]~}l\&s?Z!1^뤶>>6Tef>Lddw쑌'azrʿe j=wYs c;2ǿ¶FfzTR;D~wԹ'qGG;g%OTywL&~br>ahNdh>-3h]rOmrX^1ZȪYoW:)[%l=}Tth;jvvrĨU'k5v1jxrqN:أ ?F|3t9LYӳ@R&vWO,L!!oO3{& ǧ%%* +v/ZvR-P'Eω=K&\+Kʫ8Z׵Lx.٢޿N4hZY<SĻVS+/m8F̠5"Wl#`5 E:Aəl|XQѲnEm?vĺ;^Sߪ٦ļWhۥNA-/W,Zv{{pQKcqQEMih,k<3vpk_d^&F( n3zxKkfSۺX Vzx\aӨ bEIs)|Ft1gnF<{ǿtW6o"fW,лSzWm~Z`w&'O<^ LTuwњ԰S,b_!7N;Uћb)=_}by7}Ch9Z=a=ܓԛ9w(*WVů;~j#L+fMɦ; hf*=Ŀ}ku_Uo^y`Q,a0gbST'ݡ7ԧLٴ{<w;۬bŪ}{F/vid]b8x/y~ozo,Cl1=m)5P}LiEbir.G'hkޙ |nٲI5E!OvGzgKJpXX6q4dGL(M|`;L&3^D:&Z3&obt(mX"6ZFs#ٗOUs\=g -_|B&'LSߗRK&})D':9ԤvL8c %M~Vg_>ӛu׾mZ# 9 ^{rɳȭ{^V]0\,zjDl\_"{҉{ tݗ |y,C%6x 57~s5,yN_|1}1U3S>_;Ɗ'e>a޺\iNu]|LT0WTlo@=Y#?_ZS߽L7gj$|j\į;D垘c?Z}O,O|oPwj6l׆bZ\S}U@bn>tޠ.}8to5r{cEOWc=aSQ21w<%]t/$bq]xe챿5݇c+Vq/RjcOUi.qFHrN(s|GkOcݣbOch'gџRq* qxJ>ﳶ}jw,Ud:;?;^Rt' uOb'ݮ1,\v7 M[dObhZ,^#5\kd[ N5n/٭.\۵5vX>n=84c- \˿YjM>ڬv8sXoVp{%?l,hWVpQۭԽuc2V7Onx]\}eoWdm怣r en斏fv[*U;&XQ9p]̵0Ƶ޸]rA,0sl\Ɖbgxta.ö8c6Vfι$ܶ]68Yι~+s{ҟO1cK՞Y7dOVVVXSDwr9K}~NR1'^9.9Kw*D 6kۃ1Nsuvr:&oiG k'$>nH:Fhuܚ6d: &ɕf+E?q/:%!$E]c"|eʪ J[Nm&Dvm'osf΄3 /vRW J wŝc>t:_?M,lUr)[(e#-U#Ckx⎗cR?#' b '7:U_#sф-FT>7OViw\B/حFb>܊iq.{RcǙ̹qks;n,T[ﲷ3 53ktLw32{%~qnu\ZYޢ2yAޱSwzZ, r~[6O!\r%C-w@n_Ɠ1ۭE&r{bo}{m\=ot:e{x,k?Ч3o2x=>U'6vIy[|߮d7uHolmՏ3W nbףhT%*n;䬜/!CWjeՃ;uvbX?qf|/5m{=Awd Zڐ\N/u9:/9V_~PB}eO޷4&tyh{o}XiR|kT:5;$ԫW~SE:/. T+Vx7 ;?r۶XiV5ӶA/f7Re9ɒ_ ػ/hwWl6d]By]_Q'-6ʟkQ̄}i\<>z9h7^;Z)mJyk.O>lQ{5ڮs-UN}PvtvG^wewDzn:{Te;Z#n?u{oˮY)s-m[IvOA!r"Pzu(:%:N!o5Թx 6KOЗk:No35x*?.I]˪*uO]uq)S$55 ^b\Ō7{s+_ҏbGT={s o}mɷƕ:wnK_:=dίƽ\OkZ&ԌZx[kHUw55{N;qS6/_#mo7D먷=~g|,9I,O]n̹*e۱%B;l{?UK*{D-}ЂҗjZ"F۽ imv'mtXc?E}K ߈e^plmXZF,RkǮ^F{ =SW=F}UA-gjv|X.~9E'tt)WWybb*SwKxR6_ ]Ee]݂cru7]ҍYNd~[,eZ[$gt|]Ya*]<7>y3+ӗ4|ڃR}#9ab7e}Cl'*-~SZY_7ۨtf?P*V<>[(t<귂>=kN%pwAitvAD׳\4mϴ g钥NWxlDl쭺\kY/m[6U=YnPӳM{ {|:o\:t[mǟ%1%쑍uŧFlnb:okgOve*m7yKبZ˾WsoCsB̭5k`mY+TC nxVf[BL3^Ob9^ɝX6_?+[vիj{'~"$շ4/Wҍē=Y'Zc_39ܗ-?SlΟȫkT-&.?ޝn=9kLK%u2Q4-X}"n1[Gcj&FjϪw[߳Yo1GV;&j hL;J{lx8uf ZC]3";Ъ:Hʥ%^]r~ln'앲ӊUrS,/rXk?iݜ祅bQ6i]9.Ӫ|GsQW*INΏ-J\-vJ]UJ,u^9k=Xb?ON'慎Z>FwzzohƤy`9?INRFkN/5_[r+\DRQ3;1n}zLޘ8-btRӱb"nɞ(VcxbluX'.u1y3cKzqlucS6fS2fuR7ott;몫nnL]u[gZ7ꕧt /eOT+m)XD*hrB^ rZ( ((B9 mG *hEQPz9Z(mĊ\"*9ߙw%Gh,⑆[?֭'\6$ 9:s|9<yy]h4pθx4BPKw\0Yծ43#Iո`23GsU`3.4TF`k'G. !L} 1sORO CgktG8c{@ [CjN\ y0+偄 kQLQ3ݎTs"qdS~ AJ?J9d',B!dDk FeN#!aK?ޮVF{|Y n%e|ǂ>e|St} '@eNR3cα A k `Uw٬7%:/U/8:S\^&왉@V߱c` [?\^P NG$E8AkߓA@m Ԡ`ߌ?Ű+DV & d< xQw%*|G{O0_``3a`[= l ܒ@D>D], l=_S lN\Rh`VLS|ԉR[_ l{PRՄ`lkO͊N}*!8]dMz/iKOP'dEݾ] mщPv"S}6L.Eg ]uHqՏLdAkSZs}.DeqV3_/6 ;U̷MVjZ{$Ur24X68shYrU%nܸeDT/| j{͒yK*5l}1Fz!k'U*[^EnBs;"\,+ yMYPZ n1Q]|MfHNugȽAulXo QԀflV¯o8sv<ᙐů>gzKo cz:p oJ CQk w-yTMv m:n2<;i FYC0҇k;a$rI^ep(+5kW(Q²M>=hp_;L*ٔug4d3RIze:#'w!o: ZejCe~u N^|%/x'*ZfǨܪP)@-FcaAh_uhw&!Gϻ2 _:~FxqGa3;Gss[pnM)U`* Z}UtvP%nYN2b~!Э|+*ڄZ٨r+xCڙThW8~oEȇx*~PtN n'Ffm`T0ke 3={n+o!s0 s; M f^o! K:kkӕ`Mۡ`\*1)*r:'aT-$\~Ha1)$Jՙ"ۂF!,RCOlj*d_ 9mhc,6FOѤ)h/; Ɠjma~DM‘P % MW'&c@S]a>A[ͦ[q חqn+2sf  tU5[IIƼ^Tp&>q{,# X FE1V~iF߄go / \B$ы߄m1I7@/DQ,SL^Ɂnz> Ϻ =].5{c ]DmP֥ 57r f%kbf)9^8?$/ ;~ke`(u(m_B~/[:O?ײ-ЯBaAAh, 9WY/[/aieN,k~aZg353> 'q!P>5wlg\ rFYRlh:qּ^tI|'^aEb&yFEUbwghHZK#;`;U,Ewi`ʧ jqUYm]Ms Oyi˯Y/ZtIѳSc'^ɧ!g#& 4EH6~3񬪠C~6ޗє;*gF^`Wព{%'|2^"c0l0h,M%#8A8̽⮴<9&R|) p?R|s56ڊ B_Lb-{&Es{&Z D˸≖ܢ+躿o-KTg ' PoYGFsXww˒o`' (J6gQ_ 7n:̫\= 5b0FpE8i1^8pS| 7nxcA/tYH{8[ͯ0\ƀX!= HL(PeiS ^z m6vQ:e7I>VyYf$B9cY A>` )7;ܭF O?܌Oh'ڒ~1$H&qs}j'=P>Qc5|+n`zhp+ *Q]v 6 Gk0) B,o NRL49̞qIO(6bscK^"}=ݻf1nyrė4|[a.?'t'b\j^>ۤQ)aYƼV6M-ET#&^qp2%s]`IM9'9g`!iq>L=R?RXN5 2nSM>0T `gcuti0Cc2Qg6ugjsZ]6q9S*s KʲWd:%Fzo1'&_?WyIUHjCqkkek7SH?|o \J@7y15U̪MYw~wى> 10D<&භ0% Ӄh4(M(^WC~ۄ_pW+x ~ďUG0>f|gVy9KFMJZ1pWb -\ޤch1NW#o1v&s 04Fm)^*3gj&`4|XmZ[m &mԚ(/w0G7lv 6hij;Fx XG/;u#Nis 3qA` ̒ 7{6FUC| 0RуQ?h_-h#5zC6~*b-s:{2Bp]24l2k ]VN`bJ>UAWğ.'(5b>9(% (5?m @aUt+[q^Qp,Şa߃kDghӶ"wxl*g Y/xz B{F2 |N;(#G> IQq=^:=L}~jɽP&Ыs7jk#Qym])T: MgU{v߄XpȩY=o v2(ƒ;@K=IPdح#@aO!1oG}dp4_D`0;6{^_\Hxo-pig`~n2ҡ ZN9ƆՎk1PCkߛl rapi|1ݕ}'oB17:s (֩o`|a0`݆ V7L2}yqeTSoqM@ 4znDޡj2xU*kO7o ڹ7zq Zܑ875Q_߈RM/ܥFUiU6?H?d-n#]ԛ;/4HsǮSm p#-nohbFT6PL4zc?xkpqᰭ },<:Dbn)u[Е}F9k!xg|J?lϽNhKUW+:Q%9L悝H6I.ZwAXMMzDgL]>̱P_8|?%{5tZ CWWq v{J$gMn׀pƍD%O w *Yq OpiGCTW\ױ%Δm,T9:hZU^UYz[Y:lO/ VX '5plt:4ҟ 9`8 ٠Y5uU$Qg%ꃚD'ֺ%j?Y~Hg~IM @@q7ȿ<{ȫ\|EsLXȧh*.Q_Rڬ%j"DxJ{p狆=XB5vs7veoG9@vyW/`@4"6z6a5̃LCjҀ ݶeYMY>_u @O dhW>?QAIIsY־;xzq>_}JZII>A1C;U}k*U|lƯ ؙ>T~8s.Njպ?e}:s#Cd9 v q(hA }2;}Iw*d} L !&q%dޯ2o'AT"WAI@Y4i:TEў@I~|D7w^_Vjgl{*g IRr(AL*#T6hUgr聕SYhc?)4|)><`KuO!1śEbiOK87yFrǯXt _K02lӦAb]姼DQp %J"`ZOLwE-Td.}+q*z^PK.c: J Fh{gM2, OTE\_.(B-p9+T zfU vbleFbyC˴:]M9vY*4A`+F"*&ڱ[w^y0-)8ۦJ0q Yw˙6e0\甽 '05_NCnXecb _!Ԋ*aINoCFobx: td4/Mi/1s@75=;pKm1st5nhFkq< '5.2q@{(;N%JH™&W<# sŖ :UGWK-^uLj.1Lp_NH3A3A0b-D>`TwgTԣtE}VyƸ.DITfZ0YFn`ifhhiK-fk"[tr½̡rxqrKYJoEz+hx0wVXΔPHYVXd`=ERqUi(9D/S!*yI#& &{g:Ŷf5f?MtwXD+(diKxQ~2 WT~ "M^pWugd0@wBT,7b!II}J|d9GAzFVيZ7G\Xg wȓN ?(S:_ȳ嵃wkyub[[=ϸb+vN>qfb ؘ?j2sGnV#(Pt|8| L M[OkGzqxzp@-n=Å$- &L+al!mgbL-Z/7w6nW+=]g ҏ%[YJʐPLV y+VU`li¼ԢV x+Xyd,h<# jW,s=o,Yͣ/MO3*0 N|+9f/"\7wpK`"}\=,N\MqcfA-0YoI렚IƳ(9^\T0`ʱ]0]{g 2d < av42 sZW|   Ґ( &;SJ~R@?\!\ˋދ;*RE@.%b# Qn.1hBRE~]W7k~RPpk-' %5]l߫jyRU4!f"U3jjLA{|0'S?Ŏh3CT+g#% ܏HTAZDsS-`15`j&**fk 4$RWx)JDK -L1%lsTE L'gRj<.tQZ;}ZI,A N υ;§su6pȑ)a3씊'*"AYEH];[W)ϙoD7 "8"{$qV(*y;HHr434E!K35, II_%K(r_Qb EfY(uR{Hٯ4R8g$ŨY_RuR4oHq~f(RD"Kgb;bDfФ\M35RLgR3"v)jTIR`(PκtPZND)3h4Ѥ֌V񫈡qiR0WH5;3hWȩS:Cy?\u` ¬ԩL$lqiWl6 >7qww4-;PbFz : PP7L|̰V%:} q%BQQ6Es/*NP9>=$*EK#s:FӃ0J]{>B>mBtW0tjb Ţ8iNe0q|*%U4pv3it}>Բ텇*e&~YcR&k*0S?臰,YZЛE:ПXMs69`Dt)k #[j<@ "m4 6C<@Ţ'D2}/X0e)%W<;،MR8GɩGl{cQ,ۈxRZ{@]61T_,+fa~}L:W&2VQc܄ƈ)G*M^$dhۼ 5PmS ?&;-!ZTH4JO]8Aux"gc"$xrX(y1o(7Qҟ4CX]nqCdOՠEcY,}:D:3}ưOb>іVEϰrlP& Y̧g~J-ZPϜ{ZnQ?G:@`y$tS ٓ@/eO Z6PQo[|" zV5w |nNzc|G2eD '`zRFϨ5@6 )ZкV)'EZ aorLx-`^Xp?R?}v {#e=0Áuy%iuS2'o&Qs2sWcOi!8 `LtSZwKp;/ (LK^fZĠ2af$-f`A=W]ݝ/&͉VĐZ܉F;jM#~?8DnਭU78/Fdae /c}F_02QC(x*+5_ADyx"u J ., ОλEo =&elM7!2q?+c-V *vk|*tRŦ Cz^bx]l|SǛp=&>s1wj7^faP[.,j [hB4vEނ1MXag7fEOҎ@si{_GuT3 \R+0 PCLMR@da(G4-dOr;kZaXY$u<L,rÚԆ/x􍏵7Ű3_G0qrʞAipH(|50f›8(p0q1qG9G7Kb̫'+F>B KO@BZUcualu =u~RCxL% McyǪn2I#8V8K4|~4ղץ^-hې% tۗ^bMTnGa7\#:<#UÀadW8YZn~I \0bXɷAr 8?vpu8 9t L`檛*OPlZVO:n&\ZH1`XrmP* 9|Hq ^zB]t!ҝgiϯQ\;"a/MdS*^Rfa{#&Pq(IJCߏ&a ϶MnǹM98q%I(b+0#F12ƢCa|8qA*2C3h1]PȚ&U e 3d>+ ûCG}=ܲQ=gA,Ifl;LOLKb8;L8āuÒC!}P uUz" &[cċxnl!]`;b,wU ̧5Ö%QhAȇ|wB(0w@5AVܰF yԆf:`dad VrZLkZw#jt TC[ \7̔Sh2d&-V*bK%9Pz*jS $" >l)>BӰRw>! ʦ-+7쬡$Sq ES:|}J> ҆CZi.X\ e($:=F,уM\IEun*\UKLt\%%P!mg O|@*a%sFA@ǿv_n@[x}xRXk&4i  2Zr[Eȸ aJ4働Y<^KZy&< j/j2ЏUWlċࢼ DM ҁhG94S]{.FeiˬT\H *#2OY5@l*hIҟtgu8MO;nبC/>֩겯܍p IMJkqnFoHu<*?ogH~<>)qKr9t~6u6*V7MniwH~gFbޖz7W'Jd(sgޢg_<8MLVO 86*pkLܮH{ϰS;` _TȔr gf$v_^{OxPqÇ咰ϚK<(|z2Z$6bJ}t^o+>Fh?"Ed^REEċfEk}p͙@g)01?ηi^[\ֱM.{^gWs?+ݟ>emb?|pa:}c:#矦Y({(2c״xs_% k졜9dc~$JK-}LP`Z|kqKR~BJC/RaR!C9p*;}2u (3G$U)M}%rN< .60W=Q~SӾal B8Q!^S.Kg!"JbqU0Ś#XojOXC$7u?BF(ى%y٪ TU/"ĝȾl@bu*%)Ю܇Vr2 p,GmvOcpMhCʉ^4)i`/ 7z /dYx0Q$'+1wq8$wҘϻ&Oyy{ )#c^3孆W g†,R7\\aut!`S}O ._|6tN%B.pk_׾B}.?U)GP}7edB8c0SomWQQRɑ5+K&y`9JOONK {p߽v!A9vi1@Ru?Ͻ©LQ$r#I%5f-%MԂl'}pWk)Ӛ#lHiلdzq #tOa!ôw;/@j1oIijCbOm,W 6K٠)%j5{E "ꘆ44P3aF`0= QvNMkW'L|6nw  '6iK TBAoQFEnr d 7P"*L:RyJIJJPIZ7 ]ֽm8C}?x ïW-p1]p c8ѕ16zU#$dSL7hXy0g~}31;z.~f'a'|d "X)qξ^͒ k³1chs-* b]fotӲ:qԫdD,qh{)?O~@&+UVqtaHS꜉Y$n?fKӾ+EQ*t@*79,f<|ӓ#DAsSH$ &5\*><ʻpu:KbFX~TRrBG02Ox҅kx.Ge{. aR5 WwHnȩq k1XF52TcZcbJS'nދ_(S1Jm-r:ICԷhK.ey\^MwԦ4j0nmʔ\JA;L@)Nj˯43>g? xs Y0ܞeӼ?!a3Ҧeg .ї0ks_(|$MޑTx4o9{M2wN.w5ID0?t6 4CVMvd]e)(I)(c;X7k-4{#lʋZԇ<3h{<& 姘v As$ZIhٷ;M؎|]l=ltwj ܒ,t :  $`XS;*s%˘ T-UgAR2)+HA|OδWҼ6m$pHžV1(Xv%{h~CrUQRBM)⻕y+AxP;F F6"]SzvtZ00&:M/aZe~vZ7+!G3-η%%t5US*;hL^LU=K*O|q:SAFW@{h<">5tLHu质&OKQrS`nNsYT<^%e Nv_{KQJ}D v; o*7S$>wY{0UqSBOG͜G|=Ek;J6ۻI2 +" bpv^Qu! v\Oan6G yѪp52c /Vk? 9Tu ^u 쯨nǀܖ-rׄ3U-GSzEԟqT1+L;d' ΀/4pU>:EzJ,uLZeeo7 TgI֨sYC~t!;-i_vM%|ܷw!<`Ɂo6^ִ"322:DE4L#,WO} 9:Vm/"%L3"Ā੏쪀knmo"S&;/>SК#T]ٚpy[+*$㬫'ʃ:8ʕ3̪ntIgo5 N$EV.ߞVF3h/0IwxelgyDxq0FRG,ʾ^cvYh/f2dY*} {Y\S*zĬ3°lQd]Нauڋ^4EE+^4BE^4:E+^  [2!9>/0`s}rU1MH+dv(u0êzZm#P*8gba!/X 7ar-'2IԺ[0&*5όwXIއhMs5g{ XeێeU/½߹Kp$frX9?Q8 YF`)ƐLNQf=6ɋX 9ЂbUExp7T!TD1X_BoǦ]d[vXzs0GDv?sũg,K+k c\L,GgX,[+ׂu++SY`sK"\fK/ HzNa>XQmVv7,I\68Gt Gcz~;Kӏ`DkYJvO~QʲjD= }1T}gaWsXl>QN)WKɂ/0ze0l7,.8l%UWO$ۼ,}![rRB>bqO)3 SaIޘ90yh!C{? M2X)C6 W4F0y0VDa}x0Ԟ QAà4 ^R'07 (Ugգ: ޵ZC,6cʊ|sXҀ!Rl,O [GxG9<8 lM%}CbH0pȰda߇ HNj}Lk^6%|F2#}fGc}ڱg9}eM6]b_ZMj<$ d*܁X  KKc6߽Ag]aYF?WƫE99!G9<&r;Zʊ!`}R[W{e9GIwe cٺn#a3V䋇Ͳ5 %J FFZ%gG lG4ze'L7ʌX0!_eHy:YlT0v_dq Ð>}$;P bu8{F#r9{XȌ6ƒ'-^}~: VbM4m>Qm=( kb=G \Xg8^'ru"~W<]s6leeoe!?{1-Z L8YO= oSe+ܤN#i6v7RK & Y։y^`wXJwFoyz"}7<>vYXN(HŏJb31ښ5E9qsA˻ u_űqi7LNc8b#]t/)甗]KXc3#%[S!ȵS]d?U&3ϵYr9g/,S ocU-#0 x>} hCz`\9Tz/!96UeDets%vc&6-YBZ DB´Q>@֪ 9T?*6 jQ첨[0g@U:H,`=DD [X:õ-Lςffz %5_ 9'5l|f }#U8JMi,hKC0wSiBE|Yf &>XM1c.>uQV4eli/4EJbX:u!(ck3%j?f ތF􏮴֋+|gȯ"Up]* >U=+:?&"b:Z Ye哿hx] sV 1DߣX\ۆz:M::ktf܇DU:$riR)ܿCG^@9lŭ?2u>ŲT喋qӼ\pH1 T#wzUx>PS U[qXHSҽ0091h=Z% D4 s]:QvoLOCnq"UXMa24By+5F*,MNP4AtH"rŌpk. 48 c00QDŽM;0˒h˭5|MJ1okXA)x+])ã% +ٮDػL3Ʊ~D9 <x/*1b+YW9ja"r ||WHt8L) "?QUh!lx"vu9l1%lW# #@WrOR-Yo#ֻ(^ZzӨDUTo.gruMpM4B+L Avtmk gm^RP|3ԩxwAuwNJT_hu)R+t@޿vG 5 81o1cDO0b+vV3bSYh[rE qmRf!li)ϫ`ڗݳg4 \7 +tb}71#9N|ψFVRbʕ(hXvB5=}Kesf-YA%>kײL&`&ebd]6wP<0:U^ E* pá]^eL=i$&)s#z%KL#J_&[ 7MO.͉2b=4.:RP\BdRa_ՃtVݳEp4oPǓ9UD Ƚl0+vL썡2Yqu ˢw0Ȃ(7 $gJi}z8ÿ́ž]HK(/o;a"al](~7|%MrI=Xwb'/;~ɵ!;tmɉӋ?T''-6zHnH@qAT`J%z y`R=BouP?U* 񏣵8zqBd=O i?4Wm4ѼXfDS=O}=:ZjԺtʑ!Ki_vjYVҜPim1u@F.r-ںc3yt^yjKtsu)6^*DqeW%04 =s+9}  <gGFyEOݯ{xM{p(j'!hx+Jd0Ysm ] 2x0u3yJ l#dVbcVۏr+,KZIp}@Ǯi=.j|p >192s1ZWP[z[m\).![r@hrGB1<>aGkSy!^lbX^^kśh\X|/P pi'>eZw#r6v /X)f%vp|`Qra6$_W"m, &.IPV= FЫ:s&)`ltG\#kAם.EIw*BN՚HY&N8jͥ鵅`(Hj4oT=3LvV[|s^U}Ԭd-94Q#ERLP~u{aM+ *+2"i)e5mBH)IU \BDAEVY6PDRĂeHsI\}?~998{?{8JlEL0n+/,dh^Caj'O?ӌh-], m8+a W؉=ǹē2}_ڄ3nC1y+G:  'tk(x--_G^!O(o_+3ṭµ$`κ$Nq݆]ȸ9̸tPڡv!;&iZk񪔭 R'a"U*)`E&G:ؙT׊Vsŷ=͋%׫tL `-%'cN |0@rqh %MciBg-8@&"_œLK,~C}9ь3@\%ҙ3 ]r\rl&R渟EsQÅhՎT?C;xfR8*E0UaзHWJv^4ax=]街YqCHDwbOD·Uy@ 䎢˳ )ȣ>z;fUb! 3qp!X2yBQW/׉b7i@rw]wJOݻ䶿\x?yן,ޅ VUG-ƈ' V};si:~ MAz0ޤ%E{DVĴs,oV1}DKHCpۺVvs$7ވx5]jyWm<ɿH]$-pYpAV kB?9=g q0qˈ{lj{'{g{{{ĽJkĽNj$-&n qq醮q $n0qq1q n3 n(q&n+!ہq; qÉ+!nqۃK>G8WFUw qULd7È;#;c; n&q}57&Z;;ĝBiĝAܙĝE9ĝKyĝO܅]D}E]J]IU}kqc~Bψۉ[BK}-%A"a(qqO4qq/"q/2q+{׈{ĽI[ĽM#>$.M?qqeP(Xg fX=2cCJTnׁ+!kEPF0bxGz^ĂPc?[#1vk"C%_>F D=n(xM1"*b1b!j;# 1,ae8bi&> 1:P?ŏ*ID PP} b7;XbCV/WDQ=~Oz?J~b(Aꭈ7[ 龨1g;O@ K=~ -2a刍BLX 1b6!>bшW *;<<kXCx*q> 1|ΨD 츾OuN}bgj&'#7ۅLjmB$b#v UسC, D OzbJ-/Dl$b t]B (=9*X'rktĚ!VX=Ķ W [{]CyĢ;#^^El;b[vRb[Xbs"6z8Ĉû*"bہ oGbkT?II{5FlWJWgd\,Re,:AmvYt zxQ&M3:.Thz$O2ݚ=E">QSK[La^TTm-2Ԗ\wQ29\v|m9\`H`&3QYnF֙<=̚ :uά5eAB{zfҭe6и,340磶jcpG:{b7. ¨f4knm Fc:Ԭd8f2Z i54ԙ^ Fݒ񱱃䱱iJBxc<-0Sїl1i)CF0MXc a\uT& RIVar:I*M(M! M#ySRR_߀H^<Ր!)R!r`7/Q>L2 N$ L>@:T數0$)i`eJ>Kov$(S藘y(ᦦIӼry`iܛ"OrW̃Rg(rc=q9Ln(4YNUNTkLA*Yl0ZY9ٺ Z}ƛդcMn.Wf΄CXkɱZEәs&KIg1e]:&Wgf"(&J G|d4깊5 iN S=&8h0<8"rvI=zLѠG?8b4d,)H 5Sh1]aI]j^c#p4;;AfY')̐ mM Di`ufKR%Vl57' .&VH3} ~^! F1 VC6 Z EҤg"Q:ldPF"NZp.蘎V&q+r/|U¸~e TJ*g\2_]F3*2hɫDɫWC7U|t2E !-_07a`?qaLЙt1k,Z]c6y{E1dP4 j,p&?r?o1͌S435l,X nHٚt]6R=2r8¸ }F4NdY H̵'>I\c1! )ClՌLk `5ɓEwai 2j|o,!d 炀A} _+bZE.3Bխ|xI}! 1M- aGӌbu@Ŷ =><0 2üwDU0̼ +X<'?PX d̅g~: / 0*~ $BHR -`r #XиAPBW'w4i;k&M=CB΢p!K)\Cgnp7( (3>3>3>3MvX#_:Y 0 ĩ :Kڍz8aƩ<5ٔ5!3WV'W$MHuZ-:|RHoqjS\It*|rFPՏ7[ƫ34YLP6[4*~zUcp13t&S.y@Zը)31:-dL%PH3fb wl,ʵI0l1B*Gj\7Gg3ˋ;yq^<3)Y`CEuZ/bE';/ǗwI9p2=ҵlJ|]J/E`[{xpMy҃c6ݪ|wU{]fɧ2Hsx?ǛͫB/]xl^~C;;-]kJmo_`xyb)>G^~{6#9-)Y\՞\$ 2IC%8s\,=Ņ.-$]VQ=JR=#nGPIQ5D:$ݴL㯆M*ݤW߰2d\7J|Iyl/<6hy;aM(S[6 A.bk~6"7AG > 9OK]_"TP&X\6pFEmYȝ.77“f9#d0q PխX[,'`TgFyH_K+m9?tg8Jwlє=GtrGk)$gP Qx"G90; .Vqt5#p4^,i5ݓ28ZNC8EJ/st|J_vJ:8z%|џSzIM%9$W*Jkъݖ#ptJ*h)[)=*G(=GE速iS-JJ8rt;J/ѱnwQwΥt~( ҧ4[sqJsJoѿQZߍshT=8:=9Jpzsst[sbJ$pZJ$Q:@(7)v$_~}G`)-cK8:ҹVSH"~RSߧJ'SD;rhZP-}AJPZBM9Z] 5Iʣ<M7<:G+yHy ]ģ?yA=G yxt8a<:Gyt1>ȣO*}GoMxtkݑGwytȣxhF=GV߻~yN}ÓUxO2 v;H/1 >jcjՂţ,~we׳5`}w_kkkk;p2}X` N;4[Տ?,^ e;,>/ϗ)›Wo] v`W]  ),^ǀU} ow;>wn,>(c+m`,^,^/.;,޸w,z0,^q,2De ޓ-`9NH, xֹ ,>G] |D%u{,+X Ef0">rQ `V@`+~ 뇃,~7}cF~Iw/m䡶w#nO=O=K1[%WC{T[[Sqfu˼ʼQ%{YcZc^bzb*yj= zD.GS}VZuh=URVX<5,U݊W׸CՊcSCu:x TujNJեr[ʭC<5WI= Uެ֬Oa)"F=m:ՠ<8SMuk5y31եTROWSI䭖GPD@P=r鹸\ZF."/"B4PqCu) =N[.5!o b5Uթ >|=?׌SZݟZ:}xj>==^=uԥ_kS]n=OfJOV 7j7|}Gm<4lUЩ[-Ggz3u(5e"׍yRL0u[ťRz9MzMTc_Py5T"ΫU97VK;\ʛq{#XzZn7YzZkEWdϘwWFʋC.﹪eѫx(ʒ ҥr5\W^{\~USW~uD/Ѧu]Qh]XcF,z_݋݆^ Hnz jIx?vvݑUwM1x^&vݔN28M,OQ+S *Y2,9EϮfcqmSH- k yya{skuTRR4dJH>Ԭ"fm^ ;Bj8s E g Wtn(It 0!Q[A,ue)Nj72cd%unSU9K;f=W5uGͽs J>t=zSzjt03(P…c0Sb.O)qSQل5,R^9Ou >؞3fBٮW[tvNBecK_6oČ^֩;=׻_q{[Âm"?]?;xu5Nؖvw7m}þE=w/_k̘ͳ67-F曃\~,\vqö7uٿN'!G8m L~mJJ|_IjaϿ^JM?}:h[%80%z)NDk>Æ-{s/67*6Mx轹AT;SǷ}LA/,QQ4οTuaΉex7`~óMy7z-.qkI-n)&d豟Q|I[ 84{Gd0q-V<h;Itd~;cV5 zqv7UOrFg~)?fyD{°K_N-]zO4l Үzo̍Wrv\_:l/UlƆq_X:ëTTfƥy!{rnmm9Zމ_:2b#wm\7L_apѮ37H1C+Yy/_]g.*FbqAyTŌ~vwo$'ٓ7*Ԭ :ꀧ^mrc ڶ2'ҞkO7'u\Z't> ʽnjWUZ?u%;ߺs]_^vem^aɗ6duʒ>s: Í*3Kߕ2<)r6ï2_zw-:%ݶE׶?>C~S_;y͒K}s]n{J)L^X8WK}{9iO ?,oon>|+kvG:C?&6s%[lM~UGK_x%=hPX>p݈cpi<](/.%xK{C&_Ktu o44? R$i2vB @kՌF%3$3n 4 bG֗6TzMI bA27m1t& vKP6,y-$0ӆ\"NJ<022Rٳ[Lt'F %S.COMIР3 85koxL$ A;v!17C `[gtlX4};Gd7^ᘢc\b²6ܿ{ϗ4:t31ϥ{p6?>q~17~<[+MێXfב!Nc-Q>co/x5|r}jIɾzKeװ_ȓYqT~ǎl]^3WdRq^\w{}!wSR󟮿:RvsΜñ/m[QaK)v8krƵ˟ռ]mw ̙b)�{ٲEsxV/$3WҊ !-Vn%QJ+eIBھ~MbrUcfvދlO-?$~jCM-[~0syMVqe=m`M-zvz(pO~۩e7;o it7|D덋^Hvq 7|I1wsdޖ#}}^҇5:5Չ~zKԈYT3--ix&V(1uƚ?~syJ>j|Rv%~nsa66R5OqAs:s tk{w]I?C0Zdo s !>n-!f$oJ:V?A68͏]$Io~z]vƠչպN'P0ٚ3"\ 'DS31W>#8d'`430o#(q^6פZ$M 9^5۪v_˗B"m)Zώ3Zq72J&މ 2FR|T졧>|{[T߾rʻ)[Z|#ZoNZ>F[:hړe!A=YHf%=|w>w>.SM-[wz"=HɰP'%͹6☩LDIID],WytYRR4k"rB^m7إIfu锵VvRn J¶F,4B`\'"j*=j^ߍYrV;;ZHfOO' ?Rٛ]}_Y٧~RZR470OO=wVv17Գ'f[ׯWɎkR7da8ҥdlAX+熨FZbw-kEyZ~7~xE߮jq+KW9? 㵆)raM﵆.)xh-g g.g9).\EyUU@[D5e3iDD/u::̋-~"KBђ_wso\JJvBs_^\=WNXB-IEbɒk,}Ӧ403{z}'l}OL|G#"ҥ1a'7nxG‹N}nuokGVIzOdG[c$W,_|`mK_ MVŌ5SXb_b*ĦU-+AK Gte{8ʮ!, u_d}$GN(Miz[br[mNW%}c#/3a3Ooѧlm}EKډuP톦 ګ]~<#6"Y.%&W)FD*ej҈n'nW&c.f"gX2A6\^nFү^H~ ƬיD LɤA$OƢA$^9#_LtW$T EЀ}"h\D>PLTTpYQIw n"qS~Z*oOHxX~o߆ދLWOO,cCˢcz 7=bNz㦯./_;qr/_EI=^b7Vkض.?}w/ZcMAZ7 yk{fHNz_pMyxL6}^;uyYҵ<6jXΡI [}Q7tt-Y`}gېg 3!6ܷպrߝcͶduMeGhc`%B_C"] ]4nj#2:RңgdX%.Ɉlј(}? 2;!bJ+K?*ZO#:ٽ'a%ݕ?*̼ {xd/9"fSD6^Ceˣl&ݓikLm7L/6얋_ +=[7o1H",? [jZ>HypPƿ62g_brST _dttwoy;;ߖT(:G7hߵK565  Ѿ0 n<[ S_9y À9j5]ӭl]xn%4Fl,dBg?kҙ){To# h_;oܨ='+?qù/3#}߿aa` v `B~ VɇՕN:@UnOo]#~zLVL$Uc# jiϒjGpsu:˾ZGn}l.sQ--do =znI~oeIo5L+eRqRDґIӤxf*M6XcWHoڟZe u/ZDٕW w:yj\w\uV5js^N1[Kڬ;=,1s=Sz&\Bgz|TtT2/Ŵ@o:?#h0$4 0_t( ԱLkU @/+`* /i*ls; ہo}:-i>mzGW~lZO0zĺnc':3C ^׋ csGRo-*F*7©Le{5N% WV}P;{jHVTѢ’m(sm@Tp*YÆ:*+bCPƐkK?K28JEE Np/ҖDU%R`R8.+!7N9OK..߇usU-ޞ]M+rS٬$%cKUjh ы%w +d8P} (@ q`r`r90〄b"ckd ` ):P CE_T6zҹ[fbJnv:졪zXh~SQ< 9&'}KVpAV[4xwaɔsԟ\sB&8sStSjO@+l\ekf!7WeAYitkin ;uHYQ:1s;dS1EIvU$|@(m& YF6&T:N +T wx}c>aWV"c}SKHU"v`Tg")]'`O9`<)gwQ){}-Rׁq B$%AS2{+eL*cCao `ųg1n"Z gB{B.^Bf2pq 0stƼ% \ lqIRygahNPXg;a٘ Bװ')))\p1?[ )f@C' {E6{Y-vc_L`7aX(8)Nl!V!$T0¶Tӎ۷Uv"Tj03K,0aHY+.UJY`La"(*DZ>uf (VRV*m}˿V\&؄;ZXbdl M{'W+}X/!5R,UPl= pAp%K8?-!p%2NLi,X"{W^u~M! JHQxF>Y;Mj=\eC 9ȏld{!u LwNsv`#;&$(=]4l R$i;X:~yWN,H~F6vw>u23ȬD96Hz(mf81Fښ-mEZ XAnBU09۴I ڙ>I -l+IX[ItQΘb7@d`HQmvbYcNQC-)Nm Pj*,>.' TQ$qmړ!Kda5evh_oasv2 mP֪}3Iy2Q4+!PjGB1eWatj>t¡W}6dk! TE΃aٲcJm .dB3SȵU4&H<(=Xtz @C˫XAJEaIR4co0$03:(mB\CS?V(ٓ.`e+`oy M#UXJ(e8=;=YPLߋ엤c{*|;+_+J8znA~, pj Y+OVB@\tJG<- 3NE}֟aA_n"[8F*&}55pcs琟1CXT\&0IEH1Cv1#LNvAa5y)M5m-e@ Jgy؊ {I&L,+$DE<4W[8% ".BECc(y YHɉ4%6$p~dR[fջE͒dO9 WlE^g(uc~')Vtda5RΞq؇Q\'Dq8> rep.x5{1 '@co1oE`f OԄ`cJE3/㌽-\#O[SP#̷\Fw!zkq䘬C ,T<"dOTuPi B?bqMhwfen!ʘ{Sp*4bK_e9%Q>$d}S;Jmf@lnhBS)[(=S{-PB*'b-PZf:Ukqp*d918*؅q,4hF` N kp,Q5 J3 dtۛ1"fWXl0 >a)V ~a,M LJyDscO CRv4!|N8%g`1߯wa37D<{Gؚ=xĪ%_!\(^ +U]!"w9Zmvl(5TOG_cy?D U-V6f \4geaT v#ahTN# ƔxR|TI"67J rA rR7U^%2W23 3h~=hKSCgDwmLuжɾ!_MK֐ltN'pZIWYNy{vrr@z/ Qa=Xdp(un ΧnEoxByp@@7o rp``7eb xy}@}7/xk 'N\aT/a4_Ɍ I\5iVӢ› !͌r!M r;H +'AVpAHASm5zi4!JRiIի֫k} k#?vv6:CkD칇(*m.yiޯ6f0>k*Bc)ϱe[qxZg;d5_OLUJMGEc# ev7> iFr'day[TE&I@½Q>/aM$vN̷i)H9l=灷y <;ޛV`YL8Uo) hY(a ° =R〜WiIY@D*AJCRe~!X*m9).=LsbJuG-'9x )%~~*fYo.|Xgš]UĜQhax#Ғ l[^|D olkH=J|RsnJ=/2'i))<;Wf qM/e+BWpoWK .Bs"  $hsYGIuDOăJHA<܎ 7n!7D?s:ض2Pk7/¾c'Wb:xڪJ@V)Qt+y2 pa`Ge[:~@'T87QIB0@LCY#qa|{wsw۝bNyQ[a'^Y&f5hǹ')攵B.8 bKAvw*UfS{cpP֑g p4>oD1g?Iaᗃ? u0\HX N``C6`1r(f)M!I`|"/;w+N!i;N!DH:N'<Ԗ&iAJB{?Lb6mPPbVjKfiO=6KȂ%Z\QeYz~ Wܽ ;W=V0l).wD:,I X /?X? Hm 0JvP2 /NƟqg$XX6O(R-R6E@Dž`)Dj8}p AɎP86{fo>H  #e, YRwT*m ɰPi: 1K`_;6.t}h\_1+!H` ڷhm1;~ ZA[/M\qY>-gv ƛQ dc H&Ak dq\?0Y02wAqaI*%PW A>cW$ׇ J bvR߲U:7'r쫐Fecrtr|)C3҆ZW5iϺ&cxdTmFE*P\׷4 ùOʚj_{ԓdQxоt} I\{U@1Rɐ#󙋾Jr4}=S%daFuM0]T_MM[`_(  NdKU*dXvOÝH:g?&%|Xѭٓ 'y;&f?U(:.%Vf.{6h)MٓkX-߀̆S|m$>s 5YR)IR=KGjjW<. ~X^Gf( 2B3: U  F} XT 8B|i(<""B0f&9w-v)Ռv}8e>na@o7c~kڏ`e/%_" LtFi bIs}n-gLܳ8f[g`AԖ0%Lj> e%C{Sqos"SX\(6{> +we XdRsߧDY iUxG ŧO!K c%PET(V3`gDqy~7__~PvȆkj+(#8Ba=}_㟣8:" ;kt$(( - j{=x*d .,Y΄ړ4m*Ǿk/b5vė(Q=gc-'5ar۳Xb(.<2A1Юq~N +6 A"l^!'X lnnj20Eh)-hb U)ڷ""ZLbZLѭ=ZLn1-n1ESĴSo1-k1ŀSķbP)ZL1C[L1I-b ])RZLbT)-Hk1Ez)ƶb|)&bR)j1#-bJhtM">y"\[q(ƀrؿ7w\&I9Y5iwJ4 6Np8E!k@?"i8Rr=2HW?7ν.CoC``5cܘZnyϘ]|.f+4aL.gg}/.JZk]s&?*k](=emGi t Dzn t =z=}=1;==wz==A@@@@ORgDGI Qc'-Гy(HgJ8jZCV5U$>΁aOEt,@xK_z$ZÐy5u M]},Ep'hׅ7"F(Zia1VxơDzU܈:n)lep 1ZH ]?C7@GPx ,@]}|ҟQ֤}7:p@M+w- ?0U!Cк6RU~upk>`'dPd "r8S-$ە 'Ks6@~9 ?W !7%w(݆Sɭ$xr'w[r%w;rǑ[Ehr;ɭ"7nRjlr^B$ݯM G$KraV<k`q"TZ ۠pOI1[wN{]1ۉl3H-`|z6',ӖnjW }pJ=_{8wAr\[rv z$A= +l$q잟1Er0+j_WhR!m\;`+ IXeC7F ݀[QXLS4^U'UTMUFwHcJ˭w ߛ0'NfWi+ڡwq Pwoq!)eIvUTmCq~h bO-gk(`,x+xX`(FY6>?DQ_/evq LRXp:#'hU~`TݖqwlikGHԊQ/( %WeD\ZDq7,wOn7J%:!`2fR!]o<#rzZ&8Ewbqa"~-@ |t&&ܞlO' ScFUM|8՛8UŎz *-*ZW,$iX~v[$V2UzI~[:uu_|!tt5IircQ߰q= ʍmNB+4Cb3c,] ^tk+t&<dar1tGt~U*^bb9,Ob_bH_ y&,_?%['FP#MN9&/9"+jtmE_\ ei;b,Nq#Jpںp8Dsߵ)1I(fe4Sa.S@5ckһbsY#4*_˭a!/0+z߻E0K>,s#67AÓ,_Jba.đJK}[F{i(M3 L:L0q`bD4 UZ;(ív/ا!Tzٓ>8|_Ja@Hju+<(0 򭪲m!uyO(OY»#{VW`(SHdtǀ[H@g |zx7Eǟg(&t%gV|1:IQYm`\z":ŬBꡜIR9o xRo:U:sYQzqEt|k3{/UDw^nty2un3^{kw8(#*]?іsm.y/eRY &6 &qsG0Zmq7 %YZZy*9ثh( 322_)3qDSNq^Ƴ@T!p9Uا>wv̡\yp E!Rf<wZ,}wHF@ߒF>6@[|}66'4Gu>갞2Rܞ[o%_o%ױ$ 7D4 i(jՁջ}>{+Vq8-s@Scb~@jaj/$+I%5Tyjq hXv_&ll*/!cR=)KHSz~g4ǏyUۤ8jTIv ::IշqUX.n}- cvsJn_e>9]'T*r^JDk)tat6% .MN'QoAFORZkL1>)LZ^pb򒗞<嬡LbF%D:BN,4੟ɫͣNx[v^q.w4kQBflU=^6/ٗdA7-9/ P_p}* 4Mn_.*66o5eRZija8>_΢;) M >y*·^_皗DTtp_蕚!EM``1 EzA L,n¨rUZ70HG.G7E6bV;Ֆ+EZy)_M6X/#%^` `'%+L %SD5L*00_lX9$]jC[zEِ2W@PNGLan*myV,!޴b. ?6gV:H+8z4(5: F ZF/vϯZOmP_e&VqK;ЂP_sO$᧙VBm)g˦I"됴߃G~zm#Ad/itl&F';2PGU'KS(?r2FTl踂3# QݗK}^ jI‡N4oY{nx"xG+?;qpr8@NpE>p|9 +Kw]_=g݂1eßcs8N'O[NSQуܼ_e2讈Fk6٣tlSߦÎ>mAߥO`$J6U742~3aWC#YH4QQ _Ν/d. Ba9=Wk+~7i@OU5X.zd$( Cu6Ok[%ZyÆ01fQ$F{K[sx5F v^?C {gE.5dcw}f їB,/)zH.}aacՐsi|y(I((S8cEC^eƭQfeY+VUE{<(ċ)E>ξJi(&GEsse,7Ξn?.k؍Hɽ5*rk$~ r V0`j|L,ʢ0! Y(1~yb^Tᔙ 3]80dUĀ_J,_mwBhp3 ,/3ϒ3F\!QFR[nv0 s0qԩY5sߓ6(8֯PL׫[c401M -Bq*>L*t6`xzCSUeRE$1y|!޻edd۵%ODn$ [ ! %V uC=6ݛNFRBI|Xwyg+ty{0VfI^sE4` i>YW8lA [+J|̩0s@ MF.0IKpDuH*0 ]@PD l\"+aF\%c E,Q'8"^r@d {ZKB!vx[> \K7 Æ]tF b2a=)Mȱb!JDnqr,%d-w>O6lZ9rO.v}GV6b9r2Yd ވ*ϭ#\@'EX|hd{j3D T4Cm|wZ JS)B54W88v v3f9G@`a//AAn2ha=,srS9<:J;d|tYJ*bO$C  ADQ`b8'qX*eF#d-(ܡ܆x71\]hH(`j n,ct7ޱ!L\PFipS(yQr^έpjhNrgəDH-u<Eϲмρ*l`H/5u7!ɇE`"'> (%/LS1*cem#xqUqNM8=YyBIP'@-oz]$nV $we5D@oUU-(3:n99F:\ƪYOҕM׊2`kMrY@yQ80&/,ͮe0w)C=u?:ˡMa@4a:b]' HS;Q4M #[%lՂ#Olȶ j3טa騩\PJMttY%Rh(FttnT+>9m♒H9Bdtf˃tٸ s"_ n*dQM*܆xђʝyI{Q`ƃzf>r0ςy{`6f?c` &h; pw/3 ^72"u`N{:r S`^`[0n;z% @m^ oZ,㖼Nl58NA_kG&6oYAyG&,d4ydDvLYSiE'dCO%|My?Q4pL:`/J[Y9j?G2L! (&2:Y_F5H}G "-XAaE](~%\|j0zT żQ(N; dĥ sT`G[Bq>ěcA^e}[~-]>-X^j$3)b ѩNϔJso˓Fvqs#FƥW^nbFo;d P^4\̵Ϡpsf#VJa\0Z Lo:h9'nڛ OCپmH2R6ۅa1-0XD̖19m- `Js6qq7؜m4خ82XJ]g$@>lI,uNUĖ^Mbߕj ?B-z9*w ;P*y|8V8n.mc&w0ng2 a3yL<ŭ?(WnZiI9/K+A|0Oײst%HT%Ogah$Yk?xpH& ~o׸q[-yw `FtaRݏS nr8Ni9d Ŗ@TRfNrB[M'GxDr^sC;4>৙T4qE P8}h-/&E+s=jj[R5+E̡$TJGV=K^ɕ"N;q_~M FqN\*QfAd9[sV%DZ)c8FB6^\X,YJ<~H%gG~i̧IX'GIaL! 2U%х"jDdh]-ȗ2Re)N a i~j#쑲]mC-VaZX:Aky<1>6e\AWͅq >P:& lc2b<a )PwZVc1dzGU- ieQG |Z7zYjjO5CuZ$2d~pikr^7D_Yn CڇCY}u=,D+\vbc۾5SXfk]nXs *=v{~aEmؙei|ڲQ[F'Y[rV(v.j @K R{#먶RGmuih)aG^(lhpJhO{ m p IF|QՍw,cM:Ymoz'O.5e~?h %N }Nѵ+ Q>bMM ֞ /c[5,;1jDp0Z{-v3j;zdcГǂJ)S~MSw_-FUMJRH"x$TNYAXTJ3^訨rV|NWDf3T ܪУt>- `\ 21Z`-ݠ[Pb- &9=a9$n&^ B2c11)V1,PMI">o"I1]nr$J&u_\- t:TM v( ލ ”ngy5+ m%DN>[h|T}2ʪ=P>:Q?sG6d݇ꎆ2Ā5Q/7SVu?,qr#kTs-^@Ƈ] uIu.:eT'Tby7.j:5aQyt8 OnQ]6+XR9ꪡyf >L = wZg .h(Eڷ7`i4H,;#%6sOC,t`OH"΂^Xi4/lwaĆu~ r 13NFӐ3v ` $ 6q3 z`<"1.r29p;)<TX('';#`j<_Ŝ %`XA6%jZ;wesld jHLO^0u@g9FvR 9RMFn(􂹧8R u-8YQk=_ѸqkZYޭYH- -7ע:a+k9~O7zzG _t:d@v_RCHiuGYNM^Vq j5uF{伦V;PU&M;GGx$|RiYcu %52raL>/IҕrH,@_A8ߓ3bBy4t9&R+_tTC[ȋtm!˼}|=Rl/BB.˜\c(!QvS|]q[ep̋Jcx"H @[t:N8:NQi|>SpΕ)mwa,"5PE,GYE|Ꮸa,bx?b-"~kxE<"E,"E"c|WEfYE<qxE|!g/JG4&"g#ֳJ?% ?"o?b8""\,"?""\]a (MИ3Q$ԅY,i/dt(A<l .2 QL^#NhZ !x7/@Y]xj (A^x|L8Ja(봽FW# >ʣ2"pfnE~eLNQ Ma95}2 Bpmdrp,)|o7IJYYoa ) x~`(\cFӂ0Xli,UZGs㔗l48>1M>zO X8W'Y}yRzOLSeƎ3DU4IB7)NMH0*k~p?xr~ {K4nXZ6TP'p5ڱTJ>^'˜J*~VYuխlY_qS"rxnVu% f2tbF= zms@Mȅj_ K@0~rBJJFkCJAv74mo((yvQ&e;!-c u0~`Pbu+t$t&\,KBg}`%8C9r cjǤhf5c"C-lW`E?2xg4v~Z'y|3`ͥ)Jbͮ nd$S;JE@T,kF@9MTV0Epe`$x!7;l6Le6╛m1+q]uDBVm.bSe]p[1(ai=:b35VEavfDiR#,¥1@g +[&R7Ú!F  |cp<DSRLQ β\[ :_W7)4O> LO5 ?iv޽-yZ˥ޕ쨭Wj_Z M.: 돨ɥ!F5F [pNǸ݉KXHŞHŦa9RN6t.& Vە[&T0$I& bn`B#*%1,]/N4u5UW S8,%keJj$Y趁H%hkh,rO@"p(]cbAYSnY"CęPC%o٢ʥIGPmhup6?Ġ\ 6/L HOqC5rwnvcMY]_;St| 2P"%bDŽNp B& h[b/!\>B姻tL, OA~>O ? gQ6ʶŝH0C;d߄f7c߯ Ο}`vD_/}_"Tj-J8oϻm'ht5a[|b"]D]pA%űR89_q,f3/}XT&T0U$IOJ&LNRYXy`@|gN{xQ=dȤv^i)q8]PmTiKIQ [ {o kyYZl[ S0pÎlʯOx]3d}Mv|~ss?7p[p[4rk*rkpI "RW*kԷ}z1DՓ#kp?寅%aF1 kTF7Wl(s!ތ|ERԙ$Y~h:^50;GqzXDct]Jn5"\{;ꡙz ˆ+qe ~etNDr!h,7Wʒ,[%}5u]ծ;Ron2si,m` ivZy>%p}5hY<] {-`U1>0~a|v/,3<>ߤnN-bH 5u}d*$(p7CLV!euu0/ R+y19eϬdyqM+SC@P$Gu8A|O` $Bq=[ӸUItAO Q`mV bDֲ0:BfjGxzl5 DOaMn&;|p:tjIk& vEW6sc*bB^nZi @VVj.v3^),dsi]?s|XJ}U7Gb=X.+2o6V.dVg uZއ#WzO5% *<֏=#`C%#JAg]VJ$B2G> ":^F(x SpjTax ?^> mҀt4W@!ta|=8!1!Yߔ%yy9V$•<@׵SAb`_t(y!8!4xc^NZ FҬRО9ݛYj574H3͊lHxAKx:8_QwVu(𽟱Kqj(%" X=Ӱ'OVQ;1յ1c/ dloc xF!8Z[]^Ik=FbrO4vhZQSV_bƞ 20v(&]·xm܉|'z jy57Ov]Y\ꊜ3x%(N?)M\uwO6ǍkFYϣ8gcs4)13B\]Db-0 GmČ?7Q vЏpk=>rM"r6O)d؂D=Z_sl?˚ًbBmh;Df_uFZ2OFW:x1;`ϐLw3΋R::טΤR'GM'ʀ͓{Iؼpas]ya ߿;]7bt:=)%lҩ)Nׅ XO͎-~i:e ~ 掄؀?^Lϕ5cS.wtAߏCciyCXy nmB ]#"~u!nbݎ;$*!0VB 18C`[x'{{;o>@- ocX!t!t.31~t~ϤߣX+R([8&R [ oWb`ձ sr'b|rZtړ.XikVT t8,=ZC_{&g饞H>KЁ= wD_Нcөx 7h`vUiUCU?Gph^Ŷ55#UѼFru'ml9 sha }aæIy fuU146JoGA06ëF'|wzSQm01&/l\"" r>z6LS"؍;[cB\jơ cx~-o 3WL\/HpуL Es}\Nwf@ݺ.өu‚qR )^u]Ɨ >&P^ ^y7)#fN(~曖j݋N`B ',@c'BT|7/cpɤ!+KJn\řl sfP'OE/Zԣ A#4#%t S!=:=[BSqDmBz|`FCWy1UDlUȡ ]4Β@q^\۳A|;$MT^R`DIyB)3#c/4gHB`@KS>4>xoh4 SjlIuOᗠ@mlT4o~bPݐAa:,WAi0Oq oA = n'F;BrWZkPZSZӫAݖ& \^>7 i{q(mA G_Ҷ)A .XEl8&H3aDڏ_{ YWv{3N=*.uȰ۠.M"NXӍՓW㔄=KU=n=ĠsuWlܺO6ߜ6ׅ(bЎJ݃Wˇ[/ anmocй = ThҭM8((JuF!pw!p[7?!<r<Г!Ő߃@W3R[HS.>KqaBk] z:[Տ@QP C%zaNB`eRf,3⪯~nxC˭ަ :+T {VVZfmY`Ji,ۨYH BX ;BڲX zZ{́P1BYW,$B"Yf 1O~!d,RLыE<"" 0FwRԽ3t({عa)/T\]h}+Ҏ+gCXn}5h겜Z_m7)ßeGI-qN)$~3wv*az% 0l~%o#sugl pX,M&KniPr+?Oh2!әҨX@յVp/s锁yz\xZoqu' e]g!ӯRkt=o_JL; <*H>Ň`roJ*No[~F{~Aw=V~?_nw+V6~wo-߯w/߃5#{~c3ߓ{~ Uq\ ;] t9kPtV:>V.~؍\|Uny.޹uN17]tݏ蚄.<[.|z(W@*t. sqmEtG/*DaAW?t"W.<מ xtDpt-AW<^B~33/ ]\[^ o8~ y&c1sAGntUхT澆uZˁWѵ]Ϣ0*u]O vTx!Tx @%z|HF=2٥?e ;V%T- ݩ5䉰}ÿuƌ;#BGEٗ;Ys޽K>TyKMW 1 :=<Xk:ft]Û}nY8zP?:DsWw~7w-XiAjs>Mye)*`ԯeŽ]u}is[|W}hsx3ȱF}Ӌk~Gg~kLq.Ē3.)r-s?u_w$]fA;=|_X{bg'84匓~)٬>|{-OV+y~xza#?]rfeS:fgmb͢G,-=gbbwNdSFX@Ȱ0nr/'׽N^?]@/Œ1Ն并ޓ۟CDǵ+^xK'vo?SGm5 /V;=M] uGw쓿ul74c_ڣEk_3f}5˽#oZwJ־~a{]ʿ.f_N%g_Y{Ӏ5TZ[%q۟/|}ξ&]lY cFF5EǗɽJXcRdE;g_jdN#SdFy{ L|.Qq3ww+AO>ڽ]x}4v/u^^Z;^\/'tk|W!}xkޒ{{]8!׾wO?x/GOt͓{ug/vR<[`iϖϨx{?bC~t96\` i >T@X\``YiIə V<&x א~H‘ ۋ_pwbs1m^`}W xk C_C^){?TÞ >#ۇ!{B%>]E~ p7>#OAHA\,ioB^ gu/a{y/{wGp fG' ǀ'Tᅢ+R[ K06o5dH7Dx&,"p q#ptS3䫁w/6\@8̔3}pܶ Fxw Ω!|,,0N6p = /l0ǐDH@WY`H?+r/i3K4s+bN0=ނ\ oy[<hc^ڎbBpg9;~ ]8q^9 '>O lǥCq>m/$He$7O `D0xd al|y`,OOvB“P>m >#cob@f3N'~j݂r5 ;ogrcLV=&!/$&=%;$`2&PAA'O=>({ě"M$G],l`~_T:A<_^~~| y DC<ոċJȫQ AR!@Z2N-o<!;elrS%0(0N0a7>1\ ;8!݀ _+xGWvA,b$3P z_<'c" ?Ava$KpцZl9{<j5 AlM#UOӺT㄁Q65ڇڵ S Qe@CW.qFv!w7LЧ%)  8SQvLٕ)yscF7GkEƚg]#qُgeeEEEWƧgeμZ$f,(wLS5R3˺FØk冱~V,St~Lʕc̦BI=œ]N17O.֟5eοk@&Q6m~F,SvѬl,Wgz[وyΒ;nMqw%ge<6shଂYŦYDO7mvvQq^$=DZ]^qDWyzvN~)jǍ;OW͝_P| _%T`t/8i ̦k%ʒBg.J*y L7yRHf:_U118UqKviN=+;{zz%Vk_=͜SVV<[֧XWU`RgggMWfffi2r@V?JJMc8(yR*zH5dWC>20ȆF#D2Vti33 gM6L_=- kƸٚ0hFNfhX\紂<ӼaqW-yf6:gf7_73d)S_=0aij` 4+~xF7OL}l+S_1 o,J+(̄1(ds8aꗢdaï6e˧}mLib舆4y\\,!mdmz:/9-?{:vs7!U/ 0R վ"}EzW|căyӳY0H 8laT$8X#E Nc?AKcEӠ&lH^5 fk yHcC7qY#?E"YӲ1PzM1r[nE2 &SH Ф%'ckn2hd$\`\&whdLA7kTPBβ`ELCLVO!`V.._dG=vYЪe2`,ΗWdrk2 lzYа 255Ƭ)v˂{d3wͿ7nwͿ7ngKvd/dH&*ٵ}P]/A?2[%ٝ$[-wJvdl^J##م=_LWIdWKnZII>/يcn/Q}dA}Ϳ7nwͿ7n/:.zÓ2ҍܢd<.[!)##ؔ5##+wFƣ̢IO`iygɖS9ETBvQ~FVf~~F~^ bТ($cVAV,S\J8nnqa5`N,SfQQ< |4l*%. %fe71o6%5 +0IXNc'ÐI̜y9E&xȮ cr1G `p?xvƀt #F,(2ecp<00 CyiLp踼3r fbHLBj_êSPE5m+4@X=$tV7 eT$(;'oc#G2Fᦜ$YWDKyY[,̓fL+(0efg$j6Ey[iF̢9yXĴE[AM3'3Uj4Zf* xU?>t 2TAZB+"+H@Ȣ ol ia+*㎊Pei (]vIJ-[?ܙI2](s]?sϹ8*9qT)BrJI18FL=Eo'ˉl&墸.5M\.snH ~h0 dmsr7nEDV/ln3iW g`Pk Y#A)&u0-k7"ea |d1aS#=>FD$ku(cy߳,@{))ZYbn߷cL'BkP;0Œ]L|4 nС}?2t(;ƻ-ߋi?_| ^rvhMs]jo9H5׹v/#ʩ_s*旈cʋȋȇ~8S/?ϏB~Ms9(0g uoo+H;*` h_eqt@?(F?%oT0ڪyKJel3c3Uڝc*}F ь>ҩ*fU=M=_* Oƨodtg~q+Ǫmmg*}pT|Uzov3~}G HC SU>48n\#f|@0s<س"<m xEPM|vRklOJ jz^CCA(ajT/Uz<ƴb/hVgdx}BiL5Fk;rCiLޮh-}[><}(][O~>%/ OJ ϮW[ 71OS4g?CSTk~)<}(雾jzJczmHƐ~!WkvC ]j|EM2/m>?g[jzһ Ҥ_ߨw6mH Fh-:Cu3U{ɧh-}!}!foS?gHABo\\8+躎b55}!|JS}h>2*<}(5{ 5FkWJcz~ݬh- ]a[h-)CS},4T_^xކi3^Pfߧh-}Pk#j_+Ck<5F5,Uk>Ӏ_(5a^^7KZzѐ^445F5 Vkt]Gf5ZK`߆Ҙ^>Vkt]W5c']5If>x6F]P/]QO7t1˳;z'||p.{ӗgiuo /u.??%#Flǂ n@N3h_0vV5`HH``h␭ ‚-D27nD讎T֎1n Qplv Zr'.tܸ].wUwvwkܻݵ_]Nu=jvKW!]e'-j6kmqٰlX6(WlCy\Ӯ%k'eΰ%\u/l_Xv-`mWvWeU΂@&O(9^;RFU *>iԄCQC 59iEn~ءUj5MXxiZuLvHlb\VK-[sjF<%2D`W!KD/ jXZj5D w"k^޾VKKVx՘j r辣Ǩ_CA_4bL|tc8M *7j0fڎ?&Qgm3rImGOVP۩o+or4pA/3 5T hI@ &jofljYMbVe^ 59Ԕdh_ :m"!MblOH43z3Ѱ2hWg:珄Ugzտ 0gr}-39;#s%ogaRFO=psVB3ڶhwyg~CSSl;RꐖvwRdõ? ,JŃhcm~䯭}YŅxWyZD42_ˣ&bٍgs!T+;-'7vئKQݬ8)*Jჲ]?|\.|un)v! *A 7_yz/|bsxɉey2ͦ,J d|ВLB,$qv]KPɅ=l%9UTr("d<m'rWT:o#'|yKU!ꔘW݌p^LI>/)I^$gʮtDC-}B[qL1Kބyn)*bV[b.="WZ䓾|b#~%Ty7QYߩFoGrc'cbW30F'd<"cXgLeN11q.AgXTgf{oLe@<+ēYZ 4^cs=>㌱X/1xx1>b M:cc,e7񌱎1UgaC16с12ƻѨ1~j3cGb1nH'cCg,cj3e 'cuΘ3FQ{11>gSw#1N1fd8S30yƘQglȰytHa֝uFctd3V1cg:9Ƙ=%bgcMg f㭞:+c,fw:V(b:c`ӽtFE13F>:c/c::1f}uњ1^32ƿcu8c11.ޯ3l$cTƘ錦1ΨeX1Fp;cb;F茟\cH-cd٣t댑ߎ3cc311ތ1c3bq|θ13F:#1vL% x Qڊ#U{Llb_[Fy)ɳ@_-)={ٖd7e'vOvzꑖ绣qƷ+')a:I#AiK)뤥>Iog͂g&P6"$17F>g l5$֦ []s8s$nr5hIɌdkL/V)\$yRB}Ĥ@RL;h$<7&8O$W )E}3 b5tWr'xN\}J-,?F&ቿΨA~{a1¶NR MBNyf_,)W{y.ZZ:{43vW^R|,ՕE z hU9p #â^dEE+ 9RQPf<5iKeZ݆2KFvF?62"FF X}z|.C::d!PSAuȦj>a$/FÁ("^^q G:mmTH[5Z H?S壱9C|[/RFi1Ugݓ'Ba4Ref:@@C~$.wh8jzիEN_%3)J|n)V7AeF%f$YM1/T:}'g)a1e>렌+ٷy>_ 2!^hG2<| jqGf^$;QJ) 1;]y(Q= 6!Ftc) \n _?Hٕ=~rhaGPDc &j~{W.xjsޗBe-\/M{^ʨ`_G2ƎtizdZ^IJ\D 0I% 0c-v 䃮MЌ=L(5LБar')/rʦD&KbOޡU9 .T1wLr;hJ JJ:(C {|/h4ђ <ƪ4:QCz:Iu@MX`|u{{7(KLLJ)eA'uR\2 k@#|bgIJCP$QT/\/ ${*5jj̮HWS)pu^M$t >.bc\qjIua߸8PG~tw |;?Z?üsoUsux#ߝu|:柝y:Ug517qЂqv\(vy% ,aS &9dXZĚ-Iv#K@KTsdG*XkZ՜laHXZTC2vѤ&zY4k)k[=(VPK6x{ |G b)3/[o{sH51l(0I@&/ߎbQ~69)օV9'y5i!nsI|ېocgJ_xQ.]D7^pIrٿ tZz #%ˎwMyfLZ\m9Fz$Lu}`(eGZ٠B-ToÔ8[w*`W&BLk^SCBTl"ߗVΗq1}!fHhyN ɦMEF9yWf\m#X85_߬2곓­Ԑ\rY~$*To@q=9<ICn]%ctϐNw!4X[GZuʯ\9L5:&_+$DbO&=b'~E$xqKihQƷqרLc63y"^"GCGL*i'I$)Iv0ܬ%WΜKim}bًB\zּL+Xs}i,_Af(4N< L9mEk6`va\䛂z,w*oI,4EU1ӣJR1s *$gU5ZC.$w)¥TH)'?#J[YYG[ L|'-D)cfJ|.$fp93|8ղn'4'L׽6psZjyR}6j\ a uP<8#N%߃Ը5k+:l7㠡b{~UL >g 4>x-`K+qꃙ)z=^ͼQn[oA22xUG+.}YFZȦxfsƒv?Ӛ-?-zjRM΅蚢_Ҕ)rϥ(Ma$$Qqpe>;ؔfĵP̘`IS5V&w dVnY9ºU1VqO\*ˬȷW80,%%)Lq "ŵt}Ζ,agPT35jJz]*~Y&)t U T}aoɾT>X'gƃ(Iu?UTDTK:e~lzWtU^լ} pD{3:]SPFI2hT& [T!{ϜHDsM(Oܡ-7'^2~,^ Um_r3SãM%E5)3ժ,r4xUHrt?[rrzrdY9&I>|HI< Sk$OKPۅL~W Ώd n(t2U@0_x+P;5 Y*:wdgK QoPIƇ8h.w9YdA4pY 6.ra4ٿbuk fvY9|ҡNX.֣ n,Nyr9lɨˮïɳLp Êf41{`:c8`xrEA 1|r0،٥#qӚ0l0Lǰ+c1r0r_ i sk_0L0Lqw^KNFðx/aZu{M ^&kİlO0=0qm! '>bx: 41 k0|la_=rG=Ts1:l _5%K칛|i+"9,V;_ Bۈÿ a%G>t5aqaoau ߮fVg!j;r]aBU`:2`&oM 4,I6NyE0BXtpa;Äp{P?iȎ:a*pq ax*4 g 7\cĎ+;aNcaa b8n%|Mט0H:ۯ@~d{r&3o ȭTnnp:x=̙F8Vŭ`+] `@`l_` FoZ'ȱKx&L' ˷x[.' :;EВXgS'27d'laRiWwaY ?nAX'$' R_9vԗ88Pl\_MΆլ_ ŕ uzjEl%x~ "VH!ƠU" [SZZ=; =UMXRl; 9v[ac^Լl-Nn!W$l4jRuvwa"%Lb-=ne'J#i}f&:d|st$"aO"q,ڎgM$2i?EC7]&~̦96w4`B9@c Φ t8_M3qr7.n_&B6,uV; cq-# tf>z3i"=>/U*Jz$YGgup+[Ɉ xOO/@2N[miַڒـ 9yxiI,mo٦RQ7p^d,&Zӎ6s<AuR&_)= 77 8Ea=3Qh2mz*7vW{շ)KJ++i͚ 8TO,b1K9D[aND,_D=x͛`Êw﫟p;HwȻEyp˖ WFl:v)"֊kƽ^\AO1"A3!Jcv@G۰T'ٕw]+zG+LYg{u'>守~^Zx??ٯl? <q-OM%<3Deh_pY -E8gq1e+emLNwȋkyR(rM9S7UT+[pbvއe1iv~E*OCc#s={`ŮtƪL`L^02 Ni= 7n)il`>O!ŐvzQ5,zy$]΢-EaE"ma\M}xT/:]  raءr03|<>zQ>lԝ:A~u^oQPoYAm;+ʼ{Ԝ:)GQNq9Hi *)m9kyu^~,ða,n/[Q^s<#u0,Uj==,XZGY?^!L\Qg!jGiy͏F ~󋫏rr 7~ (1|+"Pg!lj!lC[T9?\N~K6Z7G 4-'?*:r<}]t_'@Kx8 x k'G+` ೧1_.v/{#] T)xܾL>ik/K/ko*{| Vw1n{|%'^ӣ#qe' Ors ='uͽ":O&Q'ȽܚN N5Jb:Id% gP9A=Ib%'t % Cp6uּo;JFDڦrQZԪx_B2PgsR&%̣J@_Oe+wﯴ֜2Qƪ?śT)d4Ke+SW*xgBVO, ٍ$܏&X'OmJ\Vfc,݇yƒ<C̢5qHO ٳipg$&qP;1ȳ2EEU=W1EyVczo\DU\ӣ qiUŷqQYn^tǯ_{yǣ&d%;(ڇG47L+qo.wx7wվqAbƱ Yoj6N .pmR}#>p}uՍVUވp*>[O#&kOZDG"(%>ZOkĞJe{=tEt_|b(jtbۛH=-=PU܅E^zo0 "|\RLeZUd+h{OA z"qgIeGg3V5wjw]lx!9q_ z-ɸi(:MkD8oŧE;}~f[H==#95nق=Ӟ,5UYT)EPbvgEM)e lL˃Sr>zνeLWQV~t$La )=0J%bT_Њ$`f*IɊWJ)[mwռ\~_V[;I&oLOI{1,s֗kav$yڃ7Ir`Bt-缃?@*`g-qNK9Gis9W|ykƺWm)we{OJЀMHZW1Q^k6s"ۑf0Kɻf!!t+26cqNMԨ,j|co̎ u}(RI(Ir1>SJ[{"\_MLJlevqY_ŮveS}C u9Nro09LO&:{@߶ ׷iф5J\äo]3 ?#}| (A}qlN~Vwwf~|86> slyݱy3c:96hJOO8C?#:+ᗟ Ñ^§5 S#o|R' г /+q/$ 0L0~Pǰ'W|Rg `r0\}ᦟ1A0Fϒ&E{0ܶ_DŽa?>"޼fv}|9>qM›?6bxu0%MJ' _ڧaG}:w1 T၏.|ᙽ W?R*uDZGa8έ #½)8##y ү҄!LPܲi^ >$H۫C+"Xg|oeapSL>A0|fLP=? ܣce/ NwR5`0n椶׺+L5{}"좪^c73.ܟ_RN⍡`5N[+J1S.oFsuB6lc7\9 8,qL34R]zo-j| DZkX\;k2=%!Tv5jZ..3Xvm0ORzӅ^9e|H^H:'Kǎ#xm L? ab'[."cjI!_.U: y!{\t:'*ŋWv=og?9o!ExێU*xJ!E 3ổ2jOݩw aT Gي7Z$1﫲^UYسVBq1>J2t}yMd|Fky˂V~{E֩F\)q%kj'xK#WJ3QHI/-xhC?nQdd}6[Z`-xf 5p8[b_1H/|a*Jgk!" |S&eS.g#]\ tE}QOuxӛ t| gGt4-BA,$ % f!} ;rzHOW\% &u؎y|?S»|%p; ]<7۽ow6g닏c^0G|NVTH?|*s@; )ӱk1כb.>etiBJ%,7 !Y:2 eRv}VY ,^ G!o:UBF{Y> L! `@Y Cu/0i 26Ea"B*-aXB+R֨'J.J_ #ʺz'uR2)#kڡOH\7EըTѢL 5˧)$La&3 YsدfW`t2ho؂ xuo '%Ys96'-\:{ݔ ߰D4e f] ʅ4J3n.X Ka]aqmc)8)ysbIVJ|>>  ^Z5M8sRB}$ŸF|&iy&?+lycw e=3@F̲״yKrT~M)6$X 5%kTG^F9baTmV:a-2g o?ͳGGCM`hT04$`9Z/Z?  6 *PN 9C+l i۶" bF.8m5C }y>;8B¬ rx3KJ@ĭ^U*,ת8MǮ4>:ptMQ룃6MǬ4>:`tpM A>/)Φv~CcP*F,u I _J Bfț?9ďf 1&az>m!"^l+?`ۖgbmWkWk ’w.(x|1: ϞR b=ck86i(ysq3 Byn{a #Fznp3)}\ co`M{SP+{נ\!<^[XM@Kr-[ɻl$A ^y^fYV W&APn:TI*C~v7*PIue+#\Qvy[I4Ѝ"Jǔ鶍b9䟋Q2X#荠qB[l]hCh9s%'p?+ڡ:S^w i?%o>\r17. f=Ii7Y1qK-:}wi4ӈ;#PJqdg+J^ˬ|$ ~}!,Ƹ+G2% +//x@H:oD8x2rFzEQ-AUSuHެXIby&rKTXD 8/z<rW%H(lyL[XU"@+KxŘ:U#U zʝ Yz1OPgY”ѠʽSCYZ" ¬!z˫R1vYSq3&y {N))n[p[ˢOpIB ;OCq@JTg#/DMo+ Vy!U~ldu32r);{d!?OHe+IvF c.9z+Ō@vV C?:z"`NeKo pP!# ǩ)߽T,Ƒ*,+Ws s/Z2N}"[CbZ^X3D5)X)C"8T){d4Ҝ&Ĕx(luj KJE9kpC/HB}dq}/)'sD(kq!7Oer8gCI鞎QRF3jOw$sZlKռf,9c,oI.fvĖfZ{u7u^+}(W;dg4DQvtϧ %Q@.<Z0;R:cz14#l%xQ6lYW9U<0_iC.BZOUnXIq(c!?ȒA ÇzJJB{>v0|7zPID.y{ʐQO(`gBӯ(oiנ5&o=%%; LK/}x;Hz:r}q>G~r` vC560Dk^3XwY%&rqkW&Ar7$/}̌SQ'\ c2io2,CZI6eqYmxw^t!lj[%Ye]8C:^'y[ rD85;^)OϳݖhFqW)9޸73%(z#)V̊o4`j 3)$2^ڹ3|KZŢ&9,i Ώ薊$Pb#Li-1.s> Zuu|j1T}TU:͂DǕ=&`NK<[ O/PXVt8 1nk-1)k=)of'zE| D L0Q $ c錇bkM5YOL4?DlgW֬ w;r'fj_Pt諝jډpXQ,ז4+i&#?AyT6&3ͱީtd?'|YsvW&&V%P;F\]C.8#] vyqsl)k+>E4Jejxl+Xc(q廤;[j {Y.3OwvфK]7Ga'*m:.U(M`"w<NkãiZx$^]Xޖ5k6E7XC0ܶj́l<1VœfQU\-)HSZV8K2C$n/m (?qp'uXeX"d ?K;W=~ٝg:YV?g*ժ4t/-q)q~|/~%TIkq?ŇrğFKr Ö!  >k*k T gHa:U%U4}16b26}ͬQa=ɘb!+n(eXp;Rr!E=:5_#i=O`"`س",YlX%e8S1eWF;Q$α(8BWc~] .ez;fZg92 kEd’'1M)ޞցw Ot['CnA]S0*CGTɆ4Ȑ_~e(|[yoQl֘ٽ(,_/X%>}-fO|#nrڌ?bf>،T7eSa];OAgwCG,0CD8݂u@}E@o&~ФU*2X+XKhZ,ߌr!MX%;kSO)]&kB"TIzkpp@ZD:tG ud"8IK}Mke%c ]ԩҦM:ԧt꛲ XzH&0X,턞6)V1# kѮsՐo.)b+P7}ojv}1z }h 匲fydAVҡIOMW&կ%xF#刃?m mjkCZk Z5{m-\E&1 Xf}53J푵9wlNH=@^gg5ǖtd/$YXɒC㚨K U,$,'ewKå*2>'hAha\$uhVu](|Yi4Gnjc;#I߾ `vNRfX-TFn<0[يslMgTL/HwwM.&AB*Rj*J$(jj=ljSKh [`&ei*3) Du|52d]h{uEipX嬁/"S!єqT[31@,@ cc68yaq5n 7oZdi'ma  h# nE;mR&B,Z&YLx.|w~WQ۴H)"{kT6ey̤MB x39<9<ܣѐ ^j8|[I e:c!:}LR rgaYŝtD2?=Fob ް_:nYqM<$, DCq&&0 1GV˞8.WAmx /A24 o*܌.s,o$>\ƹGS4a 9/pݜg:-Fk*5B!tݭl6euVTK0E}x8Pz›qܾ"Ts L~-B?RYK>(eZ3/C4}o3:c Կos`(,D<[zxʼnegwp?jA3<botUÏrt:"~J4Hɨ&m(N*ACnP] U倩WuԒ4ؼfn=^\ sf77MeEvZqVx!`dc*NM@jf,BXϛUϗa cCqU™aI/a!Gx`;^%0 O20V<` @\?|kz} >r~G'~!-Q(h͋M*ŸiV_:(@ü;y7-d? =ᤡCa3u5/Nj$"{7.L%P `lF ⅦQhy R&5;&ҩ EK"҄x,d#5/4n(8C'3‹fO[۶ؗqRR:vAd𳽵w}Ʀ_,HO m1 ) u'l01f C\BӁ0T{X"/vh5bHFjBJ&e«Ѣ R'k)~>X^pV;},%޺&hiQw{mR ^Ϻ8Z7-:/ǎ.2*L= p;83y/L? zKxO=/j{ *3+>wwV3aݫ2-!A0<$mY*=4 Y۬tfz4-yIi8WwƐc#:Uѩx 2C(S 훥JyA]#I3/6XҭtT]6ڍ(ZWğ=xqLuEb@ +jXp69{PQ~0*mdp r[ 8W"=GI0@aL"O9_G&QtLAAllL"NӮJGwtbn~[gQ6AӸ ]-4&;~X݋)guW|s `[rսzpjUY[4ی t)+)Ul\=140Bhӎd*jUĜÁ fj| ԯ{OIQ 9j.ݜ:"xesA&AM.'*mn f:\m"{7$@+~L=@E5~'iDaXNP8ω(Յ >/ѢK^;b%2iT[PA:&s8>)(UDp{m5DYlQ3WrSli`2p=0A)9U0WxBk-ӶjJh"PTšgH36( i=Pִ'H#-YYZA%16&!Dܛ5I #Eq~{<4i1;jXݱ)H.3-0U"EɍyQ  ̆]e2[r7#pLk/&H[CHϱ&ffCߦ+Wf:[|wz{%Èm oHS" {ua uhhyTc㆟1gF~c!3 f:nHKRz(hjDfԅ\vAO<}?ۡA 9tx`Dk565&O@J S>\z37T6j#XG'e޽ʟQ M j!֙ɗ#- *GM1(d#Z.N' MA3BcP_pRdS`8DPdhTuayy)ܼV';CPaDT7vw8r?ӕXE %K3g9c!u%26מu#45sJ# 1G>s3ab KrCkž޽b/`̦€1FrҽyqtG7߂l5L9:Dh_f( Nq&6H;ۙ>䡓֖ @h%>R 9T=+3aaE+D9%Mmq6g:H ʨ(5+0o$+-B9[hlk+%Њ^[lf`zZ!e8[0&,A!lQ)~͍VUq8w<_v z=o*{R!E.þ}5)WZ>fn*Afw:c'ŗmVHT4Z'ewnʗLGd*AlkoҗX|]ĸT(f"W~}u`:PrM6H/S9y (/O[gjlȜm JU<+;\Lf&%ˊm?b6\hN@ׂ*<՚RzD;81t)t Ӹ0i ;o{I2bԸf8NEN 9~HIwZK3n/ZeYw$ }hKV3_ PTāVՐCcBXw31;~ޟXfӫK! r>4G*Odioϲ{mYі%\F/ Gr~WGpWb9s݆l=2Bpg NXE5CՌkz&[üj vz]0jo<"vDZ͈¼{xaP#O*j'0_k^ j.[!vTKE`SyQ. Dn} ^y1CKi?Hn}8S0kh+@^.zģt e?*^+:njvDMgxÛw7 1z@{tYo =y֦jAYy;s9N"%/OGj,z#iwعXCm;`6];E XSTay NCvTTmU n,*YMpU ǹ0lWV7CjB["Y}+&glƒ^,ONHӤeT>* -biwJgE"]T9pND(põmDEOyqrɦI;p,s)fqM%EvSVYgiJ?}*lp5* i;称EM$6+8#wѢ>H293 oSaGp,o7K:9 #QzgJpVuv^ޤm] لHf#Qjg2_pЕ"sg>5swnL&e<&+|be~|zY{bo-dUhO٤<&z~.i^4L=@+3<ʤtՐ`1^62Vpz.BSLnx'HɫAT[[&D:+SK U iYz6YKiOIx$ Ã6K:@'L,KWUq++M;9WispxB:ϭE:Ni71&e/N]ZM⣄%'pU$2*ҬX8'SɉEl6񩌜o  RI,TN'Bu3L/?R곈g5-ʁXҤf#!iPpU 3>"Q}ݭ|xOj 9 ΎBT!2"{P&)A01qifܽ7=W1V l#c2՝&NM'К]0[*#OH57 N̟\Ж!-W2eeyI\`jSk-HLdG״KJr[54y)}v'rj@ZE{)H35u*tAs ܗ< ҂|}f;`rJ<дǘ>s2ХU᫊Jx@d6ѦNOjQ*zm]:55AJCOnPsttC+?Ɔ97xZŏiҶ},](v|)^_hdh0M^^X4U0eew.AAm([݋-I( #Q2<'hDetË)Mo~)@b=`gnABbOnN/}>)O4O@C,:-.*?pL:ܣTXpƪ>+d-BqHgq? UȊJ@E(񼬖W*)Œ*l0}x; ˜,ImFՈ?bS4u_?>C9*b`c1FH 4}b)m32TE $+byqx<>_į0$ iz zVˢxwk ]i5x̌Kul趝HHpVCK3$H!'mI7brA>R?f~ R e& 1N.6j0䞌&v[D[\K+D'F+Dpu7"! NJc>,VQMkЖ<+ČVH5>EP9ey&"M߈F#Ѥx(y!);zT ]f峻J62S0z`:NȜ$dNIns62KJҟn QP Ov#.NO5͹gAtl8: O-~sM}2sPei<AmcR:|6QA,+ S\3Nx:7S6&oٜ@ΡhO+>AN2jD*^P䥴(ZB :6J_.̢|xos'6 R |'TiV!45⸷y%Ci2oN|欌6?q7ėGBWyx9WNA**vm4VUݥ\)n;㉶{ \WiwqWbĴ|7h1:+Gr !612Xy_=fi3BeKk\%c\NDbaיh{WqnW<5ߦ2ߺSm''Lrr0_;k޻TCL_r/R8\8*~U[Qb v1a  avr!uLzkfg޹'ǹWɂ޷gⲮpngvNa7#"w|YWk8ee.ql9: =clʣe 4b8ˇT8!NL.1J+GI[I[vs+9akf^lHeꍕ\ElyZ[m-,+ ;;~"}c=W37kܝdq˕ 0 749>!wG6ڝ/qWZVCkC;3iƭPdGٙ;b pwLa/ZJhzj-B5s uctڜkbelI1:wOthRP5H,ҍ;&:VI8,I]&E/iҒkTXi64E*qeHC0_@iP0F.O0fXk1Mίld64 ^Rsy/A9< !ȱ5F4 w\^kƮa0kT,lW7xͮݎJDi|t>e4_UEmK$n4w{"2nWk>p^)<60ְ^S l/Ս oe^kjAF /j\:+} ;5z%4fq7_Yȗ]dA5.x X}4 m6i-, ςj_GDyNvv d-r{:? vd#P'PMZO[5+a8n̮-qs:~ 1pa7O^ b숋q"('d((/*}xIvdEX\ p8^pf9Գf˝FN4Eq)%'^tlq N8(>/ց)=AX_ =4]0QzT?V2` ;QNAFBH㕐J0pnb̟7U9&,^GF1ԣ^,H/6o>sl:Pb<' wtHjWkjkUϗŰ$&Q+3D,Jg<-k\}D5rck۟Z濴bmϿ@{v~BOTWN-+qlL< ӽ/&۹5MKk(|X7:v]Aq4ΪO`$JO5=h$=& ::+T9K!_1K1^6,SB}t̟b5'`=5$!s/2!KL[Vߒ8']N\*aeO[હoҋFP jvQͽKu TnR3}oax4XJK+#e%푊:l B9Z,|%[:1e'ށ@Զ1| A;TbC'lPm.Re羣J/[}[BVs&V:%֟ &Ki %B`YA1Go2p{K*ļ!cVo)xM\42`Z \*YA6 đk πGK?DfY$ۂdVጢ[m7^ך}^p:(HM 'Pن=szb 2x8w܄e=me>[=V/'ALKUIieffjqhΕ%JR!z7 dVJJTth(ScW"8kZ9eam@hQC9<ɟږp4U. ی4,_ǂG5hVϸ|aBfZCLN4˨~M'jwkL)-hjc*ߧVw^  gZfS-SZys|{꫆zjZrw:gskgϝ3 ?W?D6/]д%!Sug{蹔31=oj޹Iͼ8"sG̬e~ ?'>;M6E< kF*]'KҢGhfo!s(;Mvkʉ3{Lu^afċr<.*kȬˮ5/UA+;(- ٌGl£?9s#OOm՗"P^AAŽPά6aq€ICl:Јoty;'ٲձW5ybV$;j~=#GM/Rb X!LqέspoF 3 ֥mZJ)*ce6H؆7sf9j_XQΫBSRȩtNSUd9dbLoh%97eG.Nho*٤ R̽D >#>vI?\3pt{,oڡ/!R\EwFp>T߱@qt[6ڭfCsu2\XN@<>eXJ^e\_cΎ|CNKi j^QOX壹ze~`NT-)q{ƫ kqótgT:~΋ܑ1fɊ>!OШ8 -NCgnI-q:N7@џvsGnQF W⒙&Ts+kdf1g½Q66BT+ntQ桁[?? T{pNxzL#k1b8p[ʤ򨰤AQ_iwOJo[_6ߤjFO=Q.1.M{{/}}>F_7}7#}L'}Bg}_KBdU0f;3}GwWK7w/}}Owwfy <݈py$oybҵ7oy+ѧD|rf/Loď=>b`N(-;yT s4r+F^|~5Ϭ0yb㧻5"~?ڪ8N<W|HĊ(P<`g/b״pOuOP£v3gWsݲ> -oW?<GE"޻oG"I_=ܺ/h1dCǼ77A<V<(WmkMIŠucw#pvQh2=0``!Y yySEyYEqs^W5FZ@Z)In!> !d $I$kRC~]_WM(/b@&ӀZ'y O2B! aT0a D1L,gDfr`8qa=~ ~7_o%0*FՆ<:y"Ck ^xG|/w p』 mt透> GǠE8D0  JD0` 0 `,v5H&@&SZSK[r,J1QT]pf*h@ZMTi!7 ;@'jntH m -ԙ\Ä*! m\o|ᇆ@:"T JN ^?&@DׅEh#5QN w&?OJ18@\ŅDT H T ͡)F)*$(OV­T%7?A_Q20vPPgLfF]uBh <؜[\(_s _{}i;z6;Qs].EQ12-˞n˚wݮL;nI9W.@ v*M5br3m^Hh"7YSf۳/ėm78.p\_Ý^<4𱎎HOIp!ΕW!=p몣?Y'm+֫W wLO!.EO!ίrC_ VV,+=_XWuo@IH^<u;rO[b~2 *o$2IyRk5bLu{Ml2rqmN*Mz[[{fE9 ]N"3Ib}n>˝aN,* O8 E _ :-w@ O| ^mxgJG?)1I'ZRm-hDlS-G q))#l $ujƏkm)qVvo Uwb`!#ǀcmd2 H:ZNd; ƍxl#hf)VXhY夶b1c1q)r@zĈ?J0;&"Ə(5yn鯧Mi}ԟGk|,}f"}nŃB'k,yF `aJb (?@dDˎe^eO˺xie ˨0 zZN\ \{1MɶŊK{[3; <8?J:Q^I]G?Oh9gLF665b]&ud: zx=emOBBydo"(+=3YX KoAȋ,fAJ>~WaˣvmǑ:0 ggddee9@=HN9Y`6$_ G&L\ CH0@2g3s 9ơ6ǽA[;گ(;rNs0AK25.R8!)!Y!ɦ,D$#1nfJg3#B>MjBn0Eb-Qi`Q'm|x0 )!w'?'s8OT!M B$z2NĐ2|5ckـaDo~m?C4mU ~XJtRO*$|yr[qp*d_lnT2 NWpxn<7ύsxn<7ύƓK)x)x_Q_7(J(x)eU|pJAA^:Brg٬ ^PdC | i`!2S̬EѲ.Kf 4pa^V> 4hAS삢LM[CsUi>5- 1+Li_1.N= qPӷMӊ2 2gBopWbkVJ(UԵҡee1@GحdʜZUY Ij3rZBY3 )PN/Iq۳i/pHLaGKZ*) &O>;}N&Guvd0w~}%騯I^gGdeeQQ`2QƯvm9LM'!,Q$`%&8&R4^Ɨ !t6CC0uTE4J|R1OKhpVѭ*$-w!Papj4?kA@$TjܩP}/ӊrgɻjB~9z 9O%?ɏ[1AeeK*lC7?R1N%N^S7#:P^]b?C:Nj HfR1+G4%7<5d% ܦX%FCrmנ:\Ղ{5*6kjmw?p8>v;,a~y1O.FO{0`4ɼ t23ՏIL'Ni3 ݇TWԩJ3 Әoſ6J:+pp knǮr|>XrR)k@7| 3vuE]|,OcWmW%]ʋ+Ҽ_\kpV*>p-, mp-T%?p% P=ëA| /ǿ dW"kϼ:`e 9uv<_a_sКy}cm.Xꇮ#*jI?ILn¿gMHS7_Mnno;~ڿw~v|v/+1oL~{;0'G;~POo?}܎?gOy'yœ~cgmG^OyC~y>C;W_+yGzOxs/xˎ_gW|_ 䊍\k?;+?uO7nWp'=Y_m~ ތf߻my}lۆ7OtU2|;?}d.+ Kf +p=W\pw3|?rï[m;O0{aí cOb>(`! MᅢO 2 O Cb-0i| eV?^x3f찛i#n ɾ>&k. G+[xs r^!}/;WxG b?.)aX3e~ۿ 4E Ҭzo׷o;aHU?., wY0Nj|Ƕ0?Z?" +S"W[|՟~IVa_O Š7ngO.WX7_. +fKTV_0⫾VWW򓂯p>_nU=, +፟Ww{~spW}pf|-_=p~ =pj?+W{?'v~+j8! wKjx+++/ŷasc([uk{+-ڇ|W{7] +?iF|WRVq_[|7=ن_a0Š蕿蕯}o?V|W[_a6߆Hx=- +Q xj_+ 9ѲߒÏo{};e=y^{z9/Â?O&{Wxxj^13g<^p]N.R^^!?xdÈb;W{'=}.^ҫ^›s'?o6].|9)%R^}lG~+zoÈwof!WX{+bo] w_?>?0].$K%vvuWXQ}%>3{f?Ifox׼wŠ?,߆_~]Vy߆aw_aşoÈCkWX?7?yO?OVag ŠW #CFÿÿU?.+x0/=vRRү Ozzz_MW72?ϟX?^aĿntޘϯ~K/WayeÈ 2GVkÝs ͯGKʿΫu^0ï| oÈ9I9oÝ_l+W z'gygyG~+oʷap( +G=zc +aWCoÈw ~ {2\|oÈ>' +ÒU?zoOzwywy0:~_76L'+ozo$ Š?߆/0YWX_Ï$ ~گH& + ŷaWy/F) +y3/+ +={={W|gokRV?'^kNVv>ܖ}0?߅_ӟAR7x76ܩ6w~?v+_&_eV7omH{||F_ +6l?;_ʷaZ/şp+هq+=Wz 0I>u{ƿzV~?)s+/ rV`ݏ!u X '~6~¿ } I}!XU^M`?V}߾P`՗ V} ~3!M/ W3}V;O~RjXnX fH`OU=}V{ GV{_ X_X]'<z+=N?fx·yA^zY~ك_`' 6{= = }|/K3/ˮ`^_ϟ x5? ` ? oOM}3|_<"+= ߟ!_m -.fg3苋"2r01t`~9g R_`cQc:۶6Ţ Za~f?"_*d%: 4~?$(S 7>0AÀ@!@AO%<> X "nE ?(Ɔ POX4ܛ''؍^7fOD;3bi( ,@.ȽVسOv#a y W7`YX%89㰈T;艆vX<mjGP ;Kˎ?+7rVk,'Z'ˉrbF²c`Ej{*7UKV9QZYıj `*?d RD K&U@T^*/s6e /W]@M#Iu!!v eEʉQ!L( ʄxPY @w筊Z*xcmڼ:c've-m]y6[;i:{-nZW6͉/^]ڷuf69_!eb_ Y=yv+8.Qf׭Ll$q I[DзIr҄`v鼅bp|ԍz\-{nY7c@nfγM,t16's76/E8+ܤ]1@eVÛ7(Famm fxxMVCρB:r63-O "8fUlK{uESnd >'u`K$%;F!VPQx5m0=Tb=d,[b*3x7XIiw:zq5 YPMrj jIJl{6 ٔ8m,],5*Y"j.5kn+5uq8%Y h1V :iKٸDJWLqC26Jy K/).5 h̆VJ6$`a9bDP&ͨJh0di1+"霠A9fD : LK$*kQepHg LAn<}]CQxP.ն1NJpu:ۊdx麇fTuSvkYstq6 ҅o_ j KfT1VzU/G:kIJtwљ_;]{:ְb8N<]88n9>A[Ra>Q󥱜leS5iw_Ռm+3nkiب1= F/PJ]؊/G0Y j# KհRmdDitzX6aJZ aʥJ!m-.>L0 !5Mj &5I1\nVȮPF)R/H/rS;x܉c̉;iLBf%7ũcԱɩũ9~v|bdN9ࡉ|xđI~:=k9q Z750uhqjT/>13O&g>"xA$*a㵍]u8xYO )^N}>tRH :y!cɲλzӛ4u`+ ` { z&<<3qdqqGdi'&CiGsNkI;?c'N-N;~bMX*T2 Uhl ^H׏ .t8YC.0c{ `Z.PK<6V׃¬gbU,Gic,#}j 1 D2C}w,Kzh+9,/[Hc!=a4+eQy[e. Xw'Y) @ `gYNۇizSОNf&Lѡsq+ب!vDLg2ZHJ+=lF[,Q.N1mcKWE\:!UXGcG 3ArB + ,@<^䁰̚ucy$,}A-s&̟|O:I&vyrQJ q菔Kҹsӷ+Ԛ PCoKr$Q\Mc+і+\K5Y^rl(R'.^!Pɹ yCkꙤkTA7j *PEiCF-!'Y2J+VO1ȶR = HHu9lS I)=IgƲƨRj}ţ5UKM`a# cj4Ұ^bH*ö44+~6 $w,V|r.> z~Ʃc0IHٽΔu^,rL-]O@EG:i$Q9f1ݷxon8)CKq(! B p)WT"Ytp)ӚT`NWZX>]?\]T g"ֈ`0=#2<qFZNUPb&'.,E!4x 3^.~*"NM78z))#eA=Mqy\kqA\ %BCJBtuJf2u, 3!XNm~X &ؚ۠Eh\r&4XFD$]J؅#l9 IE @\V bLDtq#:s^&a5E &*ИMXj-^@6CT1P l $WLZ܀ٌ=F 2K2V&Cz夈@(Q_.yQ&4XYbPjl1TJQz#QyZaFrT.Cecob>hD7, R')H4Qy=HMO&Z*o ֽ5p(`C U3żqsI,GkOeؕv˼'>Si׾(V:OҘM#fɮdY*ܔTaY*JNVg5Dj%GĵpP$7*!tpFu0#L^yqUM( вVb" Ƀ̖ȕPRz&J~_$jB("5`  #2,oXB(-_ AeoW5hGVM.wlMtY/ESg#}‘"b H`Oˌd}-UӤ\oW9YKoR5=z1V.dmӸki jxTFԨ Lib{zxjR\E4$&˺,,5xD\`C*^Y XӐdШd Zt6YkIQuaTGpP,MFk*bgV4c= O"C]imrpWbYa=h'=q+dPTnXRO(I}ܬ( K vĴ2t(eKŢ2n㿸Wǁ>) ^"H5f$.Azܠ: |0jC7XԯT ̩+ĈD,厉E@j%47l(9cͰϜ P[ĕV!8#W0Mڳ\iSTA( $)Yt w۴mqA$} :OoEҘqڡW}Z=L6{QτOP\@OKdxP[BVXba&T0nE[><d &(OD~ہEXb%e iM!dnDthf^(FWxؠ>4vC9@$Xb \[VOo,WQ6˓IxݝO[&]Qa>mhͬ(%)rU^)7phXLR-#d{ ͱxmbyIv8:ףr rqʾ;KAW 4cB0ѨcCC+0њK {a(ISw<pʣޠ j}e8y FaV,0Zsd~j* .яDo{ /hZ`2VΙu{\n`n̜[rQNTW=ڤ^7?fUcT1",礿/m }5Q;{HQn':N1PQtyvʛWA '6"v!z"U_feBkի+ !Ϧ]Zm֋:pMyr|kОMD}5Spi2KҔ.,DkRTamܡߚGgMit7ۤMлR1{޹#w.3ӓSuA!}ptxxmn] hz )qӸ~&Dw0sЮLJ((b]stBhc @FZKQAWUFG[ yO(v}8F/L7A!ѡ3 SP0ql<{>Ёf͊]rx'f3-!5K|pfvypj51+u<9{5uh+[/wV0s{'[3 Ss]7NPNwl.Qf=]WD;EG6L^#C;mv3ք1Cӓ ]+CZkw(u%<kAA8twH0x.5mƏN_.2 we MeoNC23泄-NONO[p[~˻{Jd̲ Y;|^aڵro7br`Ӷ,{rڮ9 .>xk6XNw7!3ligN/$!Pawsޠi^C#5+i'h47$ќv& qKݺ/ؙoVITfڨT83E<0$ =|y!>`{OulL"J;$R\nO2k#. I'w,}\wSfz6yldcAdГY07#'o92dH#aZj]HccYgWmp19օUTR =z.JRwxW΁2P>u`ѼCT"qoonr9///hf;|O5q8R t8#S99yncox]ko?Z=yMi}Dny c1]IMҌ.{B">]JGMj:gWCپWsr^ʉm\m9F c@ c;F <`PGnb*cib<9Qh;BW>>$ߪ ny@@YIU ?~f8#6zpk0 }펝e_Z\=m4\[Exݤ(#=Z\Z $w=5`TΉ;dBJuQ xn~X:N,[N}8.nz&K3>j%apC!٬O6)Iwȩ~)㰏fPQdA)70,1h7JcיS=~WC:d8x*/.97?fc=}3g-Xn.]Tiow!D4ۥ| "^$=k1Cd@xrk{v w Ofש00Iіa;9ԥSWNJZC'?TLX&N8ydx=>N2+WIlxq{sR~bISt"^084նUo Cw35^w}ؒIW={p): U{nx`gAҮ։`ݙT[n>YL֩r0 {Y gB2dˎفդ3vEr'ި} "rO;-%lD0G姧yZߨVH aķ|T1+u"⠵#~N`ߤ`W 0j8b!ImАyNkdsP[免/yѽȊnjl3oG^p6.`X%Л#!i mq|7~¡_yאldUv1F*~*do> k a?xe<]Yv{iÛv 놶@ĸ=5AAv5==Rf r.;676zF <u_^=.:ͷkV'A2@7XdGR< vSY3U A^{'0B3ipd蝜e̷.h#K.kkK@{aӾfs߮QڵmWVln1`H{;WlCXӾ涛^inFe/IJ|zz¾[\}SvJ&o_xAQXVQmB!8cpvl', VX0$J妢,ma/Lg_9;;g&6ӹ lW's #q[Ӭ75XnS;ve>nBS#Nfqe8>#,OԪH-%{cPd_^i ~||G"<ǒ'H0:ޛv\' 0 كWڰ|[|f7{ϳޜ_5\[18utؼa-I>7i^O:ښY?NvNq۳6h3>gwtw i{ f(难]:[@}tʩ DKd&v4'џGaVsq7r^x09ohtJɐN:O$QmDeИrBckčE~9u7t7^9:W28&% :boTieoJ.ϓ>OrSn/r|ӵCnMWP8.|]]$A닦]9+Kc 5!7 -ոNYU?y\KZqQBW,aQ>k Zg+,xA]vƴ= htx 1ԍ $ ;4mbEFq1w)0U")úYW[5 Slfs'Ñ 2AaL ny6..ܟmiԉݗBr. hNˌ[B04y/}94uؽ߀]>4բ5%jeckG&L_9o:MM2=5js3S=U;(&Ԕ`Z=%? yFw.FFu #l" a N) Rj'vLw7 8DHoSŽBS s@kiv=LwEkmcŇG%yKM!xpXnrkA$gڮqzkHgZMK+XG}JWEN]Jf> {хe)p1yր-ƓQS=gZlԗrnk-^8F6uE&s~e$xPpJWh!x C"7A#kp4,WQO-kh( 42XFU#zK$dE˯Fuyd5zmnS2)e˩Rt-#vדj3-cѕzTjQ,2פxI!EZokF!IxEacP}#to#ńhݴVM*0v&&n%WfOye=>nx /lE)`-D:,֌, -SIpgM8'XyY `Ve "8^T{jbFayԺCzbȵrieq{+DSE/WhޅO)1P8!-רܼZȵӀ vy2_d C8~kT'V?b!w3δ`*! %6 v塶R"U 3vU`ܹi0_[ʀ|YYP٤oYm!_On0b94VAX.s}cdRcE;x챮fIh1Xyf[rrI"W(w * KP݄9gIݥ6W2hUȶ"Qy#0:lϸ$lv&6dˉn>[b {djZG\@-:Qy=HUޗUtjGKe[*pĮl3yKx k/qɏU.IRbbZBB\wL20ج6uDW=_`⌦jxyf]/QTjѲhϞ9!4-( X N*?z)JI)|M,\|DGJ¡cG'2]X,ymFGr D8Vz%")f:k-ȵbhDkrĵte1(rkFjeMZtt׵wqov.c;\[ףּkuUl*Ƿ$aA4^0}/1'.%K<_l*ZiAq 3&ǝx G wuFF3ٚόG#t= [܉,Li'0 :ZE& w|~&e?aK@ٺۺAi Fw ]5ت:̇߷w<ћ=F{o1lR>IgGܩn]ӚRc'=lreykj9N  lE=E is,ŞPA+d<.)PP -<^p3v-pkUvl~& $U6>` 2>,f,FJddikFESj){i/ƅVBTcՐ唆%~3es6: 碥 GnѦ8uK IZ90: P. |d?Rh9!Pqo[uJ!4(DRopkZyZD!Tԉc-zadۉ-`2& g:U;אh%K b}jaG2`.Kn#c3.ohiǗ-쑵 )ոʕ\Pt)hȍfz&TfU 'X¥qˆ.F\H@|e?$x`d685C5hb A~^r[^tbQ *@aLd[6x73Juq$Z#]wve3%@ KcBs_ k bfBp9qeG [&N(&+\ !.S6pb;.GMzN NPIqį<vl?:C3_X*QDg{ lSڋ20r܄-F$!_RR6;8&Y4;,4iHa͚|R6N 6AV*]M BcЍ%ENUp(N2 x ,uʪH̔?YyNVցH9'g2ܤ҆h)@~g=SE-}q\9~_gO+_맵8n2>TׁUr}2^яqK.VrQ.[d/0e+/S٠e;2)m|3ϢٞENA<ްөSIh9Bcg6ϥ<#lgV$꼬[QKl>3)]U (m*me(8')`^Rj]a%E<38ϙuV؋.LA!yDCsƤRqjQ7KA&*d9[G#sO8% aT75BB濴\鲀T#4Ák&Ud8hl'\l[dկ,Ñpjnwj~aBV&>յHpLpËSsssJLn1d7~GѨ7Sϛ?q4<|$]{<FK6oáZi!MpqaxjKQ/eȜ`MdJƓCqO05Qj=w`*k٥poPw.SDLLh)FɅT)Dgp@f6U%c hi Zcoc@pLCV5pЭa\tj;-luQ$-": SKTL8v9~h H=H&+rfN֞CXOjw!;G{[~ǝSFbX`c`˨7Rb%Igt@8f~=V8'r fɗyUwb g <\Z";il坒J&i럔4h_30r߈1NKK\C& ,_B䬢FԵK]\c)QAOfz]сIR4Rͤ5* @wLVNNGיZժV VI7qJ:km vc,2%4!W`J QhR wRrkF=YYM)0 mNG<U6,eL(ҞBfxU&#yTs/vOMd;J挹M`ŷg,ƄQf(-i.M^ge-=@Ra&4zWGOBf]IBDUu 7+a[`1Y U%Re+.oʛ ZGÍ8AV_(-m i[Qy+z6>}VK%_n:& )gcUb, !$S(t(Y{|{ mcHc%"Kb! ĸ2IOq-F2S"OfBtbNnfe 7fą)`|Ik\xcɫy ]+r@\Sn\ĻfqqΉmG,{Ů䍤̨Z ? 3ؖ e,0h4riaְ@Ɔ6aɣ1K 4[ivBzS0zwq5QDA7h]oKa&F47kPf$(?ǎMOL̓t]FieUۚ}4@2L$t=~ML,E"R l: ]Ck0cX>+bµزXsiPz!D*w|%qF\fƃܹ=[i0xIր=;X wa<qAn Q(r0jҤܤʁ]p*sU]^ iPjk Z=;hU|ߗR7 =ȉ -0p$E ^O-&DeJ-HJ`-.mj㍚gwwW<ꨅ`4{Id,x_mw'vCm7!\A,p68Hek.WE;s.CS)؆n=JŷU"{= 93n:wAI:83-ggFpzl7k5X<~#n73 *ÞܝO[!ѩqs!U]DOc~lbt1sD5Y/AN V4Oi;U);,|+A*F-d2xs&9+Poc $=FҋP= iˇuɿ"BO?>;GhC.Ca!= Ġ"'\`fjQKdžVKrC!-zJĂxþMͲ7 ZT)T+CǛK8t(IV6 `@Kv‰rn^Lvr+akŲ>^=E;H9墜82{εIooon͜Ǩc,EXI_(Ahjw-MEt %\]:T\TG:aRCnVŇ`<4eT[__/,G4 M2#8ݦG9^2nȊ~j^GrY EA:HW+DIB\j:\|kܲW)a)(\ݩjI궓m3o:XPT] 2`/ CCӇ''*sz~av^imP( sG\' g'%zܺ ,%gȿ%(.ס iuB>#,b%NtyPl5)Ci۞||`N,zT~Ξ=! wtp䖽#G>gd$==jBnTԫFtly{qGƿ^+V j{v?::w{_~߹^ W&A%7D`ɶK.j&I00Vӑ[QP++@Z`riKʞS_1bfv|ОNwHZRӍ])9ҏ/P ӏG@CS# .<{!*qjz *cΌwWyX:h68. dvZP6Hs314a-L tWİ4@TMAB1@xT6`S%a8aOj Z> ipq!'pkk KuR$Y:BġKZsi fı^rɠrǻϬJ)LZ'Zu겜Ԑ9 dO#gk6mW[mDꢽ-Ҹ酩yRRSھ"^qP8\^д[OT\=ׄcfoQtÔ90YfG;Eo~LC_Y !s ,8Tbbӌ`:*/#|׳kxh01Hw:V%DC{hX ]^<7ŨF|o^]Bv"w.,@MJˤ, =JT5upwz)CH t̨ǁM}&cZD&OEc$xqI3c[ȧYhkJvExt`2}n\bZ &}BЩ95qXi0wqQaDߓ)7eSR03(.ԚW"Μ ;͜WW߮foFcg"D|:$ՊnXigV`RHOX*+99u[`ꆷueQ_Xa&dEю Oe;n+MV*+v1JEy%Nx.D:TV _p[&'RYs ,Ȓ6g@`ŁAZUkq=RcCC] xjVH1̰[Ep}V" t+ĦrPz(6dpUnM;>X&E̙SXőׁs84zc4kL9~RRװ}t}[H5eT =k@33;zjDЌv~XêP/&E[֫hO$;jH^{ST!tm"W {!iUb\b/CgJGx 儂E(er2A}PcXb ՘NxdW 2^@r>Mˇ" 簔53Zd=^(`SYYRbRNWP K#! G HȠǸDT+g}Z!i^&jִ3Q=Y(- iamweף$.})k .3^>$(ٳk3.fdGD4[`GI;{D:FQN("gc11a&y=3qC 89#@h CxHyt$_'NC2=eӕkLuGȨwVMIlVvPvQ_>{0߫&4hcԋA4wY"c-CÅYd S SC'N!4 &Ǧ(MHݫ L FAl#o9m:! *ZTA,쨒N} @E)چVF[b@#fX lm8@|Xģ^dũ @Wm:"86g篻8=x9Q޿0=++ ,B17H|#ÙLXQ}l v̶n8"hjKp}@yPr Ռ!c1*GI^XTyR-lD*=-e&@@d'fH Sؤ|6/!;i/y=8 d+(^iø 3/ kV4`߼@ܫ X|PyϞTI= T);e"l宫^? 1W#)ѠrlXTkq1ZҖE»T1B6Ia92zNUm5ܩ0 {9ԩcL;blgj6[K$g} 2,}"esBJQ5.KJ\!{}R>8V@{s||Dyy_:z^`EFѾ-iL+1L$rxˌC~6'B~Ehp{ӓ|VR²"jvᑁH3Rq|fe'\?>_xt6;g^oϞ[{,>PA88NTH]h6$*atϕܣ@Kd=,1IZ#g X]G@ mh7ṫrrj "V׏Pâ7>j3Bxgu,*_E%܋1zid㽃SE? ĻݓB>I-\4*47b`SB"Ee']x%lDi8JU|mTv!i+Xf T1 w=r۸ -m rCX\*is :j[ݸT9; dyZ|`,3]iy'foBq4sySrC,W b, H˜K89!$vClj`d" ܆) 7Ñl?KVN<>4x6D[@Hx\}lDq$#JyZ$-vDmX@9YYv6tw|ہM.2a W2Q\D3 Y_sРTDI9nW6O w.С3 tM9W%p $} \IЫJxTn,L7V#a.ĩR\Rjaˇ }ue6tx3,SI?xFYF-xr -.=Str?L;1b{ٶ fwTxO.iฑq4)u2t{冩/ D0[=jwG#pEAn-樝haǘkZ!JeHmҞ6@d)AM7ۡChg.|aGȖP';Bwg؉0KxHw4f[#R GAۯ4;E?`egqP7KAJy?(`Z񾾆ZeUj1۫8R=B(f5ӟ~#H])8ȌqsM.3bA!Q9'֧:{d edɀn^פɑ"fܨ!FTCuaL $N '8:]I0ٟ?mfwbi^;LZQeZc@ߪLEjn5tȫ}9ֳ{x7ޥFSd$3q'7YEhh%Yz}z7=S1ǽ`QVY")GBwxA MRaq |d^&1d#ӇҰi'x}d"nHjX\ĕD*l"3+dc"OH`%H$C} K7@!9+uE =-Q<3[/́zuq$q9@f]J _lTzj(f6v#McrܰD+2d Q~# * ?@!'pGeXԮFdMuE|P-33lc$aI;*颞ǝ^\ib=ɸr*;vD?{8G% 'ϳgZT/+yMNQ-=zGnh6ouD&ũy)Lj_S=ދ"^$]zh* hڲ/ ;=VG"' Rxy%|8қaZxIZ@C۸Nh40OsF2'a &mvDRP%! .R=V 9Z]^"*("mٱOv\3iN=Su Zc9Db⤵|I r`)jבε]˕>an 3( lHO4٠G7bS%[9H6lsLGÑw𲾊\jJ*I!*&*UepDe[Ɠۡw,<˧8{pQ. ItD/Rs=R#dSRf~FoRܩ]gNv;.C!?8$֢ʯaA7e?]a@,UL19$ԺH]udCVd*8oF͛Q}#pOA>8г&jf>Ƶ ܼ,/Q͍,oً (7烜}$KwtFL厭l h[B,+Tj9igHʎ5;#z >+J:;ȱ^qS*O,AE []|8Nbu?"MGj+3%9|p=)Z,G͋%[$a2cԴvVm|P$E_'umm}/txh@Pp;Ѥqm{jeeΣ6F:v9A)[4jmBXykt:ftl7ϦGwuYy哹TjN>i܅8܏dDPG5[ds 3k]4=fCuE͇LpБHkZn|r3Bs1nRM82V1S6ԦWu7 'Cp3BvūljQ-"5!2ڙ+FMSz^ԛ*Otܽ {>;{ō  UjAC53\E Y`=)DpƥVIiR+J:3w B߼Kp~N\T̔|R>̭yӻ(1̗h)Քԫ eYmP/I.f+H0 bEŇ",+Xd2~C 5|Y۵m,ŋZ]XQl iѭFCr?:X5&t/u)-Q`vާ+D .ib5?97u=} 3z{X[X^kmbFd/ fm+~`Ukq!AƈdAPms,IQ瞻HK`>$(DǷs_2/"ߘEdv}9`S ґ5EM6Gaeq4b7sЊyԨ(5eH9DT{ɲT#PB I{kJg32H*ۿw S0Z+9X2s-KW4xZT,ݍ"KUtmE ^ [EB zURK2a7pv?p8ܱadQO2vGGk֊86k~%\g.N"m.zշosFX.HpIUpN)SZMMvxSqyEZiUb=/3`[nC7I-ߜۈ]Ϗ{~a8,i9j=Ef!.DY-Y$ทE;[eC++ BH訵e+ %|a!RZAnqSRyIq]鶃9'A<.ٚt=x5܏_^c01FNfJ9{Kĺެ,Q$'\`+9X&O OMx0h%5}5ɔ_J,ecuov$ XdFfs4N!ƥ+lQwΡ8Q!b: t8rZJn=BdiN7^kAC^H:F5Yip"p0Ѓad< !mf˿zY\K M &?8nI/5qon"RHDVG0^L5Ow"dwWsѹ? m9IGI0-z ;TuCAt|PJw|ȳ0Q@߇kR tN F*3 LAnqz;BSt#-Sبs[=|yYTD$Ԅ @)`z@ >$1GmT,UT'(.90pD! <'ݱᴥ rO]f?tJڋ2_I;O{AFAf\-,t-85.]m+Aӊ7\c4i p>̀LR|ٝ^[[q 3{Llպu'اva 6{`8|X"aLXa]ԙ|1ŪE:#f2m(4=m)\a7!ڵ[',0q8M ӗ 0y GMh/kݻ^vLumm7(!XhL&g_b76IwKި bۅ`\u/[ {03kǷ@:ܗkWIFMI:M,z2`b#(PT MBܹaqӪjBklOeX\*}ފ"|,&+_'yW'tګ/cڭPd$LW\ElcrdV)Rh q č]iv cތϏ*>O0H"0Xf40Ř~%n f/2D m>HM {]FD629dϜub=EM  rF_׈_x8e|U vo DM:uELH/BDmSBdÂ+8V $'z' FBXH|Xþa}\N&W;;aKd!Q꺿8Y@3H @S*3Iwӓ(/N)"'*ɆiKP[6iddJ{_89Ptx .xN g,L&[0ibPDO'!, 4 jT-KĹO~ (㏾B`>jSꓣ+pHvұͮg'.=!=`MZ]r)y1¼; w4 (A6h|tT:>㌤G+b3bURW7@b{- fqT| r:]o[Ⱥ{⣤>ڲH:tJwHFeMx3X-m9X9( r7Eaؽ~#B9n$z>{P퉥Z{=~m>"kҢaH?}P> <:H׋6:\Bn]=ou¹m pRA\D}7^Y`T+:jZN.y[żUTd2~ tgIjN3LJEO !x VgOz?+Deq pWHQ@iCͥ(:KۢC 2g\cԱzKCVZ jIČ;)o5 !3_9a麌o#糯MT?:UnixAgent-2.8/macosx/ocsinventory_packages_setup/000077500000000000000000000000001372663377700224245ustar00rootroot00000000000000UnixAgent-2.8/macosx/ocsinventory_packages_setup/.gitignore000066400000000000000000000000301372663377700244050ustar00rootroot00000000000000*.xcarchive app/ build/ UnixAgent-2.8/macosx/ocsinventory_packages_setup/OCS Inventory Pkg Setup.pkgproj000066400000000000000000000554541372663377700302240ustar00rootroot00000000000000 PACKAGES MUST-CLOSE-APPLICATION-ITEMS MUST-CLOSE-APPLICATIONS PACKAGE_FILES DEFAULT_INSTALL_LOCATION / HIERARCHY CHILDREN CHILDREN BUNDLE_CAN_DOWNGRADE BUNDLE_POSTINSTALL_PATH PATH_TYPE 0 BUNDLE_PREINSTALL_PATH PATH_TYPE 0 CHILDREN GID 80 PATH app/OCSNG.app PATH_TYPE 1 PERMISSIONS 493 TYPE 3 UID 0 GID 80 PATH Applications PATH_TYPE 0 PERMISSIONS 509 TYPE 1 UID 0 CHILDREN CHILDREN GID 80 PATH Application Support PATH_TYPE 0 PERMISSIONS 493 TYPE 1 UID 0 CHILDREN GID 0 PATH Automator PATH_TYPE 0 PERMISSIONS 493 TYPE 1 UID 0 CHILDREN GID 0 PATH Documentation PATH_TYPE 0 PERMISSIONS 493 TYPE 1 UID 0 CHILDREN GID 0 PATH Extensions PATH_TYPE 0 PERMISSIONS 493 TYPE 1 UID 0 CHILDREN GID 0 PATH Filesystems PATH_TYPE 0 PERMISSIONS 493 TYPE 1 UID 0 CHILDREN GID 0 PATH Frameworks PATH_TYPE 0 PERMISSIONS 493 TYPE 1 UID 0 CHILDREN GID 0 PATH Input Methods PATH_TYPE 0 PERMISSIONS 493 TYPE 1 UID 0 CHILDREN GID 0 PATH Internet Plug-Ins PATH_TYPE 0 PERMISSIONS 493 TYPE 1 UID 0 CHILDREN GID 0 PATH LaunchAgents PATH_TYPE 0 PERMISSIONS 493 TYPE 1 UID 0 CHILDREN GID 0 PATH LaunchDaemons PATH_TYPE 0 PERMISSIONS 493 TYPE 1 UID 0 CHILDREN GID 0 PATH PreferencePanes PATH_TYPE 0 PERMISSIONS 493 TYPE 1 UID 0 CHILDREN GID 0 PATH Preferences PATH_TYPE 0 PERMISSIONS 493 TYPE 1 UID 0 CHILDREN GID 80 PATH Printers PATH_TYPE 0 PERMISSIONS 493 TYPE 1 UID 0 CHILDREN GID 0 PATH PrivilegedHelperTools PATH_TYPE 0 PERMISSIONS 1005 TYPE 1 UID 0 CHILDREN GID 0 PATH QuickLook PATH_TYPE 0 PERMISSIONS 493 TYPE 1 UID 0 CHILDREN GID 0 PATH QuickTime PATH_TYPE 0 PERMISSIONS 493 TYPE 1 UID 0 CHILDREN GID 0 PATH Screen Savers PATH_TYPE 0 PERMISSIONS 493 TYPE 1 UID 0 CHILDREN GID 0 PATH Scripts PATH_TYPE 0 PERMISSIONS 493 TYPE 1 UID 0 CHILDREN GID 0 PATH Services PATH_TYPE 0 PERMISSIONS 493 TYPE 1 UID 0 CHILDREN GID 0 PATH Widgets PATH_TYPE 0 PERMISSIONS 493 TYPE 1 UID 0 GID 0 PATH Library PATH_TYPE 0 PERMISSIONS 493 TYPE 1 UID 0 CHILDREN CHILDREN GID 0 PATH Shared PATH_TYPE 0 PERMISSIONS 1023 TYPE 1 UID 0 GID 80 PATH Users PATH_TYPE 0 PERMISSIONS 493 TYPE 1 UID 0 GID 0 PATH / PATH_TYPE 0 PERMISSIONS 493 TYPE 1 UID 0 PAYLOAD_TYPE 0 PRESERVE_EXTENDED_ATTRIBUTES SHOW_INVISIBLE SPLIT_FORKS TREAT_MISSING_FILES_AS_WARNING VERSION 5 PACKAGE_SCRIPTS POSTINSTALL_PATH PATH scripts/postinstall PATH_TYPE 1 PREINSTALL_PATH PATH_TYPE 0 RESOURCES PACKAGE_SETTINGS AUTHENTICATION 1 CONCLUSION_ACTION 0 FOLLOW_SYMBOLIC_LINKS IDENTIFIER org.ocsinventory-ng.agent.macosx LOCATION 0 NAME OCS Inventory Pkg Setup OVERWRITE_PERMISSIONS PAYLOAD_SIZE -1 REFERENCE_PATH RELOCATABLE USE_HFS+_COMPRESSION VERSION 2.6 TYPE 0 UUID BC109A21-9EAA-4729-A1B3-A6785D957867 PROJECT PROJECT_COMMENTS NOTES PROJECT_PRESENTATION BACKGROUND APPAREANCES DARK_AQUA LIGHT_AQUA SHARED_SETTINGS_FOR_ALL_APPAREANCES INSTALLATION TYPE HIERARCHIES INSTALLER LIST CHILDREN DESCRIPTION OPTIONS HIDDEN STATE 1 PACKAGE_UUID BC109A21-9EAA-4729-A1B3-A6785D957867 TITLE TYPE 0 UUID 225BE162-243E-4A1A-9060-15D1A23BEB6D REMOVED MODE 0 INSTALLATION_STEPS ICPRESENTATION_CHAPTER_VIEW_CONTROLLER_CLASS ICPresentationViewIntroductionController INSTALLER_PLUGIN Introduction LIST_TITLE_KEY InstallerSectionTitle ICPRESENTATION_CHAPTER_VIEW_CONTROLLER_CLASS ICPresentationViewReadMeController INSTALLER_PLUGIN ReadMe LIST_TITLE_KEY InstallerSectionTitle ICPRESENTATION_CHAPTER_VIEW_CONTROLLER_CLASS ICPresentationViewLicenseController INSTALLER_PLUGIN License LIST_TITLE_KEY InstallerSectionTitle ICPRESENTATION_CHAPTER_VIEW_CONTROLLER_CLASS ICPresentationViewInstallerPluginController ICPRESENTATION_CHAPTER_VIEW_CONTROLLER_INSTALLERPLUGIN_PATH PATH config.bundle PATH_TYPE 1 ICPRESENTATION_CHAPTER_VIEW_CONTROLLER_CLASS ICPresentationViewInstallerPluginController ICPRESENTATION_CHAPTER_VIEW_CONTROLLER_INSTALLERPLUGIN_PATH PATH daemonconfig.bundle PATH_TYPE 1 ICPRESENTATION_CHAPTER_VIEW_CONTROLLER_CLASS ICPresentationViewDestinationSelectController INSTALLER_PLUGIN TargetSelect LIST_TITLE_KEY InstallerSectionTitle ICPRESENTATION_CHAPTER_VIEW_CONTROLLER_CLASS ICPresentationViewInstallationTypeController INSTALLER_PLUGIN PackageSelection LIST_TITLE_KEY InstallerSectionTitle ICPRESENTATION_CHAPTER_VIEW_CONTROLLER_CLASS ICPresentationViewInstallationController INSTALLER_PLUGIN Install LIST_TITLE_KEY InstallerSectionTitle ICPRESENTATION_CHAPTER_VIEW_CONTROLLER_CLASS ICPresentationViewSummaryController INSTALLER_PLUGIN Summary LIST_TITLE_KEY InstallerSectionTitle INTRODUCTION LOCALIZATIONS LICENSE LOCALIZATIONS LANGUAGE English VALUE PATH license/gpl-2.0.txt PATH_TYPE 1 LANGUAGE French VALUE PATH license/gpl-2.0.txt PATH_TYPE 1 MODE 0 README LOCALIZATIONS SUMMARY LOCALIZATIONS TITLE LOCALIZATIONS LANGUAGE English VALUE OCS Inventory Pkg Setup PROJECT_REQUIREMENTS LIST RESOURCES ROOT_VOLUME_ONLY PROJECT_SETTINGS BUILD_FORMAT 1 BUILD_PATH PATH build PATH_TYPE 1 EXCLUDED_FILES PATTERNS_ARRAY REGULAR_EXPRESSION STRING .DS_Store TYPE 0 PROTECTED PROXY_NAME Remove .DS_Store files PROXY_TOOLTIP Remove ".DS_Store" files created by the Finder. STATE PATTERNS_ARRAY REGULAR_EXPRESSION STRING .pbdevelopment TYPE 0 PROTECTED PROXY_NAME Remove .pbdevelopment files PROXY_TOOLTIP Remove ".pbdevelopment" files created by ProjectBuilder or Xcode. STATE PATTERNS_ARRAY REGULAR_EXPRESSION STRING CVS TYPE 1 REGULAR_EXPRESSION STRING .cvsignore TYPE 0 REGULAR_EXPRESSION STRING .cvspass TYPE 0 REGULAR_EXPRESSION STRING .svn TYPE 1 REGULAR_EXPRESSION STRING .git TYPE 1 REGULAR_EXPRESSION STRING .gitignore TYPE 0 PROTECTED PROXY_NAME Remove SCM metadata PROXY_TOOLTIP Remove helper files and folders used by the CVS, SVN or Git Source Code Management systems. STATE PATTERNS_ARRAY REGULAR_EXPRESSION STRING classes.nib TYPE 0 REGULAR_EXPRESSION STRING designable.db TYPE 0 REGULAR_EXPRESSION STRING info.nib TYPE 0 PROTECTED PROXY_NAME Optimize nib files PROXY_TOOLTIP Remove "classes.nib", "info.nib" and "designable.nib" files within .nib bundles. STATE PATTERNS_ARRAY REGULAR_EXPRESSION STRING Resources Disabled TYPE 1 PROTECTED PROXY_NAME Remove Resources Disabled folders PROXY_TOOLTIP Remove "Resources Disabled" folders. STATE SEPARATOR NAME OCS Inventory Pkg Setup PAYLOAD_ONLY TREAT_MISSING_PRESENTATION_DOCUMENTS_AS_WARNING TYPE 0 VERSION 2 UnixAgent-2.8/macosx/ocsinventory_packages_setup/config.bundle/000077500000000000000000000000001372663377700251415ustar00rootroot00000000000000UnixAgent-2.8/macosx/ocsinventory_packages_setup/config.bundle/Contents/000077500000000000000000000000001372663377700267365ustar00rootroot00000000000000UnixAgent-2.8/macosx/ocsinventory_packages_setup/config.bundle/Contents/Info.plist000066400000000000000000000027671372663377700307220ustar00rootroot00000000000000 BuildMachineOSBuild 19D76 CFBundleDevelopmentRegion en CFBundleExecutable config CFBundleIdentifier org.ocsinventory.agent.config CFBundleInfoDictionaryVersion 6.0 CFBundleName config CFBundlePackageType BNDL CFBundleShortVersionString 1.0 CFBundleSupportedPlatforms MacOSX CFBundleVersion 1 DTCompiler com.apple.compilers.llvm.clang.1_0 DTPlatformBuild 11C504 DTPlatformVersion GM DTSDKBuild 19B90 DTSDKName macosx10.15 DTXcode 1130 DTXcodeBuild 11C504 InstallerSectionTitle config LSMinimumSystemVersion 10.15 NSHumanReadableCopyright Copyright © 2020 OCS Inventory. All rights reserved. NSMainNibFile ConfigInstallerPane NSPrincipalClass InstallerSection UnixAgent-2.8/macosx/ocsinventory_packages_setup/config.bundle/Contents/MacOS/000077500000000000000000000000001372663377700277005ustar00rootroot00000000000000UnixAgent-2.8/macosx/ocsinventory_packages_setup/config.bundle/Contents/MacOS/config000077500000000000000000001374601372663377700311060ustar00rootroot00000000000000 __TEXT@@__text__TEXT__stubs__TEXT 66 6__stub_helper__TEXTD6jD6__objc_methname__TEXT66__cstring__TEXT:^:__objc_classname__TEXT??__objc_methtype__TEXT5?z5?__unwind_info__TEXT?H?__DATA_CONST@@__got__DATA_CONST@(@ __cfstring__DATA_CONST(@`(@__objc_classlist__DATA_CONSTEE__objc_imageinfo__DATA_CONSTEEx__DATAPP__la_symbol_ptr__DATAPHP__objc_const__DATAHPHP__objc_selrefs__DATAPSHPS__objc_classrefs__DATAT0T__objc_ivar__DATATpT__objc_data__DATA8UP8U__data__DATAUUH__LINKEDIT```0_"0`@@`bcda,k P88Hj">FiH0}}7^2   * `~,/System/Library/Frameworks/Foundation.framework/Versions/C/Foundation 8/usr/lib/libobjc.A.dylib 8/usr/lib/libSystem.B.dylib X~ f-/System/Library/Frameworks/AppKit.framework/Versions/C/AppKit h~/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation p//System/Library/Frameworks/InstallerPlugins.framework/Versions/A/InstallerPlugins&d)dv0IUHH@H}HuH==HuH}HH5;H=S(HMH}HHHEH_H5;HI(E1DHHMLELMHEAH-H (H}HEHEHH@]f.UHH H (H "(1AH}HuH5F<H=:H}HHuH°'H ]UHH`H'H}HuHUHEHi'HEH;H5:H>'H^HUH5;H<2H2%'H'HUH5;HHH+H'HUH5;HHH H'HUH5;HHHH'HUH5;HHHHEHR;HHUH59Hz&<+1HUH5#;H2HuH=;H4>H=9H}HHUHuHHU-&E1DHUH5:H2HuH=:H4>H=r9H}HHUHuHHUE%E1DHUH5:H2HuH=:H4>H=(9H}HHUHuHHUE%E1DHUH5H:H2HuH=Y:H4>H=8H}HHUHuHHUEO%Eh1HUH59H2HuH=8HxHHxHpHHpHhLhLh$gH%HMH9H H5*8HH$<HO9HH58H$HuHEH$HEH59H}HXHP~H57HPHE$HeHv%H5%1AH=s7IHHLLHH@LH@H8#HH5j7HXHHH0#H0H#H8H#HEH -8HUHH(H H56H HHi#HH $H$E1EH56HHHHH%#HEH56H(HHH"HH"HH"HEH a7HUHHHH55HHH"HH .$H#E1EH55HHHHHY"HyH55HHHH0"H\HHH"HH "HEH 6HUHHHH55HHH!HH s#H #E1EH54HHHHH~!HH55HHHHU!HHHH>!HH.!HEH54HǺ !HEH54H H=HEH54H H"HMH5H H5i4HH H"HMH5H H5@4HH| E1DHEH c5HH5 4HW E1DHEH F5HH53H2 HEH /5HH53HǺ HEH 5HH53HǺHEH 4HH53HH!HMH4H H5~3HHH!HMH4H H5U3HHyH!HMH4H H543HHPE1DHEHlE1DHEHZH`]f.UHHpHHHEHpHhHDž`H`HH3H52HHHXHB3HH H5!H=-!H F!E1ELa2HHHLHHHLLLMH$,1HPHXH52H HXH51HǺ1HXH51HHXHPH51HHXH5S1HHHHH1HHǺ@HXH5y1H`HH5i1HHHHxAH*HHp1HHHH6HHHHHHHHH2HH9>HHHHHHHH@H@H50HhHHHpH k1HHH5/H0E1DHHIHHHH9HHH50HHHHxAE1DHHHHH1HPH1HXH1H`H OH HuH9 Hp]= f.DUHH H}HuHEH}H2HUH50H2H5/HHHEHEH/HHUH5.H1ɉHEH1ɉH}H ]f.UHHpH}HuHUHEHEHEHEHEHEHUH5N/H2H5S.H"HBHEH} HEH .HH5-.HH H5.HHHhHhHH`H`H+ H{H5-HHuHEHHEHUH5-HbHEHUH5;.H2H5-HHX8HXHH5v-HXHPHP HHUH5C-HHHHUH5%-HHHEH-HH5,HHH5,HHHHHHHH@yH@HHHMH5,HHBHEHMH[-H H5,HH8H8HH5V,H8HHH0H0HHMH5,HHHEH ,HH5+HH H5+HHH(H(HH qH HHHMH5+HH:HEHMH,H H5x+HHH0 HH5N+HHHHHHHMH5+HHHEH +HH5+HH#H HMH5*HHrHHMH5*HHOHEH D+HH5*H0H#HHMH5d*HHHHMH5A*HHHEH *HH5/*HH#HHMH5)HHHHMH5)HH{1AHMHUH5/*H2H5)HϹAHHH5)H׈+HUHEH"HEH*HH5d)HH#HJHMH5/)HHHGHMH5 )HH1AHMHUH5l)H2H5(HϹA}HUH5)H2H5(H׈XHx H5(HHH6HHH'HHJHH `H}H5=(HHHHH}HEHHEH5'HHHHEHEHEHEHEHEHEHMHEHMH5'HHHHAHELL $H@HD$=H 'HUHuH=(H4>H=t'HHHHHHH H H5R'HHHHIHHHMHEHHE1EHEHMHQ'HH5&HǹAZHUH5'H2HuH=`'H4>H=&HHHHH11AHHuH=&H >H5k&HHHHEH &HH5&H1AƅwHDHEH &HH5%Hi1AHDRHEH h&HH5u%H4HTHxƅwH5W%HHˆwHxHDHa%HH5*$HHuHEHHiHuH=$HHHHdHHUH5$H}HxHpHhUH5t#HhHHH9H H5c1AH=G#IH`LL`HXLHXHPHH5>#HpHHHHHHHHPHHEH $HUHH@H8yH5"H8HH=H]H NHE1EH5j"HH0HH0H(HH5z"H@HHH H HH(HHEH5E"HǺHEH54"HH^H#HxH5!HXHuHEHOH HuH=!HHHHHGHUH5"H}HHH H5+!HHH HHH51AH= IHLLHLHH| HH5 HHHHS HHK HH; HEH !HUHHH0H5O HHH HH EH>E1EH5! HHHHH HH51 HHHH HH HHo HEH5HǺN HEH5H: HMH5 HH 1HMH21HMH"1HMH1HMH1HMH1HMH1HMHHp]f.@UHH 1H}HuHuH=I HHHHuH1H ! HUHHh1H HUHHN1H HUHH41H HUHH1H HUHH1H HUHH1H HUHH1H HUHH1H qHUHH1H HUHH~1H 5HUHHd1H SHUHHJ1H HUHH0H ]%%%%%%%%%L=AS% h&h8h[h{hhhhhbundleForClass:localizedStringForKey:value:table:arrayWithObjects:defaultManagerfileExistsAtPath:removeItemAtPath:error:createDirectoryAtPath:withIntermediateDirectories:attributes:error:initsetMessageText:setInformativeText:addButtonWithTitle:setAlertStyle:runModalgotoNextPanesetStringValue:setState:removeAllItemsaddItemWithTitle:selectItemWithTitle:openPanelinitWithObjects:setCanChooseDirectories:setCanChooseFiles:setAllowsMultipleSelection:setAllowedFileTypes:URLscountByEnumeratingWithState:objects:count:pathtitleOfSelectedItemsetTitle:stringValuelengthmutableCopyappendString:objectValuestatewriteToFile:atomically:encoding:error:replaceOccurrencesOfString:withString:options:range:stringWithFormat:copyItemAtPath:toPath:error:gotoPreviousPanetitleprotocolsdidEnterPane:chooseCacertFile:chooseProtocol:shouldExitPane:.cxx_destructservertaglogfilecacertfiledebugmodelazymodedownloadsslprotocolistfilemgrtmpCfgFilePathtmpModulesFilePathtmpServerdirFilePathtmpCacertFilePathPaneTitlehttphttps/tmp/ocs_installer/tmp/ocs_installer/ocsinventory-agent.cfg/tmp/ocs_installer/modules.conf/tmp/ocs_installer/serverdir/tmp/ocs_installer/cacert.pem/etc/ocsinventory-agent/ocsinventory-agent.cfgAlready_conf_warnAlready_conf_warn_commentYesNoocsinventory-ng/var/log/ocsng.loghttp://https://pemPEMcrtCRTserver=/ocsinventory tag=logfile=debug=1 debug=0 lazy=1 lazy=0 ssl=1 ssl=0 # this list of module will be load by the at run time # to check its syntax do: # #perl modules.conf # You must have NO error. Else the content will be ignored # This mechanism goal it to keep compatibility with 'plugin' # created for the previous linux_agent. # The new unified_agent have its own extension system that allow # user to add new information easily. #use Ocsinventory::Agent::Modules::Example; use Ocsinventory::Agent::Modules::Download; # DO NOT REMOVE THE 1; 1;#use Ocsinventory::Agent::Modules::Download; # DO NOT REMOVE THE 1; 1;//var/lib/ocsinventory-agent/%@__%@_ocsinventoryOKMissing_cert_warnMissing_cert_warn_commentInvalid_srv_addrInvalid_srv_addr_commentConfigInstallerPane@16@0:8v24@0:8q16v24@0:8@16c24@0:8q16v16@0:8@"NSTextField"@"NSButton"@"NSPopUpButton"@"NSFileManager"@"NSString"44 64 : ::::);3;P;n;.;;;;;;;;;< < <<<< +<-<2<;<D<M<U<]<d<k<>FL>G>>/>>>>?`U@66T6^6h6r6|666((?95?95?09=?9H? 9H?$:S?%:^?4 T&:f?0U-:f?T1:f?(U9:f?UD:u?UN:u?UW:u?U`:u? Ud:?Tp:?Tx:?T:?T:?T:?@3??P@Q666677,7p7u7777777777 8"8,8=8V8i8888888889 99&9,9S9999@P`hpxXHHP8US!8*pQ"YCp0`ASASASASASASASASASASASASASASCSAp`)0RCQ@_OBJC_CLASS_$_NSBundleQr @_OBJC_CLASS_$_NSFileManager@_OBJC_CLASS_$_NSString@_OBJC_METACLASS_$_NSObjectp@__objc_empty_cache@_objc_msgSendq@_objc_release@_objc_retain@___stack_chk_guard@dyld_stub_binder@_OBJC_CLASS_$_NSAlertr @_OBJC_CLASS_$_NSOpenPanel@_OBJC_CLASS_$_NSArray@___CFConstantStringClassReferenceq(*@_OBJC_CLASS_$_InstallerPaner @_OBJC_METACLASS_$_InstallerPaner@___stack_chk_failr@_memsetr@_objc_allocr@_objc_autoreleaseReturnValuer @_objc_enumerationMutationr(@_objc_opt_classr0@_objc_retainAutoreleasedReturnValuer8@_objc_storeStrongr@@_objc_unsafeClaimAutoreleasedReturnValue_OBJC_ IVAR_$_ConfigInstallerPane.iMETACLASS_$_ConfigInstallerPaneCLASS_$_ConfigInstallerPanefilemgrtsldprotocolistcacertfileȩmpagCModulesFilePathServerdirFilePathfgFilePathacertFilePathЩةerverslogfileazymodeebugmodeownload/P0&K t$%4UdAdWf6^.$$N.08$0$PNP.Y$$pNp. ~$ $N.$$$$N.%$%$N.4$4$N C s    8 a  2 ^ d`U$(UPU{UTUT! UNTvU0UTT#TWT8U.H_%?M]kxRUVWXZ]^_SY[\`RUVWXZ]^_ _OBJC_CLASS_$_ConfigInstallerPane_OBJC_IVAR_$_ConfigInstallerPane.cacertfile_OBJC_IVAR_$_ConfigInstallerPane.debugmode_OBJC_IVAR_$_ConfigInstallerPane.download_OBJC_IVAR_$_ConfigInstallerPane.filemgr_OBJC_IVAR_$_ConfigInstallerPane.lazymode_OBJC_IVAR_$_ConfigInstallerPane.logfile_OBJC_IVAR_$_ConfigInstallerPane.protocolist_OBJC_IVAR_$_ConfigInstallerPane.server_OBJC_IVAR_$_ConfigInstallerPane.ssl_OBJC_IVAR_$_ConfigInstallerPane.tag_OBJC_IVAR_$_ConfigInstallerPane.tmpCacertFilePath_OBJC_IVAR_$_ConfigInstallerPane.tmpCfgFilePath_OBJC_IVAR_$_ConfigInstallerPane.tmpModulesFilePath_OBJC_IVAR_$_ConfigInstallerPane.tmpServerdirFilePath_OBJC_METACLASS_$_ConfigInstallerPane_OBJC_CLASS_$_InstallerPane_OBJC_CLASS_$_NSAlert_OBJC_CLASS_$_NSArray_OBJC_CLASS_$_NSBundle_OBJC_CLASS_$_NSFileManager_OBJC_CLASS_$_NSOpenPanel_OBJC_CLASS_$_NSString_OBJC_METACLASS_$_InstallerPane_OBJC_METACLASS_$_NSObject___CFConstantStringClassReference___stack_chk_fail___stack_chk_guard__objc_empty_cache_memset_objc_alloc_objc_autoreleaseReturnValue_objc_enumerationMutation_objc_msgSend_objc_opt_class_objc_release_objc_retain_objc_retainAutoreleasedReturnValue_objc_storeStrong_objc_unsafeClaimAutoreleasedReturnValuedyld_stub_binder-[ConfigInstallerPane title]-[ConfigInstallerPane protocols]-[ConfigInstallerPane didEnterPane:]-[ConfigInstallerPane chooseCacertFile:]-[ConfigInstallerPane chooseProtocol:]-[ConfigInstallerPane shouldExitPane:]-[ConfigInstallerPane .cxx_destruct]__dyld_private/Users/gillesdubois/Documents/Projets/ConfigPluginInstaller/config/config/ConfigInstallerPane.m/Users/gillesdubois/Library/Developer/Xcode/DerivedData/config-byddwnuciqfzlbaoqfvkkroobjxe/Build/Intermediates.noindex/config.build/Debug/config.build/Objects-normal/x86_64/ConfigInstallerPane.o-[ConfigInstallerPane title]-[ConfigInstallerPane protocols]-[ConfigInstallerPane didEnterPane:]-[ConfigInstallerPane chooseCacertFile:]-[ConfigInstallerPane chooseProtocol:]-[ConfigInstallerPane shouldExitPane:]-[ConfigInstallerPane .cxx_destruct]_OBJC_IVAR_$_ConfigInstallerPane.filemgr_OBJC_IVAR_$_ConfigInstallerPane.tmpCfgFilePath_OBJC_IVAR_$_ConfigInstallerPane.tmpModulesFilePath_OBJC_IVAR_$_ConfigInstallerPane.tmpServerdirFilePath_OBJC_IVAR_$_ConfigInstallerPane.tmpCacertFilePath_OBJC_IVAR_$_ConfigInstallerPane.server_OBJC_IVAR_$_ConfigInstallerPane.logfile_OBJC_IVAR_$_ConfigInstallerPane.debugmode_OBJC_IVAR_$_ConfigInstallerPane.lazymode_OBJC_IVAR_$_ConfigInstallerPane.download_OBJC_IVAR_$_ConfigInstallerPane.ssl_OBJC_IVAR_$_ConfigInstallerPane.protocolist_OBJC_IVAR_$_ConfigInstallerPane.cacertfile_OBJC_IVAR_$_ConfigInstallerPane.tag_OBJC_METACLASS_$_ConfigInstallerPane_OBJC_CLASS_$_ConfigInstallerPane H$ 4v  Rorg.ocsinventory.agent.configKHDBNPH65U#W$V^$:d(tVR7@XW;fY/!A %f7"Fv"LGsmVd8'E{5j<^S2LJ2Uyk<5Z:_燥蜛"O{sktzrl$״ {o,b5Zf5iNѪB2 t/ ' p mp}6z .ڰs - u{:<(ٿAҝ;/ބWɯ{jI*2chR=k}g7j gQd\ѼWng5v6n8+N{%ZNғq`3NUX  wEPH+-䔅ĝhg~pYKwB9L;H!]jj5`F)Ëyjaghb_nϙce00U' `GYRT0U00U#0+iGv k.@GM^0.U'0%0#!http://crl.apple.com/root.crl0U0 *Hcd0  *H OY,l/25n}i w,gm:Y\߃*arE0 G񓊣tØr;>E T2Sk NPl! NWk[<= # J&?LmWzX{h䆌JIUK0ᠱ) w4 ;bcA;L۫ɕOM&)zf.!xၮӐ8g0Q\ql 000  *H 0b1 0 UUS10U  Apple Inc.1&0$U Apple Certification Authority10U Apple Root CA0 060425214036Z 350209214036Z0b1 0 UUS10U  Apple Inc.1&0$U Apple Certification Authority10U Apple Root CA0"0  *H 0 䑩 GP^y-6WLUKl"0>P Af$kУ*z G[73Mir]_%UM] d5#KYPXPg ˬ, op?0C=+I(ε^=: !.t< bqGSU/ApLE~LkPAtb A30XZ2hesg^eIv3ew-z0v0U0U00U+iGv k.@GM^0U#0+iGv k.@GM^0U 00 *Hcd00*+https://www.apple.com/appleca/0+0Reliance on this certificate by any party assumes acceptance of the then applicable standard terms and conditions of use, certificate policy and certification practice statements.0  *H \6L-x팛wvw0O=G7@,ԱؾsdyO4آ>xk}9S 8ıO k+Y |@Vtӷ#;Go$ѷpE'mx~"5%kԢ$#s`[ /DH`8=&g 3j /Sj[dc3w:,V!ںsO6U٧2Bq~RB$*M^cKP 7uu!00 s_]0  *H  01 0 UUS10U Apple Inc.1,0*U #Apple Worldwide Developer Relations1D0BU ;Apple Worldwide Developer Relations Certification Authority0 200128202322Z 210127202322Z010 &,d B6L7P2DFAL1C0AU :Apple Development: gilles.dubois18@icloud.com (645QEV68Z4)10U KHDBNPH65U10U Gilles Dubois1 0 UUS0"0  *H 0 ȃ@]/>/U?)Rh@_^7K,-n\'73O].w"ʎCfBX(1% r:]['F~ys}_7EqZånͣJ-fQr1n,rCϮ}ϓNcwyb n>*n.CD4FMKXuS#Yp>7/xe/CWNoB h1[VB%NwtMMXn00 U00U#0' `GYRT0?+3010/+0#http://ocsp.apple.com/ocsp03-wwdr190U 00  *Hcd00+0 Reliance on this certificate by any party assumes acceptance of the then applicable standard terms and conditions of use, certificate policy and certification practice statements.06+*http://www.apple.com/certificateauthority/0U% 0 +0U~Dh~W90U0 *Hcd0 *Hcd 0  *H  (~WE'Oʒi\ 'b2=dPYW+A}|iͿi2e!h^mU.[,v7CU3O#= cdhashes Q8CYRtiZFCviEOcKlzc4LgnxP4w= 0  *H 8=(DH UY51ydWIa|~Soњ+]wԪ7k$37W UnixAgent-2.8/macosx/ocsinventory_packages_setup/config.bundle/Contents/Resources/000077500000000000000000000000001372663377700307105ustar00rootroot00000000000000UnixAgent-2.8/macosx/ocsinventory_packages_setup/config.bundle/Contents/Resources/Base.lproj/000077500000000000000000000000001372663377700327075ustar00rootroot00000000000000ConfigInstallerPane.nib000066400000000000000000000504121372663377700372130ustar00rootroot00000000000000UnixAgent-2.8/macosx/ocsinventory_packages_setup/config.bundle/Contents/Resources/Base.lprojbplist00 X$versionY$archiverT$topX$objects_NSKeyedArchiver _IB.systemFontUpdateVersion]IB.objectdataG %)*048ISZ[\_`dj&'(19:;?PSWXY]iln,-.7GHIJX]^_cdgikz{  !&'(9<=AFOTUVefnstu{ %*05;@FLQW]chnty~256 eABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~U$null "#$VNSRoot]NSConnections\NSOidsValues_NSObjectsValues]NSObjectsKeys_NSAccessibilityOidsValues_NSVisibleWindows_NSAccessibilityOidsKeys_NSAccessibilityConnectorsV$classZNSOidsKeysEEDF&'([NSClassName_InstallerSection+,-.Z$classnameX$classes^NSCustomObject-/XNSObject123ZNS.objects+,56\NSMutableSet57/UNSSet19H:;<=>?@ABCDEFG&ԀՀր׀؀ڀۀ܀݀ހ3JKLMNPQRXNSSource]NSDestinationWNSLabel_%NSChildControllerCreationSelectorName T&UVWXY_NSInitializeWithInit_NSOriginalClassName _ConfigInstallerPaneXNSObject+,]^^NSClassSwapper]/YfirstPane+,ab_NSNibOutletConnectorac/^NSNibConnectorJKLMNPghR klmnopqrstuvwxyz{|}~hVVVRV_%NSTextFieldAlignmentRectInsetsVersion_NSReuseIdentifierKeyXNSvFlags_NSControlSendActionMask_NSControlContinuous_NSAllowsLogicalLayoutDirection_NSNextResponder_NSControlWritingDirection]NSControlSize_&NSViewWantsBestResolutionOpenGLSurface_NSControlTextAlignment_ NSDoNotTranslateAutoresizingMask_NSControlLineBreakModeWNSFrameVNSCell]NSNibTouchBarYNSEnabled[NSSuperview_NSControlRefusesFirstResponder_NSControlUsesSingleLineMode  %  U&tqmzYVRRZNSSubviews_NSViewConstraints[NSFrameSize' ' (_{{22, 20}, {251, 21}}ZcacertfilegVh[NSCellFlags]NSControlViewYNSSupport_NSDrawsBackground_NSBackgroundColorZNSContents[NSTextColor_NSCellIdentifier\NSCellFlags2pA$ !@PVNSSizeXNSfFlagsVNSName#@*_.AppleSystemUIFont+,VNSFont/[NSColorName\NSColorSpace]NSCatalogNameWNSColor VSystem_textBackgroundColorWNSWhite\NSComponents_NSCustomColorSpaceB1C1 1 TNSIDUNSICCWNSModel OhhapplmntrGRAYXYZ .acspAPPLnone-appldescydscm<cprt $#wtpt HkTRC \ descGeneric Gray Gamma 2.2 Profilemluc skSK.daDK8caES8viVN@"ptBRJbukUA,frFU>huHU4zhTWJnbNO:hcsCZ(heIL$itITNroRO*plPLJruRU:FenUS<arEG,Vaeobecn siv gama 2,2Generisk gr 2,2 gammaprofilGamma de grisos genrica 2.2Cu hnh Mu xm Chung Gamma 2.2Perfil Genrico da Gama de Cinzas 2,2030;L=0 Gray-30<0 2.2Profil gnrique gris gamma 2,2ltalnos szrke gamma 2.2u(ppQI^ 2.2 r_icϏGenerisk gr gamma 2,2-profilObecn aed gama 2.2   2.2Profilo grigio generico della gamma 2,2Gama gri generic 2,2Allgemeines Graustufen-Profil Gamma 2,2| ֌  2.2 \ |fnpp^|ep 2.2 cϏeNN,000000 2.2 000000   2.2Perfil genrico de cinzentos da Gamma 2,2Algemeen grijs gamma 2,2-profielPerfil genrico de gamma de grises 2,2#1*5A!!2@#"L1H'D 2.2Genel Gri Gama 2,2Yleinen harmaan gamma 2,2 -profiiliGeneri ki Gray Gamma 2.2 profilUniwersalny profil szaro[ci gamma 2,21I0O A5@0O 30<<0 2,2-?@>D8;LGeneric Gray Gamma 2.2 Profile:'E' 2.2 DHF 1E'/J 9'EtextCopyright Apple Inc., 2012XYZ Qcurv #(-27;@EJOTY^chmrw| %+28>ELRY`gnu| &/8AKT]gqz !-8COZfr~ -;HUcq~ +:IXgw'7HYj{+=Oat 2FZn  % : O d y  ' = T j " 9 Q i  * C \ u & @ Z t .Id %A^z &Ca~1Om&Ed#Cc'Ij4Vx&IlAe@e Ek*Qw;c*R{Gp@j>i  A l !!H!u!!!"'"U"""# #8#f###$$M$|$$% %8%h%%%&'&W&&&''I'z''( (?(q(())8)k))**5*h**++6+i++,,9,n,,- -A-v--..L.../$/Z///050l0011J1112*2c223 3F3334+4e4455M555676r667$7`7788P8899B999:6:t::;-;k;;<' >`>>?!?a??@#@d@@A)AjAAB0BrBBC:C}CDDGDDEEUEEF"FgFFG5G{GHHKHHIIcIIJ7J}JK KSKKL*LrLMMJMMN%NnNOOIOOP'PqPQQPQQR1R|RSS_SSTBTTU(UuUVV\VVWDWWX/X}XYYiYZZVZZ[E[[\5\\]']x]^^l^__a_``W``aOaabIbbcCccd@dde=eef=ffg=ggh?hhiCiijHjjkOkklWlmm`mnnknooxop+ppq:qqrKrss]sttptu(uuv>vvwVwxxnxy*yyzFz{{c{|!||}A}~~b~#G k͂0WGrׇ;iΉ3dʋ0cʍ1fΏ6n֑?zM _ɖ4 uL$h՛BdҞ@iءG&vVǥ8nRĩ7u\ЭD-u`ֲK³8%yhYѹJº;.! zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)Km+,\NSColorSpace/\NSColorSpace+,WNSColor/ "#_controlTextColorB0C0 1 +,_NSTextFieldCell/\NSActionCellVNSCell+,[NSTextField/YNSControlVNSView[NSResponderJKLMNPR ӀVNSView1H     g)1U^bouy3klmnopqrstuvwxyz{|}~VVV RV+ % *, _{{128, 272}, {155, 21}}VserverV.)$ -!+2345678YNS.stringUNSDevUNSKey0_ocsinventory-ng/._0Sw-Bb-gYo.title_ocsinventory-ng+,<=_NSLocalizableString<>/XNSStringlmnopqrsutvwxyz{|}~@VDEVVHIRVO5 T6 4: 21QH3+,TU^NSMutableArrayTV/WNSArray_{{18, 269}, {105, 25}}[protocolist1Z\[79^_`abcdeVgge_NSFirstAttributeV2_NSShouldBeArchivedZNSConstant[NSFirstItem\NSConstantV2_NSFirstAttribute8 #@Y1+,jk_NSLayoutConstraintj/+,VmV/opqrstuvwxyz{| ~VVV@_NSPreferredEdgeVNSMenu_NSPeriodicDelay]NSButtonFlags_NSPeriodicInterval]NSAltersState_NSUsesItemFromMenu_NSMenuItemRespectAlignment_NSAlternateContents_NSKeyEquivalent^NSButtonFlags2_NSAuxButtonTypeZNSMenuItem_NSArrowPosition1=@@@SK ;5E[NSMenuItemsIR23450Whttp://@?_3w5-Xc-SgN.titleWhttp://[NSClassName^NSResourceNameBDCWNSImage_NSMenuCheckmark+,_NSCustomResource/BDF_NSMenuMixedState__popUpItemAction:+,ZNSMenuItem/1Hǀ\?9^_`abcdeVDDe8 #@SsrwxzqyLGJeLV@;m2345QRS0VBrowse_MAB-ch-ni8.titleVBrowsekmnopqrstuvwxyz{|}~VVV]^RV % W_{{135, 301}, {108, 16}}i lm$\2345pqr0^OCS Server URL_w48-wL-2Wx.title^OCS Server URLvwV_NSFontUsesAppearanceFontSize kmnopqrsutvwxyz{|}~VVVRV % W_{{289, 272}, {101, 21}}1\9^_`abcdeVe8 #@X@ m$\23450]/ocsinventory_DIf-zY-Upa.title]/ocsinventoryZ{408, 323}1\$ɀ€ÀĀŀƀǀȀɀʀˀ̀̀΀πЀрҀ9^_acdV \NSSecondItem_NSSecondAttribute_NSSecondAttributeV28 U1^_acdVր8 )1^_acdVր8 )1 ^_acdV_NSSymbolicConstant8 1WNSSpace^_acdV  Ѐ8 ^U^_ab`cdV Հ8 1U#@?^_acdV  ʀ8 u^^_acdV  Հ8 ^U^_acdV  ր8 b^^_acdVЀ8 )1^_acdVՀ8 )^_acdV8 )^_acdVՀ8 )^_ab`cdVЀ8 #@a ^_ab`cdV  $$Հ8 ^o#@<^_acdV  Ѐ8 uo^_ab`cdV //Ѐ8 o#@6^_acdV ր8 yu^_acdV  Հ8 uo^_acdVg Ѐ8 u^_acdVՀ8 ^_ab`cdVKKЀ8 #@8^_acdV Ѐ8 yb^_ab`cdV  VVЀ8 ^b#@H^_acdVgՀ8 ^_acdVg8 ^_acdVgր8 ^_acdVʀ8 ^_acdVЀ8 )^_acdVʀ8 y^_acdVЀ8 y^_acdVЀ8 ^_ab`cdVՀ8 y#@(^_ab`cdVՀ8 #@,^_acdVgЀ8 ^_ab`cdVʀ8 #@H[contentViewJKLMNP 8R bdJKLMNPR y{JKLMNPR JKLMNP R ^`JKLMNPR ـ]parentSectionJKLMNP@R 15JKLMNPR )+JKLMNPR JKLMNP R uwJKLP׀ ߀_chooseCacertFile:+,_NSNibControlConnector/^NSNibConnectorJKLP׀1 _chooseProtocol:1\LP I~[  & @ s g1?^ɀ ),1:=?@ABCDEFG ),1:=?      !"#$%&'()*+,-./0123456789:;<=>?@ABC9    !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJLMNOPQRSTUVWXYZ[1H31\9+,^NSIBObjectData/",1:?QZw!NUcp   !*68:MVajy~#19acegik|,ACEGIK;Miw(Igiknpqrt}   B N \ f z      , 5 < A V b o }     " $'9BOV_kvZ\]^`bcdfhjkmno,5KR[   ' 0 3 5 7 T i ~ !I![!b!t!!!!!!!"" "+"="?"A"D"I"R"T"V"W"X"Y"\"^"`"b"d"f"h"i""""""""""#### # ########/#1#3#5#F#H#P#R#T#g#o#|###############$$$&$+$4$;$=$?$A$C$l$n$p$r$t$v$x$z$|$$$$$$$$$$$$$$$$$%%% % %%%%.%5%:%C%W%d%s%%%%%&&&&&&&& &"&$&&&'&)&*&+&-&E&P&q&v&x&z&|&~&&&&&&&&&&&&&&&&'T'V'W'X'Z'\']'^'`'b'd'e'g'h'i'''''''''''((((((!("(#(%('()(*(,(-(.(0(J(T(_((((((((((((((((((())))')))+)4)=)S)X)a)j)s)~)))))))))))))))**$*&*(***,*.*0*A*C*\*^*`*s****************+++>+@+B+D+E+G+I+K+M++++++++++++++++++,,&,(,*,,,.,0,2,4,6,G,I,^,`,b,u,,,,,,,,,,,,,,,,,---X-Z-\-^-`-b-d-f-h-y-{-------....... . . ......,.0.o.q.s.u.w.y.{.}........///////// /"/#/%/&/'/)/A/b/d/f/h/j/l/n//////00[0\0]0_0a0c0d0e0g0i0k0l0n0o0p0r0t0}0~0000000000011111111 1"13151<1>1@1S1Z111111111111111122222 2 2 22#2%2426282K2Z2o2222222222222223333333"3+3.30323O3Q3R3[3]3~3333333333333334/41434547494;4=4?4A4C4E4G4I4K4M4O4Q4S4U4W4Y4[4]4_4a4c4e4g4i4k4m4o4q4s4u4w4y4444444444445555%5'5(5*5,5.5S5h5j5k5m5o5q5y55555555555555666'6)6*6,6.606Q6S6T6V6X6}6666666666666666667777-7/7072747=7f7h7i7k7m7v77777777777777778$8&8'8)8+8-8N8P8Q8S8U8z8|8}888888888888889 999999B9D9E9G9I9K9p9r9s9u9w9y99999999999999999:: :!:#:%:F:H:I:K:M:n:p:q:s:u::::::::::::; ;;;;;;>;@;A;C;E;N;Z;o;q;s;u;w;y;;;;;;;;;;;;;;;;;;;;;;;;<<<<<< <"<7<9<;<=>>>>> > >>>>>>>>>> >">$>&>(>*>,>.>0>2>4>6>8>:><>>>@>B>D>F>H>J>L>U>W>Y>g>p? ? ??????????!?#?%?'?)?+?-?/?1?3?5?7?9?;?=???A?C?E?G?I?K?M?O?Q?S?U?W?Y?[?]?_?a?c?e?g?i?k?m?o?q?s?u?w?y?{?}?????????????????????@g@i@k@m@o@q@s@u@w@y@{@}@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@AAAAA A A AAAAAAAAAA(AAAAAAAAAAAAAAAABBBBB B B BBBBBBB!B$B'B*B-B0B3B6B9B SectionOrder Introduction ReadMe License config.bundle Target PackageSelection Install UnixAgent-2.8/macosx/ocsinventory_packages_setup/config.bundle/Contents/Resources/en.lproj/000077500000000000000000000000001372663377700324375ustar00rootroot00000000000000ConfigInstallerPane.strings000066400000000000000000000027451372663377700376720ustar00rootroot00000000000000UnixAgent-2.8/macosx/ocsinventory_packages_setup/config.bundle/Contents/Resources/en.lproj /* Class = "NSButtonCell"; title = "SSL check"; ObjectID = "0JY-Jz-90N"; */ "0JY-Jz-90N.title" = "SSL check"; /* Class = "NSTextFieldCell"; title = "ocsinventory-ng"; ObjectID = "0Sw-Bb-gYo"; */ "0Sw-Bb-gYo.title" = "ocsinventory-ng"; /* Class = "NSButtonCell"; title = "Debug mode"; ObjectID = "31X-X1-h1b"; */ "31X-X1-h1b.title" = "Debug mode"; /* Class = "NSMenuItem"; title = "http://"; ObjectID = "3w5-Xc-SgN"; */ "3w5-Xc-SgN.title" = "http://"; /* Class = "NSTextFieldCell"; title = "Log File path :"; ObjectID = "Bqz-yE-1gz"; */ "Bqz-yE-1gz.title" = "Log File path :"; /* Class = "NSTextFieldCell"; title = "TAG Value (optional) :"; ObjectID = "CJY-Du-ySH"; */ "CJY-Du-ySH.title" = "TAG Value (optional) :"; /* Class = "NSTextFieldCell"; title = "/ocsinventory"; ObjectID = "DIf-zY-Upa"; */ "DIf-zY-Upa.title" = "/ocsinventory"; /* Class = "NSButtonCell"; title = "Deployment feature"; ObjectID = "Fz6-ny-C1b"; */ "Fz6-ny-C1b.title" = "Deployment feature"; /* Class = "NSButtonCell"; title = "Browse"; ObjectID = "MAB-ch-ni8"; */ "MAB-ch-ni8.title" = "Browse"; /* Class = "NSTextFieldCell"; title = "Certificate File (needed by 'Deployment feature')"; ObjectID = "UvL-Ff-Y6G"; */ "UvL-Ff-Y6G.title" = "Certificate File (needed by 'Deployment feature')"; /* Class = "NSButtonCell"; title = "Lazy mode"; ObjectID = "gFK-QK-e24"; */ "gFK-QK-e24.title" = "Lazy mode"; /* Class = "NSTextFieldCell"; title = "OCS Server URL"; ObjectID = "w48-wL-2Wx"; */ "w48-wL-2Wx.title" = "OCS Server URL";∂ InfoPlist.strings000066400000000000000000000001421372663377700356770ustar00rootroot00000000000000UnixAgent-2.8/macosx/ocsinventory_packages_setup/config.bundle/Contents/Resources/en.lprojInstallerSectionTitle = "Agent configuration"; Localizable.strings000066400000000000000000000040601372663377700362140ustar00rootroot00000000000000UnixAgent-2.8/macosx/ocsinventory_packages_setup/config.bundle/Contents/Resources/en.lproj/* Localized versions of Info.plist keys */ "PaneTitle" = "OCSInventory Agent Config"; //Yes button "Yes" = "Yes"; //No button "No" = "No"; //Warning about already existing cofiguration file "Already_conf_warn" = "OCS agent configuration file seems to already exists. Do you want to launch OCS Inventory NG agent configuration?"; //Warning about already existing cofiguration file comment "Already_conf_warn_comment" = "The previous /etc/ocsinventory-agent/ocsinventory-agent.cfg file will be erased"; //Warning about missing certificate file "Missing_cert_warn" = "You have enabled Download feature and SSL certicate check but you don't specify a certificate file"; //Warning about missing certificate file comment "Missing_cert_warn_comment" = "If you don't specifiy a certificate file, Download feature won't work"; //Warning about invalid server address "Invalid_srv_addr" = "Invalid OCS server address"; //Warning about invalid server address comment "Invalid_srv_addr_comment" = "Please check and re-enter your OCS server address"; UnixAgent-2.8/macosx/ocsinventory_packages_setup/config.bundle/Contents/_CodeSignature/000077500000000000000000000000001372663377700316315ustar00rootroot00000000000000UnixAgent-2.8/macosx/ocsinventory_packages_setup/config.bundle/Contents/_CodeSignature/CodeResources000066400000000000000000000074331372663377700343300ustar00rootroot00000000000000 files Resources/Base.lproj/ConfigInstallerPane.nib l8zcaJESf2WEryTIkN6KaenTARI= Resources/InstallerSections.plist LpXhZ1VvF2siFxs4mpia0PCnR5c= Resources/en.lproj/ConfigInstallerPane.strings hash PzyXIbbioRBe8IB10xAeUcFqpQs= optional Resources/en.lproj/InfoPlist.strings hash KjbuOb4lqm/uiqKFnyUAUqhTfKQ= optional Resources/en.lproj/Localizable.strings hash m6w4i8zyDoQz37Wax6vL4HBa3Lk= optional files2 Resources/Base.lproj/ConfigInstallerPane.nib hash2 f5WqT/uWCDHaQ9NyjvgZE99L0Y4X6qJ6SxrrMuvUTiQ= Resources/InstallerSections.plist hash2 luK21Ws/HQdlP/xeZXZ1Sw+m/repA8RbW72bm8ELOY8= Resources/en.lproj/ConfigInstallerPane.strings hash2 5ou2+oxEv8fJwzCru3W2EWlaOFIzIqxLzlRIvJe3A/Y= optional Resources/en.lproj/InfoPlist.strings hash2 KQQbL7yg0pVKzwqwiD7sT3VAy5Pik/w/gtKizZSSzYc= optional Resources/en.lproj/Localizable.strings hash2 jVwd52Zgtjk0de+f9zdgvJRvbNHadUyNTZZeuzeqnRc= optional rules ^Resources/ ^Resources/.*\.lproj/ optional weight 1000 ^Resources/.*\.lproj/locversion.plist$ omit weight 1100 ^Resources/Base\.lproj/ weight 1010 ^version.plist$ rules2 .*\.dSYM($|/) weight 11 ^(.*/)?\.DS_Store$ omit weight 2000 ^(Frameworks|SharedFrameworks|PlugIns|Plug-ins|XPCServices|Helpers|MacOS|Library/(Automator|Spotlight|LoginItems))/ nested weight 10 ^.* ^Info\.plist$ omit weight 20 ^PkgInfo$ omit weight 20 ^Resources/ weight 20 ^Resources/.*\.lproj/ optional weight 1000 ^Resources/.*\.lproj/locversion.plist$ omit weight 1100 ^Resources/Base\.lproj/ weight 1010 ^[^/]+$ nested weight 10 ^embedded\.provisionprofile$ weight 20 ^version\.plist$ weight 20 UnixAgent-2.8/macosx/ocsinventory_packages_setup/daemonconfig.bundle/000077500000000000000000000000001372663377700263255ustar00rootroot00000000000000UnixAgent-2.8/macosx/ocsinventory_packages_setup/daemonconfig.bundle/Contents/000077500000000000000000000000001372663377700301225ustar00rootroot00000000000000UnixAgent-2.8/macosx/ocsinventory_packages_setup/daemonconfig.bundle/Contents/Info.plist000066400000000000000000000030141372663377700320700ustar00rootroot00000000000000 BuildMachineOSBuild 19D76 CFBundleDevelopmentRegion en CFBundleExecutable daemonconfig CFBundleIdentifier org.ocsinventory.agent.daemonconfig CFBundleInfoDictionaryVersion 6.0 CFBundleName daemonconfig CFBundlePackageType BNDL CFBundleShortVersionString 1.0 CFBundleSupportedPlatforms MacOSX CFBundleVersion 1 DTCompiler com.apple.compilers.llvm.clang.1_0 DTPlatformBuild 11C504 DTPlatformVersion GM DTSDKBuild 19B90 DTSDKName macosx10.15 DTXcode 1130 DTXcodeBuild 11C504 InstallerSectionTitle daemonconfig LSMinimumSystemVersion 10.15 NSHumanReadableCopyright Copyright © 2020 OCS Inventory. All rights reserved. NSMainNibFile DaemonConfigPane NSPrincipalClass InstallerSection UnixAgent-2.8/macosx/ocsinventory_packages_setup/daemonconfig.bundle/Contents/MacOS/000077500000000000000000000000001372663377700310645ustar00rootroot00000000000000UnixAgent-2.8/macosx/ocsinventory_packages_setup/daemonconfig.bundle/Contents/MacOS/daemonconfig000077500000000000000000001134001372663377700334420ustar00rootroot00000000000000 __TEXT __text__TEXT< __stubs__TEXT,$,__stub_helper__TEXTPLP__objc_methname__TEXT\__cstring__TEXTE__objc_classname__TEXT==__objc_methtype__TEXTP^P__unwind_info__TEXTH__DATA_CONST  __got__DATA_CONST __cfstring__DATA_CONST  __objc_classlist__DATA_CONST""__objc_imageinfo__DATA_CONST""x__DATA00__la_symbol_ptr__DATA000 __objc_const__DATA0000__objc_selrefs__DATA11__objc_classrefs__DATA2(2__objc_ivar__DATA202__objc_data__DATA3P3__data__DATAh3h3H__LINKEDIT@`@W"0@((@AxBhC=xG P!!)8GoQ3lCj2   * `~,/System/Library/Frameworks/Foundation.framework/Versions/C/Foundation 8/usr/lib/libobjc.A.dylib 8/usr/lib/libSystem.B.dylib X~ f-/System/Library/Frameworks/AppKit.framework/Versions/C/AppKit h~/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation p//System/Library/Frameworks/InstallerPlugins.framework/Versions/A/InstallerPlugins&XC)hC NHUHH@H}HuH="HuH}H! H5!H=HMH}HHHEH H5!HE1DHHMLELMHEAH H H}HEHEHH@] f.UHHpHH}HuHUHLHEH!H5*!H!HW HUH5!H<2H2HYHUH5!HHH$ HYHUH5!HHH HEH!HHUH5 H<1HUH5n!H2HuH=g!H4>H=| H}HHUHuHHUPE1DHUH5'!H2HuH=(!H4>H=5 H}HHUHuHHUEEP1HUH5 H2HuH=H}HHUHuHHUHMLELM EHGHMH H H5HH HEH HH5HǺa HEH f HH5sHǺ= E1DHEHoHp]DUHH@H H}HuHUHEHEH5H HUHEH HEHHH5H HH HMH5HH HEH HH5Hk HH5HHHEL HMHHEC HEH}HHJH5oH HEHEHuH=H4>H=8H}HHuHE HH5,H}HHE HHEHEH H}HEH5H H5| EiEEH}H HuHHUS H l HUH5EH=H}HHuHUHʉ HQH5LHUHHHx HxH H HUH5HH HHH5H HuHEH HEH5GH=HpHHpHhb HH5 H= 1AH8IH`LHXHHXH`HP HDH5HhHHHH H'HHHH@ HPH HEH kHUHH8H0H5zH0HHw HH  H E1EH5LHH(HH(H 3 HiH5H8HHH HH H HHEH HUHHHH5HHHHH \ H E1EH5HHHHHgHH5HHHH>HH6HH&HEH5HǺHEH5HHMH5HH1HMH1HMHH HMH5HHE1EHEHMHmHH5"HǹA^HUH5cH2H5H׈9He1HUH5H2HuH= H4>H=HHHHHHHL1HMH1HMHH@]f.fUHH 1H}HuHuH=iHHHHuH1H AHUHH1H HUHHl1H %HUHHR1H HUHH81H HUHHH ]%%%%%%LAS%hhh5hKhuhbundleForClass:localizedStringForKey:value:table:defaultManagerfileExistsAtPath:removeItemAtPath:error:createDirectoryAtPath:withIntermediateDirectories:attributes:error:setStringValue:setState:mutableCopystateappendString:stringValuelengthinitnumberFromString:intValuestringWithFormat:mainBundleaddButtonWithTitle:setMessageText:setInformativeText:setAlertStyle:runModalgotoPreviousPanewriteToFile:atomically:encoding:error:createFileAtPath:contents:attributes:titledidEnterPane:shouldExitPane:.cxx_destructperiodicitynowstartupfilemgrtmpLaunchdFilePathtmpNowFilePathPaneTitle/tmp/ocs_installer/tmp/ocs_installer/org.ocsng.agent.plist/tmp/ocs_installer/now5 Label org.ocsng.agent ProgramArguments /Applications/OCSNG.app/Contents/MacOS/OCSNG RunAtLoad StartInterval %d OKPeriodicity_warnPeriodicity_warn_comment DaemonConfigPane@16@0:8v24@0:8q16c24@0:8q16v16@0:8@"NSTextField"@"NSButton"@"NSFileManager"@"NSString"44-4  (>UWR$ ,@3@`jt~((=PXcnp 3v33222@pN=x00L\frx&7^X`h@PH0031!0pQ"VCp0\ASASASASASASCSAp`0xRCQ@_OBJC_CLASS_$_NSBundleQr@_OBJC_CLASS_$_NSFileManager@_OBJC_CLASS_$_NSNumberFormatter@_OBJC_CLASS_$_NSString@_OBJC_METACLASS_$_NSObject8@__objc_empty_cache@_objc_msgSendq@_objc_release@_objc_retain@dyld_stub_binder@_OBJC_CLASS_$_NSAlertr@___CFConstantStringClassReferenceq @_OBJC_CLASS_$_InstallerPaner@_OBJC_METACLASS_$_InstallerPaner@_objc_allocr@_objc_autoreleaseReturnValuer@_objc_opt_classr@_objc_retainAutoreleasedReturnValuer @_objc_storeStrongr(@_objc_unsafeClaimAutoreleasedReturnValue_OBJC_ IVAR_$_DaemonConfigPane.`METACLASS_$_DaemonConfigPaneCLASS_$_DaemonConfigPanefilemgrtmpperiodicitystartupnoweLaunchdFilePathNowFilePatheefffff 2Txph3ddf47^.$$N.$$@N@."$$N.pF$p$Nh     < ^  d@3!2G3i33223:Vl3FRo}3469:;578<3469:; _OBJC_CLASS_$_DaemonConfigPane_OBJC_IVAR_$_DaemonConfigPane.filemgr_OBJC_IVAR_$_DaemonConfigPane.now_OBJC_IVAR_$_DaemonConfigPane.periodicity_OBJC_IVAR_$_DaemonConfigPane.startup_OBJC_IVAR_$_DaemonConfigPane.tmpLaunchdFilePath_OBJC_IVAR_$_DaemonConfigPane.tmpNowFilePath_OBJC_METACLASS_$_DaemonConfigPane_OBJC_CLASS_$_InstallerPane_OBJC_CLASS_$_NSAlert_OBJC_CLASS_$_NSBundle_OBJC_CLASS_$_NSFileManager_OBJC_CLASS_$_NSNumberFormatter_OBJC_CLASS_$_NSString_OBJC_METACLASS_$_InstallerPane_OBJC_METACLASS_$_NSObject___CFConstantStringClassReference__objc_empty_cache_objc_alloc_objc_autoreleaseReturnValue_objc_msgSend_objc_opt_class_objc_release_objc_retain_objc_retainAutoreleasedReturnValue_objc_storeStrong_objc_unsafeClaimAutoreleasedReturnValuedyld_stub_binder-[DaemonConfigPane title]-[DaemonConfigPane didEnterPane:]-[DaemonConfigPane shouldExitPane:]-[DaemonConfigPane .cxx_destruct]__dyld_private/Users/gillesdubois/Documents/Projets/ConfigPluginInstaller/daemonconfig/daemonconfig/DaemonConfigPane.m/Users/gillesdubois/Library/Developer/Xcode/DerivedData/daemonconfig-dercaroxijaqmfctqcpkomjsojjx/Build/Intermediates.noindex/daemonconfig.build/Debug/daemonconfig.build/Objects-normal/x86_64/DaemonConfigPane.o-[DaemonConfigPane title]-[DaemonConfigPane didEnterPane:]-[DaemonConfigPane shouldExitPane:]-[DaemonConfigPane .cxx_destruct]_OBJC_IVAR_$_DaemonConfigPane.filemgr_OBJC_IVAR_$_DaemonConfigPane.tmpLaunchdFilePath_OBJC_IVAR_$_DaemonConfigPane.tmpNowFilePath_OBJC_IVAR_$_DaemonConfigPane.periodicity_OBJC_IVAR_$_DaemonConfigPane.startup_OBJC_IVAR_$_DaemonConfigPane.now_OBJC_METACLASS_$_DaemonConfigPane_OBJC_CLASS_$_DaemonConfigPane $[ c4N  Xorg.ocsinventory.agent.daemonconfigKHDBNPH65UEdPP,z/SP:q G8 G/|؝Դ@Jq9ͣEÂ4v(=n).&R}FsW>&tgz? ?wS1.lˉ .GuHrJ"Z <`"tb) A{qGFҩХ^'u73pDJF5v4qUzBM!CV7в׊g  #org.ocsinventory.agent.daemonconfig subject.CN:Apple Development: gilles.dubois18@icloud.com (645QEV68Z4) *Hcd 0 *H 010  `He0 *H 0"0 ޼9m0  *H 0b1 0 UUS10U  Apple Inc.1&0$U Apple Certification Authority10U Apple Root CA0 130207214847Z 230207214847Z01 0 UUS10U Apple Inc.1,0*U #Apple Worldwide Developer Relations1D0BU ;Apple Worldwide Developer Relations Certification Authority0"0  *H 0 8TV$9H_&4Sz|cawd^#9P-VXp-~nJ>/ބWɯ{jI*2chR=k}g7j gQd\ѼWng5v6n8+N{%ZNғq`3NUX  wEPH+-䔅ĝhg~pYKwB9L;H!]jj5`F)Ëyjaghb_nϙce00U' `GYRT0U00U#0+iGv k.@GM^0.U'0%0#!http://crl.apple.com/root.crl0U0 *Hcd0  *H OY,l/25n}i w,gm:Y\߃*arE0 G񓊣tØr;>E T2Sk NPl! NWk[<= # J&?LmWzX{h䆌JIUK0ᠱ) w4 ;bcA;L۫ɕOM&)zf.!xၮӐ8g0Q\ql 000  *H 0b1 0 UUS10U  Apple Inc.1&0$U Apple Certification Authority10U Apple Root CA0 060425214036Z 350209214036Z0b1 0 UUS10U  Apple Inc.1&0$U Apple Certification Authority10U Apple Root CA0"0  *H 0 䑩 GP^y-6WLUKl"0>P Af$kУ*z G[73Mir]_%UM] d5#KYPXPg ˬ, op?0C=+I(ε^=: !.t< bqGSU/ApLE~LkPAtb A30XZ2hesg^eIv3ew-z0v0U0U00U+iGv k.@GM^0U#0+iGv k.@GM^0U 00 *Hcd00*+https://www.apple.com/appleca/0+0Reliance on this certificate by any party assumes acceptance of the then applicable standard terms and conditions of use, certificate policy and certification practice statements.0  *H \6L-x팛wvw0O=G7@,ԱؾsdyO4آ>xk}9S 8ıO k+Y |@Vtӷ#;Go$ѷpE'mx~"5%kԢ$#s`[ /DH`8=&g 3j /Sj[dc3w:,V!ںsO6U٧2Bq~RB$*M^cKP 7uu!00 s_]0  *H  01 0 UUS10U Apple Inc.1,0*U #Apple Worldwide Developer Relations1D0BU ;Apple Worldwide Developer Relations Certification Authority0 200128202322Z 210127202322Z010 &,d B6L7P2DFAL1C0AU :Apple Development: gilles.dubois18@icloud.com (645QEV68Z4)10U KHDBNPH65U10U Gilles Dubois1 0 UUS0"0  *H 0 ȃ@]/>/U?)Rh@_^7K,-n\'73O].w"ʎCfBX(1% r:]['F~ys}_7EqZånͣJ-fQr1n,rCϮ}ϓNcwyb n>*n.CD4FMKXuS#Yp>7/xe/CWNoB h1[VB%NwtMMXn00 U00U#0' `GYRT0?+3010/+0#http://ocsp.apple.com/ocsp03-wwdr190U 00  *Hcd00+0 Reliance on this certificate by any party assumes acceptance of the then applicable standard terms and conditions of use, certificate policy and certification practice statements.06+*http://www.apple.com/certificateauthority/0U% 0 +0U~Dh~W90U0 *Hcd0 *Hcd 0  *H  (~WE'Oʒi\ 'b2=dPYW+A}|iͿi2e!h^mU.[,v7CU3O#= cdhashes bVjyQ/jkByv95kIiNEcLN9sixW4= 0  *H Բ᪝nE8 Y?/Qttܗ5 ltJi$5~KnI`ո FN ]Ȼ~ B\2cSlPk⼫"RU)nQ@w&rug!oLWYeVsIJ[?(#[Jܣ`p::h{0xj  2j^*Bc8U/}qH #:ϼu!+QaӸq$2|ŶUnixAgent-2.8/macosx/ocsinventory_packages_setup/daemonconfig.bundle/Contents/Resources/000077500000000000000000000000001372663377700320745ustar00rootroot00000000000000UnixAgent-2.8/macosx/ocsinventory_packages_setup/daemonconfig.bundle/Contents/Resources/Base.lproj/000077500000000000000000000000001372663377700340735ustar00rootroot00000000000000DaemonConfigPane.nib000066400000000000000000000277261372663377700376610ustar00rootroot00000000000000UnixAgent-2.8/macosx/ocsinventory_packages_setup/daemonconfig.bundle/Contents/Resources/Base.lprojbplist00 X$versionY$archiverT$topX$objects_NSKeyedArchiver _IB.systemFontUpdateVersion]IB.objectdata %)*048AKRSTWX\btu} !-03@EFGKLQRabinop%,-.4:;ABHdgh )U$null "#$VNSRoot]NSConnections\NSOidsValues_NSObjectsValues]NSObjectsKeys_NSAccessibilityOidsValues_NSVisibleWindows_NSAccessibilityOidsKeys_NSAccessibilityConnectorsV$classZNSOidsKeysrpmq&'([NSClassName_InstallerSection+,-.Z$classnameX$classes^NSCustomObject-/XNSObject123ZNS.objects+,56\NSMutableSet57/UNSSet19@:;<=>?ghjlXBCDEFHIJXNSSource]NSDestinationWNSLabel_%NSChildControllerCreationSelectorName L&MNOPQ_NSInitializeWithInit_NSOriginalClassName _DaemonConfigPaneXNSObject+,UV^NSClassSwapperU/YfirstPane+,YZ_NSNibOutletConnectorY[/^NSNibConnectorBCDEFH_`J fM&cdefghijQjNnJpqJs_&NSViewWantsBestResolutionOpenGLSurfaceZNSSubviews_NSNextResponder_NSViewConstraintsXNSvFlags]NSNibTouchBar[NSFrameSize  ZYVNSView1v@wxyz{+:@QX~gechN_NNJN__%NSTextFieldAlignmentRectInsetsVersion_NSControlSendActionMask_NSControlContinuous_NSAllowsLogicalLayoutDirection_NSControlWritingDirection]NSControlSize_NSControlTextAlignment_ NSDoNotTranslateAutoresizingMask_NSControlLineBreakModeWNSFrameVNSCellYNSEnabled[NSSuperview_NSControlRefusesFirstResponder_NSControlUsesSingleLineMode_NSHuggingPriority  *  _{{48, 228}, {155, 16}}Z{251, 750}w[NSCellFlags]NSControlViewYNSSupport_NSBackgroundColor[NSTextColorZNSContents\NSCellFlags2@)&YNS.stringUNSDevUNSKey_Launch OCS agent every_CR7-Av-TyG.title_Launch OCS agent every+,_NSLocalizableString/XNSStringNVNSSizeXNSfFlags_NSFontUsesAppearanceFontSizeVNSName#@* _.AppleSystemUIFont+,VNSFont/[NSColorName\NSColorSpace]NSCatalogNameWNSColor% !VSystem_textBackgroundColorWNSWhite\NSComponents_NSCustomColorSpaceB1C1 1"%TNSIDUNSICCWNSModel #$OhhapplmntrGRAYXYZ .acspAPPLnone-appldescydscm<cprt $#wtpt HkTRC \ descGeneric Gray Gamma 2.2 Profilemluc skSK.daDK8caES8viVN@"ptBRJbukUA,frFU>huHU4zhTWJnbNO:hcsCZ(heIL$itITNroRO*plPLJruRU:FenUS<arEG,Vaeobecn siv gama 2,2Generisk gr 2,2 gammaprofilGamma de grisos genrica 2.2Cu hnh Mu xm Chung Gamma 2.2Perfil Genrico da Gama de Cinzas 2,2030;L=0 Gray-30<0 2.2Profil gnrique gris gamma 2,2ltalnos szrke gamma 2.2u(ppQI^ 2.2 r_icϏGenerisk gr gamma 2,2-profilObecn aed gama 2.2   2.2Profilo grigio generico della gamma 2,2Gama gri generic 2,2Allgemeines Graustufen-Profil Gamma 2,2| ֌  2.2 \ |fnpp^|ep 2.2 cϏeNN,000000 2.2 000000   2.2Perfil genrico de cinzentos da Gamma 2,2Algemeen grijs gamma 2,2-profielPerfil genrico de gamma de grises 2,2#1*5A!!2@#"L1H'D 2.2Genel Gri Gama 2,2Yleinen harmaan gamma 2,2 -profiiliGeneri ki Gray Gamma 2.2 profilUniwersalny profil szaro[ci gamma 2,21I0O A5@0O 30<<0 2,2-?@>D8;LGeneric Gray Gamma 2.2 Profile:'E' 2.2 DHF 1E'/J 9'EtextCopyright Apple Inc., 2012XYZ Qcurv #(-27;@EJOTY^chmrw| %+28>ELRY`gnu| &/8AKT]gqz !-8COZfr~ -;HUcq~ +:IXgw'7HYj{+=Oat 2FZn  % : O d y  ' = T j " 9 Q i  * C \ u & @ Z t .Id %A^z &Ca~1Om&Ed#Cc'Ij4Vx&IlAe@e Ek*Qw;c*R{Gp@j>i  A l !!H!u!!!"'"U"""# #8#f###$$M$|$$% %8%h%%%&'&W&&&''I'z''( (?(q(())8)k))**5*h**++6+i++,,9,n,,- -A-v--..L.../$/Z///050l0011J1112*2c223 3F3334+4e4455M555676r667$7`7788P8899B999:6:t::;-;k;;<' >`>>?!?a??@#@d@@A)AjAAB0BrBBC:C}CDDGDDEEUEEF"FgFFG5G{GHHKHHIIcIIJ7J}JK KSKKL*LrLMMJMMN%NnNOOIOOP'PqPQQPQQR1R|RSS_SSTBTTU(UuUVV\VVWDWWX/X}XYYiYZZVZZ[E[[\5\\]']x]^^l^__a_``W``aOaabIbbcCccd@dde=eef=ffg=ggh?hhiCiijHjjkOkklWlmm`mnnknooxop+ppq:qqrKrss]sttptu(uuv>vvwVwxxnxy*yyzFz{{c{|!||}A}~~b~#G k͂0WGrׇ;iΉ3dʋ0cʍ1fΏ6n֑?zM _ɖ4 uL$h՛BdҞ@iءG&vVǥ8nRĩ7u\ЭD-u`ֲK³8%yhYѹJº;.! zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)Km+,\NSColorSpace/\NSColorSpace+,WNSColor/%'(ZlabelColorB0C0 1"%+,_NSTextFieldCell/\NSActionCellVNSCell+,[NSTextField /YNSControlVNSView[NSResponder~ gefch N_ NNJN__NSReuseIdentifierKey- *. ,2 _{{217, 225}, {38, 21}}[periodicity1 /1"#$%&'()N+x+)_NSFirstAttributeV2_NSShouldBeArchivedZNSConstant[NSFirstItem\NSConstantV2_NSFirstAttribute0 #@C++,./_NSLayoutConstraint./+,12WNSArray1/456x9N<=>?_NSDrawsBackground_NSCellIdentifierpA+)6 387@BCDQ554_Kd5-vS-SZ8.titleQ5H[periodicityN%9(_controlTextColor~gechN_NNYZJN_ * ;< _{{261, 228}, {49, 16}}y9h:)6&=klmWhour(s)?>_L5X-oH-TrN.titleWhour(s) gefchqN_uvNNyzJN_B PC AF E_{{48, 179}, {245, 18}}Wstartup1 D1"#$%&'()Nz)0 #@n @Z{250, 750}5zq9_NSPeriodicInterval]NSButtonFlags_NSAlternateContents_NSKeyEquivalent_NSAlternateImage_NSAuxButtonType_NSPeriodicDelay^NSButtonFlags2KH"#%&$'(Nz{0 @Q#@1"#%'(Nyx0 :+"#%&$'(Nwx0 +#@0"#%&$'(N_x$$0 +#@U"#&%'(N)yx_NSSymbolicConstant0 e:+WNSSpace[contentViewBCDEFH{J QSBCDEFH8J i]parentSectionBCDEFHx?J +k[periodicityBCDEFHzqJ @B1I JH_wxyZzz{n +2/:<@FDQT[\]^_`abcd1&e(o]NSApplication1i _w_xx_y_zz_{__________++:@@Q11  JH_wxyZzz{:;<=>?n +2/:<@FDQT[\]^_`abcdghjl11  Ȁstuvwxyz{|}~1     1@X1 1+,^NSIBObjectData/",1:?QZw -I\v )457@MTZcprtvxz|~ "#%')<EN]blu0DM[gikmnprtwy{!;Qr 7Uiknpqrt} $168:<>@BGXbhnp  , 3 < ? @ B D Y b i n     ! # % 6 ; A I K M O Q#8;?ACL^gt{*,-.024568:<=?@AZfortv "'08=fz (  o q r s u w y z { }  !.!C!Q!g!y!!!!!!!!!!!!!!!!!!!!""!"#"6"Y"b"n"p"r"{"""""""""""#4#6#7#8#:#<#=#>#@#B#D#E#G#H#I#K#d#h###############$$&$5$<$G$P$e$g$i$k$m$o$q$s$u$w$y${$$$$$$$$$$$%%%%%/%1%2%4%6%?%`%b%c%e%g%%%%%%%%%%%%%%%%&&*&,&-&/&1&:&c&e&f&h&j&s&&&&&&&&&&&&&&&&'''''''+'-'/'1'3'5'A'V'X'Z'\'^'`'i''''''''''''''''''''''''''''''''(+(-(/(1(3(5(7(9(;(=(?(A(C(E(G(I(K(M(O(Q(S(U(W(Y([(](_(h((((((((((((((((((((((((((((((((((()9);)=)?)A)C)E)G)I)K)M)O)Q)S)U)W)Y)[)])_)a)c)e)g)i)k)m)o)q)s)u)w)y){)}))))))))))))))))))))))))))))))))InstallerSections.plist000066400000000000000000000007711372663377700365440ustar00rootroot00000000000000UnixAgent-2.8/macosx/ocsinventory_packages_setup/daemonconfig.bundle/Contents/Resources SectionOrder Introduction ReadMe License daemonconfig.bundle Target PackageSelection Install UnixAgent-2.8/macosx/ocsinventory_packages_setup/daemonconfig.bundle/Contents/Resources/en.lproj/000077500000000000000000000000001372663377700336235ustar00rootroot00000000000000DaemonConfigPane.strings000066400000000000000000000012141372663377700403120ustar00rootroot00000000000000UnixAgent-2.8/macosx/ocsinventory_packages_setup/daemonconfig.bundle/Contents/Resources/en.lproj /* Class = "NSTextFieldCell"; title = "Launch OCS agent every"; ObjectID = "CR7-Av-TyG"; */ "CR7-Av-TyG.title" = "Launch OCS agent every"; /* Class = "NSTextFieldCell"; title = "5"; ObjectID = "Kd5-vS-SZ8"; */ "Kd5-vS-SZ8.title" = "5"; /* Class = "NSTextFieldCell"; title = "hour(s)"; ObjectID = "L5X-oH-TrN"; */ "L5X-oH-TrN.title" = "hour(s)"; /* Class = "NSButtonCell"; title = "Launch OCS Agent at daemon start"; ObjectID = "dlF-LS-rTI"; */ "dlF-LS-rTI.title" = "Launch OCS Agent at daemon start"; /* Class = "NSButtonCell"; title = "Launch daemon after install"; ObjectID = "kI2-ox-p1X"; */ "kI2-ox-p1X.title" = "Launch daemon after install"; InfoPlist.strings000066400000000000000000000001441372663377700370650ustar00rootroot00000000000000UnixAgent-2.8/macosx/ocsinventory_packages_setup/daemonconfig.bundle/Contents/Resources/en.lprojInstallerSectionTitle = "Daemon configuration"; Localizable.strings000066400000000000000000000007541372663377700374060ustar00rootroot00000000000000UnixAgent-2.8/macosx/ocsinventory_packages_setup/daemonconfig.bundle/Contents/Resources/en.lproj/* Localized versions of Info.plist keys */ "PaneTitle" = "OCS agent daemon options"; //Peridocity warn "Periodicity_warn"="Invalid periodicity value"; //Periodicity warn comment "Periodicity_warn_comment"="Please enter a valid number value"; UnixAgent-2.8/macosx/ocsinventory_packages_setup/daemonconfig.bundle/Contents/_CodeSignature/000077500000000000000000000000001372663377700330155ustar00rootroot00000000000000CodeResources000066400000000000000000000074171372663377700354370ustar00rootroot00000000000000UnixAgent-2.8/macosx/ocsinventory_packages_setup/daemonconfig.bundle/Contents/_CodeSignature files Resources/Base.lproj/DaemonConfigPane.nib Pu4PmcDFtaJLc1EkcDgVrS9crXA= Resources/InstallerSections.plist FmRNRuAEAYqK2RpLIFeIg+9+eiU= Resources/en.lproj/DaemonConfigPane.strings hash eiGDqgREZn8HceRx9B8K/gkZH04= optional Resources/en.lproj/InfoPlist.strings hash Ap5X6SZrkIlC/1YsU77r6gFzm/k= optional Resources/en.lproj/Localizable.strings hash QfqBhmtEWE7k7/JEDj9TMckLuYY= optional files2 Resources/Base.lproj/DaemonConfigPane.nib hash2 sWdxk/B8D7oofAZaGimwxEp5vEwWzzHK/o6ixyak0D0= Resources/InstallerSections.plist hash2 2P+v0n1PTQjdpYze2cgaBZ20QzsklEInKYnQFbgHigo= Resources/en.lproj/DaemonConfigPane.strings hash2 ch/7In9R0lRrq8IKXcyfgevRJNnS6wGSfc70wd5AN9c= optional Resources/en.lproj/InfoPlist.strings hash2 GWlsYxdk4Xhflv7F+rV96boG3puquJ6R2TTtqmKzkIc= optional Resources/en.lproj/Localizable.strings hash2 F5eHWu45VUsWfzZPxEBjkaB/9TJLEZToW7wQmQs25Cc= optional rules ^Resources/ ^Resources/.*\.lproj/ optional weight 1000 ^Resources/.*\.lproj/locversion.plist$ omit weight 1100 ^Resources/Base\.lproj/ weight 1010 ^version.plist$ rules2 .*\.dSYM($|/) weight 11 ^(.*/)?\.DS_Store$ omit weight 2000 ^(Frameworks|SharedFrameworks|PlugIns|Plug-ins|XPCServices|Helpers|MacOS|Library/(Automator|Spotlight|LoginItems))/ nested weight 10 ^.* ^Info\.plist$ omit weight 20 ^PkgInfo$ omit weight 20 ^Resources/ weight 20 ^Resources/.*\.lproj/ optional weight 1000 ^Resources/.*\.lproj/locversion.plist$ omit weight 1100 ^Resources/Base\.lproj/ weight 1010 ^[^/]+$ nested weight 10 ^embedded\.provisionprofile$ weight 20 ^version\.plist$ weight 20 UnixAgent-2.8/macosx/ocsinventory_packages_setup/license/000077500000000000000000000000001372663377700240465ustar00rootroot00000000000000UnixAgent-2.8/macosx/ocsinventory_packages_setup/license/gpl-2.0.txt000066400000000000000000000432541372663377700256760ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. UnixAgent-2.8/macosx/ocsinventory_packages_setup/logos/000077500000000000000000000000001372663377700235475ustar00rootroot00000000000000UnixAgent-2.8/macosx/ocsinventory_packages_setup/logos/OCS_logo.jpg000077500000000000000000000245671372663377700257360ustar00rootroot00000000000000PNG  IHDR,rF pHYs.#.#x?v OiCCPPhotoshop ICC profilexڝSgTS=BKKoR RB&*! J!QEEȠQ, !{kּ> H3Q5 B.@ $pd!s#~<<+"x M0B\t8K@zB@F&S`cbP-`'{[! eDh;VEX0fK9-0IWfH  0Q){`##xFW<+*x<$9E[-qWW.(I+6aa@.y24x6_-"bbϫp@t~,/;m%h^ uf@Wp~<5j>{-]cK'Xto(hw?G%fIq^D$.Tʳ?D*A, `6B$BB dr`)B(Ͱ*`/@4Qhp.U=pa( Aa!ڈbX#!H$ ɈQ"K5H1RT UH=r9\F;2G1Q= C7F dt1r=6Ыhڏ>C03l0.B8, c˱" VcϱwE 6wB aAHXLXNH $4 7 Q'"K&b21XH,#/{C7$C2'ITFnR#,4H#dk9, +ȅ3![ b@qS(RjJ4e2AURݨT5ZBRQ4u9̓IKhhitݕNWGw Ljg(gwLӋT071oUX**| J&*/Tު UUT^S}FU3S ԖUPSSg;goT?~YYLOCQ_ cx,!k u5&|v*=9C3J3WRf?qtN (~))4L1e\kXHQG6EYAJ'\'GgSSݧ M=:.kDwn^Loy}/TmG X $ <5qo</QC]@Caaᄑ.ȽJtq]zۯ6iܟ4)Y3sCQ? 0k߬~OCOg#/c/Wװwa>>r><72Y_7ȷOo_C#dz%gA[z|!?:eAAA!h쐭!ΑiP~aa~ 'W?pX15wCsDDDޛg1O9-J5*>.j<74?.fYXXIlK9.*6nl {/]py.,:@LN8A*%w% yg"/6шC\*NH*Mz쑼5y$3,幄'L Lݛ:v m2=:1qB!Mggfvˬen/kY- BTZ(*geWf͉9+̳ې7ᒶKW-X潬j9(xoʿܔĹdff-[n ڴ VE/(ۻCɾUUMfeI?m]Nmq#׹=TR+Gw- 6 U#pDy  :v{vg/jBFS[b[O>zG499?rCd&ˮ/~јѡ򗓿m|x31^VwwO| (hSЧc3- cHRMz%u0`:o_FIDATxyTŹ ; EEAE\@ D 5^1.֘nqԸt4brMr5+jsܐ#ffT6MOm癇sN꭯"444ra&PR?X,D:顠D5 Q;,MXGVOO'0= ԄduX;b`J,i9:xagaih6Yu>jipn |VkX_h3P&, Ӯ|Z{`p&, X]ŏ5aihk8MX!Zq1XFA\h;hkhhhDэ!V԰}6h҄kۭ> ŰG|cM9oz!+-FnW1=ag~w=,@SIL~TJO KȳwMTV6^*$eYJJln<D_2+(1։ >iw _2T6a1@|5ax x2|^a@v@?LORV%1W,s8ZF]u y456tL M+fS&+~ \t,-:P&?tu |#Dl-)Z"m Cq {٪yLz<^&qA5X ,C3PQd)R۸GUc#}a45RjYtVdq1 85|[~\WѹWgj|w"B"GV eq>oF T #*7Hp}q:+`i`6R&X6MYS.',ӣM#33&RoCN\{f䴃i+UXȒ5-=pб{=gs (Ih+%-HpkIWpDs~ gjyTN2 wHΙ)r]Kag]-5zXfj<9zWKظd]>OmU- <3&iقJ7ݗgLWGXWʉڵu' CͶ]w xlK&,l6ӴC}9v:1_<"j^3:ZƘ+ǥu=MXق2t0H]vcNc|= >y⃜| sE~J=ɉ&,l}uW1u]zwa[xs:F`'y{F~%cSNjd  >Cn4F[3@$ئ=ġu>LzT ld3_z/fCڷ7t.)ࣩAFn  nC ozP -~k>+B(\Uv޸U*q(-#oS˒PSǏOc]CJՄM<a#^. D߶+W/}@:vأ3.<8]6;{ 9Y{lUi`k&AĚ, C'"z&TE[NuA(\ʎ)ݶYz%lX~6kds[X W;C7duECm[>zWZ6@TkmozMX& SC,G L=Ԅ9I;Gm&,<ղ*+O! o^FFhDBG1p~뚰4򛴶U* Gߺ&,&@$x?˨J:g7yUC-xLJs{T)Y MXHb9au`)`xm/_ɩ:tDo 54'֕@PzW9")=]fХOWv;RPkX,~y_3?eGP_SzKEeU[B <Ѳ{W^ҜӰ6VyFLňVu&VBG-O5!?pGH~{y Qϒa:k}/21"5{V]u-ZφEk.( VJThSuN2Pp pG8 NgW( 68Շ߱J>DiDUyOUhO.VI&+JڹyT**lJg4pB5q>[ﶰ?ԡ@dՁV s٣M#^Lf cv70/(n!_|'?T m CP6(4< F#c(y, Cv>~gw`,p)%ACKX~߁y&n ?2&"<,BxeYt?M;I^x&WDWx9 ƛ8KpC埆* duz8w9}Hp0Gd<@$MGC[WL-.q٬UNA$!NI@$8yؤEa",tܘ@$FlBvcZ|{`="Uw{* ?BI5nvE@ +a%p.5bH |>Β.b`616c_~8- V'1E86q!2pu Di3.  fpL ܐzTj3Y-äBZP'VZ=) x82 m\ Lt{ |8XNd-pĵ&)J"@ Xqϰ?Γ?T1ah 5;V#+j@Y ;8(pRmF8d x6 J;2Lhgh9>:\)~(*D!)$;H9GroV"%128Qz?T\ DIy&Ṳe444$vGp`1@ #U;zqeºB cu4§iG:kZTpBZTxb5R Ԣ*H ;4rQh@3*# T WkT5aia]j Qp"hױ?ӢjЄS(Oȿ0-؍ *]vIhi"zG3,]s"`ؕ Ǯ5:v&sg'e;IlױWets;R$nnզ4JhH"ôFțo]+_~$Ru &`0 \v"͏eflIױ_j>b.Oʖ| (FW(HQ"ױ7zLlXPg]0:#Nls~9Gc]Ƕcdq!"TS|< <:h~ERUcWxI%'vA $BD28ױ$٦؏G䔏CѦv&= Qױ7+ٚ*h~$K[{aZMql Y]fؽ^$vC u]i ~K*8u-11mMczTN0ZP ӺXP$e8u\sO`("%:tF Ώ$!^Eo=9 $Yz4SĻGr/]~H&DYXt0c񮂴ul 2=4cQŠ\@$=γuGL8'lXd{ {*P=?0/ `2aZYo7oH-1 S dԚu| 4 Ӛ!yY!'ôF>B!`tv))\K jD DA "!cXn]i ۢ Od`vCV\yPQ]juׁ%$Ѥ-6e$W]=U;-E}JJ6%;k" _R1lK'F&%bVkQ.~KY8BQ<㕉HSW(;LC3$Yôv~aMg 5uծcfF׷ű/Á :) \{kt +&^^DO?twTKvOO*ٍ  Z+Vp` YBijXIIQ1Z*Ṃqg<4MLRjŅRe,rxǮ5Lk*`yLv#MP{}땳*C74V%z)0:l%{IX*#:Gi h:ױϔ/*;ô'˚V 7uiIÌtpSY?%hLq;m(ln)u-i=NbTv\Ǯ"؞QR*YUMô-Nki2e> )s݊`(.3NW߼Ѯ7ORD]IU^dT'[G͛/ JFzugJde[~ L?Qf42JXm: G^Db)lHgi4V1}* mV(5fƜb~x4/ʚ2LXy M3LkߨBu{{vd5UdFu$zҩo%K5 oq~wT BF?k|[}J7wG8f6U w-Ym[oMS ōcYL8/Te[u&J׉jESƄ?^6 Ӛ:ca= C/ad'|co'z4=0;=TTߺBkl[c3K TJufôf) 9b=,j )"666x0n$*;;]Fo2%Tdzq!Qf(frG+0i-2L,lt]nSbxô40z\/"`Uv(>\npv꧊c/o[ݵg0w ӚcWҶߧyN: 0نiوL*Aϧ0i5u܋Z&Յױo'eV11oiKVʑcG Ӻ=Nc4PED'}ôV"/}+ `Xv?pN RE/=h5?U:{2{BptV#ˆvH:6<.R%\Kps-aWP LK[6dfz=Rnȃ]yo7+dױZΖpJ<ݨ@%1""&\XaW#36;",xŞA9ҫΩ|o fJHo<<}.TױF/Hf`=K0[!hy=W f@d^x90I:`GID \=3g#ܒ D?Tu!ADMh1pI xaZGU'ZV95k/DxIDxr.F'yدf` #include #include /***************************************************** * GetAllPIDsForProcessName ***************************************************** * Purpose: This functions purpose is to lookup a BSD * process PID given the BSD process name. This function may * potentially return multiple PIDs for a given BSD process name * since several processes can have the same BSD process name. * * Parameters: * ProcessName A constant C-string. On calling * GetAllPIDsForProcessName this variable holds the BSD process name * used to do the process lookup. Note that the process name you need * to pass is the name of the BSD executable process. If trying * to find the PID of an regular OSX application you will need to pass the * name of the actual BSD executable inside an application bundle (rather * than the bundle name itself). In any case as a user you can find the * BSD process name of any process (including OSX applications) by * typing the command "ps -axcocommand,pid" in terminal. * * ArrayOfReturnedPIDs A pointer to a pre-allocated array of pid_t. * On calling GetAllPIDsForProcessName this variable must be a pointer to a * pre-allocated array of pid_t whos length (in number of pid_t entries) is defined * in ArrayOfPIDsLength. On successful return from GetAllPIDsForProcessName * this array will hold the PIDs of all processes which have a matching process * name to that specified in the ProcessName input variable. The number of actual * PIDs entered in the array starting at index zero will be the value returned * in NumberOfMatchesFound. On failed return if the error is a buffer overflow * error then the buffer will be filled to the max with PIDs which matched. * Otherwise on failed return the state of the array will be undefined. Note * the returned PID array is not sorted and is listed in order of process encountered. * * NumberOfPossiblePIDsInArray A unsigned integer. On calling * GetAllPIDsForProcessName this variable will hold the number of * pre-allocated PID entries which are in the ArrayOfReturnedPIDs for this functions * use. Note this value must have a value greater than zero. * * NumberOfMatchesFound An unsigned integer. On calling GetAllPIDsForProcessName * this variable will point to a pre-allocated unsigned integer. On return from * GetAllPIDsForProcessName this variable will contain the number of PIDs contained in the * ArrayOfReturnedPIDs. On failed return the value of the variable will be undefined. * * SysctlError A pointer to a pre-allocated integer. On failed return, this * variable represents the error returned from the sysctl command. On function * success this variable will have a value specified by the sysctl based on the * error that occurred. On success the variable will have the value zero. * Note this variable can also be NULL in which case the variable is ignored. * * *Function Result* A integer return value. * See result codes listed below. * Result Codes: * 0 Success. A set of process PIDs were found and are located in * ArrayOfReturnedPIDs array. * -1 Could not find a process with a matching process name * (i.e. process not found). * -2 Invalid arguments passed. * -3 Unable to get the size of sysctl buffer required * (consult SysctlError return value for more information) * -4 Unable to allocate memory to store BSD process information * (consult SysctlError return value for more information) * -5 The array passed to hold the returned PIDs is not large enough * to hold all PIDs of process with matching names. * *****************************************************/ int GetAllPIDsForProcessName(const char* ProcessName, pid_t ArrayOfReturnedPIDs[], const unsigned int NumberOfPossiblePIDsInArray, unsigned int* NumberOfMatchesFound, int* SysctlError) { // --- Defining local variables for this function and initializing all to zero --- // int mib[6] = {0,0,0,0,0,0}; //used for sysctl call. int SuccessfullyGotProcessInformation; size_t sizeOfBufferRequired = 0; //set to zero to start with. int error = 0; long NumberOfRunningProcesses = 0; unsigned int Counter = 0; struct kinfo_proc* BSDProcessInformationStructure = NULL; pid_t CurrentExaminedProcessPID = 0; char* CurrentExaminedProcessName = NULL; // --- Checking input arguments for validity --- // if (ProcessName == NULL) //need valid process name { return(kInvalidArgumentsError); } if (ArrayOfReturnedPIDs == NULL) //need an actual array { return(kInvalidArgumentsError); } if (NumberOfPossiblePIDsInArray <= 0) { //length of the array must be larger than zero. return(kInvalidArgumentsError); } if (NumberOfMatchesFound == NULL) //need an integer for return. { return(kInvalidArgumentsError); } //--- Setting return values to known values --- // //initalizing PID array so all values are zero memset(ArrayOfReturnedPIDs, 0, NumberOfPossiblePIDsInArray * sizeof(pid_t)); *NumberOfMatchesFound = 0; //no matches found yet if (SysctlError != NULL) //only set sysctlError if it is present { *SysctlError = 0; } //--- Getting list of process information for all processes --- // /* Setting up the mib (Management Information Base) which is an array of integers where each * integer specifies how the data will be gathered. Here we are setting the MIB * block to lookup the information on all the BSD processes on the system. Also note that * every regular application has a recognized BSD process accociated with it. We pass * CTL_KERN, KERN_PROC, KERN_PROC_ALL to sysctl as the MIB to get back a BSD structure with * all BSD process information for all processes in it (including BSD process names) */ mib[0] = CTL_KERN; mib[1] = KERN_PROC; mib[2] = KERN_PROC_ALL; /* Here we have a loop set up where we keep calling sysctl until we finally get an unrecoverable error * (and we return) or we finally get a successful result. Note with how dynamic the process list can * be you can expect to have a failure here and there since the process list can change between * getting the size of buffer required and the actually filling that buffer. */ SuccessfullyGotProcessInformation = FALSE; while (SuccessfullyGotProcessInformation == FALSE) { /* Now that we have the MIB for looking up process information we will pass it to sysctl to get the * information we want on BSD processes. However, before we do this we must know the size of the buffer to * allocate to accomidate the return value. We can get the size of the data to allocate also using the * sysctl command. In this case we call sysctl with the proper arguments but specify no return buffer * specified (null buffer). This is a special case which causes sysctl to return the size of buffer required. * * First Argument: The MIB which is really just an array of integers. Each integer is a constant * representing what information to gather from the system. Check out the man page to know what * constants sysctl will work with. Here of course we pass our MIB block which was passed to us. * Second Argument: The number of constants in the MIB (array of integers). In this case there are three. * Third Argument: The output buffer where the return value from sysctl will be stored. In this case * we don't want anything return yet since we don't yet know the size of buffer needed. Thus we will * pass null for the buffer to begin with. * Forth Argument: The size of the output buffer required. Since the buffer itself is null we can just * get the buffer size needed back from this call. * Fifth Argument: The new value we want the system data to have. Here we don't want to set any system * information we only want to gather it. Thus, we pass null as the buffer so sysctl knows that * we have no desire to set the value. * Sixth Argument: The length of the buffer containing new information (argument five). In this case * argument five was null since we didn't want to set the system value. Thus, the size of the buffer * is zero or NULL. * Return Value: a return value indicating success or failure. Actually, sysctl will either return * zero on no error and -1 on error. The errno UNIX variable will be set on error. */ error = sysctl(mib, 3, NULL, &sizeOfBufferRequired, NULL, 0); /* If an error occurred then return the accociated error. The error itself actually is stored in the UNIX * errno variable. We can access the errno value using the errno global variable. We will return the * errno value as the sysctlError return value from this function. */ if (error != 0) { if (SysctlError != NULL) { *SysctlError = errno; //we only set this variable if the pre-allocated variable is given } return(kErrorGettingSizeOfBufferRequired); } /* Now we successful obtained the size of the buffer required for the sysctl call. This is stored in the * SizeOfBufferRequired variable. We will malloc a buffer of that size to hold the sysctl result. */ BSDProcessInformationStructure = (struct kinfo_proc*) malloc(sizeOfBufferRequired); if (BSDProcessInformationStructure == NULL) { if (SysctlError != NULL) { *SysctlError = ENOMEM; //we only set this variable if the pre-allocated variable is given } return(kUnableToAllocateMemoryForBuffer); //unrecoverable error (no memory available) so give up } /* Now we have the buffer of the correct size to hold the result we can now call sysctl * and get the process information. * * First Argument: The MIB for gathering information on running BSD processes. The MIB is really * just an array of integers. Each integer is a constant representing what information to * gather from the system. Check out the man page to know what constants sysctl will work with. * Second Argument: The number of constants in the MIB (array of integers). In this case there are three. * Third Argument: The output buffer where the return value from sysctl will be stored. This is the buffer * which we allocated specifically for this purpose. * Forth Argument: The size of the output buffer (argument three). In this case its the size of the * buffer we already allocated. * Fifth Argument: The buffer containing the value to set the system value to. In this case we don't * want to set any system information we only want to gather it. Thus, we pass null as the buffer * so sysctl knows that we have no desire to set the value. * Sixth Argument: The length of the buffer containing new information (argument five). In this case * argument five was null since we didn't want to set the system value. Thus, the size of the buffer * is zero or NULL. * Return Value: a return value indicating success or failure. Actually, sysctl will either return * zero on no error and -1 on error. The errno UNIX variable will be set on error. */ error = sysctl(mib, 3, BSDProcessInformationStructure, &sizeOfBufferRequired, NULL, 0); //Here we successfully got the process information. Thus set the variable to end this sysctl calling loop if (error == 0) { SuccessfullyGotProcessInformation = TRUE; } else { /* failed getting process information we will try again next time around the loop. Note this is caused * by the fact the process list changed between getting the size of the buffer and actually filling * the buffer (something which will happen from time to time since the process list is dynamic). * Anyways, the attempted sysctl call failed. We will now begin again by freeing up the allocated * buffer and starting again at the beginning of the loop. */ free(BSDProcessInformationStructure); } }//end while loop // --- Going through process list looking for processes with matching names --- // /* Now that we have the BSD structure describing the running processes we will parse it for the desired * process name. First we will the number of running processes. We can determine * the number of processes running because there is a kinfo_proc structure for each process. */ NumberOfRunningProcesses = sizeOfBufferRequired / sizeof(struct kinfo_proc); /* Now we will go through each process description checking to see if the process name matches that * passed to us. The BSDProcessInformationStructure has an array of kinfo_procs. Each kinfo_proc has * an extern_proc accociated with it in the kp_proc attribute. Each extern_proc (kp_proc) has the process name * of the process accociated with it in the p_comm attribute and the PID of that process in the p_pid attibute. * We test the process name by compairing the process name passed to us with the value in the p_comm value. * Note we limit the compairison to MAXCOMLEN which is the maximum length of a BSD process name which is used * by the system. */ for (Counter = 0 ; Counter < NumberOfRunningProcesses ; Counter++) { //Getting PID of process we are examining CurrentExaminedProcessPID = BSDProcessInformationStructure[Counter].kp_proc.p_pid; //Getting name of process we are examining CurrentExaminedProcessName = BSDProcessInformationStructure[Counter].kp_proc.p_comm; if ((CurrentExaminedProcessPID > 0) //Valid PID && ((strncmp(CurrentExaminedProcessName, ProcessName, MAXCOMLEN) == 0))) //name matches { // --- Got a match add it to the array if possible --- // if ((*NumberOfMatchesFound + 1) > NumberOfPossiblePIDsInArray) { //if we overran the array buffer passed we release the allocated buffer give an error. free(BSDProcessInformationStructure); return(kPIDBufferOverrunError); } //adding the value to the array. ArrayOfReturnedPIDs[*NumberOfMatchesFound] = CurrentExaminedProcessPID; //incrementing our number of matches found. *NumberOfMatchesFound = *NumberOfMatchesFound + 1; } }//end looking through process list free(BSDProcessInformationStructure); //done with allocated buffer so release. if (*NumberOfMatchesFound == 0) { //didn't find any matches return error. return(kCouldNotFindRequestedProcess); } else { //found matches return success. return(kSuccess); } } /***************************************************** * GetPIDForProcessName ***************************************************** * Purpose: A convience call for GetAllPIDsForProcessName(). * This function looks up a process PID given a BSD process * name. * * Parameters: * ProcessName A constant C-string. On calling * GetPIDForProcessName this variable holds the BSD process name * used to do the process lookup. Note that the process name you need * to pass is the name of the BSD executable process. If trying * to find the PID of an regular OSX application you will need to pass the * name of the actual BSD executable inside an application bundle (rather * than the bundle name itself). In any case as a user you can find the * BSD process name of any process (including OSX applications) by * typing the command "ps -axcocommand,pid" in terminal. * * *Function Result* A integer return value. * See result codes listed below. * Result Codes: * >0 Success. The value returned is the PID of the * matching process. * -1 Error getting PID for requested process. This error can * be caused by several things. One is if no such process exists. * Another is if more than one process has the given name. The * thing to do here is to call GetAllPIDsForProcessName() * for complete error code or to get PIDs if there are multiple * processes with that name. *****************************************************/ int GetPIDForProcessName(const char* ProcessName) { pid_t PIDArray[1] = {0}; int Error = 0; unsigned int NumberOfMatches = 0; /* Here we are calling the function GetAllPIDsForProcessName which wil give us the PIDs * of the process name we pass. Of course here we are hoping for a single PID return. * First Argument: The BSD process name of the process we want to lookup. In this case the * the process name passed to us. * Second Argument: A preallocated array of pid_t. This is where the PIDs of matching processes * will be placed on return. We pass the array we just allocated which is length one. * Third Argument: The number of pid_t entries located in the array of pid_t (argument 2). In this * case our array has one pid_t entry so pass one. * Forth Argument: On return this will hold the number of PIDs placed into the * pid_t array (array passed in argument 2). * Fifth Argument: Passing NULL to ignore this argument. * Return Value: An error indicating success (zero result) or failure (non-zero). * */ Error = GetAllPIDsForProcessName(ProcessName, PIDArray, 1, &NumberOfMatches, NULL); if ((Error == 0) && (NumberOfMatches == 1))//success! { return((int) PIDArray[0]); //return the one PID we found. } else { return(-1); } } UnixAgent-2.8/macosx/ocsng_app-xcode/GetPID.h000077500000000000000000000207141372663377700211110ustar00rootroot00000000000000/* File: GetPID.h Description: This file defines a simple API to do process PID lookup based on process name. Author: Chad Jones Copyright: Copyright 2003 Apple Computer, Inc. All rights reserved. Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc. ("Apple") in consideration of your agreement to the following terms, and your use, installation, modification or redistribution of this Apple software constitutes acceptance of these terms. If you do not agree with these terms, please do not use, install, modify or redistribute this Apple software. In consideration of your agreement to abide by the following terms, and subject to these terms, Apple grants you a personal, non-exclusive license, under Apples copyrights in this original Apple software (the "Apple Software"), to use, reproduce, modify and redistribute the Apple Software, with or without modifications, in source and/or binary forms; provided that if you redistribute the Apple Software in its entirety and without modifications, you must retain this notice and the following text and disclaimers in all such redistributions of the Apple Software. Neither the name, trademarks, service marks or logos of Apple Computer, Inc. may be used to endorse or promote products derived from the Apple Software without specific prior written permission from Apple. Except as expressly stated in this notice, no other rights or licenses, express or implied, are granted by Apple herein, including but not limited to any patent rights that may be infringed by your derivative works or by other works in which the Apple Software may be incorporated. The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. Change History (most recent first): */ #if !defined(__DTSSampleCode_GetPID__) #define __DTSSampleCode_GetPID__ 1 #include #include #if defined(__cplusplus) extern "C" { #endif // --- Defining constants for use with sample code --- // enum {kSuccess = 0, kCouldNotFindRequestedProcess = -1, kInvalidArgumentsError = -2, kErrorGettingSizeOfBufferRequired = -3, kUnableToAllocateMemoryForBuffer = -4, kPIDBufferOverrunError = -5}; /***************************************************** * GetAllPIDsForProcessName ***************************************************** * Purpose: This functions purpose is to lookup a BSD * process PID given the BSD process name. This function may * potentially return multiple PIDs for a given BSD process name * since several processes can have the same BSD process name. * * Parameters: * ProcessName A constant C-string. On calling * GetAllPIDsForProcessName this variable holds the BSD process name * used to do the process lookup. Note that the process name you need * to pass is the name of the BSD executable process. If trying * to find the PID of an regular OSX application you will need to pass the * name of the actual BSD executable inside an application bundle (rather * than the bundle name itself). In any case as a user you can find the * BSD process name of any process (including OSX applications) by * typing the command "ps -axcocommand,pid" in terminal. * * ArrayOfReturnedPIDs A pointer to a pre-allocated array of pid_t. * On calling GetAllPIDsForProcessName this variable must be a pointer to a * pre-allocated array of pid_t whos length (in number of pid_t entries) is defined * in ArrayOfPIDsLength. On successful return from GetAllPIDsForProcessName * this array will hold the PIDs of all processes which have a matching process * name to that specified in the ProcessName input variable. The number of actual * PIDs entered in the array starting at index zero will be the value returned * in NumberOfMatchesFound. On failed return if the error is a buffer overflow * error then the buffer will be filled to the max with PIDs which matched. * Otherwise on failed return the state of the array will be undefined. * * NumberOfPossiblePIDsInArray A unsigned integer. On calling * GetAllPIDsForProcessName this variable will hold the number of * pre-allocated PID entries which are in the ArrayOfReturnedPIDs for this functions * use. Note this value must have a value greater than zero. * * NumberOfMatchesFound An unsigned integer. On calling GetAllPIDsForProcessName * this variable will point to a pre-allocated unsigned integer. On return from * GetAllPIDsForProcessName this variable will contain the number of PIDs contained in the * ArrayOfReturnedPIDs. On failed return the value of the variable will be undefined. * * SysctlError A pointer to a pre-allocated integer. On failed return, this * variable represents the error returned from the sysctl command. On function * success this variable will have a value specified by the sysctl based on the * error that occurred. On success the variable will have the value zero. * Note this variable can also be NULL in which case the variable is ignored. * * *Function Result* A integer return value. * See result codes listed below. * Result Codes: * 0 Success. A set of process PIDs were found and are located in * ArrayOfReturnedPIDs array. * -1 Could not find a process with a matching process name * (i.e. process not found). * -2 Invalid arguments passed. * -3 Unable to get the size of sysctl buffer required * (consult SysctlError return value for more information) * -4 Unable to allocate memory to store BSD process information * (consult SysctlError return value for more information) * -5 The array passed to hold the returned PIDs is not large enough * to hold all PIDs of process with matching names. * *****************************************************/ int GetAllPIDsForProcessName(const char* ProcessName, pid_t ArrayOfReturnedPIDs[], const unsigned int NumberOfPossiblePIDsInArray, unsigned int* NumberOfMatchesFound, int* SysctlError); //Can be NULL /***************************************************** * GetPIDForProcessName ***************************************************** * Purpose: A convience call for GetAllPIDsForProcessName(). * This function looks up a process PID given a BSD process * name. * * Parameters: * ProcessName A constant C-string. On calling * GetPIDForProcessName this variable holds the BSD process name * used to do the process lookup. Note that the process name you need * to pass is the name of the BSD executable process. If trying * to find the PID of an regular OSX application you will need to pass the * name of the actual BSD executable inside an application bundle (rather * than the bundle name itself). In any case as a user you can find the * BSD process name of any process (including OSX applications) by * typing the command "ps -axcocommand,pid" in terminal. * * *Function Result* A integer return value. * See result codes listed below. * Result Codes: * >=0 Success. The value returned is the PID of the * requested process. * -1 Error getting PID for requested process. This error can * be caused by several things. One is if no such process exists. * Another is if more than one process has the given name. The * Answer is to call GetAllPIDsForProcessName() * for complete error code or to get PIDs if there are multiple * processes with that name. *****************************************************/ int GetPIDForProcessName(const char* ProcessName); #if defined(__cplusplus) } #endif #endifUnixAgent-2.8/macosx/ocsng_app-xcode/Info.plist000066400000000000000000000015551372663377700216330ustar00rootroot00000000000000 CFBundleDevelopmentRegion English CFBundleExecutable ${EXECUTABLE_NAME} CFBundleIconFile ocs_logo CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName ${PRODUCT_NAME} CFBundlePackageType APPL CFBundleSignature OCNG CFBundleVersion $(CURRENT_PROJECT_VERSION) LSApplicationCategoryType public.app-category.utilities LSUIElement UnixAgent-2.8/macosx/ocsng_app-xcode/OCSNG.xcodeproj/000077500000000000000000000000001372663377700225225ustar00rootroot00000000000000UnixAgent-2.8/macosx/ocsng_app-xcode/OCSNG.xcodeproj/ocs.mode1000066400000000000000000001171621372663377700242450ustar00rootroot00000000000000 ActivePerspectiveName Project AllowedModules BundleLoadPath MaxInstances n Module PBXSmartGroupTreeModule Name Groups and Files Outline View BundleLoadPath MaxInstances n Module PBXNavigatorGroup Name Editor BundleLoadPath MaxInstances n Module XCTaskListModule Name Task List BundleLoadPath MaxInstances n Module XCDetailModule Name File and Smart Group Detail Viewer BundleLoadPath MaxInstances 1 Module PBXBuildResultsModule Name Detailed Build Results Viewer BundleLoadPath MaxInstances 1 Module PBXProjectFindModule Name Project Batch Find Tool BundleLoadPath MaxInstances n Module PBXRunSessionModule Name Run Log BundleLoadPath MaxInstances n Module PBXBookmarksModule Name Bookmarks Tool BundleLoadPath MaxInstances n Module PBXClassBrowserModule Name Class Browser BundleLoadPath MaxInstances n Module PBXCVSModule Name Source Code Control Tool BundleLoadPath MaxInstances n Module PBXDebugBreakpointsModule Name Debug Breakpoints Tool BundleLoadPath MaxInstances n Module XCDockableInspector Name Inspector BundleLoadPath MaxInstances n Module PBXOpenQuicklyModule Name Open Quickly Tool BundleLoadPath MaxInstances 1 Module PBXDebugSessionModule Name Debugger BundleLoadPath MaxInstances 1 Module PBXDebugCLIModule Name Debug Console Description DefaultDescriptionKey DockingSystemVisible Extension mode1 FavBarConfig PBXProjectModuleGUID 061EA96D130275AC009A0BD6 XCBarModuleItemNames XCBarModuleItems FirstTimeWindowDisplayed Identifier com.apple.perspectives.project.mode1 MajorVersion 31 MinorVersion 1 Name Default Notifications OpenEditors Content PBXProjectModuleGUID 06C5590613CC1F6A00405FC9 PBXProjectModuleLabel main.m PBXSplitModuleInNavigatorKey Split0 PBXProjectModuleGUID 06C5590713CC1F6A00405FC9 PBXProjectModuleLabel main.m _historyCapacity 0 bookmark 06C5593E13CC2EFB00405FC9 history 06C5591D13CC27B200405FC9 SplitCount 1 StatusBarVisibility Geometry Frame {{0, 20}, {948, 609}} PBXModuleWindowStatusBarHidden2 RubberWindowFrame 390 203 948 650 0 0 1440 878 PerspectiveWidths -1 -1 Perspectives ChosenToolbarItems active-target-popup active-buildstyle-popup action NSToolbarFlexibleSpaceItem buildOrClean build-and-runOrDebug com.apple.ide.PBXToolbarStopButton get-info toggle-editor NSToolbarFlexibleSpaceItem com.apple.pbx.toolbar.searchfield ControllerClassBaseName IconName WindowOfProjectWithEditor Identifier perspective.project IsVertical Layout BecomeActive ContentConfiguration PBXBottomSmartGroupGIDs 1C37FBAC04509CD000000102 1C37FAAC04509CD000000102 1C08E77C0454961000C914BD 1C37FABC05509CD000000102 1C37FABC05539CD112110102 E2644B35053B69B200211256 1C37FABC04509CD000100104 1CC0EA4004350EF90044410B 1CC0EA4004350EF90041110B PBXProjectModuleGUID 1CE0B1FE06471DED0097A5F4 PBXProjectModuleLabel Files PBXProjectStructureProvided yes PBXSmartGroupTreeModuleColumnData PBXSmartGroupTreeModuleColumnWidthsKey 186 PBXSmartGroupTreeModuleColumnsKey_v4 MainColumn PBXSmartGroupTreeModuleOutlineStateKey_v7 PBXSmartGroupTreeModuleOutlineStateExpansionKey 29B97314FDCFA39411CA2CEA 080E96DDFE201D6D7F000001 29B97315FDCFA39411CA2CEA 29B97317FDCFA39411CA2CEA 29B97323FDCFA39411CA2CEA 1058C7A0FEA54F0111CA2CBB 1058C7A2FEA54F0111CA2CBB 1C37FBAC04509CD000000102 06C5593713CC2B2600405FC9 06C5593813CC2B2600405FC9 1C37FABC05509CD000000102 PBXSmartGroupTreeModuleOutlineStateSelectionKey 5 3 0 PBXSmartGroupTreeModuleOutlineStateVisibleRectKey {{0, 0}, {186, 690}} PBXTopSmartGroupGIDs XCIncludePerspectivesSwitch XCSharingToken com.apple.Xcode.GFSharingToken GeometryConfiguration Frame {{0, 0}, {203, 708}} GroupTreeTableConfiguration MainColumn 186 RubberWindowFrame 10 115 1440 749 0 0 1440 878 Module PBXSmartGroupTreeModule Proportion 203pt Dock ContentConfiguration PBXProjectModuleGUID 1CE0B20306471E060097A5F4 PBXProjectModuleLabel MyNewFile14.java PBXSplitModuleInNavigatorKey Split0 PBXProjectModuleGUID 1CE0B20406471E060097A5F4 PBXProjectModuleLabel MyNewFile14.java SplitCount 1 StatusBarVisibility GeometryConfiguration Frame {{0, 0}, {1232, 0}} RubberWindowFrame 10 115 1440 749 0 0 1440 878 Module PBXNavigatorGroup Proportion 0pt ContentConfiguration PBXProjectModuleGUID 1CE0B20506471E060097A5F4 PBXProjectModuleLabel Detail GeometryConfiguration Frame {{0, 5}, {1232, 703}} RubberWindowFrame 10 115 1440 749 0 0 1440 878 Module XCDetailModule Proportion 703pt Proportion 1232pt Name Project ServiceClasses XCModuleDock PBXSmartGroupTreeModule XCModuleDock PBXNavigatorGroup XCDetailModule TableOfContents 06C5590413CC1F6A00405FC9 1CE0B1FE06471DED0097A5F4 06C5590513CC1F6A00405FC9 1CE0B20306471E060097A5F4 1CE0B20506471E060097A5F4 ToolbarConfiguration xcode.toolbar.config.default ControllerClassBaseName IconName WindowOfProject Identifier perspective.morph IsVertical 0 Layout BecomeActive 1 ContentConfiguration PBXBottomSmartGroupGIDs 1C37FBAC04509CD000000102 1C37FAAC04509CD000000102 1C08E77C0454961000C914BD 1C37FABC05509CD000000102 1C37FABC05539CD112110102 E2644B35053B69B200211256 1C37FABC04509CD000100104 1CC0EA4004350EF90044410B 1CC0EA4004350EF90041110B PBXProjectModuleGUID 11E0B1FE06471DED0097A5F4 PBXProjectModuleLabel Files PBXProjectStructureProvided yes PBXSmartGroupTreeModuleColumnData PBXSmartGroupTreeModuleColumnWidthsKey 186 PBXSmartGroupTreeModuleColumnsKey_v4 MainColumn PBXSmartGroupTreeModuleOutlineStateKey_v7 PBXSmartGroupTreeModuleOutlineStateExpansionKey 29B97314FDCFA39411CA2CEA 1C37FABC05509CD000000102 PBXSmartGroupTreeModuleOutlineStateSelectionKey 0 PBXSmartGroupTreeModuleOutlineStateVisibleRectKey {{0, 0}, {186, 337}} PBXTopSmartGroupGIDs XCIncludePerspectivesSwitch 1 XCSharingToken com.apple.Xcode.GFSharingToken GeometryConfiguration Frame {{0, 0}, {203, 355}} GroupTreeTableConfiguration MainColumn 186 RubberWindowFrame 373 269 690 397 0 0 1440 878 Module PBXSmartGroupTreeModule Proportion 100% Name Morph PreferredWidth 300 ServiceClasses XCModuleDock PBXSmartGroupTreeModule TableOfContents 11E0B1FE06471DED0097A5F4 ToolbarConfiguration xcode.toolbar.config.default.short PerspectivesBarVisible ShelfIsVisible SourceDescription file at '/Developer/Library/PrivateFrameworks/DevToolsInterface.framework/Versions/A/Resources/XCPerspectivesSpecificationMode1.xcperspec' StatusbarIsVisible TimeStamp 0.0 ToolbarDisplayMode 1 ToolbarIsVisible ToolbarSizeMode 1 Type Perspectives UpdateMessage The Default Workspace in this version of Xcode now includes support to hide and show the detail view (what has been referred to as the "Metro-Morph" feature). You must discard your current Default Workspace settings and update to the latest Default Workspace in order to gain this feature. Do you wish to update to the latest Workspace defaults for project '%@'? WindowJustification 5 WindowOrderList 06E04A76134C3537009FD4CA 06C5590613CC1F6A00405FC9 1C0AD2B3069F1EA900FABCE6 /Users/ocs/work/ocs/dev/ocsng_app-xcode/OCSNG.xcodeproj WindowString 10 115 1440 749 0 0 1440 878 WindowTools FirstTimeWindowDisplayed Identifier windowTool.build IsVertical Layout Dock ContentConfiguration PBXProjectModuleGUID 1CD0528F0623707200166675 PBXProjectModuleLabel main.m StatusBarVisibility GeometryConfiguration Frame {{0, 0}, {1440, 466}} RubberWindowFrame 185 -243 1440 748 0 0 1440 878 Module PBXNavigatorGroup Proportion 466pt BecomeActive ContentConfiguration PBXProjectModuleGUID XCMainBuildResultsModuleGUID PBXProjectModuleLabel Build XCBuildResultsTrigger_Collapse 1021 XCBuildResultsTrigger_Open 1011 GeometryConfiguration Frame {{0, 471}, {1440, 236}} RubberWindowFrame 185 -243 1440 748 0 0 1440 878 Module PBXBuildResultsModule Proportion 236pt Proportion 707pt Name Build Results ServiceClasses PBXBuildResultsModule StatusbarIsVisible TableOfContents 06E04A76134C3537009FD4CA 06C558F513CC1D1900405FC9 1CD0528F0623707200166675 XCMainBuildResultsModuleGUID ToolbarConfiguration xcode.toolbar.config.build WindowString 185 -243 1440 748 0 0 1440 878 WindowToolGUID 06E04A76134C3537009FD4CA WindowToolIsVisible FirstTimeWindowDisplayed Identifier windowTool.debugger IsVertical Layout Dock ContentConfiguration Debugger HorizontalSplitView _collapsingFrameDimension 0.0 _indexOfCollapsedView 0 _percentageOfCollapsedView 0.0 isCollapsed yes sizes {{0, 0}, {313, 196}} {{313, 0}, {381, 196}} VerticalSplitView _collapsingFrameDimension 0.0 _indexOfCollapsedView 0 _percentageOfCollapsedView 0.0 isCollapsed yes sizes {{0, 0}, {694, 196}} {{0, 196}, {694, 185}} LauncherConfigVersion 8 PBXProjectModuleGUID 1C162984064C10D400B95A72 PBXProjectModuleLabel Debug - GLUTExamples (Underwater) GeometryConfiguration DebugConsoleDrawerSize {100, 120} DebugConsoleVisible None DebugConsoleWindowFrame {{200, 200}, {500, 300}} DebugSTDIOWindowFrame {{200, 200}, {500, 300}} Frame {{0, 0}, {694, 381}} RubberWindowFrame 496 358 694 422 0 0 1440 878 Module PBXDebugSessionModule Proportion 381pt Proportion 381pt Name Debugger ServiceClasses PBXDebugSessionModule StatusbarIsVisible TableOfContents 1CD10A99069EF8BA00B06720 06BF31CC13CAD57A006FA767 1C162984064C10D400B95A72 06BF31CD13CAD57A006FA767 06BF31CE13CAD57A006FA767 06BF31CF13CAD57A006FA767 06BF31D013CAD57A006FA767 06BF31D113CAD57A006FA767 06BF31D213CAD57A006FA767 ToolbarConfiguration xcode.toolbar.config.debug WindowString 496 358 694 422 0 0 1440 878 WindowToolGUID 1CD10A99069EF8BA00B06720 WindowToolIsVisible Identifier windowTool.find Layout Dock Dock ContentConfiguration PBXProjectModuleGUID 1CDD528C0622207200134675 PBXProjectModuleLabel <No Editor> PBXSplitModuleInNavigatorKey Split0 PBXProjectModuleGUID 1CD0528D0623707200166675 SplitCount 1 StatusBarVisibility 1 GeometryConfiguration Frame {{0, 0}, {781, 167}} RubberWindowFrame 62 385 781 470 0 0 1440 878 Module PBXNavigatorGroup Proportion 781pt Proportion 50% BecomeActive 1 ContentConfiguration PBXProjectModuleGUID 1CD0528E0623707200166675 PBXProjectModuleLabel Project Find GeometryConfiguration Frame {{8, 0}, {773, 254}} RubberWindowFrame 62 385 781 470 0 0 1440 878 Module PBXProjectFindModule Proportion 50% Proportion 428pt Name Project Find ServiceClasses PBXProjectFindModule StatusbarIsVisible 1 TableOfContents 1C530D57069F1CE1000CFCEE 1C530D58069F1CE1000CFCEE 1C530D59069F1CE1000CFCEE 1CDD528C0622207200134675 1C530D5A069F1CE1000CFCEE 1CE0B1FE06471DED0097A5F4 1CD0528E0623707200166675 WindowString 62 385 781 470 0 0 1440 878 WindowToolGUID 1C530D57069F1CE1000CFCEE WindowToolIsVisible 0 Identifier MENUSEPARATOR FirstTimeWindowDisplayed Identifier windowTool.debuggerConsole IsVertical Layout Dock ContentConfiguration PBXProjectModuleGUID 1C78EAAC065D492600B07095 PBXProjectModuleLabel Debugger Console GeometryConfiguration Frame {{0, 0}, {440, 358}} RubberWindowFrame 73 409 440 400 0 0 1440 878 Module PBXDebugCLIModule Proportion 358pt Proportion 359pt Name Debugger Console ServiceClasses PBXDebugCLIModule StatusbarIsVisible TableOfContents 06C399E61394981F0047198A 06BF31D313CAD57A006FA767 1C78EAAC065D492600B07095 WindowString 73 409 440 400 0 0 1440 878 WindowToolGUID 06C399E61394981F0047198A WindowToolIsVisible FirstTimeWindowDisplayed Identifier windowTool.run IsVertical Layout Dock ContentConfiguration LauncherConfigVersion 3 PBXProjectModuleGUID 1CD0528B0623707200166675 PBXProjectModuleLabel Run Runner HorizontalSplitView _collapsingFrameDimension 0.0 _indexOfCollapsedView 0 _percentageOfCollapsedView 0.0 isCollapsed yes sizes {{0, 0}, {493, 167}} {{0, 176}, {493, 267}} VerticalSplitView _collapsingFrameDimension 0.0 _indexOfCollapsedView 0 _percentageOfCollapsedView 0.0 isCollapsed yes sizes {{0, 0}, {405, 443}} {{414, 0}, {514, 443}} GeometryConfiguration Frame {{0, 0}, {459, 159}} RubberWindowFrame 31 655 459 200 0 0 1440 878 Module PBXRunSessionModule Proportion 159pt Proportion 159pt Name Run Log ServiceClasses PBXRunSessionModule StatusbarIsVisible TableOfContents 1C0AD2B3069F1EA900FABCE6 06C558F613CC1D1900405FC9 1CD0528B0623707200166675 06C558F713CC1D1900405FC9 ToolbarConfiguration xcode.toolbar.config.run WindowString 31 655 459 200 0 0 1440 878 WindowToolGUID 1C0AD2B3069F1EA900FABCE6 WindowToolIsVisible Identifier windowTool.scm Layout Dock ContentConfiguration PBXProjectModuleGUID 1C78EAB2065D492600B07095 PBXProjectModuleLabel <No Editor> PBXSplitModuleInNavigatorKey Split0 PBXProjectModuleGUID 1C78EAB3065D492600B07095 SplitCount 1 StatusBarVisibility 1 GeometryConfiguration Frame {{0, 0}, {452, 0}} RubberWindowFrame 743 379 452 308 0 0 1280 1002 Module PBXNavigatorGroup Proportion 0pt BecomeActive 1 ContentConfiguration PBXProjectModuleGUID 1CD052920623707200166675 PBXProjectModuleLabel SCM GeometryConfiguration ConsoleFrame {{0, 259}, {452, 0}} Frame {{0, 7}, {452, 259}} RubberWindowFrame 743 379 452 308 0 0 1280 1002 TableConfiguration Status 30 FileName 199 Path 197.09500122070312 TableFrame {{0, 0}, {452, 250}} Module PBXCVSModule Proportion 262pt Proportion 266pt Name SCM ServiceClasses PBXCVSModule StatusbarIsVisible 1 TableOfContents 1C78EAB4065D492600B07095 1C78EAB5065D492600B07095 1C78EAB2065D492600B07095 1CD052920623707200166675 ToolbarConfiguration xcode.toolbar.config.scm WindowString 743 379 452 308 0 0 1280 1002 Identifier windowTool.breakpoints IsVertical 0 Layout Dock BecomeActive 1 ContentConfiguration PBXBottomSmartGroupGIDs 1C77FABC04509CD000000102 PBXProjectModuleGUID 1CE0B1FE06471DED0097A5F4 PBXProjectModuleLabel Files PBXProjectStructureProvided no PBXSmartGroupTreeModuleColumnData PBXSmartGroupTreeModuleColumnWidthsKey 168 PBXSmartGroupTreeModuleColumnsKey_v4 MainColumn PBXSmartGroupTreeModuleOutlineStateKey_v7 PBXSmartGroupTreeModuleOutlineStateExpansionKey 1C77FABC04509CD000000102 PBXSmartGroupTreeModuleOutlineStateSelectionKey 0 PBXSmartGroupTreeModuleOutlineStateVisibleRectKey {{0, 0}, {168, 350}} PBXTopSmartGroupGIDs XCIncludePerspectivesSwitch 0 GeometryConfiguration Frame {{0, 0}, {185, 368}} GroupTreeTableConfiguration MainColumn 168 RubberWindowFrame 315 424 744 409 0 0 1440 878 Module PBXSmartGroupTreeModule Proportion 185pt ContentConfiguration PBXProjectModuleGUID 1CA1AED706398EBD00589147 PBXProjectModuleLabel Detail GeometryConfiguration Frame {{190, 0}, {554, 368}} RubberWindowFrame 315 424 744 409 0 0 1440 878 Module XCDetailModule Proportion 554pt Proportion 368pt MajorVersion 2 MinorVersion 0 Name Breakpoints ServiceClasses PBXSmartGroupTreeModule XCDetailModule StatusbarIsVisible 1 TableOfContents 1CDDB66807F98D9800BB5817 1CDDB66907F98D9800BB5817 1CE0B1FE06471DED0097A5F4 1CA1AED706398EBD00589147 ToolbarConfiguration xcode.toolbar.config.breakpoints WindowString 315 424 744 409 0 0 1440 878 WindowToolGUID 1CDDB66807F98D9800BB5817 WindowToolIsVisible 1 Identifier windowTool.debugAnimator Layout Dock Module PBXNavigatorGroup Proportion 100% Proportion 100% Name Debug Visualizer ServiceClasses PBXNavigatorGroup StatusbarIsVisible 1 ToolbarConfiguration xcode.toolbar.config.debugAnimator WindowString 100 100 700 500 0 0 1280 1002 Identifier windowTool.bookmarks Layout Dock Module PBXBookmarksModule Proportion 100% Proportion 100% Name Bookmarks ServiceClasses PBXBookmarksModule StatusbarIsVisible 0 WindowString 538 42 401 187 0 0 1280 1002 FirstTimeWindowDisplayed Identifier windowTool.classBrowser IsVertical Layout Dock BecomeActive ContentConfiguration OptionsSetName Hierarchy, all classes PBXProjectModuleGUID 1CA6456E063B45B4001379D8 PBXProjectModuleLabel Class Browser - NSObject GeometryConfiguration ClassesFrame {{0, 0}, {378, 96}} ClassesTreeTableConfiguration PBXClassNameColumnIdentifier 208 PBXClassBookColumnIdentifier 22 Frame {{0, 0}, {630, 332}} MembersFrame {{0, 101}, {378, 231}} MembersTreeTableConfiguration PBXMemberTypeIconColumnIdentifier 22 PBXMemberNameColumnIdentifier 216 PBXMemberTypeColumnIdentifier 101 PBXMemberBookColumnIdentifier 22 RubberWindowFrame 397 461 630 352 0 0 1440 878 Module PBXClassBrowserModule Proportion 332pt Proportion 332pt Name Class Browser ServiceClasses PBXClassBrowserModule StatusbarIsVisible TableOfContents 1C0AD2AF069F1E9B00FABCE6 069BBEBB134C395300F43B40 1CA6456E063B45B4001379D8 ToolbarConfiguration xcode.toolbar.config.classbrowser WindowString 397 461 630 352 0 0 1440 878 WindowToolGUID 1C0AD2AF069F1E9B00FABCE6 WindowToolIsVisible UnixAgent-2.8/macosx/ocsng_app-xcode/OCSNG.xcodeproj/project.pbxproj000066400000000000000000000563301372663377700256050ustar00rootroot00000000000000// !$*UTF8*$! { archiveVersion = 1; classes = { }; objectVersion = 45; objects = { /* Begin PBXBuildFile section */ 0625C76F13CAC89000D6EB7C /* ocs_logo.icns in Resources */ = {isa = PBXBuildFile; fileRef = 0625C76E13CAC89000D6EB7C /* ocs_logo.icns */; }; 0649FB3414D9E198001EC640 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 0649FB3314D9E198001EC640 /* Localizable.strings */; }; 06C39B371394ADB20047198A /* CoreData.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 06C39B361394ADB20047198A /* CoreData.framework */; }; 06C39B381394ADB20047198A /* CoreData.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 06C39B361394ADB20047198A /* CoreData.framework */; }; 06C39B3A1394ADDF0047198A /* AppKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 06C39B391394ADDF0047198A /* AppKit.framework */; }; 06C39B3B1394ADDF0047198A /* AppKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 06C39B391394ADDF0047198A /* AppKit.framework */; }; 06C39BCE1394B5600047198A /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 06C39BCD1394B5600047198A /* Security.framework */; }; 06C39BCF1394B5600047198A /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 06C39BCD1394B5600047198A /* Security.framework */; }; 06D657B4134FDBFF00981FE3 /* ocscontact.m in Sources */ = {isa = PBXBuildFile; fileRef = 06D657B3134FDBFF00981FE3 /* ocscontact.m */; }; 0B6A94131F83D4E600D02E57 /* THANKS in Resources */ = {isa = PBXBuildFile; fileRef = 0B6A940E1F83D4E500D02E57 /* THANKS */; }; 0B6A94141F83D4E600D02E57 /* LICENSE in Resources */ = {isa = PBXBuildFile; fileRef = 0B6A940F1F83D4E600D02E57 /* LICENSE */; }; 0B6A94151F83D4E600D02E57 /* Changes in Resources */ = {isa = PBXBuildFile; fileRef = 0B6A94101F83D4E600D02E57 /* Changes */; }; 0B6A94161F83D4E600D02E57 /* ocsinventory-agent in Resources */ = {isa = PBXBuildFile; fileRef = 0B6A94111F83D4E600D02E57 /* ocsinventory-agent */; }; 0B6A94171F83D4E600D02E57 /* AUTHORS in Resources */ = {isa = PBXBuildFile; fileRef = 0B6A94121F83D4E600D02E57 /* AUTHORS */; }; 0B6A943E1F83DB3F00D02E57 /* uninstaller.sh in Resources */ = {isa = PBXBuildFile; fileRef = 0B6A943D1F83DB3F00D02E57 /* uninstaller.sh */; }; 438B3A6123E0D16500631B54 /* lib in Resources */ = {isa = PBXBuildFile; fileRef = 438B3A6023E0D16500631B54 /* lib */; }; 8D11072B0486CEB800E47090 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 089C165CFE840E0CC02AAC07 /* InfoPlist.strings */; }; 8D11072D0486CEB800E47090 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 29B97316FDCFA39411CA2CEA /* main.m */; settings = {ATTRIBUTES = (); }; }; 8D11072F0486CEB800E47090 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */; }; EE2C4E5B0DF1CA5800171780 /* GetPID.c in Sources */ = {isa = PBXBuildFile; fileRef = EE2C4E590DF1CA5800171780 /* GetPID.c */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ 0625C76E13CAC89000D6EB7C /* ocs_logo.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; name = ocs_logo.icns; path = icons/ocs_logo.icns; sourceTree = ""; }; 06C39B361394ADB20047198A /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = /System/Library/Frameworks/CoreData.framework; sourceTree = ""; }; 06C39B391394ADDF0047198A /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = /System/Library/Frameworks/AppKit.framework; sourceTree = ""; }; 06C39BCD1394B5600047198A /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = /System/Library/Frameworks/Security.framework; sourceTree = ""; }; 06D65785134FD5B800981FE3 /* ocscontact-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "ocscontact-Info.plist"; sourceTree = ""; }; 06D657A7134FD97A00981FE3 /* ocscontact */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = ocscontact; sourceTree = BUILT_PRODUCTS_DIR; }; 06D657B2134FDBFF00981FE3 /* ocscontact.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ocscontact.h; sourceTree = ""; }; 06D657B3134FDBFF00981FE3 /* ocscontact.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ocscontact.m; sourceTree = ""; }; 0B6A940E1F83D4E500D02E57 /* THANKS */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = THANKS; path = ../../../THANKS; sourceTree = ""; }; 0B6A940F1F83D4E600D02E57 /* LICENSE */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = LICENSE; path = ../../../LICENSE; sourceTree = ""; }; 0B6A94101F83D4E600D02E57 /* Changes */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = Changes; path = ../../../Changes; sourceTree = ""; }; 0B6A94111F83D4E600D02E57 /* ocsinventory-agent */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.perl; name = "ocsinventory-agent"; path = "../../../ocsinventory-agent"; sourceTree = ""; }; 0B6A94121F83D4E600D02E57 /* AUTHORS */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = AUTHORS; path = ../../../AUTHORS; sourceTree = ""; }; 0B6A943D1F83DB3F00D02E57 /* uninstaller.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; name = uninstaller.sh; path = ../scripts/uninstaller.sh; sourceTree = ""; }; 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = /System/Library/Frameworks/Cocoa.framework; sourceTree = ""; }; 29B97316FDCFA39411CA2CEA /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 29B97325FDCFA39411CA2CEA /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = ""; }; 32CA4F630368D1EE00C91783 /* OCSNG_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OCSNG_Prefix.pch; sourceTree = ""; }; 438B3A5D23E0D10A00631B54 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 438B3A5E23E0D10B00631B54 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = ""; }; 438B3A5F23E0D10F00631B54 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/Localizable.strings; sourceTree = ""; }; 438B3A6023E0D16500631B54 /* lib */ = {isa = PBXFileReference; lastKnownFileType = folder; name = lib; path = ../../../lib; sourceTree = ""; }; 8D1107310486CEB800E47090 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 8D1107320486CEB800E47090 /* OCSNG.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = OCSNG.app; sourceTree = BUILT_PRODUCTS_DIR; }; EE2C4E590DF1CA5800171780 /* GetPID.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = GetPID.c; sourceTree = ""; }; EE2C4E5A0DF1CA5800171780 /* GetPID.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GetPID.h; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ 06D657A5134FD97A00981FE3 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( 06C39B371394ADB20047198A /* CoreData.framework in Frameworks */, 06C39B3A1394ADDF0047198A /* AppKit.framework in Frameworks */, 06C39BCE1394B5600047198A /* Security.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; 8D11072E0486CEB800E47090 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( 8D11072F0486CEB800E47090 /* Cocoa.framework in Frameworks */, 06C39B381394ADB20047198A /* CoreData.framework in Frameworks */, 06C39B3B1394ADDF0047198A /* AppKit.framework in Frameworks */, 06C39BCF1394B5600047198A /* Security.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ 080E96DDFE201D6D7F000001 /* Classes */ = { isa = PBXGroup; children = ( 29B97316FDCFA39411CA2CEA /* main.m */, ); name = Classes; sourceTree = ""; }; 1058C7A0FEA54F0111CA2CBB /* Linked Frameworks */ = { isa = PBXGroup; children = ( 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */, ); name = "Linked Frameworks"; sourceTree = ""; }; 1058C7A2FEA54F0111CA2CBB /* Other Frameworks */ = { isa = PBXGroup; children = ( 06C39BCD1394B5600047198A /* Security.framework */, 06C39B391394ADDF0047198A /* AppKit.framework */, 06C39B361394ADB20047198A /* CoreData.framework */, 29B97325FDCFA39411CA2CEA /* Foundation.framework */, ); name = "Other Frameworks"; sourceTree = ""; }; 19C28FACFE9D520D11CA2CBB /* Products */ = { isa = PBXGroup; children = ( 8D1107320486CEB800E47090 /* OCSNG.app */, 06D657A7134FD97A00981FE3 /* ocscontact */, ); name = Products; sourceTree = ""; }; 29B97314FDCFA39411CA2CEA /* OCSNG */ = { isa = PBXGroup; children = ( 080E96DDFE201D6D7F000001 /* Classes */, 29B97315FDCFA39411CA2CEA /* Other Sources */, 29B97317FDCFA39411CA2CEA /* Resources */, 29B97323FDCFA39411CA2CEA /* Frameworks */, 19C28FACFE9D520D11CA2CBB /* Products */, 06D65785134FD5B800981FE3 /* ocscontact-Info.plist */, ); name = OCSNG; sourceTree = ""; }; 29B97315FDCFA39411CA2CEA /* Other Sources */ = { isa = PBXGroup; children = ( 06D657B2134FDBFF00981FE3 /* ocscontact.h */, 06D657B3134FDBFF00981FE3 /* ocscontact.m */, EE2C4E590DF1CA5800171780 /* GetPID.c */, EE2C4E5A0DF1CA5800171780 /* GetPID.h */, 32CA4F630368D1EE00C91783 /* OCSNG_Prefix.pch */, ); name = "Other Sources"; sourceTree = ""; }; 29B97317FDCFA39411CA2CEA /* Resources */ = { isa = PBXGroup; children = ( 438B3A6023E0D16500631B54 /* lib */, 0B6A943D1F83DB3F00D02E57 /* uninstaller.sh */, 0B6A94121F83D4E600D02E57 /* AUTHORS */, 0B6A94101F83D4E600D02E57 /* Changes */, 0B6A940F1F83D4E600D02E57 /* LICENSE */, 0B6A94111F83D4E600D02E57 /* ocsinventory-agent */, 0B6A940E1F83D4E500D02E57 /* THANKS */, 0625C76E13CAC89000D6EB7C /* ocs_logo.icns */, 8D1107310486CEB800E47090 /* Info.plist */, 089C165CFE840E0CC02AAC07 /* InfoPlist.strings */, 0649FB3314D9E198001EC640 /* Localizable.strings */, ); name = Resources; sourceTree = ""; }; 29B97323FDCFA39411CA2CEA /* Frameworks */ = { isa = PBXGroup; children = ( 1058C7A0FEA54F0111CA2CBB /* Linked Frameworks */, 1058C7A2FEA54F0111CA2CBB /* Other Frameworks */, ); name = Frameworks; sourceTree = ""; }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ 06D657A6134FD97A00981FE3 /* ocscontact */ = { isa = PBXNativeTarget; buildConfigurationList = 06D657A9134FD99800981FE3 /* Build configuration list for PBXNativeTarget "ocscontact" */; buildPhases = ( 06D657A4134FD97A00981FE3 /* Sources */, 06D657A5134FD97A00981FE3 /* Frameworks */, ); buildRules = ( ); dependencies = ( ); name = ocscontact; productName = ocscontact; productReference = 06D657A7134FD97A00981FE3 /* ocscontact */; productType = "com.apple.product-type.tool"; }; 8D1107260486CEB800E47090 /* OCSNG */ = { isa = PBXNativeTarget; buildConfigurationList = C01FCF4A08A954540054247B /* Build configuration list for PBXNativeTarget "OCSNG" */; buildPhases = ( 8D1107290486CEB800E47090 /* Resources */, 8D11072C0486CEB800E47090 /* Sources */, 8D11072E0486CEB800E47090 /* Frameworks */, ); buildRules = ( ); dependencies = ( ); name = OCSNG; productInstallPath = "$(HOME)/Applications"; productName = OCSNG; productReference = 8D1107320486CEB800E47090 /* OCSNG.app */; productType = "com.apple.product-type.application"; }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ 29B97313FDCFA39411CA2CEA /* Project object */ = { isa = PBXProject; attributes = { LastUpgradeCheck = 1130; }; buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "OCSNG" */; compatibilityVersion = "Xcode 3.0"; developmentRegion = en; hasScannedForEncodings = 1; knownRegions = ( Base, en, de, fr, ja, ); mainGroup = 29B97314FDCFA39411CA2CEA /* OCSNG */; projectDirPath = ""; projectRoot = ""; targets = ( 8D1107260486CEB800E47090 /* OCSNG */, 06D657A6134FD97A00981FE3 /* ocscontact */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ 8D1107290486CEB800E47090 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( 0B6A94151F83D4E600D02E57 /* Changes in Resources */, 8D11072B0486CEB800E47090 /* InfoPlist.strings in Resources */, 0625C76F13CAC89000D6EB7C /* ocs_logo.icns in Resources */, 0B6A94161F83D4E600D02E57 /* ocsinventory-agent in Resources */, 0649FB3414D9E198001EC640 /* Localizable.strings in Resources */, 0B6A94171F83D4E600D02E57 /* AUTHORS in Resources */, 438B3A6123E0D16500631B54 /* lib in Resources */, 0B6A943E1F83DB3F00D02E57 /* uninstaller.sh in Resources */, 0B6A94131F83D4E600D02E57 /* THANKS in Resources */, 0B6A94141F83D4E600D02E57 /* LICENSE in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXResourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ 06D657A4134FD97A00981FE3 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 06D657B4134FDBFF00981FE3 /* ocscontact.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; 8D11072C0486CEB800E47090 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 8D11072D0486CEB800E47090 /* main.m in Sources */, EE2C4E5B0DF1CA5800171780 /* GetPID.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin PBXVariantGroup section */ 0649FB3314D9E198001EC640 /* Localizable.strings */ = { isa = PBXVariantGroup; children = ( 438B3A5E23E0D10B00631B54 /* en */, 438B3A5F23E0D10F00631B54 /* fr */, ); name = Localizable.strings; sourceTree = ""; }; 089C165CFE840E0CC02AAC07 /* InfoPlist.strings */ = { isa = PBXVariantGroup; children = ( 438B3A5D23E0D10A00631B54 /* en */, ); name = InfoPlist.strings; sourceTree = ""; }; /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ 06D657AA134FD99800981FE3 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { CLANG_ENABLE_OBJC_WEAK = YES; CODE_SIGN_IDENTITY = "Apple Development"; COPY_PHASE_STRIP = NO; DEVELOPMENT_TEAM = KHDBNPH65U; ENABLE_HARDENED_RUNTIME = YES; GCC_DYNAMIC_NO_PIC = NO; GCC_GENERATE_DEBUGGING_SYMBOLS = YES; GCC_MODEL_TUNING = G5; GCC_OPTIMIZATION_LEVEL = 0; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "$(SYSTEM_LIBRARY_DIR)/Frameworks/AppKit.framework/Headers/AppKit.h"; GCC_VERSION = com.apple.compilers.llvm.clang.1_0; INSTALL_PATH = "$(HOME)/bin"; OBJROOT = build; OTHER_LDFLAGS = ( "-framework", Foundation, "-framework", AppKit, ); PRODUCT_BUNDLE_IDENTIFIER = org.ocsng.agentcontact; PRODUCT_NAME = ocscontact; SYMROOT = build; ZERO_LINK = NO; }; name = Debug; }; 06D657AB134FD99800981FE3 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { CLANG_ENABLE_OBJC_WEAK = YES; CODE_SIGN_IDENTITY = "Apple Development"; COPY_PHASE_STRIP = YES; DEVELOPMENT_TEAM = KHDBNPH65U; ENABLE_HARDENED_RUNTIME = YES; GCC_GENERATE_DEBUGGING_SYMBOLS = NO; GCC_MODEL_TUNING = G5; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "$(SYSTEM_LIBRARY_DIR)/Frameworks/AppKit.framework/Headers/AppKit.h"; GCC_VERSION = com.apple.compilers.llvm.clang.1_0; INSTALL_PATH = /Applications; OBJROOT = build; OTHER_LDFLAGS = ( "-framework", Foundation, "-framework", AppKit, ); PRODUCT_BUNDLE_IDENTIFIER = org.ocsng.agentcontact; PRODUCT_NAME = ocscontact; SDKROOT = macosx; SKIP_INSTALL = YES; SYMROOT = build; ZERO_LINK = NO; }; name = Release; }; C01FCF4B08A954540054247B /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ADDITIONAL_SDKS = ""; CLANG_ENABLE_OBJC_WEAK = YES; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; CURRENT_PROJECT_VERSION = 2.6.0; DEVELOPMENT_TEAM = KHDBNPH65U; ENABLE_HARDENED_RUNTIME = YES; GCC_DYNAMIC_NO_PIC = NO; GCC_MODEL_TUNING = G5; GCC_OPTIMIZATION_LEVEL = 0; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = OCSNG_Prefix.pch; GCC_VERSION = com.apple.compilers.llvm.clang.1_0; INFOPLIST_FILE = Info.plist; INSTALL_PATH = "$(HOME)/Applications"; MACOSX_DEPLOYMENT_TARGET = 10.12; MARKETING_VERSION = 2.6; OBJROOT = build; ONLY_ACTIVE_ARCH = NO; PRODUCT_BUNDLE_IDENTIFIER = org.ocsng.agent; PRODUCT_NAME = OCSNG; PROVISIONING_PROFILE_SPECIFIER = ""; SDKROOT = macosx; SYMROOT = build; VALID_ARCHS = "x86_64 i386"; WRAPPER_EXTENSION = app; ZERO_LINK = ""; }; name = Debug; }; C01FCF4C08A954540054247B /* Release */ = { isa = XCBuildConfiguration; buildSettings = { CLANG_ENABLE_OBJC_WEAK = YES; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 2.6.0; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = KHDBNPH65U; ENABLE_HARDENED_RUNTIME = YES; GCC_MODEL_TUNING = G5; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = OCSNG_Prefix.pch; GCC_VERSION = com.apple.compilers.llvm.clang.1_0; INFOPLIST_FILE = Info.plist; MACOSX_DEPLOYMENT_TARGET = 10.12; MARKETING_VERSION = 2.6; OBJROOT = build; ONLY_ACTIVE_ARCH = YES; PRODUCT_BUNDLE_IDENTIFIER = org.ocsng.agent; PRODUCT_NAME = OCSNG; PROVISIONING_PROFILE_SPECIFIER = ""; SDKROOT = macosx; SYMROOT = build; VALID_ARCHS = "x86_64 i386"; WRAPPER_EXTENSION = app; ZERO_LINK = ""; }; name = Release; }; C01FCF4F08A954540054247B /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; GCC_NO_COMMON_BLOCKS = YES; GCC_VERSION = ""; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; INSTALL_GROUP = $GROUP; INSTALL_MODE_FLAG = ""; INSTALL_OWNER = $USER; MACOSX_DEPLOYMENT_TARGET = 10.11; ONLY_ACTIVE_ARCH = YES; SDKROOT = macosx; VALID_ARCHS = "i386 x86_64"; }; name = Debug; }; C01FCF5008A954540054247B /* Release */ = { isa = XCBuildConfiguration; buildSettings = { CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; DEPLOYMENT_LOCATION = YES; DSTROOT = "/tmp/$(PROJECT_NAME).dst"; ENABLE_STRICT_OBJC_MSGSEND = YES; FRAMEWORK_SEARCH_PATHS = ""; GCC_GENERATE_DEBUGGING_SYMBOLS = YES; GCC_NO_COMMON_BLOCKS = YES; GCC_VERSION = ""; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; HEADER_SEARCH_PATHS = ""; INSTALL_GROUP = $GROUP; INSTALL_MODE_FLAG = ""; INSTALL_OWNER = $USER; INSTALL_PATH = /Applications; LD_MAP_FILE_PATH = "$(TARGET_TEMP_DIR)/$(PRODUCT_NAME)-LinkMap-$(CURRENT_VARIANT)-$(CURRENT_ARCH).txt"; MACOSX_DEPLOYMENT_TARGET = 10.11; "MACOSX_DEPLOYMENT_TARGET[arch=x86_64]" = 10.11; SDKROOT = macosx; }; name = Release; }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ 06D657A9134FD99800981FE3 /* Build configuration list for PBXNativeTarget "ocscontact" */ = { isa = XCConfigurationList; buildConfigurations = ( 06D657AA134FD99800981FE3 /* Debug */, 06D657AB134FD99800981FE3 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; C01FCF4A08A954540054247B /* Build configuration list for PBXNativeTarget "OCSNG" */ = { isa = XCConfigurationList; buildConfigurations = ( C01FCF4B08A954540054247B /* Debug */, C01FCF4C08A954540054247B /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; C01FCF4E08A954540054247B /* Build configuration list for PBXProject "OCSNG" */ = { isa = XCConfigurationList; buildConfigurations = ( C01FCF4F08A954540054247B /* Debug */, C01FCF5008A954540054247B /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; rootObject = 29B97313FDCFA39411CA2CEA /* Project object */; } UnixAgent-2.8/macosx/ocsng_app-xcode/OCSNG_Prefix.pch000066400000000000000000000002151372663377700225350ustar00rootroot00000000000000// // Prefix header for all source files of the 'OCSNG' target in the 'OCSNG' project // #ifdef __OBJC__ #import #endif UnixAgent-2.8/macosx/ocsng_app-xcode/en.lproj/000077500000000000000000000000001372663377700214045ustar00rootroot00000000000000UnixAgent-2.8/macosx/ocsng_app-xcode/en.lproj/InfoPlist.strings000066400000000000000000000003721372663377700247300ustar00rootroot00000000000000/* Localized versions of Info.plist keys */ NSHumanReadableCopyright = "Copyleft Barely3am.com - claimid/saxjazman9, 2008";UnixAgent-2.8/macosx/ocsng_app-xcode/en.lproj/Localizable.strings000066400000000000000000000010621372663377700252370ustar00rootroot00000000000000// // OCSINVENTORY-NG // Copyleft Guillaume PROTET 2011 // Web : http://www.ocsinventory-ng.org // // This code is open source and may be copied and modified as long as the source // code is always made freely available. // Please refer to the General Public Licence http://www.gnu.org/ or Licence.txt // // //Yes button "Yes" = "Yes"; //No button "No" = "No"; //First Window question "Ask_agent_run" = "Do you want to launch OCS Inventory NG agent ?"; //First window comment "Ask_agent_run_comment" = "This will take contact with OCS Inventory NG server";UnixAgent-2.8/macosx/ocsng_app-xcode/fr.lproj/000077500000000000000000000000001372663377700214115ustar00rootroot00000000000000UnixAgent-2.8/macosx/ocsng_app-xcode/fr.lproj/Localizable.strings000066400000000000000000000010641372663377700252460ustar00rootroot00000000000000// // OCSINVENTORY-NG // Copyleft Guillaume PROTET 2011 // Web : http://www.ocsinventory-ng.org // // This code is open source and may be copied and modified as long as the source // code is always made freely available. // Please refer to the General Public Licence http://www.gnu.org/ or Licence.txt // // //Yes button "Yes" = "Oui"; //No button "No" = "Non"; //First Window question "Ask_agent_run" = "Voulez-vous lancer l'agent OCS Inventory NG ?"; //First window comment "Ask_agent_run_comment" = "Ceci prendra contact avec le serveur OCS Inventory NG";UnixAgent-2.8/macosx/ocsng_app-xcode/icons/000077500000000000000000000000001372663377700207705ustar00rootroot00000000000000UnixAgent-2.8/macosx/ocsng_app-xcode/icons/ocs_logo.icns000066400000000000000000000246261372663377700234640ustar00rootroot00000000000000icns)TOC ic08)~ic08)~PNG  IHDR\rfsRGB)0IDATx} x]ywfYeyWٲ-K^11IhI6 ihJBP~~p44 PU˛,aٖe--־/wkdՕts}ys37yϜov0~6O#d,Q&O,] ¿baG5|TQGǶ?}l I||C@$ `aL 69pC90! x^#QDtFQ o7"2|D $Ln 1,d>0$ 0Ev@m?\[.Jq䥹e`΂[[, w?yK%3$ ܌A !NjyF kJ&KYX,\ \BK=3y60-])6rIl@]Gy&0W)~ٿ$ gLn*OxpE!xg^!|뿓gՓcR0GfyY2j<C@T`L .;Lw'dPFY j$p&jo ~WE9 ]nkg.p1Ocϻڀ%F^'vB?mx»>Ed>>d60arJ<x;FA@^ӟ`"_|w1Qy (=$ ʤ|a W$ ̆ SV0vv;CW\]w{20bk;y;LnBR "`TG26KL+< L@\C\ o&^o&Ch F# 3q;t]~2G_@XY5cX*X 4'˹9~F>@X itg/L}G@ZxHh4ku8Z" @z  `u"ld_[ _K% :XKH d #gxw,~B FbT ̑@)n#Q JXhkf(=0 ,]{K *H@vژwC@ ȶh#c??!F[@cO OV 0@ mA0zmc??!F[@cO OǶ? ?~!Mq)vAŤPph ٩J7k&jn^?AX?D3WϢ7gQ$ ֚WC4ȓ݆ |I}k`m+h*C2 GM/qLT_wt;K)F/JVSL>P|/Pש3$.nQTY~G3D7:s Ϫ"d!3!M,L/ri eŽ';;NBٹS"n~)4w[rd~maMjLԒRD|F[6cֻyA\]8\|[6-"q}t"͉K7aTnW@tr4/tn3|()@>[{-wbPz, p^*@Y?A<R\f="a< oSGGPgs2THCnt5TwB3yc-|׻ `ub.o>L_42ki:$AGU)eUʰ@T=:i] J3v.K *ESuiWQ2xko;?iN^IELVI'^:BPIC8M%[NU0Z;@^ h]GaaJ_~t=l%SK4s;(*CyK2읎Z@^:2=?|͊T^*Q@M^U R鳅TwVIhѧҢ[AQK]0a0͚,zPsaq|z~:R¾ .iPı xhdzep}܇;Ind:H}q5s,+z@T#8~ J_>r7;Tr=PsJqYW(o!SS 7"S9x{iUgB6i,R뽫E>@ǰ@a5~b<VҼtd$|HCp1DI60etR= #p%0L!o*uν;gMw@pD #"fk)cBM98jwE1Wn}xAUo H9IeFWw7W?Me~:jh#Ro[d7fݿmwLбvVr~KTw=4d.=͘6R]4'ƌM gxeeJ~s}dK38qE*^(ɪCtD|U(Y}JeBb^flNZ*AGd??_6Qh\g1AL1Q.W6iż;7|?#/l%!8 4gֆT-}Rs-t}}KUD߶N_-5 н(0vzJ ǫ:7S!ks5~z ct :[zITlɤ_ZCt-@d3hC)<>\Tu)ˣW_! Cy]:<$їBZ]`9;mLQQ>q[UA7VHA`'a/Kj:AK]%I^P~ :ߋZzzE}[Bp"-l#W1{Ђwl=?OGyŹP1ޗn*qOëצ/Zx-D~M߿1UOLJw렒gЕ3NDrБ{8H>-H,UwqϦLw8%;W=S: :RAGBch=/-KOFZ AyEx /-UOҠPdWNpБgAGD|1#~G'O/0Ԫifܳ} 39ݚ^TVEϒ[(2M͜wMj"a~KQT|02M/4#E!U)nnpU+6?m*^tJ:@MԳet][ & !  *gAG*f7 AG'_gwQ6JDvֵ  y9 ݀4/(? v؅~T=$GHE@"0UuF2,OKo#dFggg7Q$CO!Ud}x0 dwh-)ӼSĻFVN%Hmewl?OCJ`c?ض R73%aˎ @@=Yc߼ET\5{?v5.5Ul 2>8ײXۂYϛ@%LVv8(Ape):mV%8LM閄R +ɣ|ug?q:Z%;M=gRNB\3KYƬ',Cbb8*_?J*Q;k۩]uEQvDJ +>C 9fK.ܮZiz0DE) YA"ot|&eliC/QcIG`],:'C11:~d>*޹9xǞ(t6@_K/>AG?TdQ0mmEЯ)iOQx,wL AGJOdk@ $9?qrk2dž({HTqd xtR Dω;e<}lEtKU% @LC}G= ] IӈurЖ~rT e9F&FѬj+@z27r Ƒ^ܔ56eg'k?Wk;Zf>ևvqⒺ)Ry=63bt_|(jyt_P)/ SP5Ӝp^>s\BVqscއ%\Yj57'ER-)C)<֜굲exTpܟ@"NlILZLKfRg4@))\I5'OZjT{r5ڧ+/щWh `=ydV_W6~a?^\ͳBvau--tWnr#AWk[žf$Z)bZ2'&+?jx SPwPzn/h@ 68qbelA>[(8K ⵐTEui sh߯]~#,D_<@Uo}uz6'Kdյ{)<9#hցA>L2͏MIR(vNZ|[6ԗ"{ny P=j6ᶮT=;@,SN8Fp,cjv9EYYՔ(QdঅTk*&䥟]A (Tl[A;[uva\poOE(Gv6)e\:[SФ)4Q z-`ϼC/ )= Ak:Ew4Ǥz2(WR$6X5eܐIb[/ut'RF<PCVA)kVUMu/2If`D{Й rrTH^EUybY/XaqLfګw;b[Ux<ֻ}Ca=IHr?=XWbf(7 #y ռ+lf?#EOy"gEmPs\M΃<ZfSF j)(R Q(M^jGZUԦ!]T8EF`E뀀S@NI `m@_8EF`E뀀S@NI `m@_8Eϝ?$ k@> +||SՈd_   J1_   J1_   J1_   J1_   J1_   J1_   J1_   <S݅>W[ 2h\S@XZ(8\QB;52;8R*ԩ{.w}r mx| 'E1l&?g8>̍9S-{ 7l,&XctԶQoߣϯ֝">fLw|A׵ )qYe~x>%,L 7[jZwj? q Li =/" {{3e"=c/RwV@>>:b1EH͈UJ#Khڡ,dCCtǩa X0@m'ib1kǩrc6A˴kzNUO[{1U ?Lvj`jy* x|x-HP{DT Oҕ&!T[N̅p2]CsnGgS *RwK75U\?Kh@v. p]qȞ#tL3(nI͘Gn<2I,ڨejlΆqo4{6^f@a!!.$s!0Wib݄fP74(P X{m."p(VD`^E\ ŀXW& " B1 `E@VU EP X{m."p(VD`^E8(`miFlf6 @٨CJj`jB@O/-Wï6:' G3̨dYW 8hm_:6 ɤlTΑg o;~6G^g G+~ xP'EsG&>,Ѻu:|+"`JW;6vP>ѭJ konUδn';vF#@:qSne#[%O]C|R,~̋@@ 5ߌm50rE; @|~ հRk!$@@wn]< L^Ժ0R9(A< `*ciw$%/Ua A{Xo]KI| |vh!p&vVFI#zmAg(0DGAT)C<a2^  d}N+_vJRj[}-6~ʌ|\cyB y&Pw1N@# `~ƒf  .ǩU\&ȴB0paD@|IfUM\I+cM`<p|j*4H%2`!Yl P۩Uʓ_3mcyiKlFb Nv8;1u)iԼ3{G,[ɺ]|HE_i]w<f~6&cJr/$ G@x\ML6pD 3;YmvJɑ*bgW?ֹn'G32G"0H@`BxݾymeiMx1R YK!"#3!bG U|e<|ݹcIENDB`UnixAgent-2.8/macosx/ocsng_app-xcode/main.m000066400000000000000000000077121372663377700207660ustar00rootroot00000000000000// // OCSINVENTORY-NG // // Copyleft Wes Young (claimid.com/saxjazman9 - Barely3am.com) 2008 // // // This code is open source and may be copied and modified as long as the source // code is always made freely available. // Please refer to the General Public Licence http://www.gnu.org/ // // #import #include #include int main(int argc, char *argv[]) { NSAutoreleasePool *autoreleasepool = [[NSAutoreleasePool alloc] init]; [NSApplication sharedApplication]; int launchOcsAgent = 1; //Getting current user NSString *user = NSUserName() ; if (![user isEqualToString:@"root"]) { //If not launched by Launchd //show icon on Dock if (![[NSUserDefaults standardUserDefaults] boolForKey:@"hideDockIcon"]) { ProcessSerialNumber psn = { 0, kCurrentProcess }; TransformProcessType(&psn, kProcessTransformToForegroundApplication); } NSAlert *askOcsAgentLaunch = [[NSAlert alloc] init]; [askOcsAgentLaunch setMessageText:NSLocalizedString(@"Ask_agent_run", @"First Window question")]; [askOcsAgentLaunch setInformativeText:NSLocalizedString(@"Ask_agent_run_comment", @"First window comment")]; [askOcsAgentLaunch addButtonWithTitle:NSLocalizedString(@"Yes", @"Yes Button")]; [askOcsAgentLaunch addButtonWithTitle:NSLocalizedString(@"No", @"No Button")]; [askOcsAgentLaunch setAlertStyle:NSInformationalAlertStyle]; //Our application become the topmost window [NSApp activateIgnoringOtherApps:YES]; if ([askOcsAgentLaunch runModal] != NSAlertFirstButtonReturn) { // Button 'No' was clicked, we don't launch OCS agent launchOcsAgent = 0; } [askOcsAgentLaunch release]; } if (launchOcsAgent == 1 ) { // Too be on the safe side, I chose the array length to be 10. const int kPIDArrayLength = 10; pid_t myArray[kPIDArrayLength]; unsigned int numberMatches; // simple way of geting our PID, see if we're already running.... int error = GetAllPIDsForProcessName("OCSNG",myArray,kPIDArrayLength,&numberMatches,NULL); if (error == 0) { // Success if (numberMatches > 1) { // There's already a copy of this app running return -1; } } //We launch contact to server using Authorization Services (with asking password) OSStatus myStatus; AuthorizationFlags myFlags = kAuthorizationFlagDefaults; AuthorizationRef myAuthorizationRef; myStatus = AuthorizationCreate(NULL, kAuthorizationEmptyEnvironment,myFlags, &myAuthorizationRef); if (myStatus != errAuthorizationSuccess) return myStatus; do { { AuthorizationItem myItems = {kAuthorizationRightExecute, 0, NULL, 0}; AuthorizationRights myRights = {1, &myItems}; myFlags = kAuthorizationFlagDefaults | kAuthorizationFlagInteractionAllowed | kAuthorizationFlagPreAuthorize | kAuthorizationFlagExtendRights; myStatus = AuthorizationCopyRights (myAuthorizationRef,&myRights, NULL, myFlags, NULL ); } if (myStatus != errAuthorizationSuccess) break; { //We use an helper tool instead of running OCS agent directly NSString *ocscontactPath = [[NSBundle mainBundle] pathForResource:@"ocscontact"ofType:nil]; char *myArguments[] = { "", NULL }; FILE *myCommunicationsPipe = NULL; char myReadBuffer[128]; myFlags = kAuthorizationFlagDefaults; myStatus = AuthorizationExecuteWithPrivileges (myAuthorizationRef, [ocscontactPath UTF8String], kAuthorizationFlagDefaults, myArguments, &myCommunicationsPipe); if (myStatus == errAuthorizationSuccess) for(;;) { int bytesRead = read (fileno (myCommunicationsPipe),myReadBuffer, sizeof (myReadBuffer)); if (bytesRead < 1) break; write (fileno (stdout), myReadBuffer, bytesRead); } } } while (0); AuthorizationFree (myAuthorizationRef, kAuthorizationFlagDefaults); return myStatus; } [autoreleasepool release]; return NSApplicationMain(argc, (const char **) argv); } UnixAgent-2.8/macosx/ocsng_app-xcode/ocscontact-Info.plist000066400000000000000000000013401372663377700237610ustar00rootroot00000000000000 CFBundleDevelopmentRegion English CFBundleExecutable ${EXECUTABLE_NAME} CFBundleIdentifier org.ocsinventory-ng.ocscontact CFBundleInfoDictionaryVersion 6.0 CFBundlePackageType APPL CFBundleSignature ???? CFBundleVersion 2.6 NSMainNibFile MainMenu NSPrincipalClass NSApplication UnixAgent-2.8/macosx/ocsng_app-xcode/ocscontact.h000066400000000000000000000005741372663377700221740ustar00rootroot00000000000000// // OCSINVENTORY-NG // Copyleft Guillaume PROTET 2011 // Web : http://www.ocsinventory-ng.org // // This code is open source and may be copied and modified as long as the source // code is always made freely available. // Please refer to the General Public Licence http://www.gnu.org/ or Licence.txt // // #import @interface ocscontact : NSObject { } @end UnixAgent-2.8/macosx/ocsng_app-xcode/ocscontact.m000066400000000000000000000020131372663377700221670ustar00rootroot00000000000000// // OCSINVENTORY-NG // Copyleft Guillaume PROTET 2011 // Web : http://www.ocsinventory-ng.org // // This code is open source and may be copied and modified as long as the source // code is always made freely available. // Please refer to the General Public Licence http://www.gnu.org/ or Licence.txt // // //ocscontact is the helper tool to run OCS agent using Authorization Services. //ocscontact executable MUST be owned by root and have 700 permissions #import "ocscontact.h" @implementation ocscontact int main( int argc, char *argv[], char *envp[]) { NSAutoreleasePool *autoreleasepool = [[NSAutoreleasePool alloc] init]; NSLog(@"Running ocscontact"); setuid(0); //To be able to run OCS agent as root NSTask *Task = [[NSTask alloc] init]; //We get the path of ocsinventory-agent executable NSString *ocsinventoryAgentPath = [[NSBundle mainBundle] pathForResource:@"ocsinventory-agent"ofType:nil]; [Task setLaunchPath:ocsinventoryAgentPath]; [Task launch]; [autoreleasepool release]; return 0; } @end UnixAgent-2.8/macosx/patches/000077500000000000000000000000001372663377700162335ustar00rootroot00000000000000UnixAgent-2.8/macosx/patches/lib-ocsinventory-agent-backend-darwn.patch000066400000000000000000000011471372663377700263570ustar00rootroot00000000000000--- a/lib/Ocsinventory/Agent/Backend.pm +++ b/lib/Ocsinventory/Agent/Backend.pm @@ -85,8 +87,11 @@ sub initModList { } if ($config->{devlib}) { - # devlib enable, I only search for backend module in ./lib - push (@dirToScan, './lib'); + eval "use Cwd qw(abs_path);"; + eval "use File::Basename;"; + my $path = dirname( abs_path($0) ); + $logger->debug("devlib mode: Only looking in $path for backend modules."); + push (@dirToScan, $path . "/lib"); } else { # my ($inst) = ExtUtils::Installed->new(); # eval {@installed_files = UnixAgent-2.8/macosx/patches/ocsinventory-agent-darwin.patch000066400000000000000000000006341372663377700243770ustar00rootroot00000000000000--- ../unified_unix_agent/ocsinventory-agent 2011-05-08 19:23:10.000000000 +0200 +++ ocsinventory-agent 2011-07-29 00:15:15.000000000 +0200 @@ -18,6 +18,18 @@ #USA. # +BEGIN { + use File::Basename; + use Cwd qw(abs_path); + + my $scriptname = basename(__FILE__); + my $path = abs_path($0); + $path =~ s/$scriptname//g; + + unshift(@INC,$path."/lib/"); +} + + use strict; use warnings; UnixAgent-2.8/macosx/scripts/000077500000000000000000000000001372663377700162735ustar00rootroot00000000000000UnixAgent-2.8/macosx/scripts/create-darwin-perl-lib_fromCPAN.pl000066400000000000000000000127471372663377700245610ustar00rootroot00000000000000#!/usr/bin/perl -w # # COPYRIGHT: # # This software is Copyright (c) 2008 claimid.com/saxjazman9 # # (Except where explicitly superseded by other copyright notices) # # Special thanks to Jesse over a best practical for the framework # from which this script is has been created # # LICENSE: # # This work is made available to you under the terms of Version 2 of # the GNU General Public License. A copy of that license should have # been provided with this software, but in any event can be snarfed # from www.gnu.org. # # This work is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA # 02110-1301 or visit their web page on the internet at # http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. # # # This is just a basic script that checks to make sure that all # the modules needed by OCS MacOSX agent before you can compile it. # # You have to install LWP in your system to use this script # # WARNING: Before executing this script please modify your ~/.cpan/CPAN/MyConfig.pm file as follows: # $> perl -MCPAN -e shell # cpan> o conf makepl_arg 'LIB=~/darwin-perl-lib PREFIX=--perl-only' # cpan> o conf commit # cpan> quit # # This will set the CPAN shell up to install the modules in this script to ~/darwin-perl-lib # it will also cause the man pages and other misc perl stuff to not be installed... we only need the modules anyway # # After this script is done, you will take the ~/darwin-perl-lib and move it to the source code directory for # compiling your application # # Once the script has completed and you are confident you have everything, you can reverse the changes to your # MyConfig.pm by: # # # $> perl -MCPAN -e shell # cpan> o conf makepl_arg '' # cpan> o conf commit # cpan> quit # # # THIS IS A BETA SCRIPT! USE AT YOUR OWN RISK # use strict; use warnings; use Getopt::Long; use CPAN; use LWP::Simple qw/getstore/; my %args; my %deps; GetOptions( \%args, 'install', ); unless (keys %args) { help(); exit(0); } # Set up defaults my %default = ( 'CORE' => 1, ); $args{$_} = $default{$_} foreach grep !exists $args{$_}, keys %default; # # Place any core modules (+ versions) that are required in the form: MOD::MOD 0.01 # $deps{'CORE'} = [ text_to_hash( << ".") ]; XML::SAX XML::Parser XML::Simple URI XML::NamespaceSupport File::Listing Net::IP Compress::Zlib Compress::Raw::Zlib IO::Zlib Mac::SysProfile Mac::PropertyList Parse::EDID LWP LWP::UserAgent LWP::Protocol::https XML::Entities Mac::SysProfile . # push all the dep's into a @missing array my @missing; my @deps = @{ $deps{'CORE'} }; while (@deps) { my $module = shift @deps; my $version = shift @deps; push @missing, $module, $version; } # assuming we've passed the --install, proceed with the compiling and install to our if ( $args{'install'} ) { while( @missing ) { resolve_dep(shift @missing, shift @missing); } } # convert the dep text list to a hash sub text_to_hash { my %hash; for my $line ( split /\n/, $_[0] ) { my($key, $value) = $line =~ /(\S+)\s*(\S*)/; $value ||= ''; $hash{$key} = $value; } return %hash; } # pull in our local .cpan/CPAN/MyConfig.pm file # use the cpan shell to force install the module to our local dir # force install is used because although we may have the package already up-to-date on our system, # we want a clean fresh copy installed to our darwin-perl-lib dir. sub resolve_dep { my $module = shift; my $version = shift; local @INC = @INC; my $user = `whoami`; chomp $user; unshift @INC, "/Users/$user/Library/Application Support/.cpan"; if ( $ENV{'HOME'} ) { unshift @INC, "$ENV{'HOME'}/.cpan"; } unshift @INC, "/Users/$user/~darwin-perl-lib"; print "\nInstall module $module\n"; my $cfg = (eval { require CPAN::MyConfig }); unless($cfg){ die('CPAN Not configured properly'); } CPAN::Shell->force('install',$module); } # the help.... sub help { print <<'.'; By default, testdeps determine whether you have installed all the perl modules OCSNG.app needs to run. --install Install missing modules . } sub install_tarball { my $cpan_url = shift; my $tarball_url = shift; my $directory = shift; my $mod_dir; my $tarball = $tarball_url; $tarball =~ s/(.*)\/(.*)\/(.*)\///; if ($directory) { $mod_dir = $directory; } else { $mod_dir = $tarball ; $mod_dir =~ s/\.tar\.gz//; } print "Getting $cpan_url/$tarball_url file\n"; my $resp = getstore("$cpan_url/$tarball_url", $tarball); die "Couldn't get $cpan_url/$tarball_url -> HTTP response: $resp." unless $resp == 200; print "Extracting $tarball file\n"; open(EXCLUDE,">exclude_hiddens"); print EXCLUDE ".*"; close EXCLUDE; system("tar -xvzf $tarball -X exclude_hiddens"); #We exclude hiddens files from extract (mainly for older Mac::Sysprofile package) unlink "exclude_hiddens"; print "Installing $mod_dir module\n"; chdir($mod_dir); system("env ARCHFLAGS='-arch i386 -arch ppc -arch x86_64' perl Makefile.PL LIB='~/darwin-perl-lib' PREFIX='--perl-only'"); #Multi architectures support system("make && make install"); chdir('..'); system("rm -Rf $mod_dir"); } 1; UnixAgent-2.8/macosx/scripts/uninstaller.sh000077500000000000000000000012711372663377700211730ustar00rootroot00000000000000#!/bin/bash OSVER=`uname -r` echo "OSVer is $OSVER" PID=`ps ax -e | grep OCSNG | grep -v grep | grep -v $0 | awk '{print $1}'` if [ "$PID" != "" ]; then echo "killing process: $PID" sudo kill $PID fi FILES="/Library/Receipts/OCSNG* /etc/ocsinventory-agent/ /var/lib/ocsinventory-agent/ /Applications/OCSNG.app /var/log/ocsng.log" if [ "$OSVER" == "7.9.0" ]; then FILES="$FILES /Library/StartupItems/OCSInventory" else FILES="$FILES /Library/LaunchDaemons/org.ocsng.agent.plist" echo 'Stopping and unloading service' launchctl stop org.ocsng.agent launchctl unload /Library/LaunchDaemons/org.ocsng.agent.plist fi for FILE in $FILES; do echo 'removing '.$FILE rm -f -R $FILE done UnixAgent-2.8/macosx/setup_plugins/000077500000000000000000000000001372663377700175055ustar00rootroot00000000000000UnixAgent-2.8/macosx/setup_plugins/.gitkeep000066400000000000000000000000001372663377700211240ustar00rootroot00000000000000UnixAgent-2.8/macosx/setup_plugins/config_plugin_installer/000077500000000000000000000000001372663377700244055ustar00rootroot00000000000000UnixAgent-2.8/macosx/setup_plugins/config_plugin_installer/config.xcodeproj/000077500000000000000000000000001372663377700276465ustar00rootroot00000000000000UnixAgent-2.8/macosx/setup_plugins/config_plugin_installer/config.xcodeproj/project.pbxproj000066400000000000000000000305531372663377700327300ustar00rootroot00000000000000// !$*UTF8*$! { archiveVersion = 1; classes = { }; objectVersion = 50; objects = { /* Begin PBXBuildFile section */ 43E4B07623E70E4F00E03641 /* ConfigInstallerPane.m in Sources */ = {isa = PBXBuildFile; fileRef = 43E4B07523E70E4F00E03641 /* ConfigInstallerPane.m */; }; 43E4B07923E70E4F00E03641 /* ConfigInstallerPane.xib in Resources */ = {isa = PBXBuildFile; fileRef = 43E4B07723E70E4F00E03641 /* ConfigInstallerPane.xib */; }; 43E4B07C23E70E4F00E03641 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 43E4B07A23E70E4F00E03641 /* Localizable.strings */; }; 43E4B07E23E70E4F00E03641 /* InstallerSections.plist in Resources */ = {isa = PBXBuildFile; fileRef = 43E4B07D23E70E4F00E03641 /* InstallerSections.plist */; }; 43E4B08223E70E4F00E03641 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 43E4B08023E70E4F00E03641 /* InfoPlist.strings */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ 43E4B07123E70E4F00E03641 /* config.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = config.bundle; sourceTree = BUILT_PRODUCTS_DIR; }; 43E4B07423E70E4F00E03641 /* ConfigInstallerPane.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ConfigInstallerPane.h; sourceTree = ""; }; 43E4B07523E70E4F00E03641 /* ConfigInstallerPane.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ConfigInstallerPane.m; sourceTree = ""; }; 43E4B07823E70E4F00E03641 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/ConfigInstallerPane.xib; sourceTree = ""; }; 43E4B07B23E70E4F00E03641 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = ""; }; 43E4B07D23E70E4F00E03641 /* InstallerSections.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = InstallerSections.plist; sourceTree = ""; }; 43E4B07F23E70E4F00E03641 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 43E4B08123E70E4F00E03641 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 43E4B08D23E7187F00E03641 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/ConfigInstallerPane.strings; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ 43E4B06E23E70E4E00E03641 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ 43E4B06823E70E4E00E03641 = { isa = PBXGroup; children = ( 43E4B07323E70E4F00E03641 /* config */, 43E4B07223E70E4F00E03641 /* Products */, ); sourceTree = ""; }; 43E4B07223E70E4F00E03641 /* Products */ = { isa = PBXGroup; children = ( 43E4B07123E70E4F00E03641 /* config.bundle */, ); name = Products; sourceTree = ""; }; 43E4B07323E70E4F00E03641 /* config */ = { isa = PBXGroup; children = ( 43E4B07423E70E4F00E03641 /* ConfigInstallerPane.h */, 43E4B07523E70E4F00E03641 /* ConfigInstallerPane.m */, 43E4B07723E70E4F00E03641 /* ConfigInstallerPane.xib */, 43E4B07A23E70E4F00E03641 /* Localizable.strings */, 43E4B07D23E70E4F00E03641 /* InstallerSections.plist */, 43E4B07F23E70E4F00E03641 /* Info.plist */, 43E4B08023E70E4F00E03641 /* InfoPlist.strings */, ); path = config; sourceTree = ""; }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ 43E4B07023E70E4E00E03641 /* config */ = { isa = PBXNativeTarget; buildConfigurationList = 43E4B08523E70E4F00E03641 /* Build configuration list for PBXNativeTarget "config" */; buildPhases = ( 43E4B06D23E70E4E00E03641 /* Sources */, 43E4B06E23E70E4E00E03641 /* Frameworks */, 43E4B06F23E70E4E00E03641 /* Resources */, ); buildRules = ( ); dependencies = ( ); name = config; productName = config; productReference = 43E4B07123E70E4F00E03641 /* config.bundle */; productType = "com.apple.product-type.bundle"; }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ 43E4B06923E70E4E00E03641 /* Project object */ = { isa = PBXProject; attributes = { LastUpgradeCheck = 1130; ORGANIZATIONNAME = "Gilles Dubois"; TargetAttributes = { 43E4B07023E70E4E00E03641 = { CreatedOnToolsVersion = 11.3.1; }; }; }; buildConfigurationList = 43E4B06C23E70E4E00E03641 /* Build configuration list for PBXProject "config" */; compatibilityVersion = "Xcode 9.3"; developmentRegion = en; hasScannedForEncodings = 0; knownRegions = ( en, Base, ); mainGroup = 43E4B06823E70E4E00E03641; productRefGroup = 43E4B07223E70E4F00E03641 /* Products */; projectDirPath = ""; projectRoot = ""; targets = ( 43E4B07023E70E4E00E03641 /* config */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ 43E4B06F23E70E4E00E03641 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( 43E4B07923E70E4F00E03641 /* ConfigInstallerPane.xib in Resources */, 43E4B08223E70E4F00E03641 /* InfoPlist.strings in Resources */, 43E4B07C23E70E4F00E03641 /* Localizable.strings in Resources */, 43E4B07E23E70E4F00E03641 /* InstallerSections.plist in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXResourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ 43E4B06D23E70E4E00E03641 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 43E4B07623E70E4F00E03641 /* ConfigInstallerPane.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin PBXVariantGroup section */ 43E4B07723E70E4F00E03641 /* ConfigInstallerPane.xib */ = { isa = PBXVariantGroup; children = ( 43E4B07823E70E4F00E03641 /* Base */, 43E4B08D23E7187F00E03641 /* en */, ); name = ConfigInstallerPane.xib; sourceTree = ""; }; 43E4B07A23E70E4F00E03641 /* Localizable.strings */ = { isa = PBXVariantGroup; children = ( 43E4B07B23E70E4F00E03641 /* en */, ); name = Localizable.strings; sourceTree = ""; }; 43E4B08023E70E4F00E03641 /* InfoPlist.strings */ = { isa = PBXVariantGroup; children = ( 43E4B08123E70E4F00E03641 /* en */, ); name = InfoPlist.strings; sourceTree = ""; }; /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ 43E4B08323E70E4F00E03641 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_ENABLE_OBJC_WEAK = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; MACOSX_DEPLOYMENT_TARGET = 10.15; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = macosx; }; name = Debug; }; 43E4B08423E70E4F00E03641 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_ENABLE_OBJC_WEAK = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; MACOSX_DEPLOYMENT_TARGET = 10.15; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; SDKROOT = macosx; }; name = Release; }; 43E4B08623E70E4F00E03641 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; DEVELOPMENT_TEAM = KHDBNPH65U; INFOPLIST_FILE = config/Info.plist; INSTALL_PATH = "$(HOME)/Library/Bundles"; PRODUCT_BUNDLE_IDENTIFIER = org.ocsinventory.agent.config; PRODUCT_NAME = "$(TARGET_NAME)"; WRAPPER_EXTENSION = bundle; }; name = Debug; }; 43E4B08723E70E4F00E03641 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; DEVELOPMENT_TEAM = KHDBNPH65U; INFOPLIST_FILE = config/Info.plist; INSTALL_PATH = "$(HOME)/Library/Bundles"; PRODUCT_BUNDLE_IDENTIFIER = org.ocsinventory.agent.config; PRODUCT_NAME = "$(TARGET_NAME)"; WRAPPER_EXTENSION = bundle; }; name = Release; }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ 43E4B06C23E70E4E00E03641 /* Build configuration list for PBXProject "config" */ = { isa = XCConfigurationList; buildConfigurations = ( 43E4B08323E70E4F00E03641 /* Debug */, 43E4B08423E70E4F00E03641 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 43E4B08523E70E4F00E03641 /* Build configuration list for PBXNativeTarget "config" */ = { isa = XCConfigurationList; buildConfigurations = ( 43E4B08623E70E4F00E03641 /* Debug */, 43E4B08723E70E4F00E03641 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; rootObject = 43E4B06923E70E4E00E03641 /* Project object */; } UnixAgent-2.8/macosx/setup_plugins/config_plugin_installer/config/000077500000000000000000000000001372663377700256525ustar00rootroot00000000000000UnixAgent-2.8/macosx/setup_plugins/config_plugin_installer/config/Base.lproj/000077500000000000000000000000001372663377700276515ustar00rootroot00000000000000UnixAgent-2.8/macosx/setup_plugins/config_plugin_installer/config/Base.lproj/ConfigInstallerPane.xib000066400000000000000000000463001372663377700342470ustar00rootroot00000000000000

); close(FILE); } elsif (-f '/etc/model') { # DLink NAS model open(FILE, "); close(FILE); } } # Use dmidecode for Linux x86, not for Linux SPARC &check_dmidecode if ($config_cmd =~ /dmidecode/ && -x "$config_cmd" && ($machine =~ /.86/ || ! -x '/usr/sbin/prtconf')); if ($machine =~ /.86/ || ! -e '/dev/openprom') { &show_header; &show_supported; } } elsif ($os ne "SunOS") { &show_header; &show_supported; } if (-f '/vmunix') { # SunOS 4.X (Solaris 1.X) $BSD=1; if (! -x '/usr/etc/devinfo') { print "ERROR: no 'devinfo' command. Aborting.\n"; &pdebug("exit 1"); exit 1; } $config_cmd="/usr/etc/devinfo -pv"; $config_command="devinfo"; } else { # Solaris 2.X or later $BSD=0; if (! -x '/usr/sbin/prtconf') { print "ERROR: no 'prtconf' command. Aborting.\n"; &pdebug("exit 1"); exit 1; } $config_cmd="/usr/sbin/prtconf -vp"; $config_command="prtconf"; } } else { # Special case for regression testing SunOS4 and SunOS5 files if ($filename =~ /\bdevinfo\./) { $os="SunOS"; $BSD=1; } elsif ($filename =~ /\bprtconf\./) { $os="SunOS"; $BSD=0; } # Special case for regression testing Linux files $os="Linux" if ($filename =~ /Linux/); # Special case for regression testing HP-UX files if ($filename =~ /\bcprop[\.+]/) { &hpux_check; &hpux_cprop; } elsif ($filename =~ /\b(cstm|machinfo)[\.+]/) { &hpux_check; &hpux_cstm; } } $kernbit=""; $hasprtconfV=0; $solaris=""; $solaris="1.0" if ($osrel eq "4.1.1"); $solaris="1.0.1" if ($osrel eq "4.1.2"); $solaris="1.1" if ($osrel =~ /4.1.3/); $solaris="1.1.1" if ($osrel eq "4.1.3_U1"); $solaris="1.1.2" if ($osrel eq "4.1.4"); if ($osrel =~ /^5./) { $osminor=$osrel; $osminor=~s/^5.//; if ($SUNWexplo) { if (-f "$filename/etc/release") { open(FILE, "<$filename/etc/release"); $release=; close(FILE); } } else { if (-f '/etc/release') { open(FILE, "; close(FILE); } } if ($release =~ "Solaris") { $release=~s/\s+//; $release=&mychomp($release); $solaris="$release"; } if ($release =~ "OmniOS") { $release=~s/\s+//; $release=&mychomp($release); $solaris="$release"; } if ($osminor =~ /^[7-9]$|^1[0-9]$/) { $hasprtconfV=1; $solaris=$osminor if (! $solaris); $kernbit=32; if ($SUNWexplo) { $cpuarch=""; if (-f "$filename/sysconfig/isainfo.out") { open(FILE, "<$filename/sysconfig/isainfo.out"); $cpuarch=; close(FILE); } elsif (-f "$filename/sysconfig/isainfo-kv.out") { open(FILE, "<$filename/sysconfig/isainfo-kv.out"); $cpuarch=; close(FILE); } $kernbit=64 if ($cpuarch =~ /sparcv9|ia64|amd64/); } elsif (-x '/bin/isainfo') { $kernbit=&mychomp(`/bin/isainfo -b`); } } elsif ($osminor =~ /^[4-6]$/) { $hasprtconfV=1; $solaris="2.$osminor" if (! $solaris); } else { $solaris="2.$osminor"; } # x86 Solaris 2.1 through 2.5.1 has different syntax than SPARC $config_cmd="/usr/sbin/prtconf -v" if ($machine eq "i86pc" && $osminor =~ /^[1-5]$/); # Solaris x86 returns booting system rather than PROM version $hasprtconfV=0 if ($machine eq "i86pc"); } if (! $filename) { @config=&run("$config_cmd"); if ($hasprtconfV) { # SPARC Solaris 2.4 or later $romver=&mychomp(`/usr/sbin/prtconf -V 2>&1`); if ($romver eq "Cannot open openprom device") { $prtconf_warn="ERROR: $romver"; $romver=""; } else { @romverarr=split(/\s/, $romver); $romvernum=$romverarr[1]; } } else { # SPARC Solaris 2.3 or older, or Solaris x86 # Try to use sysinfo if installed to determine the OBP version. # sysinfo is available from http://www.MagniComp.com/sysinfo/ close(STDERR) if ($verbose != 3); $romver=`sysinfo -show romver 2>/dev/null | tail -1`; open(STDERR) if ($verbose != 3); if ($romver) { $romver=&mychomp($romver); @romverarr=split(/\s/, $romver); $romver=$romverarr[$#romverarr]; } else { # Assume it is old $romver="2.X" if ($machine =~ /sun4/); } $romvernum=$romver; } } if ($filename && $have_prtpicl_data && ! $SUNWexplo) { foreach $line (@prtpicl) { $line=&dos2unix($line); $line=&mychomp($line); $line=~s/\s+$//; # Parse osrel and hostname from prtpicl data if ($line =~ /\s+:OS-Release\s/) { $osrel=$line; $osrel=~s/^.*:OS-Release\s+(.*)$/$1/; if ($osrel =~ /^5./) { $osminor=$osrel; $osminor=~s/^5.//; if ($osminor =~ /^[7-9]$|^1[0-9]$/) { $solaris=$osminor; # Solaris 10 SPARC and later is 64-bit $kernbit=64 if ($osminor =~ /^1[0-9]$/ && $machine =~ /sun4/); } else { # Solaris 2.6 and earlier is 32-bit $solaris="2.$osminor"; $kernbit=32; } if ($machine =~ /86/) { $solaris .= " X86" if ($solaris !~ / X86/); # Solaris 9 X86 and earlier is 32-bit $kernbit=32 if ($osminor =~ /^[7-9]$/); } elsif ($machine =~ /sun4/) { $solaris .= " SPARC" if ($solaris !~ / SPARC/); $kernbit=32 if ($machine =~ /sun4[cdm\b]/); } } } if ($line =~ /\s+:HostName\s/) { $hostname=$line; $hostname=~s/^.*:HostName\s+(.*)$/$1/; } } } sub please_wait { return if ($waitshown); $waitshown=1; print "Gathering data for memconf. This may take over a minute. Please wait...\n" if (-t STDOUT); } sub find_helpers { return if ($helpers_defined); $helpers_defined=1; if ($os eq "HP-UX") { $config_cmd="echo 'selclass qualifier cpu;info;wait;selclass qualifier memory;info;wait;infolog'|/usr/sbin/cstm"; } elsif ($os =~ /Linux|FreeBSD/) { if (defined($ENV{DMIDECODE}) && -x $ENV{DMIDECODE}) { # this may be a setuid-root version of dmidecode $config_cmd=$ENV{DMIDECODE}; } else { foreach $bin ('/usr/local/sbin','/usr/local/bin','/usr/sbin','/usr/bin','/bin') { if (-x "$bin/dmidecode") { $config_cmd="$bin/dmidecode"; last; } } } } elsif (-x '/usr/sbin/prtconf') { # Solaris 2.X or later $config_cmd="/usr/sbin/prtconf -vp"; $prtfru_cmd='/usr/sbin/prtfru' if (-x '/usr/sbin/prtfru'); $prtpicl_cmd='/usr/sbin/prtpicl' if (-x '/usr/sbin/prtpicl'); $psrinfo_cmd='/usr/sbin/psrinfo' if (-x '/usr/sbin/psrinfo'); $virtinfo_cmd='/usr/sbin/virtinfo' if (-x '/usr/sbin/virtinfo'); $cfgadm_cmd='/usr/sbin/cfgadm' if (-x '/usr/sbin/cfgadm'); $smbios_cmd='/usr/sbin/smbios' if (-x '/usr/sbin/smbios'); $kstat_cmd='/usr/bin/kstat -m cpu_info' if (-x '/usr/bin/kstat'); $ldm_cmd='/opt/SUNWldm/bin/ldm' if (-x '/opt/SUNWldm/bin/ldm'); } if ($os =~ /Linux|FreeBSD/) { $free_cmd='/usr/bin/free -m' if (-x '/usr/bin/free'); $meminfo_cmd='cat /proc/meminfo' if (-r '/proc/meminfo' || $running_on !~ /Linux|FreeBSD/); $topology_cmd='/usr/bin/topology --summary --nodes --cpus --io --routers' if (-x '/usr/bin/topology' || $running_on !~ /Linux|FreeBSD/); if (&is_xen_hv) { $xm_info_cmd='/usr/sbin/xm info'; $xm_info_cmd='/usr/bin/xm info' if (-x '/usr/bin/xm'); } if (-x '/usr/bin/decode-dimms.pl' || $running_on !~ /Linux|FreeBSD/) { $modprobe_eeprom_cmd='/sbin/modprobe eeprom'; $decodedimms_cmd='/usr/bin/decode-dimms.pl'; } } if ($os =~ /SunOS|Linux|FreeBSD/) { if (defined($ENV{IPMITOOL}) && -x $ENV{IPMITOOL}) { # this may be a setuid-root version of ipmitool $ipmitool_cmd=$ENV{IPMITOOL}; } else { foreach $bin ('/usr/sfw/bin','/usr/local/sbin','/usr/local/bin','/usr/sbin','/usr/bin','/bin') { if (-x "$bin/ipmitool") { $ipmitool_cmd="$bin/ipmitool"; last; } } } } } sub show_helpers { $s=shift; # Prefer prtconf for Linux SPARC if ($machine =~ /sun|sparc/i || $filename =~ /LinuxSPARC/) { print "$s/usr/sbin/prtconf -vp\n"; print "$s$config_cmd\n" if ($config_cmd =~ /dmidecode/ && -x "$config_cmd"); } else { print "$s$config_cmd\n" if ($config_cmd); } if ($os eq "SunOS") { print "$s$prtdiag_cmd -v\n" if ($prtdiag_exec); print "$s$prtfru_cmd -x\n" if ($prtfru_cmd); print "$s$prtpicl_cmd -v\n" if ($prtpicl_cmd); if ($psrinfo_cmd) { print "$s$psrinfo_cmd -v\n"; $tmp=&mychomp(`$psrinfo_cmd -p 2>/dev/null`); if ($tmp ne "") { print "$s$psrinfo_cmd -p\n"; print "$s$psrinfo_cmd -p -v\n"; } } print "$s$virtinfo_cmd -pa\n" if ($virtinfo_cmd); print "$s$cfgadm_cmd -al\n" if ($cfgadm_cmd); print "$s$smbios_cmd\n" if ($smbios_cmd); print "$s$kstat_cmd\n" if ($kstat_cmd); print "$s$ldm_cmd list-devices -a -p\n" if ($ldm_cmd); } if ($os =~ /Linux|FreeBSD/) { print "${s}cat /proc/cpuinfo\n" if (-r '/proc/cpuinfo' || $running_on !~ /Linux|FreeBSD/); print "${s}cat /proc/meminfo\n" if (-r '/proc/meminfo' || $running_on !~ /Linux|FreeBSD/); print "$s$free_cmd\n" if ($free_cmd); print "${s}/usr/bin/topology\n" if (-x '/usr/bin/topology' || $running_on !~ /Linux|FreeBSD/); print "$s$xm_info_cmd\n" if ($xm_info_cmd); print "${s}/usr/bin/xenstore-ls /local/domain/DOMID\n" if (-x '/usr/bin/xenstore-ls' || $running_on !~ /Linux|FreeBSD/); print "$s$modprobe_eeprom_cmd; $decodedimms_cmd\n" if ($decodedimms_cmd); } if ($os =~ /SunOS|Linux|FreeBSD/) { print "$s$ipmitool_cmd fru\n" if ($ipmitool_cmd && $running_on eq $os); } if ($os eq "HP-UX") { print "$s/usr/contrib/bin/machinfo\n" if (-x '/usr/contrib/bin/machinfo'); } } sub show_help { &find_helpers; if ($os =~ /Linux|FreeBSD/ && $config_cmd =~ /prtconf/) { if ($machine =~ /.86|ia64|amd64|sparc/) { $config_cmd="dmidecode"; } else { $config_cmd=""; } } print "Usage: memconf [ -v | -D | -h ] [explorer_dir]\n"; print " -v verbose mode\n"; print " -D E-mail results to memconf maintainer\n"; print " -h print help\n"; print " explorer_dir Sun/Oracle Explorer output directory\n"; print "\nThis is memconf, $version $version_date\n\nCheck my website "; print "at $URL to get the latest\nversion of memconf.\n\n"; &show_supported if ($os !~ /SunOS|HP-UX|Linux|FreeBSD/); print "Please send bug reports and enhancement requests along with "; print "the output of the\nfollowing commands to tschmidt\@micron.com "; print "as E-mail attachments so that memconf\nmay be enhanced. "; print "You can do this using the 'memconf -D' command if this system\n"; print "can E-mail to the Internet.\n"; &show_helpers(" "); &pdebug("exit"); exit; } sub check_hyperthread { &pdebug("in check_hyperthread: corecnt=$corecnt"); if ($cputype =~ /Intel.*\sXeon.*\s(E5540|E5620|L5520|X5560|X5570)\b/ && (($corecnt == 8 && ! &is_xen_hv) || &is_xen_hv)) { &pdebug("hyperthread=1: hack in cpubanner, cputype=$cputype") if (! $hyperthread); $hyperthread=1; $corecnt=4; $cputype=~s/Eight.Core //ig; $cputype=&multicore_cputype($cputype,$corecnt); } if ($cputype =~ /Intel.*\sXeon.*\s(L5640|X5670|X5675)\b/ && (($corecnt == 12 && ! &is_xen_hv) || &is_xen_hv)) { &pdebug("hyperthread=1: hack in cpubanner, cputype=$cputype") if (! $hyperthread); $hyperthread=1; $corecnt=6; $cputype=~s/Twelve.Core //ig; $cputype=&multicore_cputype($cputype,$corecnt); } } sub show_hyperthreadcapable { if ($hyperthreadcapable && ! $hyperthread) { print "NOTICE: CPU"; if ($npcpu > 1) { print "s are"; } else { print " is"; } print " capable of Hyper-Threading, but it is not enabled in the BIOS.\n"; } } sub cpubanner { # Hard-code some CPU models for hyper-threading on regression tests. # Hyper-Thread detection in Solaris x86 is done earlier by check_kstat # This hard-code method assumes Hyper-Threading is enabled if the # core count matches. This is not used when kstat data is available. if ($kstat_cpubanner && $modelmore !~ /MHz\)/) { &pdebug("in cpubanner, using kstat_cpubanner for cpubanner"); $cpubanner=$kstat_cpubanner; return; } &checkX86; if ($filename && $os eq "SunOS" && $isX86 && ! $hyperthread && ! $kstat_checked) { &check_hyperthread; } elsif ($filename && &is_xen_hv) { # Xen Hypervisor hides Hyper-Threading from /proc/cpuinfo, so # also hard-core some CPU models for it. &check_hyperthread; } &pdebug("in cpubanner, corecnt=$corecnt, npcpu=$npcpu, nvcpu=$nvcpu, cputype=$cputype"); if ($modelmore =~ /\(Solaris x86 machine\)/ && ! $cpubanner && $cputype ne "x86") { $modelmore=""; while (($cf,$cnt)=each(%cpucnt)) { $cf=~/^(.*) (\d+)$/; $cputype=$1; $cpufreq=$2; } &x86multicorecnt($cputype); $ncpu=$cpucnt{"$cputype $cpufreq"}; if ($cpucntflag == 0 && $npcpu == 0) { for $tmp (2,3,4,6,8,10,12,16) { $ncpu /= $tmp if ($corecnt == $tmp && $ncpu % $tmp == 0); } } $ncpu=$npcpu if ($npcpu); $cpubanner="$ncpu X " if ($ncpu > 1); $tmp=&multicore_cputype($cputype,$corecnt); $cpubanner .= "$tmp"; $cpubanner .= " x86" if ($cputype eq "AMD"); $cpubanner .= " ${cpufreq}MHz" if ($cpufreq && $cpufreq ne "0" && $cputype !~ /Hz$/); } } sub show_header { return if ($header_shown); &pdebug("cpucntfrom=$cpucntfrom"); &cpubanner; $header_shown=1; undef %saw; @saw{@simmsizesfound}=(); @simmsizesfound=sort numerically keys %saw; print "hostname: $hostname\n" if ($hostname); if ($filename) { print (($SUNWexplo) ? "Sun/Oracle Explorer directory" : "filename"); print ": $filename\n"; } if ($manufacturer) { $manufacturer="Sun Microsystems, Inc." if ($manufacturer =~ /Sun Microsystems/i); } if ($diagthreadcnt && $cpucntfrom eq "prtdiag") { # Replace @cpucnt with @diagcpucnt while (($cf,$tmp)=each(%cpucnt)) { delete $cpucnt{"$cf"}; $cpucnt{"$cf"}=$diagcpucnt{"$cf"}; } } if ($banner) { # See if banner includes CPU information if ($banner !~ /\(.*SPARC/ && $banner !~ /MHz/ && ! $kstat_cpubanner) { @cputypecnt=keys(%cpucnt); $x=0; while (($cf,$cnt)=each(%cpucnt)) { $x++; $cf=~/^(.*) (\d*)$/; $ctype=$1; $cfreq=$2; &multicore_cpu_cnt(""); $cpubanner .= "$cnt X " if ($cnt > 1); if ($ctype =~ /390Z5/) { $cpubanner .= "SuperSPARC"; $cpubanner .= "-II" if ($cfreq > 70); } elsif ($ctype =~ /MB86907/) { $cpubanner .= "TurboSPARC-II"; } elsif ($ctype =~ /MB86904|390S10/) { $cpubanner .= "microSPARC"; $cpubanner .= "-II" if ($cfreq > 70); } elsif ($ctype =~ /L2A0925/) { $cpubanner .= "microSPARC-IIep"; } elsif ($ctype =~ /,RT62[56]/) { $cpubanner .= "hyperSPARC"; } else { $cpubanner .= "$ctype"; } $cpubanner .= " ${cfreq}MHz" if ($cfreq && $cpubanner !~ /Hz$/); $cpubanner .= ", " if ($x < scalar(@cputypecnt)); } } elsif ($banner =~ /\(/ && $banner !~ /MHz/) { # CPU listed without speed while (($cf,$cnt)=each(%cpucnt)) { $cf=~/^(.*) (\d*)$/; $cfreq=$2; $banner=~s/\)/ ${cfreq}MHz\)/g if ($cfreq); } } } $modelmore="" if ($modelmore =~ /\(Solaris x86 machine\)/ && $model ne "i86pc" && $model ne "i86xpv" && $model ne "i86xen"); if ($verbose) { if ($banner) { print "banner: $banner"; print " $bannermore" if ($bannermore); print " ($cpubanner)" if ($cpubanner); print "\n"; } if ($manufacturer) { print "manufacturer: $manufacturer\n"; } if ($model) { print "model: $model"; print " $modelmore" if ($modelmore); print " $realmodel" if ($realmodel); print " ($cpubanner)" if ($cpubanner && ! $banner); print "\n"; } if ($baseboard) { print "base board: $baseboard\n"; } if (! $clone) { $tmp="Sun"; if ($manufacturer) { $tmp="Sun/Oracle" if ($manufacturer =~ /^Oracle\b/); } $tmp="Oracle" if ($platform =~ /^ORCL,/); print "$tmp development codename: $devname\n" if ($devname); print "$tmp Family Part Number: $familypn\n" if ($familypn); } if (! $filename || $SUNWexplo) { if ($solaris) { print "Solaris " if ($solaris !~ /(Solaris|OmniOS)/); print "$solaris"; if ($machine =~ /86/) { print " X86" if ($solaris !~ / X86/); } elsif ($machine =~ /sun4/) { print " SPARC" if ($solaris !~ / SPARC/); } print ", ${kernbit}-bit kernel, " if ($kernbit); } if ($os =~ /Linux|FreeBSD/ && $release) { if (-x '/bin/busybox') { @busybox=`/bin/busybox cat --help 2>&1`; $busyboxver=""; for (@busybox) { next if (! /^BusyBox/); $busyboxver=&mychomp($_); $busyboxver=~s/\).*$/\)/; } if ($busyboxver) { print "$busyboxver, "; } else { print "BusyBox, "; } } print "$release\n"; } else { print "$os"; print " $osrel" if ($osrel); print " ($osrelease)" if ($osrelease); print ", ${kernbit}-bit kernel" if ($kernbit && $HPUX); print "\n"; } } elsif ($HPUX) { print "$os"; print " $osrel" if ($osrel); print " ($osrelease)" if ($osrelease); print ", ${kernbit}-bit kernel" if ($kernbit); print "\n"; } elsif ($os =~ /Linux|FreeBSD/) { print "BusyBox " if ($filename =~ /BusyBox/); # for regression tests if ($release) { print "$release"; } elsif ($machine =~ /sun|sparc/i || $filename =~ /LinuxSPARC/) { print "Linux SPARC"; } elsif ($machine =~ /arm/i) { print "Linux ARM"; } elsif ($machine =~ /mips/i) { print "Linux MIPS"; } elsif ($have_dmidecode) { print "Linux x86"; } print ", ${kernbit}-bit kernel" if ($kernbit); print "\n"; } elsif ($BSD) { print "Solaris 1.X SPARC, 32-bit kernel, SunOS 4.X\n"; } elsif ($osrel && $solaris) { print "Oracle " if ($solaris !~ /Oracle/ && $platform =~ /^ORCL,/); print "Solaris " if ($solaris !~ /(Solaris|OmniOS)/); print "$solaris, "; print "${kernbit}-bit kernel, " if ($kernbit); print "SunOS $osrel\n"; } else { print "Solaris 2.X"; if ($machine =~ /86/) { print " X86"; } elsif ($machine =~ /sun4/) { print " SPARC"; } print ", SunOS 5.X\n"; } $ncpu=1 if ($ncpu == 0); # It has at least 1 CPU if ($kstat_cpubanner) { $tmp=$kstat_cpubanner; $tmp=~s/(\d) X /$1 /g; print "1 " if ($tmp eq $kstat_cpubanner); print "$tmp cpu"; print "s" if ($tmp ne $kstat_cpubanner); print (($sysfreq) ? ", " : "\n"); } elsif ($cpuarr == -1 && ! &is_xen_vm) { @cputypecnt=keys(%cpucnt); $x=0; $ctype=""; while (($cf,$cnt)=each(%cpucnt)) { if ($cpucntflag == 0 && $npcpu == 0 && $cpucntfrom ne "prtdiag") { for $tmp (2,3,4,6,8,10,12,16) { $cnt /= $tmp if ($corecnt == $tmp && $cnt % $tmp == 0); } $cpucntflag=1; } if ($npcpu) { $cnt=$npcpu; } else { $cnt=$ndcpu if ($ndcpu); $cnt=$ncpu if ($cpucntfrom =~ /cpuinfo/); } $x++; $cf=~/^(.*) (\d*)$/; $ctype=$1; $ctype=$cf if (! $ctype); $cfreq=$2; &checkX86; $ctype=&multicore_cputype($ctype,$corecnt) if ($isX86); &multicore_cpu_cnt(""); $ctype="" if ($ctype =~ /^\S*-Core $/); if ($ctype) { print "$cnt $ctype"; if ($cfreq) { print " ${cfreq}MHz" if ($cfreq && $ctype !~ /Hz$/); } print " cpu"; print "s" if ($cnt > 1); print ", " if ($x < scalar(@cputypecnt)); } } print (($sysfreq) ? ", " : "\n") if ($x && $ctype); } print "system freq: ${sysfreq}MHz\n" if ($sysfreq); } else { $modelbuf=""; if ($manufacturer) { $modelbuf .= "$manufacturer " if ($banner !~ /^$manufacturer/ && $model !~ /^$manufacturer/ && ($banner || $model)); } if ($banner && $bannermore) { $modelbuf .= "$banner $bannermore"; } elsif ($modelmore) { $modelbuf .= "$model $modelmore"; } elsif ($banner) { $modelbuf .= "$banner"; } elsif ($diagbanner) { $modelbuf .= "$diagbanner"; } elsif ($model) { $modelbuf .= "$model"; } if ($cpubanner) { if ($modelbuf) { $modelbuf .= " ($cpubanner)"; } else { $modelbuf = "$cpubanner"; } } $modelbuf .= " $realmodel" if ($realmodel); print "$modelbuf\n" if ($modelbuf); } # debug output if ($verbose > 1) { print "banner = $banner\n" if ($banner); print "diagbanner = $diagbanner\n" if ($diagbanner); print "cpubanner = $cpubanner\n" if ($cpubanner); print "bannermore = $bannermore\n" if ($bannermore); print "model = $model\n" if ($model); print "modelmore = $modelmore\n" if ($modelmore); print "machine = $machine\n" if ($machine); print "platform = $platform\n" if ($platform); print "ultra = $ultra\n" if ($ultra); if ($ultra eq "AXi") { print "found10bit = $found10bit\n"; print "found11bit = $found11bit\n"; } print "systemmanufacturer = $systemmanufacturer\n" if ($systemmanufacturer); print "systemmodel = $systemmodel\n" if ($systemmodel); print "boardmanufacturer = $boardmanufacturer\n" if ($boardmanufacturer); print "boardmodel = $boardmodel\n" if ($boardmodel); print "motherboard = $motherboard\n" if ($motherboard); print "romver = $romver\n" if ($romver); print "freephys = $freephys\n" if ($freephys); print "perl version: " . &mychomp($]) . "\n"; print "memory line: $gotmemory\n" if ($gotmemory); print "module info: $gotmodule\n" if ($gotmodule); print "dmidecode version: $dmidecode_ver\n" if ($dmidecode_ver); # Fujitsu GP7000F and PrimePower systems print "cpu name info: $gotcpunames\n" if ($gotcpunames); print "cpu board info: $gotcpuboards\n" if ($gotcpuboards); print "module name info: $gotmodulenames\n" if ($gotmodulenames); print "simmsizes = @simmsizes\n" if ($simmsizes[0]); print "simmsizesfound = @simmsizesfound\n" if ($simmsizesfound[0]); } if ($verbose && $boardfound_cpu) { if ($format_cpu == 1) { print "CPU Units: Frequency Cache-Size Version\n" if ($model =~ /-Enterprise/ || $ultra eq "e"); } else { print "CPU Units:\n"; } if ($model ne "SPARCserver-1000" && $model ne "SPARCcenter-2000") { print @boards_cpu; print "Memory Units:\n" if (! &is_virtualmachine); } } if ($interleave && ! &is_virtualmachine) { print "Memory Interleave Factor: $interleave"; print "-way" if ($interleave =~/^\d+$/); print "\n"; } print "Maximum Memory Bus Speed: $maxmembusspeed\n" if ($maxmembusspeed); } sub show_unrecognized { if ($perlhexbug) { print " This is most likely because Perl V$PERL_VERSION"; print " is buggy in hex number\n conversions. Please"; print " upgrade your perl release to Perl V5.002 or later\n"; print " for best results.\n"; } else { print " This is most likely because memconf $version"; print " does not completely\n recognize this $os"; print " $osrel" if ($osrel); print " $platform system.\n"; &show_request if ($untested == 0); } } sub show_untested { $osname="$os $osrel"; $osname="$os" if ($osrel eq ""); if ($untested_type eq "OS") { print "WARNING: This is an untested $osname operating"; } elsif ($untested_type eq "OBP") { print "ERROR: This is an untested $osname OBP $romvernum"; } elsif ($untested_type eq "CPU") { print "ERROR: This is an untested CPU type on this $osname"; } else { print "ERROR: This is an untested $osname"; } print " system by memconf $version\n"; print " Please let the author know how it works.\n"; $exitstatus=1; &show_request; } sub show_request { print " Check my website at $URL\n"; print " for a newer version of memconf that may recognize this system better.\n"; print " Please run 'memconf -D' to create a tar file of the output from the\n"; print " following commands to send to Tom Schmidt (tschmidt\@micron.com) so\n"; print " memconf $version may be enhanced to properly recognize this system:\n"; print " memconf -d\n"; &show_helpers(" "); if ($untested) { print " If this system is a Sun clone, please also send any hardware\n"; print " documentation on the memory layout that you may have.\n"; } } sub show_supported { &show_total_memory; print "ERROR: memconf $version is not supported on this $os"; print" $osrel $machine system.\n memconf is supported on:\n"; print " Solaris (SunOS 4.X or 5.X) on SPARC\n"; print " Solaris 10 6/06 or later on x86 with /usr/platform/i86pc/sbin/prtdiag\n"; print " Linux on SPARC with sparc-utils and /dev/openprom\n"; print " Linux on x86 and x86_64 with kernel-utils or pmtools for dmidecode\n"; print " FreeBSD on x86 and x86_64 with dmidecode\n"; print " Most HP-UX systems with SysMgmtPlus (cprop) or Support Tools Manager (cstm)\n"; if ($os =~ /Linux|FreeBSD/) { if ($machine =~ /.86|ia64|amd64|sparc/) { if ($config_cmd =~ /dmidecode/) { print "ERROR: dmidecode command was not found. Please install "; print "dmidecode from\n $dmidecodeURL "; print "to fix this issue.\n"; } print "NOTICE: This may be corrected by installing the "; print (($machine =~ /sparc/) ? "sparc-utils" : "kernel-utils or pmtools"); print "\n package if available for this $machine system.\n"; } else { $config_cmd=""; } } print " memconf may be able to process Sun/Oracle Explorer data on this machine.\n"; print " Check my website at $URL\n"; print " for a newer version of memconf that may recognize this system better.\n"; $exitstatus=1; &mailmaintainer if ($verbose == 3); &pdebug("exit $exitstatus"); exit $exitstatus; } sub show_memory { $mem=shift; print "${mem}MB"; if ($mem >= $meg) { print " (", $mem / $meg, "TB)"; } elsif ($mem >= 1024) { print " (", $mem / 1024, "GB)"; } print "\n"; } sub show_memory_label { $mem=shift; return if (! defined($mem)); return "$mem" if ($mem =~ /[MG]B/); return $mem / 1024 . "GB" if ($mem >= 1024); return "${mem}MB"; } sub show_errors { if ($failing_memory) { print "ERROR: Some of the installed memory has failed.\n"; print " You should consider replacing the failed memory.\n"; $exitstatus=1; } if ($unknown_JEDEC_ID) { print "ERROR: An unknown memory manufacturer was detected by memconf.\n"; &show_request; $exitstatus=1; } } sub check_model { &pdebug("in check_model, model=$model, platform=$platform, banner=$banner, diagbanner=$diagbanner"); $modelbanner=$banner; $modelbanner=$diagbanner if ($banner eq "" && $diagbanner ne ""); &find_helpers; # Workaround for broken "uname -i" on Oracle SPARC T3 systems $platform=$model if ($platform eq "sun4v"); if ($filename) { $platform=$model; $platform="SUNW,Ultra-5_10" if ($diagbanner =~ /Sun Ultra 5\/10/); $platform="SUNW,Sun-Fire" if ($diagbanner =~ /Sun Fire ([346]8[01]0|E[246]900)\b/); $platform="SUNW,Sun-Fire-15000" if ($diagbanner =~ /Sun Fire E2[05]K\b/); $platform=~s/-S$// if ($model =~ /Sun-Blade-[12]500-S\b/); if ($prtdiag_cmd =~ /platform/) { $prtdiag_cmd="/usr/platform/$platform/sbin/prtdiag"; $prtdiag_cmd="/usr/platform/sun4v/sbin/prtdiag" if ($platform =~ /ORCL,/); } } $model=~s/.*SUNW,//g; $model=~s/.*ORCL,//g; $model=~s/TWS,//g; $model=~s/CYCLE,//g; $model=~s/Tadpole_//g; $model=~s/ASPX,//g; $model=~s/PFU,//g; $model=~s/FJSV,//g; $model=~s/CompuAdd //g; $model=~s/RDI,//g; $model=~s/\s+$//; $ultra="ultra" if ($ultra eq 0 && ($model =~ /Ultra|Blade|Fire/ || ($machine eq "sun4v" && ! $filename))); if ($model =~ /Fire[- ](X|B[12]00x)/i) { # Sun Fire X??00 Servers, i86pc # Sun B100x or B200x Blade Servers, i86pc $ultra=""; $machine="x86" if ($machine ne "i86pc"); $untested=1; &x86_devname; } $ultra="sparc64" if ($model =~ /SPARC64/); $ultra="e" if ($model =~ /-Enterprise/ && $model !~ /SPARC-Enterprise/); $ultra=1 if ($model =~ /Ultra-1\b/); $ultra=2 if ($model =~ /Ultra-2\b/); $ultra=5 if ($model =~ /Ultra-5\b/); $ultra="5_10" if ($model =~ /Ultra-5_10\b/); $ultra=30 if ($model =~ /Ultra-30\b/); $ultra=60 if ($model =~ /Ultra-60\b/); $ultra=80 if ($model =~ /Ultra-80\b/); $ultra=250 if ($model =~ /Ultra-250\b/); $ultra=450 if ($model =~ /Ultra-4\b/); $ultra="Netra t1" if ($banner =~ /Netra t1\b/); if ($model =~ /Ultra-4FT\b/) { $ultra="Netra ft1800"; $bannermore="(Netra ft1800)"; $modelmore="(Netra ft1800)"; } $ultra="Sun Blade 1000" if ($model =~ /Ultra-100\b/); # prototype $ultra="Sun Blade 1000" if ($model =~ /Sun-Blade-1000\b/); $ultra="Sun Blade 2000" if ($model =~ /Sun-Blade-2000\b/); $ultra="Netra 20" if ($model =~ /Netra-20\b/); $ultra="Netra 20" if ($model =~ /Netra-T4\b/); # E2900/E4900 also use Netra-T12 $ultra="Netra T12" if ($model =~ /Netra-T12\b/ && $ultra !~ /Sun Fire/); $ultra="Sun Blade 100" if ($model =~ /Grover\b/); # prototype $ultra="Sun Blade 100" if ($model =~ /Sun-Blade-100\b/); $ultra="Sun Fire 280R" if ($model =~ /Enterprise-820R\b/); # prototype $ultra="Sun Fire 280R" if ($model =~ /Sun-Fire-280R\b/); $ultra="Sun Fire" if ($model =~ /Serengeti\b/); # prototype $ultra="Sun Fire" if ($model eq "Sun-Fire" || $model =~ /Sun-Fire-[346]8[01]0\b/); $ultra="Sun Fire V480" if ($model =~ /Sun-Fire-480R\b/); $ultra="Sun Fire V490" if ($model =~ /Sun-Fire-V490\b/); $ultra="Sun Fire V880" if ($model =~ /Sun-Fire-880\b/); $ultra="Sun Fire V890" if ($model =~ /Sun-Fire-V890\b/); # Sun Fire 12K, E25K, etc. systems identifies itself as Sun Fire 15K $ultra="Sun Fire 15K" if ($model =~ /Sun-Fire-15000\b/ && $ultra !~ /Sun Fire /); $ultra="Sun Fire 12K" if ($model =~ /Sun-Fire-12000\b/); $ultra="Serverblade1" if ($model =~ /Serverblade1\b/); # UltraSPARC-IIIi (Jalapeno) systems $ultra="Enchilada" if ($model =~ /Enchilada\b/); # prototype $ultra="Enchilada" if ($model =~ /Sun-Fire-V210\b/); $ultra="Enchilada" if ($model =~ /Netra-210\b/); $ultra="Enchilada" if ($model =~ /Sun-Fire-V240\b/); $ultra="Enchilada" if ($model =~ /Netra-240\b/); $ultra="Sun Fire V440" if ($model =~ /Sun-Fire-V440\b/); $ultra="Netra 440" if ($model =~ /Netra-440\b/); $ultra="Sun Fire V250" if ($model =~ /Sun-Fire-V250\b/); $ultra="Sun Blade 1500" if ($model =~ /Sun-Blade-1500\b/); $ultra="Sun Blade 2500" if ($model =~ /Sun-Blade-2500\b/); if ($model =~ /Sun-Blade-[12]500-S\b/) { $model=~s/-S$//; $modelmore="(Silver)" if ($banner !~ /\(Silver\)/); } $ultra="Sun Ultra 45 Workstation" if ($model =~ /Sun-Ultra-45-Workstation\b/ || $model eq "A70"); $ultra="Sun Ultra 25 Workstation" if ($model =~ /Sun-Ultra-25-Workstation\b/ || $model eq "Ultra-25"); $ultra="Sun Ultra 45 or Ultra 25 Workstation" if ($model =~ /Sun-Ultra-45-or-Ultra-25-Workstation\b/); $ultra="Sun Fire V125" if ($model =~ /Sun-Fire-V125\b/); $ultra="Seattle" if ($model =~ /Sun-Fire-V215\b/); $ultra="Seattle" if ($model =~ /Sun-Fire-V245\b/); $ultra="Boston" if ($model =~ /Sun-Fire-V445\b/); # UltraSPARC-IV (Jaguar) or UltraSPARC-IV+ (Panther) systems $ultra="Sun Fire E2900" if ($model =~ /Sun-Fire-E2900\b/); $ultra="Sun Fire E4900" if ($model =~ /Sun-Fire-E4900\b/); $ultra="Sun Fire E6900" if ($model =~ /Sun-Fire-E6900\b/); $ultra="Sun Fire E20K" if ($model =~ /Sun-Fire-(E|Enterprise-)20K\b/); $ultra="Sun Fire E25K" if ($model =~ /Sun-Fire-(E|Enterprise-)25K\b/); # SPARC64-VI or SPARC64-VII systems $ultra=$banner if ($banner =~ /SPARC Enterprise M[34589]000 Server/); # UltraSPARC-T1 (Niagara) systems if ($model =~ /Sun-Fire-T200\b/) { $ultra="T2000"; $modelmore="(Sun Fire T2000)"; } $ultra="T2000" if ($model =~ /Sun-Fire-T2000\b|SPARC-Enterprise-T2000\b|Netra-T2000\b/ || $modelbanner =~ /SPARC Enterprise T2000\b|Netra T2000\b/); $ultra="T1000" if ($model =~ /Sun-Fire-T1000\b|SPARC-Enterprise-T1000\b/ || $modelbanner =~ /SPARC Enterprise T1000/); $ultra="T6300" if ($model =~ /Sun-Blade-T6300\b/ || $modelbanner =~ /\bT6300\b/); # UltraSPARC-T2 (Niagara-II) systems $ultra="T5120" if ($model =~ /SPARC-Enterprise-T5120\b/ || $modelbanner =~ /\bT5120\b/); $ultra="T5220" if ($model =~ /(SPARC-Enterprise|Netra)-T5220\b/ || $modelbanner =~ /\bT5220\b/); $ultra="T6320" if ($model =~ /Sun-Blade-T6320\b/ || $modelbanner =~ /\bT6320\b/); $ultra="CP3260" if ($model =~ /Netra-CP3260\b/ || $modelbanner =~ /\bNetra CP3260\b/); # UltraSPARC-T2+ (Victoria Falls) systems $ultra="T5140" if ($model =~ /\bT5140\b/ || $modelbanner =~ /\bT5140\b/); $ultra="T5240" if ($model =~ /\bT5240\b|-USBRDT-5240\b/ || $modelbanner =~ /\bT5240\b/); $ultra="T5440" if ($model =~ /\bT5440\b|-USBRDT-5440\b/ || $modelbanner =~ /\bT5440\b/); $ultra="T6340" if ($model =~ /Sun-Blade-T6340\b/ || $modelbanner =~ /\bT6340\b/); # SPARC-T3 (Rainbow Falls) systems $ultra="T3-1" if ($model =~ /SPARC-T3-1\b/ || $modelbanner =~ /SPARC T3-1\b/); $ultra="T3-1B" if ($model =~ /SPARC-T3-1B\b/ || $modelbanner =~ /SPARC T3-1B\b/); $ultra="T3-1BA" if ($model =~ /SPARC-T3-1BA\b/ || $modelbanner =~ /SPARC T3-1BA\b/); $ultra="T3-2" if ($model =~ /SPARC-T3-2\b/ || $modelbanner =~ /SPARC T3-2\b/); $ultra="T3-4" if ($model =~ /SPARC-T3-4\b/ || $modelbanner =~ /SPARC T3-4\b/); # SPARC-T4 systems $ultra="T4-1" if ($model =~ /SPARC-T4-1\b/ || $modelbanner =~ /SPARC T4-1\b/); $ultra="T4-1B" if ($model =~ /SPARC-T4-1B\b/ || $modelbanner =~ /SPARC T4-1B\b/); $ultra="T4-2" if ($model =~ /SPARC-T4-2\b/ || $modelbanner =~ /SPARC T4-2\b/); $ultra="T4-2B" if ($model =~ /SPARC-T4-2B\b/ || $modelbanner =~ /SPARC T4-2B\b/); $ultra="T4-4" if ($model =~ /SPARC-T4-4\b/ || $modelbanner =~ /SPARC T4-4\b/); # SPARC-T5 systems $ultra="T5-2" if ($model =~ /SPARC-T5-2\b/ || $modelbanner =~ /SPARC T5-2\b/); $ultra="T5-4" if ($model =~ /SPARC-T5-4\b/ || $modelbanner =~ /SPARC T5-4\b/); $ultra="T5-8" if ($model =~ /SPARC-T5-8\b/ || $modelbanner =~ /SPARC T5-8\b/); $ultra="T5-1B" if ($model =~ /SPARC-T5-1B\b/ || $modelbanner =~ /SPARC T5-1B\b/); # SPARC M5 and M6 systems $ultra="M5-32" if ($model =~ /SPARC-M5-32\b/ || $modelbanner =~ /SPARC M5-32\b/); $ultra="M6-32" if ($model =~ /SPARC-M6-32\b/ || $modelbanner =~ /SPARC M6-32\b/); # Fujitsu SPARC M10 systems $ultra="M10-1" if ($model =~ /SPARC-M10-1\b/ || $modelbanner =~ /SPARC M10-1\b/); $ultra="M10-4" if ($model =~ /SPARC-M10-4\b/ || $modelbanner =~ /SPARC M10-4\b/); $ultra="M10-4S" if ($model =~ /SPARC-M10-4S\b/ || $modelbanner =~ /SPARC M10-4S\b/); # SPARC S7 and M7 systems $ultra="S7-2" if ($model =~ /SPARC-S7-2\b/ || $modelbanner =~ /SPARC S7-2\b/); $ultra="S7-2L" if ($model =~ /SPARC-S7-2L\b/ || $modelbanner =~ /SPARC S7-2L\b/); $ultra="T7-1" if ($model =~ /SPARC-T7-1\b/ || $modelbanner =~ /SPARC T7-1\b/); $ultra="T7-2" if ($model =~ /SPARC-T7-2\b/ || $modelbanner =~ /SPARC T7-2\b/); $ultra="T7-4" if ($model =~ /SPARC-T7-4\b/ || $modelbanner =~ /SPARC T7-4\b/); $ultra="M7-8" if ($model =~ /SPARC-M7-8\b/ || $modelbanner =~ /SPARC M7-8\b/); $ultra="M7-16" if ($model =~ /SPARC-M7-16\b/ || $modelbanner =~ /SPARC M7-16\b/); # Older SPARCstations $modelmore="SPARCstation SLC" if ($model eq "Sun 4/20"); $modelmore="SPARCstation ELC" if ($model eq "Sun 4/25"); $modelmore="SPARCstation IPC" if ($model eq "Sun 4/40"); $modelmore="SPARCstation IPX" if ($model eq "Sun 4/50"); $modelmore="SPARCstation 1" if ($model eq "Sun 4/60"); $modelmore="SPARCstation 1+" if ($model eq "Sun 4/65"); $modelmore="SPARCstation 2" if ($model eq "Sun 4/75"); $modelmore="(SPARCsystem 600)" if ($model =~ /Sun.4.600/ && $banner !~ /SPARCsystem/); $modelmore="Sun 4/30" if ($model =~ /SPARCstation-LX/); $modelmore="Sun 4/15" if ($model =~ /SPARCclassic/); $modelmore="Sun 4/10" if ($model =~ /SPARCclassic-X/); $modelmore="(SPARCstation 10SX)" if ($model =~ /Premier-24/); if ($model eq "S240") { $manufacturer="Sun Microsystems, Inc."; $modelmore="SPARCstation Voyager"; } # x86 &checkX86; if ($isX86) { $modelmore="(Solaris x86 machine)"; $cputype="x86"; $machine=$model; $ultra=0; $cpucntfrom="prtconf" if (! $cpucntfrom); return if ($model_checked); &check_prtdiag if ($use_psrinfo_data == 2); &check_psrinfo; &cpubanner; $cpucnt{"$cputype $cpufreq"}++; } # Clones if ($banner =~ /\bMP-250[(\b]/) { $ultra="axus250"; $bannermore="Ultra-250"; $modelmore="(Ultra-250)"; } $manufacturer="AXUS" if ($ultra =~ /axus/); $manufacturer="Force Computers" if ($model =~ /SPARC CP/); if ($model eq "S3GX") { $bannermore="(SPARCbook 3GX)"; $modelmore="(SPARCbook 3GX)"; } if ($model eq "S3XP") { $bannermore="(SPARCbook 3XP)"; $modelmore="(SPARCbook 3XP)"; } $manufacturer="Sun Microsystems, Inc." if ($banner !~ /Axil/ && ( $model =~ /^SPARCstation|^SPARCsystem|^SPARCclassic/ || $model =~ /^SPARCserver|^SPARCcenter|Enterprise|Premier 24/ || $model =~ /Netra|Sun.Fire|Sun.Blade|Serverblade1/)); # Oracle purchased Sun in 2010, so newer systems bear the Oracle name. $manufacturer="Oracle Corporation" if ($platform =~ /^ORCL,/ && $manufacturer eq "Sun Microsystems, Inc."); if ($model =~ /Auspex/) { $manufacturer="Auspex"; $model=~s/Auspex //g; $bannermore="Netserver"; $modelmore="Netserver"; } $manufacturer="Fujitsu" if ($banner =~ /Fujitsu/); $manufacturer="Fujitsu Siemens" if ($banner =~ /Fujitsu Siemens/); $manufacturer="Fujitsu Siemens Computers" if ($banner =~ /Fujitsu Siemens Computers/); if ($model =~ /S-4|^GPU[SZU]/ || $model eq "GP") { $manufacturer="Fujitsu" if ($manufacturer !~ /^Fujitsu/); $model=~s,_,/,g; $untested=1 if ($model =~ /^GPUSC-L/); $untested=1 if ($model =~ /^GPUU/); } if ($model =~ /PowerLite-/) { $bannermore=$model; $bannermore=~s/PowerLite-//g; } $model_checked=1; } sub check_banner { &pdebug("in check_banner, banner=$banner, ultra=$ultra"); $ultra="ultra" if ($ultra eq 0 && ($banner =~ /Ultra|Blade|Fire/)); $ultra="sparc64" if ($banner =~ /SPARC64/); $ultra=5 if ($banner =~ /Ultra 5\b/); $ultra="5_10" if ($banner =~ /Ultra 5\/10\b/); $ultra=10 if ($banner =~ /Ultra 10\b/); $ultra="220R" if ($banner =~ /Enterprise 220R\b/); $ultra=80 if ($banner =~ /Ultra 80\b/); # E410 is prototype name of E420R, but may still be in the # banner as "Sun Ultra 80/Enterprise 410 UPA/PCI" $ultra="420R" if ($banner =~ /Enterprise 410\b/); $ultra="420R" if ($banner =~ /Enterprise 420R\b/); $ultra="Netra t140x" if ($banner =~ /Netra t 1400\/1405\b/); $ultra="CP1400" if ($banner =~ /Ultra CP 1400\b/); $ultra="CP1500" if ($banner =~ /Ultra CP 1500\b/); $ultra="CP2000" if ($banner =~ /\bCP2000\b/); $ultra="CP2040" if ($banner =~ /\bCP2000 model 40\b/); $ultra="CP2060" if ($banner =~ /\bCP2000 model 60\b/); $ultra="CP2080" if ($banner =~ /\bCP2000 model 80\b/); $ultra="CP2140" if ($banner =~ /\bCP2000 model 140\b/); $ultra="CP2160" if ($banner =~ /\bCP2000 model 160\b/); $ultra="Sun Blade 1000" if ($banner =~ /Sun Excalibur\b/); # prototype $ultra="Sun Blade 2000" if ($banner =~ /Sun Blade 2000\b/); $ultra="Netra ct400" if ($banner =~ /Netra ct400\b/); $ultra="Netra ct410" if ($banner =~ /Netra ct410\b/); $ultra="Netra ct800" if ($banner =~ /Netra ct800\b/); $ultra="Netra ct810" if ($banner =~ /Netra ct810\b/); $ultra="Sun Blade 150" if ($banner =~ /Sun Blade 150\b/); # Sun Fire 12K, E25K, etc. systems identifies itself as Sun Fire 15K $ultra="Sun Fire 12K" if ($banner =~ /Sun Fire (12000|12K)\b/); if ($banner =~ /Ultra 4FT\b/) { $ultra="Netra ft1800"; $bannermore="(Netra ft1800)"; $modelmore="(Netra ft1800)"; } # UltraSPARC-IIIi (Jalapeno) systems $ultra="Sun Ultra 45 Workstation" if ($banner =~ /Sun Ultra 45 Workstation\b/); $ultra="Sun Ultra 25 Workstation" if ($banner =~ /Sun Ultra 25 Workstation\b/); # UltraSPARC-IV (Jaguar) or UltraSPARC-IV+ (Panther) systems $ultra="Sun Fire E2900" if ($banner =~ /Sun Fire E2900\b/); $ultra="Sun Fire E4900" if ($banner =~ /Sun Fire E4900\b/); $ultra="Sun Fire E6900" if ($banner =~ /Sun Fire E6900\b/); $ultra="Sun Fire E20K" if ($banner =~ /Sun Fire E20K\b/); $ultra="Sun Fire E25K" if ($banner =~ /Sun Fire E25K\b/); # SPARC64-VI or SPARC64-VII systems $ultra=$banner if ($banner =~ /SPARC Enterprise M[34589]000 Server/); # Clones if ($banner =~ /\bMP-250[(\b]/) { $ultra="axus250"; $bannermore="Ultra-250"; $modelmore="(Ultra-250)"; } $manufacturer="Sun Microsystems, Inc." if ($banner =~ /Sun |Netra /); $manufacturer="AXUS" if ($ultra =~ /\baxus\b/); $manufacturer="Rave" if ($banner =~ /Axil/); $manufacturer="Tadpole/Cycle" if ($banner =~ /Cycle|\bUP-20\b|\b520IIi\b/); $manufacturer="Tadpole" if ($banner =~ /Tadpole|\bRDI\b|\bVoyagerIIi\b|\bSPARCLE\b/); $manufacturer="Tatung" if ($banner =~ /COMPstation/); $manufacturer="Twinhead" if ($banner =~ /TWINstation/); $manufacturer="Fujitsu" if ($banner =~ /Fujitsu/); $manufacturer="Fujitsu Siemens" if ($banner =~ /Fujitsu Siemens/); $manufacturer="Fujitsu Siemens Computers" if ($banner =~ /Fujitsu Siemens Computers/); } sub check_for_prtdiag { return if (! $prtdiag_exec && ! $filename); return if ($have_prtdiag_data); &find_helpers; # Check for LDOMs if ($ldm_cmd && ! $have_ldm_data) { # Warn that ldm and prtdiag may take a while to run &please_wait; @ldm=&run("$ldm_cmd list-devices -a -p"); $have_ldm_data=1; foreach $line (@ldm) { $line=&dos2unix($line); $line=&mychomp($line); &check_LDOM; } } @prtdiag=&run("$prtdiag_exec") if (! $filename); $have_prtdiag_data=1; foreach $line (@prtdiag) { $line=&dos2unix($line); # Some Solaris prtdiag outputs have malformed header, so # handle them also. if ($line =~ /^System Configuration: +|.BIOS Configuration: |Sun Microsystems .*Fire *X|Sun Microsystems *X|Sun Microsystems .*Blade *X|Sun Microsystems .*Memory size: |^Oracle Corporation/i || ($line =~ /Sun Microsystems .*Ultra / && $machine eq "i86pc")) { $line=&mychomp($line); $tmp=$line; $line=~s/System Configuration: +//g; $line=~s/BIOS Configuration: .*//g; if ($line =~ /^Sun Microsystems/i) { $manufacturer="Sun Microsystems, Inc." if ($line !~ / i86pc$/); if ($tmp =~ /System Configuration: *W[12]00z/ && ! $model && $machine eq "i86pc") { $diagbanner=$line; $diagbanner=~s/^.* Inc\. *(.*)/$1/; } } elsif ($line =~ /^Oracle /i) { $manufacturer="Oracle Corporation" if ($line !~ / i86pc$/); } elsif ($line =~ /Inc\./i) { $manufacturer=$line; $manufacturer=~s/^(.* Inc\.).*/$1/i; if ($tmp !~ /BIOS Configuration: / && ! $model && $machine eq "i86pc") { $diagbanner=$line; $diagbanner=~s/^.* Inc\. *(.*)/$1/; } } elsif ($line =~ /Corporation/i) { $manufacturer=$line; $manufacturer=~s/^(.* Corporation).*/$1/i; if ($tmp !~ /BIOS Configuration: / && ! $model && $machine eq "i86pc") { $diagbanner=$line; $diagbanner=~s/^.* Corporation *(.*)/$1/; } } elsif ($line !~ /(To Be Filled|System Manufacturer)/i) { $manufacturer=$line; $manufacturer=~s/^(\w+)[ \/].*/$1/; } foreach $tmp ("Sun Microsystems, Inc.","Sun Microsystems","Oracle Corporation") { if ($line =~ /^$tmp +sun\w+ +/) { $diagbanner=$line; $diagbanner=~s/$tmp +sun\w+ +//g; $diagbanner=~s/Memory size: .*$//g; } elsif ($line =~ /^$tmp *Sun +/i) { $diagbanner=$line; $diagbanner=~s/$tmp *Sun/Sun/ig; $diagbanner=~s/Memory size: .*$//g; $diagbanner=~s/ BLADE / Blade /g; $diagbanner=~s/ FIRE / Fire /g; $diagbanner=~s/ SERVER\b/ Server /g; $diagbanner=~s/ MODULE*\b/ Module /g; $diagbanner=~s/ */ /g; } elsif ($line =~ /^$tmp.*Ultra/i) { $diagbanner=$line; $diagbanner=~s/$tmp.*Ultra/Ultra/ig; $diagbanner=~s/Memory size: .*$//g; } elsif ($line =~ /^$tmp *W[12]100z/i) { $diagbanner=$line; $diagbanner=~s/$tmp *//ig; } $diagbanner=~s/\s+$//; } } $prtdiag_failed=1 if ($line =~ /Prtdiag Failed/i); # prtdiag only works on the global zone, so find out # if we are in a Solaris zone. solaris8 brand container shows # kernel version of "Generic_Virtual" $prtdiag_failed=2 if ($line =~ /prtdiag can only be run in the global /i || $kernver eq "Generic_Virtual"); } if ($psrinfo_cmd && ! $have_psrinfo_data) { @psrinfo=&run("$psrinfo_cmd -v"); $tmp=&mychomp(`$psrinfo_cmd -p 2>/dev/null`); # physical CPUs if ($tmp) { push(@psrinfo, "#psrinfo -p\n$tmp\n"); $tmp=&mychomp(`$psrinfo_cmd -p -v 2>/dev/null`); push(@psrinfo, "#psrinfo -p -v\n$tmp\n"); } $have_psrinfo_data=1; } if ($ipmitool_cmd && ! $have_ipmitool_data) { @ipmitool=&run("$ipmitool_cmd fru"); $have_ipmitool_data=1; } if ($smbios_cmd && ! $have_smbios_data) { @smbios=&run("$smbios_cmd"); $have_smbios_data=1; } if ($kstat_cmd && ! $have_kstat_data) { @kstat=&run("$kstat_cmd"); $have_kstat_data=1; } if (! $filename && $verbose == 3) { # Only run the following commands if E-mailing maintainer since # this data is used by memconf only for some systems if ($prtpicl_cmd && ! $have_prtpicl_data) { @prtpicl=&run("$prtpicl_cmd -v"); $have_prtpicl_data=1; } if ($virtinfo_cmd && ! $have_virtinfo_data) { @virtinfo=&run("$virtinfo_cmd -pa"); $have_virtinfo_data=1; } if ($cfgadm_cmd && ! $have_cfgadm_data) { @cfgadm=&run("$cfgadm_cmd -al"); $have_cfgadm_data=1; } if ($ldm_cmd && ! $have_ldm_data) { @ldm=&run("$ldm_cmd list-devices -a -p"); $have_ldm_data=1; } } } sub add_to_sockets_used { $_=shift; # strip leading slash for matching $_=~s/^\///; if ($sockets_used !~ /$_/) { $sockets_used .= "," if ($sockets_used && /\s/); $sockets_used .= " $_"; # &pdebug("in add_to_sockets_used, added $_"); } } sub add_to_sockets_empty { $_=shift; $sockets_empty .= "," if ($sockets_empty && /\s/); $sockets_empty .= " $_"; } sub check_prtdiag { return if ($prtdiag_checked); &pdebug("in check_prtdiag"); $prtdiag_checked=1; return if (! $prtdiag_exec && ! $filename); &check_for_prtdiag; if ($diagbanner =~ /W1100z\b/i) { $model=$diagbanner if ($model eq "i86pc"); } $flag_cpu=0; $flag_mem=0; $build_socketstr=0; foreach $line (@prtdiag) { $line=&dos2unix($line); if ($line =~ /====|\/ \(picl,|= 2) { if ($linearr[2] =~ /\bU\d\d\d\d\b/) { # Sun Ultra-250 format $sockets_used .= " $linearr[2]"; } elsif ($linearr[2] =~ /\b\d\d\d\d\b/) { # Sun Ultra-4 format $sockets_used .= " U$linearr[2]"; } } if ($#linearr >= 3) { if ($linearr[3] ne "BankIDs" && $linearr[3] ne "GroupID" && $line !~ /^0x\d[\d ]+\d.+ +\d +-$/) { if ($linearr[1] =~ /\b\d+MB\b/) { # Sun Blade 100/1000 format $simmsize=$linearr[1]; $simmsize=~s/MB//g; push(@simmsizesfound, "$simmsize"); } elsif ($linearr[1] =~ /\b\d+GB\b/) { # Sun Blade 1000 format $simmsize=$linearr[1]; $simmsize=~s/GB//g; $simmsize *= 1024; push(@simmsizesfound, "$simmsize"); } } if ($model eq "Ultra-250" || $ultra eq 250 || $model eq "Ultra-4" || $ultra eq 450 || $model eq "Ultra-4FT" || $ultra eq "Netra ft1800") { if ($linearr[3] =~ /\b\d+\b/) { $simmsize=$linearr[3]; push(@simmsizesfound, "$simmsize"); } } } if ($#linearr >= 2) { if ($linearr[$#linearr] =~ /\bDIMM\d/ && $linearr[$#linearr - 1] =~ /\bCPU\d/) { $socket="$linearr[$#linearr - 1]_$linearr[$#linearr]"; &add_to_sockets_used("$socket") if ($linearr[1] ne "empty"); $build_socketstr=1 if ($#socketstr == 0); push(@socketstr, ("$socket")) if ($build_socketstr); } elsif ($linearr[$#linearr - 2] =~ /\bDIMM\d|_DIMM\d/ && $linearr[$#linearr - 1] =~ /\bBank\b/i) { # Ultra40 and JavaWorkstation $socket="$linearr[$#linearr - 2] $linearr[$#linearr - 1] $linearr[$#linearr]"; &add_to_sockets_used("$socket") if ($linearr[1] ne "empty"); $build_socketstr=1 if ($#socketstr == 0); push(@socketstr, ("$socket")) if ($build_socketstr); } elsif ($linearr[$#linearr] =~ /\b(DIMM\d|[UJ]\d\d\d\d[\b,])/ || ($linearr[$#linearr - 1] eq "Label" && $linearr[$#linearr] eq "-")) { $sockets_used .= " $linearr[$#linearr]"; # May be multiple sockets separated by "," $sockets_used=~s/,/ /g; } elsif ($linearr[2] =~ /MB\/P[01]\/B[01]\/D[01]|C[0-3]\/P[01]\/B[01]\/D[01]/) { $sockets_used .= " $linearr[2]"; # May be multiple sockets separated by "," $sockets_used=~s/,/ /g; } } if ($linearr[0] !~ /^0x/ && ($linearr[$#linearr] eq "-" || $linearr[$#linearr] =~ /^-,/)) { # unlabeled sockets $sockets_used .= " $linearr[$#linearr]"; # May be multiple sockets separated by "," $sockets_used=~s/,/ /g; } if ($linearr[$#linearr] =~ /\/J\d\d\d\d$/) { $linearr[$#linearr]=~s/.+\///g; $sockets_used .= " $linearr[$#linearr]"; } if ($ultra eq "Sun Fire 280R") { if ($line =~ / CA +0 +[0-3] .+4-way/) { $sockets_used="J0100 J0202 J0304 J0406 J0101 J0203 J0305 J0407"; } elsif ($line =~ / CA +0 +[02] /) { $sockets_used .= " J0100 J0202 J0304 J0406" if ($sockets_used !~ / J0100 /); } elsif ($line =~ / CA +[01] +[13] /) { $sockets_used .= " J0101 J0203 J0305 J0407" if ($sockets_used !~ / J0101 /); } } # Memory on Sun Fire systems if ($line =~ /^\/N\d\/SB\d\/P\d\/B\d\b/) { $boardslot_mem=substr($line,0,13); push(@boardslot_mems, "$boardslot_mem"); $boardslot_mems .= $boardslot_mem . " "; } elsif ($line =~ /^\/N\d\/SB\d\d\/P\d\/B\d\b/) { $boardslot_mem=substr($line,0,14); push(@boardslot_mems, "$boardslot_mem"); $boardslot_mems .= $boardslot_mem . " "; } elsif ($line =~ /^\/SB\d\d\/P\d\/B\d\b/) { $boardslot_mem=substr($line,0,11); push(@boardslot_mems, "$boardslot_mem"); $boardslot_mems .= $boardslot_mem . " "; } elsif ($line =~ /\bSB\d\/P\d\/B\d\/D\d\b,/) { $boardslot_mem=substr($line,24,51); push(@boardslot_mems, "$boardslot_mem"); $boardslot_mems .= $boardslot_mem . " "; } elsif ($line =~ /\bSB\d\/P\d\/B\d\/D\d\b/) { $boardslot_mem=substr($line,24,12); push(@boardslot_mems, "$boardslot_mem"); $boardslot_mems .= $boardslot_mem . " "; } if ($ultra =~ /Sun Fire/ && $#linearr >= 5) { if ($linearr[5] =~ /\d+MB/) { $simmsize=$linearr[5]; $simmsize=~s/MB//g; push(@simmsizesfound, "$simmsize"); } } if ($ultra =~ /Sun Fire V[48][89]0\b/) { # Fire V480, V490, V880, V890 $bankname="groups"; if ($banks_used ne "A0 A1 B0 B1") { $banks_used="A0 B0" if ($line =~ /^ ?[ABCD] .+ 4-way /); $banks_used="A0 A1 B0 B1" if ($line =~ /^ ?[ABCD] .+ 8-way /); } } if ($linearr[$#linearr] =~ /MB\/CMP0\/CH[0-3]\/R[01]\/D[01]/) { # UltraSPARC-T1 systems if ($#linearr >= 5) { if ($linearr[5] eq "MB") { $simmsize=$linearr[4]; $simmsize=~s/MB//g; $simmsize /= 2; push(@simmsizesfound, "$simmsize"); } elsif ($linearr[5] eq "GB") { $simmsize=$linearr[4]; $simmsize=~s/GB//g; $simmsize *= 512; push(@simmsizesfound, "$simmsize"); } if ($linearr[2] eq "MB") { $prtdiag_memory += $linearr[1]; } elsif ($linearr[2] eq "GB") { $prtdiag_memory += $linearr[1] * 1024; } $installed_memory=$prtdiag_memory if ($prtdiag_memory); } $sockets_used .= " $linearr[$#linearr]"; } if ($linearr[$#linearr] =~ /MB\/CMP[0-3]\/BR[0-3]\/CH[01]\/D[01]|MB\/CMP[0-3]\/MR[01]\/BR[01]\/CH[01]\/D[23]/) { # UltraSPARC-T2 systems: T5120, T5220, T6320 # UltraSPARC-T2+ systems: T5140, T5240, T5440 $sockets_used .= " $linearr[$#linearr]"; } if ($linearr[$#linearr] =~ /MB\/CPU[0-3]\/CMP[0-3]\/BR[01]\/CH[01]\/D[01]|MB\/MEM[0-3]\/CMP[0-3]\/BR[01]\/CH[01]\/D[01]/) { $sockets_used .= " $linearr[$#linearr]"; } if ($linearr[$#linearr] =~ /MB\/CMP[01]\/BOB[0-3]\/CH[01]\/D[01]/) { # SPARC T3-1, T3-1B, T4-1 or T4-1B $sockets_used .= " $linearr[$#linearr]"; } if ($linearr[$#linearr] =~ /MB\/CMP[01]\/MR[01]\/BOB[01]\/CH[01]\/D[01]/) { # SPARC T3-2, T4-2 $sockets_used .= " $linearr[$#linearr]"; } if ($linearr[$#linearr] =~ /PM[01]\/CMP[01]\/BOB[0-3]\/CH[01]\/D[01]/) { # SPARC T3-4, T4-4 $sockets_used .= " $linearr[$#linearr]"; } if ($linearr[$#linearr] =~ /SYS\/MB\/CM[01]\/CMP\/MR[0-3]\/BOB[01]\/CH[01]\/D[01]/) { # SPARC T5-2 $sockets_used .= " $linearr[$#linearr]"; } if ($linearr[$#linearr] =~ /SYS\/PM[0-3]\/CM[01]\/CMP\/BOB[0-7]\/CH[01]\/D[01]/) { # SPARC T5-4, T5-8 $sockets_used .= " $linearr[$#linearr]"; } if ($linearr[$#linearr] =~ /SYS\/MB\/CM0\/CMP\/BOB[0-7]\/CH[01]\/D[01]/) { # SPARC T5-1B $sockets_used .= " $linearr[$#linearr]"; } if ($linearr[$#linearr] =~ /SYS\/CMU\d+\/CMP\d+\/D\d+/) { # SPARC M5-32, M6-32 $sockets_used .= " $linearr[$#linearr]"; } if ($linearr[$#linearr] =~ /SYS\/MBU\/CMP0\/MEM[01][0-3][AB]/) { # Fujitsu SPARC M10-1 $sockets_used .= " $linearr[$#linearr]"; } if ($linearr[$#linearr] =~ /BB\d+\/CMU[LU]\/CMP[01]\/MEM[01][0-7][AB]/) { # Fujitsu SPARC M10-4, M10-4S (guess) $sockets_used .= " $linearr[$#linearr]"; } if ($linearr[$#linearr] =~ /SYS\/MB\/CMP\d+\/MCU\d+\/CH\d+\/D\d+/) { # SPARC S7-2, S7-2L $sockets_used .= " $linearr[$#linearr]"; } } if ($line =~ /CPU Units:/) { $flag_cpu=1; # Start of CPU section $flag_mem=0; # End of memory section $format_cpu=1; } if ($line =~ /==== (CPU|Processor Sockets |Virtual CPU)/) { $flag_cpu=1; # Start of CPU section $flag_mem=0; # End of memory section $format_cpu=2; } if ($line =~ /Memory Units:|==== Memory |==== Physical Memory |Used Memory:/) { $flag_cpu=0; # End of CPU section $flag_mem=1; # Start of memory section } if ($line =~ /CPU Units:/ && $line =~ /Memory Units:/) { $flag_cpu=1; # Start of CPU section $flag_mem=1; # Start of memory section } if ($flag_cpu && $line !~ /^\s*\n$/) { if ($model eq "Ultra-5_10" || $ultra eq "5_10" || $ultra eq 5 || $ultra eq 10) { $newline=$line; $newline=~s/^ //g if ($line !~ /Run Ecache CPU CPU/); push(@boards_cpu, "$newline"); } else { push(@boards_cpu, "$line"); } $boardfound_cpu=1; &checkX86; if ($flag_cpu == 2 && $isX86) { # Solaris x86 CPU type found in prtdiag $cputype2=&mychomp($line); # Remove multiple spaces before some Xeon models $cputype2=~s/\s\s+([ELWX][3-9])/ $1/; $cputype2=~s/\s\s+.*//; $cputype2=~s/(^.* Processor \d+) .*/$1/; $cputype2=&cleanup_cputype($cputype2); &x86multicorecnt($cputype2); # rewrite %cpucnt $cputype2 $cfreq=0; while (($cf,$cnt)=each(%cpucnt)) { $cf=~/^(.*) (\d+)$/; if (defined($2)) { $cfreq=$2; delete $cpucnt{"$1 $2"}; } else { delete $cpucnt{"$cf"}; } } $ndcpu++; if ($cpucntfrom ne "psrinfo") { $cpucntfrom="prtdiag"; $cpucntflag=1; $ncpu++ if ($filename); } $cputype=$cputype2 if ($cputype2); $cputype=$cputype_prtconf if (($cputype eq "AMD" || $cputype eq "Opteron") && $cputype_prtconf); $cputype=$cputype_psrinfo if ($cputype_psrinfo); $cpucnt{"$cputype $cfreq"}=$ncpu; } # CPUs on Sun Fire systems if ($line =~ /^\/N\d\/SB\d\/P\d\b/) { $boardslot_cpu=substr($line,0,10); push(@boardslot_cpus, "$boardslot_cpu"); $boardslot_cpus .= $boardslot_cpu . " "; } elsif ($line =~ /^\/N\d\/SB\d\d\/P\d\b/) { $boardslot_cpu=substr($line,0,11); push(@boardslot_cpus, "$boardslot_cpu"); $boardslot_cpus .= $boardslot_cpu . " "; } elsif ($line =~ /^\/SB\d\d\/P\d\b/) { $boardslot_cpu=substr($line,0,8); push(@boardslot_cpus, "$boardslot_cpu"); $boardslot_cpus .= $boardslot_cpu . " "; &prtdiag_threadcount(1); } elsif ($line =~ /^ SB\d\/P\d\b/) { $boardslot_cpu=substr($line,4,6); push(@boardslot_cpus, "$boardslot_cpu"); $boardslot_cpus .= $boardslot_cpu . " "; # prtdiag does not show cpuid or cputype } elsif ($line =~ / SB\d\/P\d$/) { $boardslot_cpu=substr($line,length($line)-7,6); push(@boardslot_cpus, "$boardslot_cpu"); $boardslot_cpus .= $boardslot_cpu . " "; &prtdiag_threadcount(0); } } if ($flag_cpu && $line =~ /------/) { # Next lines are the CPUs on each system board $flag_cpu=2; } if ($flag_mem && $line =~ /------/) { # Next lines are the memory on each system board $flag_mem=2; } if ($filename && $use_psrinfo_data) { # May have "psrinfo -v" output in regression test file if ($line =~ /.+ operates at \d+ MHz/) { $cpufreq=&mychomp($line); $cpufreq=~s/.+ operates at //; $cpufreq=~s/ MHz.+//; $cpucntfrom="psrinfo" if ($cpucntfrom ne "ldm"); $cpucntflag="0"; # reset flag $psrcpucnt++; # rewrite %cpucnt $cputype with frequency while (($cf,$cnt)=each(%cpucnt)) { $cf=~/^(.*) (\d+)$/; $tmp=$1; if (defined($tmp)) { delete $cpucnt{"$1 $2"} if ($2 == 0); } } if (defined($tmp)) { $cpucnt{"$tmp $cpufreq"}=$psrcpucnt; $ncpu=$psrcpucnt; } } # May have "psrinfo -p -v" output in regression test # file that has more detailed information about the # CPUs. Assumes all CPUs are same. $foundpsrinfocpu=1 if ($line =~ /.+ \d+ virtual processor/); if ($foundpsrinfocpu && (($line =~ /.+Hz$/ && $line !~ /Speed: / && $line !~ / PCI/) || $line =~ /\bAMD .* Processor /) && $line !~ / x86 /) { $cputype=&mychomp($line); $cputype=&cleanup_cputype($cputype); $cputype=~s/^Version:\s+//; $cputype=~s/^brand\s+//; $cputype=~s/^:brand-string\s+//; # rewrite %cpucnt $cputype with cputype while (($cf,$cnt)=each(%cpucnt)) { $cf=~/^(.*) (\d+)$/; $cpufreq=$2; delete $cpucnt{"$1 $2"}; } $cpucnt{"$cputype $cpufreq"}=$psrcpucnt; } } if ($filename && $filename !~ /Sun/ && $line =~ /^ *Manufacturer:/ && $manufacturer =~ /^Sun\b/ && $diagbanner !~ /^Sun\b|^Ultra/) { # Regression test file with smbios output $manufacturer=&mychomp($line); $manufacturer=~s/^.*Manufacturer: *//; $manufacturer=~s/\s*$//g; &pdebug("in check_prtdiag, smbios manufacturer=$manufacturer"); } } # Rewrite prtdiag output to include DIMM information on SB1X00, SB2X00, # Enchilada, Chalupa (Sun Fire V440), Netra T12, Seattle and Boston # systems @new_boards_mem=""; $grpcnt=0; $intcnt=0; if ($ultra =~ /Sun Blade [12][05]00\b/ || $ultra eq "Sun Fire 280R" || $ultra eq "Netra 20" || $ultra eq "Sun Fire V250" || $ultra eq "Netra T12") { foreach $line (@boards_mem) { $line=&mychomp($line); $newline=$line; if ($line eq "-----------------------------------------------------------" && ! $prtdiag_banktable_has_dimms) { $newline=$line . "------"; } elsif ($line eq "--------------------------------------------------") { $newline=$line . "-----------"; } elsif ($line =~ /ControllerID GroupID Size/ && ! $prtdiag_banktable_has_dimms) { $newline="ID ControllerID GroupID Size DIMMs Interleave Way"; } elsif ($line =~ /ControllerID GroupID Labels Status/) { $newline=$line . " DIMMs"; } elsif ($line =~ /ControllerID GroupID Labels/) { $newline=$line . " DIMMs"; } elsif ($line =~ /ControllerID GroupID Size Labels/) { $newline=$line . " DIMMs"; } elsif ($line =~ /^\d[\d ] \d[\d ] \d /) { &read_prtdiag_bank_table; } elsif ($line =~ /^0x\d[\d ]+\d.+ +\d +-$| GroupID \d[\d ]$/) { &read_prtdiag_memory_segment_table; } elsif ($line =~ /J0100,/) { $sz=$grpsize{0,0}; if (defined($sz)) { $sz=~s/ //g; $newline=$line . " 4x$sz"; } } elsif ($line =~ /J0101,/) { $sz=$grpsize{0,1}; if (defined($sz)) { $sz=~s/ //g; $newline=$line . " 4x$sz"; } } elsif ($line =~ /\/J0[1-4]0[0246]\b/) { $sz=$grpsize{0,0}; if (defined($sz)) { $sz=~s/ //g; $newline=$line . " $sz"; } } elsif ($line =~ /\/J0[1-4]0[1357]\b/) { $sz=$grpsize{0,1}; if (defined($sz)) { $sz=~s/ //g; $newline=$line . " $sz"; } } elsif ($line =~ /\bSB\d\/P\d\/B\d\/D\d,/) { $tmp=substr($line,0,2); $tmp=~s/ //g; $sz=$grpsize{$tmp,substr($line,15,1)}; $sz=$grpsize{0,substr($line,15,1)} if (! defined($sz)); if (defined($sz)) { $sz=~s/ //g; $newline=$line . " 4x$sz"; } } elsif ($line =~ /\bSB\d\/P\d\/B\d\/D\d\b/) { $tmp=substr($line,0,2); $tmp=~s/ //g; $sz=$grpsize{$tmp,substr($line,15,1)}; $sz=$grpsize{0,substr($line,15,1)} if (! defined($sz)); if (defined($sz)) { $sz=~s/ //g; $newline=$line . " $sz"; } } elsif ($line =~ / MB\/DIMM\d,/) { $sz=$grpsize{0,substr($line,15,1)}; $newline=$line . " 2x$sz" if (defined($sz)); } elsif ($line =~ /DIMM\d,DIMM\d/) { @linearr=split(' ', $line); if ($linearr[2] =~ /\d+[MG]B/) { $sz=$linearr[2]; if ($sz =~ /\dGB/) { $sz=~s/GB//g; $sz *= 512; } else { $sz=~s/MB//g; $sz /= 2; } $sz=&show_memory_label($sz); } $newline=$line . " 2x$sz" if (defined($sz)); if ($line =~ /DIMM[13],DIMM[24]/ && $ultra eq "Sun Blade 1500") { # prototype has sockets DIMM1-DIMM4 @socketstr=("DIMM1".."DIMM4"); } if ($line =~ /DIMM[1357],DIMM[2468]/ && $ultra eq "Sun Blade 2500") { # prototype has sockets DIMM1-DIMM8 if ($line =~ /DIMM[13],DIMM[24]/) { @socketstr=("DIMM1".."DIMM4"); } elsif ($line =~ /DIMM[57],DIMM[68]/) { push(@socketstr, "DIMM5".."DIMM8"); } } } push(@new_boards_mem, "$newline\n") if ($newline); } @boards_mem=@new_boards_mem; $memfrom="prtdiag"; } elsif ($ultra eq "Enchilada" || $ultra eq "Sun Fire V440" || $ultra eq "Netra 440" || $ultra =~ /Sun Ultra [24]5 .*Workstation/ || $ultra eq "Sun Fire V125" || $ultra eq "Seattle" || $ultra eq "Boston" || $banner =~ /Sun Fire E[24]900\b/ || $diagbanner =~ /Sun Fire E[24]900/) { foreach $line (@boards_mem) { $line=&mychomp($line); $newline=$line; if ($line eq "-----------------------------------------------------------" && ! $prtdiag_banktable_has_dimms) { $newline=$line . "------"; } elsif ($line eq "--------------------------------------------------") { $newline=$line . "-----------"; } elsif ($line =~ /ControllerID GroupID Size/ && ! $prtdiag_banktable_has_dimms) { $newline="ID ControllerID GroupID Size DIMMs Interleave Way"; } elsif ($line =~ /ControllerID GroupID Labels Status/) { $newline=$line . " DIMMs"; } elsif ($line =~ /ControllerID GroupID Labels/) { $newline=$line . " DIMMs"; } elsif ($line =~ /^\d[\d ] \d[\d ] \d /) { &read_prtdiag_bank_table; } elsif ($line =~ /^0x\d[\d ]+\d.+ +\d +-$| GroupID \d[\d ]$/) { &read_prtdiag_memory_segment_table; } elsif ($line =~ / MB\/P[01]\/B[01]\/D[01],|C[0-3]\/P[01]\/B[01]\/D[01],/) { $sz=$grpsize{substr($line,0,1),substr($line,15,1)}; $sz=$grpsize{0,substr($line,15,1)} if (! defined($sz)); if (defined($sz)) { $newline=$line . " 2x$sz"; } else { $newline=$line . " Failing"; $failing_memory=1; } } elsif ($line =~ / MB\/P[01]\/B[01]\/D[01]\b|C[0-3]\/P[01]\/B[01]\/D[01]\b/) { $sz=$grpsize{substr($line,0,1),substr($line,15,1)}; $sz=$grpsize{0,substr($line,15,1)} if (! defined($sz)); if (defined($sz)) { $sz=~s/ //g; $sz=&show_memory_label($sz); } $space=" "; $space="" if ($line =~ / okay/); if ($line =~ / failed/) { if (defined($sz)) { $failed_memory += $sz; } else { $failing_memory=1; } } if (defined($sz)) { # If interleave factor is 16, then print 4x$sz if (defined($grpinterleave{substr($line,28,1),0})) { if ($grpinterleave{substr($line,28,1),0} eq "0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15" && ! $prtdiag_banktable_has_dimms) { $newline=$line . "$space 4x$sz"; } else { $newline=$line . "$space $sz"; } } else { $newline=$line . "$space $sz"; } } } elsif ($line =~ / MB\/DIMM[0-7]\b/) { $sz=$grpsize{substr($line,0,1),substr($line,15,1)}; $sz=$grpsize{0,substr($line,15,1)} if (! defined($sz)); $newline=$line . " $sz" if (defined($sz)); } elsif ($line =~ /\bSB\d\/P\d\/B\d\/D\d,/) { $tmp=substr($line,0,2); $tmp=~s/ //g; $sz=$grpsize{$tmp,substr($line,15,1)}; $sz=$grpsize{0,substr($line,15,1)} if (! defined($sz)); if (defined($sz)) { $sz=~s/ //g; $newline=$line . " 4x$sz"; } } elsif ($line =~ /\bSB\d\/P\d\/B\d\/D\d\b/) { $tmp=substr($line,0,2); $tmp=~s/ //g; $sz=$grpsize{$tmp,substr($line,15,1)}; $sz=$grpsize{0,substr($line,15,1)} if (! defined($sz)); if (defined($sz)) { $sz=~s/ //g; $newline=$line . " $sz"; } } push(@new_boards_mem, "$newline\n") if ($newline); } @boards_mem=@new_boards_mem; $memfrom="prtdiag"; } # Rewrite prtdiag output to exclude redundant labels @new_boards_mem=""; $flag_group=0; foreach $line (@boards_mem) { $line=&mychomp($line); $newline=$line; $flag_group++ if ($line =~ /Memory Module Groups:/); if ($flag_group ge 2) { $newline="" if ($line =~ /Memory Module Groups:|--------------------------------------------------|ControllerID GroupID/); } push(@new_boards_mem, "$newline\n") if ($newline); } if ($machine eq "sun4v" && $cputype !~ /UltraSPARC-T1$/) { if ($prtpicl_cmd && ! $have_prtpicl_data) { # Warn that prtpicl may take a while to run &please_wait; @prtpicl=&run("$prtpicl_cmd -v"); $have_prtpicl_data=1; } &check_prtpicl if ($have_prtpicl_data); if ($picl_foundmemory) { @new_boards_mem=""; $memfrom="prtpicl"; $picl_bank_cnt=scalar(keys %picl_mem_bank); if (scalar(keys %picl_mem_dimm) == 1 || $picl_bank_cnt > 1) { while (($socket,$simmsize)=each(%picl_mem_bank)) { if (scalar(keys %picl_mem_pn) == $picl_bank_cnt * 2 || $interleave == 8) { # CH1 was not listed $simmsize /= 2; $picl_mem_dimm{"$socket"}=$simmsize; $socket=~s/CH0/CH1/g; $picl_mem_dimm{"$socket"}=$simmsize; &add_to_sockets_used($socket); } else { $picl_mem_dimm{"$socket"}=$simmsize; } } } while (($socket,$simmsize)=each(%picl_mem_dimm)) { $pn=$picl_mem_pn{"$socket"}; $sz=&show_memory_label($simmsize); $newline="socket $socket has a "; $newline .= $pn . " " if (defined($pn)); $newline .= $sz . " " if (defined($sz)); $newline .= "$memtype"; push(@new_boards_mem, "$newline\n"); push(@simmsizesfound, $simmsize) if (defined($sz)); } @new_boards_mem=sort alphanumerically @new_boards_mem; } elsif ($flag_rewrite_prtdiag_mem) { # Hack: Rewrite prtdiag output better than original if ($sockets_used =~ /MB\/CMP[0-3]\/BR[0-3]\/CH[01]\/D1/) { # All 16 DIMMs are installed @new_boards_mem=""; if ($sockets_used !~ /MB\/CMP[0-3]\/BR[0-3]\/CH1\/D[01]/) { foreach $line (@boards_mem) { $line=&mychomp($line); $newline=$line; if ($line =~ /MB\/CMP[0-3]\/BR[0-3]\/CH0\/D[01]/) { $line=~s/\s+$//; $tmp=$line; $tmp=~s/^.*(MB\/CMP.*)/$1/; $tmp=~s/CH0/CH1/g; $space=""; $space=" " if ($line =~ /^MB\/CMP/); $newline="$space$line,$tmp"; } push(@new_boards_mem, "$newline\n") if ($newline); } } $sockets_used=""; for ($cnt=0; $cnt <= $#socketstr; $cnt++) { $sockets_used .= " $socketstr[$cnt]"; } $simmsize=$installed_memory / 16; } else { # 8-DIMMs or 4-DIMMs are installed. # Hack: assume 4-DIMM configuration since # 8-DIMM has prtpicl output. @new_boards_mem=""; foreach $line (@boards_mem) { $line=&mychomp($line); $newline=$line; if ($line =~ /MB\/CMP[0-3]\/BR[0-3]\/CH0\/D[01]/) { $line=~s/\s+$//; $space=""; $space=" " if ($line =~ /^MB\/CMP/); $newline="$space$line"; } push(@new_boards_mem, "$newline\n") if ($newline); } $simmsize=$installed_memory / 4; } # Round up DIMM value $simmsize=&roundup_memory($simmsize); push(@simmsizesfound, $simmsize); } else { $tmp=0; foreach $socket (sort split(' ', $sockets_used)) { $tmp++; } if ($tmp) { # Round up DIMM value $simmsize=&roundup_memory($installed_memory / $tmp); push(@simmsizesfound, $simmsize); } } } @boards_mem=@new_boards_mem; # &pdebug("sockets_used=$sockets_used"); } sub prtdiag_threadcount { $arg=shift; # column with thread count $diagthreadcnt++; $tmp=$line; $tmp=~s/,\s+/,/; @linearr=split(' ', $tmp); $cputype=$linearr[4]; $cputype=~s/SUNW,U/U/; $cpufreq=$linearr[1+$arg]; if ($line =~ /\bUS-/) { $cputype=~s/US-/UltraSPARC-/; $cpufreq=$linearr[2]; } $cputype=~s/UltraSPARC-IV/Dual-Core UltraSPARC-IV/; $diagcpucnt{"$cputype $cpufreq"}++; if ($linearr[$arg] =~ /,/) { $tmp=$linearr[$arg]; @linearr=split(',', $tmp); $diagthreadcnt += $#linearr; } $cpucntfrom="prtdiag"; } sub check_prtpicl { &pdebug("in check_prtpicl"); $flag_mem_seg=0; $flag_mem_bank=0; $flag_mem_chan=0; $flag_mem_mod=0; $flag_physical_platform=0; $processorbrd=""; $cpumembrd=""; $mem_riser=""; $mem_cu=""; $picl_dimm_per_bank=0; $max_picl_dimm_per_bank=0; $has_picl_mem_mod=0; foreach $line (@prtpicl) { $line=&dos2unix($line); $line=&mychomp($line); $line=~s/\s+$//; if ($line =~ /^\s+:Label\s+PM[01]/) { # SPARC T3-4, T4-4 $processorbrd=$line; $processorbrd=~s/^.*:Label\s+(.*)$/$1/; } if ($line =~ /^\s+:Label\s+CM[0-3]/) { # SPARC T5-2, T5-4, T5-8, T5-1B $cpumembrd=$line; $cpumembrd=~s/^.*:Label\s+(.*)$/$1/; } if ($line =~ /^\s+:Label\s+(CPU[0-3]|MEM[0-3])/) { $cpumembrd=$line; $cpumembrd=~s/^.*:Label\s+(.*)$/$1\//; } if ($line =~ /^\s+:Label\s+CMP[0-3]/) { $cmp=$line; $cmp=~s/^.*:Label\s+(.*)$/$1/; } if ($line =~ /\s+:name\s+memory-module/) { $flag_mem_mod=0; # End of memory module section &add_to_sockets_used($mem_dimm); } if (($line =~ /^\s+\w.*/ && $line !~ /^\s+memory-/ && $has_picl_mem_mod) || ($line =~ /\s+:name\s/ && ! $has_picl_mem_mod)) { $flag_mem_seg=0; $max_picl_dimm_per_bank=$picl_dimm_per_bank if ($picl_dimm_per_bank); if ($flag_mem_mod && $mem_dimm !~ /\//) { if ($ultra eq "S7-2" || $ultra eq "S7-2L") { # SPARC S7-2, S7-2L (guess) $socket="/SYS/MB/$cpumembrd$cmp/$mem_cu/$mem_channel/$mem_dimm"; } elsif ($ultra =~ /T5-(2|1B)/) { # SPARC T5-2, T5-1B (guess) $socket="/SYS/MB/$cpumembrd/CMP/$mem_branch/$mem_channel/$mem_dimm"; } elsif ($ultra =~ /T5-(4|8)/) { # SPARC T5-4, T5-8 (guess) $socket="/SYS/$processorbrd/$cpumembrd/CMP/$mem_branch/$mem_channel/$mem_dimm"; } elsif ($processorbrd) { # SPARC T3-4, T4-4 $socket="/SYS/$processorbrd/$cpumembrd$cmp/$mem_branch/$mem_channel/$mem_dimm"; } else { $socket="MB/$cpumembrd$cmp/$mem_branch/$mem_channel/$mem_dimm"; } $flag_mem_mod=0; # End of memory module section &add_to_sockets_used($socket); if (defined($mem_model) && defined($mem_mfg)) { $picl_mem_pn{"$socket"}="$mem_mfg $mem_model"; } elsif (defined($mem_mfg)) { $picl_mem_pn{"$socket"}="$mem_mfg"; } if ($max_picl_dimm_per_bank) { $picl_mem_dimm{"$socket"}=$picl_bank_size / $max_picl_dimm_per_bank; push(@simmsizesfound, "$picl_mem_dimm{\"$socket\"}"); } elsif ($sockets_used =~ /\/CH1\//) { $picl_mem_dimm{"$socket"}+=$picl_bank_size / 2; } else { $picl_mem_dimm{"$socket"}+=$picl_bank_size; } } elsif ($flag_mem_bank) { $socket="$bank_nac" if ($bank_nac); $flag_mem_bank=0; # End of memory bank section $bank_nac=""; if ($socket) { &add_to_sockets_used($socket); $picl_mem_bank{"$socket"}=$picl_bank_size; } } } if ($line =~ /^\s+memory-segment\s/) { $flag_mem_seg=1; # Start of memory segment section } if ($flag_mem_seg) { if ($line =~ /^\s+:InterleaveFactor\s/) { $interleave=$line; $interleave=~s/^.*:InterleaveFactor\s+(.*)$/$1/; $interleave=hex($interleave) if ($interleave =~ /^0x\d/); } if ($line =~ /^\s+:Size\s/) { $segment_size=$line; $segment_size=~s/^.*:Size\s+(.*)$/$1/; if ($segment_size =~ /^0x\d/) { $segment_size=~s/^(.*)00000$/$1/; $segment_size=hex($segment_size); } else { $segment_size /= $meg; } } } if ($line =~ /^\s+memory-bank\s/) { $flag_mem_bank=1; # Start of memory bank section $picl_dimm_per_bank=0; } if ($flag_mem_bank) { if ($line =~ /^\s+:Label\s/) { $bank_label=$line; $bank_label=~s/^.*:Label\s+(.*)$/$1/; } if ($line =~ /^\s+:nac\s/) { $bank_nac=$line; $bank_nac=~s/^.*:nac\s+(.*)\s*$/$1/; } if ($line =~ /^\s+:Size\s/) { $picl_bank_size=$line; $picl_bank_size=~s/^.*:Size\s+(.*)$/$1/; if ($picl_bank_size =~ /^0x\d/) { $picl_bank_size=~s/^(.*)00000$/$1/; $picl_bank_size=hex($picl_bank_size); } else { $picl_bank_size=$segment_size / $meg; } } } if ($line =~ /^\s+memory-module\s/) { $flag_mem_mod=1; # Start of memory module section $has_picl_mem_mod=1; } if ($flag_mem_mod) { if ($line =~ /^\s+:nac\s/) { $mem_dimm=$line; $mem_dimm=~s/^.*:nac\s+(.*)\s*$/$1/; $picl_dimm_per_bank++; } } if ($line =~ /^\s+MR\d\s/) { $mem_riser=$line; $mem_riser=~s/^.*(MR\d).*/$1/; } if ($line =~ /^\s+MCU\d\s/) { $mem_cu=$line; $mem_cu=~s/^.*(MCU\d).*/$1/; } if ($line =~ /^\s+(BR|BOB)\d\s/) { $flag_mem_chan=0; $mem_branch=$line; $mem_branch=~s/^.*(BR\d).*/$1/; $mem_branch=~s/^.*(BOB\d).*/$1/; # SPARC T3-2, T4-2 $mem_branch=$mem_riser . "/" . $mem_branch if ($mem_riser); } if ($line =~ /^\s+CH\d\s/) { $flag_mem_chan=1; # Start of memory channel section $mem_channel=$line; $mem_channel=~s/^.*(CH\d).*/$1/; } if ($flag_mem_chan && $line =~ /^\s+D\d\s/) { $flag_mem_mod=1; # Start of memory module section $picl_foundmemory=1; $mem_dimm=$line; $mem_dimm=~s/^.*(D\d).*/$1/; } if ($flag_mem_mod) { if ($line =~ /\s+:ModelName\s/) { $mem_model=$line; $mem_model=~s/^.*:ModelName\s+(.*)$/$1/; } if ($line =~ /\s+:MfgName\s/) { $mem_mfg=$line; $mem_mfg=~s/^.*:MfgName\s+(.*)$/$1/; } } if ($line =~ /\s+:name\s+physical-platform/) { $flag_physical_platform=1; } elsif ($line =~ /\s+:name\s+SYS/) { $flag_physical_platform=0; } if ($flag_physical_platform) { if ($line =~ /\s+:MfgName\s/) { $manufacturer=$line; $manufacturer=~s/^.*:MfgName\s+(.*)$/$1/; } } } } sub check_prtfru { &pdebug("in check_prtfru"); if ($prtfru_cmd && ! $have_prtfru_data) { # Warn that prtfru may take a while to run &please_wait; @prtfru=&run("$prtfru_cmd -x"); $have_prtfru_data=1; } $flag_mem_mod=0; $cpu_mem_slot=""; $mem_slot=""; $mem_desc=""; $mem_mfg=""; $mem_mfg_loc=""; $mem_pn=""; $sun_pn=""; $fru_details=""; $fru_sb=""; $fru_cpu=""; $fru_bank=""; $fru_dimm=""; $prevline=""; foreach $line (@prtfru) { $line=&dos2unix($line); $line=&mychomp($line); $line=~s/\s+$//; if ($line =~ //) { $fru_sb=$prevline; $fru_sb=~s/^.*Label=(.*)\s*\".*/$1/; &pdebug("in check_prtfru, found fru_sb=$fru_sb"); } if ($line =~ //) { $flag_mem_mod=0; # End of memory module section if ($mem_slot) { if ($mem_desc) { $have_prtfru_details=1; $fru_details .= "$cpu_mem_slot " if ($cpu_mem_slot); $fru_details .= "$mem_slot: $mem_desc"; $fru_details .= ", Sun $sun_pn" if ($sun_pn); if ($mem_mfg && $mem_pn) { $fru_details .= ", $mem_mfg $mem_pn"; } else { $fru_details .= ", $mem_mfg" if ($mem_mfg); $fru_details .= ", $mem_pn" if ($mem_pn); } $fru_details .= "\n"; } else { $missing_prtfru_details .= "${cpu_mem_slot}_" if ($cpu_mem_slot); $missing_prtfru_details .= "$mem_slot "; } } $mem_slot=""; $mem_desc=""; $mem_mfg=""; $mem_mfg_loc=""; $mem_pn=""; $sun_pn=""; $fru_dimm=""; } if ($flag_mem_mod) { if ($line =~ /(DIMM_Capacity|Fru_Description) value=/) { $mem_desc=$line; $mem_desc=~s/^.*\"(.*)\s*\".*$/$1/; } if ($line =~ /(Fundamental_Memory_Type|DIMM_Config_Type) value=/) { $tmp=$line; $tmp=~s/^.*\"(.*)\s*\".*$/$1/; if ($mem_desc) { $mem_desc .= " $tmp"; } else { $mem_desc="$tmp"; } } if ($line =~ /Manufacture_Loc value=/ && ! $mem_mfg_loc) { $mem_mfg_loc=$line; if ($mem_mfg_loc =~ /\".*\"/) { $mem_mfg_loc=~s/^.*\"(.*)\s*\".*$/$1/; } else { $mem_mfg_loc=~s/^.*\"(.*)\s*$/$1/; } } if ($line =~ /Vendor_Name value=/ && ! $mem_mfg) { $mem_mfg=$line; if ($mem_mfg =~ /\".*\"/) { $mem_mfg=~s/^.*\"(.*)\s*\".*$/$1/; } else { $mem_mfg=~s/^.*\"(.*)\s*$/$1/; } $mem_mfg=&get_mfg($mem_mfg); # Fix some unrecognized manufacturers if ($mem_mfg =~ /(unrecognized value|UNKNOWN Invalid Value)/i) { if ($mem_mfg =~ /[0\b]4400\b/ || $mem_mfg_loc =~ /Boise.*Idaho/i) { $mem_mfg="Micron Technology"; } elsif ($mem_mfg =~ /[0\b]7800\b/ || $mem_mfg_loc =~ /Onyang.*Korea/i) { $mem_mfg="Samsung"; } elsif ($mem_mfg =~ /[0\b]0551\b/ || $mem_mfg_loc =~ /\bQMY\b/) { $mem_mfg="Qimonda"; } else { # unrecognized manufacturer $recognized=-3; $exitstatus=1; } } } if ($line =~ /Manufacturer_Part_No value=/ && ! $mem_pn) { $mem_pn=$line; $mem_pn=~s/^.*\"(.*)\s*\".*$/$1/; } if ($line =~ /Sun_Part_No value=/ && ! $sun_pn) { $sun_pn=$line; $sun_pn=~s/^.*\"(.*)\s*\".*$/$1/; $sun_pn=~s/^(\d\d\d)(\d\d\d\d)$/$1-$2/; } # This data is not always accurate, so ignore it # if ($line =~ /Fru_Type value=/ && ! $mem_desc) { # $mem_desc=$line; # $mem_desc=~s/^.*\"(.*)\s*\".*$/$1/; # } } $prevline=$line; } } sub multicore_cputype { $s=shift; $tmp=shift; return if (! defined($s) || ! defined($tmp)); $s="Hyper-Threaded $s" if ($hyperthread && $s !~ /Hyper.Thread/i); if ($tmp == 2) { $s="Dual-Core $s" if ($s !~ /(Dual|Two).Core/i); } elsif ($tmp == 3) { $s="Triple-Core $s" if ($s !~ /(Triple|Three).Core/i); } elsif ($tmp == 4) { $s="Quad-Core $s" if ($s !~ /(Quad|Four).Core/i); } elsif ($tmp == 6) { $s="Six-Core $s" if ($s !~ /(Hex|Six).Core/i); } elsif ($tmp == 8) { $s="Eight-Core $s" if ($s !~ /(Octal|Eight).Core/i); } elsif ($tmp == 10) { $s="Ten-Core $s" if ($s !~ /Ten.Core/i); } elsif ($tmp == 12) { $s="Twelve-Core $s" if ($s !~ /Twelve.Core/i); } elsif ($tmp > 1) { $s="${tmp}-Core $s" if ($s !~ /${tmp}.Core/i); } $s=~s/ Core/-Core/ if ($s =~ /(Dual|Two|Triple|Three|Quad|Four|Hex|Six|Octal|Eight|Ten|Twelve|[0-9]) Core/i); return($s); } sub cleanup_cputype { $_=shift; return "" if (! defined($_)); s/ CPU//; s/ [Pp]rocessor//; s/ +MHz/MHz/; s/ (\d[\d\.]*GHz) \d*MHz/ $1/; s/\s+/ /g; s/^\s+//; s/\s+$//; s/\(r\)/\(R\)/g; s/\(tm\)/\(TM\)/g; s/ Core/-Core/ if (/(Dual|Two|Triple|Three|Quad|Four|Hex|Six|Octal|Eight|Ten|Twelve|[0-9]) Core/i); return($_); } sub multicore_cpu_cnt { $arg=shift; &check_psrinfo; &pdebug("in multicore_cpu_cnt, cputype=$cputype, threadcnt=$threadcnt"); if ($cputype =~ /UltraSPARC-T1$/) { $cputype="UltraSPARC-T1"; # Count 4-Thread (4, 6, or 8 Core) Niagara CPUs as 1 CPU if ($npcpu && $ldm_cmd && ! $have_ldm_data) { $ncpu=$npcpu; } else { # Each CPU has 8 Cores max (32 threads) $ncpu=int(($threadcnt - 1) / 32) + 1; } if (defined($arg)) { $cnt=$ncpu; return; } if ($threadcnt) { $cputype=$threadcnt / 4 / $ncpu . "-Core Quad-Thread $cputype"; $cpucnt{"$cputype $cpufreq"}=$ncpu; } } elsif ($cputype =~ /UltraSPARC-T2\+/) { $cputype="UltraSPARC-T2+"; # Count 8-Thread (4, 6, or 8 Core) Victoria Falls CPUs as 1 CPU if ($npcpu && $ldm_cmd && ! $have_ldm_data) { $ncpu=$npcpu; } else { # Assume there are no single-cpu systems with the US-T2+ $ncpu=2; # Valid configurations: # T5140,T5240: 2 x 4-Core (64 threads), 2 x 6-Core # (96 threads), 2 x 8-Core (128 threads) # T5440: 4 x 4-Core (128 threads), 4 x 8-Core # (256 threads) # Netra-T5440: 2 x 8-Core (128 threads) if ($ultra eq "T5140" || $ultra eq "T5240") { $ncpu=2; } elsif ($ultra eq "T5440") { $ncpu=4; $ncpu=2 if ($model =~ /Netra-T5440/); } } if (defined($arg)) { $cnt=$ncpu; return; } if ($threadcnt) { $cputype=$threadcnt / 8 / $ncpu . "-Core 8-Thread $cputype"; $cpucnt{"$cputype $cpufreq"}=$ncpu; } } elsif ($cputype =~ /UltraSPARC-T2$/) { $cputype="UltraSPARC-T2"; # Count 8-Thread (4 or 8 Core) Niagara-II CPUs as 1 CPU if ($npcpu && $ldm_cmd && ! $have_ldm_data) { $ncpu=$npcpu; } else { # Each CPU has 8 Cores max (64 threads) $ncpu=int(($threadcnt - 1) / 64) + 1; } if (defined($arg)) { $cnt=$ncpu; return; } if ($threadcnt) { $cputype=$threadcnt / 8 / $ncpu . "-Core 8-Thread $cputype"; $cpucnt{"$cputype $cpufreq"}=$ncpu; } } elsif ($cputype =~ /SPARC-T3$/) { $cputype="SPARC-T3"; # Count 8-Thread (8 or 16 Core) Rainbow Falls CPUs as 1 CPU if ($npcpu && $ldm_cmd && ! $have_ldm_data) { $ncpu=$npcpu; } else { # Each CPU has 16 Cores max (128 threads) $ncpu=int(($threadcnt - 1) / 128) + 1; } if (defined($arg)) { $cnt=$ncpu; return; } if ($threadcnt) { $cputype=$threadcnt / 8 / $ncpu . "-Core 8-Thread $cputype"; $cpucnt{"$cputype $cpufreq"}=$ncpu; } } elsif ($cputype =~ /SPARC-T4$/) { $cputype="SPARC-T4"; # Count 8-Thread 8-Core SPARC-T4 CPUs as 1 CPU if ($npcpu && $ldm_cmd && ! $have_ldm_data) { $ncpu=$npcpu; } else { # Each CPU has 8 Cores max (64 threads) $ncpu=int(($threadcnt - 1) / 64) + 1; } if (defined($arg)) { $cnt=$ncpu; return; } if ($threadcnt) { $cputype=$threadcnt / 8 / $ncpu . "-Core 8-Thread $cputype"; $cpucnt{"$cputype $cpufreq"}=$ncpu; } } elsif ($cputype =~ /SPARC-T5$/) { $cputype="SPARC-T5"; # Count 8-Thread 16-Core SPARC-T5 CPUs as 1 CPU if ($npcpu && $ldm_cmd && ! $have_ldm_data) { $ncpu=$npcpu; } else { # Each CPU has 16 Cores max (128 threads) $ncpu=int(($threadcnt - 1) / 128) + 1; } if (defined($arg)) { $cnt=$ncpu; return; } if ($threadcnt) { $cputype=$threadcnt / 8 / $ncpu . "-Core 8-Thread $cputype"; $cpucnt{"$cputype $cpufreq"}=$ncpu; } } elsif ($cputype =~ /SPARC.M5$/) { $cputype="SPARC-M5"; # Count 8-Thread 6-Core SPARC-M5 CPUs as 1 CPU if ($npcpu && $ldm_cmd && ! $have_ldm_data) { $ncpu=$npcpu; } else { # Each CPU has 6 Cores max (48 threads) $ncpu=int(($threadcnt - 1) / 48) + 1; } if (defined($arg)) { $cnt=$ncpu; return; } if ($threadcnt) { $cputype=$threadcnt / 8 / $ncpu . "-Core 8-Thread $cputype"; $cpucnt{"$cputype $cpufreq"}=$ncpu; } } elsif ($cputype =~ /SPARC.M6$/) { $cputype="SPARC-M6"; # Count 8-Thread 12-Core SPARC-M6 CPUs as 1 CPU if ($npcpu && $ldm_cmd && ! $have_ldm_data) { $ncpu=$npcpu; } else { # Each CPU has 12 Cores max (96 threads) $ncpu=int(($threadcnt - 1) / 96) + 1; } if (defined($arg)) { $cnt=$ncpu; return; } if ($threadcnt) { $cputype=$threadcnt / 8 / $ncpu . "-Core 8-Thread $cputype"; $cpucnt{"$cputype $cpufreq"}=$ncpu; } } elsif ($cputype =~ /SPARC.S7$/) { $cputype="SPARC-S7"; # Count 8-Thread 8-Core SPARC-S7 CPUs as 1 CPU if ($npcpu && $ldm_cmd && ! $have_ldm_data) { $ncpu=$npcpu; } else { # Each CPU has 8 Cores max (64 threads) $ncpu=int(($threadcnt - 1) / 64) + 1; } if (defined($arg)) { $cnt=$ncpu; return; } if ($threadcnt) { $cputype=$threadcnt / 8 / $ncpu . "-Core 8-Thread $cputype"; $cpucnt{"$cputype $cpufreq"}=$ncpu; } } elsif ($cputype =~ /SPARC.M7$/) { $cputype="SPARC-M7"; # Count 8-Thread 32-Core SPARC-M7 CPUs as 1 CPU if ($npcpu && $ldm_cmd && ! $have_ldm_data) { $ncpu=$npcpu; } else { # Each CPU has 32 Cores max (256 threads) $ncpu=int(($threadcnt - 1) / 256) + 1; } if (defined($arg)) { $cnt=$ncpu; return; } if ($threadcnt) { $cputype=$threadcnt / 8 / $ncpu . "-Core 8-Thread $cputype"; $cpucnt{"$cputype $cpufreq"}=$ncpu; } } elsif ($cputype =~ /SPARC64-VI$/) { # Count Dual-Core Dual-Thread Olympus-C SPARC64-VI CPUs as 1 CPU $ncpu=$threadcnt / 4; $cputype="Dual-Core Dual-Thread SPARC64-VI"; if (defined($arg)) { $cnt=$ncpu; return; } $cpucnt{"$cputype $cpufreq"}=$ncpu; } elsif ($cputype =~ /SPARC64-VII\+\+$/) { # Count Quad-Core Dual-Thread Jupiter++ SPARC64-VII++ CPUs as 1 CPU $ncpu=$threadcnt / 8; $cputype="Quad-Core Dual-Thread SPARC64-VII++"; if (defined($arg)) { $cnt=$ncpu; return; } $cpucnt{"$cputype $cpufreq"}=$ncpu; } elsif ($cputype =~ /SPARC64-VII\+$/) { # Count Quad-Core Dual-Thread Jupiter+ SPARC64-VII+ CPUs as 1 CPU $ncpu=$threadcnt / 8; $cputype="Quad-Core Dual-Thread SPARC64-VII+"; if (defined($arg)) { $cnt=$ncpu; return; } $cpucnt{"$cputype $cpufreq"}=$ncpu; } elsif ($cputype =~ /SPARC64-VII$/) { # Count Quad-Core Dual-Thread Jupiter SPARC64-VII CPUs as 1 CPU $ncpu=$threadcnt / 8; $cputype="Quad-Core Dual-Thread SPARC64-VII"; if (defined($arg)) { $cnt=$ncpu; return; } $cpucnt{"$cputype $cpufreq"}=$ncpu; } elsif ($cputype =~ /SPARC64-VIII$/) { # Guess on the Venus SPARC64-VIII name ??? # Count 8-Core Dual-Thread Venus SPARC64-VIII CPUs as 1 CPU $ncpu=$threadcnt / 16; $cputype="8-Core Dual-Thread SPARC64-VIII"; if (defined($arg)) { $cnt=$ncpu; return; } $cpucnt{"$cputype $cpufreq"}=$ncpu; } elsif ($cputype =~ /SPARC64-X$/) { # Count 16-Core Dual-Thread SPARC64-X CPUs as 1 CPU $ncpu=$threadcnt / 32; $cputype="16-Core Dual-Thread SPARC64-X"; if (defined($arg)) { $cnt=$ncpu; return; } $cpucnt{"$cputype $cpufreq"}=$ncpu; } } sub x86multicorecnt { $_=shift; return if (! defined($_)); $corecnt=2 if (/\b(Dual|Two).Core/i); $corecnt=3 if (/\b(Triple|Three).Core/i); $corecnt=4 if (/\b(Quad|Four).Core/i); $corecnt=6 if (/\b(Hex|Six).Core/i); $corecnt=8 if (/\b(Octal|Eight).Core/i); $corecnt=10 if (/\bTen.Core/i); $corecnt=12 if (/\bTwelve.Core/i); } sub checkX86 { $isX86=1 if ($model eq "i86pc" || $machine eq "i86pc" || $model eq "i86xpv" || $machine eq "i86xpv" || $model eq "i86xen" || $machine eq "i86xen"); # Use CPU count from prtdiag (ndcpu) and thread count from psrinfo to # get core count per cpu for i86xpv/i86xen $use_psrinfo_data=2 if ($model eq "i86xpv" || $machine eq "i86xpv" || $model eq "i86xen" || $machine eq "i86xen"); } sub check_psrinfo { return if ($psrinfo_checked); &pdebug("in check_psrinfo, ndcpu=$ndcpu, npcpu=$npcpu, nvcpu=$nvcpu"); $psrinfo_checked=1; return if ($nvcpu || ! $use_psrinfo_data); if ($filename) { $npcpu=0; $j=0; $have_npcpu=0; foreach $line (@psrinfo) { $line=&dos2unix($line); # May have "psrinfo -p" output in regression test file # that has number of physical CPUs. if ($line =~ /^#.*psrinfo -p$/ && $psrinfo[$j + 1] =~ /^\d+$/) { $npcpu=&mychomp($psrinfo[$j + 1]); $have_npcpu=1; &pdebug("in check_psrinfo, found npcpu=$npcpu"); } # May have "psrinfo -p -v" output in regression test # file that has number of virtual CPUs. Assumes all # CPUs are same. if ($line =~ /^The .+ \d+ virtual processor/) { &check_psrinfo_pv; if ($use_psrinfo_data == 2 && $ndcpu > 1) { $corecnt /= $ndcpu; $npcpu=$ndcpu if (! $have_npcpu); } else { $npcpu++ if (! $have_npcpu); } $cpucntfrom="psrinfo" if ($cpucntfrom ne "ldm"); $cpucntflag="0"; # reset flag &pdebug("in check_psrinfo, found nvcpu=$nvcpu, corecnt=$corecnt, npcpu=$npcpu, hyperthread=$hyperthread"); } $j++; } } elsif ($psrinfo_cmd) { $ncpu=&mychomp(`$psrinfo_cmd | wc -l`); # physical & virtual CPUs $ncpu=~s/\s+//; $npcpu=&mychomp(`$psrinfo_cmd -p 2>/dev/null`); # physical CPUs if ($npcpu) { # Find number of virtual CPUs @tmp=`$psrinfo_cmd -p -v`; foreach $line (@tmp) { $line=&dos2unix($line); if ($line =~ /^The .+ \d+ virtual processor/) { &check_psrinfo_pv; if ($use_psrinfo_data == 2 && $ndcpu > 1) { $corecnt /= $ndcpu; $npcpu=$ndcpu; } } } if ($cputype eq "x86") { if ($tmp[2] =~ /.+Hz|\bAMD .* Processor /) { $cputype_psrinfo=&cleanup_cputype(&mychomp($tmp[2])); } } } else { $npcpu=$ncpu; $nvcpu=1; } @tmp=`$psrinfo_cmd -v`; if ($tmp[2] =~ /MHz/) { $cpufreq=&mychomp($tmp[2]); $cpufreq=~s/.+ operates at //; $cpufreq=~s/ MHz.+//; } $cpucntfrom="psrinfo" if ($cpucntfrom ne "ldm"); $have_psrinfo_data=1; } } sub check_psrinfo_pv { $nvcpu=&mychomp($line); $nvcpu=~s/.+ processor has //; $nvcpu=~s/ virtual processor.+//; if ($nvcpu =~ / cores and /) { $nvcpu=~s/cores and //; $corecnt=$nvcpu; $corecnt=~s/ \d+$//; $nvcpu=~s/^\d+ //; if ($nvcpu == 2 * $corecnt && $isX86) { $hyperthread=1; &pdebug("hyperthread=1: from psrinfo -p -v"); } } else { $corecnt=$nvcpu if ($nvcpu >= 2); $corecnt /= 2 if ($hyperthread); } } sub get_mfg { $_=shift; return "" if (! defined($_)); s/Manufacturer: *//ig; $has_JEDEC_ID=0; if (/JEDEC ID:/) { s/JEDEC ID://g; s/ //g; $has_JEDEC_ID=1; } s/^\s+//; s/\s+$//; s/^0x//; &pdebug("in get_mfg, JEDEC_ID=$_"); return "" if (/(^$|^\r$|^FFFFFFFFFFFF|^000000000000|^Undefined|Manufacturer\d)/i); s/^(00|80)// if (! /^007F/); # Based on JEDEC JEP106AT return "Micron Technology" if (/(^2C|Micron\b)/i); return "Micron CMS" if (/(^7F45|Micron CMS)/i); return "Crucial Technology" if (/(^1315$|^859B|^9B|^7F7F7F7F7F9B|Crucial\b)/i); # Inotera was a Joint Venture between Micron and Nanya # Micron fully acquired Inotera in 2016 return "Inotera Memories" if (/Inotera/i); # Micron acquired Elpida in August 2013 return "Elpida" if (/(^0500|^FE|^7F7FFE|^02FE|Elpida)/i); # Micron acquired Numonyx in February 2010 return "Numonyx (Intel)" if (/(^89|Intel)/i); return "Numonyx" if (/Numonyx/i); return "Fujitsu" if (/(^04|Fujitsu)/i); return "Hitachi" if (/(^07|Hitachi)/i); return "Inmos" if (/(^08|Inmos)/i); return "Intersil" if (/(^0B|Intersil)/i); return "Mostek" if (/(^0D|Mostek)/i); return "Freescale (Motorola)" if (/(^0E|Motorola)/i); return "Freescale" if (/Freescale/i); return "NEC" if (/^10/); return "Conexant (Rockwell)" if (/(^13|Rockwell)/i); return "Conexant" if (/Conexant/i); return "NXP (Philips Semi, Signetics)" if (/(^15|Philips Semi|Signetics)/i); return "Synertek" if (/(^16|Synertek)/i); return "Xicor" if (/(^19|Xicor)/i); return "Zilog" if (/(^1A|Zilog)/i); return "Mitsubishi" if (/(^1C|Mitsubishi)/i); return "ProMOS/Mosel Vitelic" if (/(^40|ProMOS|Mosel Vitelic)/i); return "Qimonda" if (/(^51|^8551|Qimonda)/i); return "Wintec Industries" if (/(^61|Wintec\b)/i); return "Goldenram" if (/(^6A|Goldenram)/i); return "Fairchild" if (/(^83|Fairchild)/i); return "GTE" if (/(^85|GTE)/i); return "DATARAM" if (/^91|^7F91/); return "Smart Modular" if (/^94|^0194|Smart Modular/i); return "Toshiba" if (/(^98|Toshiba)/i); return "Corsair" if (/(^9E|Corsair)/i); return "IBM" if (/^A4/i); return "Hynix Semiconductor (Hyundai Electronics)" if (/(^AD|Hyundai)/i); return "Hynix Semiconductor" if (/(HYN|Hynix)/i); return "Infineon (Siemens)" if (/(^C1|^7F7F7F7F7F51|Siemens)/i); return "Infineon" if (/Infineon/i); return "Samsung" if (/(^CE|Samsung)/i); return "Winbond Electronics" if (/(^DE|Winbond)/i); return "LG Semiconductor (Goldstar)" if (/(^E0|Goldstar)/i); return "LG Semiconductor" if (/LG Semi/i); return "Kingston" if (/(^7F98|^0198|Kingston)/i); return "SpecTek Incorporated" if (/(^7F7FB5|SpecTek)/i); return "Nanya Technology" if (/(^7F7F7F0B|^830B|Nanya)/i); return "Kingmax Semiconductor" if (/(^7F7F7F25|KINGMAX)/i); return "Ramaxel Technology" if (/(^7F7F7F7F43|Ramaxel)/i); return "A-DATA Technology" if (/(^7F7F7F7FCB|ADATA|A-DATA)/i); return "Team Group Inc." if (/^(7F7F7F7FEF|Team\b)/i); return "AMD" if (/^01/); return "AMI" if (/^02/); if ($has_JEDEC_ID || /^7F|^80|^FF/i) { $unknown_JEDEC_ID=1; &pdebug("in get_mfg, found unknown JEDEC ID $_"); } return &mychomp($_); } # See if CPUs and memory modules are listed in "ipmitool fru" output sub check_ipmitool { &pdebug("in check_ipmitool"); return if (! $ipmitool_cmd && ! $filename); $cputype2=""; $mem_mfg=""; $mem_model=""; $mem_pn=""; $flag_cpu=0; $flag_mem=0; $flag_mfg=0; $socket=""; foreach $line (@ipmitool) { $line=&dos2unix($line); $line=&mychomp($line); if ($line =~ /^ *$/) { # store cpu and memory modules in hash if ($flag_cpu) { if ($cputype2) { $cputype2=~s/DUAL.CORE/Dual-Core/; $cputype2=~s/TRIPLE.CORE/Triple-Core/; $cputype2=~s/QUAD.CORE/Quad-Core/; $cputype2=~s/SIX.CORE/Six-Core/; $cputype2=~s/EIGHT.CORE/Eight-Core/; $cputype2=~s/TEN.CORE/Ten-Core/; $cputype2=~s/TWELVE.CORE/Twelve-Core/; $cputype2=~s/ Core/-Core/; $cputype2=~s/OPTERON\(TM\) PROCESSOR/Opteron\(TM\)/; $ipmi_cputype="$cputype2"; $ipmi_cpucnt++; } } if ($flag_mem && $socket) { $ipmi_mem{"$socket"}=("$mem_mfg$mem_model$mem_pn") ? "$mem_mfg $mem_model$mem_pn" : ""; } $flag_cpu=0; # End of CPU section $flag_mem=0; # End of memory section $flag_mfg=0; # End of mfg section $cputype2=""; $mem_mfg=""; $mem_model=""; $mem_pn=""; } if ($line =~ / (cpu\d+\.vpd|p\d+\.fru )/) { $flag_cpu=1; # Start of CPU section $socket=$line; $socket=~s/^.*: +(.*\S)\.[vf][pr][du].*$/$1/; } if ($flag_cpu && $line =~ / Product Name /) { $cputype2=$line; $cputype2=~s/^.*: +(.*\S) *$/$1/; &x86multicorecnt($cputype2); } if ($line =~ / (cpu\d+\.mem\d+\.vpd|p\d+\.d\d+\.fru) /) { $flag_mem=1; # Start of memory module section $socket=$line; $socket=~s/^.*: +(.*\S)\.[vf][pr][du].*$/$1/; } elsif ($line =~ / P\d+C\d+\/B\d+\/C\d+\/D\d+ / && $ultra =~ /^T7-/) { # Need what M7-8 and M7-16 format looks like $flag_mem=1; # Start of memory module section $socket=$line; $socket=~s/^.*: +(.*\S)\s*.*$/$1/; } if ($flag_mem && $line =~ / Device not present /) { # Ignore missing Processor Modules $flag_mem=0 if ($ultra eq "T7-4" && $corecnt == 2 && $socket =~ /P1C\d+\/B\d+\/C\d+\/D\d+/); # Need what M7-8 and M7-16 format looks like } if ($flag_mem && $line =~ / Product Manufacturer /) { $mem_mfg=$line; $mem_mfg=~s/^.*: +(.*\S) *$/$1/; $mem_mfg=&get_mfg($mem_mfg); } if ($flag_mem && $line =~ / Product Name /) { $mem_model=$line; $mem_model=~s/^.*: +(.*\S) *$/$1/; $mem_model=~s/ ADDRESS\/COMMAND//; $mem_model=~s/PARITY/Parity/; } if ($flag_mem && $line =~ / Product Part Number /) { $mem_pn=$line; $mem_pn=~s/^.*: +(.*\S) *$/, $1/; $mem_pn=~s/^, .*,(.*\S)$/, $1/; } if ($line =~ /FRU Device Description *: *\/*SYS /) { $flag_mfg=1; # Start of mfg section } if ($flag_mfg && $line =~ / Product Manufacturer /) { $manufacturer="Sun Microsystems, Inc." if ($line =~ /Sun /i); $manufacturer="Oracle Corporation" if ($line =~ /Oracle/i); } } # Is ipmitool CPU count better? # &pdebug("ipmi_cpucnt=$ipmi_cpucnt"); if ($ncpu != $ipmi_cpucnt && $npcpu == 0 && $ipmi_cpucnt != 0) { $ncpu=$ipmi_cpucnt; $npcpu=$ipmi_cpucnt; $cpucntfrom="ipmitool"; $cpucnt{"$cputype $cpufreq"}=$ipmi_cpucnt; } # Did ipmitool find a better cputype? if (&lc($cputype) ne &lc($ipmi_cputype) && $ipmi_cputype) { # rewrite %cpucnt $cputype with cputype while (($cf,$cnt)=each(%cpucnt)) { $cf=~/^(.*) (\d+)$/; $cpufreq=$2; delete $cpucnt{"$1 $2"}; } $cpucnt{"$ipmi_cputype $cpufreq"}=$ipmi_cpucnt; } } # Check for logical domains sub check_for_LDOM { &pdebug("in check_for_LDOM"); $kernbit=64 if (! $kernbit && $machine eq "sun4v"); # Handle control LDOM on UltraSPARC-T1 and later systems if ($ldm_cmd && ! $have_ldm_data) { @ldm=&run("$ldm_cmd list-devices -a -p"); $have_ldm_data=1; } $ldmthreadcnt=0; if ($have_ldm_data) { foreach $line (@ldm) { $line=&dos2unix($line); $line=&mychomp($line); &check_LDOM; # Count virtual CPUs $ldmthreadcnt++ if ($line =~ /^\|pid=\d/); if ($line =~ /^\|pa=\d.*\|size=\d/) { # Add up total memory found in ldm output $sz=$line; $sz=~s/^.*size=(\d*).*/$1/; $ldm_memory += $sz; } } # Was ldm data found? $have_ldm_data=0 if (! $ldmthreadcnt && ! $ldm_memory); if ($ldmthreadcnt) { # VCPUs found in ldm output delete $cpucnt{"$cputype $cpufreq"}; &pdebug("ldm: ncpu=$ncpu, npcpu=$npcpu"); $cpucntfrom="ldm"; $threadcnt=$ldmthreadcnt; &multicore_cpu_cnt; } $installed_memory=$ldm_memory / $meg if ($ldm_memory); } # Handle guest domains on UltraSPARC-T1 and later systems if ($virtinfo_cmd && ! $have_virtinfo_data) { @virtinfo=&run("$virtinfo_cmd -pa"); $have_virtinfo_data=1; } if ($cfgadm_cmd && ! $have_cfgadm_data) { @cfgadm=&run("$cfgadm_cmd -al"); $have_cfgadm_data=1; } if ($have_virtinfo_data) { foreach $line (@virtinfo) { $line=&dos2unix($line); if ($line =~ /Domain role: LDoms guest|DOMAINROLE\|impl=LDoms\|control=false/i) { &found_guest_LDOM; &pdebug("exit 1"); exit 1; } $virtinfoLDOMcontrolfound=1 if ($line =~ /DOMAINROLE\|impl=LDoms\|control=true/i); } } if ($have_cfgadm_data) { foreach $line (@cfgadm) { $line=&dos2unix($line); if ($line =~ /Configuration administration not supported/ && $ldmthreadcnt == 0 && $virtinfoLDOMcontrolfound == 0) { # Hack: Assume cfgadm fails on guest domains. &found_guest_LDOM; &pdebug("exit 1"); exit 1; } } } } sub check_LDOM { if ($line =~ /Authorization failed|Connection refused/i) { if ($uid eq "0") { # No LDOMs configured $ldm_cmd=""; $have_ldm_data=0; } else { &found_guest_LDOM(""); print "ERROR: ldm: $line\n"; print " This user does not have permission to run '/opt/SUNWldm/bin/ldm'.\n"; print " Run memconf as a privileged user like root on the control LDOM.\n"; &pdebug("exit 1"); exit 1; } } } sub found_guest_LDOM { # Rewrite cputype and cpucnt hash since I don't # know how many cores the guest domain host has if ($cputype =~ /UltraSPARC-T1$/) { delete $cpucnt{"$cputype $cpufreq"}; $cputype="UltraSPARC-T1"; $cpucnt{"$cputype $cpufreq"}=1; } elsif ($cputype =~ /UltraSPARC-T2\+/) { delete $cpucnt{"$cputype $cpufreq"}; $cputype="UltraSPARC-T2+"; $cpucnt{"$cputype $cpufreq"}=1; } elsif ($cputype =~ /UltraSPARC-T2$/) { delete $cpucnt{"$cputype $cpufreq"}; $cputype="UltraSPARC-T2"; $cpucnt{"$cputype $cpufreq"}=1; } elsif ($cputype =~ /SPARC-T3$/) { delete $cpucnt{"$cputype $cpufreq"}; $cputype="SPARC-T3"; $cpucnt{"$cputype $cpufreq"}=1; } elsif ($cputype =~ /SPARC-T4$/) { delete $cpucnt{"$cputype $cpufreq"}; $cputype="SPARC-T4"; $cpucnt{"$cputype $cpufreq"}=1; } elsif ($cputype =~ /SPARC-T5$/) { delete $cpucnt{"$cputype $cpufreq"}; $cputype="SPARC-T5"; $cpucnt{"$cputype $cpufreq"}=1; } elsif ($cputype =~ /SPARC-M5$/) { delete $cpucnt{"$cputype $cpufreq"}; $cputype="SPARC-M5"; $cpucnt{"$cputype $cpufreq"}=1; } elsif ($cputype =~ /SPARC-M6$/) { delete $cpucnt{"$cputype $cpufreq"}; $cputype="SPARC-M6"; $cpucnt{"$cputype $cpufreq"}=1; } elsif ($cputype =~ /SPARC-S7$/) { delete $cpucnt{"$cputype $cpufreq"}; $cputype="SPARC-S7"; $cpucnt{"$cputype $cpufreq"}=1; } &show_header; $arg=shift; return if (defined($arg)); $domaincontrol=""; if ($have_virtinfo_data) { foreach $line (@virtinfo) { $line=&dos2unix($line); if ($line =~ /DOMAINCONTROL\|name=/i) { $domaincontrol=&mychomp($line); $domaincontrol=~s/^.*name=//; } } } print "ERROR: Guest Logical Domain (LDOM) detected.\n"; print " Run memconf on the control LDOM"; print " host \"$domaincontrol\"" if ($domaincontrol ne ""); print ".\n It cannot show system memory details on guest LDOMs.\n"; } sub found_nonglobal_zone { # non-global zone (container) print "WARNING: More details can be reported if memconf is run in the global zone"; if ($filename) { print ".\n"; } else { $globalzone=&mychomp(`/usr/sbin/arp -a | awk '/SP/ {print \$2}' | head -1`); print "\n on hostname '$globalzone'.\n"; } } sub check_smbios { &pdebug("in check_smbios"); $flag_smb_cpudevice=0; $flag_smb_memdevice=0; $cpu_membank=-1; $cpu_cnt=-1; $physmemarray=""; foreach $line (@smbios) { $line=&dos2unix($line); $line=&mychomp($line); next if ($line =~ /( *Unknown|: Other|: \.\.|: Not Specified)/i); if ($model eq "i86pc" || $model eq "i86xpv" || $model eq "i86xen") { if ($line =~ /^ *Manufacturer:/ && $line !~ /(To Be Filled|System Manufacturer)/i && $manufacturer eq "") { $manufacturer=$line; $manufacturer=~s/^ *Manufacturer: *//g; $manufacturer=~s/\s*$//g; &pdebug("in check_smbios, manufacturer=$manufacturer"); } if ($line =~ /^ *Product:/ && $line !~ /(To Be Filled|System .*Name|XXXX)/i) { $model=$line; $model=~s/^ *Product: *//g; $model=~s/\s*$//g; &pdebug("in check_smbios, model=$model"); &x86_devname; } } if ($line =~ /SMB_TYPE_PROCESSOR\b/) { $flag_smb_cpudevice=1; $cpu_cnt++; } if ($flag_smb_cpudevice && $line =~ /Location Tag:/) { $CPUSocketDesignation[$cpu_cnt]=$line; $CPUSocketDesignation[$cpu_cnt]=~s/^ *Location Tag: *//g; $flag_smb_cpudevice=0; } if ($line =~ /SMB_TYPE_MEMDEVICE\b/) { $mem_mfg=""; $socket=""; $pn=""; $simmsize=0; $memtype=""; $formfactor=""; $smb_mdf=""; $maxmembusspeed=""; $flag_smb_cpudevice=0; $flag_smb_memdevice=1; } if ($flag_smb_memdevice) { if ($line =~ /Manufacturer:/) { $mem_mfg=$line; $mem_mfg=~s/^ *Manufacturer: *//g; $mem_mfg=&get_mfg($mem_mfg); $mem_mfg=", $mem_mfg" if ($mem_mfg); } if ($line =~ /Location Tag:/) { # Ignore System ROM FLASH if ($line =~ /SYSTEM ROM/i) { $flag_smb_memdevice=0; } else { $socket=$line; $socket=~s/^ *Location Tag: *//g; $socket=~s/\s*$//g; } } if ($line =~ /Part Number:/) { $pn=$line; $pn=~s/^ *Part Number: *//g; $pn=~s/\s*$//g; $pn="" if ($pn =~ /^0xFF|PartNum/i); $pn=&hex2ascii($pn); if ($pn) { # Hack: Ballistic modules may have mfg Undefined $mem_mfg=", Crucial Technology" if (! $mem_mfg && $pn =~ /^BL/); if ($mem_mfg) { $pn=" $pn"; } else { $pn=", $pn"; } } } if ($line =~ /Physical Memory Array:/) { $tmp=&mychomp($line); $tmp=~s/^ *Physical Memory Array: *//g; $cpu_membank++ if ($physmemarray ne $tmp); $physmemarray=$tmp; } if ($line =~ /Size:/) { $simmsize=$line; $simmsize=~s/^ *Size: //g; $simmsize=~s/ bytes//g; $simmsize=0 if ($simmsize =~ /Not Populated/); $simmsize /= $meg; } if ($line =~ /Memory Type:/) { # Ignore FLASH (System ROM) if ($line =~ /FLASH/i) { $flag_smb_memdevice=0; } else { $memtype=$line; $memtype=~s/^ *Memory Type:.*\((.*)\).*/$1/g; $memtype .= " " if ($formfactor); $memtype="" if ($memtype =~ /Memory Type:|^other/); } } if ($line =~ /Form Factor:/) { $formfactor=$line; $formfactor=~s/^ *Form Factor:.*\((.*)\).*/$1/g; $formfactor="" if ($formfactor =~ /Form Factor:/); } $smb_mdf="Fast-Page " if ($line =~ /SMB_MDF_FASTPG/); $smb_mdf="Synchronous " if ($line =~ /SMB_MDF_SYNC/); $smb_mdf="EDO " if ($line =~ /SMB_MDF_EDO/); if ($line =~ /^ *Speed: *\d+ *MHz/) { $maxmembusspeed=$line; $maxmembusspeed=~s/^ *Speed: *(\d+) *MHz/${1}MHz/g; } if ($line =~ /Bank Locator:|^ *ID *SIZE *TYPE/ && $socket) { $bank_label=$line; $bank_label=~s/^ *(Bank Locator:|ID *SIZE *TYPE) *//g; $bank_label=~s/ *SLOT$//ig; $bank_label="BANK $bank_label" if ($bank_label =~ /^.$/); $bank_label="" if ($bank_label eq $socket || $bank_label eq "BANK"); if ($socket =~ /^CPU/ && $socket !~ /$bank_label/) { $socket .= "_$bank_label"; $bank_label=""; } $bank_label=" $bank_label" if ($bank_label); $flag_smb_memdevice=0; # Don't overwrite duplicate socket names if (! defined($smbios_mem{"$socket"})) { # Add CPU to X4170/X4270/X4275/X6270/X6275 if ($model =~ /Sun .*X(4[12]7[05]|627[05])\b/i && $socket !~ /CPU/) { $bank_label="" if ($bank_label =~ /\/P\d+$/); $cpu_number=$CPUSocketDesignation[$cpu_membank]; $cpu_number=~s/\s*//g; $socket="${cpu_number}_$socket"; } if ($model =~ /W1100z\b/i && $model !~ /2100z\b/i && $socket =~ /DIMM[5-8]/) { # DIMM5-DIMM8 don't exist on W1100z } else { $smbios_mem{"$socket$bank_label"}=($simmsize) ? "${simmsize}MB $smb_mdf$memtype$formfactor$mem_mfg$pn" : ""; $sockets_used=""; } } } } } $tmp=scalar(keys %smbios_mem); if (defined($tmp)) { if ($tmp) { &pdebug("Memory found with smbios"); &show_header; if (! &is_virtualmachine) { for (sort alphanumerically keys %smbios_mem) { if ($smbios_mem{$_}) { print "$_: $smbios_mem{$_}\n"; $simmsize=$smbios_mem{$_}; $simmsize=~s/^.*\b(\d+)M[Bb].*/$1/; $smbios_memory += $simmsize if ($simmsize); } else { &add_to_sockets_empty($_); } } } $totmem=$installed_memory; &print_empty_memory("memory sockets"); &finish; &pdebug("exit"); exit; } } } sub check_kstat { &pdebug("in check_kstat"); $instance=0; foreach $line (@kstat) { $line=&dos2unix($line); $_=&mychomp($line); # cpu thread instance number if (/\scpu_info\s+instance:\s+/) { ($instance)=(/.*\s(\d+)\s*$/); } if (/^\s*brand\s/) { ($val)=(/^\sbrand\s*(\S.*)\s*$/); push(@kstat_brand, "$val") if ($val); } if (/\sclock_MHz\s/) { ($val)=(/.*\s(\d+)\s*$/); push(@kstat_MHz, "$val") if ($val); } # count # of threads per unique core_id for each chip if (/\score_id\s/) { ($val)=(/.*\s(\d+)\s*$/); $kstat_core_id{$instance}=$val; $kstat_core{$val}++; } # number of cores per chip if (/\sncore_per_chip\s/) { ($val)=(/.*\s(\d+)\s*$/); $kstat_ncore_per_chip{$instance}=$val; } # max number of cpus (threads) per chip if (/\sncpu_per_chip\s/) { ($val)=(/.*\s(\d+)\s*$/); $kstat_ncpu_per_chip{$instance}=$val; } $foundGenuineIntel=1 if (/\svendor_id\s+GenuineIntel/); } if ($foundGenuineIntel && $instance) { # Assume all CPUs are same for ($val=0; $val <= $instance; $val++) { last if (! defined($kstat_core_id{$val}) || ! defined($kstat_ncore_per_chip{$val}) || ! defined($kstat_ncpu_per_chip{$val})); $kstat_checked=1; if ($kstat_ncpu_per_chip{$val} == 2 * $kstat_ncore_per_chip{$val}) { # CPU is hyper-thread capable, but it may not be # enabled in the BIOS &pdebug("in check_kstat, found CPU capable of Hyper-Threading") if (! $hyperthreadcapable); $hyperthreadcapable=1; if ($kstat_core{$kstat_core_id{$val}} == 2) { # Hyper-Thread is enabled in BIOS. # Only change corecnt if not already # done earlier in check_psrinfo_pv. $corecnt /= 2 if (! $hyperthread); $hyperthread=1; &pdebug("hyperthread=1: from kstat, cputype=$cputype"); last; } } } } elsif (@kstat_brand && @kstat_MHz) { @kstat_brandMHz=(); @kstat_brand_arr=(); @kstat_MHz_arr=(); $i=0; foreach $brand (@kstat_brand) { $kstat_brandMHz{$brand,$kstat_MHz[$i]}++; push(@kstat_brand_arr, "$brand") if (! grep($_ eq $brand, @kstat_brand_arr)); push(@kstat_MHz_arr, "$kstat_MHz[$i]") if (! grep($_ eq $kstat_MHz[$i], @kstat_MHz_arr)); $i++; } @kstat_cpubanners=(); # return unless have mix of CPUs or is VM return if ($#kstat_brand_arr == 0 && $#kstat_MHz_arr == 0 && ! &is_virtualmachine); foreach $brand (@kstat_brand_arr) { foreach $MHz (@kstat_MHz_arr) { if ($kstat_brandMHz{$brand,$MHz}) { $cputype=$brand; if ($isX86) { $cputype=&multicore_cputype($cputype,$corecnt); } else { &multicore_cpu_cnt; } $tmp=""; $cnt=$kstat_brandMHz{$brand,$MHz} / $corecnt; $cpucntfrom="kstat"; $tmp .= "$cnt X " if ($cnt > 1); push(@kstat_cpubanners, "$tmp$cputype ${MHz}MHz"); } } } $i=0; foreach (@kstat_cpubanners) { $kstat_cpubanner .= ", " if ($i); $kstat_cpubanner .= $_; $i++; } $kstat_cpubanner=&cleanup_cputype($kstat_cpubanner); &pdebug("in check_kstat, kstat_cpubanner=$kstat_cpubanner"); } } sub found_empty_bank { $empty_banks .= "," if ($empty_banks); $boardslot_mem=~s/[: ]//g; $empty_banks .= " Board $boardslot_mem @_"; } sub print_empty_memory { return if (&is_virtualmachine || $empty_memory_printed); $s=shift; print "empty $s: "; $sockets_empty=~s/^\s*//; $sockets_empty=~s/^,\s*//; print (($sockets_empty) ? "$sockets_empty\n" : "None\n"); $empty_memory_printed=1; } sub print_bios_error { return if (&is_virtualmachine); print " An upgraded BIOS from your manufacturer "; if (&check_dmidecode_ver != 0) { print "or a newer version of dmidecode\n from "; print "$dmidecodeURL "; } print "may fix this issue.\n This is a BIOS "; print "or dmidecode " if (&check_dmidecode_ver != 0); print "bug, not a bug in memconf"; print " or dmidecode" if (&check_dmidecode_ver == 0); print ".\n"; &check_dmidecode_ver(1); $recognized=0; $exitstatus=1; } sub found_nvsimm_bank { $nvsimm_banks .= ", Board $boardslot_mem @_"; } sub recommend_prtdiag_patch { # Sun BugID 4664349 print " This may be corrected by installing "; if ($osrel eq "5.9") { print "Sun patch 113221-03 or 118558-06 or later.\n"; } elsif ($osrel eq "5.8") { print "Sun patch 109873-26 or 111792-11 or later.\n"; } else { print "a Sun patch on this system.\n"; } } sub numerically { $a <=> $b; } sub alphanumerically { local($&, $`, $', $1, $2); # Sort numbers numerically return $a cmp $b if ($a !~ /\D/ && $b !~ /\D/); # Handle things like CH0/D0, p0.d0, DIMM1_A, Board 1,1A return $a cmp $b if ($a =~ /[\/\.,_]/ && $b =~ /[\/\.,_]/); # Handle things like DIMM 1A return $a cmp $b if ($a =~ /\d\D$/ && $b =~ /\d\D$/); # Handle things like DIMM 1 BANK A, ..., DIMM 12 BANK D if ($a =~ /(.*\D)(\d+)\D+$/) { ($a1, $a2) = ($1, $2); if ($b =~ /(.*\D)(\d+)\D+$/) { ($b1, $b2) = ($1, $2); return $a2 <=> $b2 if ($a1 eq $b1); } } # Handle things like DIMM1, ..., DIMM10 if ($a =~ /^(\D+)(\d+)\b/) { ($a1, $a2) = ($1, $2); if ($b =~ /^(\D+)(\d+)\b/) { ($b1, $b2) = ($1, $2); return $a2 <=> $b2 if ($a1 eq $b1); } } # Default is to sort alphabetically return $a cmp $b; } sub lc { $s=shift; return "" if (! defined($s)); $s=~tr/[A-Z]/[a-z]/; return $s; } sub dos2unix { # Convert "CR LF" or "CR" to "LF" $s=shift; $s=~s/\r\n/\n/g; $s=~s/\r/\n/g; return $s; } sub convert_freq { ($freqx)=@_; if ($isX86) { $freq=int(hex("0x$freqx") / 10000 + 0.5); } else { if ($freqx =~ /'/) { $freqpack=$freqx; $freqpack=~s/'//g; @frequnpack=unpack("C*",$freqpack); $freqx=""; foreach $field (@frequnpack) { $freqx.=sprintf("%02lx", $field); } if ($#frequnpack < 3) { $freqx.="00"; } } $freq=int(hex("0x$freqx") / 1000000 + 0.5); } return $freq; } sub mychomp { # Used instead of chop or chomp for compatibility with perl4 and perl5 ($a)=@_; return "" if (! defined($a)); $a=~s,$/$,,g; return $a; } sub hex2ascii { $_=shift; return $_ if (! /^0x/); s/0x(([0-9a-f][0-9a-f])+)/pack('H*', $1)/ie; s/[\x00|\s]+$//; # remove trailing nulls and spaces return $_; } sub pdebug { if ($debug == 1) { print "DEBUG: @_\n"; } elsif ($debug == 2) { printf "DEBUG time %.2f", ((times)[0] - $starttime); print ": @_\n"; } } sub run { &pdebug("Running @_"); `@_ 2>&1`; } sub read_prtdiag_bank_table { # prtdiag Bank Table $simmsize=substr($line,33,5); if ($simmsize =~ /\dGB/) { $simmsize=~s/GB//g; $simmsize *= 1024; } else { $simmsize=~s/MB//g; } if (! $prtdiag_banktable_has_dimms || $line =~ / 0$/) { # Interleave Way = 0 $simmsize /= 2; } if ($prtdiag_banktable_has_dimms && $line =~ / 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15/) { # Interleave Way = 16 $simmsize *= 4; $intcnt=1; push(@simmsizesfound, "$simmsize"); } elsif ($intcnt) { # Interleave Way = 16 $intcnt++; $simmsize *= 4; } $a=substr($line,9,2); $a=~s/ //g; $b=substr($line,23,1); $sz=&show_memory_label($simmsize); $grpsize{$a,$b}=$sz; $memlength=length($line); if ($memlength > 49) { $grpinterleave{$a,$b}=substr($line,49,40) if (substr($line,49,40)); } if ($intcnt == 0) { push(@simmsizesfound, "$simmsize"); $simmsize=&show_memory_label($simmsize) . " "; if (! $prtdiag_banktable_has_dimms) { $newline=substr($line,0,38) . " 2x" . substr($simmsize,0,5); $newline .= substr($line,42,20) if ($memlength > 38); } } $intcnt=1 if ($prtdiag_banktable_has_dimms && $line =~ / 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15/); $intcnt=0 if ($intcnt == 16); } sub read_prtdiag_memory_segment_table { # prtdiag Memory Segment Table $simmsize=($line =~ /\dGB/) ? substr($line,19,1) * 512 : substr($line,19,3) / 2; $grp=substr($line,-2,2); $grp=~s/ //g; if ($grp eq "-") { $grp=$grpcnt; $grpcnt++; } push(@simmsizesfound, "$simmsize"); $simmsize=&show_memory_label($simmsize); $grpsize{0,$grp}=$simmsize; } $motherboard=""; $realmodel=""; $manufacturer=""; $i=0; # May not have had permission to run prtconf, so see if prtdiag works &check_for_prtdiag; if ($diagbanner) { if (! $filename || $SUNWexplo) { $model=$platform; $model=~s/SUNW,//g; $model=~s/ORCL,//g; } else { $model=$diagbanner; $model=~s/ /-/g; # define $model for systems with $diagbanner != $model $model="Ultra-4" if ($diagbanner =~ /Sun.Enterprise.450\b/); $model="Sun-Blade-1000" if ($diagbanner =~ /Sun.Blade.1000\b/); $model="Sun-Fire-280R" if ($diagbanner =~ /Sun.Fire.280R\b/); $model="Netra t1" if ($diagbanner =~ /Netra.t1\b/); $model="Netra-T4" if ($diagbanner =~ /Netra.T4\b/); $model="Sun-Blade-100" if ($diagbanner =~ /Sun.Blade.1[05]0\b/); $model="Netra-T12" if ($diagbanner =~ /Sun.Fire.V1280\b/); $model="Serverblade1" if ($diagbanner =~ /Serverblade1\b/); $model="Ultra-Enterprise" if ($diagbanner =~ /Enterprise.(E?[3-6][05]00|10000)\b/); } # Check model and banner here in case we don't have prtconf data &check_model; &check_banner; } foreach $line (@config) { $line=&dos2unix($line); $line=&mychomp($line); $config_permission=1 if ($line =~ /Node /); if ($line =~ /Permission denied/i) { $permission_error="ERROR: $line" if (! $diagbanner || ! $prtdiag_has_mem); } if ($line =~ /(^\[Component\]:\s+Memory|cstm.*selclass qualifier )/) { # for HP-UX regression test file &hpux_check; &hpux_cprop if ($line =~ /^\[Component\]:\s+Memory/); &hpux_cstm; } if ($line =~ /banner-name:/ && ! $banner) { $banner=$line; $banner=~s/\s+banner-name:\s+//; $banner=~s/'//g; $banner=~s/SUNW,//g; $banner=~s/ORCL,//g; $banner=~s/TWS,//g; $banner=~s/CYCLE,//g; $banner=~s/\s+$//; &check_banner; } if ($line =~ /model:.*AXUS/) { # AXUS clones with their name on OBP $manufacturer="AXUS"; } if (($line =~ /SUNW,(Ultra-|SPARC|S240|JavaEngine1|Ultra.*[Ee]ngine)/ || $line =~ /SUNW,(Ultra.*Netra*|Premier-24|UltraAX-|Netra|Grover)/ || $line =~ /SUNW,(Enchilada|Serverblade1|Enterprise|A[0-9]|T[0-9])/ || $line =~ /ORCL,SPARC-|Sun.4|SUNW,Axil-|^i86pc|^i86xpv|^i86xen/ || $line =~ /model:\s+'(SPARC CPU|SPARC CPCI)-/ || $line =~ /\s+name:.*(SUNW,Sun-|'i86pc'|COMPstation|Tadpole)/ || $line =~ /\s+name:.*(Auspex|S-4|FJSV,GP|CompuAdd|RDI,)/) && $line !~ /\s+:Description\s+/ && $line !~ /\s+:*whoami:*\s+/ && $line !~ /\s+:*impl-arch-name:*\s+/ && $line !~ /Sun 4x Quad/i) { $model=$line; $model=~s/\s+name:\s+//; $model=~s/\s+model:\s+//; $model=~s/\s+:binding-name\s+//; $model=~s/\s+:PlatformName\s+//; $model=~s/'//g; $model=~s/\s+$//; &check_model; if ($line =~ /CompuAdd/) { $manufacturer="CompuAdd"; if ($model eq "SS-2") { $banner=$model if (! $banner); $bannermore="SPARCstation 2"; $modelmore="SPARCstation 2"; } } } $foundname=1 if ($line =~ /\s+name:\s+/); if ($line =~ /\s+model:\s+'.+,/ && ! $foundname) { # Ultra 5/10 motherboard is 375-xxxx part number # SS10/SS20 motherboard is Sxx,501-xxxx part number if ($line =~ /,(375|500|501)-/) { $motherboard=$line; $motherboard=~s/\s+model:\s+//; $motherboard=~s/'//g; } } if ($line =~ /\sname:\s+'memory'/) { $j=$i - 2; if ($config[$j] =~ /\sreg:\s/) { $gotmemory=&mychomp($config[$j]); } elsif ($config[$j - 1] =~ /\sreg:\s/) { $gotmemory=&mychomp($config[$j - 1]); } elsif ($config[$j + 1] =~ /\sreg:\s/) { $gotmemory=&mychomp($config[$j + 1]); } } if ($line =~ /\sdevice_type:\s+'memory-bank'/) { $j=$i - 3; if ($config[$j] =~ /\sreg:\s/ && $config[$j] !~ /.00000000$/) { $config[$j]=~s/\s+reg:\s+//; $gotmemory=($gotmemory) ? "$gotmemory.$config[$j]" : $config[$j]; $gotmemory=&mychomp($gotmemory); } } # The following is not used yet #if ($line =~ /\sdevice_type:\s+'memory-module'/) { # if ($config[$i - 2] =~ /\sreg:\s/) { # $config[$i - 3]=~s/\s+socket-name:\s+//; # if ($gotmodule) { # $gotmodule .= ".$config[$i - 3]"; # } else { # $gotmodule=$config[$i - 3]; # } # $gotmodule=&mychomp($gotmodule); # $config[$i - 2]=~s/\s+reg:\s+//; # @module=split(/\./, $config[$i - 2]); # $gotmodule .= ".$module[3]"; # $gotmodule=&mychomp($gotmodule); # $config[$i + 1]=~s/\s+name:\s+//; # $config[$i + 1] =~ y/[a-z]/[A-Z]/; # $gotmodule .= ".$config[$i + 1]"; # $gotmodule=&mychomp($gotmodule); # $gotmodule=~s/'//g; # } #} if ($line =~ /\ssimm-use:\s+/) { # DIMM usage on Fujitsu GP7000 $gotmodule=&mychomp($config[$i]); $gotmodule=~s/\s+simm-use:\s+//; $slotname0="SLOT0" if ($banner =~ /GP7000\b/); } if ($line =~ /\scomponent-name:\s+'.*CPU.*'/) { # CPUs on Fujitsu GP7000F and PrimePower systems $slotname=$line; $slotname=~s/\s+component-name:\s+//; $slotname=~s/'//g; $gotcpunames=($gotcpunames) ? "$gotcpunames $slotname" : $slotname; $boardname=$slotname; $boardname=~s/-.*//g; if ($boardname ne $slotname) { if ($gotcpuboards) { $gotcpuboards .= " $boardname" if ($gotcpuboards !~ /\b$boardname\b/); } else { $gotcpuboards=$boardname; } } } if ($line =~ /\sdevice_type:\s+'memory-module'/) { # DIMM usage on Fujitsu GP7000F and PrimePower systems $slotname=""; if ($config[$i - 3] =~ /\scomponent-name:\s/) { $slotname=$config[$i - 3]; } if ($config[$i - 4] =~ /\scomponent-name:\s/) { $slotname=$config[$i - 4]; } if ($slotname) { $slotname=~s/\s+component-name:\s+//; $slotname=~s/'//g; $slotname=&mychomp($slotname); $gotmodulenames=($gotmodulenames) ? "$gotmodulenames.$slotname" : $slotname; $slotname0=$slotname if (! $slotname0); $config[$i - 1]=~s/\s+reg:\s+//; @module=split(/\./, $config[$i - 1]); $gotmodulenames .= ".$module[1]"; $gotmodulenames=&mychomp($gotmodulenames); } } if ($line =~ /\sname:\s+'cgfourteen'/) { # Determine size of VSIMM # Currently assumes only one VSIMM is installed if ($config[$i - 2] =~ /\sreg:\s/) { $sx_line=&mychomp($config[$i - 2]); } elsif ($config[$i - 3] =~ /\sreg:\s/) { $sx_line=&mychomp($config[$i - 3]); } @sxline=split(/\./, $sx_line); $sxmem=hex("0x$sxline[5]") / $meg; } if ($line =~ /501-2197/) { # 1MB Prestoserve NVSIMMs (SS1000/SC2000) if ($config[$i + 1] =~ /\sreg:\s/) { $nv_line=&mychomp($config[$i + 1]); } elsif ($config[$i + 2] =~ /\sreg:\s/) { $nv_line=&mychomp($config[$i + 2]); } @nvline=split(/\./, $nv_line); $nvmem += hex("0x$nvline[2]") / $meg; } if ($line =~ /501-2001/) { # 2MB Prestoserve NVSIMMs (SS10/SS20) if ($config[$i + 1] =~ /\sreg:\s/) { $nv_line=&mychomp($config[$i + 1]); } elsif ($config[$i + 2] =~ /\sreg:\s/) { $nv_line=&mychomp($config[$i + 2]); } @nvline=split(/\./, $nv_line); $nvmem += hex("0x$nvline[2]") / $meg; $nvmem1=1 if ($nvline[1] eq "10000000"); $nvmem2=1 if ($nvline[1] eq "14000000" || $nvline[1] eq "1c000000"); } if ($line =~ /Memory size:\s/ && $installed_memory == 0) { $installed_memory=$line; $installed_memory=~s/^.*size: *(\d*[GM]*[Bb]*).*/$1/; if ($installed_memory =~ /GB/) { $installed_memory=~s/GB//g; $installed_memory *= 1024; } else { $installed_memory=~s/MB//ig; } # prtconf sometimes reports incorrect total memory # 32MB is minimum for sun4u machines if ($installed_memory < 32 && $machine eq "sun4u") { $prtconf_warn="Incorrect total installed memory (${installed_memory}MB) was reported by prtconf."; $installed_memory=0; } # Round up some odd-number total memory values $installed_memory++ if (sprintf("%3d", ($installed_memory + 1) / 2) * 2 != $installed_memory && $installed_memory >= 1023); $BSD=0; # prtconf and prtdiag only have this output $config_cmd="/usr/sbin/prtconf -vp" if ($config_cmd !~ /prtconf/); $config_command="prtconf"; } if ($sysfreq == 0 && $freq) { $sysfreq=$freq; $freq=0; } if ($devtype eq "cpu" || $line =~ /compatible: 'FJSV,SPARC64-/) { if ($cputype =~ /SPARC64-/) { $cpufreq=$freq if ($freq > $cpufreq); } else { $cpufreq=$freq; } $cpuline=$line; $j=$i - 3; while ($cpuline !~ /^$/ && $cpuline !~ /^\r$/) { if ($cpuline =~ /clock-frequency:/) { @freq_line=split(' ', $cpuline); $cpufreq=&convert_freq($freq_line[1]); $sysfreq=$freq if ($sysfreq == 0 && $freq); } elsif ($cpuline =~ /\s(name:|compatible:)\s/ && $cpuline !~ /Sun 4/ && $cpuline !~ /SPARCstation/ && $cpuline !~ /CompuAdd/ && $cpuline !~ /'cpu/ && $cpuline !~ /'core'/) { $cputype=&mychomp($cpuline); $cputype=~s/\s+name:\s+//; $cputype=~s/\s+compatible:\s+//; $cputype=~s/'//g; $cputype=~s/SUNW,//g; $cputype=~s/ORCL,//g; $cputype=~s/FJSV,//g; $cputype=~s/ .*//g; } elsif ($cpuline =~ /\sname:\s/ && ! $model) { $model=&mychomp($cpuline); $model=~s/\s+name:\s+//; $model=~s/'//g; $model=~s/SUNW,//g; $model=~s/ORCL,//g; $model=~s/FJSV,//g; } $j++; $cpuline=($config[$j]) ? $config[$j] : ""; } $freq=0; $cpufreq=$sysfreq if ($sysfreq >= $cpufreq); &pdebug("Checking cputype=$cputype, ncpu=$ncpu, threadcnt=$threadcnt"); if (! $cputype) { $cputype=$machine; $cputype="SPARC" if ($cputype =~ /^sun4/ || $model =~ /Sun 4\//); @bannerarr=split(/\s/, $banner); foreach $field (@bannerarr) { if ($field =~ /SPARC/ && $field !~ /SPARCstation/) { $cputype=$field; } elsif ($field =~ /390Z5/) { $field="TI,TMS$field" if ($field =~ /^390Z5/); $cputype=($cpufreq > 70) ? "SuperSPARC-II $field" : "SuperSPARC $field"; } elsif ($field =~ /RT62[56]/) { $cputype="hyperSPARC $field"; $machine="sun4m"; } } $cputype=~s/[()]//g; } elsif ($cputype =~ /MB86907/) { $cputype="TurboSPARC-II $cputype"; } elsif ($cputype =~ /MB86904|390S10/) { $cputype=($cpufreq > 70) ? "microSPARC-II $cputype" : "microSPARC $cputype"; } elsif ($cputype =~ /,RT62[56]/) { $cputype="hyperSPARC $cputype"; $machine="sun4m"; } elsif ($cputype =~ /UltraSPARC-IV/) { # Count Dual-Core US-IV & US-IV+ as 1 CPU $cputype="Dual-Core $cputype"; $machine="sun4u"; $threadcnt++; $threadcnt=0 if ($threadcnt == 2); # CPU count is better from prtdiag than psrinfo for # US-IV & US-IV+ Dual-Core processors. $use_psrinfo_data=0; } elsif ($cputype =~ /UltraSPARC-T1$/) { # Count 4-Thread (4, 6, or 8 Core) Niagara CPUs as 1 CPU $machine="sun4v"; $threadcnt++; # Number of cores & CPUs counted outside this loop below } elsif ($cputype =~ /UltraSPARC-T2\+/) { # Count 8-Thread (4, 6, or 8 Core) Victoria Falls CPUs as 1 CPU $machine="sun4v"; $threadcnt++; # Number of cores & CPUs counted outside this loop below } elsif ($cputype =~ /UltraSPARC-T2$/) { # Count 8-Thread (4 or 8 Core) Niagara-II CPUs as 1 CPU $machine="sun4v"; $threadcnt++; # Number of cores & CPUs counted outside this loop below } elsif ($cputype =~ /SPARC-T3$/) { # Count 8-Thread (8 or 16 Core) Rainbow Falls CPUs as 1 CPU $machine="sun4v"; $threadcnt++; # Number of cores & CPUs counted outside this loop below } elsif ($cputype =~ /SPARC-T4$/) { # Count 8-Thread 8-Core SPARC-T4 CPUs as 1 CPU $machine="sun4v"; $threadcnt++; # Number of cores & CPUs counted outside this loop below } elsif ($cputype =~ /SPARC-T5$/) { # Count 8-Thread 16-Core SPARC-T5 CPUs as 1 CPU $machine="sun4v"; $threadcnt++; # Number of cores & CPUs counted outside this loop below } elsif ($cputype =~ /SPARC64-VI$/ && $devtype eq "cpu") { # Count Dual-Core Dual-Thread as 1 CPU $machine="sun4u"; $threadcnt++; # Number of cores & CPUs counted outside this loop below } elsif ($cputype =~ /SPARC64-VII\+\+$/ && $devtype eq "cpu") { # Count Quad-Core Dual-Thread as 1 CPU $machine="sun4u"; $threadcnt++; # Number of cores & CPUs counted outside this loop below } elsif ($cputype =~ /SPARC64-VII\+$/ && $devtype eq "cpu") { # Count Quad-Core Dual-Thread as 1 CPU $machine="sun4u"; $threadcnt++; # Number of cores & CPUs counted outside this loop below } elsif ($cputype =~ /SPARC64-VII$/ && $devtype eq "cpu") { # Count Quad-Core Dual-Thread as 1 CPU $machine="sun4u"; $threadcnt++; # Number of cores & CPUs counted outside this loop below } elsif ($cputype eq "SPARC64-VIII" && $devtype eq "cpu") { # Guess on the Venus SPARC64-VIII name ??? # Count 8-Core Dual-Thread as 1 CPU $machine="sun4u"; $threadcnt++; # Number of cores & CPUs counted outside this loop below } elsif ($cputype =~ /SPARC64-X$/ && $devtype eq "cpu") { # Count 16-Core Dual-Thread as 1 CPU $machine="sun4v"; $threadcnt++; # Number of cores & CPUs counted outside this loop below } if ($threadcnt == 0 && $devtype eq "cpu") { $ncpu++; $cpucnt{"$cputype $cpufreq"}++; $cpucntfrom=$config_command; } $devtype=""; if (! $kernbit) { $kernbit=32 if ($machine =~ /sun4[cdm\b]/); $kernbit=64 if ($machine eq "sun4v" || $cputype =~ /UltraSPARC-III|UltraSPARC-IV|SPARC64/); } } if ($line =~ /device_type:/) { @dev_line=split(/\'/, $line); $devtype=$dev_line[1]; } if ($line =~ /clock-frequency:/) { @freq_line=split(' ', $line); $freq=&convert_freq($freq_line[1]); } if ($line =~ /\sversion:\s+'OBP/ && ! $romver) { $romver=$line; $romver=~s/\s+version:\s+//; $romver=~s/'//g; @romverarr=split(/\s/, $romver); $romvernum=$romverarr[1]; } if ($line =~ /compatible:\s+'sun4.'/ && ! $osrel) { @compatible_line=split(/\'/, $line); $machine=$compatible_line[1]; } if ($line =~ /value='.*AMD Opteron/ && $cputype eq "x86") { $cputype_prtconf=$line; $cputype_prtconf=~s/.*='//; $cputype_prtconf=~s/'//g; } $i++; } &multicore_cpu_cnt; &check_cpuinfo; &check_xm_info; if (! $osrel) { if ($BSD) { $osrel="4.X"; $config_cmd="/usr/etc/devinfo -pv"; $config_command="devinfo"; $cpucntfrom="devinfo"; # } elsif ($os =~ /Linux|FreeBSD/) { # $osrel="2.X"; # Could also be 3.X Linux kernel, so leave empty } else { $osrel="5.X"; $solaris="2.X"; if ($machine =~ /86/) { $solaris .= " X86"; } elsif ($machine =~ /sun4/) { $solaris .= " SPARC"; } $config_cmd="/usr/sbin/prtconf -vp"; $config_command="prtconf"; } } $memfrom=$config_command; #$sysfreq=$freq if ($sysfreq == 0 && $freq); #$cpufreq=$sysfreq if ($sysfreq > $cpufreq && $ncpu); @romverarr=split(/\./, $romvernum) if ($romver); $romvermajor=($romverarr[0]) ? $romverarr[0] : 2; $romverminor=($romverarr[1]) ? $romverarr[1] : 0; $romverminor=0 if (! $romverminor || $romverminor eq "X"); if ($banner =~ /^ \(/) { # banner-name does not include the eeprom banner name. This happens # sometimes when OBP 3.23 is installed on Ultra-60/E220R and # Ultra-80/E420R systems. $bannermore="Ultra 60 or Enterprise 220R" if ($model eq "Ultra-60"); $bannermore="Ultra 80, Enterprise 420R or Netra t 1400/1405" if ($model eq "Ultra-80"); } # # SPARCengine systems # $ultra="AX" if ($motherboard =~ /501-3043/); $ultra="AX-300" if ($motherboard =~ /501-5037/); $ultra="AXi" if ($motherboard =~ /501-4559/); $ultra="AXmp" if ($banner =~ /UltraAX-MP/ || $model =~ /UltraAX-MP/ || $motherboard =~ /501-(5296|5487|5670)/); $ultra="AXmp+" if ($banner =~ /UltraAX-MP\+/ || $model =~ /UltraAX-MP\+/ || $motherboard =~ /501-4324/); $ultra="AXe" if ($banner =~ /UltraAXe\b/ || $model =~ /UltraAX-e\b/ || $motherboard =~ /375-0088/); $ultra="AX-e2" if ($banner =~ /Netra AX1105-500\b/ || $model =~ /UltraAX-e2\b/ || $motherboard =~ /375-0128/); $ultra="Netra X1" if ($banner =~ /Netra X1\b/ || $motherboard =~ /375-3015/); $ultra="Netra T1 200" if ($banner =~ /Netra T1 200\b/ || $motherboard =~ /375-0132/); $ultra="Sun Fire V100" if ($banner =~ /Sun Fire V100\b/); # Sun Fire V120/Netra 120 can use motherboard 375-0132 like Netra T1 200 above $ultra="Sun Fire V120" if ($banner =~ /Sun Fire V120\b/); $ultra="Netra 120" if ($banner =~ /Netra 120\b/); if ($ultra =~ /AX/) { if ($banner !~ /SPARCengine.*Ultra/) { $tmp="(SPARCengine Ultra $ultra)"; $bannermore=($bannermore) ? "$tmp $bannermore" : $tmp; } } if ($model =~ /Ultra-5_10\b/) { if ($banner =~ /\bVoyagerIIi\b/) { # Tadpole Voyager IIi has 8 DIMM slots, but prtconf reports # it as an Ultra 5/10 $model="VoyagerIIi"; $ultra="VoyagerIIi"; } } $ultra="Sun Blade 150" if ($banner =~ /Sun Blade 150\b/ || $diagbanner =~ /Sun Blade 150\b/); $ultra="UP-20" if ($banner =~ /\bUP-20\b/); # untested ??? $ultra="UP-520IIi" if ($motherboard =~ /501-4559/ && $banner =~ /\b520IIi\b/); $need_obp2=0; if ($model eq "Sun 4/20" || $model eq "Sun 4/25" || $model eq "Sun 4/40" || $model eq "Sun 4/50" || $model eq "Sun 4/60" || $model eq "Sun 4/65" || $model eq "Sun 4/75" || $model eq "SS-2") { $machine="sun4c"; $need_obp2=1 if ($model eq "Sun 4/40" || $model eq "Sun 4/60" || $model eq "Sun 4/65"); } &check_prtdiag if ($isX86); if ($isX86) { # Round up Solaris x86 memory (may have 128MB or more reserved) $installed_memory=&roundup_memory($installed_memory); } if (! $gotmemory && $ultra eq 0 && $machine ne "sun4d" && $boardfound_mem eq 0) { &check_prtdiag; &show_header; if ($installed_memory) { print "total memory = "; &show_memory($installed_memory); } print "$permission_error\n" if ($permission_error); print "$prtconf_warn\n" if ($prtconf_warn); if ($prtdiag_failed == 2) { &found_nonglobal_zone; } else { print "ERROR: no 'memory' line in \"$config_cmd\" output.\n" if ($machine =~ /sun4/); if (! $config_permission && $machine =~ /sun4/ && ! $prtconf_warn) { print " This user "; print (($permission_error) ? "does" : "may"); print " not have permission to run $config_command.\n"; print " Try running memconf as a privileged user like root.\n" if ($uid ne "0"); } elsif ($need_obp2) { print " Upgrading from Open Boot PROM V1.X to V2.X will "; print "allow memconf to\n detect the memory installed.\n"; } elsif ($prtconf_warn =~ /openprom/) { print " Please correct the problem with the openprom device.\n" if ($machine =~ /sun4/); } else { print " This is an unsupported system by memconf.\n" if ($machine =~ /sun4/); } } &show_supported if ($machine !~ /sun4/ && $prtdiag_failed != 2); $exitstatus=1; &mailmaintainer if ($verbose == 3); &pdebug("exit $exitstatus"); exit $exitstatus; } $gotmemory=~s/\s+reg:\s+//; $gotmemory=~s/'//g; @slots=split(/\./, $gotmemory); $slot=1; if ($machine =~ /sun4|i86pc|i86xpv|i86xen/ && $manufacturer && $manufacturer !~ /^Sun\b|^Oracle\b/ && $ultra !~ /SPARC Enterprise M[34589]000 Server/ && ! &is_virtualmachine) { $bannermore=($bannermore) ? "$bannermore clone" : "clone" if ($manufacturer ne "Force Computers"); $modelmore=($modelmore) ? "$modelmore clone" : "clone" if (! $isX86); $clone=1; } # DIMMs are installed in pairs on Ultra 1, 5 and 10; quads on # Ultra 2, 60, 80, 220R, 420R, 450; 8's in Ultra Enterprise # # On 64-bit systems, prtconf format is AAAAAAAA.AAAAAAAA.SSSSSSSS.SSSSSSSS # and on 32-bit systems, prtconf format is AAAAAAAA.AAAAAAAA.SSSSSSSS # where A is for Address, S is for Size. # Minimum module size is 1MB (0x00100000), so strip off last 5 hex digits of LSB # and prepend last 5 digits of MSB, which allows recognizing up to 4500TB! # if ($ultra) { $val0=3; # simmsize is in 3rd and 4th fields $valaddr=2; # address is 2 fields before simmsize $valinc=4; # fields per simm $memtype="DIMM"; } else { $val0=2; # simmsize is in 3rd field $valaddr=1; # address is 1 field before simmsize $valinc=3; # fields per simm } # # Define memory layout for specific systems # if ($model eq "Sun 4/20") { # SLC accepts 4MB SIMMs on motherboard # 501-1676 (4MB 100ns), 501-1698 (4MB 80ns) # 33-bit 72-pin Fast Page Mode (36-bit work also) # Does not support Open Boot PROM V2.X, so devinfo/prtconf output will # not have memory lines. $devname="OffCampus"; $untested=1; $simmrangex="00000010"; $simmbanks=4; $simmsperbank=1; @simmsizes=(4); @socketstr=("U0502","U0501","U0602","U0601"); } if ($model eq "Sun 4/25") { # ELC accepts 4MB or 16MB SIMMs on motherboard # 501-1698 or 501-1812 (4MB 80ns), 501-1822 (16MB 80ns) # 33-bit 72-pin Fast Page Mode (36-bit work also) $devname="NodeWarrior"; $untested=0; $simmrangex="00000010"; $simmbanks=4; $simmsperbank=1; @simmsizes=(4,16); @socketstr=("U0407".."U0410"); @bankstr=("MEM1".."MEM4"); } if ($model eq "Sun 4/40") { # IPC accepts 1MB or 4MB SIMMs on motherboard # 501-1697 (1MB 80ns), 501-1625 (4MB 100ns), 501-1739 (4MB 80ns) # Does not show memory with Open Boot PROM V1.X, but does with OBP V2.X $devname="Phoenix"; $untested=0; $simmrangex="00000010"; $simmbanks=3; $simmsperbank=4; @simmsizes=(1,4); @socketstr=("U0588","U0587","U0586","U0585","U0584","U0591","U0590","U0589","U0678","U0676","U0683","U0677"); @bankstr=(0,0,0,0,1,1,1,1,2,2,2,2); @bytestr=(0..3,0..3,0..3); } if ($model eq "Sun 4/50") { # IPX accepts 4MB or 16MB SIMMs on motherboard # 501-1812 (4MB 80ns), 501-1915 or 501-1822 (16MB 80ns) # 33-bit 72-pin Fast Page Mode (36-bit work also) $devname="Hobbes"; $untested=0; $simmrangex="00000010"; $simmbanks=4; $simmsperbank=1; @simmsizes=(4,16); @socketstr=("U0310","U0309","U0308","U0307"); @bankstr=(0..3); } if ($model eq "Sun 4/60" || $model eq "Sun 4/65") { # SS1 and SS1+ accepts 1MB or 4MB SIMMs on motherboard # 501-1408 (1MB 100ns), 501-1697 (SS1+ only) (1MB 80ns), # 501-1625 (4MB 100ns), 501-1739 (4MB 80ns) # Does not show memory with Open Boot PROM V1.X, but does with OBP V2.X if ($model eq "Sun 4/60") { $devname="Campus"; $untested=0; } else { $devname="CampusB, Campus+"; $untested=1; } $simmrangex="00000010"; $simmbanks=4; $simmsperbank=4; @simmsizes=(1,4); @socketstr=("U0588","U0587","U0586","U0585","U0584","U0591","U0590","U0589","U0678","U0676","U0683","U0677","U0682","U0681","U0680","U0679"); @bankstr=(0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3); @bytestr=(0..3,0..3,0..3,0..3); } if ($model eq "Sun 4/75" || $model eq "SS-2") { # SS2 accepts 4MB SIMMs on motherboard and 32MB or 64MB SBus expansion # card (501-1823 Primary and 501-1824 Secondary) # 501-1739 (4MB 80ns) $devname="Calvin"; $untested=0; $simmrangex="00000010"; $simmbanks=4; $simmsperbank=4; @simmsizes=(4); @socketstr=("U0311","U0309","U0307","U0322","U0312","U0310","U0308","U0321","U0313","U0314","U0315","U0320","U0319","U0318","U0317","U0316"); @bankstr=(0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3); @bytestr=(0..3,0..3,0..3,0..3); } if ($model =~ /SPARCclassic|SPARCstation-LX/) { # Classic-X (4/10) accepts 1MB, 2MB, 4MB and 16MB SIMMs on motherboard # Classic (4/15) and LX (4/30) accepts 4MB and 16MB SIMMs on motherboard # Can accept 32MB SIMMs in bank 1, allowing 128MB total (2x32, 4x16) # Possibly accepts 8MB SIMMs in bank 1 # 501-2289 (1MB), 501-2433 (2MB) on Classic-X only # 501-1991 (4MB), 501-2059 (16MB) # 36-bit 72-pin 60ns Fast Page Mode $devname="Sunergy"; if ($model =~ /SPARCclassic-X/) { $untested=1; @simmsizes=(1,2,4,8,16,32); } else { $untested=0; @simmsizes=(4,8,16,32); } $simmrangex="00000020"; $simmbanks=3; $simmsperbank=2; @socketstr=("U0304","U0303","U0301","U0302","U0402","U0401"); @bankstr=(1,1,2,2,3,3); } if ($model eq "S240") { # Voyager has 16MB on motherboard, plus accepts one or two 16MB or 32MB # Memory cards (501-2327 32MB, 501-2366 16MB) # Motherboard, address 0x00000000-0x007fffff, 0x01000000-0x017fffff # Lower slot=Mem 1, address 0x02000000-0x07ffffff # Upper slot=Mem 2, address 0x0a000000-0x0fffffff $devname="Gypsy"; $untested=0; $memtype="memory card"; $sockettype="slot"; $simmrangex="00000020"; $simmbanks=8; # Count the skipped address range $simmsperbank=1; @simmsizes=(16,32); @socketstr=("motherboard","Mem 1","Mem 1","Mem 1","?","Mem 2","Mem 2","Mem 2"); @orderstr=("","lower slot","lower slot","lower slot","?","upper slot","upper slot","upper slot"); } if ($model eq "JavaEngine1") { # Accepts 8MB, 16MB and 32MB EDO DIMMs $devname="Bali"; $untested=0; $memtype="DIMM"; $simmrangex="00000020"; $simmbanks=2; $simmsperbank=1; @simmsizes=(8,16,32); @socketstr=("J0501","J0502"); @bankstr=(0,1); } if ($model eq "SPARCstation-4") { # Accepts 8MB and 32MB SIMMs on motherboard # 501-2470 (8MB), 501-2471 (32MB) # 168-pin 60ns Fast Page Mode $devname="Perigee"; $untested=0; $simmrangex="00000020"; $simmbanks=5; $simmsperbank=1; @simmsizes=(8,32); @socketstr=("J0301".."J0305"); @bankstr=(0..4); } if ($model eq "SPARCstation-5" || $model eq "micro COMPstation 5" || $model =~ /Axil-255/ || $banner =~ /TWINstation 5G\b/) { # Accepts 8MB and 32MB SIMMs on motherboard # 501-2470 (8MB), 501-2471 (32MB) # 168-pin 60ns Fast Page Mode $devname="Aurora" if ($model eq "SPARCstation-5"); $untested=0; $simmrangex="00000020"; $simmbanks=8; $simmsperbank=1; @simmsizes=(8,32); @socketstr=("J0300".."J0303","J0400".."J0403"); @bankstr=(0..7); if ($banner =~ /TWINstation 5G\b/) { $simmbanks=6; @socketstr=(0..5); } if ($model ne "SPARCstation-5") { $bannermore="SPARCstation 5 clone"; $modelmore="SPARCstation 5 clone"; } } if ($model =~ /SPARCstation-10/ || $model eq "Premier-24" || $motherboard eq "SUNW,S10,501-2365") { # Accepts 16MB and 64MB SIMMs on motherboard # 501-1785 or 501-2273 (16MB 80ns), 501-2479 (16MB 60ns), # 501-2622 (32MB 60ns), 501-1930 (64MB 80ns), 501-2480 (64MB 60ns) # 200-pin 60ns or 80ns Fast Page Mode ECC # 32MB SIMMs not supported according to Sun, but appears to work fine # depending on the OBP revision. OBP 2.12 and older detects the 32MB # SIMM as 16MB, OBP 2.19 and later properly detects the 32MB SIMM. $devname="Campus2" if ($model =~ /SPARCstation-10/); $devname="Campus2+" if ($model =~ /Premier-24/); $untested=0; $simmrangex="00000040"; $simmbanks=8; $simmsperbank=1; $romvernum="2.X" if (! $romvernum); $romverminor=0 if (! $romverminor || $romverminor eq "X"); @simmsizes=(($romvermajor eq 2) && ($romverminor >= 19)) ? (16,32,64) : (16,64); @socketstr=("J0201","J0203","J0302","J0304","J0202","J0301","J0303","J0305"); @orderstr=("1st","3rd","4th","2nd","8th","6th","5th","7th"); @bankstr=(0..7); } if ($model =~ /SPARCstation-20|COMPstation-20S/ || $banner =~ /TWINstation 20G\b/) { # Accepts 16MB, 32MB and 64MB SIMMs on motherboard # 501-2479 (16MB), 501-2622 (32MB), 501-2480 (64MB) # 200-pin 60ns Fast Page Mode ECC $devname="Kodiak" if ($model eq "SPARCstation-20"); $untested=0; $simmrangex="00000040"; $simmbanks=8; $simmsperbank=1; @simmsizes=(16,32,64); @socketstr=("J0201","J0303","J0202","J0301","J0305","J0203","J0302","J0304"); @orderstr=("1st","2nd","3rd","4th","5th","6th","7th","8th"); @bankstr=(0..7); if ($model !~ /SPARCstation-20/) { $bannermore="SPARCstation 20 clone"; $modelmore="SPARCstation 20 clone"; } if ($model eq "SPARCstation-20I") { $bannermore="(SPARCstation-20I) clone"; $modelmore="clone"; } if ($banner =~ /TWINstation 20G\b/) { # @socketstr=("J0201","J0303","J0202","J0301","J0305","J0203","J0302","J0304"); # @orderstr=("1st","6th","2nd","4th","8th","3rd","5th","7th"); @socketstr=(0..7); @orderstr=(""); } } if ($model eq "SPARCsystem-600" || $model =~ /Sun.4.600/) { # Accepts 4MB or 16MB SIMMs on motherboard # Accepts 1MB, 4MB or 16MB SIMMs on VME expansion cards # A memory bank is 16 SIMMs of the same size and speed # Minimum memory configuration is 16 SIMMs in Bank 0 on the motherboard # Motherboard Bank 1 must be populated before adding expansion cards # Up to two VME memory expansion cards can be added # Use 4MB SIMM 501-1739-01 or 501-2460-01 # Use 16MB SIMM 501-2060-01 $devname="Galaxy"; $untested=0; $simmrangex="00000100"; $simmbanks=2; # 2 banks on CPU board, 4 banks on each expansion cards $simmsperbank=16; @simmsizes=(4,16); # Sockets, banks and bytes on motherboard @socketstr=("U1107","U1307","U1105","U1305","U1103","U1303","U1101","U1301","U1207","U1407","U1205","U1405","U1203","U1403","U1201","U1401","U1108","U1308","U1106","U1306","U1104","U1304","U1102","U1302","U1208","U1408","U1206","U1406","U1204","U1404","U1202","U1402"); @bankstr=(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1); @banksstr=("Motherboard bank 0","Motherboard bank 1"); @bytestr=("0L0","0L1","1L0","1L1","2L0","2L1","3L0","3L1","4L0","4L1","5L0","5L1","6L0","6L1","7L0","7L1","0H0","0H1","1H0","1H1","2H0","2H1","3H0","3H1","4H0","4H1","5H0","5H1","6H0","6H1","7H0","7H1"); # Sockets, banks and bytes on VME expansion cards @socketstr_exp=("U1501","U1503","U1505","U1507","U1601","U1603","U1605","U1607","U1701","U1703","U1705","U1707","U1801","U1803","U1805","U1807","U1502","U1504","U1506","U1508","U1602","U1604","U1606","U1608","U1702","U1704","U1706","U1708","U1802","U1804","U1806","U1808","U1901","U1903","U1905","U1907","U2001","U2003","U2005","U2007","U2101","U2103","U2105","U2107","U2201","U2203","U2205","U2207","U1902","U1904","U1906","U1908","U2002","U2004","U2006","U2008","U2102","U2104","U2106","U2108","U2202","U2204","U2206","U2208"); @bankstr_exp=("B0","B0","B0","B0","B0","B0","B0","B0","B0","B0","B0","B0","B0","B0","B0","B0","B1","B1","B1","B1","B1","B1","B1","B1","B1","B1","B1","B1","B1","B1","B1","B1","B2","B2","B2","B2","B2","B2","B2","B2","B2","B2","B2","B2","B2","B2","B2","B2","B3","B3","B3","B3","B3","B3","B3","B3","B3","B3","B3","B3","B3","B3","B3","B3"); @bytestr_exp=("0L0","0L1","1L0","1L1","2L0","2L1","3L0","3L1","4L0","4L1","5L0","5L1","6L0","6L1","7L0","7L1","0H0","0H1","1H0","1H1","2H0","2H1","3H0","3H1","4H0","4H1","5H0","5H1","6H0","6H1","7H0","7H1","8L0","8L1","9L0","9L1","aL0","aL1","bL0","bL1","cL0","cL1","dL0","dL1","eL0","eL1","fL0","fL1","8H0","8H1","9H0","9H1","aH0","aH1","bH0","bH1","cH0","cH1","dH0","dH1","eH0","eH1","fH0","fH1"); } if ($model eq "Ultra-1" || $ultra eq 1) { # Accepts 16MB, 32MB, 64MB or 128MB DIMMs on motherboard # 501-2479 (16MB), 501-2622 (32MB), 501-2480 or 501-5691 (64MB), # 501-3136 (128MB) # 200-pin 60ns Fast Page Mode ECC $devname="Neutron (Ultra 1), Electron (Ultra 1E), Dublin (Ultra 150)"; $familypn="A11 (Ultra 1), A12 (Ultra 1E)"; $untested=0; $simmrangex="00000100"; $simmbanks=4; $simmsperbank=2; @simmsizes=(16,32,64,128); @socketstr=("U0701","U0601","U0702","U0602","U0703","U0603","U0704","U0604"); @bankstr=("0L","0H","1L","1H","2L","2H","3L","3H"); @bytestr=("00-15","16-31","00-15","16-31","00-15","16-31","00-15","16-31"); } if ($model eq "Ultra-2" || $ultra eq 2) { # Accepts 16MB, 32MB, 64MB or 128MB DIMMs on motherboard $devname="Pulsar"; $familypn="A14"; $untested=0; $simmrangex="00000200"; $simmbanks=4; $simmsperbank=4; @simmsizes=(16,32,64,128); @socketstr=("U0501","U0401","U0701","U0601","U0502","U0402","U0702","U0602","U0503","U0403","U0703","U0603","U0504","U0404","U0704","U0604"); @groupstr=(0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3); @bankstr=("0L","0H","1L","1H","0L","0H","1L","1H","0L","0H","1L","1H","0L","0H","1L","1H"); @bytestr=("00-15","16-31","32-47","48-63","00-15","16-31","32-47","48-63","00-15","16-31","32-47","48-63","00-15","16-31","32-47","48-63"); } if ($model eq "Ultra-30" || $ultra eq 30) { # Also Netra t 1100 # Accepts 16MB, 32MB, 64MB or 128MB DIMMs on motherboard # 501-2479 (16MB), 501-2622 (32MB), 501-2480 or 501-5691 (64MB), # 501-3136 (128MB) # 200-pin 60ns Fast Page Mode ECC # Two DIMMs form a pair, two pairs of DIMMs form a quad. # Minimum requirements is two DIMMs in any adjacent pair. # DIMMs can be installed in any order of pairs. # Interleaving requires a fully populated quad. # Each quad addresses 512MB of memory. $devname="Quark (Ultra-30), Lightweight (Netra t 1100)"; $familypn="A16 (Ultra-30), N01 (Netra t 1100)"; $untested=0; # simmrangex, simmbanks, and simmsperbank set later after determining # if interleaving banks using quads rather than pairs @simmsizes=(16,32,64,128); @socketstr=("U0701","U0801","U0901","U1001","U0702","U0802","U0902","U1002","U0703","U0803","U0903","U1003","U0704","U0804","U0904","U1004"); @bankstr=("Quad 0 Pair 0","Quad 0 Pair 0","Quad 0 Pair 1","Quad 0 Pair 1","Quad 1 Pair 0","Quad 1 Pair 0","Quad 1 Pair 1","Quad 1 Pair 1","Quad 2 Pair 0","Quad 2 Pair 0","Quad 2 Pair 1","Quad 2 Pair 1","Quad 3 Pair 0","Quad 3 Pair 0","Quad 3 Pair 1","Quad 3 Pair 1"); } if ($model eq "Ultra-5_10" || $ultra eq "5_10" || $ultra eq 5 || $ultra eq 10) { # Accepts 16MB, 32MB, 64MB, 128MB or 256MB DIMMs on motherboard # 16MB DIMM uses 10-bit column addressing and was not sold # 32, 64, 128 and 256MB DIMMs use 11-bit column addressing # Do not mix 16MB DIMMs with other sizes # 256MB DIMM not supported in Ultra 5 according to Sun documentation, # but they do work as long as you use low-profile DIMMs or take out the # floppy drive. # Memory speed is 60ns if 50ns and 60ns DIMMs are mixed # 2-way interleaving supported with four identical sized DIMMs # 50ns DIMMs supported on 375-0066 & 375-0079 motherboards # Bank 0 DIMM1/DIMM2 0x00000000-0x0fffffff, 0x20000000-0x2fffffff # Bank 1 DIMM3/DIMM4 0x10000000-0x1fffffff, 0x30000000-0x3fffffff $devname="Darwin/Otter (Ultra 5), Darwin/SeaLion (Ultra 10)"; $familypn="A21 (Ultra 5), A22 (Ultra 10)"; $untested=0; $simmrangex="00000100"; $simmbanks=2; $simmsperbank=2; @simmsizes=(16,32,64,128,256); @socketstr=("DIMM1".."DIMM4"); @bankstr=("0L","0H","1L","1H"); $sortslots=0; } if ($model eq "Ultra-60" || $ultra eq 60 || $ultra eq "220R") { # Also Netra t1120/1125 # Accepts 16MB, 32MB, 64MB or 128MB DIMMs on motherboard # 501-2479 (16MB), 501-2622 (32MB), 501-2480 or 501-5691 (64MB), # 501-3136 (128MB) # 200-pin 60ns Fast Page Mode ECC # U1001-U1004 bank 3 address 0xa0000000-0xbfffffff # U0901-U0904 bank 2 address 0x80000000-0x9fffffff # U0801-U0804 bank 1 address 0x20000000-0x3fffffff # U0701-U0704 bank 0 address 0x00000000-0x1fffffff if ($model eq "Ultra-60" || $ultra eq 60) { $devname="Deuterium (Ultra-60), Lightweight 2 (Netra t112x)"; $familypn="A23 (Ultra-60), N02/N04 (Netra t1120), N03 (Netra t1125)"; } if ($ultra eq "220R") { $devname="Razor"; $familypn="A34"; } $untested=0; $simmrangex="00000200"; $simmbanks=6; # Count the skipped address range $simmsperbank=4; @simmsizes=(16,32,64,128); @socketstr=("U0701".."U0704","U0801".."U0804","?","?","?","?","?","?","?","?","U0901".."U0904","U1001".."U1004"); @bankstr=(0,0,0,0,1,1,1,1,"?","?","?","?","?","?","?","?",2,2,2,2,3,3,3,3); } # # SPARCengine systems # if ($banner =~ /(Netra t1|Ultra CP 1500)\b/ || $ultra eq "Netra t1" || $model eq "Netra t1" || $ultra eq "CP1500" || $ultra eq "Netra ct400" || $ultra eq "Netra ct410" || $ultra eq "Netra ct800" || $ultra eq "Netra ct810") { # Netra t1 100/105, Netra ct400/410/800/810, SPARCengine CP1500 # Accepts 1 or 2 64MB, 128MB, 256MB or 512MB mezzanine memory cards # Netra ct400/800 use the Netra ct1600 DC chassis (N08) # Netra ct410/810 use the Netra ct1600 AC chassis (N09) # Also used in Sun Fire 12K & Sun Fire 15K # Install the highest capacity memory board first # The 370-4155 was sold for use in the Netra t1 100/105 # Up to four 370-4155 256MB memory boards can be installed # Only one 370-4155 can be mixed with any other memory boards # Cannot distinguish between 4 370-4155 256MB and 2 512MB memory boards # Maximum memory: 768MB for 270MHz/33MHz, 1GB for 360MHz/440MHz systems # # Top slot -> 64MB 64MB 128MB 128MB 256MB 256MB 512MB # Bottom slot SSF SS DSF SS SSF SS DSF SS DSF DS DSF SS DSF DS # | # v ------ ------ ------ ------ ------ ------ ------ # 64MB SSF SS Y N Y N N Y N # 64MB DSF SS Y Y Y Y Y Y Y # 128MB SSF SS Y N Y N N Y N # 128MB DSF SS Y Y Y Y Y Y Y # 256MB DSF SS Y Y Y Y Y Y Y # 512MB DSF DS Y/N * Y/N * Y/N * Y/N * Y/N * Y/N * Y/N * # # SSF=single-sided fab, DSF=double-sided fab # SS=stuffed on one side, DS=stuffed on both sides # * 512MB DSF DS board is supported on 360MHz and 440MHz systems, # 512MB DSF DS board is not supported on 270MHz and 333MHz systems # Lower board, address 0x00000000-0x0fffffff, 0x20000000-0x2fffffff # upper board, address 0x10000000-0x1fffffff, 0x30000000-0x3fffffff if ($banner =~ /Netra t1\b/ || $ultra eq "Netra t1" || $model eq "Netra t1") { $devname="Flyweight (Model 100), Flapjack (Model 105)"; $familypn="N07 (Model 100), N06 (Model 105)"; } $devname="Tonga" if ($ultra eq "Netra ct400"); $devname="Monte Carlo" if ($ultra eq "Netra ct800"); $familypn="N08" if ($ultra =~ /Netra ct[48]00/); if ($ultra =~ /Netra ct[48]10/) { $devname="Makaha"; $familypn="N09"; } $untested=0; $untested=1 if ($ultra eq "Netra ct400" || $ultra =~ /Netra ct[48]10/); $memtype="memory card"; $sockettype=""; $simmrangex="00000100"; $simmbanks=2; $simmsperbank=1; @simmsizes=(64,128,256,512); @socketstr=("base mezzanine board","additional mezzanine board"); @orderstr=("lower board","upper board"); $sortslots=0; } if ($banner =~ /Ultra CP 1400\b/ || $ultra eq "CP1400") { # Accepts 1 or 2 64MB, 128MB, 256MB or 512MB mezzanine memory cards # Has 64MB on-board memory on motherboard # Maximum memory: 832MB (64MB motherboard, 512MB bottom, 256MB top) # # Top slot -> 64MB 64MB 128MB 128MB 256MB 512MB # Bottom slot SSF SS DSF SS SSF SS DSF SS DSF SS DSF DS # | # v ------ ------ ------ ------ ------ ------ # 64MB SSF SS Y N Y N Y N # 64MB DSF SS Y Y Y Y Y N # 128MB SSF SS Y N Y N Y N # 128MB DSF SS Y Y Y Y Y N # 256MB DSF SS Y Y Y Y Y N # 512MB DSF DS Y Y Y Y Y N # # SSF=single-sided fab, DSF=double-sided fab # SS=stuffed on one side, DS=stuffed on both sides # 512MB DSF DS board is only supported in bottom slot # # Motherboard, address 0x00000000-0x03ffffff # Upper board, address 0x08000000-0xffffffff, 0x28000000-0x2fffffff # Lower board, address 0x10000000-0x17ffffff, 0x30000000-0x37ffffff $devname="Casanova"; $untested=0; $memtype="memory card"; $sockettype=""; $simmrangex="00000080"; $simmbanks=3; $simmsperbank=1; @simmsizes=(64,128,256,512); @socketstr=("motherboard","additional mezzanine board","base mezzanine board"); @orderstr=("","upper board","lower board"); $sortslots=0; } if ($ultra eq "AX" || $ultra eq "AX-300") { # SPARCengine Ultra AX and AX-300 # Accepts 8MB, 16MB, 32MB or 64MB DIMMs on motherboard # AX-300 also accepts 128MB DIMMs on motherboard $devname="Photon"; $untested=0; # unsure if socket order is correct $simmrangex="00000200"; $simmbanks=2; $simmsperbank=4; @simmsizes=(8,16,32,64,128); @socketstr=("U0301".."U0304","U0401".."U0404"); @bankstr=(0,0,0,0,1,1,1,1); } if ($ultra eq "AXi") { # SPARCengine Ultra AXi # Accepts 8MB, 16MB, 32MB, 64MB or 128MB single or dual bank 10-bit # column address type DIMMs on motherboard in all socket pairs # Accepts 8MB, 16MB, 32MB, 64MB, 128MB or 256MB dual bank 11-bit # column address type DIMMs on motherboard in Pairs 0 & 2 # (leave Pairs 1 & 3 empty) # DIMMs should be chosen as all 10-bit or all 11-bit column address type # Use 60ns DIMMs only #$devname="unknown"; $untested=0; $simmrangex="00000100"; $simmbanks=4; $simmsperbank=2; @simmsizes=(8,16,32,64,128,256); @socketstr=("U0404","U0403","U0304","U0303","U0402","U0401","U0302","U0301"); @bankstr=(0,0,2,2,1,1,3,3); $sortslots=0; } if ($ultra eq "AXmp" || $ultra eq "AXmp+") { # SPARCengine Ultra AXmp # Accepts 8MB, 16MB, 32MB, 64MB or 128MB DIMMs on motherboard # Accepts 256MB dual-bank DIMMs in bank 0 or 1 (not both) # Can't distinguish dual-bank DIMMs from two banks of single bank DIMMs # SPARCengine Ultra AXmp+ # Accepts 8MB, 16MB, 32MB, 64MB, 128MB or 256MB DIMMs on motherboard # Accepts dual-bank DIMMs in both bank 0 and 1 # Can't distinguish dual-bank DIMMs from two banks of single bank DIMMs $devname="Crichton"; $untested=0; $simmbanks=2; $simmsperbank=8; if ($ultra eq "AXmp+") { $simmrangex="00000400"; @simmsizes=(8,16,32,64,128,256); } else { $simmrangex="00000800"; @simmsizes=(8,16,32,64,128); } @socketstr=("U0701".."U0704","U0801".."U0804","U0901".."U0904","U1001".."U1004"); @bankstr=(0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1); $sortslots=0; } if ($ultra eq "AXe") { # SPARCengine Ultra AXe # Accepts 32MB, 64MB, 128MB or 256MB single or dual bank DIMMs # DIMMs should be chosen as all 10-bit or all 11-bit column address type $devname="Topdog"; $untested=0; $simmrangex="00000100"; $simmbanks=2; $simmsperbank=2; @simmsizes=(32,64,128,256); @socketstr=("DIMM3","DIMM4","DIMM1","DIMM2"); @bankstr=(0,0,1,1); # Assume stacked DIMMs like AXi since only 128MB DIMMs have been tested $sortslots=0; } if ($ultra eq "AX-e2") { # Netra AX1105-500 # Accepts up to 4 64MB, 128MB, 256MB or 512MB registered SDRAM PC133 # DIMMs; 128MB Minimum, 2GB Maximum # DIMM0 & DIMM1 form Bank 0, DIMM2 & DIMM3 form Bank 1 # DIMMs don't have to be installed as pairs $devname="Birdsnest Lite"; $untested=0; $simmrangex="00000200"; $simmbanks=4; $simmsperbank=1; @simmsizes=(64,128,256,512); @socketstr=("DIMM0".."DIMM3"); @bankstr=(0,0,1,1); } if ($ultra eq "Netra X1" || $ultra eq "Sun Fire V100") { # Netra X1, Sun Fire V100, UltraAX-i2 # Accepts up to 4 128MB or 256MB PC133 DIMMs for 1GB maximum # 500MHz model also accepts up to 4 512MB PC133 DIMMs for 2GB maximum # Have seen slower models also work with 512MB DIMMs for 2GB maximum # Sun Fire V100 is 500MHz only # The memory installation sequence is Slot 3, 2, 1, and 0. # Each DIMM slot addresses 512MB with 400MHz UltraSPARC IIe # Each DIMM slot addresses 1GB with >= 550MHz UltraSPARC IIe # Memory is SDRAM PC133 CL=3 ECC registered # When equal size DIMMs are installed, the lowest slot number is # mapped to the lowest address range. # When mixed size DIMMs are installed, the slot number with the largest # size DIMM is mapped to the lowest address range. $devname="Flapjack-lite" if ($ultra eq "Netra X1"); $devname="Flapjack-liteCD500" if ($ultra eq "Sun Fire V100"); $familypn="N19"; $untested=0; $simmrangex=($cpufreq > 520) ? "00000400" : "00000200"; $simmbanks=4; $simmsperbank=1; @simmsizes=(128,256,512); @socketstr=("DIMM0".."DIMM3"); } if ($ultra eq "Netra T1 200" || $ultra eq "Sun Fire V120" || $ultra eq "Netra 120") { # Netra T1 200, Sun Fire V120, Netra 120, UltraAX-i2 # Accepts up to 4 256MB, 512MB or 1GB PC133 DIMMs for 4GB maximum # Sun Fire V120 is 550MHz or 650MHz # Netra 120 is same platform as Sun Fire V120, but is 650MHz only # Memory is SDRAM PC133 CL=3 ECC registered # The minimum memory requirement is one DIMM in Slot 0 # The memory installation sequence is Slot 0, 1, 2, 3 # Each DIMM slot addresses 512MB of memory with 500MHz UltraSPARC IIe # Each DIMM slot addresses 1GB of memory with >= 550MHz UltraSPARC IIe # When equal size DIMMs are installed, the lowest slot number is # mapped to the lowest address range. # When mixed size DIMMs are installed, the slot number with the largest # size DIMM is mapped to the lowest address range. if ($ultra eq "Netra T1 200") { $devname="Flapjack2"; $familypn="N21"; } if ($ultra eq "Sun Fire V120" || $ultra eq "Netra 120") { $devname="Flapjack2+"; $familypn="N25"; } $untested=0; $simmrangex=($cpufreq > 520) ? "00000400" : "00000200"; $simmbanks=4; $simmsperbank=1; @simmsizes=(256,512,1024); @socketstr=("DIMM0".."DIMM3"); } if ($banner =~ /\bCP2000\b/ || $ultra =~ /^CP2[01]\d0$/) { # Netra CP2000/CP2100 Series CompactPCI Boards (UltraSPARC-IIe) # CP2040 (SUNW,UltraSPARC-IIe-NetraCT-40) supports 256MB, 512MB, and 1GB # CP2060 (SUNW,UltraSPARC-IIe-NetraCT-60) has non-expandable 512MB # CP2080 (SUNW,UltraSPARCengine_CP-80) supports 256MB, 512MB, and 1GB # CP2140 (SUNW,UltraSPARCengine_CP-40) supports 512MB, 1GB and 2GB # CP2160 (SUNW,UltraSPARCengine_CP-60) supports 1GB and 2GB # 256MB Single-Wide module 375-3024 # 512MB Single-Wide module 375-3025 # 1GB Double-Wide module 375-3026 # 1GB Single-Wide module 375-3125 # 2GB Double-Wide module 375-3114 # Max number of stacked memory boards is two # Install double wide memory first, then single wide memory $devname="Othello" if ($ultra eq "CP2040"); $devname="Sputnik Bluesky" if ($ultra eq "CP2060"); $devname="Sputnik Orion" if ($ultra eq "CP2080"); $devname="Othello+" if ($ultra eq "CP2140"); $devname="Sputnik+" if ($ultra eq "CP2160"); $untested=1; $untested=0 if ($ultra eq "CP2140"); if ($ultra eq "CP2060") { $memtype="embedded memory"; $sockettype=""; $simmrangex="00001000"; $simmbanks=1; $simmsperbank=1; @simmsizes=(512); } else { $memtype="memory card"; $sockettype=""; $simmrangex="00001000"; $simmbanks=2; $simmsperbank=1; if ($ultra eq "CP2140") { @simmsizes=(512,1024,2048); } elsif ($ultra eq "CP2160") { @simmsizes=(1024,2048); } else { @simmsizes=(256,512,1024); } @socketstr=("base mezzanine board","additional mezzanine board"); @orderstr=("lower board","upper board"); $sortslots=0; } } # # Clones: most do not have verbose output since I don't have any socket data # on them # if ($ultra eq "axus250" || $modelmore =~ /Ultra-250/) { # AXUS Microsystems, Inc. http://www.axus.com.tw # AXUS 250 clone # accepts up to 128MB DIMMs on motherboard $untested=0; $simmrangex="00000200"; $simmbanks=4; $simmsperbank=4; @simmsizes=(8,16,32,64,128); @socketstr=("U0501","U0601","U0701","U0801","U0502","U0602","U0702","U0802","U0503","U0603","U0703","U0803","U0504","U0604","U0704","U0804"); @bankstr=(0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3); } if ($model =~ /SPARC (CPU|CPCI)-/) { # Force Computers, http://www.forcecomputers.com # model format: "SPARC CPU-5V/64-110-X" for 64MB w/ 110MHz CPU $untested=1; $untested=0 if ($model =~ /SPARC CPU-/); if ($model =~ /\/${installed_memory}-/) { $totmem=$installed_memory; push(@simmsizesfound, "$totmem"); $buffer="motherboard contains ${totmem}MB on-board memory\n"; &finish; } } if ($model =~ /Axil/) { # RAVE Computer Association, http://rave.com $untested=1; $untested=0 if ($model =~ /Axil-(245|255|311|320)/); } if ($manufacturer =~ /Tadpole/) { # Tadpole RDI, http://www.tadpole.com $untested=1; $untested=0 if ($banner =~ /Tadpole S3|\bVoyagerIIi\b|\bCycleQUAD\b/); $untested=0 if ($model =~ /PowerLite-170/); if ($ultra eq "UP-20") { # Cycle UP-20 to upgrade SPARCstation 5/20 motherboards # Accepts 16MB, 32MB and 64MB SIMMs from SPARCstation 20 # Install SIMMs in pairs to form each bank $untested=1; $simmrangex="00000040"; $simmbanks=4; $simmsperbank=2; @simmsizes=(16,32,64); @bankstr=(0,0,1,1,2,2,3,3); } if ($ultra eq "UP-520IIi") { # Cycle UP-520-IIi to upgrade SPARCstation 5/20 motherboards # Accepts 8MB, 16MB, 32MB, 64MB, 128MB and 256MB DIMMs $untested=0; $simmrangex="00000200"; $simmbanks=4; $simmsperbank=2; @simmsizes=(8,16,32,64,128,256); @socketstr=("J301".."J304"); @bankstr=(0,0,1,1); } if ($banner =~ /\bSPARCLE\b/) { # UltraSPARC-IIe at 440MHz, 500MHz, or 650MHz # 256MB - 2GB ECC SDRAM, two slots, PC-133, 144-pin SO-DIMMs $untested=0; $simmbanks=2; $simmsperbank=1; @simmsizes=(128,256,512,1024); @socketstr=("DIMM0","DIMM1"); $memtype="SO-DIMM"; } } if ($manufacturer eq "Auspex") { # Auspex Netserver, http://www.auspex.com $memtype="Memory Module"; $untested=1; $untested=0 if ($model eq "SPARC Processor"); if ($osrel =~ /^5./) { $untested=1; # Untested with Solaris 2.X $untested_type="OS"; } } if ($manufacturer =~ /Fujitsu/) { # Hal Computer Systems, a Fujitsu Company, http://www.hal.com # Fujitsu Siemens, http://www.fujitsu-siemens.com $untested=1; $untested=0 if ($model =~ /S-4\/10H|S-4\/20[ABLH]/); if ($banner =~ /(GP7000|GP7000F)\b/) { $untested=0; if ($slotname0 =~ /SLOT[0-9]/) { # M200 # Up to 4GB of memory # System board has 16 DIMM slots, #00 - #15 # Banks - 0,0,1,1,2,2,2,2,3,3,3,3,4,4,4,4 # First Modules installed in Bank 0, slots 0-1 # Second Modules Installed in Bank 1, slots 2-3 # Modules in Bank 0 and 1 must be same size # Subsequent memory expansion installed in sets of four # modules in Bank 2 - 4 (Slots 4-7, 8-11, 12-15) @socketstr=("SLOT0".."SLOT9","SLOT10".."SLOT15"); } if ($slotname0 =~ /SLOT[AB][0-9]/) { # M400 and M600 # Up to 4GB of memory # System board has 32 DIMM slots, #00 - #15 Group A & B # Banks - 0,0,1,1,2,2,2,2,3,3,3,3,4,4,4,4 # First Modules installed in Bank 0 Group A, slots 0-1 # Second Modules installed in Bank 0 Group B, slots 0-1 # Modules in Group A and B must be same size # Next memory expansion installs in Bank 1 Group A & B, # slots 2-3 using modules of same size as Bank 0 # Subsequent memory expansion installed in sets of eight # modules in Bank 2 - 4 (Slots 4-7, 8-11, 12-15) in # both Group A and B @socketstr=("SLOTA0".."SLOTA9","SLOTA10".."SLOTA15","SLOTB0".."SLOTB9","SLOTB10".."SLOTB15"); } } if ($banner =~ /PRIMEPOWER *100N?\b/) { # PRIMEPOWER100N, 1U rack mount # Up to 2GB of memory # 4 memory module slots # 100MHz SDRAM ECC # Mount memory modules in order from memory module slot 0 $untested=1; } if ($banner =~ /PRIMEPOWER *[246]00\b/) { # Up to 8GB of memory # Each system board has 16 DIMM slots, #00 - #15 # Four banks of 4 (0-3,4-7,8-11,12-15) # PrimePower 200 and 400 use 1 system board # PrimePower 600 uses 2 system boards (00, 01) $untested=0; foreach $brd ("00","01") { if ($gotcpuboards =~ /\b$brd\b/) { if ($gotmodulenames =~ /${brd}-SLOT[0-9]/) { foreach $i (0..15) { push(@socketstr, ("${brd}-SLOT$i")); } } } } } if ($banner =~ /PRIMEPOWER *(800|1000|2000)\b/) { # 1-4 SPARC64 GP CPUs / system board # PrimePower 800 can have 4 system boards per system # PrimePower 1000 can have 8 system boards per system # PrimePower 2000 can have 32 system boards per system # Minimum Memory: 1GB / system board, 2GB / system # Maximum Memory: 8GB / system board, 32GB / system # 32 or 16 memory modules per system board, installed in quads $untested=0; @simmsizes=(128,256,512); foreach $brd ("00".."77") { if ($gotcpuboards =~ /\b$brd\b/) { if ($gotmodulenames =~ /${brd}-SLOT#[AB][0-9]/) { foreach $j ("A","B") { foreach $i ("00".."03","10".."13","20".."23","30".."33") { push(@socketstr, ("${brd}-SLOT#$j$i")); } } } } } } if ($banner =~ /PRIMEPOWER *250\b/) { # Pedestal, 2U or 4U rack mount # 1-2 SPARC64 V processors at 1.1GHz, 1.32GHz, 1.87GHz # 1GB-16GB DDR-SDRAM memory with ECC, 2-way, 8 DIMM slots $untested=0; @simmsizes=(256,512,1024,2048); foreach $i ("00".."07") { push(@socketstr, ("SLOT#$i")); } } if ($banner =~ /PRIMEPOWER *450\b/) { # Pedestal, 4U or 7U rack mount # 1-4 SPARC64 V processors at 1.1GHz, 1.32GHz, 1.87GHz # 1GB-32GB DDR-SDRAM memory with ECC, 4-way, 16 DIMM slots $untested=0; @simmsizes=(256,512,1024,2048); foreach $i ("00".."15") { push(@socketstr, ("SLOT#$i")); } } if ($banner =~ /PRIMEPOWER *[68]50\b/) { # PrimePower 650: 2-8 SPARC64 V processors at 1.1GHz or faster # 2GB-64GB memory, 8-way, 1 system board, 8U rack mount # PrimePower 850: 4-16 SPARC64 V processors at 1.1GHz or faster # 2GB-128GB memory, 16-way, 2 system boards, 16U rack mount # Uses DDR SDRAM ECC memory in 256MB, 512MB and 1GB sizes # Each system board has 32 memory module slots, laid out # with 4 DIMMs on 8 DIMM riser cards. $untested=0; @simmsizes=(256,512,1024,2048); foreach $brd ("C0S00","C0S01") { if ($gotcpuboards =~ /\b$brd\b/) { if ($gotmodulenames =~ /${brd}-SLOT#[A-D][0-9]/) { foreach $j ("A".."D") { foreach $i ("00".."07") { push(@socketstr, ("${brd}-SLOT#$j$i")); } } } } } } if ($banner =~ /PRIMEPOWER *(HPC2500|900|[12]500)\b/) { # SPARC64 V CPUs at 1.3GHz or 1.89GHz # PRIMEPOWER HPC2500 / 2500 # 2-8 CPUs / system board, 64-128 / system # Up to 16 8-way system boards / system # Up to 1024GB DDR-SDRAM memory with ECC, 128-way # Minimum Memory: 4GB / system board, 4GB / system # Maximum Memory: 64GB / system board, 1024GB / system # PRIMEPOWER 900 # 17U rack mount # 1-8 CPUs / system board, 1-16 / system # Up to 2 8-way system boards / system # Up to 128GB DDR-SDRAM memory with ECC, 8-way # Minimum Memory: 2GB / system board, 2GB / system # Maximum Memory: 64GB / system board, 128GB / system # PRIMEPOWER 1500 # 1-8 CPUs / system board, 1-32 / system # Up to 4 8-way system boards / system # Up to 256GB DDR-SDRAM memory with ECC, 8-way # Minimum Memory: 2GB / system board, 2GB / system # Maximum Memory: 64GB / system board, 256GB / system $untested=0; @simmsizes=(256,512,1024,2048); foreach $cab ("C0S","C1S") { foreach $brd ("00".."07") { if ($gotcpuboards =~ /\b$cab$brd\b/) { foreach $j ("A","B") { foreach $i ("00".."15") { push(@socketstr, ("$cab${brd}-SLOT#$j$i")); } } } } } } } if ($model =~ /COMPstation.10/) { # Tatung Science and Technology, http://www.tsti.com # Accepts 16MB and 64MB SIMMs on motherboard # Bank 0 must be filled first # Layout is like SPARCstation-10, but I don't know if it can accept # 32MB SIMMs or NVSIMMs $untested=0; $simmrangex="00000040"; $simmbanks=8; $simmsperbank=1; @simmsizes=(16,64); @socketstr=("J0201","J0203","J0302","J0304","J0202","J0301","J0303","J0305"); @bankstr=(0,2,4,6,1,3,5,7); } if ($model =~ /COMPstation-20A\b/) { # Tatung Science and Technology, http://www.tsti.com # Accepts 16MB, 32MB and 64MB SIMMs on motherboard $untested=1; $simmrangex="00000040"; $simmbanks=8; $simmsperbank=1; @simmsizes=(16,32,64); @socketstr=("J0201","J0304","J0203","J0302","J0303","J0301","J0305","J0202"); @orderstr=("1st","2nd","3rd","4th","5th","6th","7th","8th"); @bankstr=(1..8); } if ($model =~ /COMPstation-20AL/) { # Tatung Science and Technology, http://www.tsti.com # Accepts 16MB, 32MB and 64MB SIMMs on motherboard $untested=0; $simmrangex="00000040"; $simmbanks=8; $simmsperbank=1; @simmsizes=(16,32,64); @socketstr=("J0201","J0203","J0302","J0304","J0202","J0301","J0303","J0305"); @orderstr=("1st","2nd","3rd","4th","5th","6th","7th","8th"); @bankstr=(0..7); } if ($banner =~ /COMPstation_U(60|80D)_Series/) { # Tatung Science and Technology, http://www.tsti.com # Accepts 16MB, 32MB, 64MB, 128MB or 256MB DIMMs on motherboard # 4 banks with 4 DIMMs per bank $untested=0; if ($banner =~ /COMPstation_U60_Series/) { $simmrangex="00000200"; # use "00000400" with 256MB DIMMs $simmbanks=6; # Count the skipped address range } else { $simmrangex="00000400"; $simmbanks=4; } $simmsperbank=4; @simmsizes=(16,32,64,128,256); } if ($model =~ /\bVoyagerIIi\b/) { # Tadpole Voyager IIi has 8 DIMM slots, but otherwise appears # to look like an Ultra 5. It allows 256MB to 1GB of memory. $untested=0; $simmrangex="00000100"; $simmbanks=4; $simmsperbank=2; @simmsizes=(16,32,64,128); @socketstr=("DIMM1","DIMM2","DIMM5","DIMM6","DIMM3","DIMM4","DIMM7","DIMM8"); $sortslots=1; } # # systems below may have memory information available in prtdiag output # if ($model eq "SPARCserver-1000" || $model eq "SPARCcenter-2000") { $devname="Scorpion" if ($model eq "SPARCserver-1000"); $devname="Scorpion+" if ($banner =~ "1000E"); $devname="Dragon" if ($model eq "SPARCcenter-2000"); $devname="Dragon+" if ($banner =~ "2000E"); # Accepts 8MB and 32MB SIMMs on motherboard $untested=0; @simmsizes=(8,32); $prtdiag_has_mem=1; &check_prtdiag; if ($boardfound_mem) { $memfrom="prtdiag"; &pdebug("displaying memory from prtdiag"); foreach $line (@boards_mem) { if ($line =~ /Board/) { $boardslot_mem=substr($line,5,1); $simmsize=int substr($line,46,3) / 4; if ($simmsize == 0) { &found_empty_bank("Group 0"); } elsif ($simmsize == 1) { &found_nvsimm_bank("Group 0"); } else { push(@simmsizesfound, "$simmsize"); } $simmsize=int substr($line,54,3) / 4; if ($simmsize == 0) { &found_empty_bank("Group 1"); } elsif ($simmsize == 1) { &found_nvsimm_bank("Group 1"); } else { push(@simmsizesfound, "$simmsize"); } $simmsize=int substr($line,62,3) / 4; if ($simmsize == 0) { &found_empty_bank("Group 2"); } elsif ($simmsize == 1) { &found_nvsimm_bank("Group 2"); } else { push(@simmsizesfound, "$simmsize"); } $simmsize=int substr($line,70,3) / 4; if ($simmsize == 0) { &found_empty_bank("Group 3"); } elsif ($simmsize == 1) { &found_nvsimm_bank("Group 3"); } else { push(@simmsizesfound, "$simmsize"); } } } &show_header; print @boards_mem; print "Each memory unit group is comprised of 4 SIMMs\n"; $empty_banks=" None" if (! $empty_banks); print "empty memory groups:$empty_banks\n"; } else { &show_header; $recognized=0; } $totmem=$installed_memory; &finish; &pdebug("exit"); exit; } if ($model eq "Ultra-4" || $ultra eq 450 || $model eq "Ultra-4FT" || $ultra eq "Netra ft1800") { # Accepts 32MB, 64MB, 128MB or 256MB DIMMs on motherboard # 16MB DIMMs are not supported and may cause correctable ECC errors # 501-2622 (32MB), 501-2480 or 501-5691 (64MB), 501-3136 (128MB), # 501-4743 or 501-5896 (256MB) # 200-pin 60ns Fast Page Mode ECC # Netra ft1800 is based on Ultra 450 $devname="Tazmo (Tazmax/Tazmin)"; $familypn="A20, A25"; $familypn="N05" if ($model eq "Ultra-4FT" || $ultra eq "Netra ft1800"); $untested=0; $simmrangex="00000400"; $simmbanks=4; $simmsperbank=4; @simmsizes=(16,32,64,128,256); @socketstr=("U1901".."U1904","U1801".."U1804","U1701".."U1704","U1601".."U1604"); @groupstr=("A","A","A","A","B","B","B","B","C","C","C","C","D","D","D","D"); @bankstr=(2,2,2,2,3,3,3,3,0,0,0,0,1,1,1,1); } if ($model eq "Ultra-250" || $ultra eq 250) { # Accepts 16MB, 32MB, 64MB, or 128MB DIMMs on motherboard # 501-2479 (16MB), 501-2622 (32MB), 501-2480 or 501-5691 (64MB), # 501-3136 (128MB) # 200-pin 60ns Fast Page Mode ECC $devname="Javelin"; $familypn="A26"; $untested=0; $simmrangex="00000200"; $simmbanks=4; $simmsperbank=4; @simmsizes=(16,32,64,128); @socketstr=("U0701","U0801","U0901","U1001","U0702","U0802","U0902","U1002","U0703","U0803","U0903","U1003","U0704","U0804","U0904","U1004"); @bankstr=("A","A","A","A","B","B","B","B","C","C","C","C","D","D","D","D"); } if ($model eq "Ultra-80" || $ultra eq 80 || $ultra eq "420R" || $ultra eq "Netra t140x") { # Accepts 64MB or 256MB DIMMs # 501-5691 (64MB), 501-4743 501-5936 501-6005 501-6056 (256MB) # 200-pin 60ns 5V Fast Page Mode ECC, 576 bits data width # 64MB DIMMs same as in Ultra-60, 256MB DIMMs same as in Enterprise-450 # U0403,U0404,U1403,U1404 bank 3 address 0xc0000000-0xffffffff # U0303,U0304,U1303,U1304 bank 2 address 0x80000000-0xbfffffff # U0401,U0402,U1401,U1402 bank 1 address 0x40000000-0x7fffffff # U0301,U0302,U1301,U1302 bank 0 address 0x00000000-0x3fffffff # The minimum requirement is four DIMMs in any bank. The recommended # installation sequence is Bank 0,2,1,3. DIMMs are required on both the # Riser Board (U0[34]0?) and the System Board (U1[34]0?). Two-way and # four-way memory bank interleaving is supported. Memory is 2-way # interleaved when the same size DIMMs are installed in Banks 0 and 1. # Memory is 4-way interleaved when the same size DIMMs are installed in # Banks 0, 1, 2 and 3. # # prtconf does not reliably show the size of DIMMs in each slot when # 1GB of total memory is installed. It shows this: # reg: 00000000.00000000.00000000.40000000 # A system with 1GB is reported as having 4 256MB DIMMs, but may be # using 16 64MB DIMMs in a 4-way interleave. # This is an issue that Sun could fix in the OBP. # It is broken with OBP 3.33.0 2003/10/07 (patch 109082-06) and older. # prtfru (Solaris 8 and later) also does not work. # # Sun shipped U80 1GB configurations w/ 4x256MB DIMMs # Sun shipped U80 256MB configurations w/ 4x64MB DIMMs # Sun shipped E420R with 501-5936 256MB DIMMs # 64MB DIMM 501-2480 and 128MB DIMM 501-3136 are not supported. # 16MB and 32MB DIMMs are not sold for the Ultra 80. # $devname="Quasar (U80), Quahog (420R), Lightweight 3 (Netra t140x)"; $familypn="A27 (U80), A33 (420R), N14 (Netra t1405), N15 (Netra t1400)"; if ($ultra eq 80) { $devname="Quasar"; $familypn="A27"; } if ($ultra eq "420R") { $devname="Quahog"; $familypn="A33"; } if ($ultra eq "Netra t140x") { $devname="Lightweight 3"; $familypn="N14 (Netra t1405), N15 (Netra t1400)"; } $untested=0; $simmrangex="00000400"; $simmbanks=4; $simmsperbank=4; @simmsizes=(64,256); # Sun only supports 64MB and 256MB DIMMs @socketstr=("U0301","U0302","U1301","U1302","U0401","U0402","U1401","U1402","U0303","U0304","U1303","U1304","U0403","U0404","U1403","U1404"); @bankstr=(0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3); } if ($ultra eq "Sun Blade 1000" || $ultra eq "Sun Blade 2000" || $ultra eq "Sun Fire 280R" || $ultra eq "Netra 20") { # Accepts up to 8 128MB, 256MB, 512MB, 1GB or 2GB DIMMs installed in # groups of four DIMMs per bank on motherboard # Uses 232-pin 3.3V ECC 7ns SDRAM # J0407 Group 1 Bank 1/3 address 0x0fa000000 - 0x1f3ffffff # J0406 Group 0 Bank 0/2 address 0x000000000 - 0x0f9ffffff # J0305 Group 1 Bank 1/3 address 0x0fa000000 - 0x1f3ffffff # J0304 Group 0 Bank 0/2 address 0x000000000 - 0x0f9ffffff # J0203 Group 1 Bank 1/3 address 0x0fa000000 - 0x1f3ffffff # J0202 Group 0 Bank 0/2 address 0x000000000 - 0x0f9ffffff # J0101 Group 1 Bank 1/3 address 0x0fa000000 - 0x1f3ffffff # J0100 Group 0 Bank 0/2 address 0x000000000 - 0x0f9ffffff # The minimum memory requirement is four DIMMs in any Group # DIMMs can be installed in any group order # Each group addresses 4GB of memory # Memory slots (Jxxxx) map to same-numbered DIMMs (Uxxxx) # For maximum 4-way interleaving, install 8 DIMMs of identical sizes $devname="Excalibur (Sun Blade 1000), Littleneck (Sun Fire 280R), Lightweight 2+ (Netra 20/Netra T4), Sun Blade 2000 (Sun Blade 2000)"; $familypn="A28 (Sun Blade 1000), A35 (Sun Fire 280R), N28 (Netra 20/Netra T4), A29 (Sun Blade 2000)"; if ($ultra eq "Sun Blade 1000") { $devname="Excalibur (Sun Blade 1000), Sun Blade 2000 (Sun Blade 2000)"; $familypn="A28 (Sun Blade 1000), A29 (Sun Blade 2000)"; } if ($ultra eq "Sun Fire 280R") { $devname="Littleneck"; $familypn="A35"; } if ($ultra eq "Netra 20") { $devname="Lightweight 2+"; $familypn="N28"; } if ($ultra eq "Sun Blade 2000") { $devname="Sun Blade 2000"; $familypn="A29"; } $untested=0; # SB1000/2000 uses 501-4143, 501-5938, 501-6230 or 501-6560 motherboards # SB1000 can use 600, 750 and 900MHz UltraSPARC-III CPUs # SB1000 can use 900MHz and faster UltraSPARC-III+ Cu CPUs # SB2000 only shipped with 900MHz and faster UltraSPARC-III+ Cu CPUs # SB2000 can use any of the SB1000 motherboards if ($ultra eq "Sun Blade 1000") { $modelmore=$banner; $modelmore=~s/Sun-Blade-1000/or Sun-Blade-2000/g; $modelmore=~s/\s+$//; while (($cf,$cnt)=each(%cpucnt)) { $cf=~/^(.*) (\d*)$/; $cfreq=$2; $modelmore=~s/\)/ ${cfreq}MHz\)/g if ($cfreq); } } $prtdiag_has_mem=1; $simmrangex="00001000"; $simmbanks=2; $simmsperbank=4; @simmsizes=(128,256,512,1024,2048); @socketstr=("J0100","J0202","J0304","J0406","J0101","J0203","J0305","J0407"); @bankstr=(0,0,0,0,1,1,1,1); } if ($model eq "Sun-Blade-100" || $ultra eq "Sun Blade 100" || $ultra eq "Sun Blade 150") { # Accepts 128MB, 256MB or 512MB DIMMs on motherboard # Uses 168-pin 3.3V ECC PC133 CL=3 SDRAM # U5 DIMM3 address 0x60000000 - 0x7fffffff or 0xc0000000 - 0xffffffff # U4 DIMM2 address 0x40000000 - 0x5fffffff or 0x80000000 - 0xbfffffff # U3 DIMM1 address 0x20000000 - 0x3fffffff or 0x40000000 - 0x7fffffff # U2 DIMM0 address 0x00000000 - 0x1fffffff or 0x00000000 - 0x3fffffff # The minimum memory requirement is one DIMM in U2 # The memory installation sequence is U2, U3, U4, U5 # Each bank addresses 512MB of memory with 500MHz UltraSPARC # Each bank addresses 1GB of memory with >= 550MHz UltraSPARC if ($model eq "Sun-Blade-100" || $ultra eq "Sun Blade 100") { $devname="Grover"; $familypn="A36"; } if ($ultra eq "Sun Blade 150") { $devname="Grover+"; $familypn="A41"; } $untested=0; $prtdiag_has_mem=1; $simmrangex=($cpufreq > 520) ? "00000400" : "00000200"; $simmbanks=4; $simmsperbank=1; @simmsizes=(128,256,512); @socketstr=("DIMM0".."DIMM3"); @bankstr=(0..3); } if ($ultra eq "Sun Fire" || $ultra eq "Sun Fire 15K" || $ultra eq "Sun Fire 12K" || $ultra =~ /Sun Fire ([346]8[01]0|E[246]900|E2[05]K)\b/) { # Sun Fire 3800 system # 2-8 UltraSPARC-III processors # Up to 2 CPU/Memory boards # Sun Fire 4800, 4810 and 6800 system # 2-12 UltraSPARC-III processors # Up to 3 CPU/Memory boards # Sun Fire 6800 system # 2-24 UltraSPARC-III processors # Up to 6 CPU/Memory boards # Sun Fire 15K system # 16-106 UltraSPARC-III+, IV or IV+ processors # Up to 18 CPU/Memory boards # Sun Fire 12K system # up to 56 UltraSPARC-III+, IV or IV+ processors and 288GB memory # Sun Fire E2900 & E4900 system # 4, 8, or 12 UltraSPARC-IV or IV+ processors, up to 3 Uniboards # E4900 adds dynamic system domains when compared to E2900 # Sun Fire E6900 system # 4-24 UltraSPARC-IV or IV+ processors, up to 6 Uniboards # Sun Fire E20K system # 4-36 UltraSPARC-IV or IV+ processors, up to 9 Uniboards # Sun Fire E25K system # Up to 72 UltraSPARC-IV or IV+ processors, up to 18 Uniboards # Each CPU/Memory board holds up to 4 processors and up to 32GB memory # (32 DIMMs per board, 8 banks of 4 DIMMs) # Accepts 256MB, 512MB or 1GB DIMMs # 1GB DIMM not supported at 750MHz # 256MB DIMM only supported on US-III # 2GB DIMMs supported on 48x0/6800/E2900/E4900/E6900/E20K/E25K # System Board slots are labeled SB0 and higher # A populated DIMM bank requires an UltraSPARC CPU. # DIMMs are 232-pin 3.3V ECC 7ns SDRAM # prtdiag output shows the memory installed. # # CPU1 and CPU0 Memory CPU3 and CPU2 Memory # -------------------- -------------------- # Socket CPU Bank DIMM Socket CPU Bank DIMM # ------ --- ---- ---- ------ --- ---- ---- # J14600 P1 B0 D3 J16600 P3 B0 D3 # J14601 P1 B1 D3 J16601 P3 B1 D3 # J14500 P1 B0 D2 J16500 P3 B0 D2 # J14501 P1 B1 D2 J16501 P3 B1 D2 # J14400 P1 B0 D1 J16400 P3 B0 D1 # J14401 P1 B1 D1 J16401 P3 B1 D1 # J14300 P1 B0 D0 J16300 P3 B0 D0 # J14301 P1 B1 D0 J16301 P3 B1 D0 # J13600 P0 B0 D3 J15600 P2 B0 D3 # J13601 P0 B1 D3 J15601 P2 B1 D3 # J13500 P0 B0 D2 J15500 P2 B0 D2 # J13501 P0 B1 D2 J15501 P2 B1 D2 # J13400 P0 B0 D1 J15400 P2 B0 D1 # J13401 P0 B1 D1 J15401 P2 B1 D1 # J13300 P0 B0 D0 J15300 P2 B0 D0 # J13301 P0 B1 D0 J15301 P2 B1 D0 # $devname="Serengeti" if ($ultra eq "Sun Fire"); if ($banner =~ /Sun Fire 3800\b/ || $diagbanner =~ /Sun Fire 3800\b/) { $devname="Serengeti8, SF3800 or SP"; $familypn="F3800"; } if ($banner =~ /Sun Fire 4800\b/ || $diagbanner =~ /Sun Fire 4800\b/) { $devname="Serengeti12, SF4800 or MD"; $familypn="F4800"; } if ($banner =~ /Sun Fire 4810\b/ || $diagbanner =~ /Sun Fire 4810\b/) { $devname="Serengeti12i, SF4810 or ME"; $familypn="F4810"; } if ($banner =~ /Sun Fire 6800\b/ || $diagbanner =~ /Sun Fire 6800\b/) { $devname="Serengeti24, SF6800 or DC"; $familypn="F6800"; } if ($ultra eq "Sun Fire 15K") { $devname="Starcat, Serengeti72"; $familypn="F15K"; } $devname="Starkitty" if ($ultra eq "Sun Fire 12K"); if ($banner =~ /Sun Fire E2900\b/ || $diagbanner eq "Sun Fire E2900") { $devname="Amazon 2"; $familypn="E29"; } if ($banner =~ /Sun Fire E4900\b/ || $diagbanner eq "Sun Fire E4900") { $devname="Amazon 4"; $familypn="E49"; } $devname="Amazon 6" if ($banner =~ /Sun Fire E6900\b/ || $diagbanner eq "Sun Fire E6900"); $devname="Amazon 20" if ($banner =~ /Sun Fire E20K\b/ || $diagbanner eq "Sun Fire E20K"); $devname="Amazon 25" if ($banner =~ /Sun Fire E25K\b/ || $diagbanner eq "Sun Fire E25K"); $untested=0; $prtdiag_has_mem=1; @simmsizes=(256,512,1024); @simmsizes=(256,512,1024,2048) if ($ultra =~ /Sun Fire ([46]8[01]0|E[246]900|E2[05]K)\b/); } if ($ultra eq "Sun Fire V880") { # Accepts 128MB, 256MB, 512MB or 1GB DIMMs in groups of four per CPU # 128MB DIMMs only supported on 750MHz CPU/memory boards # 1GB DIMMs only supported on 900MHz or faster CPU/memory boards # 2-8 UltraSPARC-III processors, 750MHz or faster # Up to 64GB memory, 8GB max per CPU, 4 DIMMs per CPU, 2 CPUs per board # DIMMs must be added four-at-a-time within the same group of DIMM # slots; every fourth slot belongs to the same DIMM group. # Each CPU/Memory board must be populated with a minimum of eight DIMMs, # installed in groups A0 and B0. # For 1050MHz and higher system boards, each CPU/Memory board must be # populated with all sixteen DIMMs, installed in groups A0,A1,B0,B1. # Each group used must have four identical DIMMs installed (all four # DIMMs must be from the same manufacturing vendor and must have the # same capacity). # DIMMs are 232-pin 3.3V ECC 7ns SDRAM # Uses 128-bit-wide path to memory, 150MHz DIMMs, 2.4GB/sec # bandwidth to processor and an aggregate memory bw of 9.6GB/sec # prtdiag output shows the memory installed. # # CPU CPU/Memory Slot Associated DIMM Group # --- --------------- --------------------- # 0 Slot A A0,A1 # 2 Slot A B0,B1 # 1 Slot B A0,A1 # 3 Slot B B0,B1 # 4 Slot C A0,A1 # 6 Slot C B0,B1 # 5 Slot D A0,A1 # 7 Slot D B0,B1 # $devname="Daktari (V880), Nandi (V880z)"; $familypn="A30 (V880), A47 (V880z)"; $untested=0; @simmsizes=($cpufreq < 800) ? (128,256,512) : (256,512,1024,2048); @banksstr=("A0","A1","B0","B1"); $prtdiag_has_mem=1; } if ($ultra eq "Sun Fire V480") { # Accepts 256MB, 512MB or 1GB DIMMs in groups of four per CPU # 2 or 4 UltraSPARC-III processors, 900MHz or faster # Up to 32GB memory, 8GB max per CPU, 4 DIMMs per CPU, 2 CPUs per board # Smaller version of Sun Fire V880 above $devname="Cherrystone"; $familypn="A37"; $untested=0; @simmsizes=(256,512,1024,2048); @banksstr=("A0","A1","B0","B1"); $prtdiag_has_mem=1; } if ($ultra eq "Sun Fire V490" || $ultra eq "Sun Fire V890") { # Accepts 512MB or 1GB DIMMs in groups of four per CPU # 2 or 4 UltraSPARC-III, IV or IV+ processors, 1050MHz or faster # Up to 32GB memory, 8GB max per CPU, 4 DIMMs per CPU, 2 CPUs per board # Similar memory contraints as Sun Fire V880 above if ($ultra eq "Sun Fire V490") { $devname="Sebring"; $familypn="A52"; } if ($ultra eq "Sun Fire V890") { $devname="Silverstone"; $familypn="A53"; } $untested=0; @simmsizes=(512,1024,2048); @banksstr=("A0","A1","B0","B1"); $prtdiag_has_mem=1; } if ($ultra eq "Netra T12") { # Sun Fire V1280, Netra 1280 # Essentially the same as a Sun Fire 4810, but is marketed as a low cost # single domain system. # 2-12 UltraSPARC-IIIcu processors using up to 3 CPU/Memory boards # Each CPU/Memory board holds up to 4 processors and up to 32GB memory # (32 DIMMs per board, 8 banks of 4 DIMMs) # Accepts 256MB, 512MB, 1GB or 2GB DIMMs # System Board slots are labeled SB0 and higher # A populated DIMM bank requires an UltraSPARC III CPU. # DIMMs are 232-pin 3.3V ECC 7ns SDRAM # prtdiag output shows the memory installed. $devname="Lightweight 8"; $familypn="A40 (Sun Fire V1280), N40 (Netra 1280)"; $untested=0; $prtdiag_has_mem=1; @simmsizes=(256,512,1024,2048); } if ($ultra eq "Enchilada") { # Sun Fire V210, V240, Netra 210, 240 # 1-2 UltraSPARC-IIIi (Jalapeno) processors # UltraSPARC IIIi supports 128MB to 1GB single bank DIMMs. # UltraSPARC IIIi supports 256MB to 2GB dual bank DIMMs. # DDR-1 SDRAM PC2100 DIMMs, 8 DIMM slots, 4 DIMMs per processor, # 2 banks per processor, 2 DIMMs per bank # V210 accepts 1GB & 2GB DIMMs by installing Fan Upgrade Kit, X7418A # Mixing DIMM sizes and capacities is not supported. # prtdiag output can show the memory installed. $devname="Enchilada"; # Enxs if ($banner =~ /Sun Fire V210\b/ || $model =~ /Sun-Fire-V210/) { $devname="Enchilada 1U"; $familypn="N31"; } if ($model =~ /Netra-210\b/) { $devname="Salsa 19"; $familypn="N79"; } if ($banner =~ /Sun Fire V240\b/ || $model =~ /Sun-Fire-V240/) { $devname="Enchilada 2U"; $familypn="N32"; } if ($model =~ /Netra-240\b/) { $devname="Enchilada 19"; $familypn="N54"; } $untested=0 if ($banner =~ /Sun Fire (V210|240)\b/ || $model =~ /Sun-Fire-(V210|V240)/ || $model =~ /Netra-2[14]0\b/); $prtdiag_has_mem=1; $prtdiag_banktable_has_dimms=1; $simmrangex="00002000"; # Count the skipped address range for dual CPU $simmbanks=($ncpu > 1) ? 10 : 2; $simmsperbank=2; @simmsizes=(128,256,512,1024,2048); @socketstr=("MB/P0/B0/D0","MB/P0/B0/D1","MB/P0/B1/D0","MB/P0/B1/D1","?","?","?","?","?","?","?","?","?","?","?","?"); push(@socketstr, "MB/P1/B0/D0","MB/P1/B0/D1","MB/P1/B1/D0","MB/P1/B1/D1") if ($ncpu > 1); } if ($ultra eq "Sun Fire V440" || $ultra eq "Netra 440") { # 1-4 UltraSPARC-IIIi (Jalapeno) processors # UltraSPARC IIIi supports 128MB to 1GB single bank DIMMs. # UltraSPARC IIIi supports 256MB to 2GB dual bank DIMMs. # DDR-1 SDRAM PC2100 DIMMs, 16 DIMM slots, 4 DIMMs per processor, # 2 banks per processor, 2 DIMMs per bank # prtdiag output can show the memory installed. $devname="Chalupa"; $familypn="A42"; if ($ultra eq "Netra 440") { $devname="Chalupa 19"; $familypn="N42"; } $untested=0; $prtdiag_has_mem=1; $prtdiag_banktable_has_dimms=1; $simmrangex="00002000"; $simmbanks=26; # Count the skipped address range for each CPU $simmsperbank=2; @simmsizes=(128,256,512,1024,2048); # Each CPU card has 4 DIMM slots labeled J0601 (B0/D0), J0602 (B0/D1), # J0701 (B1/D0) and J0702 (B1/D1). @socketstr=("C0/P0/B0/D0","C0/P0/B0/D1","C0/P0/B1/D0","C0/P0/B1/D1","?","?","?","?","?","?","?","?","?","?","?","?"); push(@socketstr, "C1/P0/B0/D0","C1/P0/B0/D1","C1/P0/B1/D0","C1/P0/B1/D1","?","?","?","?","?","?","?","?","?","?","?","?") if ($ncpu > 1); push(@socketstr, "C2/P0/B0/D0","C2/P0/B0/D1","C2/P0/B1/D0","C2/P0/B1/D1","?","?","?","?","?","?","?","?","?","?","?","?") if ($ncpu > 2); push(@socketstr, "C3/P0/B0/D0","C3/P0/B0/D1","C3/P0/B1/D0","C3/P0/B1/D1") if ($ncpu > 3); } if ($ultra eq "Sun Blade 1500") { # 1 UltraSPARC-IIIi (Jalapeno) processor # UltraSPARC IIIi supports 128MB to 1GB single bank DIMMs. # UltraSPARC IIIi supports 256MB to 2GB dual bank DIMMs. # 184-pin DDR-1 SDRAM PC2100 DIMMs installed in pairs, 4 DIMM slots # prtdiag output can show the memory installed. $devname="Taco"; $devname .= "+" if ($modelmore =~ /\(Silver\)/ || $banner =~ /\(Silver\)/); $familypn="A43"; $untested=0; $prtdiag_has_mem=1; $prtdiag_banktable_has_dimms=1; $simmrangex="00002000"; $simmbanks=2; $simmsperbank=2; @simmsizes=(128,256,512,1024,2048); @socketstr=("DIMM0".."DIMM3"); # DIMM1-DIMM4 on prototype } if ($ultra eq "Sun Blade 2500" || $ultra eq "Sun Fire V250") { # 1-2 UltraSPARC-IIIi (Jalapeno) processors # UltraSPARC IIIi supports 128MB to 1GB single bank DIMMs. # UltraSPARC IIIi supports 256MB to 2GB dual bank DIMMs. # 184-pin DDR-1 SDRAM PC2100 DIMMs, 8 DIMM slots, 4 DIMMs per processor, # 2 banks per processor, 2 DIMMs per bank # prtdiag output can show the memory installed. if ($ultra eq "Sun Blade 2500") { $devname="Enchilada Workstation"; $devname .= " Silver" if ($modelmore =~ /\(Silver\)/ || $banner =~ /\(Silver\)/); $familypn="A39"; } if ($ultra eq "Sun Fire V250") { $devname="Enchilada 2P Tower"; $familypn="A50"; } $untested=0; $prtdiag_has_mem=1; $prtdiag_banktable_has_dimms=1; $simmrangex="00002000"; # Count the skipped address range for dual CPU $simmbanks=($ncpu > 1) ? 20 : 2; $simmsperbank=2; @simmsizes=(128,256,512,1024,2048); if ($ultra eq "Sun Blade 2500") { @socketstr=("DIMM0".."DIMM3"); push(@socketstr, "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "DIMM4".."DIMM7") if ($ncpu > 1); } else { @socketstr=("MB/DIMM0","MB/DIMM1","MB/DIMM2","MB/DIMM3"); push(@socketstr, "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "MB/DIMM4","MB/DIMM5","MB/DIMM6","MB/DIMM7") if ($ncpu > 1); } } if ($ultra eq "Sun Ultra 45 Workstation" || $ultra eq "Sun Ultra 45 or Ultra 25 Workstation") { # 1-2 UltraSPARC-IIIi (Jalapeno) 1.6GHz processors # 1GB to 16GB of DDR1 SDRAM 266 or 333MHz registered ECC memory using # matched pairs of 512MB, 1GB and 2GB DIMMs # maximum of 4 DIMMs (8GB) per CPU # CPU0 Bank0 DIMM1&DIMM3 blue sockets, Bank1 DIMM0&DIMM2 black sockets # CPU1 Bank0 DIMM4&DIMM6 blue sockets, Bank1 DIMM5&DIMM7 black sockets # prtdiag output can show the memory installed. $devname="Chicago"; # also "Netra Salsa-19" development name $familypn="A70"; $untested=0; $prtdiag_has_mem=1; $prtdiag_banktable_has_dimms=1; $simmrangex="00002000"; # Count the skipped address range for dual CPU $simmbanks=($ncpu > 1) ? 20 : 2; $simmsperbank=2; @simmsizes=(512,1024,2048); @socketstr=("MB/DIMM1","MB/DIMM3","MB/DIMM0","MB/DIMM2"); push(@socketstr, "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "MB/DIMM4","MB/DIMM6","MB/DIMM5","MB/DIMM7") if ($ncpu > 1); } if ($ultra eq "Sun Ultra 25 Workstation") { # 1 UltraSPARC-IIIi (Jalapeno) 1.34GHz processors # 1GB to 8GB of DDR1 SDRAM 266 or 333MHz registered ECC memory using # matched pairs of 512MB, 1GB and 2GB DIMMs # maximum of 4 DIMMs (8GB) # Bank0 DIMM1&DIMM3 blue sockets, Bank1 DIMM0&DIMM2 black sockets # prtdiag output can show the memory installed. $devname="Southside"; $familypn="A89"; $untested=0; $prtdiag_has_mem=1; $prtdiag_banktable_has_dimms=1; $simmrangex="00002000"; $simmbanks=2; $simmsperbank=2; @simmsizes=(512,1024,2048); @socketstr=("MB/DIMM1","MB/DIMM3","MB/DIMM0","MB/DIMM2"); } if ($ultra eq "Sun Fire V125") { # 1 UltraSPARC-IIIi (Jalapeno) processor # UltraSPARC IIIi supports 128MB to 1GB single bank DIMMs. # UltraSPARC IIIi supports 256MB to 2GB dual bank DIMMs. # DDR-1 SDRAM PC2100 DIMMs, 4 DIMM slots, 2 DIMMs per bank # Mixing DIMM sizes and capacities is not supported. # prtdiag output can show the memory installed. $devname="El Paso"; $familypn="125"; $untested=0; $prtdiag_has_mem=1; $prtdiag_banktable_has_dimms=1; $simmrangex="00002000"; $simmbanks=2; $simmsperbank=2; @simmsizes=(128,256,512,1024,2048); @socketstr=("MB/P0/B0/D0","MB/P0/B0/D1","MB/P0/B1/D0","MB/P0/B1/D1"); } if ($ultra eq "Seattle") { # Sun Fire V215, V245 # 1-2 UltraSPARC-IIIi (Jalapeno) processors # UltraSPARC IIIi supports 128MB to 1GB single bank DIMMs. # UltraSPARC IIIi supports 256MB to 2GB dual bank DIMMs. # DDR-1 SDRAM PC2100 DIMMs, 8 DIMM slots, 4 DIMMs per processor, # 2 banks per processor, 2 DIMMs per bank # Mixing DIMM sizes and capacities is not supported. # prtdiag output can show the memory installed. $devname="Seattle"; # Enxs if ($banner =~ /Sun Fire V215\b/ || $model =~ /Sun-Fire-V215/) { $devname="Seattle 1U"; $familypn="215"; } if ($banner =~ /Sun Fire V245\b/ || $model =~ /Sun-Fire-V245/) { $devname="Seattle 2U"; $familypn="245"; } $untested=0; $prtdiag_has_mem=1; $prtdiag_banktable_has_dimms=1; $simmrangex="00002000"; # Count the skipped address range for dual CPU $simmbanks=($ncpu > 1) ? 10 : 2; $simmsperbank=2; @simmsizes=(128,256,512,1024,2048); @socketstr=("MB/P0/B0/D0","MB/P0/B0/D1","MB/P0/B1/D0","MB/P0/B1/D1","?","?","?","?","?","?","?","?","?","?","?","?"); push(@socketstr, "MB/P1/B0/D0","MB/P1/B0/D1","MB/P1/B1/D0","MB/P1/B1/D1") if ($ncpu > 1); } if ($ultra eq "Boston") { # Sun Fire V445 # 2-4 UltraSPARC-IIIi (Jalapeno) processors # UltraSPARC IIIi supports 128MB to 1GB single bank DIMMs. # UltraSPARC IIIi supports 256MB to 2GB dual bank DIMMs. # DDR-1 SDRAM PC2100 DIMMs, 16 DIMM slots, 4 DIMMs per processor, # 2 banks per processor, 2 DIMMs per bank # prtdiag output can show the memory installed. $devname="Boston"; $familypn="445, A77"; $untested=0; $prtdiag_has_mem=1; $prtdiag_banktable_has_dimms=1; $simmrangex="00002000"; $simmbanks=26; # Count the skipped address range for each CPU $simmsperbank=2; @simmsizes=(128,256,512,1024,2048); # Each CPU card has 4 DIMM slots labeled J0601 (B0/D0), J0602 (B0/D1), # J0701 (B1/D0) and J0702 (B1/D1). @socketstr=("C0/P0/B0/D0","C0/P0/B0/D1","C0/P0/B1/D0","C0/P0/B1/D1","?","?","?","?","?","?","?","?","?","?","?","?"); push(@socketstr, "C1/P0/B0/D0","C1/P0/B0/D1","C1/P0/B1/D0","C1/P0/B1/D1","?","?","?","?","?","?","?","?","?","?","?","?") if ($ncpu > 1); push(@socketstr, "C2/P0/B0/D0","C2/P0/B0/D1","C2/P0/B1/D0","C2/P0/B1/D1","?","?","?","?","?","?","?","?","?","?","?","?") if ($ncpu > 2); push(@socketstr, "C3/P0/B0/D0","C3/P0/B0/D1","C3/P0/B1/D0","C3/P0/B1/D1") if ($ncpu > 3); } if ($ultra eq "Serverblade1") { # Sun Fire B100s Blade Server # 1 UltraSPARC-IIi 650MHz processors # Two PC-133 DIMM slots holding up to 2GB memory # Up to 16 Blade Servers in a single B1600 Intelligent Shelf # prtdiag output shows the memory installed. $bannermore="(Sun Fire B100s Blade Server)"; $modelmore=$bannermore; $devname="Stiletto"; $familypn="A44"; $untested=0; $prtdiag_has_mem=1; $simmrangex="00000400"; $simmbanks=2; $simmsperbank=1; @simmsizes=(256,512,1024); @socketstr=("Blade/DIMM0","Blade/DIMM1"); } if ($ultra eq "T2000") { # 1 UltraSPARC-T1 (Niagara) processor with "CoolThreads" multithreading # 8 Core 1.2GHz (9.6GHz clock speed rating) or 4, 6, or 8 Core 1.0GHz # or 8 Core 1.4GHz # Up to 64GB DDR2 memory in 16 slots w/ Chipkill and DRAM sparing, ECC # registered DIMMs. Supports 512MB, 1GB, 2GB and 4GB DIMMs. # Option X7800A - 1GB (2x512MB DDR2) 370-6207, 512MB DDR2 DIMM, 533MHz # Option X7801A - 2GB (2x1GB DDR2) 370-6208, 1GB DDR2 DIMM, 533MHz # Option X7802A - 4GB (2x2GB DDR2) 370-6209, 2GB DDR2 DIMM, 533MHz # DIMMs must be installed in sets of 8. Two basic memory configurations # are supported: 8-DIMM or 16-DIMM. All DIMMs must have identical # capacity. An 8 DIMM configuration fully populates Rank 0 (R0) slots. # Base configurations sold by Sun use all 16 DIMM slots (2 ranks) except # smallest memory configuration (4GB, 8 x 512MB in Rank 0). # The minimum T2000 memory requirement is 8 Rank 0 DIMMs. # 4 memory controllers embedded in UltraSPARC-T1 (CH0-CH3) # # T2000 Memory Map # +----------------------------------------+ # | J0901 Channel 0 Rank 1 DIMM 1 | DIMM 1 # Install 1st | J0701 Channel 0 Rank 0 DIMM 1 | DIMM 2 # | J0801 Channel 0 Rank 1 DIMM 0 | DIMM 3 # Install 1st | J0601 Channel 0 Rank 0 DIMM 0 | DIMM 4 # | J1401 Channel 1 Rank 1 DIMM 1 | DIMM 5 # Install 1st | J1201 Channel 1 Rank 0 DIMM 1 | DIMM 6 # | J1301 Channel 1 Rank 1 DIMM 0 | DIMM 7 # Install 1st | J1101 Channel 1 Rank 0 DIMM 0 | DIMM 8 # +----------------------------------------+ # +---------------+ # | UltraSPARC T1 | # +---------------+ # +----------------------------------------+ # Install 1st | J2101 Channel 3 Rank 0 DIMM 0 | DIMM 9 # | J2301 Channel 3 Rank 1 DIMM 0 | DIMM 10 # Install 1st | J2201 Channel 3 Rank 0 DIMM 1 | DIMM 11 # | J2401 Channel 3 Rank 1 DIMM 1 | DIMM 12 # Install 1st | J1601 Channel 2 Rank 0 DIMM 0 | DIMM 13 # | J1801 Channel 2 Rank 1 DIMM 0 | DIMM 14 # Install 1st | J1701 Channel 2 Rank 0 DIMM 1 | DIMM 15 # | J1901 Channel 2 Rank 1 DIMM 1 | DIMM 16 # +----------------------------------------+ $devname="Ontario"; $familypn="T20"; if ($model =~ /Netra-T2000\b/ || $banner =~ /Netra T2000\b/) { $devname="Pelton"; $familypn="N20"; } $familypn="T20, SEB" if ($model =~ /SPARC-Enterprise-T2000/ || $banner =~ /SPARC Enterprise T2000/); $untested=0; $simmrangex="00002000"; if (scalar(@slots) == 8) { # Two ranks reported $simmbanks=2; $simmsperbank=8; } else { # One rank reported, but default base configurations ship with # two ranks (16 DIMMs) $simmbanks=1; $simmsperbank=16; } @simmsizes=(512,1024,2048,4096); @socketstr=("MB/CMP0/CH0/R0/D0","MB/CMP0/CH0/R0/D1","MB/CMP0/CH1/R0/D0","MB/CMP0/CH1/R0/D1","MB/CMP0/CH2/R0/D0","MB/CMP0/CH2/R0/D1","MB/CMP0/CH3/R0/D0","MB/CMP0/CH3/R0/D1","MB/CMP0/CH0/R1/D0","MB/CMP0/CH0/R1/D1","MB/CMP0/CH1/R1/D0","MB/CMP0/CH1/R1/D1","MB/CMP0/CH2/R1/D0","MB/CMP0/CH2/R1/D1","MB/CMP0/CH3/R1/D0","MB/CMP0/CH3/R1/D1"); &check_for_LDOM; } if ($ultra eq "T1000") { # 1 UltraSPARC-T1 (Niagara) processor with "CoolThreads" multithreading # 6 or 8 Core 1.0GHz # Up to 32GB DDR2 memory in 8 slots w/ Chipkill and DRAM sparing, ECC # registered DIMMs. Supports 512MB, 1GB, 2GB and 4GB DIMMs. # Option X7800A - 1GB (2x512MB DDR2) 370-6207, 512MB DDR2 DIMM, 533MHz # Option X7801A - 2GB (2x1GB DDR2) 370-6208, 1GB DDR2 DIMM, 533MHz # Option X7802A - 4GB (2x2GB DDR2) 370-6209, 2GB DDR2 DIMM, 533MHz # DIMMs must be installed in sets of 4. # Base configurations sold by Sun use all 8 DIMM slots (2 ranks) except # smallest memory configuration (2GB, 4 x 512MB in Rank 0). # The minimum T1000 memory requirement is 4 Rank 0 DIMMs. # 4 memory controllers embedded in UltraSPARC-T1 (CH0-CH3) # # T1000 Memory Map # +----------------------------------------+ # | J1301 Channel 3 Rank 1 DIMM 1 | # Install 1st | J1101 Channel 3 Rank 0 DIMM 1 | # | J1201 Channel 3 Rank 1 DIMM 0 | # Install 1st | J1001 Channel 3 Rank 0 DIMM 0 | # +----------------------------------------+ # +---------------+ # | UltraSPARC T1 | # +---------------+ # +----------------------------------------+ # Install 1st | J0501 Channel 0 Rank 0 DIMM 0 | # | J0701 Channel 0 Rank 1 DIMM 0 | # Install 1st | J0601 Channel 0 Rank 0 DIMM 1 | # | J0801 Channel 0 Rank 1 DIMM 1 | # +----------------------------------------+ $devname="Erie"; $familypn="T10"; $familypn="T10, SEA" if ($model =~ /SPARC-Enterprise-T1000/ || $banner =~ /SPARC Enterprise T1000/); $untested=0; $simmrangex="00002000"; if (scalar(@slots) == 8) { # Two ranks reported $simmbanks=2; $simmsperbank=4; } else { $simmbanks=1; $simmsperbank=8; } @simmsizes=(512,1024,2048,4096); @socketstr=("MB/CMP0/CH0/R0/D0","MB/CMP0/CH0/R0/D1","MB/CMP0/CH3/R0/D0","MB/CMP0/CH3/R0/D1","MB/CMP0/CH0/R1/D0","MB/CMP0/CH0/R1/D1","MB/CMP0/CH3/R1/D0","MB/CMP0/CH3/R1/D1"); &check_for_LDOM; } if ($ultra eq "T6300") { # 1 UltraSPARC-T1 (Niagara) processor with "CoolThreads" multithreading # 6-Core 1.0GHz, 8-Core 1.0GHz, 1.2GHz or 1.4GHz # Up to 32GB ECC Registered DDR2 PC4200 # Supports 1GB, 2GB and 4GB DIMMs. # DIMMs must be installed in sets of 4. # Supported memory configurations: # 4 FB-DIMMs (Channel 0 and Channel 3) # 4 FB-DIMMs (Channel 1 and Channel 2) # 8 FB-DIMMs (Channel 0, 1, 2 and 3) (fully populated configuration) # Due to interleaving rules for the CPU, the system will operate at # the lowest capacity of all the DIMMs installed. Therefore, it is # ideal to install eight identical DIMMs (not four DIMMs of one # capacity and four DIMMs of another capacity). $devname="St. Paul"; $familypn="A94"; $untested=0; $memtype="FB-DIMM"; $simmrangex="00002000"; $showrange=0; $simmbanks=2; $simmsperbank=4; @simmsizes=(1024,2048,4096); @socketstr=("MB/CMP0/CH0/R0/D0","MB/CMP0/CH0/R0/D1","MB/CMP0/CH3/R0/D0","MB/CMP0/CH3/R0/D1","MB/CMP0/CH1/R0/D0","MB/CMP0/CH1/R0/D1","MB/CMP0/CH2/R0/D0","MB/CMP0/CH2/R0/D1"); @socketlabelstr=("J6301","J6401","J7201","J7301","J6601","J6701","J6901","J7001"); &check_for_LDOM; } if ($ultra eq "T5120" || $ultra eq "T5220" || $ultra eq "T6320") { # 1 UltraSPARC-T2 (Niagara-II) multicore processor with "CoolThreads" # multithreading, 1.2GHz 4 or 8-Core or 1.4GHz 8-Core # Up to 64GB Fully Buffered ECC-registered DDR2 @ 667MHz # Supports 1GB, 2GB, 4GB and 8GB DIMMs. # DIMMs must be installed in sets of 4. # All FB-DIMMs must be the same density (same type and Sun part number) # Supported memory configurations: # 4 FB-DIMMs (Group 1) MB/CMP0/BR[0-3]/CH0/D0 # 8 FB-DIMMs (Groups 1-2) MB/CMP0/BR[0-3]/CH[01]/D0 # 16 FB-DIMMs (Groups 1-3) MB/CMP0/BR[0-3]/CH[01]/D[01] # # FB-DIMM Configuration: # Install FB-DIMM # Branch Channel FRU Name FB-DIMM Order Pair # # 0 0 MB/CMP0/BR0/CH0/D0 J1001 1 A # MB/CMP0/BR0/CH0/D1 J1101 3 B # 1 MB/CMP0/BR0/CH1/D0 J1201 2 A # MB/CMP0/BR0/CH1/D1 J1301 3 B # 1 0 MB/CMP0/BR1/CH0/D0 J1401 1 C # MB/CMP0/BR1/CH0/D1 J1501 3 D # 1 MB/CMP0/BR1/CH1/D0 J1601 2 C # MB/CMP0/BR1/CH1/D1 J1701 3 D # 2 0 MB/CMP0/BR2/CH0/D0 J2001 1 E # MB/CMP0/BR2/CH0/D1 J2101 3 F # 1 MB/CMP0/BR2/CH1/D0 J2201 2 E # MB/CMP0/BR2/CH1/D1 J2301 3 F # 3 0 MB/CMP0/BR3/CH0/D0 J2401 1 G # MB/CMP0/BR3/CH0/D1 J2501 3 H # 1 MB/CMP0/BR3/CH1/D0 J2601 2 G # MB/CMP0/BR3/CH1/D1 J2701 3 H # # Note - FB-DIMM names in ILOM messages are displayed with the full FRU # name, such as /SYS/MB/CMP0/BR0/CH0/D0. $devname="Huron"; if ($ultra eq "T5120") { $devname="Huron 1U"; $familypn="SEC"; } if ($ultra eq "T5220") { $devname="Huron 2U"; $familypn="SED"; } if ($banner =~ /Netra T5220\b/) { $devname="Turgo"; $familypn="NT52"; } if ($ultra eq "T6320") { $devname="Glendale"; $familypn="A95"; } $untested=0; $memtype="FB-DIMM"; $simmrangex="00008000"; $showrange=0; $simmbanks=4; $simmsperbank=4; @simmsizes=(1024,2048,4096,8192); @socketstr=("MB/CMP0/BR0/CH0/D0","MB/CMP0/BR1/CH0/D0","MB/CMP0/BR2/CH0/D0","MB/CMP0/BR3/CH0/D0","MB/CMP0/BR0/CH1/D0","MB/CMP0/BR1/CH1/D0","MB/CMP0/BR2/CH1/D0","MB/CMP0/BR3/CH1/D0","MB/CMP0/BR0/CH0/D1","MB/CMP0/BR1/CH0/D1","MB/CMP0/BR2/CH0/D1","MB/CMP0/BR3/CH0/D1","MB/CMP0/BR0/CH1/D1","MB/CMP0/BR1/CH1/D1","MB/CMP0/BR2/CH1/D1","MB/CMP0/BR3/CH1/D1"); &check_for_LDOM; } if ($ultra eq "CP3260") { # 1 UltraSPARC-T2 (Niagara-II) multicore processor with "CoolThreads" # multithreading, 6 or 8 core with 8 threads per core # 8 FB-DIMM slots, 8GB or 16GB, using 1GB or 2GB DIMMs, 8 channels # Fully Buffered ECC-registered DDR2 @ 667MHz # All FB-DIMMs must be the same density (same type and Sun part number) # Supported memory configurations: # FB0B FB0A FB1B FB1A FB2A FB2B FB3A FB3B # DIMM Pair 0 DIMM Pair 1 DIMM Pair 2 DIMM Pair 3 $devname="Monza"; $untested=1; $memtype="FB-DIMM"; $simmrangex="00008000"; $showrange=0; $simmbanks=1; $simmsperbank=8; @simmsizes=(1024,2048); @socketstr=("FB0A","FB0B","FB1A","FB1B","FB2A","FB2B","FB3A","FB3B"); &check_for_LDOM; } if ($ultra eq "T5140" || $ultra eq "T5240" || $ultra eq "T6340") { # T5140 has 2 UltraSPARC-T2+ (Victoria Falls) multicore processors with # "CoolThreads" multithreading, 1.2GHz 4, 6, or 8-Core # T5240 has 2 UltraSPARC-T2+ (Victoria Falls) multicore processors with # "CoolThreads" multithreading, 1.2GHz 4, 6, or 8-Core or 1.4GHz 8-Core # T6340 has 2 UltraSPARC-T2+ (Victoria Falls) multicore processors with # "CoolThreads" multithreading, 1.4GHz 8-Core # 8GB to 64GB Fully Buffered ECC-registered DDR2 @ 667MHz # Supports 1GB, 2GB, 4GB and 8GB DIMMs. # T5240 also supports optional mezzanine memory board doubling memory # with an additional 16 FB-DIMM sockets # All FB-DIMMs must be the same density (same type and Sun part number) # # T5140,T5240 Supported memory configurations: # 8 FB-DIMMs (Group 1) MB/CMP[01]/BR[01]/CH[01]/D0 # 12 FB-DIMMs (Groups 1-2) MB/CMP[01]/BR[01]/CH[01]/D0,MB/CMP0/BR[01]/CH[01]/D1 # 16 FB-DIMMs (Groups 1-3) MB/CMP[01]/BR[01]/CH[01]/D[01] # T5240 with memory mezzanine assembly supports these additional # memory configurations once the motherboard is fully populated: # 24 FB-DIMMs (Groups 1-4) MB/CMP[01]/MR0/BR[01]/CH[01]/D[23] # 32 FB-DIMMs (Groups 1-5) MB/CMP[01]/MR[01]/BR[01]/CH[01]/D[23] # # FB-DIMM Configuration: # Install FB-DIMM # Branch Channel FRU Name FB-DIMM Order Pair # # CMP0,0 0 MB/CMP0/BR0/CH0/D0 J0500 1 A # MB/CMP0/BR0/CH0/D1 J0600 2 B # 1 MB/CMP0/BR0/CH1/D0 J0700 1 A # MB/CMP0/BR0/CH1/D1 J0800 2 B # CMP0,1 0 MB/CMP0/BR1/CH0/D0 J0900 1 C # MB/CMP0/BR1/CH0/D1 J1000 2 D # 1 MB/CMP0/BR1/CH1/D0 J1100 1 C # MB/CMP0/BR1/CH1/D1 J1200 2 D # CMP1,0 0 MB/CMP1/BR0/CH0/D0 J1800 1 E # MB/CMP1/BR0/CH0/D1 J1900 3 F # 1 MB/CMP1/BR0/CH1/D0 J2000 1 E # MB/CMP1/BR0/CH1/D1 J2100 3 F # CMP1,1 0 MB/CMP1/BR1/CH0/D0 J2200 1 G # MB/CMP1/BR1/CH0/D1 J2300 3 H # 1 MB/CMP1/BR1/CH1/D0 J2400 1 G # MB/CMP1/BR1/CH1/D1 J2500 3 H # CMP0,0 0 MB/CMP0/MR0/BR0/CH0/D2 J0201 4 # MB/CMP0/MR0/BR0/CH0/D3 J0301 4 # 1 MB/CMP0/MR0/BR0/CH1/D2 J0401 4 # MB/CMP0/MR0/BR0/CH1/D3 J0501 4 # CMP0,1 0 MB/CMP0/MR0/BR1/CH0/D2 J0601 4 # MB/CMP0/MR0/BR1/CH0/D3 J0701 4 # 1 MB/CMP0/MR0/BR1/CH1/D2 J0801 4 # MB/CMP0/MR0/BR1/CH1/D3 J0901 4 # CMP1,0 0 MB/CMP1/MR1/BR0/CH0/D2 J0201 5 # MB/CMP1/MR1/BR0/CH0/D3 J0301 5 # 1 MB/CMP1/MR1/BR0/CH1/D2 J0401 5 # MB/CMP1/MR1/BR0/CH1/D3 J0501 5 # CMP1,1 0 MB/CMP1/MR1/BR1/CH0/D2 J0601 5 # MB/CMP1/MR1/BR1/CH0/D3 J0701 5 # 1 MB/CMP1/MR1/BR1/CH1/D2 J0801 5 # MB/CMP1/MR1/BR1/CH1/D3 J0901 5 # # Note - FB-DIMM names in ILOM messages are displayed with the full FRU # name, such as /SYS/MB/CMP0/BR0/CH0/D0. $devname="Maramba"; if ($ultra eq "T5140") { $devname="Maramba 1U"; $familypn="SET"; } if ($ultra eq "T5240") { $devname="Maramba 2U"; $familypn="SEU"; } $untested=0; if ($model =~ /-USBRDT-5240/) { $devname="Thunder"; $untested=1; } if ($ultra eq "T6340") { $devname="Scottsdale"; $familypn="T6340"; } if ($model =~ /Netra.*T6340/) { $familypn="NT6340"; $untested=1; } $memtype="FB-DIMM"; $simmrangex="00008000"; $showrange=0; $simmbanks=4; $simmbanks=8 if ($ultra eq "T5240" || $ultra eq "T6340"); $simmsperbank=4; @simmsizes=(1024,2048,4096,8192); @socketstr=("MB/CMP0/BR0/CH0/D0","MB/CMP0/BR0/CH1/D0","MB/CMP0/BR1/CH0/D0","MB/CMP0/BR1/CH1/D0","MB/CMP1/BR0/CH0/D0","MB/CMP1/BR0/CH1/D0","MB/CMP1/BR1/CH0/D0","MB/CMP1/BR1/CH1/D0","MB/CMP0/BR0/CH0/D1","MB/CMP0/BR0/CH1/D1","MB/CMP0/BR1/CH0/D1","MB/CMP0/BR1/CH1/D1","MB/CMP1/BR0/CH0/D1","MB/CMP1/BR0/CH1/D1","MB/CMP1/BR1/CH0/D1","MB/CMP1/BR1/CH1/D1"); push(@socketstr, "MB/CMP0/MR0/BR0/CH0/D2","MB/CMP0/MR0/BR0/CH0/D3","MB/CMP0/MR0/BR0/CH1/D2","MB/CMP0/MR0/BR0/CH1/D3","MB/CMP0/MR0/BR1/CH0/D2","MB/CMP0/MR0/BR1/CH0/D3","MB/CMP0/MR0/BR1/CH1/D2","MB/CMP0/MR0/BR1/CH1/D3","MB/CMP1/MR1/BR0/CH0/D2","MB/CMP1/MR1/BR0/CH0/D3","MB/CMP1/MR1/BR0/CH1/D2","MB/CMP1/MR1/BR0/CH1/D3","MB/CMP1/MR1/BR1/CH0/D2","MB/CMP1/MR1/BR1/CH0/D3","MB/CMP1/MR1/BR1/CH1/D2","MB/CMP1/MR1/BR1/CH1/D3") if ($ultra eq "T5240"); push(@socketstr, "MB/CMP0/BR0/CH0/D2","MB/CMP0/BR0/CH0/D3","MB/CMP0/BR0/CH1/D2","MB/CMP0/BR0/CH1/D3","MB/CMP0/BR1/CH0/D2","MB/CMP0/BR1/CH0/D3","MB/CMP0/BR1/CH1/D2","MB/CMP0/BR1/CH1/D3","MB/CMP1/BR0/CH0/D2","MB/CMP1/BR0/CH0/D3","MB/CMP1/BR0/CH1/D2","MB/CMP1/BR0/CH1/D3","MB/CMP1/BR1/CH0/D2","MB/CMP1/BR1/CH0/D3","MB/CMP1/BR1/CH1/D2","MB/CMP1/BR1/CH1/D3") if ($ultra eq "T6340"); &check_for_LDOM; } if ($ultra eq "T5440") { # T5440 has 4 UltraSPARC-T2+ (Victoria Falls) multicore processors # Netra-T5440 has 2 UltraSPARC-T2+ (Victoria Falls) multicore processors # 16GB to 256GB Fully Buffered ECC-registered DDR2 @ 667MHz # Supports 2GB, 4GB and 8GB DIMMs. # All FB-DIMMs must be the same density (same type and Sun part number) # # Note - FB-DIMM names in ILOM messages are displayed with the full FRU # name, such as /SYS/MB/CMP0/BR0/CH0/D0. $devname="Batoka" if ($ultra eq "T5440"); $devname="Congo" if ($model =~ /Netra-T5440/); $devname="Lightning" if ($model =~ /-USBRDT-5440/); $untested=0; $untested=1 if ($model =~ /-USBRDT-5440/); $memtype="FB-DIMM"; $simmrangex="00004000"; $showrange=0; $simmbanks=4; $simmsperbank=4; @simmsizes=(2048,4096,8192); if ($model =~ /Netra-T5440/) { $familypn="NT544"; @socketstr=("MB/CMP0/BR0/CH0/D0","MB/CMP0/BR0/CH1/D0","MB/CMP0/BR1/CH0/D0","MB/CMP0/BR1/CH1/D0","MB/CMP1/BR0/CH0/D0","MB/CMP1/BR0/CH1/D0","MB/CMP1/BR1/CH0/D0","MB/CMP1/BR1/CH1/D0","MB/CMP0/BR0/CH0/D1","MB/CMP0/BR0/CH1/D1","MB/CMP0/BR1/CH0/D1","MB/CMP0/BR1/CH1/D1","MB/CMP1/BR0/CH0/D1","MB/CMP1/BR0/CH1/D1","MB/CMP1/BR1/CH0/D1","MB/CMP1/BR1/CH1/D1","MB/CMP0/MR0/BR0/CH0/D2","MB/CMP0/MR0/BR0/CH0/D3","MB/CMP0/MR0/BR0/CH1/D2","MB/CMP0/MR0/BR0/CH1/D3","MB/CMP0/MR0/BR1/CH0/D2","MB/CMP0/MR0/BR1/CH0/D3","MB/CMP0/MR0/BR1/CH1/D2","MB/CMP0/MR0/BR1/CH1/D3","MB/CMP1/MR1/BR0/CH0/D2","MB/CMP1/MR1/BR0/CH0/D3","MB/CMP1/MR1/BR0/CH1/D2","MB/CMP1/MR1/BR0/CH1/D3","MB/CMP1/MR1/BR1/CH0/D2","MB/CMP1/MR1/BR1/CH0/D3","MB/CMP1/MR1/BR1/CH1/D2","MB/CMP1/MR1/BR1/CH1/D3"); } else { $familypn="SEV"; @socketstr=("MB/CPU0/CMP0/BR0/CH0/D0","MB/CPU0/CMP0/BR0/CH1/D0","MB/CPU0/CMP0/BR1/CH0/D0","MB/CPU0/CMP0/BR1/CH1/D0","MB/MEM0/CMP0/BR0/CH0/D1","MB/MEM0/CMP0/BR0/CH1/D1","MB/MEM0/CMP0/BR1/CH0/D1","MB/MEM0/CMP0/BR1/CH1/D1","MB/CPU1/CMP1/BR0/CH0/D0","MB/CPU1/CMP1/BR0/CH1/D0","MB/CPU1/CMP1/BR1/CH0/D0","MB/CPU1/CMP1/BR1/CH1/D0","MB/MEM1/CMP1/BR0/CH0/D1","MB/MEM1/CMP1/BR0/CH1/D1","MB/MEM1/CMP1/BR1/CH0/D1","MB/MEM1/CMP1/BR1/CH1/D1","MB/CPU2/CMP2/BR0/CH0/D0","MB/CPU2/CMP2/BR0/CH1/D0","MB/CPU2/CMP2/BR1/CH0/D0","MB/CPU2/CMP2/BR1/CH1/D0","MB/MEM2/CMP2/BR0/CH0/D1","MB/MEM2/CMP2/BR0/CH1/D1","MB/MEM2/CMP2/BR1/CH0/D1","MB/MEM2/CMP2/BR1/CH1/D1","MB/CPU3/CMP3/BR0/CH0/D0","MB/CPU3/CMP3/BR0/CH1/D0","MB/CPU3/CMP3/BR1/CH0/D0","MB/CPU3/CMP3/BR1/CH1/D0","MB/MEM3/CMP3/BR0/CH0/D1","MB/MEM3/CMP3/BR0/CH1/D1","MB/MEM3/CMP3/BR1/CH0/D1","MB/MEM3/CMP3/BR1/CH1/D1"); } &check_for_LDOM; } if ($ultra eq "T3-1" || $ultra eq "T3-1B") { # SPARC T3-1 and T3-1B have 1 SPARC-T3 (Rainbow Falls) multicore # processor with 8-Threads, 16-Core, 1.65GHz # 16 DIMM slots for up to 128GB memory (16 x 8GB), 8GB min (4 x 2GB) # supports 2GB, 4GB & 8GB DDR3 DIMMs, dual-rank # DIMM slots are organized into four branches, with each branch # connected to a separate Buffer-on-Board (BOB) ASIC, designated BOB0 # through BOB3. Each BOB ASIC has two DDR3 channels, with each channel # supporting two DIMMs. # Populate the 4 blue slots first (CH1/D0), the 4 white slots second # (CH0/D0), and the 8 black slots third (D1). $memtype="DDR3 DIMM"; $simmrangex="00004000"; $showrange=0; $simmbanks=4; # Assume largest DIMMs installed for prtconf-only data $simmsperbank=&roundup_memory($installed_memory) / 8192; @simmsizes=(2048,4096,8192); $familypn="SE3" if ($ultra eq "T3-1"); $familypn="T31B" if ($ultra eq "T3-1B"); $familypn="NST3" if ($ultra eq "T3-1" && $banner =~ /Netra/i); $untested=0 if ($ultra eq "T3-1" || $ultra eq "T3-1B"); $untested=1 if ($banner =~ /Netra/i); @socketstr=("MB/CMP0/BOB0/CH1/D0","MB/CMP0/BOB1/CH1/D0","MB/CMP0/BOB2/CH1/D0","MB/CMP0/BOB3/CH1/D0","MB/CMP0/BOB0/CH0/D0","MB/CMP0/BOB1/CH0/D0","MB/CMP0/BOB2/CH0/D0","MB/CMP0/BOB3/CH0/D0","MB/CMP0/BOB0/CH1/D1","MB/CMP0/BOB1/CH1/D1","MB/CMP0/BOB2/CH1/D1","MB/CMP0/BOB3/CH1/D1","MB/CMP0/BOB0/CH0/D1","MB/CMP0/BOB1/CH0/D1","MB/CMP0/BOB2/CH0/D1","MB/CMP0/BOB3/CH0/D1"); &check_for_LDOM; } if ($ultra eq "T3-1BA") { # Netra SPARC T3-1BA has 1 SPARC-T3 (Rainbow Falls) multicore processor # with 8-Threads, 12-Core, 1.4GHz # 8 DIMM slots, 2GB or 4GB DDR3, all slots must be populated same # 16GB min (8 x 2GB), 32GB max (8 x 4GB) $memtype="DDR3 DIMM"; $simmrangex="00004000"; $showrange=0; $simmbanks=1; $simmsperbank=8; @simmsizes=(2048,4096); $untested=1; @socketstr=("DIMM0".."DIMM7"); # Guess &check_for_LDOM; } if ($ultra eq "T3-2") { # SPARC T3-2 has 2 SPARC-T3 (Rainbow Falls) multicore processors, each # with 8-Threads, 16-Core, 1.65GHz # 32 DIMM slots for up to 256GB memory (32 x 8GB), 64GB min (16 x 4GB) # supports 4GB & 8GB DDR3 DIMMs, dual-rank # A maximum of two memory risers (MR0 & MR1) supported per CPU, thus # allowing up to four memory risers total. # Each memory riser slot in the server chassis must be filled with # either a memory riser or filler panel, and each memory riser must be # filled with DIMMs and/or DIMM filler panels. # Each memory riser has 8 DIMM slots (D0-D3 for MB1, D4-D7 for MB0) # Install D0/D4 (blue), then D2/D6 (white), then D1/D5 (black), and # then D3/D7 (green). # Performance-oriented configurations should be configured with two # memory risers per CPU. In configurations that do not require two # memory risers per CPU, the following guidelines should be followed: # - Populate riser slot MR0 for each CPU, starting with the lowest # numbered CPU (P0). # - Populate riser slot MR1 for each CPU, starting with the lowest # numbered CPU (P0). $memtype="DDR3 DIMM"; $simmrangex="00004000"; $showrange=0; $simmbanks=4; # Assume largest DIMMs installed for prtconf-only data $simmsperbank=&roundup_memory($installed_memory) / 8192; @simmsizes=(4096,8192); $familypn="SE4"; $untested=0; $untested=1 if ($banner =~ /Netra/i); @socketstr=("MB/CMP0/MR0/BOB0/CH0/D0","MB/CMP0/MR0/BOB0/CH1/D0","MB/CMP0/MR0/BOB1/CH0/D0","MB/CMP0/MR0/BOB1/CH1/D0","MB/CMP1/MR0/BOB0/CH0/D0","MB/CMP1/MR0/BOB0/CH1/D0","MB/CMP1/MR0/BOB1/CH0/D0","MB/CMP1/MR0/BOB1/CH1/D0","MB/CMP0/MR1/BOB0/CH0/D0","MB/CMP0/MR1/BOB0/CH1/D0","MB/CMP0/MR1/BOB1/CH0/D0","MB/CMP0/MR1/BOB1/CH1/D0","MB/CMP1/MR1/BOB0/CH0/D0","MB/CMP1/MR1/BOB0/CH1/D0","MB/CMP1/MR1/BOB1/CH0/D0","MB/CMP1/MR1/BOB1/CH1/D0","MB/CMP0/MR0/BOB0/CH0/D1","MB/CMP0/MR0/BOB0/CH1/D1","MB/CMP0/MR0/BOB1/CH0/D1","MB/CMP0/MR0/BOB1/CH1/D1","MB/CMP1/MR0/BOB0/CH0/D1","MB/CMP1/MR0/BOB0/CH1/D1","MB/CMP1/MR0/BOB1/CH0/D1","MB/CMP1/MR0/BOB1/CH1/D1","MB/CMP0/MR1/BOB0/CH0/D1","MB/CMP0/MR1/BOB0/CH1/D1","MB/CMP0/MR1/BOB1/CH0/D1","MB/CMP0/MR1/BOB1/CH1/D1","MB/CMP1/MR1/BOB0/CH0/D1","MB/CMP1/MR1/BOB0/CH1/D1","MB/CMP1/MR1/BOB1/CH0/D1","MB/CMP1/MR1/BOB1/CH1/D1"); &check_for_LDOM; } if ($ultra eq "T3-4") { # SPARC T3-4 has 2 or 4 SPARC-T3 (Rainbow Falls) multicore processors, # each with 8-Threads, 16-Core, 1.65GHz # 64 DIMM slots for up to 512GB memory (64 x 8GB), 128GB min (32 x 4GB) # supports 4GB & 8GB DDR3 DIMMs, dual-rank $memtype="DDR3 DIMM"; $simmrangex="00004000"; $showrange=0; $simmbanks=4; # Assume largest DIMMs installed for prtconf-only data $simmsperbank=&roundup_memory($installed_memory) / 8192; @simmsizes=(4096,8192); $familypn="SE5"; $untested=1; $untested=1 if ($banner =~ /Netra/i); # Guess on socket name order ??? @socketstr=("PM0/CMP1/BOB0/CH0/D0","PM0/CMP1/BOB0/CH1/D0","PM0/CMP1/BOB1/CH0/D0","PM0/CMP1/BOB1/CH1/D0","PM0/CMP1/BOB2/CH0/D0","PM0/CMP1/BOB2/CH1/D0","PM0/CMP1/BOB3/CH0/D0","PM0/CMP1/BOB3/CH1/D0","PM0/CMP0/BOB0/CH0/D0","PM0/CMP0/BOB0/CH1/D0","PM0/CMP0/BOB1/CH0/D0","PM0/CMP0/BOB1/CH1/D0","PM0/CMP0/BOB2/CH0/D0","PM0/CMP0/BOB2/CH1/D0","PM0/CMP0/BOB3/CH0/D0","PM0/CMP0/BOB3/CH1/D0"); push(@socketstr, "PM0/CMP1/BOB0/CH0/D1","PM0/CMP1/BOB0/CH1/D1","PM0/CMP1/BOB1/CH0/D1","PM0/CMP1/BOB1/CH1/D1","PM0/CMP1/BOB2/CH0/D1","PM0/CMP1/BOB2/CH1/D1","PM0/CMP1/BOB3/CH0/D1","PM0/CMP1/BOB3/CH1/D1","PM0/CMP0/BOB0/CH0/D1","PM0/CMP0/BOB0/CH1/D1","PM0/CMP0/BOB1/CH0/D1","PM0/CMP0/BOB1/CH1/D1","PM0/CMP0/BOB2/CH0/D1","PM0/CMP0/BOB2/CH1/D1","PM0/CMP0/BOB3/CH0/D1","PM0/CMP0/BOB3/CH1/D1"); # Need to determine if PM1 is installed, its DIMMs are next push(@socketstr, "PM1/CMP1/BOB0/CH0/D0","PM1/CMP1/BOB0/CH1/D0","PM1/CMP1/BOB1/CH0/D0","PM1/CMP1/BOB1/CH1/D0","PM1/CMP1/BOB2/CH0/D0","PM1/CMP1/BOB2/CH1/D0","PM1/CMP1/BOB3/CH0/D0","PM1/CMP1/BOB3/CH1/D0","PM1/CMP0/BOB0/CH0/D0","PM1/CMP0/BOB0/CH1/D0","PM1/CMP0/BOB1/CH0/D0","PM1/CMP0/BOB1/CH1/D0","PM1/CMP0/BOB2/CH0/D0","PM1/CMP0/BOB2/CH1/D0","PM1/CMP0/BOB3/CH0/D0","PM1/CMP0/BOB3/CH1/D0"); push(@socketstr, "PM1/CMP1/BOB0/CH0/D1","PM1/CMP1/BOB0/CH1/D1","PM1/CMP1/BOB1/CH0/D1","PM1/CMP1/BOB1/CH1/D1","PM1/CMP1/BOB2/CH0/D1","PM1/CMP1/BOB2/CH1/D1","PM1/CMP1/BOB3/CH0/D1","PM1/CMP1/BOB3/CH1/D1","PM1/CMP0/BOB0/CH0/D1","PM1/CMP0/BOB0/CH1/D1","PM1/CMP0/BOB1/CH0/D1","PM1/CMP0/BOB1/CH1/D1","PM1/CMP0/BOB2/CH0/D1","PM1/CMP0/BOB2/CH1/D1","PM1/CMP0/BOB3/CH0/D1","PM1/CMP0/BOB3/CH1/D1"); &check_for_LDOM; } if ($ultra eq "T4-1" || $ultra eq "T4-1B") { # SPARC T4-1 and T4-1B have 1 SPARC-T4 multicore processor with # 8-Threads, 8-Core, 2.85GHz # 16 DIMM slots for up to 256GB memory (16 x 16GB), 16GB min (4 x 4GB) # supports 4GB, 8GB & 16GB DDR3 DIMMs # DIMM slots are organized into four branches, with each branch # connected to a separate Buffer-on-Board (BOB) ASIC, designated BOB0 # through BOB3. Each BOB ASIC has two DDR3 channels, with each channel # supporting two DIMMs. # Populate the 4 blue slots first (CH1/D0), the 4 white slots second # (CH0/D0), and the 8 black slots third (D1). $memtype="DDR3 DIMM"; $simmrangex="00008000"; # Guess $showrange=0; $simmbanks=4; # Assume largest DIMMs installed for prtconf-only data $simmsperbank=&roundup_memory($installed_memory) / 16384; @simmsizes=(4096,8192,16384); $familypn="T41B" if ($ultra eq "T4-1B"); $untested=0 if ($ultra eq "T4-1"); @socketstr=("MB/CMP0/BOB0/CH1/D0","MB/CMP0/BOB1/CH1/D0","MB/CMP0/BOB2/CH1/D0","MB/CMP0/BOB3/CH1/D0","MB/CMP0/BOB0/CH0/D0","MB/CMP0/BOB1/CH0/D0","MB/CMP0/BOB2/CH0/D0","MB/CMP0/BOB3/CH0/D0","MB/CMP0/BOB0/CH1/D1","MB/CMP0/BOB1/CH1/D1","MB/CMP0/BOB2/CH1/D1","MB/CMP0/BOB3/CH1/D1","MB/CMP0/BOB0/CH0/D1","MB/CMP0/BOB1/CH0/D1","MB/CMP0/BOB2/CH0/D1","MB/CMP0/BOB3/CH0/D1"); &check_for_LDOM; } if ($ultra eq "T4-2" || $ultra eq "T4-2B") { # SPARC T4-2 and T4-2B have 2 SPARC-T4 multicore processor with # 8-Threads, 8-Core, 2.85GHz # 32 DIMM slots for up to 512GB memory (32 x 16GB), 64GB min (16 x 4GB) # supports 4GB, 8GB & 16GB DDR3 DIMMs $memtype="DDR3 DIMM"; $simmrangex="00008000"; # Guess $showrange=0; $simmbanks=8; # Assume largest DIMMs installed for prtconf-only data $simmsperbank=&roundup_memory($installed_memory) / 16384; @simmsizes=(4096,8192,16384); $untested=0 if ($ultra eq "T4-2"); $untested=1 if ($banner =~ /Netra/i); @socketstr=("MB/CMP0/MR0/BOB0/CH0/D0","MB/CMP0/MR0/BOB0/CH1/D0","MB/CMP0/MR0/BOB1/CH0/D0","MB/CMP0/MR0/BOB1/CH1/D0","MB/CMP1/MR0/BOB0/CH0/D0","MB/CMP1/MR0/BOB0/CH1/D0","MB/CMP1/MR0/BOB1/CH0/D0","MB/CMP1/MR0/BOB1/CH1/D0","MB/CMP0/MR1/BOB0/CH0/D0","MB/CMP0/MR1/BOB0/CH1/D0","MB/CMP0/MR1/BOB1/CH0/D0","MB/CMP0/MR1/BOB1/CH1/D0","MB/CMP1/MR1/BOB0/CH0/D0","MB/CMP1/MR1/BOB0/CH1/D0","MB/CMP1/MR1/BOB1/CH0/D0","MB/CMP1/MR1/BOB1/CH1/D0","MB/CMP0/MR0/BOB0/CH0/D1","MB/CMP0/MR0/BOB0/CH1/D1","MB/CMP0/MR0/BOB1/CH0/D1","MB/CMP0/MR0/BOB1/CH1/D1","MB/CMP1/MR0/BOB0/CH0/D1","MB/CMP1/MR0/BOB0/CH1/D1","MB/CMP1/MR0/BOB1/CH0/D1","MB/CMP1/MR0/BOB1/CH1/D1","MB/CMP0/MR1/BOB0/CH0/D1","MB/CMP0/MR1/BOB0/CH1/D1","MB/CMP0/MR1/BOB1/CH0/D1","MB/CMP0/MR1/BOB1/CH1/D1","MB/CMP1/MR1/BOB0/CH0/D1","MB/CMP1/MR1/BOB0/CH1/D1","MB/CMP1/MR1/BOB1/CH0/D1","MB/CMP1/MR1/BOB1/CH1/D1"); &check_for_LDOM; } if ($ultra eq "T4-4") { # SPARC T4-4 has 4 SPARC-T4 multicore processor with # 8-Threads, 8-Core, 3.0GHz # 64 DIMM slots for up to 1TB memory (64 x 16GB), 64GB min (16 x 4GB) # supports 4GB, 8GB & 16GB DDR3 DIMMs $memtype="DDR3 DIMM"; $simmrangex="00008000"; # Guess $showrange=0; $simmbanks=16; # Assume largest DIMMs installed for prtconf-only data $simmsperbank=&roundup_memory($installed_memory) / 16384; @simmsizes=(4096,8192,16384); $untested=0; $untested=1 if ($banner =~ /Netra/i); @socketstr=("/SYS/PM0/CMP0/BOB0/CH0/D0","/SYS/PM0/CMP0/BOB0/CH1/D0","/SYS/PM0/CMP0/BOB1/CH0/D0","/SYS/PM0/CMP0/BOB1/CH1/D0","/SYS/PM0/CMP0/BOB2/CH0/D0","/SYS/PM0/CMP0/BOB2/CH1/D0","/SYS/PM0/CMP0/BOB3/CH0/D0","/SYS/PM0/CMP0/BOB3/CH1/D0","/SYS/PM0/CMP1/BOB0/CH0/D0","/SYS/PM0/CMP1/BOB0/CH1/D0","/SYS/PM0/CMP1/BOB1/CH0/D0","/SYS/PM0/CMP1/BOB1/CH1/D0","/SYS/PM0/CMP1/BOB2/CH0/D0","/SYS/PM0/CMP1/BOB2/CH1/D0","/SYS/PM0/CMP1/BOB3/CH0/D0","/SYS/PM0/CMP1/BOB3/CH1/D0","/SYS/PM1/CMP0/BOB0/CH0/D0","/SYS/PM1/CMP0/BOB0/CH1/D0","/SYS/PM1/CMP0/BOB1/CH0/D0","/SYS/PM1/CMP0/BOB1/CH1/D0","/SYS/PM1/CMP0/BOB2/CH0/D0","/SYS/PM1/CMP0/BOB2/CH1/D0","/SYS/PM1/CMP0/BOB3/CH0/D0","/SYS/PM1/CMP0/BOB3/CH1/D0","/SYS/PM1/CMP1/BOB0/CH0/D0","/SYS/PM1/CMP1/BOB0/CH1/D0","/SYS/PM1/CMP1/BOB1/CH0/D0","/SYS/PM1/CMP1/BOB1/CH1/D0","/SYS/PM1/CMP1/BOB2/CH0/D0","/SYS/PM1/CMP1/BOB2/CH1/D0","/SYS/PM1/CMP1/BOB3/CH0/D0","/SYS/PM1/CMP1/BOB3/CH1/D0"); &check_for_LDOM; } if ($ultra eq "T5-2") { # SPARC T5-2 has 2 SPARC-T5 multicore processor with # 8-Threads, 16-Core, 3.6GHz # 32 DIMM slots for up to 1TB memory (32 x 32GB), 256GB min (32 x 8GB) # supports 8GB, 16GB & 32GB DDR3 DIMMs # Each slot on a memory riser must be filled with a DIMM # All memory risers must contain the same type of DIMM $memtype="DDR3 DIMM"; $showrange=0; @simmsizes=(8192,16384,32768); $untested=0; # /SYS/MB/CM0/CMP/MR0/BOB0/CH0/D0 - /SYS/MB/CM1/CMP/MR3/BOB1/CH1/D0 for $s_cm (0,1) { for $s_mr (0..3) { for $s_bob (0,1) { for $s_ch (0,1) { push(@socketstr, "/SYS/MB/CM$s_cm/CMP/MR$s_mr/BOB$s_bob/CH$s_ch/D0"); } } } } &check_for_LDOM; } if ($ultra eq "T5-4") { # SPARC T5-4 has 4 SPARC-T5 multicore processor with # 8-Threads, 16-Core, 3.6GHz # 64 DIMM slots for 2TB memory (64 x 32GB) or 1TB min (64 x 16GB) # supports 16GB & 32GB DDR3 DIMMs # All DIMMs installed in the server must have identical capacities # All DIMMs installed in each processor module must be identical $memtype="DDR3 DIMM"; $showrange=0; @simmsizes=(16384,32768); $untested=0; # /SYS/PM0/CM0/CMP/BOB0/CH0/D0 - /SYS/PM1/CM1/CMP/BOB7/CH1/D0 for $s_pm (0,1) { for $s_cm (0,1) { for $s_bob (0..7) { for $s_ch (0,1) { push(@socketstr, "/SYS/PM$s_pm/CM$s_cm/CMP/BOB$s_bob/CH$s_ch/D0"); } } } } &check_for_LDOM; } if ($ultra eq "T5-8") { # SPARC T5-8 has 8 SPARC-T5 multicore processor with # 8-Threads, 16-Core, 3.6GHz # 128 DIMM slots for 4TB memory (128 x 32GB) or 2TB min (128 x 16GB) # supports 16GB & 32GB DDR3 DIMMs # All DIMMs installed in the server must have identical capacities # All DIMMs installed in each processor module must be identical $memtype="DDR3 DIMM"; $showrange=0; @simmsizes=(16384,32768); $untested=1; # /SYS/PM0/CM0/CMP/BOB0/CH0/D0 - /SYS/PM3/CM1/CMP/BOB7/CH1/D0 for $s_pm (0..3) { for $s_cm (0,1) { for $s_bob (0..7) { for $s_ch (0,1) { push(@socketstr, "/SYS/PM$s_pm/CM$s_cm/CMP/BOB$s_bob/CH$s_ch/D0"); } } } } &check_for_LDOM; } if ($ultra eq "T5-1B") { # SPARC T5-1B has 1 SPARC-T5 multicore processor with # 8-Threads, 16-Core, 3.6GHz # 16 DIMM slots for up to 512GB memory (16 x 32GB), 128GB min (16 x 8GB) # supports 8GB, 16GB & 32GB DDR3 DIMMs # Install quantities of 16 DIMMs # Ensure that all DIMMs are the same capacity and rank classification $memtype="DDR3 DIMM"; $showrange=0; @simmsizes=(8192,16384,32768); $untested=1; # /SYS/MB/CM0/CMP/BOB0/CH0/D0 - /SYS/MB/CM0/CMP/BOB7/CH1/D0 for $s_bob (0..7) { for $s_ch (0,1) { push(@socketstr, "/SYS/MB/CM0/CMP/BOB$s_bob/CH$s_ch/D0"); } } &check_for_LDOM; } if ($ultra eq "M5-32" || $ultra eq "M6-32") { # SPARC M5-32 has 8 to 32 SPARC M5 processor at 3.6GHz, each with: # 6 cores, 48 threads # 32 DIMM slots for up to 1TB memory (32 x 32GB) # supports 16GB & 32GB 1066MHz DDR3 DIMMs # SPARC M6-32 has 8 to 32 SPARC M5 processor at 3.6GHz, each with: # 12 cores, 96 threads # 32 DIMM slots for up to 1TB memory (32 x 32GB) # supports 16GB & 32GB 1066MHz DDR3 DIMMs # Each CMU (CPU Memory Unit) includes 2 CMPs and 64 DIMM slots # Each CMU can be Quarter, Half, or Fully-Populated # Quarter-Populated: CMP[01]/D0000-D1101 (16 DIMMs) # Half-Populated: CMP[01]/D0000-D1103 (32 DIMMs) # Fully-Populated: CMP[01]/D0000-D1113 (64 DIMMs) $memtype="DDR3 DIMM"; $showrange=0; @simmsizes=(16384,32768); $untested=1; # /SYS/CMU0/CMP0/D0000 - /SYS/CMU15/CMP1/D1113 $s_cmu=int(($npcpu/2)-1); for (0..$s_cmu) { for $s_cmp (0,1) { for $s_d1 (0,1) { for $s_d2 (0,1) { for $s_d3 (0,1) { for $s_d4 (0..3) { push(@socketstr, "/SYS/CMU$s_cmu/CMP$s_cmp/D$s_d1$s_d2$s_d3$s_d4"); } } } } } } &check_for_LDOM; } if ($ultra eq "M10-1") { # Fujitsu SPARC M10-1 has 1 SPARC64-X processor at 2.8GHz # 16 cores, 32 threads # 16 DIMM slots for up to 512GB memory (16 x 32GB), 128GB min (16 x 8GB) # supports 8GB, 16GB & 32GB R-DIMM or 64GB LR-DIMM # Mount memory in units of four or eight modules # Within a unit of four or eight modules, all the DIMMs must be of the # same capacity and rank # First mount memory group A, then mount memory group B $memtype="DIMM"; $showrange=0; @simmsizes=(8192,16384,32768,65536); $untested=0; # /SYS/MBU/CMP0/MEM[01][0-3][AB] for $s_memAB ("A","B") { for $s_cmp (0,1) { for $s_memN (0..3) { push(@socketstr, "/SYS/MBU/CMP0/MEM$s_cmp$s_memN$s_memAB"); } } } &check_for_LDOM; } if ($ultra eq "M10-4" || $ultra eq "M10-4S") { # Fujitsu SPARC M10-4 has up to 4 SPARC64-X processor at 2.8GHz # 16 cores, 32 threads each # 32 DIMM slots per memory unit for up to 2TB memory (32 x 64GB), 64GB min (8 x 8GB) # supports 8GB, 16GB & 32GB R-DIMM or 64GB LR-DIMM # Mount memory in units of eight modules # Within a unit of eight modules, all the DIMMs must be of the same # capacity and rank # First mount memory group A, then mount memory group B # M10-4S is a modular system that combines up to 16 M10-4 servers for # up to 64 processors and up to 32TB memory $memtype="DIMM"; $showrange=0; @simmsizes=(8192,16384,32768,65536); $untested=0; $untested=1 if ($ultra eq "M10-4S"); if ($npcpu > 4) { # M10-4S $ultra="M10-4S"; $untested=1; } # M10-4: /BB0/CMUL/CMP0/MEM0[0-7]A - /BB0/CMUU/CMP1/MEM1[0-7]B # M10-4S: /BB00/CMUL/CMP0/MEM0[0-7]A - /BB15/CMUU/CMP1/MEM1[0-7]B # Guess $bb=int(($npcpu/4)-1); # BB: Building Block for (0..$bb) { $bb="0$bb" if ($ultra eq "M10-4S" && $bb < 10); # Guess if (($npcpu/2) % 2) { push(@cmus, "/BB$bb/CMUL"); } else { push(@cmus, "/BB$bb/CMUU"); } for $s_cmu (@cmus) { for $s_cmp (0,1) { for $s_memAB ("A","B") { for $s_memN (0..7) { push(@socketstr, "$s_cmu/CMP$s_cmp/MEM$s_cmp$s_memN$s_memAB"); } } } } } &check_for_LDOM; } if ($ultra eq "S7-2" || $ultra eq "S7-2L") { # SPARC S7-2 has 1 or 2 SPARC S7 processors at 4.267GHz # SPARC S7-2L has 2 SPARC S7 processors at 4.267GHz # Each SPARC S7 processor supports: # 8 cores, 8 threads. # 16 DIMM slots for up to 1TB memory (16 x 64GB). # supports 16GB, 32GB & 64GB DDR4 DIMMs. # Do not mix DIMMs sizes. # Can be half populated (D0 white sockets), 4 DIMMs per CPU, or # fully populated (D0 white & D1 black sockets), 8 DIMMs per CPU. $memtype="DDR4 DIMM"; $showrange=0; @simmsizes=(16384,32768,65536); $untested=1; $untested=0 if ($ultra eq "S7-2"); $cmp_range=0; $cmp_range=1 if ($ncpu eq 2 || $corecnt eq 2); # /SYS/MB/CMP0/MCU0/CH0/D0 - /SYS/MB/CMP1/MCU1/CH1/D1 for $s_d (0,1) { for ($s_cmp=0; $s_cmp <= $cmp_range; $s_cmp++) { for $s_mcu (0,1) { for $s_ch (0,1) { push(@socketstr, "/SYS/MB/CMP$s_cmp/MCU$s_mcu/CH$s_ch/D$s_d"); } } } } &check_for_LDOM; } if ($ultra eq "T7-1") { # SPARC T7-1 has 1 SPARC M7 processors at 4.13GHz # SPARC M7 processor supports: # 32 cores, 8 threads # 16 DIMM slots for up to 1TB memory (16 x 64GB) # SPARC T7-1 supports: # 16GB, 32GB & 64GB DDR4 DIMMs # Left Memory Riser: /SYS/MB/CM/CMP/MR1/BOB[01]0/CH[01] # Left Motherboard: /SYS/MB/CM/CMP/BOB[13]1/CH[01] # Right Motherboard: /SYS/MB/CM/CMP/BOB[02]1/CH[01] # Right Memory Riser: /SYS/MB/CM/CMP/MR0/BOB[23]0/CH[01] # CH0 Black sockets, CH1 White sockets # In base configuration, all DIMM slots on motherboard must be # fully occupied (8 DIMMs). # In upgrade configuration (16 DIMMs), both memory risers are # added and must be fully occupied. $memtype="DDR4 DIMM"; $showrange=0; @simmsizes=(16384,32768,65536); $untested=1; for $s_bob (0..3) { # Motherboard for $s_ch (0,1) { push(@socketstr, "/SYS/MB/CM/CMP/BOB${s_bob}1/CH$s_ch"); } } for $s_bob (0,1) { # MR1 for $s_ch (0,1) { push(@socketstr, "/SYS/MB/CM/CMP/MR1/BOB${s_bob}0/CH$s_ch"); } } for $s_bob (2,3) { # MR0 for $s_ch (0,1) { push(@socketstr, "/SYS/MB/CM/CMP/MR0/BOB${s_bob}0/CH$s_ch"); } } &check_for_LDOM; } if ($ultra eq "T7-2") { # SPARC T7-2 has 2 SPARC M7 processors at 4.13GHz # SPARC M7 processor supports: # 32 cores, 8 threads # 16 DIMM slots for up to 1TB memory (16 x 64GB) # SPARC T7-2 supports: # 16GB, 32GB & 64GB DDR4 DIMMs # /SYS/MB/CM[01]/CMP/MR[0-3]/BOB[01]/CH[01]/DIMM # CH0 Black sockets, CH1 White sockets # All 8 memory risers must be installed in all configurations # Half-populated configurations populate CH0 Black sockets (16 DIMMs) # Full-populated configurations fill CH0 and CH1 sockets (32 DIMMs) $memtype="DDR4 DIMM"; $showrange=0; @simmsizes=(16384,32768,65536); $untested=1; for $s_ch (0,1) { for $s_cm (0,1) { for $s_mr (0..3) { for $s_bob (0,1) { push(@socketstr, "/SYS/MB/CM$s_cm/CMP/MR$s_mr/BOB$s_bob/CH$s_ch/DIMM"); } } } } &check_for_LDOM; } if ($ultra eq "T7-4") { # SPARC T7-4 has 2 or 4 SPARC M7 processors at 4.13GHz # SPARC M7 processor supports: # 32 cores, 8 threads # 16 DIMM slots for up to 1TB memory (16 x 64GB) # SPARC T7-4 supports: # 16GB, 32GB & 64GB DDR4 DIMMs # /SYS/PM[0-3]/CM[01]/CMP/BOB[0-3][01]/CH[01]/DIMM # CH0 Black sockets, CH1 White sockets # Half-populated configurations populate CH0 Black sockets (16 DIMMs) # Full-populated configurations fill CH0 and CH1 sockets (32 DIMMs) $memtype="DDR4 DIMM"; $showrange=0; @simmsizes=(16384,32768,65536); $untested=0; for $s_pm (0..$npcpu-1) { for $s_ch (0,1) { for $s_cm (0,1) { for $s_boba (0..3) { for $s_bobb (0,1) { push(@socketstr, "/SYS/PM$s_pm/CM$s_cm/CMP/BOB$s_boba$s_bobb/CH$s_ch/DIMM"); } } } } } &check_for_LDOM; } if ($ultra eq "M7-8" || $ultra eq "M7-16") { # SPARC M7-8 has 2 to 8 SPARC M7 processors at 4.13GHz # SPARC M7-16 has 4 to 16 SPARC M7 processors at 4.13GHz # Each SPARC M7 processor has 32 cores, 8 threads # SPARC M7-8 & M7-16 supports: # 16 DIMM slots for up to 512GB memory (16 x 32GB) # supports 16GB & 32GB DDR4 DIMMs # SPARC M7-8, has CMIOU_0 to CMIOU_7 # SPARC M7-16, has CMIOU_0 to CMIOU_15 # /SYS/CMIOU[0-15]/CM/CMP/BOB[0-3][01]/CH[01]/DIMM # CH0 Black sockets, CH1 White sockets # Half-populated configurations populate CH0 Black sockets (8 DIMMs) # Full-populated configurations fill CH0 and CH1 sockets (16 DIMMs) $memtype="DDR4 DIMM"; $showrange=0; @simmsizes=(16384,32768); $untested=1; for $s_cmiou (0..$npcpu-1) { for $s_ch (0,1) { for $s_boba (0..3) { for $s_bobb (0,1) { push(@socketstr, "/SYS/CM$s_cmiou/CM/CMP/BOB$s_boba$s_bobb/CH$s_ch/DIMM"); } } } } &check_for_LDOM; } if ($model eq "SPARC-Enterprise" || $ultra =~ /SPARC Enterprise M[34589]000 Server/) { # CPUs: Dual-Core Dual-Thread SPARC64-VI or # Quad-Core Dual-Thread SPARC64-VII, VII+, VII++ # M3000: 2RU rack, single SPARC64-VII 2.52GHz cpu # up to 32GB, uses DDR2-533 4GB or 8GB memory DIMMs # M4000: 6RU rack, up to 4 SPARC64-VI or SPARC64-VII cpus # Up to 2 CPU (CMU), 2 CPUs per board # Main memory Up to 128 GB per domain / system, up to 4 memory # boards w/ maximum 32GB per board using 8 DDR2 4GB memory DIMMs # M5000: 10RU rack, up to 8 SPARC64-VI or SPARC64-VII cpus # Up to 4 CPU (CMU), 2 CPUs per board # Main memory Up to 256 GB per domain / system, up to 8 memory # boards w/ maximum 32GB per board using 8 DDR2 4GB memory DIMMs # M8000: up to 16 SPARC64-VI or SPARC64-VII cpus # Up to 4 CPU memory boards (CMU), Up to 4 processors and up to # 128 GB memory per board based on 32 4GB DIMMs # Main memory Up to 512GB per domain / system # M9000: 32 or 64 SPARC64-VI or SPARC64-VII cpus # 32 CPU # Up to 8 CPU memory boards (CMU), Up to 4 processors and up to # 128 GB memory per board based on 32 4GB DIMMs # Main memory Up to 1TB per domain / system # 64 CPU # Up to 16 CPU memory boards (CMU), Up to 4 processors and up to # 128 GB memory per board based on 32 4GB DIMMs # Main memory Up to 2TB per domain / system $familypn="SEW" if ($ultra =~ /Sun SPARC Enterprise M3000 Server/); if ($ultra =~ /Sun SPARC Enterprise M4000 Server/) { $devname="OPL FF1"; $familypn="SEE"; } if ($ultra =~ /Sun SPARC Enterprise M5000 Server/) { $devname="OPL FF2"; $familypn="SEF"; } $familypn="SEG" if ($ultra =~ /Sun SPARC Enterprise M8000 Server/); $familypn="SEH/SEJ" if ($ultra =~ /Sun SPARC Enterprise M9000 Server/); $untested=1; $untested=0 if ($ultra =~ /SPARC Enterprise M[34589]000 Server/); $prtdiag_has_mem=1; @simmsizes=(1024,2048,4096); } if (($model =~ /-Enterprise/ || $ultra eq "e") && $model !~ /SPARC-Enterprise/) { # E3x00/E4x00/E5x00/E6x00 accepts 8MB, 32MB, 128MB or 256MB DIMMs on # motherboard, 2 banks of 8 DIMMs per board. # 256MB DIMMs (2GB kit X7026A) can be used with OBP 3.2.24 or later and # Solaris 2.5.1 11/97, Solaris 2.6 3/98 or later # 501-2652 (8MB), 501-2653 (32MB), 501-2654 (128MB), 501-5658 (256MB) # 168-pin 60ns 3.3V ECC # E10000 accepts 32MB or 128MB DIMMs on motherboard, # using 2 or 4 banks of 8 DIMMs per board. # 501-2653 (32MB), 501-2654 (128MB) # 168-pin 60ns 3.3V ECC $devname="Duraflame" if ($banner =~ /\bE?3[05]00\b/); $devname="Campfire Rack" if ($banner =~ /\bE?5[05]00\b/); $devname="Campfire" if ($banner =~ /\bE?4[05]00\b/); $devname="Sunfire" if ($banner =~ /\bE?6[05]00\b/); $devname .= "+" if ($banner =~ /\bE?[3-6]500\b/); $devname="Starfire" if ($model =~ /-10000\b/); $familypn="E3000, A17" if ($banner =~ /\bE?3000\b/); $familypn="E3500" if ($banner =~ /\bE?3500\b/); $familypn="E4000, A18" if ($banner =~ /\bE?4000\b/); $familypn="E4500" if ($banner =~ /\bE?4500\b/); $familypn="E5000" if ($banner =~ /\bE?5000\b/); $familypn="E5500" if ($banner =~ /\bE?5500\b/); $familypn="E6000" if ($banner =~ /\bE?6000\b/); $familypn="E6500" if ($banner =~ /\bE?6500\b/); $familypn="E10000" if ($model =~ /-10000\b/); $untested=1; if ($banner =~ /\bE?[3-6][05]00\b/ || $model =~ /-Enterprise-E?[3-6][05]00/ || $model eq "Ultra-Enterprise") { $untested=0; @simmsizes=(8,32,128,256); } if ($model =~ /-Enterprise-10000\b/) { $untested=0; @simmsizes=(32,128); } $prtdiag_has_mem=1; @prtdiag=&run("$prtdiag_exec") if (! $filename); $i=0; $flag_cpu=0; $flag_mem=0; foreach $line (@prtdiag) { $line=&dos2unix($line); if ($line =~ /Memory Units:/) { # Start of memory section, Solaris 2.5.1 format $flag_mem=1; $format_mem=1; $flag_cpu=0; # End of CPU section } if ($line =~ /====( | Physical )Memory /) { # Start of memory section, Solaris 2.6 and later format $flag_mem=1; $format_mem=2; $flag_cpu=0; # End of CPU section } if ($line =~ /Factor/) { # No interleave factor on E10000 $format_mem += 2 if ($format_mem == 1 || $format_mem == 2); } if ($line =~ /Failed Field Replaceable Unit/) { $tmp=$line; $tmp=~s/^\t/ /g; $failed_fru .= $tmp; } if ($line =~ /IO Cards/) { $flag_cpu=0; # End of CPU section $flag_mem=0; # End of memory section } if ($flag_cpu && $line !~ /^\s*\n$/) { push(@boards_cpu, "$line"); $boardfound_cpu=1; $boardslot_cpu=($line =~ /Board/) ? substr($line,6,2) : substr($line,0,2); $boardslot_cpu=~s/[: ]//g; if ($flag_cpu == 2 && $boardslot_cpus !~ /\s$boardslot_cpu\s/ && $boardslot_cpu) { push(@boardslot_cpus, "$boardslot_cpu"); $boardslot_cpus .= $boardslot_cpu . " "; } } if ($line =~ /CPU Units:/) { $flag_cpu=1; # Start of CPU section $flag_mem=0; # End of memory section $format_cpu=1; } if ($line =~ /====( | Virtual )CPUs ====/) { $flag_cpu=1; # Start of CPU section $flag_mem=0; # End of memory section $format_cpu=2; } if ($flag_mem == 2 && $line !~ /^\s*\n$/) { $memfrom="prtdiag"; $boardslot_mem=($line =~ /Board/) ? substr($line,5,2) : substr($line,0,2); $boardslot_mem=~s/[: ]//g; if ($boardslot_mems !~ /\s$boardslot_mem\s/) { push(@boardslot_mems, "$boardslot_mem"); $boardslot_mems .= $boardslot_mem . " "; } if ($format_mem == 1) { # Memory on each system board, E10000 $mem0=substr($line,12,4); $mem0=0 if ($mem0 !~ /\d+/); $dimm0=$mem0 / 8; if ($dimm0) { $dimms0=sprintf("8x%3d", $dimm0); push(@simmsizesfound, "$dimm0"); } else { $dimms0=" "; &found_empty_bank("Bank 0"); } $mem1=substr($line,20,4); $mem1=0 if ($mem1 !~ /\d+/); $dimm1=$mem1 / 8; if ($dimm1) { $dimms1=sprintf("8x%3d", $dimm1); push(@simmsizesfound, "$dimm1"); } else { $dimms1=" "; &found_empty_bank("Bank 1"); } $mem2=substr($line,28,4); $mem2=0 if ($mem2 !~ /\d+/); $dimm2=$mem2 / 8; if ($dimm2) { $dimms2=sprintf("8x%3d", $dimm2); push(@simmsizesfound, "$dimm2"); } else { $dimms2=" "; &found_empty_bank("Bank 2"); } $mem3=substr($line,36,4); $mem3=0 if ($mem3 !~ /\d+/); $dimm3=$mem3 / 8; if ($dimm3) { $dimms3=sprintf("8x%3d", $dimm3); push(@simmsizesfound, "$dimm3"); } else { $dimms3=" "; &found_empty_bank("Bank 3"); } $newline=substr($line,0,10); $newline .= " " . $mem0 . " " . $dimms0; $newline .= " " . $mem1 . " " . $dimms1; $newline .= " " . $mem2 . " " . $dimms2; $newline .= " " . $mem3 . " " . $dimms3; $newline .= "\n"; push(@boards_mem, "$newline"); $boardfound_mem=1; } if ($format_mem == 2) { # Memory on each system board, E10000 # untested ??? reporting of empty banks $untested=1; $bank_slot=substr($line,6,2); $mem=substr($line,12,4); $mem=0 if ($mem !~ /\d+/); $dimm=$mem / 8; if ($dimm) { $dimms=sprintf("8x3d", $dimm); push(@simmsizesfound, "$dimm"); $newline=substr($line,0,18) . $dimms; $newline .= substr($line,16,47); push(@boards_mem, "$newline"); $boardfound_mem=1; $failed_memory += $mem if ($newline =~ /\b\bFailed\b\b/); $spare_memory += $mem if ($newline =~ /\b\bSpare\b\b/); } else { $flag_mem=0; &found_empty_bank("Bank $bank_slot"); } if ($bank_slot == 0) { $next_boardslot_mem=substr($prtdiag[$i + 1],0,2); $next_boardslot_mem=~s/[: ]//g; &found_empty_bank("Bank 1") if ($next_boardslot_mem ne $boardslot_mem); } if ($bank_slot == 1) { $prev_boardslot_mem=substr($prtdiag[$i - 1],0,2); $prev_boardslot_mem=~s/[: ]//g; &found_empty_bank("Bank 0") if ($prev_boardslot_mem ne $boardslot_mem); } } if ($format_mem == 3) { # Memory on each system board, E[3456]x00 $mem0=substr($line,10,4); $mem0=0 if ($mem0 !~ /\d+/); $dimm0=$mem0 / 8; if ($dimm0) { $dimms0=sprintf("8x%3d", $dimm0); push(@simmsizesfound, "$dimm0"); } else { $dimms0=" "; &found_empty_bank("Bank 0"); } $memlength=length($line); $mem1=($memlength > 34) ? substr($line,34,4) : 0; $mem1=0 if ($mem1 !~ /\d+/); $dimm1=$mem1 / 8; if ($dimm1) { $dimms1=sprintf("8x%3d", $dimm1); push(@simmsizesfound, "$dimm1"); } else { $dimms1=" "; &found_empty_bank("Bank 1"); } $newline=substr($line,0,16) . $dimms0; $newline .= substr($line,16,24); if ($dimm1) { $newline .= $dimms1; $newline .= substr($line,39,16); } push(@boards_mem, "$newline"); $boardfound_mem=1; } if ($format_mem == 4) { # Memory on each system board, E[3456]x00 $bank_slot=substr($line,7,1); $mem=substr($line,12,4); $mem=0 if ($mem !~ /\d+/); $dimm=$mem / 8; if ($dimm) { $dimms=sprintf("8x%3d", $dimm); push(@simmsizesfound, "$dimm"); $newline=substr($line,0,18) . $dimms; $newline .= substr($line,16,47); push(@boards_mem, "$newline"); $boardfound_mem=1; $failed_memory += $mem if ($newline =~ /\b\bFailed\b\b/); $spare_memory += $mem if ($newline =~ /\b\bSpare\b\b/); } else { $flag_mem=0; &found_empty_bank("Bank $bank_slot"); } if ($bank_slot == 0) { $next_boardslot_mem=substr($prtdiag[$i + 1],0,2); $next_boardslot_mem=~s/[: ]//g; &found_empty_bank("Bank 1") if ($next_boardslot_mem ne $boardslot_mem); } if ($bank_slot == 1) { $prev_boardslot_mem=substr($prtdiag[$i - 1],0,2); $prev_boardslot_mem=~s/[: ]//g; &found_empty_bank("Bank 0") if ($prev_boardslot_mem ne $boardslot_mem); } } } if ($flag_cpu == 1 && $line =~ /-----/) { # Next lines are the CPUs on each system board $flag_cpu=2; } if ($flag_mem == 1 && $line =~ /-----/) { # Next lines are the memory on each system board $flag_mem=2; } $i++; } &show_header; if ($boardfound_mem) { if ($boardfound_cpu) { foreach $board (@boardslot_cpus) { if ($boardslot_mems !~ /\s$board\s/) { $boardslot_mem=$board; if ($format_mem <= 2) { # E10000 &found_empty_bank("Bank 0"); &found_empty_bank("Bank 1"); &found_empty_bank("Bank 2"); &found_empty_bank("Bank 3"); } else { # E3x00/E4x00/E5x00/E6x00 &found_empty_bank("Bank 0"); &found_empty_bank("Bank 1"); } } } } if ($format_mem == 1) { # E10000 running Solaris 2.5.1 print " Bank 0 Bank 1 Bank 2 Bank 3\n"; print " MB DIMMs MB DIMMs MB DIMMs MB DIMMs\n"; print " ---- ----- ---- ----- ---- ----- ---- -----\n"; print @boards_mem; } if ($format_mem == 2) { # E10000 running Solaris 2.6 or later print "Brd Bank MB DIMMs Status Condition Speed\n"; print "--- ----- ---- ----- ------- ---------- -----\n"; print @boards_mem; } if ($format_mem == 3) { # E3x00/E4x00/E5x00/E6x00 running Solaris 2.5.1 print " Bank 0 Bank 1\n"; print " J3100-J3800 Interleave J3101-J3801 Interleave\n"; print " MB DIMMs Factor With MB DIMMs Factor With\n"; print " ---- ----- ------ ---- ---- ----- ------ ----\n"; print @boards_mem; } if ($format_mem == 4) { # E3x00/E4x00/E5x00/E6x00 running Solaris 2.6 or later print " Intrlv. Intrlv.\n"; print "Brd Bank MB DIMMs Status Condition Speed Factor With\n"; print "--- ----- ---- ----- ------- ---------- ----- ------- -------\n"; print @boards_mem; print "Bank 0 uses sockets J3100-J3800, Bank 1 uses sockets J3101-J3801\n"; } $empty_banks=" None" if (! $empty_banks); print "empty memory banks:$empty_banks\n"; } $totmem=$installed_memory; &finish; &pdebug("exit"); exit; } # # Check to see if this system has memory defined in the prtdiag output # &check_prtdiag; $model=$diagbanner if ($diagbanner && $isX86); $untested=0 if ($boardfound_mem && $isX86 && ! $have_x86_devname); &x86_devname; # Don't use prtdiag data on this clone $boardfound_mem=0 if ($manufacturer eq "AXUS"); # # Check to see if this system has module information in prtconf output # (Seen on Fujitsu GP7000, GP7000F, PrimePower) # if ($gotmodule || $gotmodulenames) { @simmslots=($gotmodulenames) ? split(/\./, $gotmodulenames) : split(/\./, $gotmodule); $totmem=0; for ($val=0; $val < scalar(@simmslots); $val += 2) { $socket=($gotmodulenames) ? $simmslots[$val] : "SLOT" . $val / 2; $simmsz=$simmslots[$val + 1]; $simmsize=hex("0x$simmsz") / $meg; $perlhexbug=1 if ($simmsize <= 0 && $simmsz ne "00000000"); $totmem += $simmsize; if ($simmsize) { push(@simmsizesfound, "$simmsize"); if (! $boardfound_mem) { push(@memorylines, "$socket has a ${simmsize}MB"); if ($simmsize > 1023) { push(@memorylines, " ("); push(@memorylines, $simmsize/1024); push(@memorylines, "GB)"); } push(@memorylines, " $memtype\n"); } $sockets_used .= " $socket"; } } &show_header; &pdebug("displaying memory from $memfrom") if ($memfrom); print (($boardfound_mem) ? @boards_mem : @memorylines); $totmem=$installed_memory; &finish; &pdebug("exit"); exit; } # # Check to see if this system has module information in ipmitool output # if ($have_ipmitool_data) { &check_ipmitool; $tmp=scalar(keys %ipmi_mem); if (defined($tmp)) { if ($tmp) { &pdebug("Memory found with ipmitool"); &show_header; for (sort alphanumerically keys %ipmi_mem) { if ($ipmi_mem{$_}) { print "socket $_: $ipmi_mem{$_}\n"; $simmsize=$ipmi_mem{$_}; $simmsize=~s/^.*\b(\d+)M[Bb].*/$1/; $ipmi_memory += $simmsize if ($simmsize); } else { &add_to_sockets_empty($_); } } $totmem=$installed_memory; &print_empty_memory("memory sockets"); &finish; &pdebug("exit"); exit; } } } # # Check to see if this system has cpu information in kstat output to recognize # Hyper-Threaded Intel CPUs # &check_kstat if ($have_kstat_data); # # Check to see if this system has module information in smbios output # &check_smbios if ($have_smbios_data); # # Check to see if this system has module information in prtfru output # &check_prtfru; # # Display memory if found in prtdiag and/or prtfru output # if ($boardfound_mem) { &show_header; &pdebug("displaying memory from $memfrom") if ($memfrom); &pdebug("displaying memory from prtfru") if ($fru_details && $memfrom ne "prtfru"); # Rewrite prtdiag output to exclude DIMM5-DIMM8 on W1100z if ($model =~ /W1100z\b/i && $model !~ /2100z\b/i) { @new_boards_mem=""; foreach $line (@boards_mem) { push(@new_boards_mem, "$line") if ($line !~ /DIMM[5-8]/); } @boards_mem=@new_boards_mem; } print @boards_mem if (! &is_virtualmachine); if ($have_prtfru_details) { print "FRU Memory Data:\n-----------------------------------------------------------------------\n$fru_details"; if ($missing_prtfru_details ne " ") { print "NOTICE: Not all memory modules reported detailed FRU data\n"; } print "-----------------------------------------------------------------------\n"; } $totmem=$installed_memory; } # # Look for empty memory banks on Sun Fire 3800, 4800, 4810, 6800, 12K, 15K and # Netra T12 systems. Also Sun Fire E2900, E4900, E6900, E20K and E25K. # if ($ultra eq "Sun Fire" || $ultra eq "Sun Fire 15K" || $ultra eq "Sun Fire 12K" || $ultra eq "Netra T12" || $ultra =~ /Sun Fire ([346]8[01]0|E[246]900|E2[05]K)\b/) { foreach $cpu (@boardslot_cpus) { $empty_banks .= " $cpu/B0" if ($boardslot_mems !~ /$cpu\/B0/); $empty_banks .= " $cpu/B1" if ($boardslot_mems !~ /$cpu\/B1/); } $empty_banks=" None" if (! $empty_banks); if ($boardslot_mems eq " ") { $empty_banks=" Unknown"; $exitstatus=1; } print "empty memory banks:$empty_banks\n" if ($boardfound_mem); } if ($boardfound_mem) { &finish; &pdebug("exit"); exit; } # # OK, get ready to print out results # for ($val=$val0; $val < scalar(@slots); $val += $valinc) { $newaddrmsb=substr($slots[$val - $valaddr - 1],3,5); $newaddrlsb=substr($slots[$val - $valaddr],0,3); $newsizemsb=($valinc == 4) ? substr($slots[$val - 1],3,5) : ""; $newsizelsb=substr($slots[$val],0,3); # Round up for DIMM value seen on US-T1 and US-T2 Niagara systems # Two Ranks of DIMMs appear as one in prtconf if ($newsizelsb eq "ff8") { if ($newsizemsb eq "00000") { $newsizemsb="00001"; # 512MB if ($ultra eq "T2000") { # Hack: 1 rank of smallest DIMMs $simmbanks=2; $simmsperbank=8; } # Hack: Could be 1 Rank of 1GB on T1000 $recognized=-1 if ($ultra eq "T1000" && scalar(@slots) == 4); } elsif ($newsizemsb eq "00001") { $newsizemsb="00002"; # 1GB # Hack: Could be 1 Rank of 1GB on T2000 $recognized=-1 if ($ultra eq "T2000" && scalar(@slots) == 4); # Hack: Could be 1 Rank of 2GB on T1000 $recognized=-1 if ($ultra eq "T1000" && scalar(@slots) == 4); } elsif ($newsizemsb eq "00003") { $newsizemsb="00004"; # 2GB # Hack: Could be 1 Rank of 2GB on T2000 $recognized=-1 if ($ultra eq "T2000" && scalar(@slots) == 4); } elsif ($newsizemsb eq "00007") { $newsizemsb="00008"; # Fully stuffed 2 Ranks of 2GB } $newsizelsb="000"; $installed_memory += 8; } elsif ($newsizelsb eq "7f8" && $newsizemsb eq "00000") { if ($ultra eq "T1000") { # Hack: 1 rank of smallest DIMMs $newsizelsb="800"; # 512MB $simmbanks=2; $simmsperbank=4; } else { $newsizelsb="800"; # Hack: unsupported 256MB DIMM } $installed_memory += 8; } elsif ($newsizelsb eq "f80") { if ($newsizemsb eq "00001") { $newsizemsb="00002"; # 1GB } elsif ($newsizemsb eq "00003") { $newsizemsb="00004"; # 2GB } elsif ($newsizemsb eq "00007") { $newsizemsb="00008"; # 4GB } elsif ($newsizemsb eq "0000f") { $newsizemsb="00010"; # 8GB } $newsizelsb="000"; $installed_memory += 128; } if ($sortslots) { $mods{"$newaddrmsb$newaddrlsb"}="$newsizemsb$newsizelsb"; } else { push(@newslots, "$newaddrmsb$newaddrlsb"); push(@newslots, "$newsizemsb$newsizelsb"); } } if ($sortslots) { for (sort alphanumerically keys %mods) { push(@newslots, $_); push(@newslots, $mods{$_}); } } # For Ultra-30, determine if interleaving of banks using four DIMMs if ($model eq "Ultra-30" || $ultra eq 30) { $interleave=2; # pairs show up in odd numbered address ranges for ($val=0; $val < scalar(@newslots); $val += 2) { $interleave=1 if ($newslots[$val] =~ /00000[1357]00/); } if ($interleave eq 2) { $simmrangex="00000200"; $simmbanks=4; $simmsperbank=4; } else { $simmrangex="00000100"; $simmbanks=8; $simmsperbank=2; } } # Check if SPARCsystem-600 has VME memory expansion boards if ($model eq "SPARCsystem-600" || $model =~ /Sun.4.600/) { for ($val=0; $val < scalar(@newslots); $val += 2) { if ($newslots[$val] =~ /00000[4-9ab]00/) { @simmsizes=(1,4,16); push(@socketstr, @socketstr_exp); push(@bankstr, @bankstr_exp); push(@bytestr, @bytestr_exp); $exp=($newslots[$val] =~ /00000[4-7]00/) ? "Expansion board 0 bank" : "Expansion board 1 bank"; push(@banksstr, ("$exp B0","$exp B1", "$exp B2","$exp B3")); } } } # Hack: Rewrite interleaved memory line for Ultra-80 or Enterprise 420R if (($model eq "Ultra-80" || $ultra eq 80 || $ultra eq "420R" || $ultra eq "Netra t140x") && $newslots[0] eq "00000000") { if ($newslots[1] eq "00001000" && $installed_memory eq 4096) { # 4GB of memory (maximum) using 16x256MB in Banks 0-3 $newslots[1]="00000400"; $newslots[2]="00000400"; $newslots[3]="00000400"; $newslots[4]="00000800"; $newslots[5]="00000400"; $newslots[6]="00000c00"; $newslots[7]="00000400"; $interleave=4; } elsif ($newslots[1] eq "00000800" && $installed_memory eq 2048) { # 2GB of memory using 8x256MB in Banks 0,1 $newslots[1]="00000400"; $newslots[2]="00000400"; $newslots[3]="00000400"; $interleave=2; } elsif ($newslots[1] =~ /00000[97653]00/) { # Early OBP releases showed total memory as a single bank $recognized=-1; } elsif ($newslots[1] eq "00000400" && $installed_memory eq 1024) { # 1GB of memory can be 4x256MB in Bank 0 or 16x64MB in Banks 0-3 # so flag OBP bug $recognized=-1; } elsif ($newslots[1] eq "00000200" && $installed_memory eq 512) { # 512MB of memory using 8x64MB in Banks 0,1 $newslots[1]="00000100"; $newslots[2]="00000400"; $newslots[3]="00000100"; $interleave=2; } } # Hack: Fix address ranges for Tatung COMPstation U60 and U80D if ($banner =~ /COMPstation_U(60|80D)_Series/) { # Tatung Science and Technology, http://www.tsti.com for ($val=0; $val < scalar(@newslots); $val += 2) { $simmbanks=4 if ($newslots[$val] =~ /00000[46]00/); # Check for 256MB DIMMs or 256MB address range per bank if ($newslots[$val + 1] =~ /00000400/ || $newslots[$val] =~ /00000c00/) { $simmrangex="00000400"; $simmbanks=4; } } if ($simmbanks eq 6) { # Skipped address range similar to Sun Ultra 60 @socketstr=("J17","J32","J36","J40","J18","J33","J37","J41","?","?","?","?","?","?","?","?","J19","J34","J38","J42","J20","J35","J39","J43"); @slotstr=(1..8,"?","?","?","?","?","?","?","?",9..16); @bankstr=(0,0,0,0,1,1,1,1,"?","?","?","?","?","?","?","?",2,2,2,2,3,3,3,3); } else { @socketstr=("J17","J32","J36","J40","J18","J33","J37","J41","J19","J34","J38","J42","J20","J35","J39","J43"); @slotstr=(1..16); @bankstr=(0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3); } } # Hack: Try to rewrite memory line for Sun Blade 1000 & 2000 if prtdiag output # did not show the memory. This does not expect 2GB DIMMs to be used. if (($ultra eq "Sun Blade 1000" || $ultra eq "Sun Blade 2000" || $ultra eq "Sun Fire 280R") && ! $boardfound_mem) { # Assume 8GB is 8x1GB instead of 4x2GB if ($newslots[1] eq "00002000") { $newslots[1]="00001000"; $newslots[2]="00001000"; $newslots[3]="00001000"; $recognized=-2; } # Assume 6GB is 4x1GB + 4x512MB instead of 4x1.5GB if ($newslots[1] eq "00001800") { $newslots[1]="00001000"; $newslots[2]="00001000"; $newslots[3]="00000800"; $recognized=-1; } # Assume 5GB is 4x1GB + 4x256MB instead of 4x1280MB if ($newslots[1] eq "00001400") { $newslots[1]="00001000"; $newslots[2]="00001000"; $newslots[3]="00000400"; $recognized=-1; } # Assume 4.5GB is 4x1GB + 4x128MB instead of 4x1152MB if ($newslots[1] eq "00001200") { $newslots[1]="00001000"; $newslots[2]="00001000"; $newslots[3]="00000200"; $recognized=-1; } # Assume 3GB is 4x512MB + 4x256MB instead of 4x768MB if ($newslots[1] eq "00000c00") { $newslots[1]="00000800"; $newslots[2]="00001000"; $newslots[3]="00000400"; $recognized=-1; } # Assume 2.5GB is 4x512MB + 4x128MB instead of 4x640MB if ($newslots[1] eq "00000a00") { $newslots[1]="00000800"; $newslots[2]="00001000"; $newslots[3]="00000200"; $recognized=-1; } # Assume 1.5GB is 4x256MB + 4x128MB instead of 4x384MB if ($newslots[1] eq "00000600") { $newslots[1]="00000400"; $newslots[2]="00001000"; $newslots[3]="00000200"; $recognized=-1; } } # for prtconf output only, or fully stuffed LDOM servers if ($ultra eq "T5120" || $ultra eq "T5220" || $ultra eq "T6320" || $ultra eq "T5140") { # Hack: Rewrite fully stuffed memory line if ($installed_memory >= 130816) { $newslots[0]="00000000"; $newslots[1]="00008000"; $newslots[2]="00008000"; $newslots[3]="00008000"; $newslots[4]="00010000"; $newslots[5]="00008000"; $newslots[6]="00018000"; $newslots[7]="00008000"; } } if ($ultra eq "T5240" || $ultra eq "T6340") { # Hack: Rewrite fully stuffed memory line if ($installed_memory >= 261632) { $newslots[0]="00000000"; $newslots[1]="00008000"; $newslots[2]="00008000"; $newslots[3]="00008000"; $newslots[4]="00010000"; $newslots[5]="00008000"; $newslots[6]="00018000"; $newslots[7]="00008000"; $newslots[8]="00020000"; $newslots[9]="00008000"; $newslots[10]="00028000"; $newslots[11]="00008000"; $newslots[12]="00030000"; $newslots[13]="00008000"; $newslots[14]="00038000"; $newslots[15]="00008000"; } } # Check for dual bank DIMMs on Ultra AXmp+ if ($ultra eq "AXmp+") { if ($#newslots eq 1 && $newslots[0] eq "00000c00") { $simmsperbank=4; $dualbank=1; } if ($#newslots eq 3) { if ($newslots[2] =~ /00000[8c]00/) { $simmrangex="00000800"; $dualbank=1 if ($newslots[1] eq $newslots[3]); } } if ($#newslots ge 5) { $dualbank=1 if ($newslots[4] =~ /00000[8c]00/); } if ($dualbank eq 1) { @bankstr=("0,2","0,2","0,2","0,2","0,2","0,2","0,2","0,2","1,3","1,3","1,3","1,3","1,3","1,3","1,3","1,3"); # Rearrange slots if necessary if ($#newslots ge 5) { if ($newslots[4] eq "00000800") { $tmp=$newslots[2]; $newslots[2]=$newslots[4]; $newslots[4]=$tmp; $tmp=$newslots[3]; $newslots[3]=$newslots[5]; $newslots[5]=$tmp; } } } } $totmem=0; for ($val=0; $val < scalar(@newslots); $val += 2) { &pdebug("displaying memory from $memfrom") if ($memfrom); $simmaddr=$newslots[$val]; $simmsz=$newslots[$val + 1]; $simmsize=hex("0x$simmsz"); $simmsize=&roundup_memory($simmsize) if ($simmsize > 16384); $perlhexbug=1 if ($simmsize <= 0 && $simmsz ne "00000000"); $totmem += $simmsize; if (($model eq "Sun 4/75" || $model eq "SS-2") && ($simmbanks < $bankcnt + 2)) { # SS2 SBus memory card $buffer=($simmaddr eq "00000080") ? "${buffer}SBus primary" : "${buffer}SBus secondary"; $start1=hex("0x$simmaddr") * $meg; $perlhexbug=1 if ($start1 < 0); $simmrange=hex("0x$simmrangex") * $meg; $perlhexbug=1 if ($simmrange <= 0 && $simmrangex ne "00000000"); $start1x=sprintf("%08lx", $start1); $stop1x=sprintf("%08lx", $start1 + (2 * $simmrange) - 1); $totmem += $simmsize; $simmsize *= 2; $val += 2; $buffer .= " contains ${simmsize}MB"; $buffer .= " (address 0x${start1x}-0x$stop1x)" if ($verbose); $buffer .= "\n"; } elsif ($simmbanks) { $start1=hex("0x$simmaddr") * $meg; $perlhexbug=1 if ($start1 < 0); if ($simmrangex ne "0") { $simmrange=hex("0x$simmrangex") * $meg; $perlhexbug=1 if ($simmrange <= 0 && $simmrangex ne "00000000"); if ($simmrange < hex("0x00001000") * $meg) { $start1x=sprintf("%08lx", $start1); $stop1x=sprintf("%08lx", $start1 + ($simmsize * $meg) - 1); } else { # Systems with > 4GB of memory $start1x=$simmaddr . "00000"; $start1x=~s/^0000//; $stop1x=sprintf("%08lx", ($start1 / $meg) + $simmsize - 1) . "fffff"; $stop1x=~s/^0000//; } } $cnt=0; while ($cnt < $simmbanks * $simmsperbank) { if ($start1 >= $simmrange * $cnt && $start1 < $simmrange * ($cnt + 1)) { $bankcnt=$cnt; $cnt3=$bankcnt * $simmsperbank; if ($#socketstr) { $socket=$socketstr[$cnt3]; if ($#socketlabelstr) { $socketlabel=" ($socketlabelstr[$cnt3])" if (defined($socketlabelstr[$cnt3])); } if ($found10bit && $newslots[$val] !~ /00000[0-3]00/) { $socket=$socketstr[$cnt3 + 4]; if ($#socketlabelstr) { $socketlabel=" ($socketlabelstr[$cnt3 + 4])" if (defined($socketlabelstr[$cnt3 + 4])); } } } $order=$orderstr[$cnt3] if ($#orderstr); $group=$groupstr[$cnt3] if ($#groupstr); $slotnum=$slotstr[$cnt3] if ($#slotstr); if ($#bankstr) { $bank=$bankstr[$cnt3]; $bank=$bankstr[$cnt3 + 4] if ($found10bit && $newslots[$val] !~ /00000[0-3]00/); } $banks=$banksstr[$cnt3/$simmsperbank] if ($#banksstr); $byte=$bytestr[$cnt3] if ($#bytestr); } $cnt++; } # # Check for stacked DIMMs. A 128MB DIMM is sometimes seen as 2 # 64MB DIMMs with a hole in the address range. This may report # more slots than are really in a system. (i.e. a SS20 with # 8 32MB SIMMs reports 16 slots of 16MB each). # Special handling for $sortslots == 0 systems (Ultra 5/10, # Netra t1, Ultra CP 1400/1500, Ultra AXi/AXe/AXmp/AXmp+) # $stacked=0; if ($val < $#newslots - 2) { if ($sortslots == 0) { $start2=$start1 + ($simmrange * 2); $start2=$start1 + ($simmrange * 4) if ($banner =~ /Ultra CP 1400\b/ || $ultra eq "CP1400"); $start2x=sprintf("%08lx", $start2 / $meg); $stacked=2 if ($stacked == 0 && $newslots[$val + 2] eq $start2x && $newslots[$val + 3] eq $simmsz); if ($memtype eq "memory card") { # Some 256MB mezzanine boards are seen # as 4 64MB memory blocks with holes in # the address range. $start3=$start1 + ($simmsize * 2 * $meg) if ($simmsize eq 64); # Some 512MB mezzanine boards are seen # as 4 128MB memory blocks. $start3=$start1 + ($simmsize * $meg) if ($simmsize eq 128 && $banner !~ /Ultra CP 1400\b/ && $ultra ne "CP1400"); if ($banner =~ /\bCP2000\b/ || $ultra =~ /^CP2[01]\d0$/) { # 1GB mezzanine boards are seen # as 4 256MB memory blocks. $start3=$start1 + ($simmsize * $meg); $stacked=4; } $start3x=sprintf("%08lx", $start3 / $meg); if ($val < $#newslots - 6 && $stacked != 0) { $stacked=4 if ($newslots[$val + 4] eq $start3x && $newslots[$val + 5] eq $simmsz && $simmrange != $start3); } } if ($ultra eq "AXi") { # Check for 10-bit column address DIMMs if ($newslots[$val] =~ /00000[0-3]80/) { $found10bit=1; } elsif ($stacked == 0) { $found11bit=1; } if ($found10bit && $newslots[$val] !~ /00000[0-3]00/) { $socket=$socketstr[$cnt3 + 4]; if ($#socketlabelstr) { $socketlabel=" ($socketlabelstr[$cnt3 + 4])" if (defined($socketlabelstr[$cnt3 + 4])); } $bank=$bankstr[$cnt3 + 4]; } } } else { $start2=$start1 + ($simmrange / 2); $start2x=sprintf("%08lx", $start2 / $meg); $stacked=2 if ($newslots[$val + 2] eq $start2x && $newslots[$val + 3] eq $simmsz && ($simmsize ne 64)); } # # Check for 32MB SIMMs in bank 1 on Classic or LX. # They look like 16MB SIMMs at 0x0000000 and 0x06000000 # Also check for 8MB SIMMs in bank 1 on Classic or LX. # They look like 4MB SIMMs at 0x0000000 and 0x06000000 # if ($model =~ /SPARCclassic|SPARCstation-LX/) { if ($start1 == 0 && ($simmsize == 32 || $simmsize == 8)) { if ($newslots[$#newslots - 1] eq "00000060") { $totmem += $simmsize; $start2=hex("0x$newslots[$#newslots - 1]") * $meg; $start2x=sprintf("%08lx", $start2); $stop2x=sprintf("%08lx", $start2 + ($simmsize * $meg) - 1); $stop1x .= ", 0x${start2x}-0x$stop2x"; $simmsize *= 2; pop(@newslots); pop(@newslots); } } } if ($stacked == 2) { $totmem += $simmsize; $start2=hex("0x$newslots[$val + 2]") * $meg; if ($simmrange < hex("0x00001000") * $meg) { $start2x=sprintf("%08lx", $start2); $stop2x=sprintf("%08lx", $start2 + ($simmsize * $meg) - 1); } else { # Systems with > 4GB of memory $start2x=sprintf("%08lx", ($start2 / $meg)) . "00000"; $start2x=~s/^0000//; $stop2x=sprintf("%08lx", ($start2 / $meg) + $simmsize - 1) . "fffff"; $stop2x=~s/^0000//; } $stop1x .= ", 0x${start2x}-0x$stop2x"; $simmsize *= 2; $val += 2; } if ($stacked == 4) { $totmem += $simmsize * 3; $start2=hex("0x$newslots[$val + 2]") * $meg; $start2x=sprintf("%08lx", $start2); $stop2x=sprintf("%08lx", $start2 + ($simmsize * $meg) - 1); $stop1x .= ", 0x${start2x}-0x$stop2x"; $start3=hex("0x$newslots[$val + 4]") * $meg; $start3x=sprintf("%08lx", $start3); $stop3x=sprintf("%08lx", $start3 + ($simmsize * $meg) - 1); $stop1x .= ", 0x${start3x}-0x$stop3x"; $start4=hex("0x$newslots[$val + 6]") * $meg; $start4x=sprintf("%08lx", $start4); $stop4x=sprintf("%08lx", $start4 + ($simmsize * $meg) - 1); $stop1x .= ", 0x${start4x}-0x$stop4x"; $simmsize *= 4; $val += 6; } } # # Check for Voyager memory cards. A 32MB memory card is seen # as 4 8MB memory blocks with holes in the address range. # if ($model eq "S240" && $start1 && $simmsize == 16 && $val < $#newslots - 4) { $start=hex("0x$newslots[$val + 4]") - hex("0x$newslots[$val]"); $perlhexbug=1 if ($start < 0); $startx=sprintf("%08lx", $start); if ($newslots[$val + 1] eq "008" && $newslots[$val + 3] eq "008" && $startx eq "00000040") { $totmem += $simmsize; $startx=$newslots[$val + 2]; $start=hex("0x$startx") * $meg; $startx=sprintf("%08lx", $start); $perlhexbug=1 if ($start < 0); $stopx=sprintf("%08lx", $start + ($simmsize * $meg) - 1); $stop1x .= ", 0x${startx}-0x$stopx"; $startx=$newslots[$val + 4]; $start=hex("0x$startx") * $meg; $startx=sprintf("%08lx", $start); $perlhexbug=1 if ($start < 0); $stopx=sprintf("%08lx", $start + ($simmsize * $meg) - 1); $stop1x .= ", 0x${startx}-0x$stopx"; $simmsize *= 2; $val += 4; } } $slot0=$simmsize if ($start1 == 0); $simmsizeperbank=$simmsize / $simmsperbank; $smallestsimm=$simmsizeperbank if ($simmsize < $smallestsimm); $largestsimm=$simmsizeperbank if ($simmsize > $largestsimm); $found8mb=1 if ($simmsizeperbank == 8); $found16mb=1 if ($simmsizeperbank == 16); $found32mb=1 if ($simmsizeperbank == 32); push(@simmsizesfound, "$simmsizeperbank"); $cnt2=0; while ($cnt2 < $simmsperbank) { $socket='?' if (! defined($socket)); $bank='' if (! defined($bank)); $byte='' if (! defined($byte)); $socket='?' if ($socket eq ""); $recognized=0 if ($socket eq "?"); $sockets_used .= " $socket"; if ($socket eq "motherboard") { $buffer .= "$socket has "; $buffer .= $simmsize/$simmsperbank . "MB"; } else { if ($model eq "SPARCsystem-600" || $model =~ /Sun.4.600/) { $exp="Expansion board 0" if ($newslots[$val] =~ /00000[4-7]00/); $exp="Expansion board 1" if ($newslots[$val] =~ /00000[89ab]00/); if ($newslots[$val] =~ /00000[4-9ab]00/) { $buffer .= "$exp "; $banks="$exp bank $bank"; } $banks_used .= " $banks" if ($banks && $banks_used !~ /$banks/); } # prtconf-only data displayed here $buffer=($sockettype) ? "$buffer$sockettype $socket$socketlabel has a " : "$buffer$socket$socketlabel is a "; $buffer .= $simmsize/$simmsperbank . "MB"; $buffer .= " (" . $simmsize/$simmsperbank/1024 . "GB)" if ($simmsize/$simmsperbank > 1023); $buffer .= " $memtype"; push(@simmsizesfound, $simmsize/$simmsperbank); } if ($verbose) { $buf=""; if ($order) { $buf .= "$order"; $buf .= " $memtype" if ($memtype !~ /memory card/); } $slotnum="" if (! defined($slotnum)); $buf .= "slot $slotnum" if ($slotnum ne ""); $buf .= ", " if ($order || $slotnum ne ""); $buf .= "group $group, " if ($group ne ""); if ($bank ne "") { if ($bank =~ /Quad/) { $buf .= "$bank, "; } elsif ($dualbank eq 1) { $buf .= "banks $bank, "; } else { $buf .= "bank $bank, "; } $foundbank1or3=1 if ($bank eq 1 || $bank eq 3); } $buf .= "byte $byte, " if ($byte ne ""); $buf .= "address 0x${start1x}-0x$stop1x" if ($start1x && $showrange eq 1); $buffer .= " ($buf)" if ($buf); } $buffer .= "\n"; $cnt2++; $cnt3=($bankcnt * $simmsperbank) + $cnt2; if ($#socketstr) { $socket=$socketstr[$cnt3]; if ($#socketlabelstr) { $socketlabel=" ($socketlabelstr[$cnt3])" if (defined($socketlabelstr[$cnt3])); } if ($found10bit && $newslots[$val] !~ /00000[0-3]00/) { $socket=$socketstr[$cnt3 + 4]; if ($#socketlabelstr) { $socketlabel=" ($socketlabelstr[$cnt3 + 4])" if (defined($socketlabelstr[$cnt3 + 4])); } } # &pdebug("socketstr[$cnt3], bankcnt=$bankcnt, cnt2=$cnt2"); } $order=$orderstr[$cnt3] if ($#orderstr); $group=$groupstr[$cnt3] if ($#groupstr); $slotnum=$slotstr[$cnt3] if ($#slotstr); if ($#bankstr) { $bank=$bankstr[$cnt3]; $bank=$bankstr[$cnt3 + 4] if ($found10bit && $newslots[$val] !~ /00000[0-3]00/); } $banks=$banksstr[$cnt3/$simmsperbank] if ($#banksstr); $byte=$bytestr[$cnt3] if ($#bytestr); } } elsif ($ultra eq 1 || $ultra eq 5 || $ultra eq 10 || $ultra eq 30) { $buffer .= "bank $slot has a pair of " . $simmsize/2 . "MB DIMMs\n"; push(@simmsizesfound, $simmsize/2); } elsif ($ultra eq 2 || $ultra eq 250 || $ultra eq 450 || $ultra eq 80 || $ultra eq "420R" || $ultra eq "Netra t140x" || $ultra eq "Netra ft1800") { $buffer .= "group $slot has four " . $simmsize/4 . "MB DIMMs\n"; push(@simmsizesfound, $simmsize/4); } elsif ($ultra eq 60 || $ultra eq "220R") { $buffer .= "group $slot has four " . $simmsize/2 . "MB DIMMs\n"; push(@simmsizesfound, $simmsize/2); } elsif ($ultra eq "e") { $buffer .= "group $slot has eight " . $simmsize/8 . "MB DIMMs\n"; push(@simmsizesfound, $simmsize/8); } elsif ($socket eq "motherboard") { $buffer .= "$slot has ${simmsize}MB\n"; push(@simmsizesfound, $simmsize); } else { $buffer .= "slot $slot has a ${simmsize}MB"; $buffer .= " (" . $simmsize/1024 . "GB)" if ($simmsize > 1023); $buffer .= " $memtype\n"; push(@simmsizesfound, $simmsize); } $slot++; } # # Try to distinguish Ultra 5 from Ultra 10 # Cannot distinguish Ultra 5/333MHz from Ultra 10/333MHz (375-0066 motherboard) # Cannot distinguish Ultra 5/440MHz from Ultra 10/440MHz (375-0079 motherboard) # if ($model eq "Ultra-5_10" || $ultra eq "5_10" || $ultra eq 5 || $ultra eq 10) { if ($motherboard =~ /375-0009/) { $ultra=($sysfreq > 91) ? 10 : 5; $realmodel=($ultra eq 5) ? "(Ultra 5)" : "(Ultra 10)"; } # Determine if interleaving of banks using four identical sized DIMMs # Assume 1-way interleaving with mix of stacked and unstacked DIMMs $interleave=1; if ($#newslots == 3 && $stacked == 0) { $interleave=2 if ($newslots[1] eq $newslots[3]); } if ($#newslots == 7 && $stacked == 2) { $interleave=2 if ($newslots[1] eq $newslots[5]); } } &finish; &pdebug("exit"); exit; sub hpux_check { &pdebug("in hpux_check"); $HPUX=1; $model=$machine; if ($filename) { $model=""; $machine=""; $platform=""; $os="HP-UX"; } else { $osmajor=$osrel; $osmajor=~s/[^.]*.[0B]*//; $osmajor=~s/\..*//; &hpux_osrelease; $model=&mychomp(`/usr/bin/model`) if (-x '/usr/bin/model'); $cpuversion=""; if (-x '/usr/bin/getconf') { $kernbit=&mychomp(`/usr/bin/getconf KERNEL_BITS`); $cpuversion=&mychomp(`/usr/bin/getconf CPU_VERSION`); } $kernbit=32 if ($osmajor <= 10); if (-x '/usr/contrib/bin/machinfo') { @machinfo=&run("/usr/contrib/bin/machinfo"); &hpux_machinfo; } elsif (-x '/usr/sbin/ioscan') { $ncpu=&mychomp(`/usr/sbin/ioscan -kfnC processor | grep '^processor' | wc -l`); $cpucntfrom="ioscan"; } else { # Get CPU count from kernel if ($machine eq "ia64") { $ncpu=&hpux_kernelval("active_processor_count"); } else { $ncpu=&hpux_kernelval("processor_count"); } $cpucntfrom="kernel"; } $ncpu=1 if (! defined($ncpu)); # It has at least 1 CPU $cpubanner .= "$ncpu X " if ($ncpu > 1); if ($machine =~ /^9000\//) { $schedmodel=$model; $schedmodel=~s/^.*\/(.*$)/$1/; if (! $cputype && -r '/usr/sam/lib/mo/sched.models') { $cputype=&myawk('/usr/sam/lib/mo/sched.models',"^$schedmodel\\b",2); } if (! $cputype && -r '/opt/langtools/lib/sched.models') { $cputype=&myawk('/opt/langtools/lib/sched.models',"^$schedmodel\\b",2); } if (! $cputype && -r '/usr/lib/sched.models') { $cputype=&myawk('/usr/lib/sched.models',"^$schedmodel\\b",2); } if ($cputype) { $cpubanner .= "$cputype "; &pdebug(" cputype=$cputype"); } if ($cpuversion == 768) { $cpubanner .= "Itanium[TM] 1"; } elsif ($cpuversion == 524) { $cpubanner .= "Motorola MC68020"; } elsif ($cpuversion == 525) { $cpubanner .= "Motorola MC68030"; } elsif ($cpuversion == 526) { $cpubanner .= "Motorola MC68040"; } else { $cpubanner .= "PA-RISC"; if ($cpuversion == 532) { $cpubanner .= " 2.0"; } elsif ($cpuversion == 529) { $cpubanner .= " 1.2"; } elsif ($cpuversion == 528) { $cpubanner .= " 1.1"; } elsif ($cpuversion == 523) { $cpubanner .= " 1.0"; } elsif (&hpux_kernelval("cpu_arch_is_2_0")) { $cpubanner .= " 2.0"; } elsif (&hpux_kernelval("cpu_arch_is_1_1")) { $cpubanner .= " 1.1"; } elsif (&hpux_kernelval("cpu_arch_is_1_0")) { $cpubanner .= " 1.0"; } } } elsif ($cputype) { $cpubanner .= "$cputype"; } else { $cpubanner .= "$machine"; } if (! defined($cfreq)) { # Get CPU speed from kernel $cfreq=&hpux_kernelval("itick_per_usec"); if (! defined($cfreq)) { $cfreq=&hpux_kernelval("itick_per_tick"); $cfreq /= 10000 if (defined($cfreq)); } &pdebug(" cfreq=$cfreq found in kernel") if (defined($cfreq)); } $cpubanner .= ", ${cfreq}MHz" if (defined($cfreq)); } $model="HP $model" if ($model !~ /\bHP\b/i); $model=~s/ +$//; $is_hpvm=0; &hpux_machinfo if ($filename); } sub hpux_kernelval { return if (! -r '/dev/kmem'); $_=shift; $kernel="/hp_ux"; $kernel="/stand/vmunix" if (-f '/stand/vmunix'); $adb="/usr/bin/adb"; $adb .= " -o" if ($machine eq "ia64"); $kernelval=`echo "$_/D" | $adb $kernel /dev/kmem 2>/dev/null | tail -1`; @linearr=split(' ', $kernelval); return $linearr[1]; } sub hpux_machinfo { &pdebug("in hpux_machinfo"); $flag_cpu=0; $flag_platform=0; $flag_os=0; # parse machinfo output for CPU and other information foreach $line (@machinfo) { $line=&dos2unix($line); $line=&mychomp($line); if (! $line || $line =~ /^ +$/) { # End of sections $flag_cpu=0; $flag_platform=0; $flag_os=0; next; } if ($line =~ /^CPU info:/) { $flag_cpu=1; # Start of CPU section next; } if ($flag_cpu == 1) { # Parse CPU count, type and frequency for cpubanner if ($line =~ /^\s*\d*\s+.*[Pp]rocessor.* \(\d.*Hz,/) { $ncpu=$line; $ncpu=~s/^\s*(\d+)\s+.*/$1/; $ncpu=1 if ($ncpu eq $line); $cpucntfrom="machinfo 'CPU info'"; $cputype=$line; $cputype=~s/^\s*\d*\s+(.*)$/$1/; $cputype=~s/ processors.*$//; $cputype=~s/^(.*)\s+\(\d.*Hz.*/$1/; $cputype=~s/\s+/ /g; $cfreq=$line; $cfreq=~s/^.*[Pp]rocessor.* \((\d.* [GM]Hz),/$1/; if ($cfreq =~ /GHz/) { $cfreq=~s/ GHz.*$//; $cfreq *= 1000; } else { $cfreq=~s/ MHz.*$//; } &pdebug(" cputype=$cputype, cfreq=$cfreq"); next; } elsif ($line =~ /logical processors \(\d+ per socket/) { # Report multicore processors $tmp=$line; $tmp=~/(\d+) logical processors \((\d+) per socket/; $cputype=&multicore_cputype($cputype,$2) if (defined($2)); next; } elsif ($line =~ /Number of CPUs = /) { @linearr=split('=', $line); $ncpu=$linearr[1]; $ncpu=~s/^ *//; $cpucntfrom="machinfo 'Number of CPUs'"; next; } elsif ($line =~ /^\s*\d+ sockets\s*$/) { $tmp=$line; $tmp=~/(\d+) sockets/; $ncpu=$1; $cpucntfrom="machinfo 'sockets'"; next; } elsif ($line =~ /processor model: /) { @linearr=split(':', $line); $cputype=$linearr[1]; $cputype=~s/^ *\d+ +//; $cputype=~s/ processor$//; &pdebug(" cputype=$cputype"); next; } elsif ($line =~ /Clock speed = \d+ [GM]Hz/) { @linearr=split('=', $line); $cfreq=$linearr[1]; $cfreq=~s/^ *//; if ($cfreq =~ /GHz/) { $cfreq=~s/ GHz//; $cfreq *= 1000; } else { $cfreq=~s/ MHz//; } next; } elsif ($line =~ /LCPU attribute is /) { $hyperthreadcapable=1; if ($line =~ /enabled/i) { $hyperthread=1; $cputype=~s/ Intel/ Hyper-Threaded Intel/ if ($cputype !~ /Hyper.Thread/i); } next; } } if ($line =~ /^Memory:\s/) { $installed_memory=$line; $installed_memory=~s/^Memory:\s*(\d*\s*[GM]*[Bb]*).*/$1/; if ($installed_memory =~ /GB/) { $installed_memory=~s/\s*GB//g; $installed_memory *= 1024; } else { $installed_memory=~s/MB//ig; } $totmem=&roundup_memory($installed_memory); next; } if ($line =~ /^Platform info:/) { $flag_platform=1; # Start of Platform section next; } if ($flag_platform == 1 && $model eq "HP" && $line =~ /\bModel/i) { @linearr=split('[:=]', $line); $model=$linearr[1]; $model=~s/^ +//; $model=~s/"//g; $model=~s/ +$//; if ($model =~ /^ia64/) { $machine="ia64"; $platform="ia64"; $kernbit=64; } $model="HP $model" if ($model !~ /\bHP\b/i); next; } if ($line =~ /^OS info:/) { $flag_os=1; # Start of OS section next; } if ($flag_os == 1 && ! $osrel && $line =~ /\bRelease/i) { @linearr=split('[:=]', $line); $osrel=$linearr[1]; $osrel=~s/^ +//; $osrel=~s/^HP-UX //; &hpux_osrelease; next; } } $is_hpvm=1 if ($model =~ /Virtual Machine/); } sub hpux_osrelease { if ($osrel eq "B.11.11") { $osrelease="11i v1"; } elsif ($osrel eq "B.11.20") { $osrelease="11i v1.5"; } elsif ($osrel eq "B.11.22") { $osrelease="11i v1.6"; } elsif ($osrel eq "B.11.23") { $osrelease="11i v2"; } elsif ($osrel eq "B.11.31") { $osrelease="11i v3"; } } sub hpux_cprop { &pdebug("in hpux_cprop"); $config_cmd="/opt/propplus/bin/cprop -summary -c Memory"; $config_command="cprop"; # Use HP-UX SysMgmtPlus software to attempt to report memory if ($filename) { $cprop_out="<$filename"; } else { &show_header; $cprop_out="$config_cmd 2>&1 |"; } $cnt=0; open(FILE, $cprop_out); while() { next if (/^[\s\*\-]+$/); next if (/(| Unknown|: Other|: \.\.|: Not Specified|:\s*$)/i); ($permission_error)=(/(.*)/) if (/Permission denied|does not have privileges|is not authorized to run/i); if (/not supported on HPVM guest/i) { $is_hpvm=1; last; } $memarr++ if (/^\[Instance\]:\s+\d+/); if ($memarr >= 0) { ($Status[$memarr])=(/:\s+(.*)$/) if (/\[Status\]:\s+/); if (/\[Location\]:\s+/) { ($Location[$memarr])=(/Location\]:\s+(.*)$/); $Location[$memarr]=~s/^.*details\s+://; $Location[$memarr]=~s/\s+:\s+/:/g; $Location[$memarr]=~s/\.$//; } ($Size[$memarr])=(/:\s+(.*)$/) if (/\[Size\]:\s+/); ($ModType[$memarr])=(/:\s+(.*)$/) if (/\[Module Type\]:\s+/); ($MemType[$memarr])=(/:\s+(.*)$/) if (/\[Memory Type\]:\s+/); if (/\[Part Number\]:\s+/) { ($PN[$memarr])=(/:\s+(.*)$/); $PN[$memarr]=&hex2ascii($PN[$memarr]); } } } close(FILE); $installed_memory=0; for ($cnt=0; $cnt <= $memarr; $cnt++) { $buffer=""; if (defined($Size[$cnt])) { $buffer="$Location[$cnt]:" if (defined($Location[$cnt])); $buffer.=" $PN[$cnt]" if (defined($PN[$cnt])); $simmsize=$Size[$cnt]; if ($simmsize =~ /GB/) { $simmsize=~s/GB//g; $simmsize *= 1024; } else { $simmsize=~s/MB//ig; } $installed_memory += $simmsize; $buffer.=" $Size[$cnt]"; $buffer.=" $MemType[$cnt]" if (defined($MemType[$cnt])); $buffer.=" $ModType[$cnt]" if (defined($ModType[$cnt])); if (defined($Status[$cnt])) { if ($Status[$cnt] !~ /OK/i) { $buffer.=" - $Status[$cnt]"; $failing_memory=1; } } $buffer=~s/^\s+//; if ("$buffer" ne "") { push(@boards_mem, "$buffer\n"); $boardfound_mem=1; $memfrom="cprop"; } } elsif (defined($Location[$cnt])) { # Empty socket $sockets_empty .= ";" if ($sockets_empty); $sockets_empty .= " $Location[$cnt]"; } } $totmem=$installed_memory if (! $totmem); if ($installed_memory && $totmem && $installed_memory != $totmem) { print "ERROR: Total installed memory (${totmem}MB) does not "; print "match the total of the\n memory modules found "; print "(${installed_memory}MB).\n"; } &hpux_finish; } sub hpux_cstm { &pdebug("in hpux_cstm"); $config_cmd="echo 'selclass qualifier memory;info;wait;infolog'|/usr/sbin/cstm 2>&1"; if (! $filename && $verbose == 3) { # Include CPU information when E-mailing maintainer since this # data is used by memconf for regression testing. $config_cmd="echo 'selclass qualifier cpu;info;wait;selclass qualifier memory;info;wait;infolog'|/usr/sbin/cstm 2>&1"; } $config_command="cstm"; # Use HP-UX Support Tool Manager software to attempt to report memory if (! $filename) { &show_header; @config=&run("$config_cmd"); } $flag_memerr=0; foreach $line (@config) { $line=&dos2unix($line); next if ($line eq "\n" || $line =~ /^ +$/ || $line =~ /^ +=+$/); if ($line =~ /Internal Application error/i) { $cstm_error=$line; $cstm_error=~s/^ *//; next; } if ($line =~ /=\-\+\-=/) { $flag_mem=0; # End of section next; } if ($line =~ /\bPA [78]\d+.* CPU\b/) { $cputype=&mychomp($line); $cputype=~s/^.* (PA [78]\d+).*/$1/; $cputype=~s/ //g; &pdebug(" cputype=$cputype"); $ncpu++; } if ($line =~ /^'9000\// && $model eq "HP" && ! $machine) { @linearr=split(' ', $line); $machine=$linearr[0]; $machine=~s/\'//g; $platform=$machine; $model="HP $machine"; } if ($flag_mem == 1) { next if ($line =~ /Log creation time/); if ($line =~ /^-- Information Tool Log for /) { $flag_mem=0; # End of memory section next; } if ($line =~ /^Memory Error Log Summary/) { $flag_memerr=1; # Start of memory error log } if ($line =~ / errors logged | memory error log |Last error /) { $flag_memerr=0; # End of memory error log } if ($flag_memerr == 0 || $verbose) { push(@boards_mem, "$line"); } elsif ($verbose == 0 && $line =~ /^Memory Error Log Summary| errors logged | memory error log |Last error /) { # Only display the memory errors if verbose push(@boards_mem, "$line"); } $memory_error_logged=1 if ($line =~ / errors logged | Last error detected/); $boardfound_mem=1; $memfrom="cstm"; } if ($line =~ /^-- Information Tool Log for .*MEMORY / && $flag_mem == 0) { $flag_mem=1; # Start of memory section } } &hpux_finish; } sub hpux_finish { if ($machine =~ /^9000\/7/) { $modelmore="workstation"; } elsif ($machine =~ /^9000\/8/) { $modelmore="server"; } if ($filename) { if ($cputype) { $cpubanner="$ncpu X " if ($ncpu > 1); $cpubanner .= "$cputype"; } else { $cpubanner="$ncpu cpus" if ($ncpu > 1); } if (defined($cfreq)) { $cpubanner .= ", ${cfreq}MHz"; } &show_header; } if ($boardfound_mem) { &pdebug("displaying memory from $memfrom") if ($memfrom); print @boards_mem; &print_empty_memory("memory slots") if ($sockets_empty); &show_total_memory; } else { if ($filename) { &show_total_memory; } else { if (! $totmem) { # Get total memory from kernel if ($osmajor > 10) { $totmem=&hpux_kernelval("memory_installed_in_machine"); } else { $totmem=&hpux_kernelval("physmem"); } if (defined($totmem)) { $totmem /= 256; # Convert pages to MB } else { $totmem=0; } if (-r '/var/adm/syslog/syslog.log' && $totmem == 0) { open(FILE, "; close(FILE); @physical=grep(/Physical:/,@syslog); foreach $line (@physical) { @linearr=split(' ', $line); $totmem=$linearr[6] / 1024; last; } } } &show_total_memory; # Check if on a virtual machine (HPVM guest) if (-x '/opt/hpvm/bin/hpvminfo') { &pdebug("Checking hpvminfo"); $tmp=`/opt/hpvm/bin/hpvminfo 2>&1`; if ($tmp =~ /HPVM guest/i) { $is_hpvm=1; } elsif ($tmp =~ /Permission denied|does not have privileges|is not authorized to run/i) { print "ERROR: $tmp"; print " This user does not have permission to run '/opt/hpvm/bin/hpvminfo'.\n"; print " Run memconf as a privileged user like root on the HPVM host.\n"; } } } if ($is_hpvm) { print "NOTICE: Details shown are for the configuration of this HPVM guest, not the\n physical CPUs and memory of the HPVM host it is running on.\n"; } elsif ($config_command eq "cstm") { print "ERROR: /usr/sbin/cstm $cstm_error" if (defined($cstm_error)); print "ERROR: /usr/sbin/cstm did not report the memory installed in this HP-UX system.\n"; print " Cannot display detailed memory configuration. A newer version of\n"; print " Diagnostic and Support Tools for HP-UX may fix this issue. Aborting.\n"; } $exitstatus=1; } # # Post notice if X86 machine is Hyper-Thread capable, but not enabled # &show_hyperthreadcapable; if ($permission_error) { print "ERROR: $permission_error\n"; print " This user does not have permission to run $config_command.\n"; print " Try running memconf as a privileged user like root.\n" if ($uid ne "0"); $exitstatus=1; } # Flag untested CPU types (machine="" on regression test files) if (! $machine || $machine =~ /^9000\// || $machine eq "ia64") { # Tested HP-UX on PA-RISC and Itanium $untested=0; } else { $untested=1; $untested_type="CPU" if (! $untested_type); } &show_untested if ($untested); &show_errors; if ($memory_error_logged && $verbose == 0) { print "WARNING: Memory errors have been logged.\n"; print " Run 'memconf -v' to display the memory error log.\n"; } &mailmaintainer if ($verbose == 3); &pdebug("exit $exitstatus"); exit $exitstatus; } sub myawk { $awkfile=shift; $awksearch=shift; $awkfield=shift; open(FILE, "<$awkfile"); @tmp=; close(FILE); foreach $line (@tmp) { if ($line =~ /$awksearch/) { @linearr=split(' ', $line); return $linearr[$awkfield]; } } return ""; } sub x86_devname { return if ($have_x86_devname || $machine =~ /sun4|sparc/ || ! defined($model)); # x86 Sun development names and family part number $m=(defined($manufacturer)) ? "$manufacturer $model" : $model; $m=~s/-/ /g; &pdebug("in x86_devname, model=$m"); $untested=1 if ($m =~ /(Blade|Server) X\d/i); $untested=2 if ($m =~ /Sun |Netra /i); if ($m =~ /Sun .*W1100z.*2100z\b/i || $m =~ /Sun .*W[12]100z\b/i) { &cpubanner; # Check for Opteron 200 Series in case one CPU is disabled if ($cpubanner =~ /Opteron.* 2\d\d\b/i || $ncpu == 2) { # W2100z uses Opteron 200 Series 2-way processors. $devname="Metropolis 2P"; $familypn="A59"; $diagbanner="W2100z"; @socketstr=("DIMM2 Bank 0","DIMM1 Bank 0","DIMM4 Bank 1","DIMM3 Bank 1","DIMM6 Bank 2","DIMM5 Bank 2","DIMM8 Bank 3","DIMM7 Bank 3"); @reorder_decodedimms=(4,3,2,1,8,7,6,5); } elsif ($cpubanner) { # W1100z uses Opteron 100 Series 1-way processor. # W1100z is not upgradable to dual processors, so # don't show empty CPU2 or DIMM5-DIMM8 slots. $devname="Metropolis 1P"; $familypn="A58"; $diagbanner="W1100z"; @socketstr=("DIMM2 Bank 0","DIMM1 Bank 0","DIMM4 Bank 1","DIMM3 Bank 1"); @reorder_decodedimms=(4,3,2,1); } $model="Java Workstation $diagbanner"; $diagbanner=$model; $untested=0; } if ($m =~ /Sun .*V20z.*40z\b/i) { $devname="Stinger"; $familypn="A55 (V20z), A57 (V40z)"; } elsif ($m =~ /Sun .*V20z\b/i) { $devname="Stinger 2P"; $familypn="A55"; $untested=0; } elsif ($m =~ /Sun .*V40z\b/i) { $devname="Stinger 4P"; $familypn="A57"; $untested=0; } if ($m =~ /\bX2100 M2\b/i) { $devname="Leo"; $familypn="A84"; $untested=0; } elsif ($m =~ /Sun .*X2100\b/i) { $devname="Aquarius"; $familypn="A75"; $untested=0; } if ($m =~ /Sun .*X2200 (speedbump|M2\b.*Quad.*Core)/i) { # AMD Quad-Core Barcelona processor $devname="Taurus2"; $familypn="A85"; $untested=0; } elsif ($m =~ /Sun .*X2200 M2\b/i) { $devname="Taurus"; $familypn="A85"; $untested=0; } if ($m =~ /Sun .*X2250\b/i) { $devname="Venus"; $familypn="X2250"; $untested=0; } if ($m =~ /Sun .*X2270 M2\b/i) { # X2270 has 1 or 2 CPUs $familypn="X2270M2"; $untested=0 if ($os eq "SunOS"); } elsif ($m =~ /Sun .*X2270\b/i) { # X2270 has 1 or 2 Quad-Core hyper-threaded CPUs $familypn="X227"; $untested=0 if ($os eq "SunOS"); } if ($m =~ /Sun .*X4100 M2\b/i) { $devname="Galaxy 1F"; $familypn="A86"; $untested=0; } elsif ($m =~ /Sun .*X4100\b/i) { $devname="Galaxy 1U"; $familypn="A64"; $untested=0; } if ($m =~ /Sun .*X4100E\b/i) { $devname="Galaxy 1E"; # Cancelled $familypn="A72"; } if ($m =~ /Sun .*X4140\b/i) { $devname="Dorado 1U"; $familypn="B12"; $untested=0; } if ($m =~ /Sun .*X4150\b/i) { $devname="Doradi 1U"; $familypn="B13"; $untested=0; } if ($m =~ /Sun .*X4170\b/i) { # X4170 has 1 or 2 Quad-Core hyper-threaded CPUs $devname="Lynx 1U"; $familypn="X4170"; $untested=0; } if ($m =~ /Sun .*X4200 M2\b/i) { $devname="Galaxy 2F"; $familypn="A87"; $untested=0; } elsif ($m =~ /Sun .*X4200\b/i) { $devname="Galaxy 2U"; $familypn="A65"; $untested=0; } if ($m =~ /Netra .*X4200\b/i) { $devname="Draco"; $familypn="N87"; } if ($m =~ /Sun .*X4200E\b/i) { $devname="Galaxy 2E"; # Cancelled $familypn="A73"; } if ($m =~ /Sun .*X4240\b/i) { $devname="Dorado 2U"; $familypn="B14"; $untested=0; } if ($m =~ /Netra .*X4250\b/i) { $devname="Aries"; $familypn="NX425"; } if ($m =~ /Sun .*X4250\b/i) { $devname="Doradi 2U"; $familypn="X4250"; $untested=0 if ($os eq "SunOS"); } if ($m =~ /Sun .*X4270 M2\b/i) { # X4270 has 1 or 2 Quad-Core hyper-threaded CPUs $devname="Lynx 2U"; $familypn="X4270M2"; $untested=0; } elsif ($m =~ /Sun .*X4270\b/i) { $devname="Lynx 2U"; $familypn="X4270"; $untested=0; } if ($m =~ /Sun .*X4275\b/i) { # X4275 has 1 or 2 Quad-Core hyper-threaded CPUs $devname="Lynx 2U"; $familypn="X4275"; } if ($m =~ /Netra .*X4270\b/i) { $familypn="NX4270"; } if ($m =~ /Sun .*X4440\b/i) { $devname="Tucana"; $familypn="B16"; $untested=0 if ($os eq "SunOS"); } if ($m =~ /Sun .*X4450\b/i) { $devname="Tucani"; $familypn="B15"; $untested=0; } if ($m =~ /Netra .*X4450\b/i) { $devname="Argo"; } if ($m =~ /Sun .*X4470 M2\b/i) { # X4470 has 4 CPU sockets $familypn="X4470M2"; $untested=0 if ($os eq "SunOS"); } elsif ($m =~ /Sun .*X4470\b/i) { $familypn="X4470"; $untested=0 if ($os eq "SunOS"); } if ($m =~ /Sun .*X4500\b/i) { $devname="Thumper"; $familypn="A76"; $untested=0; } if ($m =~ /Sun .*X4540\b/i) { $devname="Thor"; $familypn="B24"; $untested=0 if ($os eq "SunOS"); } if ($m =~ /Sun .*X4600\b/i) { $devname="Galaxy 4U"; $familypn="A67"; # Same for X4600 M2 $devname="Galaxy 4F" if ($m =~ /Sun .*X4600 M2\b/); $untested=0; } if ($m =~ /Sun .*X4640\b/i) { # Replacement for Sun Fire X4600 M2 $familypn="X4640"; $untested=0 if ($os eq "SunOS"); } if ($m =~ /Sun .*X4800 M2\b/i) { # X4800 has 8 CPU sockets $familypn="X4800M2"; } elsif ($m =~ /Sun .*X4800\b/i) { # X4800 has 8 CPU sockets $familypn="X4800"; $untested=0 if ($os eq "SunOS"); } if ($m =~ /Sun .*X4950\b/i) { $devname="Streamstar StreamSwitch 2"; $familypn="A91"; } # The Sun Blade 8000 Modular System uses the Sun Blade # X8420/X8440/X8450 Server Modules if ($m =~ /Sun .*Blade 8000\b/i) { $devname="Andromeda 19"; $familypn="A81"; if ($m =~ /Sun .*Blade 8000 P\b/i) { $devname="Andromeda 14"; $familypn="A82"; } $untested=2; } if ($m =~ /Sun .*Fire V60x\b|Sun .*Fire\(tm\) V60\b/i) { $devname="Grizzly"; $familypn="A48"; } if ($m =~ /Sun .*Fire V65x\b|Sun .*Fire\(tm\) V65\b/i) { $devname="Grizzly 2U"; $familypn="A48"; $untested=0 if ($os eq "SunOS"); } if ($m =~ /Sun .*Ultra *20 M2\b/i) { $devname="Munich"; $familypn="A88"; $untested=2; $untested=0 if ($os eq "SunOS"); } elsif ($m =~ /Sun .*Ultra *20\b/i) { $devname="Marrakesh"; $familypn="A63"; $untested=2; $untested=0 if ($os eq "SunOS"); } if ($m =~ /Sun .*Ultra *24\b/i) { $devname="Ursa"; $familypn="B21"; $untested=0; } if ($m =~ /Sun .*Ultra *27\b/i) { $familypn="B27"; $untested=0; } if ($m =~ /Sun .*Ultra *40 M2\b/i) { $devname="Stuttgart"; $familypn="A83"; $untested=0; } elsif ($m =~ /Sun .*Ultra *40\b/i) { $devname="Sirius"; $familypn="A71"; $untested=0; } # The Sun Blade 6000 and 6048 Modular Systems use the Sun Blade # X6220, X6250 or T6300 Server Modules. if ($m =~ /Sun .*Blade 6000\b/i) { $devname="Constellation 10"; $familypn="A90"; $untested=2; } if ($m =~ /Sun .*Blade 6048\b/i) { $devname="Constellation 48"; $familypn="B22"; $untested=2; } if ($m =~ /Sun .*X6220\b/i) { $devname="Gemini"; $familypn="A92"; } if ($m =~ /Sun .*X6240\b/i) { $devname="Gemini+"; $familypn="X6240"; $untested=0 if ($os eq "SunOS"); } if ($m =~ /Sun .*X6250\b/i) { $devname="Wolf"; $familypn="A93"; $untested=0; } if ($m =~ /Sun .*X6270 M2\b/i) { # X6270 has 1 or 2 CPUs $familypn="X6270M2"; $untested=0; } elsif ($m =~ /Sun .*X6270\b/i) { # X6270 has 1 or 2 Quad-Core hyper-threaded CPUs $familypn="X6270"; $untested=0; } if ($m =~ /Sun .*X6275 M2\b/i) { # X6275 M2 has 2 Quad-Core or Six-Core hyper-threaded CPUs $familypn="X6275M2"; } elsif ($m =~ /Sun .*X6275\b/i) { # X6275 has 2 or 4 Quad-Core hyper-threaded CPUs $familypn="X6275"; } if ($m =~ /Sun .*X6420\b/i) { $devname="Pegasus"; } if ($m =~ /Sun .*X6440\b/i) { $devname="Pegasus+"; $familypn="X6440"; } if ($m =~ /Sun .*X6450\b/i) { $devname="Hercules2"; $familypn="X6450"; } if ($m =~ /Sun .*X8400\b/i) { $devname="Andromeda"; $familypn="X8400"; } if ($m =~ /Sun .*X8420\b/i) { $devname="Capella"; } if ($m =~ /Sun .*X8440\b/i) { $devname="Mira"; $familypn="A98"; } if ($m =~ /Sun .*X8450\b/i) { # Quad-Core CPU for Sun Blade 8000 chassis $devname="Scorpio"; $familypn="X8450"; } if ($m =~ /Sun .*X8600\b/i) { $devname="Antares"; } $untested=1 if ($m =~ /Netra Server X3.2\b/i); # X3-2 $untested=0 if ($m =~ /Sun Server X4.2\b/i && $os eq "SunOS"); # X4-2 $untested=0 if ($m =~ /Sun Server X4.2L\b/i && $os eq "SunOS"); # X4-2L $untested=1 if ($m =~ /Sun Server X4.4\b/i); # X4-4 $untested=1 if ($m =~ /Sun Server X4.8\b/i); # X4-8 $untested=1 if ($m =~ /Netra Blade X3.2B\b/i); # X3-2B $untested=1 if ($m =~ /Sun Blade X4.2B\b/i); # X4-2B $untested=0 if ($m =~ /Oracle Server X5.2\b/i && $os eq "SunOS"); # X5-2 $untested=0 if ($m =~ /Oracle Server X5.2L\b/i && $os eq "SunOS"); # X5-2L $untested=0 if ($m =~ /Oracle Server X6.2L\b/i && $os eq "SunOS"); # X6-2L $have_x86_devname=1 if ($devname); } sub releasefile { # Check file for release information $arg=shift; &pdebug("in releasefile, checking $arg"); open(FILE, $arg); while() { $tmp=&mychomp($_); next if ($tmp =~ /^[\s\*\-\_\\\/\|]*$/); # Ignore line if it starts with Escape sequence next if ($tmp =~ /^\e\[/); $tmp=~s/\s*\\[nr].*//; $tmp=~s/^Welcome to //; $tmp=~s/\s+-\s+.*//; &pdebug("in releasefile $arg, found $tmp"); return($tmp); } close(FILE); return(""); } sub linux_distro { $release=""; $osname="$os $osrel"; $osname="$os" if ($osrel eq ""); $kernbit=""; $kernbit="32-bit kernel" if ($machine =~ /i.86|sparc/); $kernbit="64-bit kernel" if ($machine =~ /x86_64|sparc64|ia64|amd64/); if (-f '/etc/freebsd-update.conf') { # FreeBSD @linearr=split(' ', $kernver); $release="$linearr[0] $linearr[1], $kernbit"; return; } $kernbit .= ", " if ($kernbit); foreach $relfile ('/etc/pclinuxos-release', '/etc/centos-release', '/etc/distro-release', '/etc/enterprise-release', '/etc/fedora-release', '/etc/frugalware-release', '/etc/kate-version', '/etc/myah-version', '/etc/pardus-release', '/etc/parsix-version', '/etc/sabayon-release', '/etc/vector-version', '/etc/whitebox-release', '/etc/yellowdog-release', '/etc/yoper-release', '/etc/UnitedLinux-release', '/etc/gentoo-release', '/etc/mandriva-release', '/etc/mandrakelinux-release','/etc/mandrake-release', '/etc/slackware-version','/etc/slackware-release', '/etc/redhat-release','/etc/redhat_version', '/etc/SuSE-release') { if (-f "$relfile") { $release=&releasefile($relfile); $release .= ", $kernbit$osname"; return; } } if (-d '/KNOPPIX') { if (-r '/cdrom/index.html') { open(FILE, ") { if (//) { $release=&mychomp($_); $release=~s/<TITLE>//; $release=~s/<\/TITLE.*//; } } close(FILE); } elsif (-r '/init') { open(FILE, "</init"); while(<FILE>) { if (/DISTRO=/) { $release=&mychomp($_); $release=~s/.*DISTRO="*(.*)$/$1/; $release=~s/"//g; } } close(FILE); } $release="Knoppix" if (! $release); $release .= ", $kernbit$osname"; $release .= ", " . &releasefile("/etc/issue") if (-f '/etc/issue'); return; } elsif (-f '/gos/gOS/gos.html') { $release="gOS, $kernbit$osname"; $release .= ", " . &releasefile("/etc/issue") if (-f '/etc/issue'); return; } elsif (-f '/etc/motd.static') { $release=&releasefile("/etc/motd.static"); $release .= ", $kernbit$osname"; if (-f '/etc/issue') { $tmp=&releasefile("/etc/issue"); if ($release =~ /Knoppix/i) { $release="Knoppix, $kernbit$osname, $tmp"; } else { $release .= ", $tmp"; } } return; } elsif (-d '/ffp/etc') { $release="fun_plug"; if (-f '/ffp/etc/ffp-version') { $tmp=&mychomp(`grep FFP_VERSION= /ffp/etc/ffp-version`); $tmp=~s/^.*=//; $release .= " $tmp" if ($tmp); } if (-f '/etc/Alt-F') { $tmp=&releasefile('/etc/Alt-F'); $release="Alt-F $tmp with $release"; } } elsif (-f '/etc/Alt-F') { $tmp=&releasefile('/etc/Alt-F'); $release="Alt-F $tmp"; } # Debian, Ubuntu, BusyBox, etc. foreach $relfile ('/etc/issue.net','/etc/issue','/etc/motd') { $release=&releasefile("$relfile") if (! $release && -f "$relfile"); } $release=(defined($release)) ? "$release, $kernbit$osname" : ""; $release=~s/^, //; } sub check_mixedspeeds { $_=shift; return if ($_ !~ /(\dMHz|\dns)/); s/^.* (\d*)MHz.*$/$1/; s/^(\d*)MHz.*$/$1/; s/^.* (\d*)ns.*$/$1/; s/^(\d*)ns.*$/$1/; return if (! $_); &pdebug("in check_mixedspeeds, value=$_"); # round some memory speeds $_=266 if ($_ >= 265 && $_ <= 285); # DDR-266 PC-2100 $_=667 if ($_ >= 665 && $_ <= 668); # DDR2-667 PC2-5300 $_=1066 if ($_ >= 1065 && $_ <= 1068); # DDR2-1066 PC2-8500, DDR3-1066 PC3-8500 $_=1866 if ($_ >= 1865 && $_ <= 1868); # DDR3-1866 PC3-14900 if ($foundspeed) { $mixedspeeds=1 if ($foundspeed ne $_); } else { $foundspeed=$_; } } sub roundup_memory { $newval=shift; # &pdebug("in roundup_memory $newval"); # Round up memory (may have 128MB or more reserved) # Works for up to 16777216GB (16TB) for ($val=16; $val <= 64; $val += 16) { $newval=$val if ($newval >= $val-8 && $newval < $val); } for ($val=64; $val <= 1024; $val += 32) { $newval=$val if ($newval >= $val-16 && $newval < $val); } for ($val=1024; $val <= 4096; $val += 512) { $newval=$val if ($newval >= $val-128 && $newval < $val); } for ($val=4096; $val <= 14336; $val += 1024) { $newval=$val if ($newval >= $val-512 && $newval < $val); } for ($val=14336; $val <= 32768; $val += 2048) { $newval=$val if ($newval >= $val-1024 && $newval < $val); } for ($val=32768; $val <= 262144; $val += 4096) { $newval=$val if ($newval >= $val-2048 && $newval < $val); } for ($val=262144; $val <= 1048576; $val += 8192) { $newval=$val if ($newval >= $val-4096 && $newval < $val); } for ($val=1048576; $val <= 4194304; $val += 16384) { $newval=$val if ($newval >= $val-8192 && $newval < $val); } for ($val=4194304; $val <= 16777216; $val += 32768) { $newval=$val if ($newval >= $val-16384 && $newval < $val); } for ($val=16777216; $val <= 67108864; $val += 65536) { $newval=$val if ($newval >= $val-32768 && $newval < $val); } for ($val=67108864; $val <= 268435456; $val += 131072) { $newval=$val if ($newval >= $val-65536 && $newval < $val); } return($newval); } sub check_dmidecode_ver { $tmp=shift; @dmidecode_verarr=split(/\./, $dmidecode_ver); if (defined($tmp)) { @latest_dmidecode_verarr=split(/\./, $latest_dmidecode_ver); if (($dmidecode_verarr[0] < $latest_dmidecode_verarr[0]) || ($dmidecode_verarr[0] == $latest_dmidecode_verarr[0] && $dmidecode_verarr[1] < $latest_dmidecode_verarr[1])) { print " Your dmidecode package is an old version"; print " ($dmidecode_ver)" if ($dmidecode_ver); print ", so consider upgrading\n"; print " to dmidecode-$latest_dmidecode_ver or later.\n"; } elsif ($dmidecode_ver) { print " Your dmidecode version is $dmidecode_ver.\n" if (defined($tmp)); } } @minimum_dmidecode_verarr=split(/\./, $minimum_dmidecode_ver); if (($dmidecode_verarr[0] < $minimum_dmidecode_verarr[0]) || ($dmidecode_verarr[0] == $minimum_dmidecode_verarr[0] && $dmidecode_verarr[1] < $minimum_dmidecode_verarr[1])) { return 1; } else { return 0; } } sub check_free { return if ($free_checked); &pdebug("in check_free"); $free_checked=1; if (! $filename && $free_cmd) { # Check memory detected by OS @free=&run("$free_cmd"); $have_free_data=1; } if (! $filename && $meminfo_cmd) { # Check memory detected by kernel @meminfo=&run("$meminfo_cmd"); $have_meminfo_data=1; } if ($have_meminfo_data) { foreach $line (@meminfo) { $line=&dos2unix($line); if ($line =~ /MemTotal:\s+\d+ kB/) { @linearr=split(' ', $line); $freephys=int($linearr[1] / 1024); $totmem=&roundup_memory($freephys) if ($totmem == 0); last; } } } if ($have_free_data && ! $freephys) { foreach $line (@free) { $line=&dos2unix($line); if ($line =~ /Mem:/) { @linearr=split(' ', $line); $freephys=$linearr[1]; $totmem=&roundup_memory($freephys) if ($totmem == 0); last; } } } } sub check_for_decodedimms { return if (&is_virtualmachine); # Need root permissions to load eeprom kernel module return if ($uid ne "0" && ! $filename); &pdebug("in check_for_decodedimms"); if (! $filename && $decodedimms_cmd) { $flag=1; # Some systems lockup when loading eeprom module, avoid them # Avoid running on systems with PIIX4 like Dell PowerEdge 2650 @tmp=&run("/sbin/modprobe i2c_dev"); @tmp=&run("/usr/sbin/i2cdetect -l | grep -w PIIX4"); $flag=0 if (@tmp); # See if eeprom module is already loaded in kernel @tmp=&run("/sbin/lsmod | grep -w eeprom"); $flag=2 if (@tmp); if ($flag) { # Check memory SPD data from EEPROM @tmp=&run("$modprobe_eeprom_cmd") if ($flag == 1); @decodedimms=&run("$decodedimms_cmd"); $have_decodedimms_data=1; } } } sub check_topology { # Stoutland Platform (SGI Blade Chassis) topology command return if (&is_virtualmachine); &pdebug("in check_topology"); if ($filename) { @topology=@config; } else { @topology=&run("$topology_cmd"); } $flag_mem=0; $partition_cnt=0; foreach (@topology) { $_=&dos2unix($_); $_=&mychomp($_); if (/^System type: /) { push(@topology_header, "$_\n"); $topology_mfg="SGI.COM" if (/ UV/); } if (/^Serial number: /) { push(@topology_header, "$_\n"); $topology_mfg="SGI.COM" if (/ UV/); } if (/^Partition number: /) { push(@topology_header, "$_\n"); $partition_cnt++; } push(@topology_header, "$_\n") if (/^\s*\d+ Blades$/); push(@topology_header, "$_\n") if (/^\s*\d+ CPUs$/); push(@topology_header, "$_\n") if (/^\s*\d+.* GB Memory Total/i); push(@topology_header, "$_\n") if (/^\s*\d+.* GB Max Memory.*/i); $flag_mem=1 if (/(Idx|Index)\s.*\sNASID\s+CPUS\s+Memory/); $flag_mem=0 if (/^\s*$/); push(@topology_data, "$_\n") if ($flag_mem); } } sub check_decodedimms { return if ($decodedimms_checked); return if (&is_virtualmachine); &pdebug("in check_decodedimms"); $decodedimms_checked=1; # TLS - uncomment to not use decode-dimms.pl data - 19-Apr-2012 # $have_decodedimms_data=0; # TLS - If decode-dimms.pl is not available, suggest that it can be installed # with lmsensors to get more detailed memory information. if ($have_decodedimms_data) { $flag_mem=0; $flag_unknown=0; $mem_mfg=""; $pn=""; $simmsize=0; $memtype=""; $dimmspeed=""; $cnt=0; foreach $line (@decodedimms) { $line=&dos2unix($line); $line=&mychomp($line); if ($line =~ /^Guessing DIMM is in/i) { $tmp=$line; $tmp=~s/^.*\s+(\d+)\s*$/$1/; $cnt=($tmp - 1) if ($tmp); $flag_mem=1; } $flag_mem=0 if ($line =~ /^(Decoding EEPROM|EEPROM Checksum of bytes.*Bad|Number of SDRAM DIMMs detected and decoded)/i); if ($flag_mem) { if ($line =~ /^Fundamental Memory type/i) { # Required data from SPD EEPROM $memtype=$line; $memtype=~s/^Fundamental Memory type\s+(.*\S)\s*$/ $1/; &pdebug("in check_decodedimms, cnt=$cnt, memtype=$memtype"); $flag_unknown=($memtype =~ /^ *Unknown/i) ? 1 : 0; if ($flag_unknown) { &pdebug("in check_decodedimms, cnt=$cnt, Unknown memtype detected - failing DIMM"); } } if ($line =~ /^Maximum module speed/i) { $dimmspeed=$line; $dimmspeed=~s/^Maximum module speed\s+\D+\s+(.*\S)\s*$/ $1/; &check_mixedspeeds($dimmspeed); &pdebug("in check_decodedimms, cnt=$cnt, dimmspeed=$dimmspeed"); } $simmsize=$sizearr[$cnt] if (defined($sizearr[$cnt]) && ! $simmsize); if ($line =~ /^Size\s+.*MB/i) { $simmsize=$line; $simmsize=~s/^Size\s+(\d+)\s*MB.*$/$1/; &pdebug("in check_decodedimms, cnt=$cnt, simmsize=$simmsize"); } if ($line =~ /^Manufacturer\s+/i) { $mem_mfg=$line; $mem_mfg=~s/^Manufacturer\s+(.*\S)\s*$/ $1/; $mem_mfg=&get_mfg($mem_mfg); $mem_mfg="" if ($mem_mfg =~ /^\s+(FFFFFFFFFFFF|000000000000|Undefined)/i); $mem_mfg=" $mem_mfg" if ($mem_mfg); &pdebug("in check_decodedimms, cnt=$cnt, mem_mfg=$mem_mfg"); } if ($line =~ /^Part Number\s+/i) { $pn=$line; $pn=~s/^Part Number\s+(.*\S)\s*$/ $1/; $pn="" if ($pn =~ /^\s+(FFFFFFFFFFFF|000000000000|Undefined)/i); &pdebug("in check_decodedimms, cnt=$cnt, pn=$pn"); } } elsif ($simmsize && $memtype) { if ($reorder_decodedimms[$cnt]) { $tmp=$reorder_decodedimms[$cnt]-1; &pdebug("in check_decodedimms, reorder cnt=$tmp"); } else { $tmp=$cnt; } if (defined($socketlabelarr[$tmp])) { $socket=$socketlabelarr[$tmp]; $offset=-1; $incr=0; foreach (@boards_mem) { if (/\b$socket\b/) { if ($MemPartNum[$incr-1]) { # make sure pn matches $offset=$incr if (" $MemPartNum[$incr-1]" eq "$pn"); } else { $offset=$incr; } } $incr++; } if ($offset >= 0) { ($old)=grep(/$socket/,@boards_mem); chop($old); if ($flag_unknown) { $tmp="$old - FAILING"; $failing_memory=1; } else { $tmp="$socket: ${simmsize}MB$dimmspeed$memtype"; $tmp .= ",$mem_mfg$pn" if ($mem_mfg || $pn); } @tmp=("$tmp\n"); # Replace socket data from dmidecode # with socket data from decode-dimms.pl &pdebug("in check_decodedimms, replace socket data '$old' with '$tmp'"); splice(@boards_mem, $offset, 1, @tmp); $memfrom="decode-dimms.pl" if ($memfrom !~ /decode-dimms.pl/); } } else { $memfrom="dmidecode and decode-dimms.pl"; } $mem_mfg=""; $pn=""; $simmsize=0; $memtype=""; $dimmspeed=""; $cnt++; } } } } sub check_dmidecode { &pdebug("in check_dmidecode"); $DMI6=0; $DMI6cnt=0; $DMI6totmem=0; $DMI17=0; $DMI17totmem=0; $DMI17end=0; $DMItype=0; $platform=""; $FoundEnd=0; $BrokenTable=""; $unknown_JEDEC_ID=0; $ECCDIMM=0; $config_command="dmidecode"; if ($filename) { $DmiFile="<$filename"; } else { $DmiFile="$config_cmd 2>&1 |"; &linux_distro if (! $release); if ($ipmitool_cmd && ! $have_ipmitool_data) { @ipmitool=&run("$ipmitool_cmd fru"); $have_ipmitool_data=1; } } $cpu_membank=-1; $physmemarray=""; $memfrom="dmidecode"; &check_for_decodedimms; &check_topology; open(FILE, $DmiFile); while(<FILE>) { next if (/(<OUT OF SPEC>| Unknown|: Other|: \.\.|: Not Specified|:\s*$)/i); # for regression tests $have_decodedimms_data=1 if (/^Guessing DIMM is in/i); ($dmidecode_ver)=(/.* dmidecode (.*)/i) if (/ dmidecode /i); ($permission_error)=(/(.*)/) if (/Permission denied/i); ($dmidecode_error)=(/# *(.*)/) if (/No SMBIOS nor DMI entry point found/i && ! &is_xen_vm); # Detect end of DMI type 17 blocks # &pdebug("In DMI type 17, $_") if ($DMItype == 17); if (/(^Handle|^\s*$)/i && $DMItype == 17 && $memarr >= 0 && ! $DMI17end) { $DMI17end=1; $DMItype=0; # Ignore Flash chips for DMI17totmem $Size17[$memarr]=0 if (! defined($Size17[$memarr])); $Type17[$memarr]="" if (! defined($Type17[$memarr])); &pdebug("End of DMI type 17 block, $Size17[$memarr] $Type17[$memarr] detected") if ($Type17[$memarr] =~ /Flash/i); if ($Size17[$memarr] !~ /Not Installed/i && $Size17[$memarr] !~ /No Module Installed/i && $Type17[$memarr] !~ /Flash/i) { &pdebug("End of DMI type 17 block, adding $Size17[$memarr] memory to total"); $simmsize=$Size17[$memarr]; if ($simmsize =~ / *GB.*/i) { $simmsize=~s/ *GB.*//ig; $simmsize *= 1024; } else { $simmsize=~s/ *MB.*//ig; } $DMI17totmem += $simmsize if ($simmsize); } } ($DMItype)=(/DMI type (\d+)/i) if (/\bDMI type /i); if (/Handle .* DMI type 16,/i) { ($tmp)=(/Handle (.*), DMI type 16,/i); $cpu_membank++ if ($physmemarray ne $tmp); $physmemarray=$tmp; } $DMI17end=0 if ($DMItype != 17); # Type Information # ---------------------------------------- # 0 BIOS # 1 System # 2 Base Board # 3 Chassis # 4 Processor # 5 Memory Controller # 6 Memory Module # 7 Cache # 8 Port Connector # 9 System Slots # 10 On Board Devices # 11 OEM Strings # 12 System Configuration Options # 13 BIOS Language # 14 Group Associations # 15 System Event Log # 16 Physical Memory Array # 17 Memory Device # 18 32-bit Memory Error # 19 Memory Array Mapped Address # 20 Memory Device Mapped Address # 21 Built-in Pointing Device # 22 Portable Battery # 23 System Reset # 24 Hardware Security # 25 System Power Controls # 26 Voltage Probe # 27 Cooling Device # 28 Temperature Probe # 29 Electrical Current Probe # 30 Out-of-band Remote Access # 31 Boot Integrity Services # 32 System Boot # 33 64-bit Memory Error # 34 Management Device # 35 Management Device Component # 36 Management Device Threshold Data # 37 Memory Channel # 38 IPMI Device # 39 Power Supply # 40 Additional Information # 41 Onboard Device # Additionally, type 126 is used for disabled entries and type # 127 is an end-of-table marker. Types 128 to 255 are for # OEM-specific data. # Keep walking the dmidecode output for more about the system # Check system information if ($DMItype == 0) { ($biosvendor)=(/: +(.*\S) *$/) if (/^\s*Vendor: /i); } if ($DMItype == 1) { ($systemmanufacturer)=(/: +(.*\S) *$/) if (/^\s*(Manufacturer|Vendor): /i); ($systemmodel)=(/: +(.*\S) *$/) if (/^\s*Product( Name|): /i); } if ($DMItype == 2) { ($boardmanufacturer)=(/: +(.*\S) *$/) if (/^\s*(Manufacturer|Vendor): /i); ($boardmodel)=(/: +(.*\S) *$/) if (/^\s*Product( Name|): /i); $boardmodel=~s/^$boardmanufacturer // if ($boardmanufacturer && $boardmodel); # use DMItype2 manufacturer if Oracle (for VirtualBox) ($systemmanufacturer)=(/: +(.*\S) *$/) if (/^\s*(Manufacturer|Vendor): *Oracle */i); } # Check CPU information if ($DMItype == 4) { if (/^\s*Processor( Information|)$/i) { $cpuarr++; $ncpu++; } if (/^\s*Socket Designation: /i) { ($CPUSocketDesignation[$cpuarr])=(/: +(.*\S) *$/); $CPUSocketDesignation[$cpuarr]="CPU $cpuarr" if ($CPUSocketDesignation[$cpuarr] eq "Microprocessor"); } ($CPUFamily[$cpuarr])=(/: +(.*\S) *$/) if (/^\s*(Processor |)Family: /i); if (/^\s*(Processor |)Manufacturer: /i) { ($CPUManufacturer[$cpuarr])=(/: +(.*\S) *$/); $CPUManufacturer[$cpuarr]=~s/GenuineIntel/Intel/; } ($CPUVersion[$cpuarr])=(/: +(.*\S) *$/) if (/^\s*(Processor |)Version: /i); ($ExtSpeed[$cpuarr])=(/: +(.*\S) *$/) if (/^\s*External Clock: /i); ($CPUSpeed[$cpuarr])=(/: +(.*\S) *$/) if (/^\s*Current Speed: /i); if (/^\s*Status: /i) { ($CPUStatus[$cpuarr])=(/: +(.*\S) *$/); if ($CPUStatus[$cpuarr] =~ /(Unpopulated|Disabled By BIOS)/i) { $ncpu--; $necpu++; $CPUVersion[$cpuarr]=""; } } } # Check memory controller information if ($DMItype == 5) { ($ECCBIOS)=(/: +(.*\S) *$/) if (/^\s*Error Detecting Method: /i && ! $ECCBIOS); ($interleave)=(/: +(.*\S) *$/) if (/^\s*Current Interleave: /i && $interleave eq "0"); ($MAXMEM)=(/: +(.*\S) *$/) if (/^\s*Maximum Total Memory Size: /i && ! $MAXMEM); } # Check each memory device if ($DMItype == 6) { $DMI6=1; $memarr++ if (/^\s*Memory (Module Information|Bank)$/i); ($Locator6[$memarr])=(/: +(.*\S) *$/) if (/^\s*Socket( Designation|): /i); ($Speed6[$memarr])=(/: +(.*\S) *$/) if (/^\s*Current Speed: /i); ($Type6[$memarr])=(/: +(.*\S) *$/) if (/^\s*Type: /i); if (/^\s*Installed Size: /i) { ($Size6[$memarr])=(/: +(.*\S) *$/); if ($Size6[$memarr] !~ /Not Installed/i && $Size6[$memarr] !~ /No Module Installed/i) { $simmsize=$Size6[$memarr]; $simmsize=~s/ *MB.*//ig; $DMI6totmem += $simmsize if ($simmsize); $SizeDetail[$memarr]=$Size6[$memarr]; $Size6[$memarr]=$simmsize . "MB"; $SizeDetail[$memarr]=~s/\d+ *MBy*t*e* *//i; } } ($BankConnections6[$memarr])=(/: +(.*\S) *$/) if (/^\s*Bank Connections: /i); $DMI6cnt=$memarr + 1; } # SMBIOS 2.1 added DMI Types 16 & 17, obsoleting Types 5 & 6 # Check physical memory array if ($DMItype == 16) { ($ECCBIOS)=(/: +(.*\S) *$/) if (/^\s*Error Correction Type: /i && ! $ECCBIOS); ($MAXMEM)=(/: +(.*\S) *$/) if (/^\s*Maximum Capacity: /i && ! $MAXMEM); ($NUMMOD)=(/: +(.*\S) *$/) if (/^\s*Number Of Devices: /i && ! $NUMMOD); } # Check each memory device if ($DMItype == 17) { if ($DMI6) { # Prefer DMI type 17 information over DMI type 6 $memarr=-1 if (! $DMI17); } $DMI17=1; $memarr++ if (/^\s*Memory Device$/i); ($FormFactor[$memarr])=(/: +(.*\S) *$/) if (/^\s*Form Factor: /i); ($TotalWidth[$memarr])=(/: +(\d*) */) if (/^\s*Total Width: /i); ($DataWidth[$memarr])=(/: +(\d*) */) if (/^\s*Data Width: /i); if (/^\s*Locator: /i) { ($Locator17[$memarr])=(/: +(.*\S) *$/); $Locator17[$memarr]=~s/ */ /g; # Add CPU to X4170/X4270/X4275/X6270/X6275 if ($systemmodel =~ /Sun .*X(4[12]7[05]|627[05])\b/i && $Locator17[$memarr] !~ /CPU/) { $cpu_number=$CPUSocketDesignation[$cpu_membank]; $cpu_number=~s/\s*//g; $Locator17[$memarr]="${cpu_number}_$Locator17[$memarr]"; } } ($BankLocator[$memarr])=(/: +(.*\S) *$/) if (/^\s*Bank Locator: /i); ($Type17[$memarr])=(/: +(.*\S) *$/) if (/^\s*Type: /i); ($TypeDetail[$memarr])=(/: +(.*\S) *$/) if (/^\s*Type Detail: /i); ($Size17[$memarr])=(/: +(.*\S) *$/) if (/^\s*Size: /i); ($Speed17[$memarr])=(/: +(.*\S) *$/) if (/^\s*Speed: /i); ($MemManufacturer[$memarr])=&get_mfg(/: +(.*\S) *$/) if (/^\s*Manufacturer: /i && $Size17[$memarr] =~ /( MB|GB)/); if (/^\s*Part Number: /i && ! /PartNum/i && ! /NOT AVAILABLE/i) { ($MemPartNum[$memarr])=(/: +(.*\S) *$/); $MemPartNum[$memarr]=&hex2ascii($MemPartNum[$memarr]); # Hack: Ballistic modules may have mfg Undefined $MemManufacturer[$memarr]="Crucial Technology" if (! $MemManufacturer[$memarr] && $MemPartNum[$memarr] =~ /^BL/); } } $BrokenTable=&mychomp($_) if (/DMI table is broken/i); $FoundEnd=1 if (/End.Of.Table/i); } close(FILE); # Determine best manufacturer and model to display (or both) from # DMI type 1 (System) or DMI type 2 (Base Board) $baseboard="$boardmanufacturer $boardmodel" if ("$boardmanufacturer$boardmodel" ne ""); $baseboard="" if ($boardmanufacturer eq $systemmanufacturer && ($boardmodel eq $systemmodel || $boardmodel eq "")); if ($systemmanufacturer) { $manufacturer=$systemmanufacturer; } else { $manufacturer=$boardmanufacturer; $baseboard=""; } if ($systemmodel) { $model=$systemmodel; } else { $model=$boardmodel; } if ($manufacturer =~ /To Be Filled|System Manufacturer/i) { $manufacturer=$boardmanufacturer; $baseboard=""; } if ($model =~ /To Be Filled|System .*Name|XXXX/i) { $model=$boardmodel; $baseboard=""; } $baseboard="" if (&is_virtualmachine); # Check kernel to see how many processors it sees (for multi-core and # hyper-threaded CPUs) &check_cpuinfo; # Check Xen hardware for processors it sees (for multi-core and # hyper-threaded CPUs) &check_xm_info; # Check topology for manufacturer $manufacturer=$topology_mfg if ($topology_mfg); # Check Xenstore for manufacturer and model if not known if (&is_xen_vm && ! -f $filename && -x '/usr/bin/xenstore-ls' && -x '/usr/bin/xenstore-read') { $domid=&mychomp(`/usr/bin/xenstore-read domid 2>/dev/null`); if ($domid) { @xenstore=`/usr/bin/xenstore-ls /local/domain/$domid 2>/dev/null`; foreach (@xenstore) { if ($manufacturer eq "" && /\bsystem-manufacturer = */) { ($manufacturer)=(/= *"(.*)"$/); } if ($model eq "" && /\bsystem-product-name = */) { ($model)=(/= *"(.*)"$/); } } } } # hash CPUs $range=$ncpu; # Only display allocated CPUs on Virtual Machines $range=$cpuinfo_cpucnt if ($cpuinfo_cpucnt && &is_virtualmachine); for ($val=0; $val < $range; $val++) { $cputype=""; $cpufreq=""; if ($CPUVersion[$val]) { if ($CPUVersion[$val] eq "AMD" && $cpuinfo_cputype && ! &is_virtualmachine) { $cputype .= "$CPUManufacturer[$val] " if ($CPUManufacturer[$val] && $cpuinfo_cputype !~ /$CPUManufacturer[$val]/i); &pdebug("Adding AMD \$cpuinfo_cputype=$cpuinfo_cputype to cputype"); $cputype .= "$cpuinfo_cputype "; } else { $cputype .= "$CPUManufacturer[$val] " if ($CPUManufacturer[$val] && $CPUVersion[$val] !~ /$CPUManufacturer[$val]/i); $CPUVersion[$val]=&cleanup_cputype($CPUVersion[$val]); &pdebug("Adding \$CPUVersion[$val]=$CPUVersion[$val] to cputype"); $cputype .= "$CPUVersion[$val] "; } } elsif ($cpuinfo_cputype && ! &is_virtualmachine) { if ($CPUManufacturer[$val]) { $cputype .= "$CPUManufacturer[$val] " if ($cpuinfo_cputype !~ /$CPUManufacturer[$val]/i); } &pdebug("Adding \$cpuinfo_cputype=$cpuinfo_cputype to cputype"); $cputype .= "$cpuinfo_cputype "; } else { $cputype .= "$CPUManufacturer[$val] " if ($CPUManufacturer[$val]); $cputype .= "$CPUFamily[$val] " if ($CPUFamily[$val]); } if (! $machine && $CPUFamily[$val]) { $machine="ia64" if ($CPUFamily[$val] eq "Itanium"); } $cputype=~s/^\s+//; $cputype=~s/\s+$//; $cputype=~s/ +/ /g; if ($ncpu < $cpuinfo_cpucnt && $cpuinfo_cpucnt && $foundGenuineIntel) { # Distinguish Multi-Core from hyper-threading if ($cpuinfo_cpucores && $cpuinfo_physicalidcnt && $cpuinfo_cpucnt) { if ($cpuinfo_cpucnt / ($cpuinfo_cpucores * $cpuinfo_physicalidcnt) == 2) { $hyperthread=1; $ncpu=$cpuinfo_physicalidcnt; $range=$ncpu; # Adjust the range of this "for" loop &pdebug("hyperthread=1: from cpuinfo physical id, ncpu=$ncpu, cpuinfo_cpucnt=$cpuinfo_cpucnt, cpuinfo_physicalidcnt=$cpuinfo_physicalidcnt, cpuinfo_cpucores=$cpuinfo_cpucores, cputype=$cputype"); } } elsif ($cpuinfo_cpucores && $cpuinfo_coreidcnt > 1) { if ($cpuinfo_coreidcnt != $ncpu * $cpuinfo_cpucores) { if ($cpuinfo_cpucnt == $cpuinfo_coreidcnt && $cpuinfo_cpucores == 1 && $cpuinfo_cpucnt / $ncpu > 2) { $cpuinfo_cpucores=$cpuinfo_cpucnt / $ncpu; } else { $hyperthread=1; &pdebug("hyperthread=1: from cpuinfo, cputype=$cputype"); } } elsif ($cpuinfo_siblings) { if ($cpuinfo_coreidcnt / ($ncpu * $cpuinfo_siblings) == 2) { $hyperthread=1; &pdebug("hyperthread=1: from cpuinfo siblings, ncpu=$ncpu, cpuinfo_cpucnt=$cpuinfo_cpucnt, cpuinfo_coreidcnt=$cpuinfo_coreidcnt, cpuinfo_siblings=$cpuinfo_siblings, cputype=$cputype"); } } } elsif ($cpuinfo_siblings && ! ($cpuinfo_cpucores == 0 && $cputype =~ /Pentium.* 4\b/)) { if ($cpuinfo_cpucores == 0 && $cpuinfo_cpucnt / $cpuinfo_siblings == 2) { $hyperthread=1; if ($cpuinfo_physicalidcnt) { $ncpu=$cpuinfo_physicalidcnt; $cpuinfo_cpucores=$cpuinfo_cpucnt / $cpuinfo_physicalidcnt / 2; $range=$ncpu; # Adjust the range of this "for" loop &pdebug("hyperthread=1: from cpuinfo physical id, ncpu=$ncpu, cpuinfo_cpucnt=$cpuinfo_cpucnt, cpuinfo_physicalidcnt=$cpuinfo_physicalidcnt, cpuinfo_siblings=$cpuinfo_siblings, cputype=$cputype"); } else { &pdebug("hyperthread=1: from cpuinfo siblings, ncpu=$ncpu, cpuinfo_cpucnt=$cpuinfo_cpucnt, cpuinfo_physicalidcnt=$cpuinfo_physicalidcnt, cpuinfo_siblings=$cpuinfo_siblings, cputype=$cputype"); } } } elsif ($cpuinfo_cpucores == 0 && $cputype =~ /Pentium.* 4\b/) { # Can't tell RHEL3 Hyper-Threaded Pentium 4 # from Dual-Core Pentium D $hyperthread=1; &pdebug("hyperthread=1: hack in cpuinfo, cputype=$cputype"); } if ($xen_cores_per_socket) { $cputype=&multicore_cputype($cputype,$xen_cores_per_socket); } elsif ($cpuinfo_cpucores) { $cputype=&multicore_cputype($cputype,$cpuinfo_cpucores); } elsif ($hyperthread && $cpuinfo_siblings) { $cputype=&multicore_cputype($cputype,$cpuinfo_physicalidcnt); } else { $cputype=&multicore_cputype($cputype,$cpuinfo_cpucnt / $ncpu); } } if ($CPUSpeed[$val]) { $cpufreq="$CPUSpeed[$val]"; $cpufreq=~s/ *MHz$//; $CPUSpeed[$val]=~s/ *MHz$/MHz/; } &x86multicorecnt($cputype); $cpucnt{"$cputype $cpufreq"}++ if (! $xen_ncpu || $val < $xen_ncpu); $cpucntfrom="dmidecode" if ($cpucntfrom !~ /cpuinfo/ && $cpucntfrom ne "xm_info"); $ExtSpeed[$val]=~s/ *MHz$/MHz/ if ($ExtSpeed[$val]); } @cputypecnt=keys(%cpucnt); $x=0; while (($cf,$cnt)=each(%cpucnt)) { $x++; $cf=~/^(.*) (\d*)$/; $ctype=$1; $cfreq=$2; if ($cpucntflag == 0 && $cpucntfrom !~ /cpuinfo/ && $cpucntfrom ne "xm_info") { for $tmp (2,3,4,6,8,10,12,16) { $cnt /= $tmp if ($corecnt == $tmp && $cnt % $tmp == 0); } $cpucntflag=1; } $ctype="" if ($ctype =~ /^\S*-Core $/); if ($ctype) { $ctype=&multicore_cputype($ctype,$corecnt) if (&is_xen_hv); $cpubanner .= "$cnt X " if ($cnt > 1); $cpubanner .= "$ctype"; $cpubanner .= " ${cfreq}MHz" if ($cfreq && $ctype !~ /Hz$/); $cpubanner .= ", " if ($x < scalar(@cputypecnt)); } } if (&is_virtualmachine && $cpubanner eq "") { $cpubanner .= "$cpuinfo_cpucnt X " if ($cpuinfo_cpucnt > 1); $_=$cpuinfo_cputype; ($vcpu_type)=(/^(\w*)/); ($vcpu_freq)=(/(\d[\d\.]*[GM]Hz)/); $cpubanner .= "$vcpu_type $vcpu_freq"; } $machine="x86" if (! $machine); &x86_devname; # # Print information # &show_header; if (@topology_data) { print @topology_header; print @topology_data; $untested=0 if ($partition_cnt == 1 && $topology_mfg); # SGI UV $totmem=$installed_memory; &finish; &pdebug("exit"); exit; } # CPU information if ($verbose) { print "WARNING: CPU Information Unknown\n" if ($cpuarr < 0 && $cpucntfrom !~ /cpuinfo/); $range=$cpuarr; $range=$cpuinfo_cpucnt - 1 if ($cpucntfrom =~ /cpuinfo/ && ! $permission_error && &is_virtualmachine); # Second CPU doesn't exist on W1100z $range=0 if ($model =~ /W1100z\b/i); # Third & fourth CPUs don't exist on Ultra 40 $range=1 if ($familypn eq "A71"); for ($cnt=0; $cnt <= $range; $cnt++) { # Only display allocated CPUs on Virtual Machines next if ($CPUStatus[$cnt] && &is_virtualmachine && $CPUStatus[$cnt] =~ /(Unpopulated|Disabled By BIOS)/i); if ($CPUSocketDesignation[$cnt]) { print "$CPUSocketDesignation[$cnt]: "; } else { print "v" if (&is_virtualmachine); print "CPU $cnt: "; } if ($cpucntfrom =~ /cpuinfo/ && &is_virtualmachine) { $_=$cpuinfo_cputype; ($vcpu_type)=(/^(\w*)/); ($vcpu_freq)=(/(\d[\d\.]*[GM]Hz)/); print "$vcpu_type $vcpu_freq cpu\n"; next; } if ($CPUStatus[$cnt]) { if ($CPUStatus[$cnt] =~ /(Unpopulated|Disabled By BIOS)/i) { print "$CPUStatus[$cnt]\n"; next; } } $ctype=""; if ($CPUVersion[$cnt]) { $ctype .= "$CPUManufacturer[$cnt] " if ($CPUManufacturer[$cnt] && $CPUVersion[$cnt] !~ /$CPUManufacturer[$cnt]/i); $ctype .= "$CPUVersion[$cnt] "; } else { $ctype .= "$CPUManufacturer[$cnt] " if ($CPUManufacturer[$cnt]); $ctype .= "$CPUFamily[$cnt] " if ($CPUFamily[$cnt]); } $ctype=~s/ +/ /g; print "$ctype"; if ($CPUSpeed[$cnt]) { print "$CPUSpeed[$cnt] " if ($ctype !~ /Hz $/); } print "cpu"; print ", system freq: $ExtSpeed[$cnt]" if ($ExtSpeed[$cnt]); print "\n"; } } if ($ncpu > 1 && $foundGenuineIntel && $cpucntfrom =~ /cpuinfo/ && ! $permission_error && ! &is_xen_vm) { print "WARNING: Cannot detect if Hyper-Threading is enabled, "; print "CPU count may be half of\n what is shown if "; print "Hyper-Threading is enabled.\n"; } # Memory information if ($permission_error) { print "ERROR: $permission_error\n"; print " This user does not have permission to run $config_command.\n"; print " Try running memconf as a privileged user like root.\n" if ($uid ne "0"); &pdebug("exit 1"); exit 1; } $max=0; if ($MAXMEM) { if ($MAXMEM =~ /\d+ MB/) { $max=$MAXMEM; $max=~s/ MB//g; } elsif ($MAXMEM =~ /\d+ GB/) { $max=$MAXMEM; $max=~s/ GB//g; $max *= 1024; } elsif ($MAXMEM =~ /\d+ TB/) { $max=$MAXMEM; $max=~s/ TB//g; $max *= $meg; } } $DMItypeshown=0; $memarr=3 if ($model =~ /W1100z\b/i); # DIMM5-DIMM8 don't exist on W1100z for ($cnt=0; $cnt <= $memarr; $cnt++) { $buf=""; # Prefer DMI type 17 information over DMI type 6 $DMI=17; $DMI=6 if ($DMI6 && ! $DMI17); # Prefer DMI type 6 information if DMI type 6 reports different # total memory than DMI type 17 (BIOS bug) $DMI=6 if ($DMI6 && $DMI17 && $DMI6totmem > $DMI17totmem && &roundup_memory($freephys) == $DMI6totmem && ! &is_virtualmachine); &pdebug("using DMI type $DMI data for memory: DMI6totmem=$DMI6totmem, DMI17totmem=$DMI17totmem") if (! $DMItypeshown); $DMItypeshown=1; if ($DMI == 6) { next if (! $Size6[$cnt]); if ($Type6[$cnt]) {next if ($Type6[$cnt] =~ /Flash/i);} if (defined($Locator6[$cnt]) && defined($BankLocator[$cnt])) { $BankLocator[$cnt]="" if ($Locator6[$cnt] eq $BankLocator[$cnt]); if ($Locator6[$cnt] =~ /:/ && $BankLocator[$cnt] =~ /:/) { $Loc1=$Locator6[$cnt]; $Loc1=~s/.*://; $Loc2=$BankLocator[$cnt]; $Loc2=~s/.*://; $Locator6[$cnt]=~s/:.*// if ($Loc1 eq $Loc2); } } if ($#socketstr && ! $have_decodedimms_data) { $socketlabelarr[$cnt]="$socketstr[$cnt]"; } else { $socketlabelarr[$cnt]=$Locator6[$cnt]; } if ($Size6[$cnt] =~ /Not Installed|No Module Installed|^0 *MB.*/i) { &add_to_sockets_empty($socketlabelarr[$cnt]); } else { $buf="$socketlabelarr[$cnt]"; $simmsize=$Size6[$cnt]; $simmsize=~s/ *MB.*//ig; $sizearr[$cnt]=$simmsize; $Size6[$cnt]=~s/MByte/ MB/ig; $Size6[$cnt]=~s/ +MB/MB/g; if (defined($BankConnections6[$cnt])) { if ($Locator6[$cnt] =~ /BANK *\d/i && $BankConnections6[$cnt] =~ / /) { $tmp=$simmsize / 2; $buf .= ": 2 X ${tmp}MB"; } else { $buf .= ": $Size6[$cnt]"; } } else { $buf .= ": $Size6[$cnt]"; } $buf .= " $SizeDetail[$cnt]" if ($SizeDetail[$cnt]); if ($Speed6[$cnt]) { $Speed6[$cnt]=~s/ +MHz/MHz/; $Speed6[$cnt]=~s/ +ns/ns/; $buf .= " $Speed6[$cnt]"; &check_mixedspeeds($Speed6[$cnt]); } elsif ($Speed17[$cnt]) { $Speed17[$cnt]=~s/ +MHz/MHz/; $Speed17[$cnt]=~s/ +ns/ns/; $buf .= " $Speed17[$cnt]"; &check_mixedspeeds($Speed17[$cnt]); } if ($TypeDetail[$cnt]) { $buf .= " $TypeDetail[$cnt]" if ($TypeDetail[$cnt] !~ /None/i); } if ($FormFactor[$cnt] && defined($Type17[$cnt])) { $buf .= " $Type17[$cnt]"; $buf .= " $FormFactor[$cnt]" if ($Type17[$cnt] !~ /$FormFactor[$cnt]/); } elsif ($Type6[$cnt]) { $buf .= " $Type6[$cnt]"; } if ($MemManufacturer[$cnt]) { $buf .= ", $MemManufacturer[$cnt]" if ($MemManufacturer[$cnt] !~ /None/i); if ($MemPartNum[$cnt]) { $buf .= " $MemPartNum[$cnt]" if ($MemPartNum[$cnt] !~ /None/i); } } elsif ($MemPartNum[$cnt]) { $buf .= ", $MemPartNum[$cnt]" if ($MemPartNum[$cnt] !~ /None/i); } } $totmem=$DMI6totmem; } else { next if (! $Size17[$cnt]); if ($Type17[$cnt]) {next if ($Type17[$cnt] =~ /Flash/i);} if (defined($Locator17[$cnt]) && defined($BankLocator[$cnt])) { $BankLocator[$cnt]="" if ($Locator17[$cnt] eq $BankLocator[$cnt]); if ($Locator17[$cnt] =~ /:/ && $BankLocator[$cnt] =~ /:/) { $Loc1=$Locator17[$cnt]; $Loc1=~s/.*://; $Loc2=$BankLocator[$cnt]; $Loc2=~s/.*://; $Locator17[$cnt]=~s/:.*// if ($Loc1 eq $Loc2); } } if ($BankLocator[$cnt]) { $bank_label="$BankLocator[$cnt]"; # Don't include bank label if memory label also # includes the CPU $bank_label="" if ($Locator17[$cnt] =~ /CPU/ && $BankLocator[$cnt] =~ /\/P\d+$/); } if ($#socketstr && ! $have_decodedimms_data) { $socketlabelarr[$cnt]="$socketstr[$cnt]"; } else { $socketlabelarr[$cnt]=$Locator17[$cnt]; $socketlabelarr[$cnt] .= " $bank_label" if ($bank_label); } if ($Size17[$cnt] =~ /Not Installed|No Module Installed|^0 *MB.*/i) { &add_to_sockets_empty($socketlabelarr[$cnt]); } else { $buf="$socketlabelarr[$cnt]"; $simmsize=$Size17[$cnt]; if ($simmsize =~ / *GB.*/i) { $simmsize=~s/ *GB.*//ig; $simmsize *= 1024; } else { $simmsize=~s/ *MB.*//ig; } $sizearr[$cnt]=$simmsize; $Size17[$cnt]=~s/MByte/ MB/ig; $Size17[$cnt]=~s/ +MB/MB/g; $buf .= ": $Size17[$cnt]"; $buf .= " $SizeDetail[$cnt]" if ($SizeDetail[$cnt]); if ($Speed17[$cnt]) { $Speed17[$cnt]=~s/ +MHz/MHz/; $Speed17[$cnt]=~s/ +ns/ns/; $buf .= " $Speed17[$cnt]"; &check_mixedspeeds($Speed17[$cnt]); } elsif ($Speed6[$cnt]) { $Speed6[$cnt]=~s/ +MHz/MHz/; $Speed6[$cnt]=~s/ +ns/ns/; $buf .= " $Speed6[$cnt]"; &check_mixedspeeds($Speed6[$cnt]); } if ($TypeDetail[$cnt]) { $buf .= " $TypeDetail[$cnt]" if ($TypeDetail[$cnt] !~ /None/i); } $buf .= " $Type17[$cnt]" if ($Type17[$cnt]); if ($FormFactor[$cnt]) { if ($Type17[$cnt]) { $buf .= " $FormFactor[$cnt]" if ($Type17[$cnt] !~ /$FormFactor[$cnt]/); } else { $buf .= " $FormFactor[$cnt]"; } } if ($TotalWidth[$cnt] && $DataWidth[$cnt]) { $ECCDIMM=1 if ($TotalWidth[$cnt] > $DataWidth[$cnt]); } if ($MemManufacturer[$cnt]) { $buf .= ", $MemManufacturer[$cnt]" if ($MemManufacturer[$cnt] !~ /None/i); if ($MemPartNum[$cnt]) { # Don't repeat MFG if it is in Partnumber $MemPartNum[$cnt]=~s/$MemManufacturer[$cnt] //; $buf .= " $MemPartNum[$cnt]" if ($MemPartNum[$cnt] !~ /None/i); } } elsif ($MemPartNum[$cnt]) { $buf .= ", $MemPartNum[$cnt]" if ($MemPartNum[$cnt] !~ /None/i); } } $totmem=$DMI17totmem; } push(@boards_mem, "$buf\n") if ($buf); } # Check memory SPD data from EEPROM if available, it can be more # accurate and detailed than the dmidecode data &check_decodedimms; &pdebug("displaying memory from $memfrom") if ($memfrom); if (! &is_virtualmachine) { # Only show ECC enabled in BIOS if ECC memory is installed if ($ECCBIOS) { $ECCBIOS="None" if (! $ECCDIMM); print "Memory Error Correction: $ECCBIOS\n"; } print "Maximum Memory: "; if (! $MAXMEM || $max < $totmem || $max == 0) { $MAXMEM="Unknown"; $MAXMEM .= " (DMI incorrectly reports ${max}MB)" if ($max < $totmem && $max); print "$MAXMEM\n"; } else { &show_memory($max); } print "Maximum Memory Bus Speed: $maxmembusspeed\n" if ($maxmembusspeed); print @boards_mem if (@boards_mem); } # # Print total memory # $sockettype="sockets"; $sockettype="banks" if ($sockets_empty =~ /BANK *\d/i && $sockets_empty !~ /DIMM/); if ($memarr < 0 || $totmem == 0) { if (&is_virtualmachine) { if ($totmem) { print "total memory = "; &show_memory($totmem); } else { $exitstatus=1; } &check_virtualmachine; } else { &print_empty_memory("memory $sockettype") if ($sockets_empty); print "ERROR: Memory Information Unknown\n"; if ((! $FoundEnd || $BrokenTable ne "") && $dmidecode_ver) { print "WARNING: dmidecode output is truncated\n" if (! $FoundEnd); if ($BrokenTable ne "") { print "ERROR: $BrokenTable\n"; print " Your BIOS may be corrupted or have an invalid checksum.\n"; } } &print_bios_error; $exitstatus=1; } } else { &print_empty_memory("memory $sockettype"); print "total memory = "; &show_memory($totmem); } if ($ECCBIOS) { if ($ECCBIOS eq "None" && $ECCDIMM) { print "WARNING: ECC memory detected, but ECC is not enabled in the BIOS.\n"; $exitstatus=1; } } print "WARNING: Mixed speeds of memory modules found.\n" if ($mixedspeeds); print "ERROR: $dmidecode_error\n" if ($dmidecode_error); if ($freephys > $totmem && $totmem && ! &is_virtualmachine) { print "ERROR: Total physical memory (${freephys}MB) is "; print "greater than the total memory found.\n The total "; print "physical memory reported by 'free -m' does not match "; print "the\n memory reported by 'dmidecode'.\n"; &print_bios_error; } # See if half of the memory is unused due to missing a second CPU if ($totmem && $totmem == &roundup_memory($freephys) * 2 && $ncpu == 1 && $necpu == 1) { print "WARNING: Half of the installed memory is not being "; print "used due to only having a\n single CPU "; print "installed in this dual-CPU capable system.\n"; } if ($os =~ /Linux|FreeBSD/ && &roundup_memory($freephys) < $totmem && $totmem > 4096) { $tmp=0; @tmp=(""); if (-r '/var/log/dmesg' && ! $filename) { open(FILE, "</var/log/dmesg"); @tmp=<FILE>; close(FILE); } elsif ($filename) { @tmp=@config; } foreach $line (@tmp) { if ($line =~ /Warning only \d.*B will be used/) { $line=~s/Warning o/WARNING: O/; print $line; $tmp=1; } if ($line =~ /Use a PAE enabled kernel/) { print "WARNING: " . $line; if (-r '/etc/grub.conf' && $osrel) { $tmp=`grep ${osrel}PAE /etc/grub.conf`; $tmp=($tmp) ? 2 : 1; } else { $tmp=1; } } } if ($tmp) { print "WARNING: Total memory available to the OS is "; print "less than the total memory found.\n"; $recognized=0; $exitstatus=1; } if ($tmp >=1 && $osrel) { $osrelk=$osrel; $osrelk=~s/smp//; $osrelk=~s/hugemem//; if ($tmp == 1) { if ($osrel =~ /smp$/) { if (`grep ${osrelk}hugemem /etc/grub.conf 2>/dev/null`) { print "WARNING: Boot the ${osrelk}hugemem kernel to use the full memory.\n"; } else { print "WARNING: Using a 'hugemem' kernel may fix this issue (supports up to 64GB).\n"; } } elsif ($osrel =~ /hugemem$/) { print "WARNING: An upgraded BIOS may fix this issue.\n"; print "WARNING: This is not a bug in memconf.\n"; } else { if ($totmem < 16384) { if (`grep ${osrelk}smp /etc/grub.conf 2>/dev/null`) { print "WARNING: Boot the ${osrelk}smp kernel to use the full memory.\n"; } elsif (`grep ${osrelk}hugemem /etc/grub.conf 2>/dev/null`) { print "WARNING: Boot the ${osrelk}hugemem kernel to use the full memory.\n"; } else { print "WARNING: Using an 'smp' or 'hugemem' kernel may fix this issue ('smp' supports\n"; print " up to 16GB, 'hugemem' supports up to 64GB).\n"; } } else { if (`grep ${osrelk}hugemem /etc/grub.conf 2>/dev/null`) { print "WARNING: Boot the ${osrelk}hugemem kernel to use the full memory.\n"; } else { print "WARNING: Using a 'hugemem' kernel may fix this issue (supports up to 64GB).\n"; } } } } if ($tmp == 2) { print "WARNING: Boot the ${osrelk}PAE kernel "; print "to use the full memory.\n"; } } elsif ($tmp == 1) { if ($totmem < 16384) { print "WARNING: Using an 'smp' or 'hugemem' kernel may fix this issue ('smp' supports\n"; print " up to 16GB, 'hugemem' supports up to 64GB).\n"; } else { print "WARNING: Using a 'hugemem' kernel may fix this issue (supports up to 64GB).\n"; } } } # Flag untested CPU types (machine="" or "x86" on regression test files) # Tested so far on x86, i86pc, x86_64, Itanium ia64, and amd64 if (! $machine || $machine eq "x86" || $machine =~ /i.86/ || $machine eq "x86_64" || $machine eq "ia64" || $machine eq "amd64") { $untested=0 if ($untested == 1); # Linux on SPARC with dmidecode # } elsif ($machine eq "sparc64" || $machine eq "sun4u") { # $untested=0 if ($untested == 1); } else { $untested=1; $untested_type="CPU" if (! $untested_type); } &check_virtualmachine; &show_untested if ($untested); &show_errors; &mailmaintainer if ($verbose == 3); &pdebug("exit $exitstatus"); exit $exitstatus; } sub show_total_memory { return if ($totalmemshown || ! $totmem); $totalmemshown=1; # # Print total memory # print "total memory = "; &show_memory($totmem); print "$permission_error\n" if ($permission_error && ! $HPUX); if ($prtconf_warn) { print "WARNING: $prtconf_warn\n"; print " This may be corrected by installing "; print "a Sun patch on this system.\n"; } } sub show_control_LDOM_message { return if ($controlLDOMshown); $controlLDOMshown=1; # # Post notice if on control LDOM # print "NOTICE: Control Logical Domain (LDOM) detected. "; $picl_bank_cnt=scalar(keys %picl_mem_bank); if ($picl_foundmemory || $picl_bank_cnt) { print "The cpus and memory modules\n"; print " reported are for the system, not necessarily the control LDOM.\n"; } else { print "The SUNWldm software package\n"; print " may need updated for prtpicl to be able to report the installed cpus and\n"; print " memory for the system.\n"; } } sub is_virtualmachine { if ($uid ne "0") { # In case non-root user is running memconf $tmp=($os =~ /Linux|FreeBSD/ && ! $filename) ? `lspci 2>/dev/null | egrep -i '(VMware|VirtualBox|VirtualPC)'` : ""; # Include special case for regression testing VM files if ((! $filename && $tmp =~ /VMware/i) || $filename =~ /VMware/i) { $manufacturer="VMware, Inc." if (! $manufacturer); $model="VMware Virtual Platform" if (! $model); return(1); } elsif ((! $filename && $tmp =~ /VirtualBox|VBox/i) || $filename =~ /VirtualBox/i) { $manufacturer="Oracle Corporation" if (! $manufacturer); $model="VirtualBox" if (! $model); return(1); } elsif ((! $filename && $tmp =~ /VirtualPC/i) || $filename =~ /VirtualPC/i) { $manufacturer="Microsoft Corporation" if (! $manufacturer); $model="Virtual Machine" if (! $model); return(1); } } return(1) if ($manufacturer =~ /VMware/ || $model =~ /VMware|Virtual Platform|Virtual Machine|VirtualBox|VBox/ || $diagbanner =~ /Virtual Machine/); return(1) if (&is_xen_vm); return(0); } sub is_xen_hv { return(1) if (-d '/proc/xen' && -f '/proc/xen/xsd_port'); # Linux Hypervisor # Special case for regression testing Xen files return(1) if ($filename =~ /Xen_dom0/i); } sub is_xen_vm { return(1) if (-d '/proc/xen' && ! -f '/proc/xen/xsd_port'); # Linux return(1) if ($model =~ /HVM domU/); # Linux return(1) if ($model eq "i86xpv" || $machine eq "i86xpv" || $model eq "i86xen" || $machine eq "i86xen"); # Solaris # Special case for regression testing Xen files return(1) if ($filename =~ /Xen_domU/i); } sub check_virtualmachine { return if ($vmshown); $vmshown=1; if (&is_virtualmachine) { if (&is_xen_vm) { $vmh="Xen dom0 hypervisor"; $vms="Xen server"; $vmg="Xen domU guest"; } else { $vmh="VM hypervisor"; $vms="VM server"; $vmg="Virtual Machine (VM)"; } print "NOTICE: Details shown may be for the configuration of this $vmg,\n not the physical CPUs and memory of the $vms it is running on.\n"; print "WARNING: More details can be reported if memconf is run on the $vmh.\n"; print " $vms CPU: $cpuinfo_cputype\n" if ($cpuinfo_cputype); } } sub check_xm_info { if ($have_xm_info_data) { &pdebug("in check_xm_info"); foreach $line (@xm_info) { $line=&dos2unix($line); $_=$line; ($xen_nr_nodes)=(/: (\d*) */) if (/^nr_nodes\s*: \d+/); ($xen_sockets_per_node)=(/: (\d*) */) if (/^sockets_per_node\s*: \d+/); ($xen_cores_per_socket)=(/: (\d*) */) if (/^cores_per_socket\s*: \d+/); $hyperthread=1 if (/^threads_per_core\s*: 2/); } $xen_ncpu=$xen_nr_nodes * $xen_sockets_per_node; &pdebug("xen_ncpu=$xen_ncpu, ncpu=$ncpu, xen_nr_nodes=$xen_nr_nodes, xen_sockets_per_node=$xen_sockets_per_node, xen_cores_per_socket=$xen_cores_per_socket, hyperthread=$hyperthread"); if ($xen_ncpu) { $cpucntfrom="xm_info"; $corecnt=$xen_cores_per_socket; $nvcpu=$xen_cores_per_socket; $nvcpu=$nvcpu * 2 if ($hyperthread); } } } sub check_cpuinfo { if ($have_cpuinfo_data) { return if ($cpuinfo_checked); &pdebug("in check_cpuinfo"); $cpuinfo_checked=1; foreach $line (@cpuinfo) { $line=&dos2unix($line); $_=$line; $cpuinfo_cpucnt++ if (/^processor\s*: \d+/); $cpuinfo_coreidcnt++ if (/^core id\s*: \d+/); if (/^physical id\s*: \d+/) { ($physicalid)=(/: (\d*) */); $cpuinfo_physicalid{$physicalid}++; } ($cpuinfo_cpucores)=(/: (\d*) */) if (/^cpu cores\s*: \d+/); ($cpuinfo_siblings)=(/: (\d*) */) if (/^siblings\s*: \d+/); # Only GenuineIntel x86 has hyper-threading capability $foundGenuineIntel=1 if (/^vendor_id\s*: GenuineIntel/); # Linux on x86 or ARM CPU model if (/^model name\s*: /) { ($cpuinfo_cputype)=(/: (.*)$/); $cpuinfo_cputype=&cleanup_cputype($cpuinfo_cputype); if (/.*(ARM|Feroceon|Marvell)/) { if ($filename) { # Special case for regression testing $machine="arm"; $platform=$machine; $os="Linux"; } $cpucnt{"$cpuinfo_cputype"}=$corecnt; } } # Linux on SPARC CPU model if (/^cpu\s+: \D/) { ($cpuinfo_cputype)=(/: (.*)$/); $cpuinfo_cputype=&cleanup_cputype($cpuinfo_cputype); $machine="sparc" if ($cpuinfo_cputype =~ /sparc/i); $os="Linux"; } # Linux on SPARC OBP version if (/^prom\s+: /) { ($romver)=(/: (.*)$/); @romverarr=split(/\s/, $romver); $romvernum=$romverarr[1]; } # Linux on SPARC CPU type ($machine)=(/: (.*)$/) if (/^type\s+: sun/); # Linux on SPARC if (/^ncpus active\s*: \d+/) { ($cpuinfo_cpucnt)=(/: (.*)$/); # Assume single core $cpuinfo_cpucores=1; } # Linux on SPARC CPU freq if (/^Cpu\dClkTck\s*: \d+/ && $cpufreq == 0) { ($freq)=(/: (.*)$/); $cpufreq=&convert_freq($freq); $cpuinfo_cputype.= " ${cpufreq}MHz" if ($cpuinfo_cputype !~ /MHz/ && $cpufreq); } # Linux on unsupported CPU models (arm, mips, etc.) if (($machine !~ /.86|ia64|amd64|sparc/ && ! $filename) || $filename) { if (/^Processor\s+: /) { ($cpuinfo_cputype)=(/: (.*)$/); if ($filename && /^Processor\s+: .*(ARM|Feroceon|Marvell)/) { # Special case for regression testing $machine="arm"; $platform=$machine; } $os="Linux"; $cpucnt{"$cpuinfo_cputype"}=$corecnt; } elsif (/^cpu model\s+: /) { ($cpuinfo_cputype)=(/: (.*)$/); if ($filename && /^cpu model\s+: .*MIPS/) { # Special case for regression testing $machine="mips"; $platform=$machine; } $os="Linux"; $cpucnt{"$cpuinfo_cputype"}=$corecnt; } } if ($filename) { ($hostname)=(/: (.*)$/) if (/^host\s*: / && $hostname eq ""); if (/^machine\s*: /) { ($machine)=(/: (.*)$/); if (! defined($kernbit)) { $kernbit=32 if ($machine =~ /i.86|sparc/); $kernbit=64 if ($machine =~ /x86_64|sparc64|ia64|amd64/); } } if (/^release\s*: / && $release eq "") { ($release)=(/: (.*)$/); $release="Linux $release"; } } } $cpuinfo_physicalidcnt=keys %cpuinfo_physicalid; $cpuinfo_physicalidcnt=0 if (! defined($cpuinfo_physicalidcnt)); if ($cpuinfo_cpucnt > $ncpu && (! $foundGenuineIntel || $foundGenuineIntel && ! $ncpu)) { # Prefer cpuinfo over dmidecode for CPU info $cpucntfrom=$config_command if (! $cpucntfrom); &pdebug("Preferring CPU count from cpuinfo ($cpuinfo_cpucnt) over $cpucntfrom ($ncpu)"); if ($ncpu) { $cpucntfrom="dmidecode and cpuinfo"; } else { $cpucntfrom="cpuinfo"; } if ($cpuinfo_cpucores) { $ncpu=$cpuinfo_cpucnt / $cpuinfo_cpucores; } else { $ncpu=$cpuinfo_cpucnt; } } &pdebug("cpuinfo_cputype=$cpuinfo_cputype, ncpu=$ncpu, cpuinfo_cpucnt=$cpuinfo_cpucnt, cpuinfo_coreidcnt=$cpuinfo_coreidcnt, cpuinfo_cpucores=$cpuinfo_cpucores, cpuinfo_physicalidcnt=$cpuinfo_physicalidcnt, cpuinfo_siblings=$cpuinfo_siblings, foundGenuineIntel=$foundGenuineIntel"); } } sub finish { &show_header; #print "newslots=@newslots\n" if ($#newslots && $verbose > 1); # Large memory system like SPARC T7-4 can mismatch memory in prtconf and ipmitool if ($isX86 || $ultra =~ /^T7-/) { # smbios and ipmitool memory data is more accurate than prtconf if ($smbios_memory && $smbios_memory > $installed_memory) { $installed_memory=$smbios_memory; $totmem=$installed_memory; } elsif ($ipmi_memory && $ipmi_memory > $installed_memory) { $installed_memory=$ipmi_memory; $totmem=$installed_memory; } } # Cannot accurately determine installed memory unless information is # is in prtpicl output, or if system is fully stuffed $picl_bank_cnt=scalar(keys %picl_mem_bank); if ($ldm_memory && ! ($picl_foundmemory || $picl_bank_cnt)) { $totmem=&roundup_memory($installed_memory); &show_total_memory; &show_control_LDOM_message; return; } print $buffer if ($buffer); # # Special memory options # if ($sxmem) { # Currently assumes only one VSIMM is installed. # Auxiliary Video Board 501-2020 (SS10SX) or 501-2488 (SS20) # required if two VSIMMs are installed. if ($model eq "SPARCstation-20" || $model eq "SuperCOMPstation-20S") { # SS20 1st VSIMM in J0304/J0407, 2nd in J0305/J0406 print "sockets J0304/J0407 have"; $sockets_used .= " J0304"; } elsif ($model =~ /COMPstation-20A\b/) { # 1st VSIMM in J0202, 2nd in J0301 print "socket J0202 has"; $sockets_used .= " J0202"; } else { # SS10SX 1st VSIMM in J0301/J1203, 2nd in J0202/J1201 print "sockets J0301/J1203 have"; $sockets_used .= " J0301"; } print " a ${sxmem}MB VSIMM installed for SX (CG14) graphics\n"; } if ($nvmem) { # NVSIMMs for Prestoserve if ($model eq "SPARCstation-20" || $model eq "SuperCOMPstation-20S") { # SS20 1st 2MB NVSIMM in J0305/J0406, 2nd in J0304/J0407 if ($nvmem1) { $sockets_used .= " J0305"; print "sockets J0305/J0406 have a 2MB NVSIMM"; print " installed for Prestoserve\n"; } if ($nvmem2) { $sockets_used .= " J0304"; print "sockets J0304/J0407 have a 2MB NVSIMM"; print " installed for Prestoserve\n"; } } elsif ($model =~ /COMPstation-20A\b/) { # 1st 2MB NVSIMM in J0301, 2nd in J0202 if ($nvmem1) { $sockets_used .= " J0301"; print "socket J0301 has a 2MB NVSIMM"; print " installed for Prestoserve\n"; } if ($nvmem2) { $sockets_used .= " J0202"; print "socket J0202 has a 2MB NVSIMM"; print " installed for Prestoserve\n"; } } elsif ($model =~ /SPARCstation-10/ || $model eq "Premier-24") { # SS10 1st 2MB NVSIMM in J0202/J1201, 2nd in J0301/J1203 if ($nvmem1) { $sockets_used .= " J0202"; print "sockets J0202/J1201 have a 2MB NVSIMM"; print " installed for Prestoserve\n"; } if ($nvmem2) { $sockets_used .= " J0301"; print "sockets J0301/J1203 have a 2MB NVSIMM"; print " installed for Prestoserve\n"; } } else { # SS1000 supports two banks of four 1MB NVSIMMs # SC2000 supports one bank of eight 1MB NVSIMMs print "Has ${nvmem}MB of NVSIMM installed for Prestoserve "; if ($model eq "SPARCserver-1000") { print "(1 bank of 4" if ($nvmem == 4); print "(2 banks of 4" if ($nvmem == 8); } else { print "(1 bank of 8"; } print " 1MB NVSIMMs$nvsimm_banks)\n"; } } # # Check for empty banks or sockets # if ($#banksstr) { foreach $banks (@banksstr) { if ($banks ne "?") { if ($banks_used !~ /\b$banks\b/ && $sockets_empty !~ /\b$banks\b/) { &add_to_sockets_empty($banks); } } } &print_empty_memory($bankname); } elsif ($#socketstr) { foreach $socket (@socketstr) { if ($socket ne "?") { # strip leading slash for matching $tmp=$socket; $tmp=~s/^\///; if ($sockets_used !~ /$tmp/ && $sockets_empty !~ /$tmp/) { &add_to_sockets_empty($socket); } } } if ($sockettype) { &print_empty_memory("${sockettype}s"); } else { &print_empty_memory("memory slots"); } } elsif ($verbose > 1 && $sockets_used) { print "memory sockets used: $sockets_used\n"; } # Look for duplicate sockets if ($sockets_used && $have_prtdiag_data) { $dup_sockets=""; if ($sockets_used =~ /;/) { $sep=';'; } elsif ($sockets_used =~ /,/) { $sep=','; } else { $sep=' '; } foreach $socket (sort split($sep, $sockets_used)) { next if ($socket eq "board" || $socket eq "mezzanine"); next if ($model eq "SPARCsystem-600" || $model =~ /Sun.4.600/); $pos=-1; $cnt=0; while (($pos=index(" $sockets_used ", " $socket ", $pos)) > -1) { $pos++; $cnt++; if ($cnt == 2 && $socket ne "-" && $socket ne "?") { # strip leading slash for matching $tmp=$socket; $tmp=~s/^\///; if ($dup_sockets !~ /$tmp/) { $dup_sockets .= " $socket"; print "ERROR: Duplicate socket $socket found\n"; $exitstatus=1; } } } } if ($dup_sockets) { print "WARNING: Memory was not properly reported by"; print " the 'prtdiag' command.\n"; &recommend_prtdiag_patch; } } # Look for unlabeled sockets if ($sockets_used =~ /\s-\s|^-\s|\s-$|^-$/) { print "WARNING: Unlabeled socket found"; print " in the 'prtdiag' command output" if ($have_prtdiag_data); print ".\n This may cause the reported empty sockets"; print " to be incorrect.\n"; &recommend_prtdiag_patch; } # Make sure Sun Fire V480/V490/V880/V890 is fully stuffed if >= 1050MHz if ($ultra =~ /Sun Fire V[48][89]0\b/) { print "ERROR: System should not have any empty banks since CPU is >= 1050MHz.\n" if ($cpufreq >= 1050 && $banks_used ne "A0 A1 B0 B1"); } if ($machine eq "sun4v") { # Round up Solaris memory (may have 128MB or more reserved) $installed_memory=&roundup_memory($installed_memory); $totmem=$installed_memory; } # # Print total memory # &show_total_memory; # # Post notice if on control LDOM # &show_control_LDOM_message if ($ldm_memory); # # Post notice if on a virtual machine # &check_virtualmachine; # # Post notice if X86 machine is Hyper-Thread capable, but not enabled # &show_hyperthreadcapable; # # Check for illegal memory stuffings # if ($model eq "Sun 4/50" || $model eq "Sun 4/25") { # IPX, ELC if ($slot0 != 16 && $largestsimm == 16 && $osrel =~ /4.1.1/) { print "ERROR: Install the highest capacity 16MB SIMM"; print " in socket $socketstr[0] under SunOS 4.1.1.\n"; $exitstatus=1; } } if ($model =~ /SPARCclassic|SPARCstation-LX/) { if ($found32mb) { # Reportedly can accept 32MB SIMMs in bank 1, allowing # 128MB total (2x32, 4x16) print "NOTICE: The 32MB SIMM is not supported in the"; print " $model according to\n Sun. However it does"; print " appear to work in bank 1 only, allowing a"; print " maximum of\n 128MB of total memory (2x32MB"; print " bank 1 + 4x16MB banks 2 & 3).\n"; } if ($found8mb) { # Possibly can accept 8MB SIMMs in bank 1 print "NOTICE: The 8MB SIMM is not supported in the"; print " $model according to\n Sun. However it does"; print " appear to work in bank 1 only.\n"; } } if ($model =~ /SPARCstation-10/ || $model eq "Premier-24") { if ($slot0 < $largestsimm && $BSD) { print "ERROR: Install the highest capacity SIMM in"; print " socket $socketstr[0] under Solaris 1.X.\n"; $exitstatus=1; } if (! $found32mb && $found16mb && ($romvermajor eq 2) && ($romverminor < 19)) { print "WARNING: The 32MB SIMM is not supported in the"; print " SS10 or SS10SX according to\n Sun. However"; print " it does work correctly depending on the Open"; print " Boot PROM\n version. This system is running"; print " OBP $romvernum, so 32MB SIMMs will only be\n"; print " recognized as 16MB SIMMs. You should"; print " upgrade to OBP 2.19 or later in order\n to"; print " be able to detect and utilize 32MB SIMMs.\n"; # OBP 2.14 and earlier see the 32MB SIMM as 16MB. # OBP 2.15 on a SS20 does see the 32MB SIMM as 32MB. # Have not tested 32MB SIMMs on SS10 with OBP 2.15-2.18 if ($romverminor > 14) { $untested=1; $untested_type="OBP"; } } if ($found32mb && ($romvermajor eq 2) && ($romverminor < 19)) { print "NOTICE: The 32MB SIMM is not supported in the"; print " SS10 or SS10SX according to\n Sun. However"; print " it does work correctly depending on the Open"; print " Boot PROM\n version. This system is running"; print " OBP $romvernum, and 32MB SIMMs were properly\n"; print " recognized.\n"; @simmsizes=(16,32,64); if ($romvernum ne "2.X") { $untested=1; $untested_type="OBP"; } } if (! $nvmem1 && $nvmem2) { print "ERROR: First NVSIMM should be installed in"; print " socket J0202, not socket J0301\n"; $exitstatus=1; } } if ($model eq "SPARCstation-20" || $model eq "SuperCOMPstation-20S") { if (! $nvmem1 && $nvmem2) { print "ERROR: First NVSIMM should be installed in"; print " socket J0305, not socket J0304\n"; $exitstatus=1; } } if ($model eq "SPARCstation-5") { if ($slot0 < $largestsimm && $BSD) { print "ERROR: Install the highest capacity SIMM in"; print " socket $socketstr[0] under Solaris 1.X.\n"; $exitstatus=1; } if ($osrel eq "4.1.3_U1" && $found32mb) { # Look to see if patch 101508-07 or later is installed # for 32MB SIMMs to work properly (bug 1176458) $what=&mychomp(`/usr/ucb/what /sys/sun4m/OBJ/module_vik.o`); if ($what !~ /module_vik.c 1.38 94\/08\/22 SMI/) { print "WARNING: Install SunOS 4.1.3_U1 patch"; print " 101508-07 or later in order for 32MB\n"; print " SIMMs to work reliably on the"; print " SPARCstation 5.\n"; } } } if ($model eq "Ultra-5_10" || $ultra eq "5_10" || $ultra eq 5 || $ultra eq 10) { if ($smallestsimm == 16 && $largestsimm > 16) { print "ERROR: 16MB DIMMs cannot be mixed with larger"; print " DIMMs on Ultra 5/10 systems.\n"; $exitstatus=1; } } if ($ultra eq 5) { if ($largestsimm == 256) { print "NOTICE: The 256MB DIMM is not supported in the"; print " Ultra 5 according to\n Sun. However it does"; print " work correctly as long as you use low-profile"; print "\n DIMMs or take out the floppy drive.\n"; } } if ($ultra eq "AXi") { # DIMMs should be chosen as all 10-bit or all 11-bit column # address type. If using 11-bit, then only use Bank 0 & 2. if ($found10bit && $found11bit) { print "ERROR: You should not mix 10-bit and 11-bit"; print " column address type DIMMs in the\n "; print "SPARCengine Ultra AXi.\n"; $exitstatus=1; } if ($found11bit) { if ($foundbank1or3) { print "ERROR"; $exitstatus=1; } else { print "WARNING"; } print ": Do not use Bank 1 (sockets U0402 & U0401) &"; print " Bank 3 (sockets U0302 &\n U0301) since"; print " 11-bit column address type DIMMs are"; print " installed. You should\n only use Bank 0"; print " (sockets U0404 & U0403) & Bank 2 (sockets"; print " U0304 & U0303).\n"; } } if ($model eq "Ultra-4" || $ultra eq 450 || $model eq "Ultra-4FT" || $ultra eq "Netra ft1800") { if ($found16mb) { print "WARNING: 16MB DIMMs are not supported and may"; print " cause correctable ECC errors.\n"; } } # # Check for unsupported memory sizes # foreach $i (@simmsizesfound) { $smallestsimm=$i if ($i < $smallestsimm); $largestsimm=$i if ($i > $largestsimm); $simmsizelegal=0; foreach $j (@simmsizes) { $simmsizelegal=1 if ($i == $j); } if (! $simmsizelegal && $simmsizes[0]) { print "ERROR: Unsupported ${i}MB $memtype found (supported "; if ($#simmsizes == 0) { print "size is @{simmsizes}MB)\n"; } else { print "MB sizes are: @simmsizes)\n"; } $exitstatus=1; } } if ($smallestsimm < $simmsizes[0]) { print "ERROR: Smaller than expected $memtype found "; print "(found ${smallestsimm}MB, smallest expected "; print "${simmsizes[0]}MB)\n"; $exitstatus=1; } if ($largestsimm > $simmsizes[$#simmsizes]) { print "ERROR: Larger than expected $memtype found "; print "(found ${largestsimm}MB, largest expected "; print "${simmsizes[$#simmsizes]}MB)\n"; $exitstatus=1; } # # Check for buggy perl version # if ($perlhexbug) { print "ERROR: This Perl V$PERL_VERSION is buggy in hex number"; print " conversions.\n"; $exitstatus=1; } if ($PERL_VERSION == 5.001) { print "WARNING: Perl V5.001 is known to be buggy in hex number"; print " conversions.\n"; } if ($PERL_VERSION < 5.002) { print "WARNING: Perl V5.002 or later is recommended for best"; print " results.\n"; print " You are running Perl V$PERL_VERSION\n"; } # # Check for bad eeprom banner-name. This happens sometimes when OBP 3.23 # or later is installed on Ultra-60/E220R and Ultra-80/E420R systems. # if ($banner =~ /^ \(/) { print "ERROR: banner-name not set in EEPROM (BugID 4257412)."; print " Cannot distinguish an\n "; print "Ultra 60 from an Enterprise 220R" if ($model eq "Ultra-60"); print "Ultra 80 from an Enterprise 420R or Netra t 1400/1405" if ($model eq "Ultra-80"); print "Sun Blade 1000/2000 from a Sun Fire 280R or Netra 20" if ($ultra eq "Sun Blade 1000" || $ultra eq "Sun Blade 2000" || $ultra eq "Sun Fire 280R" || $ultra eq "Netra 20"); print ".\n To correct this problem, please run one of "; print "the following commands as\n root depending on "; print "the system you have:\n"; if ($model eq "Ultra-60") { print " eeprom banner-name='Sun Ultra 60 UPA/PCI'\n"; print " eeprom banner-name='Sun Enterprise 220R'\n"; print "Note: Netra t1120/1125 systems may also use the 'Sun Ultra 60 UPA/PCI' banner\n"; } if ($model eq "Ultra-80") { print " eeprom banner-name='Sun Ultra 80 UPA/PCI'\n"; print " eeprom banner-name='Sun Enterprise 420R'\n"; print " eeprom banner-name='Netra t 1400/1405'\n"; print "Note: Netra t1400/1405 systems may also use the 'Sun Ultra 80 UPA/PCI' banner\n"; } if ($ultra eq "Sun Blade 1000" || $ultra eq "Sun Blade 2000" || $ultra eq "Sun Fire 280R" || $ultra eq "Netra 20") { print " eeprom banner-name='Sun-Blade-1000'\n"; print " eeprom banner-name='Sun Fire 280R'\n"; print " eeprom banner-name='Netra 20'\n"; print "Note: Netra 20 systems may also use the 'Sun-Blade-1000' banner\n"; } $exitstatus=1; } # # Check for possible memory detection errors by this program # if ($prtdiag_failed == 2) { &found_nonglobal_zone; $prtdiag_has_mem=0; } # prtdiag only available on SunOS $prtdiag_has_mem=0 if ($os ne "SunOS"); if (! $boardfound_mem && $prtdiag_has_mem) { print "WARNING: Memory should have been reported in the output from"; if ($prtdiag_cmd) { print "\n $prtdiag_cmd"; } else { if (-d '/usr/platform') { print " prtdiag,\n which was not found in /usr/platform/$machine/sbin"; } else { print " prtdiag."; } } print "\nERROR: prtdiag failed!" if ($prtdiag_failed); print "\n This system may be misconfigured, or may be"; print " missing software packages\n like SUNWpiclr,"; print " SUNWpiclu and SUNWpiclx, or may need the latest\n"; print " recommended Sun patches installed from"; print " http://sunsolve.sun.com/\n"; if ($ultra eq "Sun Fire V880") { print " This may be corrected by installing "; print "Sun patch 112186-19 or 119231-01 or later.\n"; } print " Check my website at $URL\n"; print " to get the latest version of memconf.\n"; $exitstatus=1; } if ($recognized == 0) { print "ERROR: Layout of memory ${sockettype}s not completely "; print "recognized on this system.\n"; $exitstatus=1; } if ($recognized < 0 && $os eq "SunOS") { if ($have_prtfru_details && $recognized == -3) { print "ERROR: Memory manufacturer not recognized.\n"; print " This is a bug in the Sun OBP or prtfru"; print " command, not a bug in memconf.\n"; } else { print "WARNING: Layout of memory ${sockettype}s not"; print " completely recognized on this system.\n"; } if ($model eq "Ultra-80" || $ultra eq 80 || $ultra eq "420R" || $ultra eq "Netra t140x") { if ($recognized == -1) { print " The memory configuration displayed is a guess which may be incorrect.\n"; if ($totmem eq 1024) { print " The 1GB of memory installed may be 4 256MB DIMMs populating bank 0,\n"; print " or 16 64MB DIMMs populating all 4 banks.\n"; } } print " This is a known bug due to Sun's 'prtconf', 'prtdiag' and 'prtfru'\n"; print " commands not providing enough detail for the memory layout of this\n"; print " SunOS $osrel $platform system to be accurately determined.\n"; print " This is a bug in Sun's OBP, not a bug in memconf. The latest OBP\n"; print " release (OBP 3.33.0 2003/10/07 from patch 109082-06) "; print (($totmem eq 1024) ? "still has this bug" : "should fix this"); print ".\n This system is using $romver\n"; $exitstatus=1; } if ($ultra eq "Sun Blade 1000" || $ultra eq "Sun Blade 2000" || $ultra eq "Sun Fire 280R" || $ultra eq "Netra 20") { # Do this if memory was not in the output of prtdiag if ($recognized == -2) { # Hack: If Sun Blade 1000 has 8GB of memory (maximum # allowed), then memory line was rewritten to show # memory stuffing. print " The memory configuration displayed should be"; print " correct though since this\n"; print " is a fully stuffed system.\n"; } else { print " The memory configuration displayed is a guess which may be incorrect.\n"; } } if ($ultra eq "T2000" || $ultra eq "T1000") { # Do this if memory was not in the output of prtdiag # Hack: If Sun Fire T2000 has 8GB or 16GB of memory or # if Sun Fire T1000 has 4GB or 8GB of memory, then it # may be 1 rank of DIMMs instead of default 2 ranks. print " The memory configuration displayed is a guess which may be incorrect.\n"; print " Base Sun configurations ship with two ranks of modules installed.\n"; print " This system may have one rank of " . $simmsizesfound[0]*2 . "MB DIMMs installed instead\n"; print " of two ranks of " . $simmsizesfound[0] . "MB DIMMs as shown.\n"; print " This is a known bug due to Sun's 'prtconf', 'prtdiag' and 'prtfru'\n"; print " commands not providing enough detail for the memory layout of this\n"; print " SunOS $osrel $platform system to be accurately determined.\n"; print " This is a Sun bug, not a bug in memconf.\n"; $exitstatus=1; } } if ($banner =~ /Netra t1\b/ || $ultra eq "Netra t1" || $model eq "Netra t1") { if ($totmem eq 1024) { print "WARNING: Cannot distinguish between four"; print " 370-4155 256MB mezzanine boards and\n"; print " two 512MB mezzanine boards.\n"; } if ($totmem eq 768) { print "WARNING: Cannot distinguish between three"; print " 370-4155 256MB mezzanine boards and\n"; print " one 512MB and one 256MB mezzanine boards.\n"; } } if ($installed_memory) { if ($installed_memory != $totmem) { print "ERROR: Total memory installed (${installed_memory}MB) "; print "does not match total memory found.\n"; $recognized=0; $exitstatus=1; } } if ($failed_memory) { print "ERROR: Failed memory (${failed_memory}MB) was detected.\n"; print " You should consider replacing the failed memory.\n"; $exitstatus=1; } if ($spare_memory) { print "NOTICE: Spare memory (${spare_memory}MB) was detected.\n"; print " You can configure the spare memory using the 'cfgadm' command.\n"; } &show_errors; if ($failed_fru) { print "ERROR: $failed_fru"; print " You should consider replacing the failed FRUs.\n"; $exitstatus=1; } &show_unrecognized if ($recognized == 0); if (! &is_virtualmachine) { if ($smbios_memory && &roundup_memory($smbios_memory) != $installed_memory) { print "ERROR: Memory found by smbios (${smbios_memory}MB) does not match memory found in $config_command (${installed_memory}MB).\n"; print " This may be corrected by installing a Sun BIOS patch on this system.\n"; $exitstatus=1; } if ($ipmi_memory && $ipmi_memory != $installed_memory) { print "ERROR: Memory found by ipmitool (${ipmi_memory}MB) does not match memory found in $config_command (${installed_memory}MB).\n"; print " This may be corrected by installing a Sun BIOS patch on this system.\n"; $exitstatus=1; } } # Tested on SunOS 4.X - 5.11 (Solaris 1.0 through Solaris 11) # Flag Future/Beta SunOS releases as untested if ($osrel =~ /^5.1[2-9]|^[6-9]/) { $untested=1; $untested_type="OS" if (! $untested_type); } # Flag untested CPU types: # US-IIIi+ (Serrano) if ($cputype =~ /UltraSPARC-IIIi\+/) { $untested=1; $untested_type="CPU" if (! $untested_type); } # SPARC-T4+, SPARC-T6 or newer if ($cputype =~ /SPARC-T([4-9]\+|[6-9])/) { $untested=1; $untested_type="CPU" if (! $untested_type); } # SPARC-M5, SPARC-M6 or other SPARC-M* if ($cputype =~ /SPARC.M\d\+/) { $untested=1; $untested_type="CPU" if (! $untested_type); } # SPARC-S* excluding SPARC-S7 if ($cputype =~ /SPARC.S\d\+/ && $cputype !~ /SPARC.S7\b/) { $untested=1; $untested_type="CPU" if (! $untested_type); } # SPARC64-VII++ or newer other than SPARC64-X if ($cputype =~ /SPARC64-(VII\+\+|VIII|IX|X)/ && $cputype !~ /SPARC64-X\b/) { $untested=1; $untested_type="CPU" if (! $untested_type); } # Dual-Core, Triple-Core, Quad-Core, Six-Core, Eight-Core, Ten-Core, # Twelve-Core, Fourteen-Core, Sixteen-Core, Eighteen-Core x86 CPUs # have been tested. Don't flag as untested CPU as of V3.14. # if ($isX86 && $corecnt !~ /^(1|2|3|4|6|8|10|12|14|16|18)$/) { # $untested=1; # $untested_type="CPU" if (! $untested_type); # } &show_untested if ($untested); &mailmaintainer if ($verbose == 3); &pdebug("exit $exitstatus"); exit $exitstatus; } sub createfile { $s=shift; push(@filelist, "$s"); open(OUTFILE, ">/tmp/$s") || die "can't open /tmp/$s: $!"; $tmp=0; foreach $line (@_) { print OUTFILE "$line"; print OUTFILE "\n" if ($line !~ /\n$/); $tmp++; } close(OUTFILE); print STDERR time . " created $tmp lines in $s\n" if ($debug); } sub b64encodefile { local($file)=@_; local($res)=""; local($chunk)=""; $base64_alphabet='ABCDEFGHIJKLMNOPQRSTUVWXYZ' . 'abcdefghijklmnopqrstuvwxyz' . '0123456789+/'; $uuencode_alphabet=q|`!"#$%&'()*+,-./0123456789:;<=>?| . '@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_'; # Build some strings for use in tr/// commands. # Some uuencodes use " " and some use "`", so we handle both. # We also need to protect backslashes and other special characters. $tr_uuencode=" " . $uuencode_alphabet; $tr_uuencode=~s/(\W)/\\$1/g; $tr_base64="A" . $base64_alphabet; $tr_base64=~s/(\W)/\\$1/g; $base64_pad='='; if (open(INFILE, "<$file")) { # break into chunks of 45 input chars, use perl's builtin # uuencoder to convert each chunk to uuencode format, # then kill the leading "M", translate to the base64 alphabet, # and finally append a newline. while (read(INFILE, $_, 45)) { if (length($_) == 45) { $chunk=substr(pack("u", $_), $[+1, 60); eval qq{ \$chunk =~ tr|$tr_uuencode|$tr_base64|; }; } else { # any leftover chars go onto a shorter line with # uuencode padding converted to base64 padding $chunk=substr(pack("u", $_), $[+1, int((length($_)+2)/3)*4 - (45-length($_))%3); eval qq{ \$chunk =~ tr|$tr_uuencode|$tr_base64|; }; $res .= $chunk . ($base64_pad x ((60 - length($chunk)) % 4)); } $res .= $chunk . "\n"; } close(INFILE); return($res); } else { return(""); } } sub mailmaintainer { # E-mail information of system to maintainer. Use system call to # sendmail instead of Mail::Send module so that this works for perl4 if (-x '/usr/sbin/sendmail') { $sendmail='/usr/sbin/sendmail'; } elsif (-x '/usr/lib/sendmail') { $sendmail='/usr/lib/sendmail'; } else { $sendmail=""; } if ($sendmail) { print "\nSending E-mail to memconf maintainer tschmidt\@micron.com"; print " with output of:\n memconf -d (seen above)\n"; &show_helpers(" "); print "\nIf this system cannot send E-mail to the internet, then please E-mail the\n"; print "following file to tschmidt\@micron.com as an attachment from a system that can:\n"; } else { print "\nPlease E-mail the following file as an attachment to tschmidt\@micron.com\n"; } # Rewrite fully-qualified hostnames so that attachment filename has # only one extension. $newhostname=$hostname; $newhostname=~s/\./_/g; $outfile="memconf_$newhostname"; print (" /tmp/${outfile}.tar\n"); if ($filename) { $mail_subj=($SUNWexplo) ? "Sun/Oracle Explorer directory $filename" : "filename $filename"; } else { $mail_subj="$hostname"; } $mail_subject="memconf output from $mail_subj"; close(STDOUT); rename("/tmp/memconf.output","/tmp/${outfile}.txt"); push(@filelist, "${outfile}.txt"); if ($config_cmd) { @config=&run("$config_cmd") if (! $config[0]); &createfile("${outfile}_${config_command}.txt",@config); } if ($os eq "SunOS") { &createfile("${outfile}_prtdiag.txt",@prtdiag) if ($prtdiag_exec); &createfile("${outfile}_prtfru.txt",@prtfru) if ($prtfru_cmd); &createfile("${outfile}_prtpicl.txt",@prtpicl) if ($prtpicl_cmd); &createfile("${outfile}_psrinfo.txt",@psrinfo) if ($psrinfo_cmd); &createfile("${outfile}_virtinfo.txt",@virtinfo) if ($virtinfo_cmd); &createfile("${outfile}_cfgadm.txt",@cfgadm) if ($cfgadm_cmd); &createfile("${outfile}_smbios.txt",@smbios) if ($smbios_cmd); &createfile("${outfile}_kstat.txt",@kstat) if ($kstat_cmd); &createfile("${outfile}_ldm.txt",@ldm) if ($ldm_cmd); } &createfile("${outfile}_cpuinfo.txt",@cpuinfo) if (-r '/proc/cpuinfo'); &createfile("${outfile}_meminfo.txt",@meminfo) if (-r '/proc/meminfo'); &createfile("${outfile}_free.txt",@free) if ($free_cmd); &createfile("${outfile}_xm_info.txt",@xm_info) if ($xm_info_cmd); if (-x '/usr/bin/xenstore-ls') { $domid=&mychomp(`/usr/bin/xenstore-read domid 2>/dev/null`); if ($domid) { @xenstore=`/usr/bin/xenstore-ls /local/domain/$domid 2>/dev/null`; &createfile("${outfile}_xenstore-ls.txt",@xenstore); } } &createfile("${outfile}_decodedimms.txt",@decodedimms) if ($decodedimms_cmd); &createfile("${outfile}_ipmitool.txt",@ipmitool) if ($ipmitool_cmd); if ($os eq "HP-UX") { &createfile("${outfile}_machinfo.txt",@machinfo) if (-x '/usr/contrib/bin/machinfo'); } `cd /tmp; tar cf /tmp/${outfile}.tar @filelist 2>/dev/null`; if ($sendmail) { # Make MIME attachment using sendmail open(MAIL, "|$sendmail -t"); print MAIL "To: tschmidt\@micron.com\n"; print MAIL "Subject: $mail_subject\n"; print MAIL "MIME-Version: 1.0\n"; print MAIL "Content-Type: multipart/mixed; boundary=\"memconf_UNIQUE_LINE\"\n"; print MAIL "\n"; print MAIL "This is a multi-part message in MIME format.\n"; print MAIL "--memconf_UNIQUE_LINE\n"; print MAIL "Content-Type: text/plain; charset=\"ISO-8859-1\"; format=flowed\n"; print MAIL "\n"; print MAIL "Attached is output and regression test files from memconf $version $version_date from $mail_subj\n\n"; open(FILE, "/tmp/${outfile}.txt"); @tmp=<FILE>; close(FILE); print MAIL @tmp; print MAIL "\n--memconf_UNIQUE_LINE\n"; print MAIL "Content-Type: application/octet-stream; name=\"${outfile}.tar\"\n"; print MAIL "Content-Transfer-Encoding: base64\n"; print MAIL "Content-Disposition: attachment; filename=\"${outfile}.tar\"\n"; print MAIL "\n"; print MAIL &b64encodefile("/tmp/${outfile}.tar"); print MAIL "--memconf_UNIQUE_LINE--\n"; close(MAIL); } foreach $tmp (@filelist) { unlink "/tmp/$tmp"; } } ���������������������������������������������������������������UnixAgent-2.8/ocsinventory-agent��������������������������������������������������������������������0000775�0000000�0000000�00000022162�13726633777�0017101�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!/usr/bin/perl eval 'exec /usr/bin/perl -S $0 ${1+"$@"}' if 0; # not running under some shell #Copyright (C) 2006-2016 OCS Inventory Developers # #This program is free software; you can redistribute it and/or #modify it under the terms of the GNU General Public License #as published by the Free Software Foundation; either version 2 #of the License, or (at your option) any later version. # #This program is distributed in the hope that it will be useful, #but WITHOUT ANY WARRANTY; without even the implied warranty of #MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #GNU General Public License for more details. # #You should have received a copy of the GNU General Public License #along with this program; if not, write to the Free Software #Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, #USA. # use strict; use warnings; my $devlib; foreach (@ARGV) { if (/^--devlib$/) { print "[info] --devlib are found, Developer mode enabled\n"; eval "use lib 'lib';"; } } eval "use Ocsinventory::Agent;"; if ($@) { print "Failed to load Ocsinventory::Agent, $@\n"; print "you can run the agent directly for its source directory "; print "with --devlib\n"; exit 1; } eval "Ocsinventory::Agent::run();"; print $@; __END__ =head1 NAME ocsinventory-agent - Unified client for OCS-Inventory =head1 SYNOPSIS B<ocsinventory-agent> S<[ B<-fhilpruw> ]> S<[ I<--server server> | I<--local /tmp> ]>... =head1 EXAMPLES % ocsinventory-agent --server localhost # send an inventory to the OCS server % ocsinventory-agent --server http://localhost/ocsinventory2 # send an inventory over http to a server with a non standard # virtual directory % ocsinventory-agent --server https://localhost/ocsinventory # send an inventory over https to the OCS server % ocsinventory-agent --local /tmp # write an inventory in the /tmp directory % ocsinventory-agent --server localhost --user=toto --password=pw --realm="Restricted Area" # send a report to a server protected by a basic authentication % ocsinventory-agent --lazy # send an inventory only if the a random delay between 0 and PROLOG_FREQ had been run over. % ocsinventory-agent --delaytime 60 -d # If NO PROLOG_FREQ has been preset, pick a time between execution and --delaytime for the agent to contact the server [default is 3600 seconds] =head1 DESCRIPTION F<ocsinventory-agent> creates inventory and send or write them. This agent is the successor of the former linux_agent which was released with OCS 1.01 and prior. It also replaces the Solaris/AIX/BSD unofficial agents. The detailed list of supported Operating System is available in the Wiki. =over 4 =item F<GNU/Linux> =item F<Solaris> =item F<FreeBSD> =item F<NetBSD> =item F<OpenBSD> =item F<AIX> =item F<MacOSX> =item F<GNU/kFreeBSD> =back =head1 OPTIONS Most of the options are available in a I<short> form and a I<long> form. For example, the two lines below are all equivalent: % ocsinventory-agent -s localhost % ocsinventory-agent --server localhost =over 4 =item B<--backend-collect-timeout=SECONDS_BEFORE_KILL> Time before OCS kills modules processing which don't end before the timeout. =item B<--basevardir>=I<DIR> Indicate the place where the agent should store its files. =item B<-d>, B<--daemon> Launch ocsinventory-agent in background. Proc::Daemon is needed. =item B<--debug> Turn the debug mode on. =item B<--devlib> This option is designed for backend module developer. With it enabled, ocsinventry-agent won't try to load the Backend module installed on the system. Instead it will scan the ./lib directory. =item B<--delaytime=SECONDS_TO_WAIT> This option defaults to waiting a random() time between 0 and 3600 before initially contacting the server assuming NO PROLOG_FREQ has been set. Once PROLOG_FREQ has been set, it uses that number at the top end of it's random setting. Useful for pre-setting a deployed agent's initial start time (so you don't jam the server all at once, but don't have to wait an hour to make sure the deployment worked). =item B<-f>, B<--force> The agent will first contact the server during the PROLOG period. If the server doesn't know the machine or has outdated information, it will ask for an inventory. With this option, the agent doesn't run the PROLOG with the server first but directly sends an inventory. =item B<-i>, B<--info> Turn the verbose mode on. The flag is ignored if B<--debug> is enable. =item B<--lazy> Do not contact the server more than one time during the PROLOG_FREQ and do an exit if there is nothing to do. Useful if you want to start the agent script regulary from the crontab but don't want to overload the server. =item B<-l>, B<--local>=I<DIR> Write an inventory in the I<DIR> directory. A new file will be created if needed. =item B<--logfile>=I<FILE> Log message in I<FILE> and turn off STDERR =item B<-p>, B<--password>=I<PASSWORD> Use I<PASSWORD> for an HTTP identification with the server. =item B<-P>, B<--proxy>=I<PROXY> Use I<PROXY> to specify a proxy HTTP server. By default, the agent uses HTTP_PROXY environment variable. =item B<-r>, B<--realm>=I<REALM> Use I<REALM> for an HTTP identification with the server. For example, the value can be 'Restricted Area'. You can find it in the login popup of your Internet browser. =item B<-s>, B<--server>=I<URI> The uri of the server. If I<URI> doesn't start with http:// or https://, the assume the parameter is a hostname and rewrite it like that: % http://servername/ocsinventory If you want to use https or another virtual directory you need to enter the full path. B<--server> is ignored if B<--local> is in use. =item B<--stdout> Print the inventory on stdout. % ocsinventory-agent --stdout > /tmp/report.xml # prepare an inventory and write it in the /tmp/report.xml file. # A file will be created. =item B<--scan-homedirs> Authorized OCS to scan home directories to increase the Virtual Machine inventory. WARNING: beware with user privacy by using this option because it may encounter private data scans (even if it's not designed for !). =item B<--ssl>=I<0|1> Check SSL communications using a certificate. Set to 0 if you want to disable certificate check or 1 to enable (needs CA certificates file path in this case) . Default is set to 1. =item B<--ca>=I<FILE> Path to CA certificates file in PEM format, for server SSL certificate validation. Set to <your server configuration directory>/cacert.pem by default. =item B<--tag>=I<TAG> Mark the machine with the I<TAG> tag. Once the initial inventory is accepted by the server this value is ignored and you've to change the information directly on the server. The server do so in order to centralize the administration of the machine. =item B<-u> I<USER>, B<--user>=I<USER> Use I<USER> for the server authentication. =item B<--version>=I<USER> Print the version and exit. =item B<-w> I<DURATION>, B<--wait>=I<DURATION> Wait before initializing the connexion with the server. If I<DURATION> equal I<server> the agent will use the PROLOG_FREQ of the server to determine the duration of this periode. Exactly like it would had done if it was in --daemon mode. Else if duration is a numerical value, it will be used directly. % ocsinventory-agent --wait 5 --server localhost =item B<--nosoftware> Do not inventory the software installed on the machine. B<--nosoft> also works but is deperecated. =item B<--nolocal> Deactivate local mode even if it is set in config file or command line =back =head1 CONFIG FILE The agent try to initialize the settings from the B<ocsinventory-agent.cfg> config file. It looks for the file in these directories: =over =item /etc/ocsinventory =item /usr/local/etc/ocsinventory =item /etc/ocsinventory-agent =back =head1 AUTHORS The maintainer is Guillaume PROTET <guillaume.protet@mortheres.info> Please read the AUTHORS, Changes and THANKS files to see who is behind OCS Inventory Agent. =head1 SEE ALSO =over 4 =item OCS-Inventory website, http://www.ocsinventory-ng.org/ =item LaunchPad project page, http://launchpad.net/ocsinventory-unix-agent =item forum, http://forums.ocsinventory-ng.org/ =item and wiki http://wiki.ocsinventory-ng.org/ =back =head1 BUGS Please, use the forum as much as possible. You can open your own bug tickets. Patches are welcome. You can also use LaunchPad bugtracker or push your Bazaar branch on LaunchPad and do a merge request. =head1 COPYRIGHT Copyright (C) 2006-2016 OCS Inventory contributors This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA =cut ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������UnixAgent-2.8/postinst.pl���������������������������������������������������������������������������0000775�0000000�0000000�00000044437�13726633777�0015551�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!/usr/bin/perl -w use strict; use lib 'lib'; use Cwd; use MIME::Base64; use Ocsinventory::Agent::Config; my $old_unix_agent_dir = "/etc/ocsinventory-client"; my $config; my @cacert; my $binpath; my $randomtime; my $crontab; my $cron_line; my $option; my $nowizard; my $configdir; my $remove_old_unix; my $old_unix_config; my $nossl; my $download; my $snmp; my $now; for $option (@ARGV){ if ($option=~/--nowizard$/){ $nowizard = 1; } elsif($option=~/--server=(\S*)$/){ $config->{server} = $1; } elsif($option=~/--basevardir=(\S*)$/){ $config->{basevardir} = $1; } elsif($option=~/--configdir=(\S*)$/){ $configdir = $1; } elsif($option=~/--user=(\S*)$/){ $config->{user} = $1; } elsif($option=~/--password=(\S*)$/){ $config->{password} = $1; } elsif($option=~/--realm=(\S*)$/){ $config->{realm} = $1; } elsif($option=~/--tag=(\S*)$/){ $config->{tag} = $1; } elsif($option=~/--crontab$/){ $crontab = 1; } elsif($option=~/--get-old-unix-agent-config$/){ $old_unix_config = 1; } elsif($option=~/--remove-old-unix-agent$/){ $remove_old_unix = 1; } elsif($option=~/--debug$/){ $config->{debug} = 1; } elsif($option=~/--logfile=(\S*)$/){ $config->{logfile} = $1; } elsif($option=~/--nossl$/){ $nossl = 1; } elsif($option=~/--ca=(\S*)$/){ $config->{ca} = $1; } elsif($option=~/--download$/){ $download = 1; } elsif($option=~/--snmp$/){ $config->{snmp} = 1; } elsif($option=~/--now$/){ $now = 1; } elsif($option=~/--help/ || $option=~/-h/) { print STDERR <<EOF; Usage : \t--nowizard launch this script without interaction \t--server=url set OCS Inventory NG server address (e.g: http://ocsinventory-ng/ocsinventory) \t--basevardir=path set OCS Inventory NG Unix Unified agent variables directory (e.g: /var/lib/ocsinventory-agent) \t--configdir=path set OCS Inventory NG Unix Unified configuration directory (e.g: /etc/ocsinventory-agent) \t--user=username set username for OCS Inventory server Apache authentication (if needed) \t--password=password set password for OCS Inventory NG server Apache authentication (if needed) \t--realm=realm set realm name for OCS Inventory NG server Apache authentication (if needed) \t--crontab set a crontab while installing OCS Inventory NG Unix Unified agent \t--get-old-unix-agent-config retrieve old OCS Inventory NG Unix agent configuration (if needed) \t--remove-old-unix-agent remove old OCS Inventory NG Unix agent from system (if needed) \t--debug activate debug mode configuration option while installing OCS Inventory NG Unix Unified agent \t--logfile=path set OCS Inventory NG Unix Unified agent log file path (if needed) \t--nossl disable SSL CA verification configuration option while installing OCS Inventory NG Unix Unified agent (not recommended) \t--ca=path set OCS Inventory NG Unix Unified agent CA certificates file path \t--download activate package deployment feature while installing OCS Inventory NG Unix Unified agent \t--snmp activate SNMP scans feature while installing OCS Inventory NG Unix Unified agent \t--now launch OCS Inventory NG Unix Unified agent after installation \t-h --help display this help EOF exit 0; } } loadModules (qw/XML::Simple ExtUtils::MakeMaker/); ############ Setting default values ############ my @default_configdirs = ("/etc/ocsinventory", "/usr/local/etc/ocsinventory", "/etc/ocsinventory-agent"); unless ($config->{basevardir}) { if ($^O =~ /solaris/) { $config->{basevardir} = '/var/opt/ocsinventory-agent'; } elsif ($^O =~ /bsd/) { $config->{basevardir} = '/var/db/ocsinventory-agent'; } else { $config->{basevardir} = '/var/lib/ocsinventory-agent' } } ############ Asking for questions ############## unless ($nowizard) { if (!ask_yn("Do you want to configure the agent", 'y')) { exit 0; } unless ($configdir) { $configdir = getConfigDir (@default_configdirs); #If not found unless (-d $configdir) { $configdir = askConfigDir (@default_configdirs); unless (-d $configdir) { unless (ask_yn ("Do you want to create the directory ".$configdir."?", 'y')) { die("Please create ".$configdir." directory first.\n"); } } } } #Old unix agent if (ask_yn("Should the old unix_agent settings be imported ?", 'y')) { $old_unix_config=1; } #Getting agent configuration if exists if (-f $configdir."/ocsinventory-agent.cfg") { open (CONFIG, "<".$configdir."/ocsinventory-agent.cfg") or die "Can't open ".$configdir."/ocsinventory-agent.cfg: ".$!; foreach (<CONFIG>) { s/#.+//; if (/(\w+)\s*=\s*(.+)/) { my $key = $1; my $val = $2; # Remove the quotes $val =~ s/\s+$//; $val =~ s/^'(.*)'$/$1/; $val =~ s/^"(.*)"$/$1/; $config->{$key} = $val unless $config->{$key}; } } close CONFIG; } #Getting server name print "[info] The config file will be written in $configdir/ocsinventory-agent.cfg,\n"; $config->{server} = promptUser('What is the address of your ocs server',$config->{server}); #$config->{server} = promptUser('What is the address of your ocs server', exists ($config->{server})?$config->{server}:'ocsinventory-ng'); #Getting credentials if needed if (ask_yn ("Do you need credential for the server? (You probably don't)", 'n')) { $config->{user} = promptUser("user", $config->{user}); $config->{user} = MIME::Base64::encode_base64($config->{user}); $config->{password} = promptUser("password"); $config->{password} = MIME::Base64::encode_base64($config->{password}); print "[info] The realm can be found in the login popup of your Internet browser.\n[info] In general, it's something like 'Restricted Area'.\n"; $config->{realm} = promptUser("realm"); } #Getting tag unless ($config->{tag}){ if (ask_yn('Do you want to apply an administrative tag on this machine', 'y')) { $config->{tag} = promptUser("tag", $config->{tag}); } } #Getting crontab if ($^O =~ /solaris/ || $^O =~ /bsd/) { if (ask_yn("Do yo want to install the cron task in current user crontab ?", 'y')) { $crontab = 1; } } elsif (-d "/etc/cron.d") { if (ask_yn("Do yo want to install the cron task in /etc/cron.d", 'y')) { $crontab = 1; } } #Getting basevardir $config->{basevardir} = promptUser('Where do you want the agent to store its files? (You probably don\'t need to change it)', $config->{basevardir}, '^\/\w+', 'The location must begin with /'); unless (-d $config->{basevardir}) { unless (ask_yn ("Do you want to create the ".$config->{basevardir}." directory?\n", 'y')) { die("Please create the ".$config->{basevardir}." directory manually and relaunch postinst.pl script\n"); } } #Remove old unix agent ? $remove_old_unix = ask_yn ("Should I remove the old unix_agent", 'n') unless $remove_old_unix; #Enable debug option ? $config->{debug} = ask_yn("Do you want to activate debug configuration option ?", 'y') unless $config->{debug}; #Enable log file ? unless ($config->{logfile}) { if (ask_yn("Do you want to use OCS Inventory NG UNix Unified agent log file ?", 'y')){ $config->{logfile} = promptUser('Specify log file path you want to use', $config->{logfile}, '^\/\w+', 'The location must begin with /'); } } #Disable SSL option ? unless ($nossl) { $nossl = ask_yn("Do you want disable SSL CA verification configuration option (not recommended) ?", 'n'); } #Set CA certificates file path ? unless ($config->{ca}) { if (ask_yn("Do you want to set CA certificates file path ?", 'y')){ $config->{ca} = promptUser('Specify CA certificates file path', $config->{ca}, '^\/\w+', 'The location must begin with /'); } } #Enable download feature ? $download = ask_yn("Do you want to use OCS-Inventory software deployment feature?", 'y') unless $download; #Enable SNMP feature ? $config->{snmp} = ask_yn("Do you want to use OCS-Inventory SNMP scans feature?", 'y') unless $config->{snmp}; #Run agent after configuration ? $now = ask_yn("Do you want to send an inventory of this machine?", 'y') unless $now; } ################ Here we go... ############## #Old unix agent if (-f $old_unix_agent_dir.'/ocsinv.conf' && $old_unix_config) { print STDERR "Getting old OCS Inventory NG Unix agent configuration...\n"; my $ocsinv = XMLin($old_unix_agent_dir.'/ocsinv.conf'); $config->{server} = mkFullServerUrl($ocsinv->{'OCSFSERVER'}); if (-f $old_unix_agent_dir.'/cacert.pem') { open CACERT, $old_unix_agent_dir.'/cacert.pem' or die "Can't import the CA certificate: ".$!; @cacert = <CACERT>; close CACERT; } my $admcontent = ''; if (-f "$old_unix_agent_dir/ocsinv.adm") { if (!open(ADM, "<:encoding(iso-8859-1)", "$old_unix_agent_dir/ocsinv.adm")) { warn "Can't open $old_unix_agent_dir/ocsinv.adm"; } else { $admcontent .= $_ foreach (<ADM>); close ADM; my $admdata = XMLin($admcontent) or die; if (ref ($admdata->{ACCOUNTINFO}) eq 'ARRAY') { foreach (@{$admdata->{ACCOUNTINFO}}) { $config->{tag} = $_->{KEYVALUE} if $_->{KEYNAME} =~ /^TAG$/; } } elsif ( exists($admdata->{ACCOUNTINFO}->{KEYNAME}) && exists($admdata->{ACCOUNTINFO}->{KEYVALUE}) && $admdata->{ACCOUNTINFO}->{KEYNAME} eq 'TAG' ){ print $admdata->{ACCOUNTINFO}->{KEYVALUE}."\n"; $config->{tag} = $admdata->{ACCOUNTINFO}->{KEYVALUE}; } } } } #Setting server uri print STDERR "Setting OCS Inventory NG server address...\n"; $config->{server}="ocsinventory-ng" unless $config->{server}; $config->{server} = mkFullServerUrl($config->{server}); if (!$config->{server}) { print "Server is empty. Leaving...\n"; exit 1; } my $uri; if ($config->{server} =~ /^http(|s):\/\//) { $uri = $config->{server}; } else { # just the hostname $uri = "http://".$config->{server}."/ocsinventory" } #Is OCS agent well installed ? print STDERR "Looking for OCS Invetory NG Unix Unified agent installation...\n"; chomp($binpath = `which ocsinventory-agent 2>/dev/null`); if (! -x $binpath) { # Packaged version with perl and agent ? $binpath = $^X; $binpath =~ s/perl/ocsinventory-agent/; } if (! -x $binpath) { print "sorry, can't find ocsinventory-agent in \$PATH\n"; exit 1; } else { print "ocsinventory agent presents: $binpath\n"; } #Setting crontab $randomtime = int(rand(60)).' '.int(rand(24)); $cron_line = $randomtime." * * * root $binpath --lazy > /dev/null 2>&1\n"; if ($crontab) { print STDERR "Setting crontab...\n"; if ($^O =~ /solaris/ || $^O =~ /bsd/) { my $cron = `crontab -l`; # Let's suppress Unix cron/anacron user column $cron_line =~ s/ root / /; $cron .= $cron_line; open CRONP, "| crontab" || die "Can't run crontab: $!"; print CRONP $crontab; close(CRONP); } elsif (-d "/etc/cron.d") { open DEST, '>/etc/cron.d/ocsinventory-agent' or die $!; # Save the root PATH print DEST "PATH=".$ENV{PATH}."\n"; print DEST $randomtime." * * * root $binpath --lazy > /dev/null 2>&1\n"; close DEST; } } #Creating basevardir if (!-d $config->{basevardir}) { print STDERR "Creating $config->{basevardir} directory...\n"; mkdir $config->{basevardir} or die $!; } #Disabling SSL verification if asked $config->{ssl} = 0 if $nossl; #Creating configuration directory $configdir = "/etc/ocsinventory-agent" unless $configdir; #If not set in command line if (grep (/$configdir/,@default_configdirs)) { $configdir = '/etc/ocsinventory-agent' unless $configdir; print STDERR "Creating $configdir directory...\n"; unless (-d $configdir) { unless (mkdir $configdir) { die("Failed to create ".$configdir.". Are you root?\n"); } } print STDERR "Writing OCS Inventory NG Unix Unified agent configuration\n"; open CONFIG, ">$configdir/ocsinventory-agent.cfg" or die "Can't write the config file in $configdir: ".$!; print CONFIG $_."=".$config->{$_}."\n" foreach (keys %$config); close CONFIG; chmod 0600, "$configdir/ocsinventory-agent.cfg"; } else { die("Wrong configuration directory...please choose a directory supported by OCS Inventory NG agent !!!\n"); } #Removing old unix agent if needed if ($remove_old_unix) { print STDERR "Removing old OCS Inventory Unix agent...\n"; foreach (qw# /etc/ocsinventory-client /etc/logrotate.d/ocsinventory-client /usr/sbin/ocsinventory-client.pl /etc/cron.d/ocsinventory-client /bin/ocsinv #) { print $_."\n"; next; rmdir if -d; unlink if -f || -l; } print "done\n" } # Creating vardirectory for this server my $dir = $config->{server}; $dir =~ s/\//_/g; my $vardir = $config->{basevardir}."/".$dir; print STDERR "Creating $vardir directory...\n"; recMkdir($vardir) or die "Can't create $vardir!"; if (@cacert) { # we need to migrate the certificate print STDERR "Copying cacert.pem in $vardir...\n"; open CACERT, ">".$vardir."/cacert.pem" or die "Can't open ".$vardir.'/cacert.pem: '.$!; print CACERT foreach (@cacert); close CACERT; print "Certificate copied in ".$vardir."/cacert.pem\n"; } #We copy custom XML for SNMP MIBs from sources my $workdir = getcwd(); my $source_snmpdir = "$workdir/snmp"; my $snmpdir = "$vardir/snmp"; if ( -d $source_snmpdir && -d $vardir) { unless (-d $snmpdir) { print STDERR "Creating $snmpdir directory...\n"; recMkdir($snmpdir) or die "Can't create $snmpdir!"; } print STDERR "Copying SNMP MIBs XML files...\n"; system("cp -r $source_snmpdir/* $snmpdir"); } print STDERR "Activating modules if needed...\n"; open MODULE, ">$configdir/modules.conf" or die "Can't write modules.conf in $configdir: ".$!; print MODULE "# this list of module will be load by the at run time\n"; print MODULE "# to check its syntax do:\n"; print MODULE "# #perl modules.conf\n"; print MODULE "# You must have NO error. Else the content will be ignored\n"; print MODULE "# This mechanism goal is to launch agent extension modules\n"; print MODULE "\n"; print MODULE ($download?'':'#'); print MODULE "use Ocsinventory::Agent::Modules::Download;\n"; print MODULE ($config->{snmp}?'':'#'); print MODULE "use Ocsinventory::Agent::Modules::SnmpScan;\n"; print MODULE "\n"; print MODULE "# DO NOT REMOVE THE 1;\n"; print MODULE "1;\n"; close MODULE; #Prevent security risks by removing existing snmp_com.txt file which is no longer used my $snmp_com_file = "$snmpdir/snmp_com.txt"; if ( -f $snmp_com_file ) { print STDERR "$snmp_com_file seems to exists...removing it to prevent security risks !\n"; unlink $snmp_com_file; } # Launch agent if asked if ($now) { print STDERR "Launching OCS Inventory NG Unix Unified agent...\n"; system("$binpath --force"); if (($? >> 8)==0) { print " -> Success!\n"; } else { print " -> Failed!\n"; print "You may want to launch the agent with the --verbose or --debug flag.\n"; } } #End print "New settings written! Thank you for using OCS Inventory\n"; ######## Subroutines ################ sub loadModules { my @modules = @_; foreach (@modules) { eval "use $_;"; if ($@) { print STDERR "Failed to load $_. Please install it and restart the postinst.pl script ( ./postinst.pl ).\n"; exit 1; } } } sub ask_yn { my $promptUser = shift; my $default = shift; die unless $default =~ /^(y|n)$/; my $cpt = 5; while (1) { my $line = prompt("$promptUser\nPlease enter 'y' or 'n'?>", $default); return 1 if $line =~ /^y$/; return if $line =~ /^n$/; if ($cpt-- < 0) { print STDERR "to much user input, exit...\n"; exit(0); } } } sub promptUser { my ($promptUser, $default, $regex, $notice) = @_; my $string = $promptUser; $string .= "?>"; my $line; my $cpt = 5; while (1) { $line = prompt($string, $default); if ($regex && $line !~ /$regex/) { print STDERR $notice."\n"; } else { last; } if ($cpt-- < 0) { print STDERR "to much user input, exit...\n"; exit(0); } } return $line; } sub getConfigDir { my @choices = @_; foreach (@choices) { my $t = $_.'/ocsinventory-agent.cfg'; if (-f $t) { print "Config file found are $t! Reusing it.\n"; return $_; } } } sub askConfigDir { my @choices = @_; print STDERR "Where do you want to write the configuration file?\n"; foreach (0..$#choices) { print STDERR " ".$_." -> ".$choices[$_]."\n"; } my $input = -1; my $configdir; while (1) { $input = prompt("?>"); if ($input =~ /^\d+$/ && $input >= 0 && $input <= $#choices) { last; } else { print STDERR "Value must be between 0 and ".$#choices."\n"; } } return $choices[$input]; } sub recMkdir { my $dir = shift; my @t = split /\//, $dir; shift @t; return unless @t; my $t; foreach (@t) { $t .= '/'.$_; if ((!-d $t) && (!mkdir $t)) { return; } } 1; } sub mkFullServerUrl { my $server = shift; my $ret = 'http://' unless $server =~ /^http(s|):\/\//; $ret .= $server; if ($server !~ /http(|s):\/\/\S+\/\S+/) { $ret .= '/ocsinventory'; } return $ret; } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������UnixAgent-2.8/resources/����������������������������������������������������������������������������0000775�0000000�0000000�00000000000�13726633777�0015324�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������UnixAgent-2.8/resources/cpuinfo/��������������������������������������������������������������������0000775�0000000�0000000�00000000000�13726633777�0016767�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������UnixAgent-2.8/resources/cpuinfo/cpuinfo-vmware-esx��������������������������������������������������0000664�0000000�0000000�00000000000�13726633777�0022437�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������UnixAgent-2.8/resources/cpuinfo/linux-686-1���������������������������������������������������������0000664�0000000�0000000�00000001134�13726633777�0020527�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������processor : 0 vendor_id : GenuineIntel cpu family : 6 model : 13 model name : Intel(R) Pentium(R) M processor 1.73GHz stepping : 8 cpu MHz : 1729.038 cache size : 2048 KB fdiv_bug : no hlt_bug : no f00f_bug : no coma_bug : no fpu : yes fpu_exception : yes cpuid level : 2 wp : yes flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat clflush dts acpi mmx fxsr sse sse2 ss tm pbe nx bts est tm2 bogomips : 3462.27 clflush size : 64 power management: ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������UnixAgent-2.8/resources/cpuinfo/linux-alpha-1�������������������������������������������������������0000664�0000000�0000000�00000001550�13726633777�0021273�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������cpu : Alpha cpu model : EV68CB cpu variation : 7 cpu revision : 0 cpu serial number : JA30502089 system type : Titan system variation : Privateer system revision : 0 system serial number : AY31001636 cycle frequency [Hz] : 1250000000 timer frequency [Hz] : 1024.00 page size [bytes] : 8192 phys. address bits : 44 max. addr. space # : 255 BogoMIPS : 2484.04 kernel unaligned acc : 0 (pc=0,va=0) user unaligned acc : 0 (pc=0,va=0) platform string : AlphaServer ES45 Model 3B cpus detected : 3 cpus active : 3 cpu active mask : 0000000000000007 L1 Icache : 64K, 2-way, 64b line L1 Dcache : 64K, 2-way, 64b line L2 cache : n/a L3 cache : n/a ��������������������������������������������������������������������������������������������������������������������������������������������������������UnixAgent-2.8/resources/cpuinfo/linux-armel-1�������������������������������������������������������0000664�0000000�0000000�00000001130�13726633777�0021300�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������Processor : XScale-80219 rev 0 (v5l) BogoMIPS : 593.10 Features : swp half fastmult edsp CPU implementer : 0x69 CPU architecture: 5TE CPU variant : 0x0 CPU part : 0x2e3 CPU revision : 0 Cache type : undefined 5 Cache clean : undefined 5 Cache lockdown : undefined 5 Cache format : Harvard I size : 32768 I assoc : 32 I line length : 32 I sets : 32 D size : 32768 D assoc : 32 D line length : 32 D sets : 32 Hardware : Thecus N2100 Revision : 0000 Serial : 0000000000000000 ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������UnixAgent-2.8/resources/cpuinfo/linux-ia64-1��������������������������������������������������������0000664�0000000�0000000�00000001033�13726633777�0020745�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������processor : 0 vendor : GenuineIntel arch : IA-64 family : Itanium 2 model : 2 revision : 1 archrev : 0 features : branchlong cpu number : 0 cpu regs : 4 cpu MHz : 1600.000009 itc MHz : 1600.009464 BogoMIPS : 2392.06 siblings : 1 processor : 1 vendor : GenuineIntel arch : IA-64 family : Itanium 2 model : 2 revision : 1 archrev : 0 features : branchlong cpu number : 0 cpu regs : 4 cpu MHz : 1600.000009 itc MHz : 1600.009464 BogoMIPS : 2392.06 siblings : 1 �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������UnixAgent-2.8/resources/cpuinfo/linux-mips-1��������������������������������������������������������0000664�0000000�0000000�00000000644�13726633777�0021161�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������system type : SGI Indigo2 processor : 0 cpu model : R4400SC V5.0 FPU V0.0 BogoMIPS : 74.75 wait instruction : no microsecond timers : yes tlb_entries : 48 extra interrupt vector : no hardware watchpoint : yes ASEs implemented : shadow register sets : 1 VCED exceptions : 640580539 VCEI exceptions : 9972559 ��������������������������������������������������������������������������������������������UnixAgent-2.8/resources/cpuinfo/linux-ppc-1���������������������������������������������������������0000664�0000000�0000000�00000000406�13726633777�0020767�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������processor : 0 cpu : 604r clock : ??? revision : 49.2 (pvr 0009 3102) bogomips : 299.00 machine : PReP Utah (Powerstack II Pro4000) l2 cache : 512KiB, parity disabled SRAM:synchronous, pipelined, no parity ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������UnixAgent-2.8/resources/cpuinfo/linux-ppc-2���������������������������������������������������������0000664�0000000�0000000�00000000427�13726633777�0020773�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������processor : 0 cpu : POWER4+ (gq) clock : 1452.000000MHz revision : 2.1 processor : 1 cpu : POWER4+ (gq) clock : 1452.000000MHz revision : 2.1 timebase : 181495202 machine : CHRP IBM,7029-6C3 �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������UnixAgent-2.8/resources/cpuinfo/linux-sparc-1�������������������������������������������������������0000664�0000000�0000000�00000000615�13726633777�0021317�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������cpu : TI UltraSparc IIIi (Jalapeno) fpu : UltraSparc IIIi integrated FPU prom : OBP 4.13.2 2004/03/29 10:11 type : sun4u ncpus probed : 2 ncpus active : 2 D$ parity tl1 : 0 I$ parity tl1 : 0 Cpu0ClkTck : 000000003bb94e80 Cpu1ClkTck : 000000003bb94e80 MMU Type : Cheetah+ State: CPU0: online CPU1: online �������������������������������������������������������������������������������������������������������������������UnixAgent-2.8/resources/dmidecode-freebsd-6.2�������������������������������������������������������0000664�0000000�0000000�00000014471�13726633777�0021106�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# dmidecode 2.8 SMBIOS 2.3 present. 25 structures occupying 643 bytes. Table at 0x000F0800. Handle 0x0000, DMI type 1, 25 bytes System Information Manufacturer: Product Name: Version: Serial Number: UUID: Not Present Wake-up Type: Power Switch Handle 0x0001, DMI type 2, 8 bytes Base Board Information Manufacturer: Product Name: CN700-8237R Version: Serial Number: Handle 0x0002, DMI type 3, 17 bytes Chassis Information Manufacturer: Type: Desktop Lock: Not Present Version: Serial Number: Asset Tag: Boot-up State: Unknown Power Supply State: Unknown Thermal State: Unknown Security Status: Unknown OEM Information: 0x00000000 Handle 0x0003, DMI type 4, 35 bytes Processor Information Socket Designation: NanoBGA2 Type: Central Processor Family: Other Manufacturer: VIA ID: A9 06 00 00 FF BB C9 A7 Version: VIA C7 Voltage: 1.1 V External Clock: 100 MHz Max Speed: 2000 MHz Current Speed: 2000 MHz Status: Populated, Enabled Upgrade: None L1 Cache Handle: 0x0006 L2 Cache Handle: 0x0007 L3 Cache Handle: Not Provided Serial Number: Asset Tag: Part Number: Handle 0x0004, DMI type 5, 18 bytes Memory Controller Information Error Detecting Method: None Error Correcting Capabilities: None Supported Interleave: Eight-way Interleave Current Interleave: Four-way Interleave Maximum Memory Module Size: 1024 MB Maximum Total Memory Size: 1024 MB Supported Speeds: 70 ns 60 ns Supported Memory Types: DIMM SDRAM Memory Module Voltage: 2.9 V Associated Memory Slots: 1 0x0005 Enabled Error Correcting Capabilities: None Handle 0x0005, DMI type 6, 12 bytes Memory Module Information Socket Designation: A0 Bank Connections: 0 Current Speed: 37 ns Type: Other Installed Size: 512 MB (Single-bank Connection) Enabled Size: 512 MB (Single-bank Connection) Error Status: OK Handle 0x0006, DMI type 7, 19 bytes Cache Information Socket Designation: Internal Cache Configuration: Enabled, Not Socketed, Level 1 Operational Mode: Write Back Location: Internal Installed Size: 32 KB Maximum Size: 32 KB Supported SRAM Types: Synchronous Installed SRAM Type: Synchronous Speed: Unknown Error Correction Type: Unknown System Type: Unknown Associativity: 4-way Set-associative Handle 0x0007, DMI type 7, 19 bytes Cache Information Socket Designation: Internal Cache Configuration: Enabled, Not Socketed, Level 2 Operational Mode: Write Back Location: External Installed Size: 0 KB Maximum Size: 0 KB Supported SRAM Types: Synchronous Installed SRAM Type: Synchronous Speed: Unknown Error Correction Type: Unknown System Type: Unknown Associativity: Unknown Handle 0x0008, DMI type 8, 9 bytes Port Connector Information Internal Reference Designator: PRIMARY IDE Internal Connector Type: On Board IDE External Reference Designator: Not Specified External Connector Type: None Port Type: Other Handle 0x0009, DMI type 8, 9 bytes Port Connector Information Internal Reference Designator: SECONDARY IDE Internal Connector Type: On Board IDE External Reference Designator: Not Specified External Connector Type: None Port Type: Other Handle 0x000A, DMI type 8, 9 bytes Port Connector Information Internal Reference Designator: FDD Internal Connector Type: On Board Floppy External Reference Designator: Not Specified External Connector Type: None Port Type: 8251 FIFO Compatible Handle 0x000B, DMI type 8, 9 bytes Port Connector Information Internal Reference Designator: COM1 Internal Connector Type: 9 Pin Dual Inline (pin 10 cut) External Reference Designator: External Connector Type: DB-9 male Port Type: Serial Port 16450 Compatible Handle 0x000C, DMI type 8, 9 bytes Port Connector Information Internal Reference Designator: COM2 Internal Connector Type: 9 Pin Dual Inline (pin 10 cut) External Reference Designator: External Connector Type: DB-9 male Port Type: Serial Port 16450 Compatible Handle 0x000D, DMI type 8, 9 bytes Port Connector Information Internal Reference Designator: LPT1 Internal Connector Type: DB-25 female External Reference Designator: External Connector Type: DB-25 female Port Type: Parallel Port ECP/EPP Handle 0x000E, DMI type 8, 9 bytes Port Connector Information Internal Reference Designator: Keyboard Internal Connector Type: PS/2 External Reference Designator: External Connector Type: PS/2 Port Type: Keyboard Port Handle 0x000F, DMI type 8, 9 bytes Port Connector Information Internal Reference Designator: PS/2 Mouse Internal Connector Type: PS/2 External Reference Designator: External Connector Type: PS/2 Port Type: Mouse Port Handle 0x0010, DMI type 8, 9 bytes Port Connector Information Internal Reference Designator: Not Specified Internal Connector Type: None External Reference Designator: USB0 External Connector Type: Other Port Type: USB Handle 0x0011, DMI type 9, 13 bytes System Slot Information Designation: PCI0 Type: 32-bit PCI Current Usage: Available Length: Long ID: 1 Characteristics: 5.0 V is provided PME signal is supported Handle 0x0012, DMI type 13, 22 bytes BIOS Language Information Installable Languages: 3 n|US|iso8859-1 r|CA|iso8859-1 a|JP|unicode Currently Installed Language: n|US|iso8859-1 Handle 0x0013, DMI type 16, 15 bytes Physical Memory Array Location: System Board Or Motherboard Use: System Memory Error Correction Type: None Maximum Capacity: 512 MB Error Information Handle: Not Provided Number Of Devices: 1 Handle 0x0014, DMI type 17, 27 bytes Memory Device Array Handle: 0x0013 Error Information Handle: Not Provided Total Width: Unknown Data Width: Unknown Size: 512 MB Form Factor: DIMM Set: None Locator: A0 Bank Locator: Bank0/1 Type: Unknown Type Detail: None Speed: Unknown Manufacturer: None Serial Number: None Asset Tag: None Part Number: None Handle 0x0015, DMI type 19, 15 bytes Memory Array Mapped Address Starting Address: 0x00000000000 Ending Address: 0x0001FFFFFFF Range Size: 512 MB Physical Array Handle: 0x0013 Partition Width: 0 Handle 0x0016, DMI type 20, 19 bytes Memory Device Mapped Address Starting Address: 0x00000000000 Ending Address: 0x0001FFFFFFF Range Size: 512 MB Physical Device Handle: 0x0014 Memory Array Mapped Address Handle: 0x0015 Partition Row Position: 1 Handle 0x0017, DMI type 32, 11 bytes System Boot Information Status: No errors detected Handle 0x0018, DMI type 127, 4 bytes End Of Table �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������UnixAgent-2.8/resources/dmidecode-linux-2.6���������������������������������������������������������0000664�0000000�0000000�00000032757�13726633777�0020642�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# dmidecode 2.8 SMBIOS 2.3 present. 60 structures occupying 2446 bytes. Table at 0x000F7860. Handle 0xDA00, DMI type 218, 125 bytes OEM-specific Type Header and Data: DA 7D 00 DA B2 00 0D 5F 0F 37 40 7D 00 00 00 00 00 7E 00 02 00 00 00 40 00 04 00 01 00 41 00 04 00 00 00 90 00 05 00 00 00 91 00 05 00 01 00 92 00 05 00 02 00 45 01 45 01 01 00 44 01 44 01 00 00 00 80 00 80 01 00 00 A0 00 A0 01 00 05 80 05 80 01 00 76 01 76 01 01 00 75 01 75 01 01 00 01 F0 01 F0 00 00 02 F0 02 F0 00 00 03 F0 03 F0 00 00 04 F0 04 F0 00 00 FF FF 00 00 00 00 Handle 0x0000, DMI type 0, 20 bytes BIOS Information Vendor: Dell Inc. Version: A06 Release Date: 10/02/2005 Address: 0xF0000 Runtime Size: 64 kB ROM Size: 576 kB Characteristics: ISA is supported PCI is supported PC Card (PCMCIA) is supported PNP is supported BIOS is upgradeable BIOS shadowing is allowed Boot from CD is supported Selectable boot is supported 3.5"/720 KB floppy services are supported (int 13h) Print screen service is supported (int 5h) 8042 keyboard services are supported (int 9h) Serial services are supported (int 14h) Printer services are supported (int 17h) CGA/mono video services are supported (int 10h) ACPI is supported USB legacy is supported AGP is supported Smart battery is supported BIOS boot specification is supported Function key-initiated network boot is supported Handle 0x0100, DMI type 1, 25 bytes System Information Manufacturer: Dell Inc. Product Name: Latitude D610 Version: Not Specified Serial Number: D8XD62J UUID: 44454C4C-3800-1058-8044-C4C04F36324A Wake-up Type: Power Switch Handle 0x0200, DMI type 2, 9 bytes Base Board Information Manufacturer: Dell Inc. Product Name: 0XD762 Version: Serial Number: .D8XD62J.CN4864363E7491. Handle 0x0300, DMI type 3, 13 bytes Chassis Information Manufacturer: Dell Inc. Type: Portable Lock: Not Present Version: Not Specified Serial Number: D8XD62J Asset Tag: Not Specified Boot-up State: Safe Power Supply State: Safe Thermal State: Safe Security Status: None Handle 0x0301, DMI type 126, 13 bytes Inactive Handle 0x0400, DMI type 4, 32 bytes Processor Information Socket Designation: Microprocessor Type: Central Processor Family: Pentium M Manufacturer: Intel ID: D8 06 00 00 FF FB E9 AF Signature: Type 0, Family 6, Model 13, Stepping 8 Flags: FPU (Floating-point unit on-chip) VME (Virtual mode extension) DE (Debugging extension) PSE (Page size extension) TSC (Time stamp counter) MSR (Model specific registers) PAE (Physical address extension) MCE (Machine check exception) CX8 (CMPXCHG8 instruction supported) APIC (On-chip APIC hardware supported) SEP (Fast system call) MTRR (Memory type range registers) PGE (Page global enable) MCA (Machine check architecture) CMOV (Conditional move instruction supported) PAT (Page attribute table) CLFSH (CLFLUSH instruction supported) DS (Debug store) ACPI (ACPI supported) MMX (MMX technology supported) FXSR (Fast floating-point save and restore) SSE (Streaming SIMD extensions) SSE2 (Streaming SIMD extensions 2) SS (Self-snoop) TM (Thermal monitor supported) PBE (Pending break enabled) Version: Not Specified Voltage: 3.3 V External Clock: 133 MHz Max Speed: 1800 MHz Current Speed: 1733 MHz Status: Populated, Enabled Upgrade: None L1 Cache Handle: 0x0700 L2 Cache Handle: 0x0701 L3 Cache Handle: Not Provided Handle 0x0700, DMI type 7, 19 bytes Cache Information Socket Designation: Not Specified Configuration: Enabled, Not Socketed, Level 1 Operational Mode: Write Back Location: Internal Installed Size: 8 KB Maximum Size: 8 KB Supported SRAM Types: Unknown Installed SRAM Type: Unknown Speed: Unknown Error Correction Type: None System Type: Data Associativity: 4-way Set-associative Handle 0x0701, DMI type 7, 19 bytes Cache Information Socket Designation: Not Specified Configuration: Enabled, Not Socketed, Level 2 Operational Mode: Varies With Memory Address Location: Internal Installed Size: 2048 KB Maximum Size: 2048 KB Supported SRAM Types: Pipeline Burst Installed SRAM Type: Pipeline Burst Speed: 15 ns Error Correction Type: None System Type: Unified Associativity: Other Handle 0x0800, DMI type 8, 9 bytes Port Connector Information Internal Reference Designator: PARALLEL Internal Connector Type: None External Reference Designator: Not Specified External Connector Type: DB-25 female Port Type: Parallel Port PS/2 Handle 0x0801, DMI type 8, 9 bytes Port Connector Information Internal Reference Designator: SERIAL1 Internal Connector Type: None External Reference Designator: Not Specified External Connector Type: DB-9 male Port Type: Serial Port 16550A Compatible Handle 0x0803, DMI type 126, 9 bytes Inactive Handle 0x0804, DMI type 8, 9 bytes Port Connector Information Internal Reference Designator: USB Internal Connector Type: None External Reference Designator: Not Specified External Connector Type: Access Bus (USB) Port Type: USB Handle 0x0805, DMI type 126, 9 bytes Inactive Handle 0x0806, DMI type 8, 9 bytes Port Connector Information Internal Reference Designator: MONITOR Internal Connector Type: None External Reference Designator: Not Specified External Connector Type: DB-15 female Port Type: Video Port Handle 0x0808, DMI type 126, 9 bytes Inactive Handle 0x0809, DMI type 8, 9 bytes Port Connector Information Internal Reference Designator: IrDA Internal Connector Type: None External Reference Designator: Not Specified External Connector Type: Infrared Port Type: Other Handle 0x080A, DMI type 126, 9 bytes Inactive Handle 0x080C, DMI type 8, 9 bytes Port Connector Information Internal Reference Designator: Modem Internal Connector Type: None External Reference Designator: Not Specified External Connector Type: RJ-11 Port Type: Modem Port Handle 0x080D, DMI type 8, 9 bytes Port Connector Information Internal Reference Designator: Ethernet Internal Connector Type: None External Reference Designator: Not Specified External Connector Type: RJ-45 Port Type: Network Port Handle 0x0900, DMI type 9, 13 bytes System Slot Information Designation: PCMCIA 0 Type: 32-bit PC Card (PCMCIA) Current Usage: Available Length: Other ID: Adapter 0, Socket 0 Characteristics: 5.0 V is provided 3.3 V is provided PC Card-16 is supported Cardbus is supported Zoom Video is supported Modem ring resume is supported Handle 0x0902, DMI type 126, 13 bytes Inactive Handle 0x0904, DMI type 9, 13 bytes System Slot Information Designation: MiniPCI Type: 32-bit Other Current Usage: Available Length: Other Characteristics: 5.0 V is provided 3.3 V is provided PME signal is supported Handle 0x0A00, DMI type 10, 6 bytes On Board Device Information Type: Video Status: Enabled Description: Intel 915GM Graphics Handle 0x0A01, DMI type 10, 6 bytes On Board Device Information Type: Sound Status: Enabled Description: Sigmatel 9751 Handle 0x0B00, DMI type 11, 5 bytes OEM Strings String 1: Dell System String 2: 5[0003] String 3: 13[PP11L] Handle 0x0D00, DMI type 13, 22 bytes BIOS Language Information Installable Languages: 1 en|US|iso8859-1 Currently Installed Language: en|US|iso8859-1 Handle 0x1000, DMI type 16, 15 bytes Physical Memory Array Location: System Board Or Motherboard Use: System Memory Error Correction Type: None Maximum Capacity: 4 GB Error Information Handle: Not Provided Number Of Devices: 2 Handle 0x1100, DMI type 17, 27 bytes Memory Device Array Handle: 0x1000 Error Information Handle: Not Provided Total Width: 64 bits Data Width: 64 bits Size: 1024 MB Form Factor: DIMM Set: None Locator: DIMM_A Bank Locator: Not Specified Type: DDR Type Detail: Synchronous Speed: 533 MHz (1.9 ns) Manufacturer: C100000000000000 Serial Number: 02132010 Asset Tag: Not Specified Part Number: Not Specified Handle 0x1101, DMI type 17, 27 bytes Memory Device Array Handle: 0x1000 Error Information Handle: Not Provided Total Width: 64 bits Data Width: 64 bits Size: 1024 MB Form Factor: DIMM Set: None Locator: DIMM_B Bank Locator: Not Specified Type: DDR Type Detail: Synchronous Speed: 533 MHz (1.9 ns) Manufacturer: C100000000000000 Serial Number: 02132216 Asset Tag: Not Specified Part Number: Not Specified Handle 0x1300, DMI type 19, 15 bytes Memory Array Mapped Address Starting Address: 0x00000000000 Ending Address: 0x0000009FFFF Range Size: 640 kB Physical Array Handle: 0x1000 Partition Width: 0 Handle 0x1301, DMI type 19, 15 bytes Memory Array Mapped Address Starting Address: 0x00000100000 Ending Address: 0x0007FFFFFFF Range Size: 2047 MB Physical Array Handle: 0x1000 Partition Width: 0 Handle 0x1400, DMI type 20, 19 bytes Memory Device Mapped Address Starting Address: 0x00000000000 Ending Address: 0x0000009FFFF Range Size: 640 kB Physical Device Handle: 0x1100 Memory Array Mapped Address Handle: 0x1300 Partition Row Position: 1 Handle 0x1401, DMI type 20, 19 bytes Memory Device Mapped Address Starting Address: 0x00000100000 Ending Address: 0x0003FFFFFFF Range Size: 1023 MB Physical Device Handle: 0x1100 Memory Array Mapped Address Handle: 0x1301 Partition Row Position: 1 Handle 0x1402, DMI type 20, 19 bytes Memory Device Mapped Address Starting Address: 0x00040000000 Ending Address: 0x0007FFFFFFF Range Size: 1 GB Physical Device Handle: 0x1101 Memory Array Mapped Address Handle: 0x1301 Partition Row Position: 1 Handle 0x1500, DMI type 21, 7 bytes Built-in Pointing Device Type: Touch Pad Interface: Bus Mouse Buttons: 2 Handle 0x1600, DMI type 22, 26 bytes Portable Battery Location: Sys. Battery Bay Manufacturer: Samsung SDI Name: DELL C129563 Design Capacity: 48000 mWh Design Voltage: 11100 mV SBDS Version: 1.0 Maximum Error: 3% SBDS Serial Number: 7734 SBDS Manufacture Date: 2006-03-11 SBDS Chemistry: LION OEM-specific Information: 0x00000001 Handle 0x1601, DMI type 126, 26 bytes Inactive Handle 0x1602, DMI type 126, 26 bytes Inactive Handle 0x1B00, DMI type 27, 12 bytes Cooling Device Type: Fan Status: OK OEM-specific Information: 0x0000DD00 Handle 0x1C00, DMI type 28, 20 bytes Temperature Probe Description: CPU Internal Temperature Location: Processor Status: OK Maximum Value: 127.0 deg C Minimum Value 0.0 deg C Resolution: 1.000 deg C Tolerance: 0.5 deg C Accuracy: Unknown OEM-specific Information: 0x0000DC00 Handle 0x2000, DMI type 32, 11 bytes System Boot Information Status: No errors detected Handle 0xB000, DMI type 176, 5 bytes OEM-specific Type Header and Data: B0 05 00 B0 00 Handle 0xB100, DMI type 177, 12 bytes OEM-specific Type Header and Data: B1 0C 00 B1 01 00 00 00 00 00 00 00 Handle 0xD000, DMI type 208, 10 bytes OEM-specific Type Header and Data: D0 0A 00 D0 01 04 FE 00 82 01 Handle 0xD100, DMI type 209, 12 bytes OEM-specific Type Header and Data: D1 0C 00 D1 00 00 00 03 04 07 80 05 Handle 0xD200, DMI type 210, 12 bytes OEM-specific Type Header and Data: D2 0C 00 D2 F8 03 04 03 06 80 04 05 Handle 0xD300, DMI type 211, 13 bytes OEM-specific Type Header and Data: D3 0D 00 D3 01 04 02 01 00 00 00 00 02 Strings: Back of System Handle 0xD800, DMI type 216, 9 bytes OEM-specific Type Header and Data: D8 09 00 D8 01 03 01 F0 03 Strings: Intel Corp. 1219 Handle 0xD900, DMI type 217, 8 bytes OEM-specific Type Header and Data: D9 08 00 D9 01 02 01 03 Strings: US-101 Proprietary Handle 0xDB00, DMI type 219, 9 bytes OEM-specific Type Header and Data: DB 09 00 DB 03 01 02 03 FF Strings: System Device Bay Floppy, Battery, CD-ROM, CD-RW, DVD, DVD+RW, DVD+/-RW, Hard Disk CDRW+DVD Handle 0xDB80, DMI type 126, 9 bytes Inactive Handle 0xDB81, DMI type 126, 9 bytes Inactive Handle 0x8100, DMI type 129, 8 bytes OEM-specific Type Header and Data: 81 08 00 81 01 01 02 01 Strings: Intel_ASF Dell_ASF_001 Handle 0xDC00, DMI type 220, 22 bytes OEM-specific Type Header and Data: DC 16 00 DC 01 F0 00 00 02 F0 00 00 00 00 03 F0 04 F0 00 00 00 00 Handle 0xDD00, DMI type 221, 19 bytes OEM-specific Type Header and Data: DD 13 00 DD 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 Handle 0xD400, DMI type 212, 237 bytes OEM-specific Type Header and Data: D4 ED 00 D4 70 00 71 00 00 10 2D 2E 5C 00 78 BF 40 5D 00 78 BF 00 65 00 21 F7 00 66 00 21 F7 08 5E 00 23 FE 01 5F 00 23 FE 00 F1 00 21 FC 00 F2 00 21 FC 01 F3 00 21 FC 02 0F 00 26 F8 00 11 00 26 F8 01 05 00 26 F8 02 12 00 26 F8 03 06 00 26 F8 04 31 00 26 8F 00 32 00 26 8F 10 33 00 26 8F 20 34 00 26 8F 30 35 00 26 8F 40 07 00 25 F8 00 0B 00 25 F8 01 0C 00 25 F8 02 0D 00 25 F8 03 28 00 23 F3 00 29 00 23 F3 04 2A 00 23 F3 08 2B 00 58 00 00 2C 00 59 00 00 E7 00 1D F3 04 E6 00 1D F3 00 0E 01 23 FD 02 0F 01 23 FD 00 9B 00 23 EF 10 9C 00 23 EF 00 87 00 11 FD 02 88 00 11 FD 00 E8 00 23 DF 20 E9 00 23 DF 00 51 01 22 F7 00 50 01 22 F7 08 12 01 34 FB 04 13 01 34 FB 00 08 00 1D DF 00 03 00 1D DF 00 FF FF 00 00 00 Handle 0xD401, DMI type 212, 127 bytes OEM-specific Type Header and Data: D4 7F 01 D4 70 00 71 00 03 40 49 4A 42 00 48 7F 80 43 00 48 7F 00 55 00 47 BF 00 6D 00 47 BF 40 0C 01 46 FB 04 0D 01 46 FB 00 14 01 46 E7 00 15 01 46 E7 08 16 01 46 E7 10 0A 01 48 EF 10 0B 01 48 EF 00 2D 00 48 DF 20 2E 00 48 DF 00 11 01 48 BF 00 10 01 48 BF 40 F0 00 46 DF 20 ED 00 46 DF 00 41 01 46 FE 01 40 01 46 FE 00 EA 00 67 F3 00 EB 00 67 F3 04 EC 00 67 F3 08 FF FF 00 00 00 Handle 0xDE00, DMI type 222, 13 bytes OEM-specific Type Header and Data: DE 0D 00 DE 01 02 FF FF 00 00 00 00 00 Handle 0x7F00, DMI type 127, 4 bytes End Of Table �����������������UnixAgent-2.8/resources/dmidecode-openbsd-3.7�������������������������������������������������������0000664�0000000�0000000�00000040102�13726633777�0021116�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# dmidecode 2.6 Legacy DMI 2.0 present. 41 structures occupying 1014 bytes. Table at 0x000F0800. Handle 0x0000 DMI type 0, 18 bytes. BIOS Information Vendor: Award Software International, Inc. Version: 4.51 PG Release Date: 02/11/99 Address: 0xE0000 Runtime Size: 128 kB ROM Size: 256 kB Characteristics: ISA is supported PCI is supported PNP is supported APM is supported BIOS is upgradeable BIOS shadowing is allowed ESCD support is available Boot from CD is supported Selectable boot is supported BIOS ROM is socketed EDD is supported 5.25"/360 KB floppy services are supported (int 13h) 5.25"/1.2 MB floppy services are supported (int 13h) 3.5"/720 KB floppy services are supported (int 13h) 3.5"/2.88 MB floppy services are supported (int 13h) Print screen service is supported (int 5h) 8042 keyboard services are supported (int 9h) Serial services are supported (int 14h) Printer services are supported (int 17h) CGA/mono video services are supported (int 10h) Handle 0x0001 DMI type 1, 8 bytes. System Information Manufacturer: VIA Technologies, Inc. Product Name: VT82C691 Version: Serial Number: Handle 0x0002 DMI type 2, 8 bytes. Base Board Information Manufacturer: Tekram Technology Co., Ltd. Product Name: P6PROA5 Version: Rev. 1.0 Serial Number: Handle 0x0003 DMI type 3, 9 bytes. Chassis Information Manufacturer: Type: Unknown Lock: Not Present Version: Serial Number: Asset Tag: Handle 0x0004 DMI type 4, 26 bytes. Processor Information Socket Designation: SLOT 1 Type: Central Processor Family: Pentium II Manufacturer: Intel ID: 52 06 00 00 FF F9 83 01 Signature: Type 0, Family 6, Model 5, Stepping 2 Flags: FPU (Floating-point unit on-chip) VME (Virtual mode extension) DE (Debugging extension) PSE (Page size extension) TSC (Time stamp counter) MSR (Model specific registers) PAE (Physical address extension) MCE (Machine check exception) CX8 (CMPXCHG8 instruction supported) SEP (Fast system call) MTRR (Memory type range registers) PGE (Page global enable) MCA (Machine check architecture) CMOV (Conditional move instruction supported) PAT (Page attribute table) PSE-36 (36-bit page size extension) MMX (MMX technology supported) FXSR (Fast floating-point save and restore) Version: Pentium II Voltage: 3.3 V External Clock: 100 MHz Max Speed: 500 MHz Current Speed: 400 MHz Status: Populated, Enabled Upgrade: Slot 1 Handle 0x0005 DMI type 5, 31 bytes. Memory Controller Information Error Detecting Method: 64-bit ECC Error Correcting Capabilities: Single-bit Error Correcting Supported Interleave: Four-way Interleave Current Interleave: One-way Interleave Maximum Memory Module Size: 256 MB Maximum Total Memory Size: 2048 MB Supported Speeds: 70 ns 60 ns Supported Memory Types: Other Unknown Standard FPM EDO Parity ECC SIMM DIMM SDRAM Memory Module Voltage: 5.0 V 3.3 V Associated Memory Slots: 8 0x0006 0x0007 0x0008 0x0009 0x000A 0x000B 0x000C 0x000D Handle 0x0007 DMI type 6, 12 bytes. Memory Module Information Socket Designation: BANK_1 Bank Connections: 2 Current Speed: 70 ns Type: Unknown Installed Size: Not Installed Enabled Size: Not Installed Error Status: OK Handle 0x0008 DMI type 6, 12 bytes. Memory Module Information Socket Designation: BANK_2 Bank Connections: 3 Current Speed: 70 ns Type: DIMM SDRAM Installed Size: 64 MB (Single-bank Connection) Enabled Size: 64 MB (Single-bank Connection) Error Status: OK Handle 0x0009 DMI type 6, 12 bytes. Memory Module Information Socket Designation: BANK_3 Bank Connections: 4 Current Speed: 70 ns Type: Unknown Installed Size: Not Installed Enabled Size: Not Installed Error Status: OK Handle 0x000A DMI type 6, 12 bytes. Memory Module Information Socket Designation: BANK_4 Bank Connections: 5 Current Speed: 70 ns Type: DIMM SDRAM Installed Size: 64 MB (Single-bank Connection) Enabled Size: 64 MB (Single-bank Connection) Error Status: OK Handle 0x000B DMI type 6, 12 bytes. Memory Module Information Socket Designation: BANK_5 Bank Connections: 6 Current Speed: 70 ns Type: DIMM SDRAM Installed Size: 64 MB (Single-bank Connection) Enabled Size: 64 MB (Single-bank Connection) Error Status: OK Handle 0x000C DMI type 6, 12 bytes. Memory Module Information Socket Designation: BANK_6 Bank Connections: 7 Current Speed: 70 ns Type: Unknown Installed Size: Not Installed Enabled Size: Not Installed Error Status: OK Handle 0x000D DMI type 6, 12 bytes. Memory Module Information Socket Designation: BANK_7 Bank Connections: 8 Current Speed: 70 ns Type: Unknown Installed Size: Not Installed Enabled Size: Not Installed Error Status: OK Handle 0x000E DMI type 7, 15 bytes. Cache Information Socket Designation: Internal Cache Configuration: Enabled, Not Socketed, Level 1 Operational Mode: Write Back Location: Internal Installed Size: 32 KB Maximum Size: 32 KB Supported SRAM Types: Synchronous Installed SRAM Type: Synchronous Handle 0x000F DMI type 7, 15 bytes. Cache Information Socket Designation: External Cache Configuration: Enabled, Not Socketed, Level 2 Operational Mode: Write Back Location: External Installed Size: 512 KB Maximum Size: 2048 KB Supported SRAM Types: Synchronous Installed SRAM Type: Synchronous Handle 0x0010 DMI type 8, 9 bytes. Port Connector Information Internal Reference Designator: PRIMARY IDE Internal Connector Type: On Board IDE External Reference Designator: External Connector Type: None Port Type: Other Handle 0x0011 DMI type 8, 9 bytes. Port Connector Information Internal Reference Designator: SECONDARY IDE Internal Connector Type: On Board IDE External Reference Designator: External Connector Type: None Port Type: Other Handle 0x0012 DMI type 8, 9 bytes. Port Connector Information Internal Reference Designator: FLOPPY Internal Connector Type: On Board Floppy External Reference Designator: External Connector Type: None Port Type: Other Handle 0x0013 DMI type 8, 9 bytes. Port Connector Information Internal Reference Designator: COM1 Internal Connector Type: 9 Pin Dual Inline (pin 10 cut) External Reference Designator: External Connector Type: DB-9 male Port Type: Serial Port 16550 Compatible Handle 0x0014 DMI type 8, 9 bytes. Port Connector Information Internal Reference Designator: COM2 Internal Connector Type: 9 Pin Dual Inline (pin 10 cut) External Reference Designator: External Connector Type: DB-9 male Port Type: Serial Port 16550 Compatible Handle 0x0015 DMI type 8, 9 bytes. Port Connector Information Internal Reference Designator: LPT1 Internal Connector Type: DB-25 female External Reference Designator: External Connector Type: DB-25 female Port Type: Parallel Port ECP/EPP Handle 0x0016 DMI type 8, 9 bytes. Port Connector Information Internal Reference Designator: Keyboard Internal Connector Type: Other External Reference Designator: External Connector Type: PS/2 Port Type: Keyboard Port Handle 0x0017 DMI type 8, 9 bytes. Port Connector Information Internal Reference Designator: PS/2 Mouse Internal Connector Type: Other External Reference Designator: External Connector Type: PS/2 Port Type: Mouse Port Handle 0x0018 DMI type 8, 9 bytes. Port Connector Information Internal Reference Designator: IR_CON Internal Connector Type: Other External Reference Designator: External Connector Type: Infrared Port Type: Other Handle 0x0019 DMI type 8, 9 bytes. Port Connector Information Internal Reference Designator: IR_CON2 Internal Connector Type: Other External Reference Designator: External Connector Type: Infrared Port Type: Other Handle 0x001A DMI type 9, 12 bytes. System Slot Information Designation: AGP Type: 32-bit PCI Current Usage: In Use Length: Long ID: 32 Characteristics: 5.0 V is provided Handle 0x001B DMI type 9, 12 bytes. System Slot Information Designation: PCI1 Type: 32-bit PCI Current Usage: Available Length: Long ID: 12 Characteristics: 5.0 V is provided Handle 0x001C DMI type 9, 12 bytes. System Slot Information Designation: PCI2 Type: 32-bit PCI Current Usage: Available Length: Long ID: 11 Characteristics: 5.0 V is provided Handle 0x001D DMI type 9, 12 bytes. System Slot Information Designation: PCI3 Type: 32-bit PCI Current Usage: In Use Length: Long ID: 10 Characteristics: 5.0 V is provided Handle 0x001E DMI type 9, 12 bytes. System Slot Information Designation: PCI4 Type: 32-bit PCI Current Usage: Available Length: Long ID: 9 Characteristics: 5.0 V is provided Handle 0x001F DMI type 9, 12 bytes. System Slot Information Designation: PCI5 Type: 32-bit PCI Current Usage: Available Length: Long ID: 8 Characteristics: 5.0 V is provided Handle 0x0020 DMI type 9, 12 bytes. System Slot Information Designation: ISA Type: 16-bit ISA Current Usage: Unknown Length: Long Characteristics: 5.0 V is provided Handle 0x0021 DMI type 9, 12 bytes. System Slot Information Designation: ISA Type: 16-bit ISA Current Usage: Unknown Length: Long Characteristics: 5.0 V is provided Handle 0x0022 DMI type 9, 12 bytes. System Slot Information Designation: PCIx Type: 32-bit PCI Current Usage: Unknown Length: Long ID: 0 Characteristics: 5.0 V is provided Handle 0x0023 DMI type 9, 12 bytes. System Slot Information Designation: PCIx Type: 32-bit PCI Current Usage: Unknown Length: Long ID: 0 Characteristics: 5.0 V is provided Handle 0x0024 DMI type 9, 12 bytes. System Slot Information Designation: PCIx Type: 32-bit PCI Current Usage: Unknown Length: Long ID: 0 Characteristics: 5.0 V is provided Handle 0x0025 DMI type 9, 12 bytes. System Slot Information Designation: PCIx Type: 32-bit PCI Current Usage: Unknown Length: Long ID: 0 Characteristics: 5.0 V is provided Handle 0x0026 DMI type 9, 12 bytes. System Slot Information Designation: PCIx Type: 32-bit PCI Current Usage: Unknown Length: Long ID: 0 Characteristics: 5.0 V is provided Handle 0x0027 DMI type 8, 9 bytes. Port Connector Information Internal Reference Designator: USB Internal Connector Type: Other External Reference Designator: External Connector Type: Other Port Type: USB Handle 0x0028 DMI type 13, 22 bytes. BIOS Language Information Installable Languages: 3 en|US|iso8859-1 fr|CA|iso8859-1 ja|JP|unicode Currently Installed Language: en|US|iso8859-1 Wrong DMI structures count: 41 announced, only 40 decoded. ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������UnixAgent-2.8/resources/dmidecode-openbsd-3.8�������������������������������������������������������0000664�0000000�0000000�00000067563�13726633777�0021143�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ dmidecode 2.6 SMBIOS 2.3 present. 82 structures occupying 3043 bytes. Table at 0x000FA4C0. Handle 0xDA00 DMI type 218, 11 bytes. OEM-specific Type Header and Data: DA 0B 00 DA B2 00 17 00 0E 20 00 Handle 0x0000 DMI type 0, 20 bytes. BIOS Information Vendor: Dell Computer Corporation Version: A05 Release Date: 09/21/2005 Address: 0xF0000 Runtime Size: 64 kB ROM Size: 1024 kB Characteristics: ISA is supported PCI is supported PNP is supported BIOS is upgradeable BIOS shadowing is allowed ESCD support is available Boot from CD is supported Selectable boot is supported EDD is supported Japanese floppy for Toshiba 1.2 MB is supported (int 13h) 5.25"/360 KB floppy services are supported (int 13h) 5.25"/1.2 MB floppy services are supported (int 13h) 3.5"/720 KB floppy services are supported (int 13h) Print screen service is supported (int 5h) 8042 keyboard services are supported (int 9h) Serial services are supported (int 14h) Printer services are supported (int 17h) CGA/mono video services are supported (int 10h) ACPI is supported USB legacy is supported LS-120 boot is supported BIOS boot specification is supported Function key-initiated network boot is supported Handle 0x0100 DMI type 1, 25 bytes. System Information Manufacturer: Dell Computer Corporation Product Name: PowerEdge 1800 Version: Not Specified Serial Number: 2K1012J UUID: 44454C4C-4B00-1031-8030-B2C04F31324A Wake-up Type: Power Switch Handle 0x0200 DMI type 2, 9 bytes. Base Board Information Manufacturer: Dell Computer Corporation Product Name: 0P8611 Version: A04 Serial Number: ..CN717035A80217. Handle 0x0300 DMI type 3, 17 bytes. Chassis Information Manufacturer: Dell Computer Corporation Type: Main Server Chassis Lock: Present Version: Not Specified Serial Number: 2K1012J Asset Tag: Not Specified Boot-up State: Safe Power Supply State: Safe Thermal State: Safe Security Status: Unknown OEM Information: 0x00000000 Handle 0x0400 DMI type 4, 35 bytes. Processor Information Socket Designation: PROC_1 Type: Central Processor Family: Xeon Manufacturer: Intel ID: 43 0F 00 00 FF FB EB BF Signature: Type 0, Family 15, Model 4, Stepping 3 Flags: FPU (Floating-point unit on-chip) VME (Virtual mode extension) DE (Debugging extension) PSE (Page size extension) TSC (Time stamp counter) MSR (Model specific registers) PAE (Physical address extension) MCE (Machine check exception) CX8 (CMPXCHG8 instruction supported) APIC (On-chip APIC hardware supported) SEP (Fast system call) MTRR (Memory type range registers) PGE (Page global enable) MCA (Machine check architecture) CMOV (Conditional move instruction supported) PAT (Page attribute table) PSE-36 (36-bit page size extension) CLFSH (CLFLUSH instruction supported) DS (Debug store) ACPI (ACPI supported) MMX (MMX technology supported) FXSR (Fast floating-point save and restore) SSE (Streaming SIMD extensions) SSE2 (Streaming SIMD extensions 2) SS (Self-snoop) HTT (Hyper-threading technology) TM (Thermal monitor supported) PBE (Pending break enabled) Version: Not Specified Voltage: 1.4 V External Clock: 800 MHz Max Speed: 3600 MHz Current Speed: 3000 MHz Status: Populated, Enabled Upgrade: ZIF Socket L1 Cache Handle: 0x0700 L2 Cache Handle: 0x0701 L3 Cache Handle: 0x0702 Serial Number: Not Specified Asset Tag: Not Specified Part Number: Not Specified Handle 0x0401 DMI type 4, 35 bytes. Processor Information Socket Designation: PROC_2 Type: Central Processor Family: Xeon Manufacturer: Intel ID: 00 00 00 00 00 00 00 00 Signature: Type 0, Family 0, Model 0, Stepping 0 Flags: None Version: Not Specified Voltage: 1.4 V External Clock: Unknown Max Speed: 3600 MHz Current Speed: Unknown Status: Unpopulated Upgrade: ZIF Socket L1 Cache Handle: 0x0703 L2 Cache Handle: 0x0704 L3 Cache Handle: 0x0705 Serial Number: Not Specified Asset Tag: Not Specified Part Number: Not Specified Handle 0x0700 DMI type 7, 19 bytes. Cache Information Socket Designation: Not Specified Configuration: Enabled, Not Socketed, Level 1 Operational Mode: Write Through Location: Internal Installed Size: 16 KB Maximum Size: 16 KB Supported SRAM Types: Unknown Installed SRAM Type: Unknown Speed: Unknown Error Correction Type: Parity System Type: Data Associativity: 8-way Set-associative Handle 0x0701 DMI type 7, 19 bytes. Cache Information Socket Designation: Not Specified Configuration: Enabled, Not Socketed, Level 2 Operational Mode: Write Back Location: Internal Installed Size: 2048 KB Maximum Size: 2048 KB Supported SRAM Types: Unknown Installed SRAM Type: Unknown Speed: Unknown Error Correction Type: Single-bit ECC System Type: Unified Associativity: 8-way Set-associative Handle 0x0702 DMI type 7, 19 bytes. Cache Information Socket Designation: Not Specified Configuration: Enabled, Not Socketed, Level 3 Operational Mode: Write Back Location: Internal Installed Size: 0 KB Maximum Size: 0 KB Supported SRAM Types: Unknown Installed SRAM Type: Unknown Speed: Unknown Error Correction Type: Single-bit ECC System Type: Unified Associativity: 2-way Set-associative Handle 0x0703 DMI type 7, 19 bytes. Cache Information Socket Designation: Not Specified Configuration: Enabled, Not Socketed, Level 1 Operational Mode: Write Through Location: Internal Installed Size: 0 KB Maximum Size: 16 KB Supported SRAM Types: Unknown Installed SRAM Type: Unknown Speed: Unknown Error Correction Type: Parity System Type: Data Associativity: 8-way Set-associative Handle 0x0704 DMI type 7, 19 bytes. Cache Information Socket Designation: Not Specified Configuration: Enabled, Not Socketed, Level 2 Operational Mode: Write Back Location: Internal Installed Size: 0 KB Maximum Size: 2048 KB Supported SRAM Types: Unknown Installed SRAM Type: Unknown Speed: Unknown Error Correction Type: Single-bit ECC System Type: Unified Associativity: 8-way Set-associative Handle 0x0705 DMI type 7, 19 bytes. Cache Information Socket Designation: Not Specified Configuration: Enabled, Not Socketed, Level 3 Operational Mode: Write Back Location: Internal Installed Size: 0 KB Maximum Size: 0 KB Supported SRAM Types: Unknown Installed SRAM Type: Unknown Speed: Unknown Error Correction Type: Single-bit ECC System Type: Unified Associativity: 2-way Set-associative Handle 0x0800 DMI type 8, 9 bytes. Port Connector Information Internal Reference Designator: SCSI Internal Connector Type: 68 Pin Dual Inline External Reference Designator: Not Specified External Connector Type: None Port Type: SCSI Wide Handle 0x0801 DMI type 8, 9 bytes. Port Connector Information Internal Reference Designator: Not Specified Internal Connector Type: None External Reference Designator: Not Specified External Connector Type: DB-15 female Port Type: Video Port Handle 0x0802 DMI type 8, 9 bytes. Port Connector Information Internal Reference Designator: Not Specified Internal Connector Type: None External Reference Designator: Not Specified External Connector Type: Access Bus (USB) Port Type: USB Handle 0x0803 DMI type 8, 9 bytes. Port Connector Information Internal Reference Designator: Not Specified Internal Connector Type: None External Reference Designator: Not Specified External Connector Type: Access Bus (USB) Port Type: USB Handle 0x0804 DMI type 8, 9 bytes. Port Connector Information Internal Reference Designator: Not Specified Internal Connector Type: None External Reference Designator: Not Specified External Connector Type: Access Bus (USB) Port Type: USB Handle 0x0805 DMI type 8, 9 bytes. Port Connector Information Internal Reference Designator: Not Specified Internal Connector Type: None External Reference Designator: Not Specified External Connector Type: Access Bus (USB) Port Type: USB Handle 0x0806 DMI type 8, 9 bytes. Port Connector Information Internal Reference Designator: Not Specified Internal Connector Type: None External Reference Designator: Not Specified External Connector Type: DB-25 female Port Type: Parallel Port PS/2 Handle 0x0807 DMI type 8, 9 bytes. Port Connector Information Internal Reference Designator: Not Specified Internal Connector Type: None External Reference Designator: Not Specified External Connector Type: RJ-45 Port Type: Network Port Handle 0x0808 DMI type 8, 9 bytes. Port Connector Information Internal Reference Designator: Not Specified Internal Connector Type: None External Reference Designator: Not Specified External Connector Type: DB-9 male Port Type: Serial Port 16550A Compatible Handle 0x0809 DMI type 8, 9 bytes. Port Connector Information Internal Reference Designator: Not Specified Internal Connector Type: None External Reference Designator: Not Specified External Connector Type: PS/2 Port Type: Keyboard Port Handle 0x080A DMI type 8, 9 bytes. Port Connector Information Internal Reference Designator: Not Specified Internal Connector Type: None External Reference Designator: Not Specified External Connector Type: PS/2 Port Type: Mouse Port Handle 0x0900 DMI type 9, 13 bytes. System Slot Information Designation: SLOT1 Type: 64-bit PCI Current Usage: Available Length: Long ID: 1 Characteristics: 3.3 V is provided PME signal is supported Handle 0x0901 DMI type 9, 13 bytes. System Slot Information Designation: SLOT2 Type: <OUT OF SPEC><OUT OF SPEC> Current Usage: Available Length: Long Characteristics: 3.3 V is provided PME signal is supported Handle 0x0902 DMI type 9, 13 bytes. System Slot Information Designation: SLOT3 Type: <OUT OF SPEC><OUT OF SPEC> Current Usage: Available Length: Long Characteristics: 3.3 V is provided PME signal is supported Handle 0x0903 DMI type 9, 13 bytes. System Slot Information Designation: SLOT4 Type: 32-bit PCI Current Usage: Available Length: Long ID: 4 Characteristics: 5.0 V is provided PME signal is supported Handle 0x0904 DMI type 9, 13 bytes. System Slot Information Designation: SLOT5 Type: 64-bit PCI-X Current Usage: In Use Length: Long ID: 5 Characteristics: 3.3 V is provided PME signal is supported Handle 0x0905 DMI type 9, 13 bytes. System Slot Information Designation: SLOT6 Type: 64-bit PCI-X Current Usage: Available Length: Long ID: 6 Characteristics: 3.3 V is provided PME signal is supported Handle 0x0A00 DMI type 10, 10 bytes. On Board Device 1 Information Type: SCSI Controller Status: Enabled Description: LSI Logic 53C1020 Ultra 320 SCSI On Board Device 2 Information Type: Video Status: Enabled Description: ATI RADEON 7000 PCI Video On Board Device 3 Information Type: Ethernet Status: Enabled Description: Intel 82541GI Gigabit Ethernet Handle 0x0B00 DMI type 11, 5 bytes. OEM Strings String 1: Dell System String 2: 5[0000] Handle 0x7E00 DMI type 126, 144 bytes. Inactive Handle 0x0C00 DMI type 12, 5 bytes. System Configuration Options Option 1: NVRAM_CLR: Clear user settable NVRAM areas and set defaults Option 2: PASSWD: Close to enable password Handle 0x0D00 DMI type 13, 22 bytes. BIOS Language Information Installable Languages: 1 en|US|iso8859-1 Currently Installed Language: en|US|iso8859-1 Handle 0x1000 DMI type 16, 15 bytes. Physical Memory Array Location: System Board Or Motherboard Use: System Memory Error Correction Type: Multi-bit ECC Maximum Capacity: 12 GB Error Information Handle: Not Provided Number Of Devices: 6 Handle 0x1100 DMI type 17, 27 bytes. Memory Device Array Handle: 0x1000 Error Information Handle: Not Provided Total Width: 72 bits Data Width: 64 bits Size: 512 MB Form Factor: DIMM Set: 1 Locator: DIMM1_A Bank Locator: Not Specified Type: <OUT OF SPEC> Type Detail: Synchronous Speed: 400 MHz (2.5 ns) Manufacturer: CE00000000000000 Serial Number: 50075483 Asset Tag: 010552 Part Number: M3 93T6450FZ0-CCC Handle 0x1101 DMI type 17, 27 bytes. Memory Device Array Handle: 0x1000 Error Information Handle: Not Provided Total Width: 72 bits Data Width: 64 bits Size: 512 MB Form Factor: DIMM Set: 1 Locator: DIMM1_B Bank Locator: Not Specified Type: <OUT OF SPEC> Type Detail: Synchronous Speed: 400 MHz (2.5 ns) Manufacturer: CE00000000000000 Serial Number: 500355A1 Asset Tag: 010552 Part Number: M3 93T6450FZ0-CCC Handle 0x1102 DMI type 17, 27 bytes. Memory Device Array Handle: 0x1000 Error Information Handle: Not Provided Total Width: 72 bits Data Width: 64 bits Size: No Module Installed Form Factor: DIMM Set: 2 Locator: DIMM2_A Bank Locator: Not Specified Type: <OUT OF SPEC> Type Detail: Synchronous Speed: 400 MHz (2.5 ns) Manufacturer: Serial Number: Asset Tag: Part Number: Handle 0x1103 DMI type 17, 27 bytes. Memory Device Array Handle: 0x1000 Error Information Handle: Not Provided Total Width: 72 bits Data Width: 64 bits Size: No Module Installed Form Factor: DIMM Set: 2 Locator: DIMM2_B Bank Locator: Not Specified Type: <OUT OF SPEC> Type Detail: Synchronous Speed: 400 MHz (2.5 ns) Manufacturer: Serial Number: Asset Tag: Part Number: Handle 0x1104 DMI type 17, 27 bytes. Memory Device Array Handle: 0x1000 Error Information Handle: Not Provided Total Width: 72 bits Data Width: 64 bits Size: No Module Installed Form Factor: DIMM Set: 3 Locator: DIMM3_A Bank Locator: Not Specified Type: <OUT OF SPEC> Type Detail: Synchronous Speed: 400 MHz (2.5 ns) Manufacturer: Serial Number: Asset Tag: Part Number: Handle 0x1105 DMI type 17, 27 bytes. Memory Device Array Handle: 0x1000 Error Information Handle: Not Provided Total Width: 72 bits Data Width: 64 bits Size: No Module Installed Form Factor: DIMM Set: 3 Locator: DIMM3_B Bank Locator: Not Specified Type: <OUT OF SPEC> Type Detail: Synchronous Speed: 400 MHz (2.5 ns) Manufacturer: Serial Number: Asset Tag: Part Number: Handle 0x1300 DMI type 19, 15 bytes. Memory Array Mapped Address Starting Address: 0x00000000000 Ending Address: 0x0003FFFFFFF Range Size: 1 GB Physical Array Handle: 0x1000 Partition Width: 0 Handle 0x1301 DMI type 126, 15 bytes. Inactive Handle 0x1400 DMI type 20, 19 bytes. Memory Device Mapped Address Starting Address: 0x00000000000 Ending Address: 0x0003FFFFFFF Range Size: 1 GB Physical Device Handle: 0x1100 Memory Array Mapped Address Handle: 0x1300 Partition Row Position: 1 Handle 0x1401 DMI type 20, 19 bytes. Memory Device Mapped Address Starting Address: 0x00000000000 Ending Address: 0x0003FFFFFFF Range Size: 1 GB Physical Device Handle: 0x1101 Memory Array Mapped Address Handle: 0x1300 Partition Row Position: 2 Handle 0x1402 DMI type 126, 19 bytes. Inactive Handle 0x1403 DMI type 126, 19 bytes. Inactive Handle 0x1404 DMI type 126, 19 bytes. Inactive Handle 0x1405 DMI type 126, 19 bytes. Inactive Handle 0x1406 DMI type 126, 19 bytes. Inactive Handle 0x1407 DMI type 126, 19 bytes. Inactive Handle 0x1408 DMI type 126, 19 bytes. Inactive Handle 0x1409 DMI type 126, 19 bytes. Inactive Handle 0x140A DMI type 126, 19 bytes. Inactive Handle 0x140B DMI type 126, 19 bytes. Inactive Handle 0x140C DMI type 126, 19 bytes. Inactive Handle 0x140D DMI type 126, 19 bytes. Inactive Handle 0x1420 DMI type 126, 19 bytes. Inactive Handle 0x1421 DMI type 126, 19 bytes. Inactive Handle 0x1424 DMI type 126, 19 bytes. Inactive Handle 0x1425 DMI type 126, 19 bytes. Inactive Handle 0x1428 DMI type 126, 19 bytes. Inactive Handle 0x1429 DMI type 126, 19 bytes. Inactive Handle 0x1430 DMI type 126, 19 bytes. Inactive Handle 0x1431 DMI type 126, 19 bytes. Inactive Handle 0x1434 DMI type 126, 19 bytes. Inactive Handle 0x1435 DMI type 126, 19 bytes. Inactive Handle 0x1438 DMI type 126, 19 bytes. Inactive Handle 0x1439 DMI type 126, 19 bytes. Inactive Handle 0x2000 DMI type 32, 11 bytes. System Boot Information Status: No errors detected Handle 0x2600 DMI type 38, 18 bytes. IPMI Device Information Interface Type: KCS (Keyboard Control Style) Specification Version: 1.5 I2C Slave Address: 0x10 NV Storage Device: Not Present Base Address: 0x0000000000000CA8 (I/O) Register Spacing: 32-bit Boundaries Handle 0xD000 DMI type 208, 10 bytes. OEM-specific Type Header and Data: D0 0A 00 D0 01 05 FE 00 83 01 Handle 0xD100 DMI type 209, 12 bytes. OEM-specific Type Header and Data: D1 0C 00 D1 78 03 07 03 04 0F 80 05 Handle 0xD200 DMI type 210, 12 bytes. OEM-specific Type Header and Data: D2 0C 00 D2 F8 03 04 03 06 80 04 05 Handle 0xD400 DMI type 212, 167 bytes. OEM-specific Type Header and Data: D4 A7 00 D4 70 00 71 00 00 10 2D 2E 03 00 11 7F 80 04 00 11 7F 00 07 00 25 9F 00 08 00 25 9F 20 09 00 25 9F 40 0A 00 25 9F 60 0B 00 25 7F 00 0C 00 25 7F 80 0F 00 25 F8 00 11 00 25 F8 01 12 00 25 F8 02 2E 40 25 F8 03 2F 40 25 F8 04 00 00 25 F8 05 42 00 11 FE 01 43 00 11 FE 00 44 00 11 9F 20 45 00 11 9F 00 31 40 11 FB 00 32 40 11 FB 04 9D 00 11 FD 02 9E 00 11 FD 00 9F 00 26 FE 01 A0 00 26 FE 00 51 00 26 3F 00 52 00 26 3F 40 53 00 26 3F 80 54 00 26 3F C0 28 40 26 DF 20 29 40 26 DF 00 FF FF 00 00 00 Handle 0xD401 DMI type 212, 202 bytes. OEM-specific Type Header and Data: D4 CA 01 D4 70 00 71 00 03 40 59 6D 6B 00 78 7F 80 6C 00 78 7F 00 58 00 78 FA 05 59 00 78 FA 00 5C 00 78 BF 40 5D 00 78 BF 00 04 80 78 FD 02 01 A0 78 FD 00 08 40 51 FE 01 09 40 51 FE 00 0A 40 51 FD 02 0B 40 51 FD 00 19 00 55 E7 00 1A 00 55 E7 08 1B 00 55 E7 10 FF 00 55 9F 40 FE 00 55 9F 20 FD 00 55 9F 00 1E 00 55 FD 00 50 00 55 FD 02 8A 00 55 FE 01 8B 00 55 FE 00 BF 00 53 FE 00 C0 00 53 FE 01 33 40 53 E7 00 34 40 53 E7 08 35 40 53 E7 10 36 40 53 E7 18 1A 40 53 FD 02 1B 40 53 FD 00 1C 40 53 FB 04 1D 40 53 FB 00 6E 00 58 FC 01 2D 00 58 FC 02 2E 00 58 FC 00 22 40 58 EF 10 23 40 58 EF 00 FF FF 00 00 00 Handle 0xD402 DMI type 212, 47 bytes. OEM-specific Type Header and Data: D4 2F 02 D4 70 00 71 00 03 40 59 6D D8 00 55 7F 80 D9 00 55 7F 00 00 C0 5C 00 0A 03 C0 67 00 05 83 00 76 00 00 84 00 77 00 00 FF FF 00 00 00 Handle 0xD403 DMI type 212, 177 bytes. OEM-specific Type Header and Data: D4 B1 03 D4 72 00 73 00 00 40 5D 5E 28 01 4A FC 00 29 01 4A FC 01 2A 01 4A FC 02 02 40 4A F7 00 01 40 4A F7 08 D1 00 7E FE 00 D2 00 7E FE 01 2A 40 7E FB 00 2B 40 7E FB 04 D3 00 00 00 02 D4 00 06 00 02 00 90 2C 00 00 01 90 2D 00 00 17 01 4B FE 00 18 01 4B FE 01 19 01 4B FD 00 1A 01 4B FD 02 35 01 4C FC 00 37 01 4C FC 01 39 01 4C FC 02 3B 01 4C F3 04 3D 01 4C F3 08 DE 00 76 FE 01 26 40 42 FE 01 27 40 42 FE 00 37 40 42 FB 00 38 40 42 FB 04 00 00 47 FE 01 00 00 47 FE 00 A1 00 48 FC 02 A3 00 48 FC 01 A2 00 48 FC 00 FF FF 00 00 00 Handle 0xD800 DMI type 216, 9 bytes. OEM-specific Type Header and Data: D8 09 00 D8 01 02 01 00 00 Strings: ATI RADEON 7000 V6.11 Handle 0xDE00 DMI type 222, 15 bytes. OEM-specific Type Header and Data: DE 0F 00 DE 01 04 FF FF 00 00 00 00 00 00 00 Handle 0x7F00 DMI type 127, 4 bytes. End Of Table ���������������������������������������������������������������������������������������������������������������������������������������������UnixAgent-2.8/resources/dmidecode.rhel.2.1����������������������������������������������������������0000664�0000000�0000000�00000013425�13726633777�0020421�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������PNP BIOS present. PNP BIOS present. SYSID present. SMBIOS 2.3 present. DMI 2.3 present. 40 structures occupying 1146 bytes. DMI table at 0x000FAC20. Handle 0x0000 DMI type 0, 20 bytes. BIOS Information Block Vendor: IBM Version: -[JPE130AUS-1.30]- Release: 12/11/2002 BIOS base: 0xF0000 ROM size: 448K Capabilities: Flags: 0x000000007FFBDE90 Handle 0x0100 DMI type 1, 25 bytes. System Information Block Vendor: IBM Product: -[84803AX]- Version: IBM CORPORATION Serial Number: KBKGW40 Handle 0x0200 DMI type 2, 8 bytes. Board Information Block Vendor: IBM Product: -[M51G]- Version: -1 Serial Number: NA60B7Y0S3Q Handle 0x0300 DMI type 3, 17 bytes. Chassis Information Block Vendor: IBM Chassis Type: Mini Tower Lock present Version: N/A Serial Number: N/A Asset Tag: N/A Handle 0x0400 DMI type 4, 32 bytes. Processor Socket Designation: CPU1 Processor Type: Central Processor Processor Family: Processor Manufacturer: Intel Processor Version: Pentium 4 Handle 0x0500 DMI type 5, 20 bytes. Memory Controller Handle 0x0600 DMI type 6, 12 bytes. Memory Bank Socket: DIMM1 Banks: 0 Type: ECC DIMM SDRAM Installed Size: 256Mbyte Enabled Size: 256Mbyte Handle 0x0601 DMI type 6, 12 bytes. Memory Bank Socket: DIMM2 Type: UNKNOWN Installed Size: Not Installed Enabled Size: Not Installed Handle 0x0700 DMI type 7, 19 bytes. Cache Socket: CPU1 L1 socketed Internal Cache: write-back L1 Cache Size: 32K L1 Cache Maximum: 20K L1 Cache Type: Unknown Handle 0x0701 DMI type 7, 19 bytes. Cache Socket: CPU1 L2 socketed Internal Cache: write-back L2 Cache Size: 512K L2 Cache Maximum: 512K L2 Cache Type: Pipeline burst Handle 0x0800 DMI type 8, 9 bytes. Port Connector Internal Designator: Internal Connector Type: None External Designator: SERIAL1 External Connector Type: DB-9 pin male Port Type: Serial Port 16650A Compatible Handle 0x0801 DMI type 8, 9 bytes. Port Connector Internal Designator: Internal Connector Type: None External Designator: SERIAL2 External Connector Type: DB-9 pin male Port Type: Serial Port 16650A Compatible Handle 0x0802 DMI type 8, 9 bytes. Port Connector Internal Designator: Internal Connector Type: None External Designator: PRINTER External Connector Type: DB-25 pin female Port Type: Parallel Port ECP/EPP Handle 0x0803 DMI type 8, 9 bytes. Port Connector Internal Designator: Internal Connector Type: None External Designator: KEYBOARD External Connector Type: PS/2 Port Type: Keyboard Port Handle 0x0804 DMI type 8, 9 bytes. Port Connector Internal Designator: Internal Connector Type: None External Designator: MOUSE External Connector Type: PS/2 Port Type: Mouse Port Handle 0x0805 DMI type 8, 9 bytes. Port Connector Internal Designator: Internal Connector Type: None External Designator: USB1 External Connector Type: Access Bus (USB) Port Type: USB Handle 0x0806 DMI type 8, 9 bytes. Port Connector Internal Designator: Internal Connector Type: None External Designator: USB2 External Connector Type: Access Bus (USB) Port Type: USB Handle 0x0807 DMI type 8, 9 bytes. Port Connector Internal Designator: IDE1 Internal Connector Type: On Board IDE External Designator: External Connector Type: None Port Type: Other Handle 0x0808 DMI type 8, 9 bytes. Port Connector Internal Designator: IDE2 Internal Connector Type: On Board IDE External Designator: External Connector Type: None Port Type: Other Handle 0x0809 DMI type 8, 9 bytes. Port Connector Internal Designator: FDD Internal Connector Type: On Board Floppy External Designator: External Connector Type: None Port Type: Other Handle 0x080A DMI type 8, 9 bytes. Port Connector Internal Designator: SCSI1 Internal Connector Type: SSA SCSI External Designator: External Connector Type: None Port Type: SCSI II Handle 0x0900 DMI type 9, 12 bytes. Card Slot Slot: AGP Type: Slot Features: 5v Handle 0x0901 DMI type 9, 12 bytes. Card Slot Slot: PCI1 Type: 32bit PCI Status: Available. Slot Features: 5v Handle 0x0902 DMI type 9, 13 bytes. Card Slot Slot: PCI2 Type: 32bit PCI Status: In use. Slot Features: 5v Handle 0x0903 DMI type 9, 13 bytes. Card Slot Slot: PCI3 Type: 32bit PCI Status: Available. Slot Features: 5v Handle 0x0904 DMI type 9, 13 bytes. Card Slot Slot: PCI4 Type: 32bit PCI Status: Available. Slot Features: 5v Handle 0x0905 DMI type 9, 13 bytes. Card Slot Slot: PCI5 Type: 32bit PCI Status: Available. Slot Features: 5v Handle 0x0A00 DMI type 10, 14 bytes. On Board Devices Information Description: ATI RAGE XL : Enabled Type: Description: Adaptec 7892 SCSI : Enabled Type: Description: Broadcom 5702 : Enabled Type: Description: AC 97 : Enabled Type: Description: IBM Automatic Server Restart - Machine Type 8480 : Enabled Type: Handle 0x0D00 DMI type 13, 22 bytes. BIOS Language Information Handle 0x0F00 DMI type 15, 39 bytes. Event Log Log Area: 511 bytes. Log Header At: 0. Log Data At: 16. Log Type: 3. Log Valid: Yes. Handle 0x1000 DMI type 16, 15 bytes. Physical Memory Array Handle 0x1100 DMI type 17, 23 bytes. Memory Device Handle 0x1101 DMI type 17, 23 bytes. Memory Device Handle 0x1300 DMI type 19, 15 bytes. Memory Array Mapped Address Handle 0x1400 DMI type 20, 19 bytes. Memory Device Mapped Address Handle 0x1401 DMI type 20, 19 bytes. Memory Device Mapped Address Handle 0x2000 DMI type 32, 12 bytes. System Boot Information Handle 0x2200 DMI type 34, 11 bytes. 01 06 5a 00 00 00 05 ..Z.... Handle 0x8900 DMI type 137, 10 bytes. 01 02 03 04 05 06 ...... Handle 0x7F00 DMI type 127, 4 bytes. End-of-Table �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������UnixAgent-2.8/resources/dmidecode.rhel.3.4����������������������������������������������������������0000664�0000000�0000000�00000030001�13726633777�0020412�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# dmidecode 2.2 SMBIOS 2.33 present. 59 structures occupying 2374 bytes. Table at 0x7FF77000. Handle 0x0000 DMI type 0, 20 bytes. BIOS Information Vendor: IBM Version: IBM BIOS Version 1.57-[PME157AUS-1.57]- Release Date: 08/25/2005 Address: 0xE03F0 Runtime Size: 130064 bytes ROM Size: 1024 kB Characteristics: PCI is supported PNP is supported BIOS is upgradeable BIOS shadowing is allowed ESCD support is available Boot from CD is supported Selectable boot is supported BIOS ROM is socketed Print screen service is supported (int 5h) Serial services are supported (int 14h) ACPI is supported USB legacy is supported BIOS boot specification is supported Handle 0x0001 DMI type 1, 25 bytes. System Information Manufacturer: IBM Product Name: IBM eServer x226-[8488PCR]- Version: Not Applicable Serial Number: KDXPC16 UUID: A8346631-8E88-3AE3-898C-F3AC9F61C316 Wake-up Type: Power Switch Handle 0x0002 DMI type 2, 8 bytes. Base Board Information Manufacturer: IBM Product Name: MSI-9151 Boards Version: Not Applicable Serial Number: #A123456789 Handle 0x0003 DMI type 3, 17 bytes. Chassis Information Manufacturer: IBM Type: Tower Lock: Not Present Version: N/A Serial Number: N/A Asset Tag: 12345678901234567890123456789012 Boot-up State: Safe Power Supply State: Safe Thermal State: Safe Security Status: None OEM Information: 0x00001234 Handle 0x0004 DMI type 4, 35 bytes. Processor Information Socket Designation: CPU#1 Type: Central Processor Family: Xeon MP Manufacturer: Intel Corporation ID: 41 0F 00 00 FF FB EB BF Signature: Type 0, Family F, Model 4, Stepping 1 Flags: FPU (Floating-point unit on-chip) VME (Virtual mode extension) DE (Debugging extension) PSE (Page size extension) TSC (Time stamp counter) MSR (Model specific registers) PAE (Physical address extension) MCE (Machine check exception) CX8 (CMPXCHG8 instruction supported) APIC (On-chip APIC hardware supported) SEP (Fast system call) MTRR (Memory type range registers) PGE (Page global enable) MCA (Machine check architecture) CMOV (Conditional move instruction supported) PAT (Page attribute table) PSE-36 (36-bit page size extension) CLFSH (CLFLUSH instruction supported) DS (Debug store) ACPI (ACPI supported) MMX (MMX technology supported) FXSR (Fast floating-point save and restore) SSE (Streaming SIMD extensions) SSE2 (Streaming SIMD extensions 2) SS (Self-snoop) HTT (Hyper-threading technology) TM (Thermal monitor supported) SBF (Signal break on FERR) Version: Intel(R) Xeon(TM) CPU 2.80GHz Voltage: 1.3 V External Clock: 200 MHz Max Speed: 3600 MHz Current Speed: 2800 MHz Status: Populated, Enabled Upgrade: ZIF Socket L1 Cache Handle: 0x0006 L2 Cache Handle: 0x0007 L3 Cache Handle: Not Provided Serial Number: Asset Tag: Part Number: Handle 0x0005 DMI type 4, 35 bytes. Processor Information Socket Designation: CPU#2 Type: Central Processor Family: Xeon MP Manufacturer: Intel Corporation ID: 41 0F 00 00 FF FB EB BF Signature: Type 0, Family F, Model 4, Stepping 1 Flags: FPU (Floating-point unit on-chip) VME (Virtual mode extension) DE (Debugging extension) PSE (Page size extension) TSC (Time stamp counter) MSR (Model specific registers) PAE (Physical address extension) MCE (Machine check exception) CX8 (CMPXCHG8 instruction supported) APIC (On-chip APIC hardware supported) SEP (Fast system call) MTRR (Memory type range registers) PGE (Page global enable) MCA (Machine check architecture) CMOV (Conditional move instruction supported) PAT (Page attribute table) PSE-36 (36-bit page size extension) CLFSH (CLFLUSH instruction supported) DS (Debug store) ACPI (ACPI supported) MMX (MMX technology supported) FXSR (Fast floating-point save and restore) SSE (Streaming SIMD extensions) SSE2 (Streaming SIMD extensions 2) SS (Self-snoop) HTT (Hyper-threading technology) TM (Thermal monitor supported) SBF (Signal break on FERR) Version: Intel(R) Xeon(TM) CPU 2.80GHz Voltage: 1.3 V External Clock: 200 MHz Max Speed: 3600 MHz Current Speed: 2800 MHz Status: Populated, Enabled Upgrade: ZIF Socket L1 Cache Handle: 0x0009 L2 Cache Handle: 0x000A L3 Cache Handle: Not Provided Serial Number: Asset Tag: Part Number: Handle 0x0006 DMI type 7, 19 bytes. Cache Information Socket Designation: L1 Cache for CPU#1 Configuration: Enabled, Not Socketed, Level 1 Operational Mode: Write Back Location: Internal Installed Size: 16 KB Maximum Size: 16 KB Supported SRAM Types: Burst Pipeline Burst Installed SRAM Type: Burst Pipeline Burst Speed: Unknown Error Correction Type: Single-bit ECC System Type: Data Associativity: 4-way Set-associative Handle 0x0007 DMI type 7, 19 bytes. Cache Information Socket Designation: L2 Cache for CPU#1 Configuration: Enabled, Not Socketed, Level 2 Operational Mode: Write Back Location: Internal Installed Size: 1024 KB Maximum Size: 2048 KB Supported SRAM Types: Burst Pipeline Burst Installed SRAM Type: Burst Speed: Unknown Error Correction Type: Single-bit ECC System Type: Unified Associativity: 4-way Set-associative Handle 0x0008 DMI type 126, 19 bytes. Inactive Handle 0x0009 DMI type 7, 19 bytes. Cache Information Socket Designation: L1 Cache for CPU#2 Configuration: Enabled, Not Socketed, Level 1 Operational Mode: Write Back Location: Internal Installed Size: 16 KB Maximum Size: 16 KB Supported SRAM Types: Burst Pipeline Burst Installed SRAM Type: Burst Pipeline Burst Speed: Unknown Error Correction Type: Single-bit ECC System Type: Data Associativity: 4-way Set-associative Handle 0x000A DMI type 7, 19 bytes. Cache Information Socket Designation: L2 Cache for CPU#2 Configuration: Enabled, Not Socketed, Level 2 Operational Mode: Write Back Location: Internal Installed Size: 1024 KB Maximum Size: 2048 KB Supported SRAM Types: Burst Pipeline Burst Installed SRAM Type: Burst Speed: Unknown Error Correction Type: Single-bit ECC System Type: Unified Associativity: 4-way Set-associative Handle 0x000B DMI type 126, 19 bytes. Inactive Handle 0x000C DMI type 8, 9 bytes. Port Connector Information Internal Reference Designator: J2A1 Internal Connector Type: 9 Pin Dual Inline (pin 10 cut) External Reference Designator: COM 1 External Connector Type: DB-9 male Port Type: Serial Port 16550A Compatible Handle 0x000D DMI type 8, 9 bytes. Port Connector Information Internal Reference Designator: J2A2 Internal Connector Type: 9 Pin Dual Inline (pin 10 cut) External Reference Designator: COM 2 External Connector Type: DB-9 male Port Type: Serial Port 16550A Compatible Handle 0x000E DMI type 8, 9 bytes. Port Connector Information Internal Reference Designator: J3A1 Internal Connector Type: 25 Pin Dual Inline (pin 26 cut) External Reference Designator: Parallel External Connector Type: DB-25 female Port Type: Parallel Port ECP/EPP Handle 0x000F DMI type 8, 9 bytes. Port Connector Information Internal Reference Designator: J1A1 Internal Connector Type: None External Reference Designator: Keyboard External Connector Type: Circular DIN-8 male Port Type: Keyboard Port Handle 0x0010 DMI type 8, 9 bytes. Port Connector Information Internal Reference Designator: J1A1 Internal Connector Type: None External Reference Designator: PS/2 Mouse External Connector Type: Circular DIN-8 male Port Type: Keyboard Port Handle 0x0011 DMI type 9, 13 bytes. System Slot Information Designation: PCIE Slot #1 Type: PCI Current Usage: Available Length: Other ID: 1 Characteristics: PME signal is supported Handle 0x0012 DMI type 9, 13 bytes. System Slot Information Designation: PCI/33 Slot #2 Type: 32-bit PCI Current Usage: Available Length: Short ID: 2 Characteristics: 5.0 V is provided 3.3 V is provided PME signal is supported Handle 0x0013 DMI type 9, 13 bytes. System Slot Information Designation: PCI/33 Slot #3 Type: 32-bit PCI Current Usage: Available Length: Short ID: 3 Characteristics: 5.0 V is provided 3.3 V is provided PME signal is supported Handle 0x0014 DMI type 9, 13 bytes. System Slot Information Designation: PCIX 133 Slot #4 Type: 64-bit PCI-X Current Usage: Available Length: Long ID: 4 Characteristics: 3.3 V is provided PME signal is supported Handle 0x0015 DMI type 9, 13 bytes. System Slot Information Designation: PCIX100(ZCR) Slot #5 Type: 64-bit PCI-X Current Usage: Available Length: Long ID: 5 Characteristics: 3.3 V is provided PME signal is supported Handle 0x0016 DMI type 9, 13 bytes. System Slot Information Designation: PCIX100 Slot #6 Type: 64-bit PCI-X Current Usage: Available Length: Long ID: 6 Characteristics: 3.3 V is provided PME signal is supported Handle 0x0017 DMI type 10, 6 bytes. On Board Device Information Type: Other Status: Enabled Description: IBM Automatic Server Restart - Machine Type 8648 Handle 0x0018 DMI type 10, 6 bytes. On Board Device Information Type: Video Status: Enabled Description: ATI Rage 7000 Handle 0x0019 DMI type 10, 6 bytes. On Board Device Information Type: SCSI Controller Status: Enabled Description: Adaptec AIC 7902 Handle 0x001A DMI type 10, 6 bytes. On Board Device Information Type: Ethernet Status: Enabled Description: BoardCom BCM5721 Handle 0x001D DMI type 11, 5 bytes. OEM Strings String 1: IBM Remote Supervisor Adapter -[GRET15AUS]- Handle 0x001E DMI type 12, 5 bytes. System Configuration Options Option 1: JCMOS1: 1-2 Keep CMOS Data(Default), 2-3 Clear CMOS Data (make sure the AC power cord(s) is(are) removed from the system) Handle 0x001F DMI type 12, 5 bytes. System Configuration Options Option 1: JCON1: 1-2 Normal(Default), 2-3 Configuration, No Jumper - BIOS Crisis Recovery Handle 0x0020 DMI type 13, 22 bytes. BIOS Language Information Installable Languages: 1 en|US|iso8859-1 Currently Installed Language: en|US|iso8859-1 Handle 0x0021 DMI type 15, 29 bytes. System Event Log Area Length: 320 bytes Header Start Offset: 0x0000 Header Length: 16 bytes Data Start Offset: 0x0010 Access Method: General-pupose non-volatile data functions Access Address: 0x0000 Status: Valid, Not Full Change Token: 0x00000013 Header Format: Type 1 Supported Log Type Descriptors: 3 Descriptor 1: POST error Data Format 1: POST results bitmap Descriptor 2: Single-bit ECC memory error Data Format 2: Multiple-event Descriptor 3: Multi-bit ECC memory error Data Format 3: Multiple-event Handle 0x0022 DMI type 16, 15 bytes. Physical Memory Array Location: System Board Or Motherboard Use: System Memory Error Correction Type: Single-bit ECC Maximum Capacity: 16 GB Error Information Handle: No Error Number Of Devices: 6 Handle 0x0023 DMI type 17, 27 bytes. Memory Device Array Handle: 0x0022 Error Information Handle: No Error Total Width: 72 bits Data Width: 64 bits Size: 512 MB Form Factor: DIMM Set: 1 Locator: DIMM 1 Bank Locator: BANK 1 Type: DDR Type Detail: Synchronous Speed: 400 MHz (2.5 ns) Manufacturer: Serial Number: 460360BB Asset Tag: 3342 Part Number: M3 93T6553BZ3-CCC Handle 0x0024 DMI type 17, 27 bytes. Memory Device Array Handle: 0x0022 Error Information Handle: No Error Total Width: 72 bits Data Width: 64 bits Size: 512 MB Form Factor: DIMM Set: 1 Locator: DIMM 2 Bank Locator: BANK 1 Type: DDR Type Detail: Synchronous Speed: 400 MHz (2.5 ns) Manufacturer: Serial Number: 460360E8 Asset Tag: 3342 Part Number: M3 93T6553BZ3-CCC Handle 0x0025 DMI type 17, 27 bytes. Memory Device Array Handle: 0x0022 Error Information Handle: No Error Total Width: 72 bits Data Width: 64 bits Size: 512 MB Form Factor: DIMM Set: 2 Locator: DIMM 3 Bank Locator: BANK 2 Type: DDR Type Detail: Synchronous Speed: 400 MHz (2.5 ns) Manufacturer: �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������UnixAgent-2.8/resources/dmidecode.rhel.4.3����������������������������������������������������������0000664�0000000�0000000�00000044015�13726633777�0020424�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# dmidecode 2.2 SMBIOS 2.2 present. 57 structures occupying 1719 bytes. Table at 0x000F0000. Handle 0x0000 DMI type 0, 19 bytes. BIOS Information Vendor: IBM Version: -[OQE115A]- Release Date: 03/14/2006 Address: 0xE0000 Runtime Size: 128 kB ROM Size: 1024 kB Characteristics: PCI is supported PNP is supported APM is supported BIOS is upgradeable BIOS shadowing is allowed Boot from CD is supported Selectable boot is supported BIOS ROM is socketed EDD is supported 5.25"/360 KB floppy services are supported (int 13h) 5.25"/1.2 MB floppy services are supported (int 13h) 3.5"/720 KB floppy services are supported (int 13h) 3.5"/2.88 MB floppy services are supported (int 13h) Print screen service is supported (int 5h) 8042 keyboard services are supported (int 9h) Serial services are supported (int 14h) Printer services are supported (int 17h) CGA/mono video services are supported (int 10h) ACPI is supported USB legacy is supported AGP is supported LS-120 boot is supported ATAPI Zip drive boot is supported Handle 0x0001 DMI type 1, 25 bytes. System Information Manufacturer: IBM Product Name: -[86494jg]- Version: 2.0 Serial Number: KDMAH1Y UUID: 0339D4C3-44C0-9D11-A20E-85CDC42DE79C Wake-up Type: Other Handle 0x0002 DMI type 2, 8 bytes. Base Board Information Manufacturer: IBM Product Name: MS-9121 Version: 2.0 Serial Number: 48Z1LX Handle 0x0003 DMI type 3, 13 bytes. Chassis Information Manufacturer: IBM Type: Tower Lock: Present Version: Serial Number: Asset Tag: Boot-up State: Unknown Power Supply State: Unknown Thermal State: Unknown Security Status: Unknown Handle 0x0004 DMI type 4, 32 bytes. Processor Information Socket Designation: CPU1 Type: Central Processor Family: Xeon Manufacturer: Intel ID: 29 0F 00 00 FF FB EB BF Signature: Type 0, Family F, Model 2, Stepping 9 Flags: FPU (Floating-point unit on-chip) VME (Virtual mode extension) DE (Debugging extension) PSE (Page size extension) TSC (Time stamp counter) MSR (Model specific registers) PAE (Physical address extension) MCE (Machine check exception) CX8 (CMPXCHG8 instruction supported) APIC (On-chip APIC hardware supported) SEP (Fast system call) MTRR (Memory type range registers) PGE (Page global enable) MCA (Machine check architecture) CMOV (Conditional move instruction supported) PAT (Page attribute table) PSE-36 (36-bit page size extension) CLFSH (CLFLUSH instruction supported) DS (Debug store) ACPI (ACPI supported) MMX (MMX technology supported) FXSR (Fast floating-point save and restore) SSE (Streaming SIMD extensions) SSE2 (Streaming SIMD extensions 2) SS (Self-snoop) HTT (Hyper-threading technology) TM (Thermal monitor supported) SBF (Signal break on FERR) Version: Intel Xeon(tm) Voltage: 1.4 V External Clock: 133 MHz Max Speed: 3200 MHz Current Speed: 2666 MHz Status: Populated, Enabled Upgrade: ZIF Socket L1 Cache Handle: 0x000B L2 Cache Handle: 0x000D L3 Cache Handle: 0x000F Handle 0x0005 DMI type 4, 32 bytes. Processor Information Socket Designation: CPU2 Type: Central Processor Family: Xeon Manufacturer: Intel ID: 29 0F 00 00 FF FB EB BF Signature: Type 0, Family F, Model 2, Stepping 9 Flags: FPU (Floating-point unit on-chip) VME (Virtual mode extension) DE (Debugging extension) PSE (Page size extension) TSC (Time stamp counter) MSR (Model specific registers) PAE (Physical address extension) MCE (Machine check exception) CX8 (CMPXCHG8 instruction supported) APIC (On-chip APIC hardware supported) SEP (Fast system call) MTRR (Memory type range registers) PGE (Page global enable) MCA (Machine check architecture) CMOV (Conditional move instruction supported) PAT (Page attribute table) PSE-36 (36-bit page size extension) CLFSH (CLFLUSH instruction supported) DS (Debug store) ACPI (ACPI supported) MMX (MMX technology supported) FXSR (Fast floating-point save and restore) SSE (Streaming SIMD extensions) SSE2 (Streaming SIMD extensions 2) SS (Self-snoop) HTT (Hyper-threading technology) TM (Thermal monitor supported) SBF (Signal break on FERR) Version: Intel Xeon(tm) Voltage: 1.4 V External Clock: 133 MHz Max Speed: 3200 MHz Current Speed: 2666 MHz Status: Populated, Enabled Upgrade: ZIF Socket L1 Cache Handle: 0x000C L2 Cache Handle: 0x000E L3 Cache Handle: 0x0010 Handle 0x0006 DMI type 5, 24 bytes. Memory Controller Information Error Detecting Method: 8-bit Parity Error Correcting Capabilities: Single-bit Error Correcting Double-bit Error Correcting Error Scrubbing Supported Interleave: One-way Interleave Current Interleave: One-way Interleave Maximum Memory Module Size: 2048 MB Maximum Total Memory Size: 8192 MB Supported Speeds: Other Supported Memory Types: Other ECC DIMM Memory Module Voltage: 3.3 V Associated Memory Slots: 4 0x0007 0x0008 0x0009 0x000A Enabled Error Correcting Capabilities: Single-bit Error Correcting Double-bit Error Correcting Error Scrubbing Handle 0x0007 DMI type 6, 12 bytes. Memory Module Information Socket Designation: DIMM1 Bank Connections: 0 Current Speed: Unknown Type: Other DIMM Installed Size: 512 MB (Single-bank Connection) Enabled Size: 512 MB (Single-bank Connection) Error Status: OK Handle 0x0008 DMI type 6, 12 bytes. Memory Module Information Socket Designation: DIMM2 Bank Connections: 2 Current Speed: Unknown Type: Other DIMM Installed Size: 512 MB (Single-bank Connection) Enabled Size: 512 MB (Single-bank Connection) Error Status: OK Handle 0x0009 DMI type 6, 12 bytes. Memory Module Information Socket Designation: DIMM3 Bank Connections: 4 Current Speed: Unknown Type: Other DIMM Installed Size: 512 MB (Single-bank Connection) Enabled Size: 512 MB (Single-bank Connection) Error Status: OK Handle 0x000A DMI type 6, 12 bytes. Memory Module Information Socket Designation: DIMM4 Bank Connections: 6 Current Speed: Unknown Type: Other DIMM Installed Size: 512 MB (Single-bank Connection) Enabled Size: 512 MB (Single-bank Connection) Error Status: OK Handle 0x000B DMI type 7, 19 bytes. Cache Information Socket Designation: Level 1 Cache Configuration: Enabled, Not Socketed, Level 1 Operational Mode: Write Back Location: Internal Installed Size: 20 KB Maximum Size: 20 KB Supported SRAM Types: Synchronous Installed SRAM Type: Synchronous Speed: Unknown Error Correction Type: Unknown System Type: Unknown Associativity: Unknown Handle 0x000C DMI type 7, 19 bytes. Cache Information Socket Designation: Level 1 Cache Configuration: Enabled, Not Socketed, Level 1 Operational Mode: Write Back Location: Internal Installed Size: 20 KB Maximum Size: 20 KB Supported SRAM Types: Synchronous Installed SRAM Type: Synchronous Speed: Unknown Error Correction Type: Unknown System Type: Unknown Associativity: Unknown Handle 0x000D DMI type 7, 19 bytes. Cache Information Socket Designation: Level 2 Cache Configuration: Enabled, Not Socketed, Level 2 Operational Mode: Write Back Location: Internal Installed Size: 512 KB Maximum Size: 512 KB Supported SRAM Types: Synchronous Installed SRAM Type: Synchronous Speed: Unknown Error Correction Type: Unknown System Type: Unknown Associativity: Unknown Handle 0x000E DMI type 7, 19 bytes. Cache Information Socket Designation: Level 2 Cache Configuration: Enabled, Not Socketed, Level 2 Operational Mode: Write Back Location: Internal Installed Size: 512 KB Maximum Size: 512 KB Supported SRAM Types: Synchronous Installed SRAM Type: Synchronous Speed: Unknown Error Correction Type: Unknown System Type: Unknown Associativity: Unknown Handle 0x000F DMI type 7, 19 bytes. Cache Information Socket Designation: Tertiary (Level 3) Cache Configuration: Disabled, Not Socketed, Level 3 Operational Mode: Write Back Location: Internal Installed Size: 0 KB Maximum Size: 0 KB Supported SRAM Types: Synchronous Installed SRAM Type: Synchronous Speed: Unknown Error Correction Type: Unknown System Type: Unknown Associativity: Unknown Handle 0x0010 DMI type 7, 19 bytes. Cache Information Socket Designation: Tertiary (Level 3) Cache Configuration: Disabled, Not Socketed, Level 3 Operational Mode: Write Back Location: Internal Installed Size: 0 KB Maximum Size: 0 KB Supported SRAM Types: Synchronous Installed SRAM Type: Synchronous Speed: Unknown Error Correction Type: Unknown System Type: Unknown Associativity: Unknown Handle 0x0011 DMI type 8, 9 bytes. Port Connector Information Internal Reference Designator: IDE1 Internal Connector Type: On Board IDE External Reference Designator: Not Specified External Connector Type: None Port Type: Other Handle 0x0012 DMI type 8, 9 bytes. Port Connector Information Internal Reference Designator: IDE2 Internal Connector Type: On Board IDE External Reference Designator: Not Specified External Connector Type: None Port Type: Other Handle 0x0013 DMI type 8, 9 bytes. Port Connector Information Internal Reference Designator: FDD Internal Connector Type: On Board Floppy External Reference Designator: Not Specified External Connector Type: None Port Type: 8251 FIFO Compatible Handle 0x0014 DMI type 8, 9 bytes. Port Connector Information Internal Reference Designator: COM1 Internal Connector Type: 9 Pin Dual Inline (pin 10 cut) External Reference Designator: External Connector Type: DB-9 male Port Type: Serial Port 16450 Compatible Handle 0x0015 DMI type 8, 9 bytes. Port Connector Information Internal Reference Designator: COM2 Internal Connector Type: 9 Pin Dual Inline (pin 10 cut) External Reference Designator: External Connector Type: DB-9 male Port Type: Serial Port 16450 Compatible Handle 0x0016 DMI type 8, 9 bytes. Port Connector Information Internal Reference Designator: LPT1 Internal Connector Type: DB-25 female External Reference Designator: External Connector Type: DB-25 female Port Type: Parallel Port ECP/EPP Handle 0x0017 DMI type 8, 9 bytes. Port Connector Information Internal Reference Designator: Keyboard Internal Connector Type: PS/2 External Reference Designator: External Connector Type: PS/2 Port Type: Keyboard Port Handle 0x0018 DMI type 8, 9 bytes. Port Connector Information Internal Reference Designator: PS/2 Mouse Internal Connector Type: PS/2 External Reference Designator: External Connector Type: PS/2 Port Type: Mouse Port Handle 0x0019 DMI type 8, 9 bytes. Port Connector Information Internal Reference Designator: Not Specified Internal Connector Type: None External Reference Designator: JUSB1 External Connector Type: Other Port Type: USB Handle 0x001A DMI type 8, 9 bytes. Port Connector Information Internal Reference Designator: Not Specified Internal Connector Type: None External Reference Designator: JUSB2 External Connector Type: Other Port Type: USB Handle 0x001B DMI type 8, 9 bytes. Port Connector Information Internal Reference Designator: Not Specified Internal Connector Type: None External Reference Designator: AUD1 External Connector Type: None Port Type: Audio Port Handle 0x001C DMI type 8, 9 bytes. Port Connector Information Internal Reference Designator: Not Specified Internal Connector Type: None External Reference Designator: JLAN1 External Connector Type: RJ-45 Port Type: Network Port Handle 0x001D DMI type 8, 9 bytes. Port Connector Information Internal Reference Designator: Not Specified Internal Connector Type: None External Reference Designator: SCSI1 External Connector Type: None Port Type: SCSI Wide Handle 0x001E DMI type 8, 9 bytes. Port Connector Information Internal Reference Designator: Not Specified Internal Connector Type: None External Reference Designator: SCSI2 External Connector Type: None Port Type: SCSI Wide Handle 0x001F DMI type 9, 13 bytes. System Slot Information Designation: PCI1 Type: 32-bit PCI Current Usage: Available Length: Other ID: 1 Characteristics: 3.3 V is provided PME signal is supported Handle 0x0020 DMI type 9, 13 bytes. System Slot Information Designation: PCI6 Type: 32-bit PCI Current Usage: In Use Length: Other ID: 2 Characteristics: 3.3 V is provided PME signal is supported Handle 0x0021 DMI type 10, 14 bytes. On Board Device Information Type: Other Status: Enabled Description: IBM Automatic Server Restart - Machine Type 8480 On Board Device Information Type: SCSI Controller Status: Enabled Description: LSI Logic 1030 Ultra320 SCSI Adapter - SCSI1 On Board Device Information Type: SCSI Controller Status: Enabled Description: LSI Logic 1030 Ultra320 SCSI Adapter - SCSI2 On Board Device Information Type: Ethernet Status: Enabled Description: Broadcom BCM5703 NetXtreme Gigabit Ethernet - JLAN1 On Board Device Information Type: Sound Status: Enabled Description: SoundMax Integrated Digital Audio - AUD1 Handle 0x0022 DMI type 9, 13 bytes. System Slot Information Designation: AGP Type: 32-bit AGP Current Usage: Available Length: Long ID: 8 Characteristics: 5.0 V is provided Handle 0x0023 DMI type 9, 13 bytes. System Slot Information Designation: PCI2 Type: 64-bit PCI-X Current Usage: Available Length: Long ID: 2 Characteristics: 3.3 V is provided PME signal is supported Handle 0x0024 DMI type 9, 13 bytes. System Slot Information Designation: PCI3 Type: 64-bit PCI-X Current Usage: Available Length: Long ID: 3 Characteristics: 3.3 V is provided PME signal is supported Handle 0x0025 DMI type 9, 13 bytes. System Slot Information Designation: PCI4 Type: 64-bit PCI-X Current Usage: In Use Length: Long ID: 1 Characteristics: 3.3 V is provided PME signal is supported Handle 0x0026 DMI type 9, 13 bytes. System Slot Information Designation: PCI5 Type: 64-bit PCI-X Current Usage: Available Length: Long ID: 2 Characteristics: 3.3 V is provided PME signal is supported Handle 0x0027 DMI type 13, 22 bytes. BIOS Language Information Installable Languages: 3 n|US|iso8859-1 n|US|iso8859-1 r|CA|iso8859-1 Currently Installed Language: n|US|iso8859-1 Handle 0x0028 DMI type 16, 15 bytes. Physical Memory Array Location: System Board Or Motherboard Use: System Memory Error Correction Type: Multi-bit ECC Maximum Capacity: 8 GB Error Information Handle: No Error Number Of Devices: 4 Handle 0x0029 DMI type 17, 21 bytes. Memory Device Array Handle: 0x0028 Error Information Handle: 0x002D Total Width: 257 bits Data Width: 256 bits Size: 512 MB Form Factor: DIMM Set: 1 Locator: DIMM1 Bank Locator: Bank0 Type: DDR Type Detail: None Handle 0x002A DMI type 17, 21 bytes. Memory Device Array Handle: 0x0028 Error Information Handle: 0x002E Total Width: 257 bits Data Width: 256 bits Size: 512 MB Form Factor: DIMM Set: 1 Locator: DIMM2 Bank Locator: Bank1 Type: DDR Type Detail: None Handle 0x002B DMI type 17, 21 bytes. Memory Device Array Handle: 0x0028 Error Information Handle: 0x002F Total Width: 257 bits Data Width: 256 bits Size: 512 MB Form Factor: DIMM Set: 2 Locator: DIMM3 Bank Locator: Bank2 Type: DDR Type Detail: None Handle 0x002C DMI type 17, 21 bytes. Memory Device Array Handle: 0x0028 Error Information Handle: 0x0030 Total Width: 257 bits Data Width: 256 bits Size: 512 MB Form Factor: DIMM Set: 2 Locator: DIMM4 Bank Locator: Bank3 Type: DDR Type Detail: None Handle 0x002D DMI type 18, 23 bytes. 32-bit Memory Error Information Type: Other Granularity: Other Operation: Other Vendor Syndrome: Unknown Memory Array Address: Unknown Device Address: Unknown Resolution: Unknown Handle 0x002E DMI type 18, 23 bytes. 32-bit Memory Error Information Type: Other Granularity: Other Operation: Other Vendor Syndrome: Unknown Memory Array Address: Unknown Device Address: Unknown Resolution: Unknown Handle 0x002F DMI type 18, 23 bytes. 32-bit Memory Error Information Type: Other Granularity: Other Operation: Other Vendor Syndrome: Unknown Memory Array Address: Unknown Device Address: Unknown Resolution: Unknown Handle 0x0030 DMI type 18, 23 bytes. 32-bit Memory Error Information Type: Other Granularity: Other Operation: Other Vendor Syndrome: Unknown Memory Array Address: Unknown Device Address: Unknown Resolution: Unknown Handle 0x0031 DMI type 19, 15 bytes. Memory Array Mapped Address Starting Address: 0x00000000000 Ending Address: 0x0007FFFFFFF Range Size: 2 GB Physical Array Handle: 0x0028 Partition Width: 0 Handle 0x0032 DMI type 20, 19 bytes. Memory Device Mapped Address Starting Address: 0x00000000000 Ending Address: 0x0001FFFFFFF Range Size: 512 MB Physical Device Handle: 0x0029 Memory Array Mapped Address Handle: 0x0031 Partition Row Position: 1 Handle 0x0033 DMI type 20, 19 bytes. Memory Device Mapped Address Starting Address: 0x00020000000 Ending Address: 0x0003FFFFFFF Range Size: 512 MB Physical Device Handle: 0x002A Memory Array Mapped Address Handle: 0x0031 Partition Row Position: 1 Handle 0x0034 DMI type 20, 19 bytes. Memory Device Mapped Address Starting Address: 0x00040000000 Ending Address: 0x0005FFFFFFF Range Size: 512 MB Physical Device Handle: 0x002B Memory Array Mapped Address Handle: 0x0031 Partition Row Position: 1 Handle 0x0035 DMI type 20, 19 bytes. Memory Device Mapped Address Starting Address: 0x00060000000 Ending Address: 0x0007FFFFFFF Range Size: 512 MB Physical Device Handle: 0x002C Memory Array Mapped Address Handle: 0x0031 Partition Row Position: 1 Handle 0x0036 DMI type 32, 11 bytes. System Boot Information Status: No errors detected Handle 0x0037 DMI type 129, 8 bytes. OEM-specific Type Header And Data: 81 08 37 00 01 01 02 01 Strings: Alert Standard Format IBM 0053 Handle 0x0038 DMI type 127, 4 bytes. End Of Table �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������UnixAgent-2.8/resources/dmidecode.rhel.4.6����������������������������������������������������������0000664�0000000�0000000�00000045616�13726633777�0020437�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# dmidecode 2.2 SMBIOS 2.4 present. 74 structures occupying 2059 bytes. Table at 0x000EE000. Handle 0x0000 DMI type 0, 24 bytes. BIOS Information Vendor: HP Version: D21 Release Date: 01/24/2008 Address: 0xF0000 Runtime Size: 64 kB ROM Size: 4096 kB Characteristics: PCI is supported PNP is supported BIOS is upgradeable BIOS shadowing is allowed ESCD support is available Boot from CD is supported Selectable boot is supported EDD is supported 5.25"/360 KB floppy services are supported (int 13h) 5.25"/1.2 MB floppy services are supported (int 13h) 3.5"/720 KB floppy services are supported (int 13h) Print screen service is supported (int 5h) 8042 keyboard services are supported (int 9h) Serial services are supported (int 14h) Printer services are supported (int 17h) CGA/mono video services are supported (int 10h) ACPI is supported USB legacy is supported BIOS boot specification is supported Function key-initiated network boot is supported Handle 0x0100 DMI type 1, 27 bytes. System Information Manufacturer: HP Product Name: ProLiant ML350 G5 Version: Not Specified Serial Number: GB8814HE7S UUID: 34313236-3435-4742-3838-313448453753 Wake-up Type: Power Switch Handle 0x0300 DMI type 3, 17 bytes. Chassis Information Manufacturer: HP Type: Tower Lock: Not Present Version: Not Specified Serial Number: GB8814HE7S Asset Tag: Boot-up State: Unknown Power Supply State: Unknown Thermal State: Unknown Security Status: Unknown OEM Information: 0x00000000 Handle 0x0400 DMI type 4, 40 bytes. Processor Information Socket Designation: Proc 1 Type: Central Processor Family: Xeon Manufacturer: Intel ID: 76 06 01 00 FF FB EB BF Signature: Type 0, Family 6, Model 17, Stepping 6 Flags: FPU (Floating-point unit on-chip) VME (Virtual mode extension) DE (Debugging extension) PSE (Page size extension) TSC (Time stamp counter) MSR (Model specific registers) PAE (Physical address extension) MCE (Machine check exception) CX8 (CMPXCHG8 instruction supported) APIC (On-chip APIC hardware supported) SEP (Fast system call) MTRR (Memory type range registers) PGE (Page global enable) MCA (Machine check architecture) CMOV (Conditional move instruction supported) PAT (Page attribute table) PSE-36 (36-bit page size extension) CLFSH (CLFLUSH instruction supported) DS (Debug store) ACPI (ACPI supported) MMX (MMX technology supported) FXSR (Fast floating-point save and restore) SSE (Streaming SIMD extensions) SSE2 (Streaming SIMD extensions 2) SS (Self-snoop) HTT (Hyper-threading technology) TM (Thermal monitor supported) SBF (Signal break on FERR) Version: Not Specified Voltage: 1.4 V External Clock: 1333 MHz Max Speed: 4800 MHz Current Speed: 2333 MHz Status: Populated, Enabled Upgrade: ZIF Socket L1 Cache Handle: 0x0710 L2 Cache Handle: 0x0720 L3 Cache Handle: 0x0730 Serial Number: Not Specified Asset Tag: Not Specified Part Number: Not Specified Handle 0x0406 DMI type 4, 40 bytes. Processor Information Socket Designation: Proc 2 Type: Central Processor Family: Xeon Manufacturer: Intel ID: 00 00 00 00 00 00 00 00 Signature: Type 0, Family 0, Model 0, Stepping 0 Flags: None Version: Not Specified Voltage: 1.4 V External Clock: 200 MHz Max Speed: 4800 MHz Current Speed: Unknown Status: Unpopulated Upgrade: ZIF Socket L1 Cache Handle: 0x0716 L2 Cache Handle: 0x0726 L3 Cache Handle: 0x0736 Serial Number: Not Specified Asset Tag: Not Specified Part Number: Not Specified Handle 0x0710 DMI type 7, 19 bytes. Cache Information Socket Designation: Processor 1 Internal L1 Cache Configuration: Enabled, Not Socketed, Level 1 Operational Mode: Write Back Location: Internal Installed Size: 128 KB Maximum Size: 128 KB Supported SRAM Types: Burst Installed SRAM Type: Burst Speed: Unknown Error Correction Type: Single-bit ECC System Type: Data Associativity: 8-way Set-associative Handle 0x0716 DMI type 7, 19 bytes. Cache Information Socket Designation: Processor 2 Internal L1 Cache Configuration: Disabled, Not Socketed, Level 1 Operational Mode: Unknown Location: Internal Installed Size: 0 KB Maximum Size: 128 KB Supported SRAM Types: Burst Installed SRAM Type: Burst Speed: Unknown Error Correction Type: Single-bit ECC System Type: Data Associativity: 8-way Set-associative Handle 0x0720 DMI type 7, 19 bytes. Cache Information Socket Designation: Processor 1 Internal L2 Cache Configuration: Enabled, Not Socketed, Level 2 Operational Mode: Write Back Location: Internal Installed Size: 12288 KB Maximum Size: 16384 KB Supported SRAM Types: Burst Installed SRAM Type: Burst Speed: Unknown Error Correction Type: Single-bit ECC System Type: Unknown Associativity: 8-way Set-associative Handle 0x0726 DMI type 7, 19 bytes. Cache Information Socket Designation: Processor 2 Internal L2 Cache Configuration: Disabled, Not Socketed, Level 2 Operational Mode: Unknown Location: Internal Installed Size: 0 KB Maximum Size: 16384 KB Supported SRAM Types: Burst Installed SRAM Type: Burst Speed: Unknown Error Correction Type: Single-bit ECC System Type: Unknown Associativity: 8-way Set-associative Handle 0x0730 DMI type 7, 19 bytes. Cache Information Socket Designation: Processor 1 Internal L3 Cache Configuration: Disabled, Not Socketed, Level 3 Operational Mode: Unknown Location: Internal Installed Size: 0 KB Maximum Size: 8192 KB Supported SRAM Types: Burst Installed SRAM Type: Burst Speed: Unknown Error Correction Type: Single-bit ECC System Type: Unknown Associativity: Other Handle 0x0736 DMI type 7, 19 bytes. Cache Information Socket Designation: Processor 2 Internal L3 Cache Configuration: Disabled, Not Socketed, Level 3 Operational Mode: Unknown Location: Internal Installed Size: 0 KB Maximum Size: 8192 KB Supported SRAM Types: Burst Installed SRAM Type: Burst Speed: Unknown Error Correction Type: Single-bit ECC System Type: Unknown Associativity: Other Handle 0x0801 DMI type 8, 9 bytes. Port Connector Information Internal Reference Designator: J16 Internal Connector Type: Access Bus (USB) External Reference Designator: USB Port 1 External Connector Type: Access Bus (USB) Port Type: USB Handle 0x0802 DMI type 8, 9 bytes. Port Connector Information Internal Reference Designator: J19 Internal Connector Type: Access Bus (USB) External Reference Designator: USB Port 2 External Connector Type: Access Bus (USB) Port Type: USB Handle 0x0803 DMI type 8, 9 bytes. Port Connector Information Internal Reference Designator: J69 Internal Connector Type: Access Bus (USB) External Reference Designator: USB Port 3 External Connector Type: Access Bus (USB) Port Type: USB Handle 0x0804 DMI type 8, 9 bytes. Port Connector Information Internal Reference Designator: J69 Internal Connector Type: Access Bus (USB) External Reference Designator: USB Port 4 External Connector Type: Access Bus (USB) Port Type: USB Handle 0x0805 DMI type 8, 9 bytes. Port Connector Information Internal Reference Designator: J02 Internal Connector Type: Access Bus (USB) External Reference Designator: USB Port 5 External Connector Type: Access Bus (USB) Port Type: USB Handle 0x0806 DMI type 8, 9 bytes. Port Connector Information Internal Reference Designator: J03 Internal Connector Type: Access Bus (USB) External Reference Designator: USB Port 6 External Connector Type: Access Bus (USB) Port Type: USB Handle 0x0901 DMI type 9, 13 bytes. System Slot Information Designation: PCI Slot 1 Type: 64-bit PCI-X Current Usage: Available Length: Long ID: 1 Characteristics: 3.3 V is provided PME signal is supported Handle 0x0902 DMI type 9, 13 bytes. System Slot Information Designation: PCI Slot 2 Type: 64-bit PCI-X Current Usage: Available Length: Long ID: 2 Characteristics: 3.3 V is provided PME signal is supported Handle 0x0903 DMI type 9, 13 bytes. System Slot Information Designation: PCI Slot 3 Type: 64-bit PCI-X Current Usage: Available Length: Long ID: 3 Characteristics: 3.3 V is provided PME signal is supported Handle 0x0904 DMI type 9, 13 bytes. System Slot Information Designation: PCI-E Slot 4 Type: <OUT OF SPEC><OUT OF SPEC> Current Usage: Available Length: Long Characteristics: 3.3 V is provided PME signal is supported Handle 0x0905 DMI type 9, 13 bytes. System Slot Information Designation: PCI-E Slot 5 Type: <OUT OF SPEC><OUT OF SPEC> Current Usage: Available Length: Long Characteristics: 3.3 V is provided PME signal is supported Handle 0x0906 DMI type 9, 13 bytes. System Slot Information Designation: PCI-E Slot 6 Type: <OUT OF SPEC><OUT OF SPEC> Current Usage: Available Length: Long Characteristics: 3.3 V is provided PME signal is supported Handle 0x0B00 DMI type 11, 5 bytes. OEM Strings String 1: Product ID: 412645-B21 Handle 0x1000 DMI type 16, 15 bytes. Physical Memory Array Location: System Board Or Motherboard Use: System Memory Error Correction Type: Single-bit ECC Maximum Capacity: 32 GB Error Information Handle: Not Provided Number Of Devices: 8 Handle 0x1100 DMI type 17, 23 bytes. Memory Device Array Handle: 0x1000 Error Information Handle: Not Provided Total Width: 72 bits Data Width: 64 bits Size: 512 MB Form Factor: <OUT OF SPEC> Set: 1 Locator: DIMM 1A Bank Locator: Not Specified Type: <OUT OF SPEC> Type Detail: Synchronous Speed: 667 MHz (1.5 ns) Handle 0x1101 DMI type 17, 23 bytes. Memory Device Array Handle: 0x1000 Error Information Handle: Not Provided Total Width: 72 bits Data Width: 64 bits Size: 1024 MB Form Factor: <OUT OF SPEC> Set: 2 Locator: DIMM 2B Bank Locator: Not Specified Type: <OUT OF SPEC> Type Detail: Synchronous Speed: 667 MHz (1.5 ns) Handle 0x1102 DMI type 17, 23 bytes. Memory Device Array Handle: 0x1000 Error Information Handle: Not Provided Total Width: 72 bits Data Width: 64 bits Size: 1024 MB Form Factor: <OUT OF SPEC> Set: 3 Locator: DIMM 3C Bank Locator: Not Specified Type: <OUT OF SPEC> Type Detail: Synchronous Speed: 667 MHz (1.5 ns) Handle 0x1103 DMI type 17, 23 bytes. Memory Device Array Handle: 0x1000 Error Information Handle: Not Provided Total Width: 72 bits Data Width: 64 bits Size: No Module Installed Form Factor: <OUT OF SPEC> Set: 4 Locator: DIMM 4D Bank Locator: Not Specified Type: <OUT OF SPEC> Type Detail: Synchronous Speed: Unknown Handle 0x1104 DMI type 17, 23 bytes. Memory Device Array Handle: 0x1000 Error Information Handle: Not Provided Total Width: 72 bits Data Width: 64 bits Size: 512 MB Form Factor: <OUT OF SPEC> Set: 1 Locator: DIMM 5A Bank Locator: Not Specified Type: <OUT OF SPEC> Type Detail: Synchronous Speed: 667 MHz (1.5 ns) Handle 0x1105 DMI type 17, 23 bytes. Memory Device Array Handle: 0x1000 Error Information Handle: Not Provided Total Width: 72 bits Data Width: 64 bits Size: 1024 MB Form Factor: <OUT OF SPEC> Set: 2 Locator: DIMM 6B Bank Locator: Not Specified Type: <OUT OF SPEC> Type Detail: Synchronous Speed: 667 MHz (1.5 ns) Handle 0x1106 DMI type 17, 23 bytes. Memory Device Array Handle: 0x1000 Error Information Handle: Not Provided Total Width: 72 bits Data Width: 64 bits Size: 1024 MB Form Factor: <OUT OF SPEC> Set: 3 Locator: DIMM 7C Bank Locator: Not Specified Type: <OUT OF SPEC> Type Detail: Synchronous Speed: 667 MHz (1.5 ns) Handle 0x1107 DMI type 17, 23 bytes. Memory Device Array Handle: 0x1000 Error Information Handle: Not Provided Total Width: 72 bits Data Width: 64 bits Size: No Module Installed Form Factor: <OUT OF SPEC> Set: 4 Locator: DIMM 8D Bank Locator: Not Specified Type: <OUT OF SPEC> Type Detail: Synchronous Speed: Unknown Handle 0x1300 DMI type 19, 15 bytes. Memory Array Mapped Address Starting Address: 0x00000000000 Ending Address: 0x0015FFFFFFF Range Size: 5632 MB Physical Array Handle: 0x1000 Partition Width: 0 Handle 0x1400 DMI type 20, 19 bytes. Memory Device Mapped Address Starting Address: 0x00000000000 Ending Address: 0x0015FFFFFFF Range Size: 5632 MB Physical Device Handle: 0x1100 Memory Array Mapped Address Handle: 0x1300 Partition Row Position: 1 Interleave Position: 1 Interleaved Data Depth: Unknown Handle 0x1401 DMI type 20, 19 bytes. Memory Device Mapped Address Starting Address: 0x00000000000 Ending Address: 0x0015FFFFFFF Range Size: 5632 MB Physical Device Handle: 0x1101 Memory Array Mapped Address Handle: 0x1300 Partition Row Position: 1 Interleave Position: 1 Interleaved Data Depth: Unknown Handle 0x1402 DMI type 20, 19 bytes. Memory Device Mapped Address Starting Address: 0x00000000000 Ending Address: 0x0015FFFFFFF Range Size: 5632 MB Physical Device Handle: 0x1102 Memory Array Mapped Address Handle: 0x1300 Partition Row Position: 1 Interleave Position: 1 Interleaved Data Depth: Unknown Handle 0x1403 DMI type 20, 19 bytes. Memory Device Mapped Address Starting Address: 0x00000000000 Ending Address: 0x000000003FF Range Size: 1 kB Physical Device Handle: 0x1103 Memory Array Mapped Address Handle: 0x1300 Partition Row Position: 1 Interleave Position: 1 Interleaved Data Depth: Unknown Handle 0x1404 DMI type 20, 19 bytes. Memory Device Mapped Address Starting Address: 0x00000000000 Ending Address: 0x0015FFFFFFF Range Size: 5632 MB Physical Device Handle: 0x1104 Memory Array Mapped Address Handle: 0x1300 Partition Row Position: 1 Interleave Position: 2 Interleaved Data Depth: Unknown Handle 0x1405 DMI type 20, 19 bytes. Memory Device Mapped Address Starting Address: 0x00000000000 Ending Address: 0x0015FFFFFFF Range Size: 5632 MB Physical Device Handle: 0x1105 Memory Array Mapped Address Handle: 0x1300 Partition Row Position: 1 Interleave Position: 2 Interleaved Data Depth: Unknown Handle 0x1406 DMI type 20, 19 bytes. Memory Device Mapped Address Starting Address: 0x00000000000 Ending Address: 0x0015FFFFFFF Range Size: 5632 MB Physical Device Handle: 0x1106 Memory Array Mapped Address Handle: 0x1300 Partition Row Position: 1 Interleave Position: 2 Interleaved Data Depth: Unknown Handle 0x1407 DMI type 20, 19 bytes. Memory Device Mapped Address Starting Address: 0x00000000000 Ending Address: 0x000000003FF Range Size: 1 kB Physical Device Handle: 0x1107 Memory Array Mapped Address Handle: 0x1300 Partition Row Position: 1 Interleave Position: 2 Interleaved Data Depth: Unknown Handle 0x2000 DMI type 32, 11 bytes. System Boot Information Status: No errors detected Handle 0x2600 DMI type 38, 18 bytes. IPMI Device Information Interface Type: KCS (Keyboard Control Style) Specification Version: 2.0 I2C Slave Address: 0x10 NV Storage Device: Not Present Base Address: 0x0000000000000CA2 (I/O) Register Spacing: Successive Byte Boundaries Handle 0xC100 DMI type 193, 7 bytes. OEM-specific Type Header And Data: C1 07 00 C1 01 01 02 Strings: 11/13/2007 11/13/2007 Handle 0xC200 DMI type 194, 5 bytes. OEM-specific Type Header And Data: C2 05 00 C2 01 Handle 0xC300 DMI type 195, 5 bytes. OEM-specific Type Header And Data: C3 05 00 C3 01 Strings: $0E110764 Handle 0xC400 DMI type 196, 5 bytes. OEM-specific Type Header And Data: C4 05 00 C4 00 Handle 0xC500 DMI type 197, 10 bytes. OEM-specific Type Header And Data: C5 0A 00 C5 00 04 00 01 FF 01 Handle 0xDF00 DMI type 223, 7 bytes. OEM-specific Type Header And Data: DF 07 00 DF 66 46 70 Handle 0xC506 DMI type 197, 10 bytes. OEM-specific Type Header And Data: C5 0A 06 C5 06 04 00 00 FF 02 Handle 0xD300 DMI type 211, 7 bytes. OEM-specific Type Header And Data: D3 07 00 D3 00 04 4E Handle 0xD306 DMI type 211, 7 bytes. OEM-specific Type Header And Data: D3 07 06 D3 06 04 00 Handle 0xC600 DMI type 198, 11 bytes. OEM-specific Type Header And Data: C6 0B 00 C6 17 00 00 01 3C 00 01 Handle 0xC700 DMI type 199, 112 bytes. OEM-specific Type Header And Data: C7 70 00 C7 0B 06 00 00 08 20 19 01 76 06 01 00 0B 06 00 00 08 20 19 01 76 06 01 00 04 04 00 00 07 20 08 06 74 06 01 00 04 04 00 00 07 20 08 06 74 06 01 00 B4 00 00 00 07 20 14 03 FB 06 00 00 B4 00 00 00 07 20 14 03 FB 06 00 00 67 00 00 00 07 20 26 03 F7 06 00 00 C9 00 00 00 07 20 26 03 F6 06 00 00 02 00 00 00 05 20 15 12 64 0F 00 00 Handle 0xCD00 DMI type 205, 22 bytes. OEM-specific Type Header And Data: CD 16 00 CD 01 01 46 41 54 78 00 00 E0 FF 00 00 00 00 00 00 0D 00 Handle 0xCA00 DMI type 202, 8 bytes. OEM-specific Type Header And Data: CA 08 00 CA 00 11 FF 01 Handle 0xCA01 DMI type 202, 8 bytes. OEM-specific Type Header And Data: CA 08 01 CA 01 11 FF 02 Handle 0xCA02 DMI type 202, 8 bytes. OEM-specific Type Header And Data: CA 08 02 CA 02 11 FF 03 Handle 0xCA03 DMI type 202, 8 bytes. OEM-specific Type Header And Data: CA 08 03 CA 03 11 FF 04 Handle 0xCA04 DMI type 202, 8 bytes. OEM-specific Type Header And Data: CA 08 04 CA 04 11 FF 05 Handle 0xCA05 DMI type 202, 8 bytes. OEM-specific Type Header And Data: CA 08 05 CA 05 11 FF 06 Handle 0xCA06 DMI type 202, 8 bytes. OEM-specific Type Header And Data: CA 08 06 CA 06 11 FF 07 Handle 0xCA07 DMI type 202, 8 bytes. OEM-specific Type Header And Data: CA 08 07 CA 07 11 FF 08 Handle 0xD100 DMI type 209, 12 bytes. OEM-specific Type Header And Data: D1 0C 00 D1 00 03 00 1F 29 62 C4 A4 Handle 0xD400 DMI type 212, 24 bytes. OEM-specific Type Header And Data: D4 18 00 D4 24 43 52 55 00 F8 F6 FF 00 00 00 00 00 40 00 00 00 00 00 00 Handle 0xD500 DMI type 213, 28 bytes. OEM-specific Type Header And Data: D5 1C 00 D5 00 00 36 00 00 00 BF 1F 00 00 46 00 00 00 00 00 00 00 00 00 00 00 00 00 Handle 0xD600 DMI type 214, 44 bytes. OEM-specific Type Header And Data: D6 2C 00 D6 31 31 00 02 0E 20 00 00 13 20 00 00 00 60 00 00 00 20 00 00 02 20 00 00 04 20 00 00 06 20 00 00 0C 20 00 00 08 20 00 00 Handle 0xD700 DMI type 215, 6 bytes. OEM-specific Type Header And Data: D7 06 00 D7 00 05 Handle 0xDB00 DMI type 219, 8 bytes. OEM-specific Type Header And Data: DB 08 00 DB FF 00 00 00 Handle 0xDC00 DMI type 218, 45 bytes. OEM-specific Type Header And Data: DA 2D 00 DC 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 Handle 0xDC01 DMI type 220, 45 bytes. OEM-specific Type Header And Data: DC 2D 01 DC 08 00 00 C5 00 FF 01 00 C5 01 FF 02 00 C5 02 FF 03 00 C5 03 FF 04 06 C5 02 FF 05 06 C5 03 FF 06 06 C5 00 FF 07 06 C5 01 FF Handle 0xDD00 DMI type 221, 12 bytes. OEM-specific Type Header And Data: DD 0C 00 DD 00 03 00 1F 29 62 C4 A5 Handle 0x7F00 DMI type 127, 4 bytes. End Of Table ������������������������������������������������������������������������������������������������������������������UnixAgent-2.8/resources/ipdiscover/�����������������������������������������������������������������0000775�0000000�0000000�00000000000�13726633777�0017473�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������UnixAgent-2.8/resources/ipdiscover/ipdiscover.c�����������������������������������������������������0000664�0000000�0000000�00000015474�13726633777�0022021�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* ############################################################################### ##OCSInventory Version NG Beta ##Copyleft Pascal DANEK 2006 ##Web : http://ocsinventory.sourceforge.net ## ##This code is open source and may be copied and modified as long as the source ##code is always made freely available. ##Please refer to the General Public Licence http://www.gnu.org/ or Licence.txt ################################################################################ */ #include "ipdiscover.h" /* We get IP address, netmask, index number and mac address of the adapter */ void get_iface_infos( packet *ppacket, int *index, char *iface, struct sockaddr_in *ipaddr, struct sockaddr_in *netmask){ int tmpsock; struct ifreq ifr; if( ( tmpsock = socket( AF_INET, SOCK_STREAM, 0 ) ) < 0 ){ perror("Socket creation problem"); exit(1); } /* Initialize */ memset( &ifr, 0x0, sizeof(struct ifreq)); /* We put into the ifreq struct the name of adapter */ strncpy(ifr.ifr_name, iface, IF_NAMESIZE-1); /* IP */ if(ioctl(tmpsock, SIOCGIFADDR, &ifr)< 0){ close(tmpsock); perror("Cannot get the ip address"); exit(1); } memcpy( &ipaddr->sin_addr, &( (struct sockaddr_in *) &ifr.ifr_addr )->sin_addr, 4 ); memcpy( ppacket->arphdr.ar_sip, &( (struct sockaddr_in *) &ifr.ifr_addr )->sin_addr, 4 ); /*******************/ /* SNM */ if(ioctl(tmpsock, SIOCGIFNETMASK, &ifr)< 0){ close(tmpsock); perror("Cannot get the net submask"); exit(1); } memcpy(&netmask->sin_addr, &((struct sockaddr_in *) &ifr.ifr_netmask)->sin_addr, 4); /*******************/ /* MAC */ if(ioctl(tmpsock, SIOCGIFHWADDR, &ifr)< 0){ close(tmpsock); perror("Cannot get the mac address"); exit(1); } memcpy( ppacket->ethhdr.h_source, (unsigned char *)&ifr.ifr_hwaddr.sa_data, ETH_ALEN ); memcpy( ppacket->arphdr.ar_sha, (unsigned char *)&ifr.ifr_hwaddr.sa_data, ETH_ALEN ); /*******************/ /* INDEX */ if(ioctl(tmpsock, SIOCGIFINDEX, &ifr)< 0){ close(tmpsock); perror("Cannot get the interface index"); exit(1); } *index = ifr.ifr_ifindex; /*******************/ close(tmpsock); } void data_init( struct sockaddr_in *ipaddr, struct sockaddr_in *netmask, packet **ppacket, struct sockaddr_ll *sll, int index ){ memset(ipaddr, 0x00, sizeof(struct sockaddr_in)); memset(netmask, 0x00, sizeof(struct sockaddr_in)); /* Arp structure */ *ppacket = malloc( sizeof( packet ) ); /* Tie to adapter */ sll->sll_family = AF_PACKET; sll->sll_protocol = htons(ETH_P_ARP); /* Building the packet */ memset( (*ppacket)->ethhdr.h_dest, 0xFF, 6 ); (*ppacket)->ethhdr.h_proto = htons(0x806); /* arp header */ (*ppacket)->arphdr.arp_hrdad = htons(ARPHRD_ETHER); (*ppacket)->arphdr.arp_prot = htons(ETH_P_IP); (*ppacket)->arphdr.arp_halen = ETH_ALEN; (*ppacket)->arphdr.arp_prlen = 4; (*ppacket)->arphdr.arp_opcode = htons(ARPOP_REQUEST); memset( (*ppacket)->arphdr.ar_tha, 0x0,ETH_ALEN ); } void print_xml(struct in_addr *ipsrc, packet *ppacket_r, struct hostent* name){ printf("<H><I>%s</I><M>%02x:%02x:%02x:%02x:%02x:%02x</M><N>%s</N></H>\n",inet_ntoa(*ipsrc), *ppacket_r->arphdr.ar_sha,ppacket_r->arphdr.ar_sha[1],ppacket_r->arphdr.ar_sha[2], ppacket_r->arphdr.ar_sha[3],ppacket_r->arphdr.ar_sha[4],ppacket_r->arphdr.ar_sha[5], name?name->h_name:"-"); } void create_socket(int *sd, struct sockaddr_ll *sll, int index){ /* Socket creation */ *sd = socket( PF_PACKET, SOCK_RAW, htons( ETH_P_ARP ) ); /* Put the iface index in sockaddr_ll structure to bind */ sll->sll_ifindex = index; if( *sd < 0 ){ perror("Socket creation problem"); exit(1); } if( fcntl( *sd, F_SETFL, O_NONBLOCK ) == -1 ){ perror("Cannot set socket mode to O_NONBLOCK"); exit(1); } /* Bind */ if( bind( *sd, (struct sockaddr*)sll, sizeof(*sll) ) == -1 ){ perror("Bind error"); exit(1); } } void validate_iface( struct sockaddr_in *ipaddr, struct sockaddr_in *netmask, packet *ppacket ){ char error_str[100]; if( ntohl(netmask->sin_addr.s_addr) < 0xFFFF0000){ snprintf(error_str, 100, "Invalid netmask -> too large (%s). Stop\n", inet_ntoa(netmask->sin_addr)); perror( error_str ); exit(1); } } void scan_init( unsigned long *unet, unsigned long *uhost, struct sockaddr_in *ipaddr, struct sockaddr_in *netmask, struct in_addr *ipsrc, packet **ppacket_r ){ /* Netid */ *unet = ntohl(ipaddr->sin_addr.s_addr) & ntohl(netmask->sin_addr.s_addr); /* Supposed number of hosts */ *uhost = ~( ntohl(netmask->sin_addr.s_addr) ); memset(ipsrc, 0, sizeof(struct in_addr)); *ppacket_r = malloc( sizeof( packet ) ); } int main(int argc, char ** argv){ /* Declarations */ /* full packet (tx and rx) */ packet *ppacket, *ppacket_r; /* Socket descriptor, nic index */ int sd = 0; int flag = 0; int index = 0; /* ip data */ unsigned long unet,uhost,ipdst,tip; /* The name of the interface is given in parameter to the binary */ char * iface; /* detected device's FQDN */ struct hostent* name; /* ip level sockaddr */ struct sockaddr_in ipaddr, netmask; /* Lowlevel sockaddr */ struct sockaddr_ll sll = {0x0}; /* source ip to put in packet */ struct in_addr ipsrc; int request_latency = REQUEST_LATENCY_DEFAULT; int p=0; /* Take at least one argument */ if(argc<2){ printf("IPDISCOVER binary ver. %d \nUsage : ipdiscover [iface name] [latency in ms]\n", VERSION); exit(0); }else{ iface = argv[1]; if( argc==3 ) request_latency = atoi( argv[2] ); } /* Initialize data */ data_init( &ipaddr, &netmask, &ppacket, &sll, index ); /* Reading nic parameters */ get_iface_infos( ppacket, &index, iface, &ipaddr, &netmask ); /* Check iface settings */ validate_iface( &ipaddr, &netmask, ppacket ); /* Creating socket */ create_socket( &sd, &sll, index ); /* Initialize packet target ip, potential hosts number... */ scan_init( &unet, &uhost, &ipaddr, &netmask, &ipsrc, &ppacket_r ); /* We are looking for all the possible connected host */ for(ipdst=1;ipdst<uhost;ipdst++){ tip = htonl(ipdst+unet); memcpy( ppacket->arphdr.ar_tip, &tip, 4 ); /* Sending the packet */ if( write( sd, ppacket, sizeof(packet) ) < 0 ){ perror("Transmission error"); exit(1); } flag = 0; usleep( request_latency * 1000 ); while( flag>=0 ){ memset( ppacket_r, 0, sizeof( packet ) ); flag = read( sd, ppacket_r, sizeof( packet ) ); if( flag>0 ) memcpy(&ipsrc, ppacket_r->arphdr.ar_sip, sizeof(struct in_addr)); if(ntohs(ppacket_r->arphdr.arp_opcode) == 2){ char * c; if(p==0) printf("<IPDISCOVER>\n"); p++; name = gethostbyaddr(&ipsrc, sizeof(struct in_addr), AF_INET); if(name){ while((c=strchr(name->h_name,'<')) || (c=strchr(name->h_name,'>'))){ strncpy(c,"x",sizeof(c)); } } usleep( NAME_RES_LATENCY ); print_xml( &ipsrc, ppacket_r, name ); } } } if(p) printf("</IPDISCOVER>\n"); /* That's all */ exit(0); } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������UnixAgent-2.8/resources/ipdiscover/ipdiscover.h�����������������������������������������������������0000664�0000000�0000000�00000003000�13726633777�0022004�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* ############################################################################### ##OCSInventory Version NG Beta ##Copyleft Pascal DANEK 2006 ##Web : http://ocsinventory.sourceforge.net ## ##This code is open source and may be copied and modified as long as the source ##code is always made freely available. ##Please refer to the General Public Licence http://www.gnu.org/ or Licence.txt ################################################################################ */ #include <sys/socket.h> #include <linux/if_ether.h> #include <stdio.h> #include <string.h> #include <stdlib.h> #include <netinet/in.h> #include <arpa/inet.h> #include <unistd.h> #include <linux/if_packet.h> #include <ctype.h> #include <sys/types.h> #include <sys/socket.h> #include <linux/sockios.h> #include <sys/ioctl.h> #include <net/if.h> #include <fcntl.h> #include <time.h> #include <netdb.h> #ifndef ARPHRD_ETHER #define ARPHRD_ETHER 1 #endif #ifndef ARPOP_REQUEST #define ARPOP_REQUEST 1 #endif #ifndef ARPOP_REPLY #define ARPOP_REPLY 2 #endif #define VERSION 5 #define NAME_RES_LATENCY 1000000 #define REQUEST_LATENCY_DEFAULT 100 /* ms */ /* Trame ARP */ struct arphdr{ unsigned short arp_hrdad; unsigned short arp_prot; unsigned char arp_halen; unsigned char arp_prlen; unsigned short arp_opcode; unsigned char ar_sha[ETH_ALEN]; unsigned char ar_sip[4]; unsigned char ar_tha[ETH_ALEN]; unsigned char ar_tip[4]; }; /* Ethernet header*/ struct Packet{ struct ethhdr ethhdr; struct arphdr arphdr; }; typedef struct Packet packet; UnixAgent-2.8/snmp/���������������������������������������������������������������������������������0000775�0000000�0000000�00000000000�13726633777�0014267�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������UnixAgent-2.8/snmp/mibs/����������������������������������������������������������������������������0000775�0000000�0000000�00000000000�13726633777�0015221�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������UnixAgent-2.8/snmp/mibs/local/����������������������������������������������������������������������0000775�0000000�0000000�00000000000�13726633777�0016313�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������UnixAgent-2.8/snmp/mibs/local/1588.xml��������������������������������������������������������������0000664�0000000�0000000�00000007707�13726633777�0017455�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<T_1588> <PARAMETERS> <PARSER>1</PARSER> <VERSION>1</VERSION> <NAME>Brocade</NAME> <EXECUTE> <RUN>Host_Resources_Mib</RUN> <RUN>If_Mib</RUN> <RUN>Entity_Mib</RUN> </EXECUTE> </PARAMETERS> <DATA> <COMMON> <TYPE> <SET>San</SET> </TYPE> </COMMON> <SWITCH_SAN> <SERIALNUMBER> <VALUE>1.3.6.1.4.1.1588.2.1.1.1.1.10.0</VALUE> </SERIALNUMBER> <MANUFACTURER> <SET>Brocade</SET> </MANUFACTURER> <SOFTVERSION> <VALUE>1.3.6.1.4.1.1588.2.1.1.1.1.6.0</VALUE> </SOFTVERSION> <DOMAIN_ID> <VALUE>1.3.6.1.4.1.1588.2.1.1.1.2.1.0</VALUE> </DOMAIN_ID> <PRINCIPAL_ID> <VALUE>1.3.6.1.4.1.1588.2.1.1.1.2.2.0</VALUE> </PRINCIPAL_ID> </SWITCH_SAN> </DATA> <LOOPS> <VALUE>1.3.6.1.4.1.1588.2.1.1.1.6.2.1.1</VALUE> <INDEX>1.3.6.1.4.1.1588.2.1.1.1.6.2.1.1.(\S+)</INDEX> <NAME_INDEX>IDX</NAME_INDEX> <DATA> <NETWORKS> <SLOT> <VALUE>1.3.6.1.4.1.1588.2.1.1.1.6.2.1.37.IDX</VALUE> </SLOT> <PHYSICAL> <VALUE>1.3.6.1.4.1.1588.2.1.1.1.6.2.1.3.IDX</VALUE> <REPLACE> <STRING>1</STRING> <BY>No Card</BY> </REPLACE> <REPLACE> <STRING>2</STRING> <BY>No Gbic</BY> </REPLACE> <REPLACE> <STRING>3</STRING> <BY>Laser Fault</BY> </REPLACE> <REPLACE> <STRING>4</STRING> <BY>No Light</BY> </REPLACE> <REPLACE> <STRING>5</STRING> <BY>No Sync</BY> </REPLACE> <REPLACE> <STRING>6</STRING> <BY>In Sync</BY> </REPLACE> <REPLACE> <STRING>7</STRING> <BY>Port Fault</BY> </REPLACE> <REPLACE> <STRING>8</STRING> <BY>Diagnostics Fault</BY> </REPLACE> <REPLACE> <STRING>9</STRING> <BY>Lock Reference Signal</BY> </REPLACE> </PHYSICAL> <OP_STATUS> <VALUE>1.3.6.1.4.1.1588.2.1.1.1.6.2.1.4.IDX</VALUE> <REPLACE> <STRING>0</STRING> <BY>Unknown</BY> </REPLACE> <REPLACE> <STRING>1</STRING> <BY>Online</BY> </REPLACE> <REPLACE> <STRING>2</STRING> <BY>Offline</BY> </REPLACE> <REPLACE> <STRING>3</STRING> <BY>testing</BY> </REPLACE> <REPLACE> <STRING>4</STRING> <BY>Faulty</BY> </REPLACE> </OP_STATUS> <STATUS> <VALUE>1.3.6.1.4.1.1588.2.1.1.1.6.2.1.5.IDX</VALUE> <REPLACE> <STRING>1</STRING> <BY>Online</BY> </REPLACE> <REPLACE> <STRING>2</STRING> <BY>Offline</BY> </REPLACE> <REPLACE> <STRING>3</STRING> <BY>Testing</BY> </REPLACE> <REPLACE> <STRING>4</STRING> <BY>Faulty</BY> </REPLACE> </STATUS> <TYPE> <VALUE>1.3.6.1.4.1.1588.2.1.1.1.6.2.1.7.IDX</VALUE> <REPLACE> <STRING>1</STRING> <BY>unknown</BY> </REPLACE> <REPLACE> <STRING>2</STRING> <BY>long wave laser (lw)</BY> </REPLACE> <REPLACE> <STRING>3</STRING> <BY>short wave laser (sw)</BY> </REPLACE> <REPLACE> <STRING>4</STRING> <BY>long wave LED (ld)</BY> </REPLACE> <REPLACE> <STRING>5</STRING> <BY>copper (CU)</BY> </REPLACE> </TYPE> <SPEED> <VALUE>1.3.6.1.4.1.1588.2.1.1.1.6.2.1.35.IDX</VALUE> <REPLACE> <STRING>1</STRING> <BY>1 GB</BY> </REPLACE> <REPLACE> <STRING>2</STRING> <BY>2 GB</BY> </REPLACE> <REPLACE> <STRING>3</STRING> <BY>auto</BY> </REPLACE> <REPLACE> <STRING>4</STRING> <BY>4 GB</BY> </REPLACE> <REPLACE> <STRING>5</STRING> <BY>8 GB</BY> </REPLACE> <REPLACE> <STRING>6</STRING> <BY>10 GB</BY> </REPLACE> </SPEED> <MACADDR> <VALUE>1.3.6.1.4.1.1588.2.1.1.1.6.2.1.34.IDX</VALUE> </MACADDR> </NETWORKS> </DATA> </LOOPS> </T_1588> ���������������������������������������������������������UnixAgent-2.8/snmp/mibs/local/18552.xml�������������������������������������������������������������0000664�0000000�0000000�00000000273�13726633777�0017523�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<T_18552> <PARAMETERS> <PARSER>1</PARSER> <VERSION>1</VERSION> <NAME>xxx</NAME> <EXECUTE> <RUN>8072</RUN> </EXECUTE> </PARAMETERS> </T_18552> �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������UnixAgent-2.8/snmp/mibs/local/24681.xml�������������������������������������������������������������0000664�0000000�0000000�00000002137�13726633777�0017524�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<T_24681> <PARAMETERS> <PARSER>1</PARSER> <VERSION>1</VERSION> <NAME>Nas</NAME> </PARAMETERS> <DATA> <COMMON> <TYPE> <SET>San</SET> </TYPE> <UPTIME> <VALUE>1.3.6.1.4.1.24681.1.4</VALUE> </UPTIME> </COMMON> <MEMORIES> <CAPACITY> <VALUE>1.3.6.1.4.1.24681.1.2</VALUE> </CAPACITY> </MEMORIES> </DATA> <LOOPS> <VALUE>1.3.6.1.4.1.24681.1.9.1.2</VALUE> <INDEX>1.3.6.1.4.1.24681.1.9.1.(\S+)</INDEX> <NAME_INDEX>IDX</NAME_INDEX> <DATA> <NETWORKS> <DESCRIPTION> <VALUE>1.3.6.1.4.1.24681.1.9.1.2.IDX</VALUE> </DESCRIPTION> </NETWORKS> </DATA> </LOOPS> <LOOPS> <VALUE>1.3.6.1.4.1.24681.1.11.1.2</VALUE> <INDEX>1.3.6.1.4.1.24681.1.11.1.(\S+)</INDEX> <NAME_INDEX>IDX</NAME_INDEX> <DATA> <TYPE> <VALUE>1.3.6.1.4.1.24681.1.11.5.IDX</VALUE> </TYPE> <TOTAL> <VALUE>1.3.6.1.4.1.24681.1.11.6.IDX</VALUE> </TOTAL> <LABEL> <VALUE>1.3.6.1.4.1.24681.1.11.2.IDX</VALUE> </LABEL> </DATA> </LOOPS> </T_24681> ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������UnixAgent-2.8/snmp/mibs/local/6876.xml��������������������������������������������������������������0000664�0000000�0000000�00000006042�13726633777�0017451�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<T_6876> <PARAMETERS> <PARSER>1</PARSER> <VERSION>1</VERSION> <NAME>Vmware</NAME> <EXECUTE> <RUN>Host_Resources_Mib</RUN> <RUN>If_Mib</RUN> </EXECUTE> </PARAMETERS> <DATA> <COMMON> <DESCRIPTION> <VALUE>1.3.6.1.4.1.6876.1.1.0</VALUE> </DESCRIPTION> <TYPE> <SET>Virtual Server</SET> </TYPE> </COMMON> <VIRTUAL> <TYPE> <VALUE>1.3.6.1.4.1.6876.1.1.0</VALUE> </TYPE> <MANUFACTURER> <SET>VmWare</SET> </MANUFACTURER> <SOFTVERSION> <VALUE>1.3.6.1.4.1.6876.1.2.0</VALUE> </SOFTVERSION> <REVISION> <VALUE>1.3.6.1.4.1.6876.1.4.0</VALUE> </REVISION> </VIRTUAL> </DATA> <LOOPS> <VALUE>1.3.6.1.4.1.6876.2.1.1.2</VALUE> <INDEX>1.3.6.1.4.1.6876.2.1.1.2.(\S+)</INDEX> <NAME_INDEX>VM</NAME_INDEX> <DATA> <VIRTUALMACHINES> <NAME> <VALUE>1.3.6.1.4.1.6876.2.1.1.2.VM</VALUE> </NAME> <CONFIG_FILE> <VALUE>1.3.6.1.4.1.6876.2.1.1.3.VM</VALUE> </CONFIG_FILE> <OS> <VALUE>1.3.6.1.4.1.6876.2.1.1.4.VM</VALUE> </OS> <MEMORY> <VALUE>1.3.6.1.4.1.6876.2.1.1.5.VM</VALUE> </MEMORY> <POWER> <VALUE>1.3.6.1.4.1.6876.2.1.1.6.VM</VALUE> </POWER> <CPU> <VALUE>1.3.6.1.4.1.6876.2.1.1.9.VM</VALUE> </CPU> <UUID> <VALUE>1.3.6.1.4.1.6876.2.1.1.10.VM</VALUE> </UUID> <LOOPS> <VALUE>1.3.6.1.4.1.6876.2.3.1.3.VM</VALUE> <INDEX>1.3.6.1.4.1.6876.2.3.1.3.VM.(\S+)</INDEX> <NAME_INDEX>DISK</NAME_INDEX> <DATA> <DISKS> <NAME> <VALUE>1.3.6.1.4.1.6876.2.3.1.3.VM.DISK</VALUE> </NAME> </DISKS> </DATA> </LOOPS> <LOOPS> <VALUE>1.3.6.1.4.1.6876.2.4.1.3.VM</VALUE> <INDEX>1.3.6.1.4.1.6876.2.4.1.3.VM.(\S+)</INDEX> <NAME_INDEX>NET</NAME_INDEX> <DATA> <NETWORKS> <DRIVER> <VALUE>1.3.6.1.4.1.6876.2.4.1.3.VM.NET</VALUE> </DRIVER> <DESCRIPTION> <VALUE>1.3.6.1.4.1.6876.2.4.1.4.VM.NET</VALUE> </DESCRIPTION> <MACADDR> <VALUE>1.3.6.1.4.1.6876.2.4.1.7.VM.NET</VALUE> </MACADDR> <STATUS> <VALUE>1.3.6.1.4.1.6876.2.4.1.6.VM.NET</VALUE> <REPLACE> <STRING>true</STRING> <BY>Up</BY> </REPLACE> <REPLACE> <STRING>false</STRING> <BY>Down</BY> </REPLACE> </STATUS> </NETWORKS> </DATA> </LOOPS> </VIRTUALMACHINES> </DATA> </LOOPS> </T_6876> ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������UnixAgent-2.8/snmp/mibs/local/7244.xml��������������������������������������������������������������0000664�0000000�0000000�00000031042�13726633777�0017435�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<T_7244> <PARAMETERS> <PARSER>1</PARSER> <VERSION>1</VERSION> <NAME>Blade</NAME> </PARAMETERS> <LOOPS> <VALUE>1.3.6.1.4.1.7244.1.1.1.3.2.4.1.1</VALUE> <INDEX>1.3.6.1.4.1.7244.1.1.1.3.2.4.1.1.(\S+)</INDEX> <NAME_INDEX>POWER</NAME_INDEX> <DATA> <POWERSUPPLIES> <STATUS> <VALUE>1.3.6.1.4.1.7244.1.1.1.3.2.4.1.2.POWER</VALUE> <REPLACE> <STRING>1</STRING> <BY>Unknown</BY> </REPLACE> <REPLACE> <STRING>2</STRING> <BY>Ok</BY> </REPLACE> <REPLACE> <STRING>3</STRING> <BY>Not present</BY> </REPLACE> <REPLACE> <STRING>4</STRING> <BY>Error</BY> </REPLACE> <REPLACE> <STRING>5</STRING> <BY>Critical</BY> </REPLACE> <REPLACE> <STRING>6</STRING> <BY>Off</BY> </REPLACE> <REPLACE> <STRING>7</STRING> <BY>dummy</BY> </REPLACE> </STATUS> <MANUFACTURER> <VALUE>1.3.6.1.4.1.7244.1.1.1.3.2.4.1.3.POWER</VALUE> </MANUFACTURER> <REFERENCE> <VALUE>1.3.6.1.4.1.7244.1.1.1.3.2.4.1.4.POWER</VALUE> </REFERENCE> <TYPE> <VALUE>1.3.6.1.4.1.7244.1.1.1.3.2.5.1.5.POWER</VALUE> </TYPE> <REVISION> <VALUE>1.3.6.1.4.1.7244.1.1.1.3.2.4.1.6.POWER</VALUE> </REVISION> <SERIALNUMBER> <VALUE>1.3.6.1.4.1.7244.1.1.1.3.2.4.1.7.POWER</VALUE> </SERIALNUMBER> </POWERSUPPLIES> </DATA> </LOOPS> <LOOPS> <VALUE>1.3.6.1.4.1.7244.1.1.1.4.1.1.1.1</VALUE> <INDEX>1.3.6.1.4.1.7244.1.1.1.4.1.1.1.1.(\S+)</INDEX> <NAME_INDEX>LAME</NAME_INDEX> <DATA> <DEVICE> <POWER> <VALUE>1.3.6.1.4.1.7244.1.1.1.4.1.1.1.5.LAME</VALUE> <REPLACE> <STRING>1</STRING> <BY>Unknown</BY> </REPLACE> <REPLACE> <STRING>2</STRING> <BY>On</BY> </REPLACE> <REPLACE> <STRING>3</STRING> <BY>Off</BY> </REPLACE> <REPLACE> <STRING>4</STRING> <BY>Power-cycle</BY> </REPLACE> <REPLACE> <STRING>5</STRING> <BY>Reset</BY> </REPLACE> <REPLACE> <STRING>6</STRING> <BY>Nmi</BY> </REPLACE> <REPLACE> <STRING>7</STRING> <BY>Force Off</BY> </REPLACE> </POWER> <DATA> <POSITION> <VALUE>1.3.6.1.4.1.7244.1.1.1.4.1.1.1.1.LAME</VALUE> </POSITION> <STATUS> <VALUE>1.3.6.1.4.1.7244.1.1.1.4.2.1.1.2.LAME</VALUE> <REPLACE> <STRING>1</STRING> <BY>Unknown</BY> </REPLACE> <REPLACE> <STRING>2</STRING> <BY>Ok</BY> </REPLACE> <REPLACE> <STRING>3</STRING> <BY>Not Present</BY> </REPLACE> <REPLACE> <STRING>4</STRING> <BY>Error</BY> </REPLACE> <REPLACE> <STRING>5</STRING> <BY>Critical</BY> </REPLACE> <REPLACE> <STRING>6</STRING> <BY>Standby</BY> </REPLACE> </STATUS> </DATA> <MANUFACTURER> <VALUE>1.3.6.1.4.1.7244.1.1.1.4.2.1.1.3.LAME</VALUE> <REPLACE> <STRING>FSC</STRING> <BY>Fujitsu Siemens Computers</BY> </REPLACE> </MANUFACTURER> <SERIAL> <VALUE>1.3.6.1.4.1.7244.1.1.1.4.2.1.1.5.LAME</VALUE> </SERIAL> <PRODUCT> <VALUE>1.3.6.1.4.1.7244.1.1.1.4.2.1.1.6.LAME</VALUE> </PRODUCT> <HARDWARE> <VALUE>1.3.6.1.4.1.7244.1.1.1.4.2.1.1.8.LAME</VALUE> </HARDWARE> <FIRMWARE> <VALUE>1.3.6.1.4.1.7244.1.1.1.4.2.1.1.9.LAME</VALUE> </FIRMWARE> <BIOS> <VALUE>1.3.6.1.4.1.7244.1.1.1.4.2.1.1.10.LAME</VALUE> </BIOS> <BIOS> <VALUE>1.3.6.1.4.1.7244.1.1.1.4.2.1.1.10.LAME</VALUE> </BIOS> <SOCKET> <VALUE>1.3.6.1.4.1.7244.1.1.1.4.2.1.1.11.LAME</VALUE> </SOCKET> <MEMORY_SLOT> <VALUE>1.3.6.1.4.1.7244.1.1.1.4.2.1.1.12.LAME</VALUE> </MEMORY_SLOT> <TYPE> <VALUE>1.3.6.1.4.1.7244.1.1.1.4.2.1.1.22.LAME</VALUE> </TYPE> <LOOPS> <VALUE>1.3.6.1.4.1.7244.1.1.1.4.3.1.1.1.LAME</VALUE> <INDEX>1.3.6.1.4.1.7244.1.1.1.4.3.1.1.1.LAME.(\S+)</INDEX> <NAME_INDEX>CPU</NAME_INDEX> <DATA> <CPUS> <TYPE> <VALUE>1.3.6.1.4.1.7244.1.1.1.4.3.1.1.3.LAME.CPU</VALUE> <REPLACE> <STRING>12</STRING> <BY>Xeon</BY> </REPLACE> <REPLACE> <STRING>11</STRING> <BY>Pentium M</BY> </REPLACE> <REPLACE> <STRING>10</STRING> <BY>Pentium IV</BY> </REPLACE> <REPLACE> <STRING>9</STRING> <BY>M Un</BY> </REPLACE> <REPLACE> <STRING>8</STRING> <BY>Pentium III</BY> </REPLACE> <REPLACE> <STRING>7</STRING> <BY>Pentium II Xeon</BY> </REPLACE> <REPLACE> <STRING>6</STRING> <BY>Celeron</BY> </REPLACE> <REPLACE> <STRING>5</STRING> <BY>Pentium MMX</BY> </REPLACE> <REPLACE> <STRING>4</STRING> <BY>Pentium II</BY> </REPLACE> <REPLACE> <STRING>3</STRING> <BY>Pentium Pro</BY> </REPLACE> <REPLACE> <STRING>2</STRING> <BY>Pentium</BY> </REPLACE> <REPLACE> <STRING>1</STRING> <BY>Unknown</BY> </REPLACE> </TYPE> <SPEED> <VALUE>1.3.6.1.4.1.7244.1.1.1.4.3.1.1.4.LAME.CPU</VALUE> </SPEED> <STATUS> <VALUE>1.3.6.1.4.1.7244.1.1.1.4.3.1.1.6.LAME.CPU</VALUE> <REPLACE> <STRING>1</STRING> <BY>Unknown</BY> </REPLACE> <REPLACE> <STRING>2</STRING> <BY>OK</BY> </REPLACE> <REPLACE> <STRING>3</STRING> <BY>Not Present</BY> </REPLACE> <REPLACE> <STRING>4</STRING> <BY>Error</BY> </REPLACE> <REPLACE> <STRING>5</STRING> <BY>Critical</BY> </REPLACE> <REPLACE> <STRING>6</STRING> <BY>Missing termination</BY> </REPLACE> <REPLACE> <STRING>7</STRING> <BY>Disabled</BY> </REPLACE> </STATUS> <MANUFACTURER> <VALUE>1.3.6.1.4.1.7244.1.1.1.4.3.1.1.9.LAME.CPU</VALUE> </MANUFACTURER> </CPUS> </DATA> </LOOPS> <MEMORY> <VALUE>1.3.6.1.4.1.7244.1.1.1.4.4.1.1.2.LAME</VALUE> </MEMORY> <LOOPS> <VALUE>1.3.6.1.4.1.7244.1.1.1.4.4.2.1.1.LAME</VALUE> <INDEX>1.3.6.1.4.1.7244.1.1.1.4.4.2.1.1.LAME.(\S+)</INDEX> <NAME_INDEX>SLOT</NAME_INDEX> <DATA> <MEMORIES> <NUMSLOTS> <VALUE>1.3.6.1.4.1.7244.1.1.1.4.4.2.1.2.LAME.SLOT</VALUE> </NUMSLOTS> <STATUS> <VALUE>1.3.6.1.4.1.7244.1.1.1.4.4.2.1.3.LAME.SLOT</VALUE> <REPLACE> <STRING>1</STRING> <BY>Unknown</BY> </REPLACE> <REPLACE> <STRING>2</STRING> <BY>Disable</BY> </REPLACE> <REPLACE> <STRING>3</STRING> <BY>Ok</BY> </REPLACE> <REPLACE> <STRING>4</STRING> <BY>Not Present</BY> </REPLACE> <REPLACE> <STRING>5</STRING> <BY>Critical</BY> </REPLACE> <REPLACE> <STRING>6</STRING> <BY>Prefailure Warning</BY> </REPLACE> </STATUS> <CAPACITY>3 <VALUE>1.3.6.1.4.1.7244.1.1.1.4.4.2.1.4.LAME.SLOT</VALUE> </CAPACITY> <DESCRIPTION> <VALUE>1.3.6.1.4.1.7244.1.1.1.4.4.2.1.6.LAME.SLOT</VALUE> </DESCRIPTION> <SPEED> <VALUE>1.3.6.1.4.1.7244.1.1.1.4.4.2.1.7.LAME.SLOT</VALUE> </SPEED> </MEMORIES> </DATA> </LOOPS> </DEVICE> </DATA> </LOOPS> <LOOPS> <VALUE>1.3.6.1.4.1.7244.1.1.1.3.3.1.1.2</VALUE> <INDEX>1.3.6.1.4.1.7244.1.1.1.3.3.1.1.2.(\S+)</INDEX> <NAME_INDEX>FAN</NAME_INDEX> <DATA> <FANS> <STATUS> <VALUE>1.3.6.1.4.1.7244.1.1.1.3.3.1.1.2.FAN</VALUE> <REPLACE> <STRING>1</STRING> <BY>Unknown</BY> </REPLACE> <REPLACE> <STRING>2</STRING> <BY>Disable</BY> </REPLACE> <REPLACE> <STRING>3</STRING> <BY>Ok</BY> </REPLACE> <REPLACE> <STRING>4</STRING> <BY>Fail</BY> </REPLACE> <REPLACE> <STRING>5</STRING> <BY>Prefailure predicted</BY> </REPLACE> <REPLACE> <STRING>6</STRING> <BY>Redundant fan failed</BY> </REPLACE> <REPLACE> <STRING>7</STRING> <BY>Not manageable</BY> </REPLACE> <REPLACE> <STRING>8</STRING> <BY>Not present</BY> </REPLACE> <REPLACE> <STRING>9</STRING> <BY>Not available</BY> </REPLACE> </STATUS> <DESCRIPTION> <VALUE>1.3.6.1.4.1.7244.1.1.1.3.3.1.1.3.FAN</VALUE> </DESCRIPTION> </FANS> </DATA> </LOOPS> <LOOPS> <VALUE>1.3.6.1.4.1.7244.1.1.1.2.1.1.3</VALUE> <INDEX>1.3.6.1.4.1.7244.1.1.1.2.1.1.3.(\S+)</INDEX> <NAME_INDEX>BLADE</NAME_INDEX> <DATA> <BLADE> <STATUS> <VALUE>1.3.6.1.4.1.7244.1.1.1.2.1.1.2.BLADE</VALUE> <REPLACE> <STRING>1</STRING> <BY>Unknown</BY> </REPLACE> <REPLACE> <STRING>2</STRING> <BY>Ok</BY> </REPLACE> <REPLACE> <STRING>3</STRING> <BY>Not present</BY> </REPLACE> <REPLACE> <STRING>4</STRING> <BY>Error</BY> </REPLACE> <REPLACE> <STRING>5</STRING> <BY>Critical</BY> </REPLACE> <REPLACE> <STRING>6</STRING> <BY>Standby</BY> </REPLACE> </STATUS> <MANUFACTURER> <VALUE>1.3.6.1.4.1.7244.1.1.1.2.1.1.3.BLADE</VALUE> <REPLACE> <STRING>FSC</STRING> <BY>Fujitsu Siemens Computers</BY> </REPLACE> </MANUFACTURER> <SERIALNUMBER> <VALUE>1.3.6.1.4.1.7244.1.1.1.2.1.1.5.BLADE</VALUE> </SERIALNUMBER> <TYPE> <VALUE>1.3.6.1.4.1.7244.1.1.1.2.1.1.6.BLADE</VALUE> </TYPE> <SERIALNUMBER> <VALUE>1.3.6.1.4.1.7244.1.1.1.2.1.1.7.BLADE</VALUE> </SERIALNUMBER> <FIRMVERSION> <VALUE>1.3.6.1.4.1.7244.1.1.1.2.1.1.8.BLADE</VALUE> </FIRMVERSION> <SOFTVERSION> <VALUE>1.3.6.1.4.1.7244.1.1.1.2.1.1.9.BLADE</VALUE> </SOFTVERSION> </BLADE> </DATA> </LOOPS> </T_7244> ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������UnixAgent-2.8/tools/��������������������������������������������������������������������������������0000775�0000000�0000000�00000000000�13726633777�0014452�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������UnixAgent-2.8/tools/build-perl-tree.sh��������������������������������������������������������������0000775�0000000�0000000�00000004635�13726633777�0020015�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!/bin/sh # A script to prepare a installation of Perl + OCSInventory-agent for # Unix/Linux # This in order to be able to provide an installation for system without # Perl > 5.6 set -e MAKE="make" TMP="/home2/goneri/tmp" PREFIX="$TMP/build/opt/ocsinventory-agent" ETCDIR="$PREFIX/etc" BASEDIR="$PREFIX/var/ocsinventory-agent" LOGDIR="$PREFIX/log/ocsinventory-agent" PIDFILE="$PREFIX/var/run" PERLVERSION="5.10.0" if [ ! -d $TMP ]; then echo "tmp $TMP dir is missing" fi cd $TMP if [ ! -f perl-$PERLVERSION.tar.gz ]; then wget -O perl-$PERLVERSION.tar.gz.part http://cpan.perl.org/src/perl-$PERLVERSION.tar.gz mv perl-$PERLVERSION.tar.gz.part perl-$PERLVERSION.tar.gz fi gunzip < perl-$PERLVERSION.tar.gz | tar xvf - cd perl-$PERLVERSION # AIX #./Configure -Dusenm -des -Dinstallprefix=$PREFIX -Dsiteprefix=$PREFIX -Dprefix=$PREFIX #./Configure -Dcc="gcc" -des -Dinstallprefix=$PREFIX -Dsiteprefix=$PREFIX -Dprefix=$PREFIX ./Configure -des -Dinstallprefix=$PREFIX -Dsiteprefix=$PREFIX -Dprefix=$PREFIX $MAKE $MAKE install PATH=$PREFIX/bin:$PATH export PATH cpanp 's conf prereqs 1; i XML::SAX' cpanp 's conf prereqs 1; i XML::Simple' cpanp 's conf prereqs 1; i LWP' cpanp 's conf prereqs 1; i Proc::Daemon' cpanp 's conf prereqs 1; i HTML::Parser' # For what? # Report error about IPv6 on Solaris 10 cpanp 's conf prereqs 1; i --force Net::IP' cpanp 's conf prereqs 1; i --force PAR::Packer' cpanp 's conf prereqs 1; i --force Net::SSLeay' exit; if [ ! openssl-0.9.8j.tar.gz ]; then wget -O openssl-0.9.8j.tar.gz.part http://www.openssl.org/source/openssl-0.9.8j.tar.gz mv openssl-0.9.8j.tar.gz.part openssl-0.9.8j.tar.gz fi gunzip < openssl-0.9.8j.tar.gz | tar xvf - cd openssl-0.9.8j ./config --prefix=/home2/goneri/tmp/openssl make make install ln -s apps bin #for i in `ls ../tarballs/*.gz`; do # gunzip < $i | tar xvf - #done #cd ../expat-2.0.0/ #./configure --prefix=$PREFIX #$MAKE #cd ../Ocsinventory-Agent-0.0.2/ #$PERL Makefile.PL PREFIX=$PREFIX #$MAKE PREFIX=$PREFIX #$MAKE install PREFIX=$PREFIX #:$PATH#perl -i -pe "s!/etc/ocsinventory-agent!$ETCDIR!" $PREFIX/bin/ocsinventory-agent #perl -i -pe "s!/var/lib/ocsinventory-agent!$BASEDIR!" $PREFIX/bin/ocsinventory-agent #perl -i -pe "s!/var/log/ocsinventory-agent!$LOGDIR!" $PREFIX/bin/ocsinventory-agent #perl -i -pe "s!/var/run/ocsinventory-agent.pid!$PIDFILE!" $PREFIX/bin/ocsinventory-agent #mkdir -p $ETCDIR #mkdir -p $BASEDIR #mkdir -p $LOGDIR #mkdir -p $PIDFILE ���������������������������������������������������������������������������������������������������UnixAgent-2.8/tools/encryptText.pm������������������������������������������������������������������0000775�0000000�0000000�00000000607�13726633777�0017347�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!/usr/bin/perl -w # Requirements use MIME::Base64; # (1) quit unless we have the correct number of command-line args $num_args = $#ARGV + 1; if ($num_args != 1) { print "\nUsage: perl encryptPassword.pm clearTextPassword \n"; exit; } my $hash = encode_base64($ARGV[0]); print "Password's hash is : \n"; print "$hash \n"; print "You can now put it in ocsinventory-agent.cfg \n"; �������������������������������������������������������������������������������������������������������������������������UnixAgent-2.8/tools/makedist.sh���������������������������������������������������������������������0000775�0000000�0000000�00000000663�13726633777�0016617�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!/bin/sh # Hack because of # http://rt.cpan.org/Public/Bug/Display.html?id=43060 perl Makefile.PL make manifest make dist gunzip < Ocsinventory-Agent-0.0.10beta3.tar.gz | tar xf - perl -i -pe 's/^exit;//' Ocsinventory-Agent-0.0.10beta3/inc/BUNDLES/libwww-perl-5.823/Makefile.PL rm Ocsinventory-Agent-0.0.10beta3.tar.gz tar cf Ocsinventory-Agent-0.0.10beta3.tar Ocsinventory-Agent-0.0.10beta3 gzip Ocsinventory-Agent-0.0.10beta3.tar �����������������������������������������������������������������������������UnixAgent-2.8/tools/parseVmware.pl������������������������������������������������������������������0000664�0000000�0000000�00000000623�13726633777�0017304�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!/usr/bin/perl -w use strict; use warnings; use Data::Dumper; my $data = { cpu => {}, mem => {}, }; open VMWARECPU,"</proc/vmware/cpuinfo" or die; foreach (<VMWARECPU>) { if (/^\s*(\w+)\s+(\w.*)\s*/) { my $key = $1; my @data = split(/\s+/,$2); print Dumper(\@data); $data->{cpu}->{$key} = \@data; #print $1." -> '".$2."'\n"; } } print Dumper($data); close VMWARECPU; �������������������������������������������������������������������������������������������������������������UnixAgent-2.8/tools/pre-nobundle.sh�����������������������������������������������������������������0000664�0000000�0000000�00000000216�13726633777�0017377�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!/bin/sh make distclean rm -f MANIFEST Makefile sed -i 's/^bundle/#bundle/' Makefile.PL rm -rf inc/BUNDLES* perl Makefile.PL make manifest ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������UnixAgent-2.8/tools/standalone.sh�������������������������������������������������������������������0000775�0000000�0000000�00000003771�13726633777�0017151�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!/bin/sh echo "WARNINGS: Very experimental tool" [ -f standalone.sh ] && cd .. if [ ! -f tools/standalone.sh ]; then echo "Can't find tools/standalone.sh" exit 1 fi if [ ! -f MANIFEST ]; then echo "Can't find the MANIFEST, please run:" echo " perl Makefile.PL" echo " make manifest" exit 1 fi if [ ! -x "`which pp 2>/dev/null`" ]; then echo "Can't find the pp command. Please install PAR::Packer:" echo " -CPAN: 'cpan PAR::Packer'" echo " -source: download the archive from" echo " http://search.cpan.org/dist/PAR-Packer/" echo " -Debian/Ubuntu: 'aptitude install libpar-packer-perl' OR 'aptitude install libpar-perl'" exit 1 fi BACKENDMODULE=`cat MANIFEST | perl -pe 's/.*// unless (/Ocsinventory\/Agent\/Backend\// && !/^inc/ && /pm$/); s/lib\/(.*)\.pm/ $1/; s/\//::/g; chomp'` cat > lib/Ocsinventory/Agent/Backend/ModuleToLoad.pm <<EOF # This is a workaround for PAR::Packer. Since it resets @INC # I can't find the backend modules to load dynamically. So # I prepare a list and include it. package Ocsinventory::Agent::Backend::ModuleToLoad; our @list = qw/ $BACKENDMODULE /; 1; EOF MODULES="`cat MANIFEST | perl -pe 's/.*// unless (!/^inc/ && /pm$/ && !/^contrib/); s/lib\/(.*)\.pm/ -M $1/; s/\//::/g; chomp'` -M XML::SAX::PurePerl -M XML::SAX::Expat -M PerlIO -M Getopt::Long -M Digest::MD5 -M Net::IP -M Ocsinventory::Agent::Backend::ModuleToLoad" for i in `echo $MODULES| perl -nle 's/\-M//g;print'`; do perl -I "lib" -M$i -e "1" || MISSING="$MISSING $i" ;done if [ ! -z "$MISSING" ]; then echo "Some modules are missing in your installation or failed to build, please install them first." echo "->$MISSING" exit 1 fi #pp --lib lib $MODULES -o ocsinventory-agent.bin ocsinventory-agent pp --lib lib $MODULES -B -p ocsinventory-agent -vvv -o ocsinventory-agent.par pp -o ocsinventory-agent.bin ocsinventory-agent.par if [ -f ocsinventory-agent.bin ]; then echo "ocsinventory-agent.bin generated!" else echo "Failed to generate ocsinventory-agent.bin!" fi ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������