oar-2.5.7/0000755015014700017500000000000012677211234011726 5ustar neyronneyronoar-2.5.7/AUTHORS0000644015014700017500000000167112677211234013003 0ustar neyronneyron OAR is developped within the Laboratoire ID-IMAG ENSIMAG-Antenne de Montbonnot 51 avenue Jean KUNTZMANN 38330 Montbonnot Saint-Martin FRANCE http://oar.imag.fr Developers Nicolas Capit < nicolas.capit@imag.fr > Georges Da Costa < Georges.Da-Costa@imag.fr > Joseph Emeras < Joseph.Emeras@imag.fr > Lionel Eyraud < lionel.eyraud@imag.fr > Guillaume Huard < Guillaume.Huard@imag.fr > Philippe Le Brouster < philippe.le-brouster@imag.fr > Cyrille Martin < Cyrille.Martin@imag.fr > Gregory Mounie < Gregory.Mounie@imag.fr > Olivier Richard < olivier.richard@imag.fr > Pierre Neyron < pierre.neyron@imag.fr > Ali Saidi < saidi@umich.edu > Francois Visconte < francois.visconte@inria.fr > oar-2.5.7/README0000644015014700017500000000062512677211234012611 0ustar neyronneyronOAR is a versatile resource and task manager (also called a batch scheduler) for HPC clusters, and other computing infrastructures (like distributed computing experimental testbeds where versatility is a key). OAR is suitable for production use. OAR is also a support for scientific researches in the field of distributed computing. See the OAR web site (http://oar.imag.fr/) for further information. oar-2.5.7/UPGRADING0000644015014700017500000000263412677211234013176 0ustar neyronneyronUpgrading the OAR batch system ============================== This part explains the important issues when upgrading the OAR Bach system from 2.4.x to 2.5.x. Updating the Perl admission rules --------------------------------- Due to a perl module renaming, you need to update the perl module name used in the admission rules. Here are the correspondance : - oarstat_lib -> OAR::Stat - oarnodes_lib -> OAR::Nodes - oarapi_lib -> OAR::API - oarconf_lib -> OAR::Conf - oario_lib -> OAR::IO - oarsub_lib -> OAR::Sub - oar_Tools -> OAR::Tools - oar_Version -> OAR::Version - window_forker -> OAR::WindowForker - ping_checker -> OAR::PingChecker - oar_hulot -> OAR::Modules::Hulot - Judas -> OAR::Modules::Judas - resource_tree -> OAR::Schedulers::ResourceTree - gantt_hole_storage -> OAR::Schedulers::GanttHoleStorage The OAR default values ---------------------- Please take a look on the default oar.conf (in the /usr/share/doc/oar-common/exemples/). Some default values has changed. Upgrading the sql database scheme --------------------------------- Before restarting the OAR server, you need to upgrade your database scheme. This can be done, with the following instruction (don't forget to make a copy of your database before): oar-database --setup oar-2.5.7/CHANGELOG0000644015014700017500000013134212677211234013144 0ustar neyronneyronOAR CHANGELOG ============= version 2.5.7: -------------- This version mainly brings a security fix for the oarsh command. It is highly recommanded to upgrade, since all previous versions of OAR are affected. - [oarsh] fix a security hole when passing option to OpenSSH. See oar.conf to adapt settings to your setup, if required (OARSH_* variables) - [oarsh] dropped the mechanism to select whether to use oarsh or fall back to ssh, given a list of hostname patterns - [oarsub] fix the job-key information of the manual page - [oarsub] handle cases where trailing spaces were breaking oarsub script directives - [api] added an example of Apache configuration for the authentication - [documentation] improve the SSH keys setup explanations for OAR installation version 2.5.6: -------------- - [oar.conf] add the SCHEDULER_MIN_TIME_BETWEEN_2_CALLS option - [metascheduler] fix a bug with advance reservations when predicted resources must be recomputed - [metascheduler] fix a bug with advance reservations with standby start job types (noop/cosystem/deploy=standby) - [oar-node init] create /var/run/sshd if needed - [oarsub] fix several bugs with the array job submission - [oarstat] allow using Perl's YAML::Syck for a quicker YAML output - [oarstat] improve performance and information for the --gantt option - [oarstat] prettier print of job events - [oarnodesetting] optimize grouped operations on resources and add a lock around property changes - [oaradmissionrules] fix bug: changing a rule priority does not enable it - [oar_resources_init] fix node read from standard input - [oarnodecheck] use /var/lib/oar instead of /etc/oar for working files - [logs] several cosmetic fixes - [api] add colmet extraction function - [api] proposed apache configuration now uses a virtual host on port 6668 - [drawgantt-svg] fix the possibly very long delay when zooming - [drawgantt-svg] add forecast buttons + relative start/stop url arguments - [drawgantt-svg] rework configuration for the default display - [drawgantt-svg] allow displaying resources of type != default - [drawgantt-svg] improve support for use as a widget in custom HTML pages (multisite, etc) - [monika] fix bugs with recent Perl/Perl CGI versions - [monika] fix harmless bug in configuration - [visualization] remove overlib.js (license issue), this breaks the legacy drawgantt (which is not supported anymore) - [misc] remove some old development codes from sources - [misc] fix inconsistent copyrights and licenses - [doc] update the installation documentation version 2.5.5: -------------- - [iolib] fix deadlock with TRUNCATE in postgresql - [almighty] add SCHEDULER_MIN_TIME_BETWEEN_2_CALLS: the scheduler is launched at max every t seconds (t=5 by default), this avoids the scheduler to cause starvation with regard to the other modules - [scheduler] fix some memory leaks. - [scheduler] add a cache to the resources tree computation: improve the scheduler speed by reducing the number of SQL queries. - [scheduler] backport the expire/postpone/deadline job types. - [scheduler] rename the placeholder job types: placeholder/allowed. - [scheduler] fix timesharing (adv reservation and *_placeholder schedulers). - [scheduler] allows noop/cosystem/deploy jobs to start on resources in standby, no wake-up is triggered (requires activating energy saving). - [oarsub] use jobkey (-k) if the OAR_JOB_KEY_FILE env variable is set. - [oarstat] fix accounting display - [oar_resources_init] fix HyperThreading bug + improve CLI - [oar_resources_add] make HyperThreading optional + fix long options + make nicer warning outputs for auto-offset - [admission rules] rewrite the job type check rule - [admission rules] fix oaradmissionrules bug with MySQL when modifying a rule - [oar-node] fix pid in init script. - [api] some optimizations + rework authentication configuration (apache). - [api][drawgantt-svg][monika] fix apache config (apache 2.4). - [drawgantt-svg] new version with aggreation of resources and more. - [monika] add thread to the hidden properties. - [api] fastcgi config now using suexec - [api] now using apache environment variables when headers are not available - [api] optimization of /jobs query response time (especially efficient for mysql based installations) - [api] security fix: HTML outputs which did not break on errors version 2.5.4: -------------- - [api] Implemented GET /resources//jobs to get jobs running on resources, grouped by a given property. - [api] Implemented HTTP_X_API_PATH_PREFIX header variable to prefix all returned URIs. - [api] Added GET /jobs//details support. - [api] Implemented the ability to get a set of jobs at once with GET /jobs?ids=:::... - [api] BUGFIX: stderr and stdout where reversed. - [api] BUGFIX: memory leak in the API when used with FastCGI. - [api] Rewritten/commented apache config file. - [kamelot] BUGFIX: fix hierarchies manipulation (remove toplevel resource). - [accounting] Fixed a memory leak and a rare case of bad consumption count. - [oar.conf] Replace the MAX_CONCURRENT_JOB_TERMINATIONS option by MAX_CONCURRENT_JOBS_STARTING_OR_TERMINATING - [almighty] Rewrote the handling of starting and finishing jobs: limit bipbip processes to MAX_CONCURRENT_JOBS_STARTING_OR_TERMINATING to avoid overloading the server. - [oarexec] Introduced BASH_ENV=~oar/.batch_job_bashrc for batch jobs Batch jobs with bash shell have some difficulties to source the right bash scripts when launching. Now we set BASH_ENV=~oar/.batch_job_bashrc before launching the user bash process so we can handle which script must be sourced. By default we source ~/.bashrc. - [commands] Exit immediately on wrong arguments. - [oarsh] Propagate OAR shell environment variables: The users have access to the same OAR environment variables when connecting on all the job nodes with oarsh - [job_uid] Removed job uid feature (not used). - [job_resource_manager] Use fstrim (for SSD) when cleaning files. - [deploy] Do not check the nodes when ACTIVATE_PINGCHECKER_AT_JOB_END is on and the job is of the deploy type (bug #17128). - [judas] Disabled sending log by email on errors as this could generate too many mails. - [noop] Added the 'noop' job type. If specified, nothing is done on computing nodes. The job just reserves the resources for the specified walltime. - [quotas] Added the possibility to make quotas on: - the number of used resources - the number of running jobs - the result of resources X hours of running jobs - [runner] Added runner bipbip processes in the bipbip_laucher in Almighty. - [database] Replaced field "maintenance" by "drain". The administrator can disable resources without killing current jobs by:: oarnodesetting -h n12 -p drain=YES or:: oarnodesetting --drain -h n12 :WARNING: any admission rule using the "maintenance" keyword must be adapted to use the "drain" keyword. - [oar_resources_init] Added support for SMT (hyperthreading) - [cpuset] The cpuset resources filed is now a varchar. It is now possible to specify several cpu id in the cpuset field as needed in some case where SMT is enabled on nodes, e.g.:: 1+4+8 - [oarsub] Added a filter for notifications It now is possible to specify which TAGs must trigger motifications:: oarsub --notify "[END,ERROR]mail:name@domain.com" -I - [admission rules] Added priority to rules that allows to manage more easily the rules execution order. - [admission rules] Added a enable/disable flag to rules to allow activating or deactivating rules without having to comment the code. - [oaradmin] The oaradmin rules command is now disabled since it does not handle priority and enable flags. - [oaradmin] The oaradmin conf command is disabled. - [oar_resources_add] Added the oar_resources_add command to help adding resources and replace the oaradmin resources command. - [oaradmissionrules] oaradminssionrules is a new command to manage the oaradmission rules. - [oarnodesetting] Removed dependnency to oarnodes. - [drawgantt-svg] Various bugfixes and improvements - [metasched] If a besteffort job has a checkpoint duration defined (oarsub --checkpoint) then OAR tries to checkpoint it before killing it. It is possible to define a limit of the checkpoint duration with an admission rule ($checkpoint variable). - [drawgantt] Drawgantt is not now deprecated (and not shipped with packages) - [misc] OAR packaged components do not require Ruby anymore. - [oaraccounting] Fix bug reported in Debian tracker #678976 - [sources] Clean-up some used or unrelevant files/codes - [scheduler] change default schedulers to quota The default scheduler of the queues default, admin and besteffort is now oar_sched_gantt_with_timesharing_and_fairsharing_and_quotas. The configuration file /etc/oar/scheduler_quotas.conf contains no quota enforcement so the behaviour remains the same as before. version 2.5.3: -------------- - Add the "Name" field on the main Monika page. This is easier for the users to find there jobs. - Add MAX_CONCURRENT_JOB_TERMINATIONS into the oar.conf ofthe master. This limits the number of concurrent processes launched by the Almighty when the the jobs finish. - Bug fix in ssh key feature in oarsub. - Added --compact, -c option to oarstat (compact view or array jobs). - Improvements of the API: media upload from html forms, listing of files, security fixes, add of new configuration options, listing of the scheduled nodes into jobs, fixed bad reinitialization of the limit parameter, stress_factor, accounting... See OAR-DOCUMENTATION-API-USER for more informations. - CGROUP: handle cgroup hierarchy already mounted by the OS like in Fedora 18 (by systemd in /sys/fs/cgroup) in job_resource_manager_cgroups.pl. - Bug fix oar-database: fix the reset function for mysql. - SVG version of drawgantt: all features are now implemented to replace the legacy drawgantt. Both can be installed. - Bug fix schedulers: rewrite schedulers with placeholders. - Rework default admission rules. - Add support to the oar_resource_init command to generate resources with a "thread" property (useful if HyperThreading is activated/used on nodes). - Fix stdout/stderr bug: check the allowed characters in the path given by the users. - Fix: the user shell (bash) didn't source /etc/bash.bashrc in batch jobs. - Add quota which limits the number of used resources at a time depending of the job attributes: queue, project, types, user (available with the scheduler "oar_sched_gantt_with_timesharing_and_fairsharing_and_quotas"). - Add comments in user job STDERR files to know if a job was killed or checkpointed. - Add the variable $jobproperties_applied_after_validation. It can be used in an admission rule to add a constraint after the validation of the job. Ex: $jobproperties_applied_after_validation = "maintenance='off'"; So, even if all the ressources have "maintenance='on'", the new jobs will be accepted but not scheduled now. - Add the oardel option --force-terminate-finishing-job: to use when a job is stuck in the Finishing state. - Bug #15911: Energy saving now waits SCHEDULER_NODE_MANAGER_IDLE_TIME for nodes that have been woken up, even if they didn't run any job. - Simplify job dependencies: do not check the exit code of the jobs in dependencies. - Admission rules: add the "estimate_job_nb_resources" function that is useful to know the number of resources that will be used by a job. - oarstat: add another output format that can be used by using "--format 2" or by setting "OARSTAT_DEFAULT_OUTPUT_FORMAT=2" in oar.conf. - oarsub: Add the capability to use the tag %jobname% in the STDOUT (-O) and/or STDERR (-E) filenames (like %jobid%). - bug #14935: fix timesharing jobs within a container issue - add schedulers with the placeholder feature. version 2.5.2: -------------- - Bugfix: /var/lib/oar/.bash_oar was empty due to an error in the common setup script. - Bugfix: the PINGCHECKER_COMMAND in oar.conf depends now on %%OARDIR%%. - Bug #13939: the job_resource_manager.pl and job_resource_manager_cgroups.pl now deletes the user files in /tmp, /var/tmp and /dev/shm at the end of the jobs. - Bugfix: in oardodo.c, the preprocessed variables was not defined correclty. - Finaud: fix race condition when there was a PINGCHECKER error jsut before another problem. The node became Alive again when the PINGCHECKER said OK BUT there was another error to resolve. - Bugfix: The feature CHECK_NODES_WITH_RUNNING_JOB=yes never worked before. - Speedup monika (X5). - Monika: Add the conf max_cores_per_line to have several lines if the number of cores are too big. - Minor changes into API: - added cmd_output into POST /jobs. - API: Added GET /select_all?query= (read only mode). - Add the field "array_index" into the jobs table. So that resubmit a job from an array will have the right array_index anvironment variable. - oarstat: order the output by job_id. - Speedup oarnodes. - Fix a spelling error in the oaradmin manpage. - Bugfix #14122 : the oar-node init.d script wasn't executing start_oar_node/stop_oar_node during the 'restart' action. - Allow the dash character into the --notify "exec:..." oarsub option. - Remove some old stuffs from the tarball: - visualization_interfaces/{tgoar,accounting,poar}; - scheduler/moldable; - pbs-oar-lib. - Fix some licence issues. version 2.5.1: -------------- - Sources directories reorganized - New "Phoenix" tool to try to reboot automatically broken nodes (to setup into /etc/oar/oar_phoenix.pl) - New (experimental!) scheduler written in Ocaml - Cpusets are activated by default - Bugfix #11065: oar_resource_init fix (add a space) - Bug 10999: memory leak into Hulot when used with postgresql. The leak has been minimized, but it is still there (DBD::Pg bug) - Almighty cleans ipcs used by oar on exit - Bugfix #10641 and #10999 : Hulot is automatically and periodically restarted - Feature request #10565: add the possibility to check the aliveness of the nodes of a job at the end of this one (pingchecker) - REST API heavily updated: new data structures with paginated results, desktop computing functions, rspec tests, oaradmin resources management, admission rules edition, relative/absolutes uris fixed - New ruby desktop computing agent using REST API (experimental) - Experimental testsuite - Poar: web portal using the REST API (experimental) - Oaradmin YAML export support for resources creation (for the REST API) - Bugfix #10567: enabling to bypass window mechanism of hulot. - Bugfix #10568: Wake up timeout changing with the number of nodes - Add in oar.conf the tag "RUNNER_SLIDING_WINDOW_SIZE": it allows the runner to use a sliding window to launch the bipbip processes if "DETACH_JOB_FROM_SERVER=1". This feature avoids the overload of the server if plenty of jobs have to be launched at the same time. - Fix problem when deleting a job in the Suspended state (oarexec was stopped by a SIGSTOP so it was not able to handle the delete operation) - Make the USER_SIGNAL feature of oardel multi job independant and remove the temporary file at the end of the job - Monika: display if the job is of timesharing type or not add in the job listing the initial_request (is there a reason to not display it?) - IoLib: update scheduler_priority resources property for timesharing jobs. So the scheduler will be able to avoid to launch every timesharing jobs on the same resources (they can be dispatched) - OAREXEC: unmask SIGHUP and SIGPIPE for user script - node_change_state: do not Suspect the first node of a job which was EXTERMINATED by Leon if the cpuset feature is configured (let do the job by the cpuset) - OAREXEC: ESRF detected that sometime oarexec think that he notified the Almighty with it exit code but nothing was seen on the server. So try to resend the exit code until oarexec is killed. - oar_Tools: add in notify_almighty a check on the print and on the close of the socket connected to Almighty. - oaraccounting: --sql is now possible into a "oarstat --accounting" query - Add more logs to the command "oarnodes -e host" when a node turns into Suspected - Execute user commands with /proc/self/oom_adj to 15. So the first processes that will be killed when there is no more memory available is the user ones. Hence the system will remain up and running and the user job will finished. Drawback: this file can be changed manually by the user so if someone knows a method to do the same thing but only managed by root, we take??? - Bugfix API: quotes where badly escaped into job submission - Add the possibility to automatically resubmit idempotent job which ends with an exit code of 99: oarsub -t idempotent "sleep 5; exit 99" - Bugfix API: Some informations where missing into jobs/details, especially the scheduled resources. - API: added support of "param_file" value for array job submissions. This value is a string representing the content of a parameters file. Sample submission:: {"resource":"/cpu=1", "command":"sleep", "param_file":"60\n90\n30"} This submits 3 sleep jobs with differents sleep values. - Remove any reference to gridlibs and gridapi as these components are obselete - Add stdout and stderr files of each job in oarstat output. - API now supports fastcgi (big performance raise!) - Add "-f" option to oarnodesetting to read hostnames from a file. - API can get/upload files (GET or POST /media/) - Make "X11 forwarding" working even if the user XAUTHORITY environment variable does not contain ~/.Xauthority (GDM issue). - Add job_resource_manager_cgroups which handles cpuset + other cgroup features like network packet tagging, IO disk shares, ... - Bugfix #13351: now oar_psql_db_init is executed with root privileges - Bugfix #13434: reservation were not handled correctly with the energy saving feature - Add cgroups FREEZER feature to the suspend/resume script (better than kill SIGSTOP/SIGCONT). This is doable thanks to the new job_resource_manager_cgroups. - Implement a new script 'oar-database' to manage the oar database. oar_mysql_init & oar_psql_init are dropped. - Huge code reorganisation to allow a better packaging and system integration - Drop the oarsub/oarstat 2.3 version that was kept for compatiblity issues during the 2.4.x branch. - By default the oar scheduler is now 'oar_sched_gantt_with_timesharing_and_fairsharing' and the following values has been set in oar.conf: SCHEDULER_TIMEOUT to 30, SCHEDULER_NB_PROCESSES to 4 and SCHEDULER_FAIRSHARING_MAX_JOB_PER_USER to 30 - Add a limitation on the number of concurrent bipbip processes on the server (for detached jobs). - Add IPC cleaning to the job_resource_manager* when there is no other job of the same user on the nodes. - make better scheduling behaviour for dependency jobs - API: added missing stop_time into /jobs/details version 2.4.4: -------------- - oar_resource_init: bad awk delimiter. There's a space and if the property is the first one then there is not a ','. - job suspend: oardo does not exist anymore (long long time ago). Replace it with oardodo. - oarsub: when an admission rule died micheline returns an integer and not an array ref. Now oarsub ends nicely. - Monika: add a link on each jobid on the node display area. - sshd_config: with nodes with a lot of core, 10 // connections could be too few version 2.4.3: -------------- - Hulot module now has customizable keepalive feature - Added a hook to launch a healing command when nodes are suspected (activate the SUSPECTED_HEALING_EXEC_FILE variable) - Bugfix #9995: oaraccouting script doesn't freeze anymore when db is unreachable. - Bugfix #9990: prevent from inserting jobs with invalid username (like an empty username) - Oarnodecheck improvements: node is not checked if a job is already running - New oaradmin option: --auto-offset - Feature request #10565: add the possibility to check the aliveness of the nodes of a job at the end of this one (pingchecker) version 2.4.2: -------------- - New "Hulot" module for intelligent and configurable energy saving - Bug #9906: fix bad optimization in the gantt lib (so bad scheduling version 2.4.1: -------------- - Bug #9038: Security flaw in oarsub --notify option - Bug #9601: Cosystem jobs are no more killed when a resource is set to Absent - Fixed some packaging bugs - API bug fixes in job submission parsing - Added standby info into `oarnodes -s` and available_upto info into /resources uri of the API - Bug Grid'5000 #2687 Fix possible crashes of the scheduler. - Bug fix: with MySQL DB Finaud suspected resources which are not of the "default" type. - Signed debian packages (install oar-keyring package) version 2.4.0: -------------- - Bug #8791: added CHECK_NODES_WITH_RUNNING_JOB=no to prevent from checking occupied nodes - Fix bug in oarnodesetting command generated by oar_resources_init (detect_resources) - Added a --state option to oarstat to only get the status of specified jobs (optimized query, to allow scripting) - Added a REST API for OAR and OARGRID - Added JSON support into oarnodes, oarstat and oarsub - New Makefile adapted to build packages as non-root user - add the command "oar_resources_init" to easily detect and initialize the whole resources of a cluster. - "oaradmin version" : now retrieve the most recent database schema number - Fix rights on the "schema" table in postgresql. - Bug #7509: fix bug in add_micheline_subjob for array jobs + jobtypes - Ctrl-C was not working anymore in oarsub. It seems that the signal handler does not handle the previous syntax ($SIG = 'qdel') - Fix bug in oarsh with the "-l" option - Bug #7487: bad initialisation of the gnatt for the container jobs. - Scheduler: move the "delete_unnecessary_subtrees" directly into "find_first_hole". Thus this is possible to query a job like:: oarsub -I -l nodes=1/core=1+nodes=4/core=2 (no hard separation between each group) For the same behaviour as before, you can query: oarsub -I -l {prop=1}/nodes=1/core=1+{prop=2}/nodes=4/core=2 - Bug #7634: test if the resource property value is effectively defined otherwise print a '' - Optional script to take into account cpu/core topology of the nodes at boot time (to activate inside oarnodesetting_ssh) - Bug #7174: Cleaned default PATH from "./" into oardodo - Bug #7674: remove the computation of the scheduler_priority field for besteffort jobs from the asynchronous OAR part. Now the value is set when the jobs are turned into toLaunch state and in Error/Terminated. - Bug #7691: add --array and --array-param-file options parsing into the submitted script. Fix also some parsing errors. - Bug #7962: enable resource property "cm_availability" to be manipulated by the oarnodesetting command - Added the (standby) information to a node state in oarnodes when it's state is Absent and cm_availability != 0 - Changed the name of cm_availability to available_upto which is more relevant - add a --maintenance option to oarnodesetting that sets the state of a resource to Absent and its available_upto to 0 if maintenance is on and resets previous values if maintenance is off. - added a --signal option to oardel that allow a user to send a signal to one of his jobs - added a name field in the schema table that will refer to the OAR version name - added a table containing scheduler name, script and description - Bug #8559: Almighty: Moved OAREXEC_XXXX management code out of the queue for immediate action, to prevent potential problems in case of scheduler timeouts. - oarnodes, oarstat and the REST API are no more making retry connections to the database in case of failure, but exit with an error instead. The retry behavior is left for daemons. - improved packaging (try to install files in more standard places) - improved init script for Almighty (into deb and rpm packages) - fixed performance issue on oarstat (array_id index missing) - fixed performance issue (job_id index missing in event_log table) - fixed a performance issue at job submission (optimized a query and added an index on challenges table) decisions). version 2.3.5: -------------- - Bug #8139: Drawgantt nil error (Add condition to test the presence of nil value in resources table.) - Bug #8416: When a the automatic halt/wakeup feature is enabled then there was a problem to determine idle nodes. - Debug a mis-initialization of the Gantt with running jobs in the metascheduler (concurrency access to PG database) version 2.3.4: -------------- - add the command "oar_resources_init" to easily detect and initialize the whole resources of a cluster. - "oaradmin version" : now retrieve the most recent database schema number - Fix rights on the "schema" table in postgresql. - Bug #7509: fix bug in add_micheline_subjob for array jobs + jobtypes - Ctrl-C was not working anymore in oarsub. It seems that the signal handler does not handle the previous syntax ($SIG = 'qdel') - Bug #7487: bad initialisation of the gnatt for the container jobs. - Fix bug in oarsh with the "-l" option - Bug #7634: test if the resource property value is effectively defined otherwise print a '' - Bug #7674: remove the computation of the scheduler_priority field for besteffort jobs from the asynchronous OAR part. Now the value is set when the jobs are turned into toLaunch state and in Error/Terminated. - Bug #7691: add --array and --array-param-file options parsing into the submitted script. Fix also some parsing errors. - Bug #7962: enable resource property "cm_availability" to be manipulated by the oarnodesetting command version 2.3.3: -------------- - Fix default admission rules: case unsensitive check for properties used in oarsub - Add new oaradmin subcommand : oaradmin conf. Useful to edit conf files and keep changes in a Subversion repository. - Kill correctly each taktuk command children in case of a timeout. - New feature: array jobs (option --array) (on oarsub, oarstat oardel, oarhold and oarresume) and file-based parametric array jobs (oarsub --array-param-file) /!\ in this version the DB scheme has changed. If you want to upgrade your installation from a previous 2.3 release then you have to execute in your database one of these SQL script (stop OAR before):: mysql: DB/mysql_structure_upgrade_2.3.1-2.3.3.sql postgres: DB/pg_structure_upgrade_2.3.1-2.3.3.sql version 2.3.2: -------------- - Change scheduler timeout implementation to schedule the maximum of jobs. - Bug #5879: do not show initial_request in oarstat when it is not a job of the user who launched the oarstat command (oar or root). - Add a --event option to oarnodes and oarstat to display events recorded for a job or node - Display reserved resources for a validated waiting reservation, with a hint in their state - Fix oarproperty: property names are lowercase - Fix OAR_JOB_PROPERTIES_FILE: do not display system properties - Add a new user command: oarprint which allow to pretty print resource properties of a job - Debug temporary job UID feature - Add 'kill -9' on subprocesses that reached a timeout (avoid Perl to wait something) - desktop computing feature is now available again. (ex: oarsub -t desktop_computing date) - Add versioning feature for admission rules with Subversion version 2.3.1: -------------- - Add new oarmonitor command. This will permit to monitor OAR jobs on compute nodes. - Remove sudo dependency and replace it by the commands "oardo" and "oardodo". - Add possibility to create a temporary user for each jobs on compute nodes. So you can perform very strong restrictions for each job (ex: bandwidth restrictions with iptable, memory management, ... everything that can be handled with a user id) - Debian packaging: Run OAR specific sshd with root privileges (under heavy load, kernel may be more responsive for root processes...) - Remove ALLOWED_NETWORKS tag in oar.conf (added more complexeity than resolving problems) - /!\ change database scheme for the field *exit_code* in the table *jobs*. Now *oarstat* *exit_code* line reflects the right exit code of the user passive job (before, even when the user script was not launched the *exit_code* was 0 which was BAD) - /!\ add DB field *initial_request* in the table *jobs* that stores the oarsub line of the user - Feature Request #4868: Add a parameter to specify what the "nodes" resource is a synomym for. Network_address must be seen as an internal data and not used. - Scheduler: add timeout for each job == 1/4 of the remaining scheduler timeout. - Bug #4866: now the whole node is Suspected instead of just the par where there is no job onto. So it is possible to have a job on Suspected nodes. - Add job walltime (in seconds) in parameter of prologue and epilogue on compute nodes. - oarnodes does not show system properties anymore. - New feature: container job type now allows to submit inner jobs for a scheduling within the container job - Monika refactoring and now in the oar packaging. - Added a table schema in the db with the field version, reprensenting the version of the db schema. - Added a field DB_PORT in the oar config file. - Bug #5518: add right initialization of the job user name. - Add new oaradmin command. This will permit to create resources and manage admission rules more easily. - Bug #5692: change source code into a right Perl 5.10 syntax. version 2.2.12: --------------- - Bug #5239: fix the bug if there are spaces into job name or project - Fix the bug in Iolib if DEAD_SWITCH_TIME >0 - Fix a bug in bipbip when calling the cpuset_manager to clean jobs in error - Bug #5469: fix the bug with reservations and Dead resources - Bug #5535: checks for reservations made at a same time was wrong. - New feature: local checks on nodes can be plugged in the oarnodecheck mechanism. Results can be asynchronously checked from the server (taktuk ping checker) - Add 2 new tables to keep track of the scheduling decisions (gantt_jobs_predictions_log and gantt_jobs_resources_log). This will help debugging scheduling troubles (see SCHEDULER_LOG_DECISIONS in oar.conf) - Now reservations are scheduled only once (at submission time). Resources allocated to a reservations are definitively set once the validated is done and won't change in next scheduler's pass. - Fix DrawGantt to not display besteffort jobs in the future which is meaningless. version 2.2.11: --------------- - Fix Debian package dependency on a CGI web server. - Fix little bug: remove notification (scheduled start time) for Interactive reservation. - Fix bug in reservation: take care of the SCHEDULER_JOB_SECURITY_TIME for reservations to check. - Fix bug: add a lock around the section which creates and feed the OAR cpuset. - Taktuk command line API has changed (we need taktuk >= 3.6). - Fix extra ' in the name of output files when using a job name. - Bug #4740: open the file in oarsub with user privileges (-S option) - Bug #4787: check if the remote socket is defined (problem of timing with nmap) - Feature Request #4874: check system names when renaming properties - DrawGantt can export charts to be reused to build a global multi-OAR view (e.g. DrawGridGantt). - Bug #4990: DrawGantt now uses the database localtime as its time reference. version 2.2.10: --------------- - Job dependencies: if the required jobs do not have an exit code == 0 and in the state Terminated then the schedulers refuse to schedule this job. - Add the possibility to disable the halt command on nodes with cm_availability value. - Enhance oarsub "-S" option (more #OAR parsed). - Add the possibility to use oarsh without configuring the CPUSETs (can be useful for users that don't want to configure there ssh keys) version 2.2.9: -------------- - Bug 4225: Dump only 1 data structure when using -X or -Y or -D. - Bug fix in Finishing sequence (Suspect right nodes). version 2.2.8: -------------- - Bug 4159: remove unneeded Dump print from oarstat. - Bug 4158: replace XML::Simple module by XML::Dumper one. - Bug fix for reservation (recalculate the right walltime). - Print job dependencies in oarstat. version 2.2.7: -------------- version 2.2.11: --------------- - Fix Debian package dependency on a CGI web server. - Fix little bug: remove notification (scheduled start time) for Interactive reservation. - Fix bug in reservation: take care of the SCHEDULER_JOB_SECURITY_TIME for reservations to check. - Fix bug: add a lock around the section which creates and feed the OAR cpuset. - Taktuk command line API has changed (we need taktuk >= 3.6). - Fix extra ' in the name of output files when using a job name. - Bug #4740: open the file in oarsub with user privileges (-S option) - Bug #4787: check if the remote socket is defined (problem of timing with nmap) - Feature Request #4874: check system names when renaming properties - DrawGantt can export charts to be reused to build a global multi-OAR view (e.g. DrawGridGantt). - Bug #4990: DrawGantt now uses the database localtime as its time reference. version 2.2.10: --------------- - Job dependencies: if the required jobs do not have an exit code == 0 and in the state Terminated then the schedulers refuse to schedule this job. - Add the possibility to disable the halt command on nodes with cm_availability value. - Enhance oarsub "-S" option (more #OAR parsed). - Add the possibility to use oarsh without configuring the CPUSETs (can be useful for users that don't want to configure there ssh keys) version 2.2.9: -------------- - Bug 4225: Dump only 1 data structure when using -X or -Y or -D. - Bug fix in Finishing sequence (Suspect right nodes). version 2.2.8: -------------- - Bug 4159: remove unneeded Dump print from oarstat. - Bug 4158: replace XML::Simple module by XML::Dumper one. - Bug fix for reservation (recalculate the right walltime). - Print job dependencies in oarstat. version 2.2.7: -------------- - Bug 4106: fix oarsh and oarcp issue with some options (erroneous leading space). - Bug 4125: remove exit_code data when it is not relevant. - Fix potential bug when changing asynchronously the state of the jobs into "Terminated" or "Error". version 2.2.6: -------------- - Bug fix: job types was not sent to cpuset manager script anymore. (border effect from bug 4069 resolution) version 2.2.5: -------------- - Bug fix: remove user command when oar execute the epilogue script on the nodes. - Clean debug and mail messages format. - Remove bad oarsub syntax from oarsub doc. - Debug xauth path. - bug 3995: set project correctly when resubmitting a job - debug 'bash -c' on Fedora - bug 4069: reservations with CPUSET_ERROR (remove bad hosts and continue with a right integrity in the database) - bug 4044: fix free resources query for reservation (get the nearest hole from the beginning of the reservation) - bug 4013: now Dead, Suspected and Absent resources have different colors in drawgantt with a popup on them. version 2.2.4: -------------- - Redirect third party commands into oar.log (easier to debug). - Add user info into drawgantt interface. - Some bug fixes. version 2.2.3: -------------- - Debug prologue and epilogue when oarexec receives a signal. version 2.2.2: -------------- - Switch nice value of the user processes into 0 in oarsh_shell (in case of sshd was launched with a different priority). - debug taktuk zombies in pingchecker and oar_Tools version 2.2.1: -------------- - install the "allow_clasic_ssh" feature by default - debug DB installer version 2.2: ------------ - oar_server_proepilogue.pl: can be used for server prologue and epilogue to authorize users to access to nodes that are completely allocated by OAR. If the whole node is assigned then it kills all jobs from the user if all cpus are assigned. - the same thing can be done with cpuset_manager_PAM.pl as the script used to configure the cpuset. More efficent if cpusets are configured. - debug cm_availability feature to switch on and off nodes automatically depending on waiting jobs. - reservations now take care of cm_availability field version 2.1.0: -------------- - add "oarcp" command to help the users to copy files using oarsh. - add sudo configuration to deal with bash. Now oarsub and oarsh have the same behaviour as ssh (the bash configuration files are loaded correctly) - bug fix in drawgantt (loose jobs after submission of a moldable one) - add SCHEDULER_RESOURCES_ALWAYS_ASSIGNED_TYPE into oar.conf. Thus admin can add some resources for each jobs (like frontale node) - add possibility to use taktuk to check the aliveness of the nodes - %jobid% is now replaced in stdout and stderr file names by the effective job id - change interface to shu down or wake up nodes automatically (now the node list is read on STDIN) - add OARSUB_FORCE_JOB_KEY in oar.conf. It says to create a job ssh key by default for each job. - %jobid% is now replaced in the ssh job key name (oarsub -k ...). - add NODE_FILE_DB_FIELD_DISTINCT_VALUES in oar.conf that enables the admin to configure the generated containt of the OAR_NODE_FILE - change ssh job key oarsub options behaviour - add options "--reinitialize" and "--delete-before" to the oaraccounting command - cpuset are now stored in /dev/cpuset/oar - debian packaging: configure and launch a specific sshd for the user oar - use a file descriptor to send the node list --> able to handle a very large amount of nodes - every config files are now in /etc/oar/ - oardel can add a besteffort type to jobs and vis versa version 2.0.2: -------------- - add warnings and exit code to oarnodesetting when there is a bad node name or resource number - change package version - change default behaviour for the cpuset_manager.pl (more portable) - enable a user to use the same ssh key for several jobs (at his own risk!) - add node hostnames in oarstat -f - add --accounting and -u options in oarstat - bug fix on index fields in the database (syncro): bug 2020 - bug fix about server pro/epilogue: bug 2022 - change the default output of oarstat. Now it is usable: bug 1875 - remove keys in authorized_keys of oar (on the nodes) that do not correspond to an active cpuset (clean after a reboot) - reread oar.conf after each database connection tries - add support for X11 forwarding in oarsub -I and -C - debug mysql initialization script in debian package - add a variable in oarsh for the default options of ssh to use (more useful to change if the ssh version installed does not handle one of these options) - read oar.conf in oarsh (so admin can more easily change options in this script) - add support for X11 forwarding via oarsh - change variable for oarsh: OARSH_JOB_ID --> OAR_JOB_ID version 2.0.0: -------------- - Now, with the ability to declare any type of resources like licences, VLAN, IP range, computing resources must have the type *default* and a network_address not null. - Possibility to declare associated resources like licences, IP ranges, ... and to reserve them like others. - Now you can connect to your jobs (not only for reservations). - Add "cosystem" job type (execute and do nothing for these jobs). - New scheduler : "oar_sched_gantt_with_timesharing". You can specify jobs with the type "timesharing" that indicates that this scheduler can launch more than 1 job on a resource at a time. It is possible to restrict this feature with words "user and name". For example, '-t timesharing=user,name' indicates that only a job from the same user with the same name can be launched in the same time than it. - Add PostGresSQL support. So there is a choice to make between MySQL and PostgresSQL. - New approach for the scheduling : administrators have to insert into the databases descriptions about resources and not nodes. Resources have a network address (physical node) and properties. For example, if you have dual-processor, then you can create 2 different resources with the same natwork address but with 2 different processor names. - The scheduler can now handle resource properties in a hierarchical manner. Thus, for example, you can do "oarsub -l /switch=1/cpu=5" which submit a job on 5 processors on the same switch. - Add a signal handler in oarexec and propagate this signal to the user process. - Support '#OAR -p ...' options in user script. - Add in oar.conf: * DB_BASE_PASSWD_RO : for security issues, it is possible to execute request with parts specified by users with a read only account (like "-p" option). * OARSUB_DEFAULT_RESOURCES : when nothing is specified with the oarsub command then OAR takes this default resource description. * OAREXEC_DEBUG_MODE : turn on or off debug mode in oarexec (create /tmp/oar/oar.log on nodes). * FINAUD_FREQUENCY : indicates the frequency when OAR launchs Finaud (search dead nodes). * SCHEDULER_TIMEOUT : indicates to the scheduler the amount of time after what it must end itself. * SCHEDULER_JOB_SECURITY_TIME : time between each job. * DEAD_SWITCH_TIME : after this time Absent and Suspected resources are turned on the Dead state. * PROLOGUE_EPILOGUE_TIMEOUT : the possibility to specify a different timeout for prologue and epilogue (PROLOGUE_EPILOGUE_TIMEOUT). * PROLOGUE_EXEC_FILE : you can specify the path of the prologue script executed on nodes. * EPILOGUE_EXEC_FILE : you can specify the path of the epilogue script executed on nodes. * GENERIC_COMMAND : a specific script may be used instead of ping to check aliveness of nodes. The script must return bad nodes on STDERR (1 line for a bad node and it must have exactly the same name that OAR has given in argument of the command). * JOBDEL_SOFTWALLTIME : time after a normal frag that the system waits to retry to frag the job. * JOBDEL_WALLTIME : time after a normal frag that the system waits before to delete the job arbitrary and suspects nodes. * LOG_FILE : specify the path of OAR log file (default : /var/log/oar.log). - Add wait() in pingchecker to avoid zombies. - Better code modularization. - Remove node install part to launch jobs. So it is easier to upgrade from one version to an other (oarnodesetting must already be installed on each nodes if we want to use it). - Users can specify a method to be notified (mail or script). - Add cpuset support - Add prologue and epilogue script to be executed on the OAR server before and after launching a job. - Add dependancy support between jobs ("-a" option in oarsub). - In oarsub you can specify the launching directory ("-d" option). - In oarsub you can specify a job name ("-n" option). - In oarsub you can specify stdout and stderr file names. - User can resubmit a job (option "--resubmit" in oarsub). - It is possible to specify a read only database account and it will be used to evaluate SQL properties given by the user with the oarsub command (more scecure). - Add possibility to order assigned resources with their properties by the scheduler. So you can privilege some resources than others (SCHEDULER_RESOURCE_ORDER tag in oar.conf file) - a command can be specified to switch off idle nodes (SCHEDULER_NODE_MANAGER_SLEEP_CMD, SCHEDULER_NODE_MANAGER_IDLE_TIME, SCHEDULER_NODE_MANAGER_SLEEP_TIME in oar.conf) - a command can be specified to switch on nodes in the Absent state according to the resource property *cm_availability* in the table resources (SCHEDULER_NODE_MANAGER_WAKE_UP_CMD in oar.conf). - if a job goes in Error state and this is not its fault then OAR will resubmit this one. oar-2.5.7/GUIDELINES0000644015014700017500000000023712677211234013303 0ustar neyronneyronFor syntax and name conventions see: http://www.perl.com/doc/manual/html/pod/perlstyle.html (for now not the whole code is compatible with these guidelines) oar-2.5.7/tests/0000755015014700017500000000000012677211234013070 5ustar neyronneyronoar-2.5.7/tests/test_gantt_overlap.pl0000755015014700017500000000450112677211234017334 0ustar neyronneyron#!/usr/bin/perl # $Id$ # Description: # Simple script to check that a gantt is correct, with regard to overlaping jobs # Usage: # oarstat -g "2008-04-29 18:00:00, 2008-04-30 08:00:00" | ./test_gantt_overlap.pl # Todo: # - handle timesharing jobs # - handle container jobs # - ... use strict; use Data::Dumper; my $gantt_input; while () { $gantt_input .= $_; } my $gantt = eval($gantt_input); my $jobs = $gantt->{jobs}; my @jobids = keys(%$jobs); sub match($$) { my $a1 = shift; my $a2 = shift; my %h; my @res; foreach my $k (@$a1,@$a2) { if (exists($h{$k})) { push @res,$k; } $h{$k}=undef; } return @res; } while (my $jobid0 = shift(@jobids)) { foreach my $jobidN (@jobids) { if (( # job0 across jobN start_time $jobs->{$jobid0}->{start_time} <= $jobs->{$jobidN}->{start_time} and $jobs->{$jobid0}->{stop_time} >= $jobs->{$jobidN}->{start_time} ) or ( # job0 across jobN stop_time $jobs->{$jobid0}->{start_time} <= $jobs->{$jobidN}->{stop_time} and $jobs->{$jobid0}->{stop_time} >= $jobs->{$jobidN}->{stop_time} ) or ( # job0 within jobN $jobs->{$jobid0}->{start_time} >= $jobs->{$jobidN}->{start_time} and $jobs->{$jobid0}->{stop_time} <= $jobs->{$jobidN}->{stop_time} )) { my @m = match($jobs->{$jobid0}->{resources},$jobs->{$jobidN}->{resources}); if ($#m > 0) { # exceptions my $ok; foreach my $r ($jobid0,$jobidN) { my $j = ($r == $jobid0)?$jobidN:$jobid0; if ( # besteffort $jobs->{$r}->{queue_name} eq 'besteffort' and $jobs->{$j}->{queue_name} ne 'besteffort' and $jobs->{$r}->{state} eq 'Waiting' and #other states ? $jobs->{$j}->{state} eq 'Waiting' and #other states ? $jobs->{$r}->{start_time} < $jobs->{$j}->{start_time} ) { $ok=1; } elsif (0) { # container } elsif (0) { # timesharing } last if (defined($ok)) } unless (defined($ok)) { print "CONFLICT: $jobid0 and $jobidN\n"; foreach my $j ($jobid0,$jobidN) { print "|-[$j]-start_time: ".localtime($jobs->{$j}->{start_time})."\n"; print "|-[$j]-stop_time: ".localtime($jobs->{$j}->{stop_time})."\n"; print "|-[$j]-user: ".$jobs->{$j}->{user}."\n"; print "|-[$j]-walltime: ".$jobs->{$j}->{walltime}."\n"; } print "`-conficting resources: ".join(", ",@m)."\n"; } } } } } oar-2.5.7/tests/Vagrantfile0000644015014700017500000000256612677211234015266 0ustar neyronneyron# -*- mode: ruby -*- # vi: set ft=ruby : # Build your own debian base box : # # 1) Install kameleon # $ gem install kameleon-builder # # 2) Build a new vagrant box # a) For virtualbox users : # $ cd misc/kameleon/kameleon2 # $ sudo kameleon build debian_oar_vagrant # $ vagrant box add 'oar-team/debian-oar-2.5' builds/debian_oar_vagrant/debian_oar_vagrant.box # $ sudo rm -rf builds # # 3) Up ! # $ vagrant up Vagrant.configure("2") do |config| config.vm.box = "oar-team/debian-oar-2.5" config.vm.hostname = "oar-devel" # share src folder with all nodes config.vm.synced_folder ".", "/vagrant", disabled: true config.vm.synced_folder ".", "/home/vagrant/oar", type: "rsync" # enable ssh forward agent for all VMs config.ssh.forward_agent = true config.vm.network "forwarded_port", guest: 80, host: 8080 # Config provider config.vm.provider :virtualbox do |vm| vm.memory = 1024 vm.cpus = 1 end # proxy cache with polipo if Vagrant.has_plugin?("vagrant-proxyconf") config.proxy.http = "http://10.10.10.1:8123/" config.proxy.https = "http://10.10.10.1:8123/" config.proxy.ftp = "http://10.10.10.1:8123/" config.proxy.no_proxy = "localhost,127.0.0.1" config.apt_proxy.http = "http://10.10.10.1:8123/" config.apt_proxy.https = "http://10.10.10.1:8123/" config.apt_proxy.ftp = "http://10.10.10.1:8123/" end end oar-2.5.7/tests/rspec/0000755015014700017500000000000012677211234014204 5ustar neyronneyronoar-2.5.7/tests/rspec/job_submit_spec.rb0000644015014700017500000000560212677211234017703 0ustar neyronneyron$LOAD_PATH << '.' require 'oarrestapi_lib' USER=ENV['USER'] $jobid = "" describe OarApi do before :all do # Custom variables # APIURI="http://www.grenoble.grid5000.fr/oarapi" #Object of OarApis class @oar_server = OarApi.new(APIURI) end describe "Submission" do #Submitting a job it "should submit a job successfully " do script="#!/bin/bash #OAR --name rspec_test wc -l $OAR_FILE_NODES > #{ENV['HOME']}/$OAR_JOB_ID.count echo \"Hello World\" pwd whoami sleep 120 " job = { 'resource' => "/nodes=1/core=2" , 'script' => script, 'scanscript' => 1 } lambda { @oar_server.submit_job(job) }.should_not raise_exception @oar_server.jobstatus['id'].to_i.should > 0 $jobid=@oar_server.jobstatus['id'] end end #Checking the queue (Can use GET /jobs to check) immediately. describe "Submitted job" do before :all do lambda { @oar_server.full_job_details }.should_not raise_exception end it "should have id in current queue" do timeout=60 found=0 t=0 while found==0 && t < timeout do @oar_server.jobarray['items'].each do |j| found=1 if j["id"] == $jobid && j["state"] == "Running" end @oar_server.full_job_details sleep 1 t += 1 printf "." $stdout.flush end found.should==1 end it "should be named 'rspec_test'" do @oar_server.specific_job_details($jobid) @oar_server.specificjobdetails["name"].should == "rspec_test" end it "should have created a file into $HOME" do sleep 1 File.exists?("#{ENV['HOME']}/#{$jobid}.count").should == true end it "should return the good number of resources into the created file" do f = File.open("#{ENV['HOME']}/#{$jobid}.count") f.gets.to_i.should == 2 end end #Delete the job describe "Deletion" do it "should delete the currently submitted job using the post api and jobid" do lambda { @oar_server.del_job($jobid) }.should_not raise_exception @oar_server.deletestatus['status'].should == "Delete request registered" end #Check the queue to ensure the job deleted is no more there #Negative Test it "should not contain the deleted job in the queue now" do timeout=60 lambda { @oar_server.full_job_details }.should_not raise_exception t=0 c=1 while t "rtest1" , 'besteffort' => "NO", 'cpuset' => 0 }, {'network_address' => "rtest1", 'besteffort' => "NO", 'cpuset' => 1 }, {'network_address' => "rtest2" , 'besteffort' => "YES", 'cpuset' => 0 }, {'network_address' => "rtest2", 'besteffort' => "YES", 'cpuset' => 1 } ] lambda { @oar_server.create_resources($resources) }.should_not raise_exception end #Checking the resources it "should return an items array " do @oar_server.resstatus['items'].should_not be_empty end it "should return 4 items " do @oar_server.resstatus['items'].length.should == 4 end it "should contain ids of newly created resources" do @oar_server.resstatus['items'].each do |item| item["id"].to_i.should be_a(Integer) end end it "should return the new resources links" do @oar_server.resstatus['items'].each do |item| @oar_server.get_link_href_from_array_by_rel(item["links"],"self").should be_a(String) end end it "should have created resources having asked properties" do i=0 @oar_server.resstatus['items'].each do |item| link=@oar_server.get_link_href_from_array_by_rel(item["links"],"self") @oar_server.get_hash(link) #puts @oar_server.value["network_address"] @oar_server.value["network_address"].should == $resources[i]["network_address"] @oar_server.value["besteffort"].should == $resources[i]["besteffort"] @oar_server.value["cpuset"].to_i.should == $resources[i]["cpuset"].to_i i+=1 end end it "should have created Alive resources" do i=0 @oar_server.resstatus['items'].each do |item| link=@oar_server.get_link_href_from_array_by_rel(item["links"],"self") @oar_server.get_hash(link) @oar_server.value["state"].should == "Alive" i+=1 end end # Cleaning it "should delete the test resources" do @oar_server.resstatus['items'].each do |item| @oar_server.post(@oar_server.api,"resources/#{item['id']}/state",{"state" => "Dead"}) @oar_server.delete_resource(item["id"]) end end end describe "Unique resource submission" do before(:all) do $resource = {'network_address' => "rtest" , 'besteffort' => "NO", 'cpuset' => 1 } lambda { @oar_server.create_resources($resource) }.should_not raise_exception end #Checking the resources it "should return an items array " do @oar_server.resstatus['items'].should_not be_empty end it "should return 1 item " do @oar_server.resstatus['items'].length.should == 1 end it "should contain id of newly created resource" do @oar_server.resstatus['items'][0]["id"].to_i.should be_a(Integer) end it "should return the new resource link" do links=@oar_server.resstatus['items'][0]["links"] @oar_server.get_link_href_from_array_by_rel(links,"self").should be_a(String) end it "should have created a resource having asked properties" do links=@oar_server.resstatus['items'][0]["links"] link=@oar_server.get_link_href_from_array_by_rel(links,"self") @oar_server.get_hash(link) @oar_server.value["network_address"].should == $resource["network_address"] @oar_server.value["besteffort"].should == $resource["besteffort"] @oar_server.value["cpuset"].to_i.should == $resource["cpuset"].to_i end it "should have created an Alive resource" do links=@oar_server.resstatus['items'][0]["links"] link=@oar_server.get_link_href_from_array_by_rel(links,"self") @oar_server.get_hash(link) @oar_server.value["state"].should == "Alive" end # Cleaning it "should delete the test resource" do id=@oar_server.resstatus['items'][0]["id"] @oar_server.post(@oar_server.api,"resources/#{id}/state",{"state" => "Dead"}) @oar_server.delete_resource(id) end end describe "Error checking" do context "(when submitting system properties)" do before(:all) do $resources = [ {'network_address' => "rtest1", 'besteffort' => "NO", 'cpuset' => 1 }, {'network_address' => "rtest2" , 'besteffort' => "YES", 'state' => 'Alive' } ] end it "should raise an exception" do lambda { @oar_server.create_resources($resources) }.should raise_exception end it "should raise a 403 error" do begin @oar_server.create_resources($resources) rescue => e e.should respond_to('http_code') e.http_code.should == 403 end end end context "(when forgetting network_address)" do before(:all) do $resources = [ {'besteffort' => "NO", 'cpuset' => 1 }, {'network_address' => "rtest2" , 'besteffort' => "YES", 'state' => 'Alive' } ] end it "should raise an exception" do lambda { @oar_server.create_resources($resources) }.should raise_exception end it "should raise a 400 error" do begin @oar_server.create_resources($resources) rescue => e e.should respond_to('http_code') e.http_code.should == 400 end end end end describe "GENERATE RESOURCES: post /resources/generate" do before(:all) do @api = OarApi.new(APIURI) generate = { 'resources' => '/nodes=node{2}.test.generate/cpu={2}/core={2}', 'properties' => { 'besteffort' => 'NO', 'available_upto' => '42' } } lambda { begin @api.value=@api.post(@api.api,"resources/generate",generate) rescue => e if e.respond_to?('http_code') puts "ERROR #{e.http_code}:\n #{e.response.body}" else puts "Parse error:" puts e.inspect end exit 1 end }.should_not raise_exception end it_should_behave_like "All list structures" it "should return correct resources" do resources=[ { 'network_address' => 'node1.test.generate', 'available_upto' => 42, 'besteffort' => 'NO', 'cpu' => '1', 'cpuset' => 0, 'core' => '1' }, { 'network_address' => 'node1.test.generate', 'available_upto' => 42, 'besteffort' => 'NO', 'cpu' => '1', 'cpuset' => 1, 'core' => '2' }, { 'network_address' => 'node1.test.generate', 'available_upto' => 42, 'besteffort' => 'NO', 'cpu' => '2', 'cpuset' => 2, 'core' => '3' }, { 'network_address' => 'node1.test.generate', 'available_upto' => 42, 'besteffort' => 'NO', 'cpu' => '2', 'cpuset' => 3, 'core' => '4' }, { 'network_address' => 'node2.test.generate', 'available_upto' => 42, 'besteffort' => 'NO', 'cpu' => '3', 'cpuset' => 0, 'core' => '5' }, { 'network_address' => 'node2.test.generate', 'available_upto' => 42, 'besteffort' => 'NO', 'cpu' => '3', 'cpuset' => 1, 'core' => '6' }, { 'network_address' => 'node2.test.generate', 'available_upto' => 42, 'besteffort' => 'NO', 'cpu' => '4', 'cpuset' => 2, 'core' => '7' }, { 'network_address' => 'node2.test.generate', 'available_upto' => 42, 'besteffort' => 'NO', 'cpu' => '4', 'cpuset' => 3, 'core' => '8' } ] i=0 @api.value["items"].each do |resource| resource.should == resources[i] i+=1 end end context "(when injecting results into POST /resources)" do before(:all) do lambda { @api.create_resources(@api.value["items"]) }.should_not raise_exception end it "should have created the resources (should return 8 items) " do @api.resstatus['items'].length.should == 8 end # Cleaning it "should delete the test resources" do @api.resstatus['items'].each do |item| @api.post(@api.api,"resources/#{item['id']}/state",{"state" => "Dead"}) @api.delete_resource(item["id"]) end end end end describe "GENERATE RESOURCES: post /resources/generate with auto_offset" do before(:all) do @api = OarApi.new(APIURI) generate = {'resources' => '/nodes=node{3}.test.generate/cpu={2}', 'auto_offset' => 1 } lambda { begin @api.value=@api.post(@api.api,"resources/generate",generate) rescue => e if e.respond_to?('http_code') puts "ERROR #{e.http_code}:\n #{e.response.body}" else puts "Parse error:" puts e.inspect end exit 1 end }.should_not raise_exception end it_should_behave_like "All list structures" it "should return resources with cpu number > 1" do @api.value["items"][0]["cpu"].to_i.should > 1 end end end oar-2.5.7/tests/rspec/format_checking_spec.rb0000644015014700017500000005274612677211234020704 0ustar neyronneyron# Rspec tests for OAR REST API format checking # Please, run this test on a kameleon appliance # If this is the first time, run it twice and do not care about the first time. $LOAD_PATH << '.' USER=ENV['USER'] require 'oarrestapi_lib' require 'shared_examples' $jobid="" $rjobid="" # Oar API specs describe OarApi do before :all do @api = OarApi.new(APIURI) end ############################################################# # Tests environment initialisation ############################################################# describe "INITIAL QUEUE" do it "should have an 'items' array " do @api.get_hash('jobs') @api.value['items'].should_not == nil end it "should submit some jobs to populate the database" do jhash = { 'resource' => "/nodes=1/core=1" , 'script' => "id" , 'array' => '15' } @api.submit_job(jhash) $jobid = @api.jobstatus['id'] $jobid.should be_a(Integer) $jobid.should > 0 # Now, we wait for the 15th job to be terminated # It is necessary for the rest of the tests to pass timeout=180 t=0 c=0 while t "/nodes=1/core=2" , 'property' => "network_address like 'node%'", 'script' => "ls;pwd;whoami;sleep 60" , 'array' => '10' } @api.submit_job(jhash) $jobid = @api.jobstatus['id'] $jobid.should be_a(Integer) $jobid.should > 0 # Now, we wait for the 4th job to be running # It is necessary for the rest of the tests to pass timeout=60 t=0 c=0 while t "/nodes=1/core=1" , 'script' => "ls;pwd;whoami;sleep 60" , 'reservation' => '2037-01-01 01:00:00' } @api.submit_job(jhash) $rjobid = @api.jobstatus['id'] $rjobid.should be_a(Integer) $rjobid.should > 0 end end ############################################################# # URIs basic structure format checking ############################################################# uris=[ "jobs","jobs/details","jobs/table", "jobs?state=Running,Waiting,Launching","jobs?state=Terminated&limit=10", "jobs?state=Running,Terminated&limit=10","jobs?from=0&to=2147483647&limit=10", "resources","resources/full" ] uris.each do |uri| describe "#{uri} basic data structure" do before(:all) do @api = OarApi.new(APIURI) @api.get_hash(uri) end it_should_behave_like "All list structures" end end ############################################################# # Specific URI tests ############################################################# describe "JOBS CHECKINGS: /jobs data structure" do before(:all) do @api = OarApi.new(APIURI) end context "(using state=Running,Launching,Waiting&limit=2)" do before(:all) do $uri="jobs?state=Running,Launching,Waiting&limit=2" @api.get_hash($uri) end it "should correctly limit the number of results" do @api.value['items'].length.should == 2 end it "should return 2 links" do @api.value['links'].length.should == 2 end it "should return a total of 11" do @api.value['total'].to_i.should == 11 end it "should return an offset of 0" do @api.value['offset'].to_i.should == 0 end it "should return a correct self link" do @api.get_self_link_href.should == "#{APIPATH}jobs?state=Running%2CLaunching%2CWaiting&limit=2&offset=0" end it "should return a correct next link" do @api.get_next_link_href.should == "#{APIPATH}jobs?state=Running%2CLaunching%2CWaiting&limit=2&offset=2" end end context "(using /jobs?state=Running&limit=2&offset=3)" do before(:all) do $uri="jobs?state=Running,Waiting,Launching&limit=2&offset=3" @api.get_hash($uri) end it "should correctly limit the number of results" do @api.value['items'].length.should == 2 end it "should return 3 links" do @api.value['links'].length.should == 3 end it "should return a total of 11" do @api.value['total'].to_i.should == 11 end it "should return an offset of 3" do @api.value['offset'].to_i.should == 3 end it "should return a correct self link" do @api.get_self_link_href.should == "#{APIPATH}jobs?state=Running%2CWaiting%2CLaunching&limit=2&offset=3" end it "should return a correct previous link" do @api.get_previous_link_href.should == "#{APIPATH}jobs?state=Running%2CWaiting%2CLaunching&limit=2&offset=1" end it "should return a correct next link" do @api.get_next_link_href.should == "#{APIPATH}jobs?state=Running%2CWaiting%2CLaunching&limit=2&offset=5" end end context "(using same as above plus Terminated jobs)" do before(:all) do $uri="jobs?state=Running,Waiting,Launching,Terminated&limit=15" @api.get_hash($uri) end it "should return a total >= 20" do @api.value['total'].to_i.should >= 20 end end context "(with state=Terminated)" do before(:all) do @api.get_hash("jobs?state=Terminated") end it "should return only terminated jobs" do @api.value['items'].each do |item| item['state'].should == "Terminated" end end end context "(with state=Running [note: add a sleep if test jobs are not yet running])" do before(:all) do @api.get_hash("jobs?state=Running&user=#{USER}") end it "should return a few running jobs" do @api.value['items'].length.should > 0 end it "should return only running jobs" do @api.value['items'].each do |item| item['state'].should == "Running" end end it "should return jobs having a correct self link" do links=@api.value['items'][0]['links'] id=@api.value['items'][0]['id'] @api.get_link_href_from_array_by_rel(links,"self").should == "#{APIPATH}jobs/#{id}" end it "should return jobs having a correct resources link" do links=@api.value['items'][0]['links'] id=@api.value['items'][0]['id'] @api.get_link_href_from_array(links,"resources").should == "#{APIPATH}jobs/#{id}/resources" end it "should return jobs owned by the #{USER} user" do @api.value['items'][0]['owner'].should == "#{USER}" end end context "(with non-existent obiwankenobi user)" do before(:all) do @api.get_hash("jobs?state=Terminated&user=obiwankenobi") end it "should return no jobs" do @api.value['items'].length.should == 0 end end context "(inside job)" do before(:all) do @api.get_hash("jobs?state=Running") @api.value=@api.value['items'][0] end it_should_behave_like "Job" end context "(with limit=1)" do before(:all) do @api.get_hash("jobs?limit=1") end it_should_behave_like "All list structures" end context "(with limit=1, insider job)" do before(:all) do @api.get_hash("jobs?limit=1") @api.value=@api.value['items'][0] end it_should_behave_like "Job" end end describe "JOB INFOS CHECKING: /jobs/ data structure" do context "(with normal job)" do before(:all) do @api = OarApi.new(APIURI) @api.get_hash("jobs/#{$jobid}") end it_should_behave_like "Job" it "should be owned by the #{USER} user" do @api.value['owner'].should == "#{USER}" end end context "(with non-existent job)" do before(:all) do @api = OarApi.new(APIURI) end it "should raise an exception" do lambda { @api.get_hash("jobs/00") }.should raise_exception end it "should return a 404 error" do begin @api.get_hash("jobs/00") rescue => e e.should respond_to('http_code') e.http_code.should == 404 end end end context "(with finished job)" do before(:all) do @api = OarApi.new(APIURI) @api.get_hash("jobs/1") end it_should_behave_like "Job" end end describe "JOB DETAILS CHECKING: /jobs//details data structure" do context "(with normal job)" do before(:all) do @api = OarApi.new(APIURI) @api.get_hash("jobs/#{$jobid}/details") @value=@api.value end it_should_behave_like "Job" it "should be owned by the #{USER} user" do @api.value['owner'].should == "#{USER}" end it "should have resources and nodes details" do @api.value['resources'].should be_an(Array) @api.value['nodes'].should be_an(Array) end context "should have resources behaving correctly" do before(:all) do @api.value=@value['resources'][0] end it_should_behave_like "ResourceId" end context "should have nodes behaving correctly" do before(:all) do @api.value=@value['nodes'][0] end it_should_behave_like "Node" it "should have a status" do @api.value.should have_key('status') end end end context "(with non-existent job)" do before(:all) do @api = OarApi.new(APIURI) end it "should raise an exception" do lambda { @api.get_hash("jobs/00/details") }.should raise_exception end it "should return a 404 error" do begin @api.get_hash("jobs/00/details") rescue => e e.should respond_to('http_code') e.http_code.should == 404 end end end context "(with finished job)" do before(:all) do @api = OarApi.new(APIURI) @api.get_hash("jobs/1/details") end it_should_behave_like "Job" end end describe "JOBS LIST DETAILS CHECKING: /jobs/details data structure" do before(:all) do @api = OarApi.new(APIURI) @api.get_hash("jobs/details") @values=@api.value end context "(basic structure)" do it_should_behave_like "All list structures" end context "(insider job)" do before(:all) do @api.value=@api.value["items"][0] end it_should_behave_like "Job" it "should have resources and nodes details" do @api.value['resources'].should be_an(Array) @api.value['nodes'].should be_an(Array) end context "should have resources behaving correctly" do before(:all) do @api.value=@values["items"][0]['resources'][0] end it_should_behave_like "ResourceId" end context "should have nodes behaving correctly" do before(:all) do @api.value=@values["items"][0]['nodes'][0] end it_should_behave_like "Node" it "should have a status" do @api.value.should have_key('status') end end end end describe "JOB RESOURCES: /jobs//resources" do before(:all) do @api = OarApi.new(APIURI) @api.get_hash("jobs/#{$jobid}/resources") end context "(basic data structure)" do it_should_behave_like "All list structures" end context "(inside resource)" do before(:all) do @api.value=@api.value['items'][0] end it_should_behave_like "ResourceId" it "should have a status field" do @api.value['status'].should_not be_nil end it "should have a valid status field (reserved or assigned)" do @api.value['status'].should match(/(reserved|assigned)/) end end end describe "JOB NODES: /jobs//nodes" do before(:all) do @api = OarApi.new(APIURI) @api.get_hash("jobs/#{$jobid}/nodes") end context "(basic data structure)" do it_should_behave_like "All list structures" end context "(inside node)" do before(:all) do @api.value=@api.value['items'][0] end it_should_behave_like "Node" end end describe "FUTUR JOBS CHECKING: /jobs" do before(:all) do @api = OarApi.new(APIURI) end context "(from 2036 to 2038)" do before(:all) do from=Time.local(2036,"jan",1,1,1,1).to_i to=Time.local(2038,"jan",1,1,1,1).to_i @api.get_hash("jobs?from=#{from}&to=#{to}") end it "should return only one job" do @api.value["items"].length.should == 1 end it "should return the previously submitted reservation" do @api.value["items"][0]["id"].should == $rjobid end end end describe "RESOURCES CHECKING: /resources" do before(:all) do @api = OarApi.new(APIURI) end context "(with limit=2)" do before(:all) do @api.get_hash("resources?limit=2") end it "should correctly limit the number of results" do @api.value['items'].length.should == 2 end it "should return 2 links" do @api.value['links'].length.should == 2 end it "should return a total > 4" do @api.value['total'].to_i.should > 4 end it "should return an offset of 0" do @api.value['offset'].to_i.should == 0 end it "should return a correct self link" do @api.get_self_link_href.should == "#{APIPATH}resources?limit=2&offset=0" end it "should return a correct next link" do @api.get_next_link_href.should == "#{APIPATH}resources?limit=2&offset=2" end end context "(with limit=2&offset=2)" do before(:all) do @api.get_hash("resources?limit=2&offset=2") end it "should correctly limit the number of results" do @api.value['items'].length.should == 2 end it "should return 3 links" do @api.value['links'].length.should == 3 end it "should return a total > 4" do @api.value['total'].to_i.should > 4 end it "should return an offset of 2" do @api.value['offset'].to_i.should == 2 end it "should return a correct self link" do @api.get_self_link_href.should == "#{APIPATH}resources?limit=2&offset=2" end it "should return a correct next link" do @api.get_next_link_href.should == "#{APIPATH}resources?limit=2&offset=4" end it "should return a correct previous link" do @api.get_previous_link_href.should == "#{APIPATH}resources?limit=2&offset=0" end end context "(inside resource)" do before(:all) do @api.get_hash("resources?limit=2&offset=1") @api.value=@api.value['items'][0] end it_should_behave_like "Resource" end context "(with limit=1)" do before(:all) do @api.get_hash("resources?limit=1") end it_should_behave_like "All list structures" end context "(with limit=1, insider job)" do before(:all) do @api.get_hash("resources?limit=1") @api.value=@api.value['items'][0] end it_should_behave_like "Resource" end end describe "RESOURCES DETAILS CHECKING: /resources/3 data structure" do before(:all) do @api = OarApi.new(APIURI) @api.get_hash("resources/3") end it_should_behave_like "Resource" end describe "NON-EXISTENT RESOURCE" do before(:all) do @api = OarApi.new(APIURI) end it "should raise an exception" do lambda { @api.get(@api.api,"resources/00") }.should raise_exception end it "should return a 404 error" do begin @api.get(@api.api,"resources/00") rescue => e e.should respond_to('http_code') e.http_code.should == 404 end end end describe "NODE RESOURCES: /resources/nodes/" do before(:all) do @api = OarApi.new(APIURI) @api.get_hash("resources?limit=1") node_link=@api.get_link_href_from_array(@api.value["items"][0]["links"],"node") @api.get_hash(node_link) end context "(basic data structure)" do it_should_behave_like "All list structures" end context "(insider resource)" do before(:all) do @api.value=@api.value['items'][0] end it_should_behave_like "ResourceId" end end describe "RESOURCES JOBS: /resources/3/jobs" do before(:all) do @api = OarApi.new(APIURI) @api.get_hash("resources/3/jobs") end context "(basic data structure)" do it_should_behave_like "All list structures" end context "(inside job)" do before(:all) do @api.value=@api.value['items'][0] end it_should_behave_like "JobId" end end describe "NODE JOBS: /resources/nodes//jobs" do before(:all) do @api = OarApi.new(APIURI) @api.get_hash("resources?limit=1") node_link=@api.get_link_href_from_array(@api.value["items"][0]["links"],"node") @api.get_hash(node_link+"/jobs") end context "(basic data structure)" do it_should_behave_like "All list structures" end context "(inside job)" do before(:all) do @api.value=@api.value['items'][0] end it_should_behave_like "JobId" end end describe "NODE JOBS: /resources/nodes//jobs with state=Running filter" do before(:all) do @api = OarApi.new(APIURI) @api.get_hash("resources?limit=1") node_link=@api.get_link_href_from_array(@api.value["items"][0]["links"],"node") @api.get_hash(node_link+"/jobs?state=Running") end context "(basic data structure)" do it_should_behave_like "All list structures" end context "(inside job)" do before(:all) do @api.value=@api.value['items'][0] end it_should_behave_like "JobId" end end describe "NODE JOBS: /resources/nodes//jobs with state=Obiwan filter" do before(:all) do @api = OarApi.new(APIURI) @api.get_hash("resources?limit=1") node_link=@api.get_link_href_from_array(@api.value["items"][0]["links"],"node") @api.get_hash(node_link+"/jobs?state=Obiwan") end it "should return an empty list of jobs" do @api.value=@api.value['items'].length.should==0 end end ############################################################# # Job submission responses checks ############################################################# describe "Job submission" do it "should return a self link" do jhash = { 'resource' => "/nodes=1/core=1" , 'script' => "ls;pwd;whoami;sleep 60"} @api.submit_job(jhash) $ljobid = @api.jobstatus['id'] @api.value= @api.jobstatus @api.get_self_link_href.should == "#{APIPATH}jobs/#{$ljobid}" end it "should return a 400 error on bad reservation date" do jhash = { 'resource' => "/nodes=1/core=1" , 'script' => "ls;pwd;whoami;sleep 60", 'reservation' => '1973-06-03 18:00:00' } begin @api.submit_job(jhash) rescue => e #puts e.response.body e.should respond_to('http_code') e.http_code.should == 400 end end end ############################################################# # Cleaning ############################################################# describe "Cleaning queue" do it "should delete the test jobs" do @api.del_array_job($jobid) @api.deletestatus['status'].should == "Delete request registered" end it "should delete the test reservation" do @api.del_array_job($rjobid) @api.deletestatus['status'].should == "Delete request registered" end it "should delete the test job" do @api.del_array_job($ljobid) @api.deletestatus['status'].should == "Delete request registered" end end ############################################################# # Resubmission ############################################################# describe "Re-submission of a terminated job" do before(:all) do # Wait for the 2nd job to be terminated timeout=180 t=0 c=0 while t e puts e.response.body end end it "should have a self link" do @api.get_self_link_href.should == "#{APIPATH}jobs/#{@api.value['id']}" end it "should have a parent link" do @api.get_link_href_by_rel('parent').should == "#{APIPATH}jobs/#{$jobid+1}" end it "should delete the test job (cleaning)" do @api.del_job(@api.value['id']) @api.deletestatus['status'].should == "Delete request registered" end end end oar-2.5.7/tests/rspec/shared_examples.rb0000644015014700017500000001131312677211234017674 0ustar neyronneyron# All data structures minimum requirements shared_examples_for "All structures" do specify { @api.value.should have_key('api_timestamp') } specify('api_timestamp should be an integer') { @api.value['api_timestamp'].should be_a(Integer) } specify { @api.value.should have_key('links') } specify('links should be an array') { @api.value['links'].should be_an(Array) } specify('links should not be empty') { @api.value['links'].should_not be_empty } specify('self link should not be nil') { @api.get_self_link_href.should_not be_nil } end shared_examples_for "All list structures" do it_should_behave_like "All structures" specify { @api.value.should have_key('items') } specify('items should be an array') { @api.value['items'].should be_an(Array) } specify { @api.value['items'].should_not be_empty } specify { @api.value.should have_key('total') } specify('total should be an integer') { @api.value['total'].should be_a(Integer) } specify('total should be positive') { @api.value['total'].to_i.should > 0} specify { @api.value.should have_key('offset') } specify('offset should be an integer') { @api.value['offset'].should be_a(Integer) } end # Item structure minimum requirements shared_examples_for "Item" do it_should_behave_like "All structures" specify { @api.value.should have_key('id') } specify('id should be an integer') { @api.value['id'].should be_a(Integer) } specify('should have a self link') { @api.get_self_link_href.should be_a(String) } end # Job structure minimum requirements shared_examples_for "JobId" do it_should_behave_like "Item" specify('self link should be correct') { @api.get_self_link_href.should == "#{APIPATH}jobs/#{@api.value['id']}" } end shared_examples_for "Job" do it_should_behave_like "JobId" specify { @api.value.should have_key('owner') } specify('job owner should not be nil') { @api.value['owner'].should_not be_nil } specify { @api.value.should have_key('state') } specify('job state should not be nil') { @api.value['state'].should_not be_nil } specify { @api.value.should have_key('queue') } specify('job queue should not be nil') { @api.value['queue'].should_not be_nil } specify { @api.value.should have_key('name') } specify('resources link should not be nil') { @api.get_link_href('resources').should_not be_nil } specify('resources link should be correct') { @api.get_link_href('resources').should == "#{APIPATH}jobs/#{@api.value['id']}/resources" } specify('nodes link should not be nil') { @api.get_link_href('nodes').should_not be_nil } specify('nodes link should be correct') { @api.get_link_href('nodes').should == "#{APIPATH}jobs/#{@api.value['id']}/nodes" } specify('array_id should be an integer') { if not @api.value['array_id'].nil? @api.value['array_id'].should be_a(Integer) end } specify('start_time should be an integer') { if not @api.value['start_time'].nil? @api.value['start_time'].should be_a(Integer) end } specify('exit_code should be an integer') { if not @api.value['exit_code'].nil? @api.value['exit_code'].should be_a(Integer) end } end # Resource structure minimum requirements shared_examples_for "ResourceId" do it_should_behave_like "Item" specify('self link should be correct') { @api.get_self_link_href.should == "#{APIPATH}resources/#{@api.value['id']}" } specify('available_upto should be an integer') { if not @api.value['available_upto'].nil? @api.value['available_upto'].should be_a(Integer) end } end shared_examples_for "Resource" do it_should_behave_like "ResourceId" specify { @api.value.should have_key('state') } specify('resource state should not be nil') { @api.value['state'].should_not be_nil } specify { @api.value.should have_key('network_address') } specify { @api.value.should have_key('available_upto') } specify('node link should not be nil') { @api.get_link_href('node').should_not be_nil } specify('jobs link should not be nil') { @api.get_link_href('jobs').should_not be_nil } end # Node structure minimum requirements shared_examples_for "Node" do it_should_behave_like "All structures" specify('should have a self link') { @api.get_self_link_href.should be_a(String) } specify('self link should be correct') { @api.get_self_link_href.should == "#{APIPATH}resources/nodes/#{@api.value['network_address']}" } specify { @api.value.should have_key('network_address') } end oar-2.5.7/tests/rspec/oarrestapi_lib.rb0000644015014700017500000003761212677211234017541 0ustar neyronneyron#require 'rubygems' require 'rest_client' require 'json' require 'pp' require 'uri' USER=ENV['USER'] APIURI="http://#{USER}:#{USER}@localhost/oarapi-priv/" unless ENV['APIURI'] APIURI=ENV['APIURI'] if ENV['APIURI'] api_uri = URI(APIURI) APIPATH=api_uri.path ####################################################################### #Coded By Narayanan K - GSOC Testsuites project - RESTful API Library # Modified by B. Bzeznik 2010-2011 ####################################################################### class OarApi attr_accessor :jobhash, :statushash, :specificjobdetails, :oarv, :oartz, :jobarray, :deletehash, :apiuri, :value attr_reader :deletestatus,:jobstatus,:api,:chkpointstatus,:holdjob,:rholdjob,:signalreturn,:resumejob,:resources,:resourcedetails,:resstatus,:specificres,:noderesources def initialize(apiuri,get_uri="") @api = RestClient::Resource.new apiuri @apiuri = URI.parse(apiuri) end # Converts the given uri, to something relative # to the base of the API def rel_uri(uri) abs_uri=@apiuri.merge(uri).to_s target_uri=URI.parse(abs_uri).to_s @apiuri.route_to(target_uri).to_s end ######################################################################## # # GET REST OAR API # # Purpose: Function to get objects from the api # # Result: We use the JSON format # ######################################################################## def get(api,uri) uri=rel_uri(uri) # begin return JSON.parse(api[uri].get(:accept => 'application/json')) # rescue => e # if e.respond_to?('http_code') # puts "ERROR #{e.http_code}:\n #{e.response.body}" # else # puts "Parse error:" # puts e.inspect # end # exit 1 # end end ######################################################################## # # POST REST OAR API # # Purpose: Function to create/delete/hold/resume objects through the api # # Result: We use the JSON format. # ######################################################################## def post(api,uri,j) uri=rel_uri(uri) j=j.to_json return JSON.parse(api[uri].post( j,:content_type => 'application/json')) end ######################################################################## # # DELETE REST OAR API # # Purpose: Function to Delete objects through the api # # Result: We use the JSON format. # ######################################################################## def delete(api, uri) uri=rel_uri(uri) begin return JSON.parse(api[uri].delete(:content_type => 'application/json')) rescue => e if e.respond_to?('http_code') puts "ERROR #{e.http_code}:\n #{e.response.body}" else puts "Parse error:" puts e.inspect end exit 1 end end ######################################################################## # # GENERIC FUNCTIONS TO GET REST OBJECTS # ######################################################################## def get_hash(uri) @value = get(@api, uri) if !@value.is_a?(Hash) raise "Error: GET #{uri} should return a hash" end end ######################################################################## # # Method: oar_version # # Usecase01: Gives version info & Timezone about OAR and OAR API/Server. # # Input: Nil # # Result: GETs the Version details(hash)and stores in Hash oarv # ######################################################################## def oar_version @oarv = get(@api, '/version') if !@oarv.is_a?(Hash) or @oarv.empty? raise 'Error: In return value of GET /version API' end end ######################################################################## # # Method: oar_timezone # # Usecase02: Gives the timezone of the OAR API server. # # Input: Nil # # Result: GETs the Timezone details(hash)and stores in Hash oart # ######################################################################## def oar_timezone @oartz = get(@api, '/timezone') if !@oartz.is_a?(Hash) or @oartz.empty? raise 'Error: In return value of GET /timezone API' end end ######################################################################## # # Method: full_job_details # # Usecase03: List the current jobs & some details like assigned resources # # Input: Nil # # Result: GETs details of current jobs(array of hashes)& stores in jobhash # ######################################################################## def full_job_details @jobarray = get(@api,'jobs/details') if !@jobarray.is_a?(Hash) raise 'Error: In return value of GET /jobs/details API' end end ######################################################################## # # Method: run_job_details # # Usecase04: List currently running jobs # # Input: Nil # # Result: GETs details of running jobs(array of hashes)& stores in jobhash # ######################################################################## def run_job_details @jobarray = get(@api,'jobs') if !@jobarray.is_a?(Hash) raise 'Error: In return value of GET /jobs API' end end ######################################################################## # # Method: specific_job_details(jobid) # # Usecase05: Get Details of a specific job # # Input: jobid # # Result: GETs details of specific job & stores in hash specificjobdetails # ######################################################################## def specific_job_details(jobid) @specificjobdetails = get(@api, "jobs/#{jobid}") if !@specificjobdetails.is_a?(Hash) or @specificjobdetails.empty? raise 'Error: In return value of GET /jobs/ API' end end ######################################################################## # # Method: dump_job_table # # Usecase06: Dump the jobs table (only current jobs) # # Input: None # # Result: Dumps details of current jobs into array of hash - jobhash # ######################################################################## def dump_job_table @jobarray = get(@api,'jobs/table') if !@jobarray.is_a?(Hash) raise 'Error: In return value of GET /jobs/table API' end end ######################################################################## # # Method: submit_job(jhash) # # Usecase07: Submits job # # Input: jhash containing details of resources,jobscript in hash form # # Result: Returns the submitted job Details in Hash and stores in jobstatus # ######################################################################## def submit_job(jhash) @jobstatus = post(@api, 'jobs', jhash) if !@jobstatus.is_a?(Hash) or @jobstatus.empty? raise 'Error: In return value of POST /jobs API' end end ######################################################################## # # Method: del_job(jobid) # # Usecase08: Delete job - POST /jobs/id/deletions/new # # Input: jobid # # Result: Returns the deleted job Details in Hash and stores in deletestatus # ######################################################################## def del_job(jobid) @deletestatus = post(@api,"jobs/#{jobid}/deletions/new", '') if !@deletestatus.is_a?(Hash) or @deletestatus.empty? raise 'Error: In return value of POST /jobs//deletions/new API' end end def del_array_job(jobid) @deletestatus = post(@api,"jobs/array/#{jobid}/deletions/new", '') if !@deletestatus.is_a?(Hash) or @deletestatus.empty? raise 'Error: In return value of POST /jobs/array//deletions/new API' end end ######################################################################## # # Method: send_checkpoint(jobid) # # Usecase09: Send checkpoint signal to a job # # Input: jobid # # Result: Returns details of checkpointed job in hash - chkpointstatus # ######################################################################## def send_checkpoint(jobid) @chkpointstatus = post(@api,"jobs/#{jobid}/checkpoints/new", '') if !@chkpointstatus.is_a?(Hash) or @chkpointstatus.empty? raise 'Error: In return value of POST /jobs//checkpoints/new API' end end ######################################################################## # # Method: hold_waiting_job(jobid) # # Usecase10: Hold a Waiting job # # Input: jobid # # Result: Returns details of holded job in hash - holdjob # ######################################################################## def hold_waiting_job(jobid) @holdjob = post(@api,"jobs/#{jobid}/holds/new", '') if !@holdjob.is_a?(Hash) or @holdjob.empty? raise 'Error: In return value of POST /jobs//holds/new API' end end ######################################################################## # # Method: hold_running_job(jobid) # # Usecase11: Hold a Running job # # Input: jobid # # Result: Returns details of holded job in hash - rholdjob # ######################################################################## def hold_running_job(jobid) @rholdjob = post(@api,"jobs/#{jobid}/rholds/new", '') if !@rholdjob.is_a?(Hash) or @rholdjob.empty? raise 'Error: In return value of POST /jobs//rholds/new API' end end ######################################################################## # # Method: resume_hold_job(jobid) # # Usecase12: Resume a Holded job # # Input: jobid # # Result: Returns details of resumed job in hash - resumejob # ######################################################################## def resume_hold_job(jobid) @resumejob = post(@api,"jobs/#{jobid}/resumption/new", '') if !@resumejob.is_a?(Hash) or @resumejob.empty? raise 'Error: In return value of POST /jobs//resumption/new API' end end ######################################################################## # # Method: send_signal_job(jobid, signo) # # Usecase13: Send signal to a job with signalno. # # Input: jobid, signal number # # Result: Returns details of signalled job in hash - signalreturn # ######################################################################## def send_signal_job(jobid, signo) @signalreturn = post(@api,"jobs/#{jobid}/signal/#{signo}", '') if !@signalreturn.is_a?(Hash) or @signalreturn.empty? raise 'Error: In return value of POST /jobs//signal/ API' end end ######################################################################## # # Method: update_job(jobid, actionhash) # # Usecase14: Update a job # # Input: jobid, actionhash # # Result: Returns details of updated job in hash - updatehash # ######################################################################## def update_job(jobid, actionhash) @updatehash = post(@api, "jobs/#{jobid}",actionhash) if !@updatehash.is_a?(Hash) or @updatehash.empty? raise 'Error: In return value of POST /jobs// API' end end ######################################################################## # # Method: resource_list_state # # Usecase15: Get list of Resources and state # # Input: None # # Result: Returns details of resources & states in array of hashes - resources # ######################################################################## def resource_list_state @resources = get(@api, 'resources') if !@resources.is_a?(Hash) raise 'Error: In return value of GET /resources API' end end ######################################################################## # # Method: list_resource_details # # Usecase16: Get list of all the resources and all their details # # Input: None # # Result: Returns details of resource list in array of hashes - resourcedetails # ######################################################################## def list_resource_details @resourcedetails = get(@api, 'resources/full') if !@resourcedetails.is_a?(Hash) raise 'Error: In return value of GET /resources/full API' end end ######################################################################## # # Method: specific_resource_details(jobid) # # Usecase17: Get details of resources identified by an ID # # Input: jobid # # Result: Returns details of specific resource in array of hashes - specificres # ######################################################################## def specific_resource_details(jobid) @specificres = get(@api, "jobs/#{jobid}/resources") if !@specificres.is_a?(Hash) or @specificres.empty? raise 'Error: In return value of GET /jobs//resources API' end end ######################################################################## # # Method: resource_of_nodes(netaddr) # # Usecase18: Get details about the resources belonging to the node identified by network address # # Input: netaddr # # Result: Returns details of resource of nodes - noderesources # ######################################################################## def resource_of_nodes(netaddr) @noderesources = get(@api,"resources/nodes/#{netaddr}") if !@noderesources.is_a?(Hash) or @noderesources.empty? raise 'Error: In return value of GET /resources/nodes/ API' end end ######################################################################## # Resource creation methods ######################################################################## def create_resource(rhash) @resstatus = post(@api,'resources', rhash) if !@resstatus.is_a?(Hash) or @resstatus.empty? raise 'Error: In return value of POST /resources API' end end def create_resources(array) @resstatus = post(@api,'resources', array) if !@resstatus.is_a?(Hash) or @resstatus.empty? raise 'Error: In return value of POST /resources API' end end ######################################################################## # # Method: statechange_resource(jobid, hasharray) # # Usecase20: Change the state of resources of a job # # Input: jobid, hasharray # # Result: Returns details of created resources in hash- statushash # ######################################################################## def statechange_resource(jobid, hasharray) @statushash = post(@api, 'resources/#{jobid}/state', hasharray) if !@statushash.is_a?(Hash) or @statushash.empty? raise 'Error: In return value of POST /resources//state API' end end ######################################################################## # # Method: delete_job(jobid) # # Usecase21: Delete or kill a job. # # Input: jobid # # Result: Returns details of deleted job in hash- deletehash # ######################################################################## def delete_job(jobid) @deletehash = delete(@api,"/jobs/#{jobid}") if !@deletehash.is_a?(Hash) or @deletehash.empty? raise 'Error: In return value of DELETE /jobs/ API' end end ######################################################################## # # Method: delete_resource(resid) # # Usecase22: Delete the resource identified by id # # Input: resid # # Result: Returns details of deleted resources in hash- deletehash # ######################################################################## def delete_resource(resid) @deletehash = delete(@api,"resources/#{resid}") if !@deletehash.is_a?(Hash) or @deletehash.empty? raise 'Error: In return value of DELETE /resources/ API' end end ######################################################################## # # Method: delete_resource_cpuset(node, cpuid) # # Usecase23: Delete the resource corresponding to cpuset id on node node. # # Input: node, cpuid # # Result: Returns details of deleted resources in hash- deletehash # ######################################################################## def delete_resource_cpuset(node, cpuid) @deletehash = delete(@api,"/resources/#{node}/#{cpuid}") if !@deletehash.is_a?(Hash) or @deletehash.empty? raise 'Error: In return value of DELETE /resources// API' end end def get_link_href(title) @value['links'].each do |link| if link.is_a?(Hash) && link['title'] == title return link['href'] end end raise "#{title} link not found!" end def get_link_href_by_rel(rel) @value['links'].each do |link| if link.is_a?(Hash) && link['rel'] == rel return link['href'] end end raise "#{rel} link not found!" end def get_self_link_href get_link_href_by_rel("self") end def get_next_link_href get_link_href_by_rel("next") end def get_previous_link_href get_link_href_by_rel("previous") end def get_link_href_from_array(array,title) array.each do |link| if link.is_a?(Hash) && link['title'] == title return link['href'] end end raise "#{title} link not found!" end def get_link_href_from_array_by_rel(array,rel) array.each do |link| if link.is_a?(Hash) && link['rel'] == rel return link['href'] end end raise "#{rel} link not found!" end end oar-2.5.7/tests/rspec/Makefile0000644015014700017500000000054612677211234015651 0ustar neyronneyronRSPEC=rspec SPEC_OPTS=--colour --format documentation all: format_checking job_submit usage: @echo "usage: make < format_checking | job_submit | resources_creation >" format_checking: ${RSPEC} format_checking_spec.rb ${SPEC_OPTS} job_submit: ${RSPEC} job_submit_spec.rb ${SPEC_OPTS} resources_creation: ${RSPEC} resources_creation_spec.rb ${SPEC_OPTS} oar-2.5.7/tests/scheduler/0000755015014700017500000000000012677211234015046 5ustar neyronneyronoar-2.5.7/tests/scheduler/data/0000755015014700017500000000000012677211234015757 5ustar neyronneyronoar-2.5.7/tests/scheduler/data/001_my.cnf0000777015014700017500000000000012677211234021145 2000_my.cnfustar neyronneyronoar-2.5.7/tests/scheduler/data/001_advance_reservation_with_absent_resource.sql0000644015014700017500000007456612677211234027422 0ustar neyronneyron-- MySQL dump 10.11 -- -- Host: localhost Database: oar -- ------------------------------------------------------ -- Server version 5.0.51a-15 /*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; /*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; /*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; /*!40101 SET NAMES utf8 */; /*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; /*!40103 SET TIME_ZONE='+00:00' */; /*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; -- -- Table structure for table `accounting` -- DROP TABLE IF EXISTS `accounting`; SET @saved_cs_client = @@character_set_client; SET character_set_client = utf8; CREATE TABLE `accounting` ( `window_start` int(10) unsigned NOT NULL, `window_stop` int(10) unsigned NOT NULL, `accounting_user` varchar(255) NOT NULL, `accounting_project` varchar(255) NOT NULL, `queue_name` varchar(100) NOT NULL, `consumption_type` enum('ASKED','USED') NOT NULL, `consumption` int(10) unsigned NOT NULL, PRIMARY KEY (`window_start`,`window_stop`,`accounting_user`,`accounting_project`,`queue_name`,`consumption_type`), KEY `accounting_user` (`accounting_user`), KEY `accounting_project` (`accounting_project`), KEY `accounting_queue` (`queue_name`), KEY `accounting_type` (`consumption_type`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1; SET character_set_client = @saved_cs_client; -- -- Dumping data for table `accounting` -- LOCK TABLES `accounting` WRITE; /*!40000 ALTER TABLE `accounting` DISABLE KEYS */; /*!40000 ALTER TABLE `accounting` ENABLE KEYS */; UNLOCK TABLES; -- -- Table structure for table `admission_rules` -- DROP TABLE IF EXISTS `admission_rules`; SET @saved_cs_client = @@character_set_client; SET character_set_client = utf8; CREATE TABLE `admission_rules` ( `id` int(10) unsigned NOT NULL auto_increment, `rule` text NOT NULL, PRIMARY KEY (`id`) ) ENGINE=MyISAM AUTO_INCREMENT=15 DEFAULT CHARSET=latin1; SET character_set_client = @saved_cs_client; -- -- Dumping data for table `admission_rules` -- LOCK TABLES `admission_rules` WRITE; /*!40000 ALTER TABLE `admission_rules` DISABLE KEYS */; INSERT INTO `admission_rules` VALUES (1,'if (not defined($queue_name)) {$queue_name=\"default\";}'),(2,'die (\"[ADMISSION RULE] root and oar users are not allowed to submit jobs.\\n\") if ( $user eq \"root\" or $user eq \"oar\" );'),(3,'\nmy $admin_group = \"admin\";\nif ($queue_name eq \"admin\") {\n my $members; \n (undef,undef,undef, $members) = getgrnam($admin_group);\n my %h = map { $_ => 1 } split(/\\s+/,$members);\n if ( $h{$user} ne 1 ) {\n {die(\"[ADMISSION RULE] Only member of the group \".$admin_group.\" can submit jobs in the admin queue\\n\");}\n }\n}\n'),(4,'\nmy @bad_resources = (\"type\",\"state\",\"next_state\",\"finaud_decision\",\"next_finaud_decision\",\"state_num\",\"suspended_jobs\",\"besteffort\",\"deploy\",\"expiry_date\",\"desktop_computing\",\"last_job_date\",\"available_upto\",\"scheduler_priority\");\nforeach my $mold (@{$ref_resource_list}){\n foreach my $r (@{$mold->[0]}){\n my $i = 0;\n while (($i <= $#{$r->{resources}})){\n if (grep(/^$r->{resources}->[$i]->{resource}$/, @bad_resources)){\n die(\"[ADMISSION RULE] \'$r->{resources}->[$i]->{resource}\' resource is not allowed\\n\");\n }\n $i++;\n }\n }\n}\n'),(5,'\nif (grep(/^besteffort$/, @{$type_list}) and not $queue_name eq \"besteffort\"){\n $queue_name = \"besteffort\";\n print(\"[ADMISSION RULE] Automatically redirect in the besteffort queue\\n\");\n}\nif ($queue_name eq \"besteffort\" and not grep(/^besteffort$/, @{$type_list})) {\n push(@{$type_list},\"besteffort\");\n print(\"[ADMISSION RULE] Automatically add the besteffort type\\n\");\n}\nif (grep(/^besteffort$/, @{$type_list})){\n if ($jobproperties ne \"\"){\n $jobproperties = \"($jobproperties) AND besteffort = \\\'YES\\\'\";\n }else{\n $jobproperties = \"besteffort = \\\'YES\\\'\";\n }\n print(\"[ADMISSION RULE] Automatically add the besteffort constraint on the resources\\n\");\n}\n'),(6,'\nif ((grep(/^besteffort$/, @{$type_list})) and ($reservationField ne \"None\")){\n die(\"[ADMISSION RULE] Error: a job cannot both be of type besteffort and be a reservation.\\n\");\n}\n'),(7,'\nif (grep(/^deploy$/, @{$type_list})){\n if ($jobproperties ne \"\"){\n $jobproperties = \"($jobproperties) AND deploy = \\\'YES\\\'\";\n }else{\n $jobproperties = \"deploy = \\\'YES\\\'\";\n }\n}\n'),(8,'\nmy @bad_resources = (\"core\",\"cpu\",\"resource_id\",);\nif (grep(/^(deploy|allow_classic_ssh)$/, @{$type_list})){\n foreach my $mold (@{$ref_resource_list}){\n foreach my $r (@{$mold->[0]}){\n my $i = 0;\n while (($i <= $#{$r->{resources}})){\n if (grep(/^$r->{resources}->[$i]->{resource}$/, @bad_resources)){\n die(\"[ADMISSION RULE] \'$r->{resources}->[$i]->{resource}\' resource is not allowed with a deploy or allow_classic_ssh type job\\n\");\n }\n $i++;\n }\n }\n }\n}\n'),(9,'\nif (grep(/^desktop_computing$/, @{$type_list})){\n print(\"[ADMISSION RULE] Added automatically desktop_computing resource constraints\\n\");\n if ($jobproperties ne \"\"){\n $jobproperties = \"($jobproperties) AND desktop_computing = \\\'YES\\\'\";\n }else{\n $jobproperties = \"desktop_computing = \\\'YES\\\'\";\n }\n}else{\n if ($jobproperties ne \"\"){\n $jobproperties = \"($jobproperties) AND desktop_computing = \\\'NO\\\'\";\n }else{\n $jobproperties = \"desktop_computing = \\\'NO\\\'\";\n }\n}\n'),(10,'\nif ($reservationField eq \"toSchedule\") {\n my $unlimited=0;\n if (open(FILE, \"< $ENV{HOME}/unlimited_reservation.users\")) {\n while (){\n if (m/^\\s*$user\\s*$/m){\n $unlimited=1;\n }\n }\n close(FILE);\n }\n if ($unlimited > 0) {\n print(\"[ADMISSION RULE] $user is granted the privilege to do unlimited reservations\\n\");\n } else {\n my $max_nb_resa = 2;\n my $nb_resa = $dbh->do(\" SELECT job_id\n FROM jobs\n WHERE\n job_user = \\\'$user\\\' AND\n (reservation = \\\'toSchedule\\\' OR\n reservation = \\\'Scheduled\\\') AND\n (state = \\\'Waiting\\\' OR state = \\\'Hold\\\')\n \");\n if ($nb_resa >= $max_nb_resa){\n die(\"[ADMISSION RULE] Error : you cannot have more than $max_nb_resa waiting reservations.\\n\");\n }\n }\n}\n'),(11,'\nmy $max_walltime = OAR::IO::sql_to_duration(\"12:00:00\");\nif (($jobType eq \"INTERACTIVE\") and ($reservationField eq \"None\")){ \n foreach my $mold (@{$ref_resource_list}){\n if ((defined($mold->[1])) and ($max_walltime < $mold->[1])){\n print(\"[ADMISSION RULE] Walltime to big for an INTERACTIVE job so it is set to $max_walltime.\\n\");\n $mold->[1] = $max_walltime;\n }\n }\n}\n'),(12,'\nmy $default_wall = OAR::IO::sql_to_duration(\"2:00:00\");\nforeach my $mold (@{$ref_resource_list}){\n if (!defined($mold->[1])){\n print(\"[ADMISSION RULE] Set default walltime to $default_wall.\\n\");\n $mold->[1] = $default_wall;\n }\n}\n'),(13,'\nmy @types = (\"container\",\"inner\",\"deploy\",\"desktop_computing\",\"besteffort\",\"cosystem\",\"idempotent\",\"timesharing\",\"allow_classic_ssh\");\nforeach my $t (@{$type_list}){\n my $i = 0;\n while (($types[$i] ne $t) and ($i <= $#types)){\n $i++;\n }\n if (($i > $#types) and ($t !~ /^(timesharing|inner)/)){\n die(\"[ADMISSION RULE] The job type $t is not handled by OAR; Right values are : @types\\n\");\n }\n}\n'),(14,'\nforeach my $mold (@{$ref_resource_list}){\n foreach my $r (@{$mold->[0]}){\n my $prop = $r->{property};\n if (($prop !~ /[\\s\\(]type[\\s=]/) and ($prop !~ /^type[\\s=]/)){\n if (!defined($prop)){\n $r->{property} = \"type = \\\'default\\\'\";\n }else{\n $r->{property} = \"($r->{property}) AND type = \\\'default\\\'\";\n }\n }\n }\n}\nprint(\"[ADMISSION RULE] Modify resource description with type constraints\\n\");\n'); /*!40000 ALTER TABLE `admission_rules` ENABLE KEYS */; UNLOCK TABLES; -- -- Table structure for table `assigned_resources` -- DROP TABLE IF EXISTS `assigned_resources`; SET @saved_cs_client = @@character_set_client; SET character_set_client = utf8; CREATE TABLE `assigned_resources` ( `moldable_job_id` int(10) unsigned NOT NULL, `resource_id` int(10) unsigned NOT NULL, `assigned_resource_index` enum('CURRENT','LOG') NOT NULL default 'CURRENT', PRIMARY KEY (`moldable_job_id`,`resource_id`), KEY `mjob_id` (`moldable_job_id`), KEY `log` (`assigned_resource_index`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1; SET character_set_client = @saved_cs_client; -- -- Dumping data for table `assigned_resources` -- LOCK TABLES `assigned_resources` WRITE; /*!40000 ALTER TABLE `assigned_resources` DISABLE KEYS */; /*!40000 ALTER TABLE `assigned_resources` ENABLE KEYS */; UNLOCK TABLES; -- -- Table structure for table `challenges` -- DROP TABLE IF EXISTS `challenges`; SET @saved_cs_client = @@character_set_client; SET character_set_client = utf8; CREATE TABLE `challenges` ( `job_id` int(10) unsigned NOT NULL, `challenge` varchar(255) NOT NULL, `ssh_private_key` text NOT NULL, `ssh_public_key` text NOT NULL, PRIMARY KEY (`job_id`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1; SET character_set_client = @saved_cs_client; -- -- Dumping data for table `challenges` -- LOCK TABLES `challenges` WRITE; /*!40000 ALTER TABLE `challenges` DISABLE KEYS */; INSERT INTO `challenges` VALUES (1,'841021991175','',''); /*!40000 ALTER TABLE `challenges` ENABLE KEYS */; UNLOCK TABLES; -- -- Table structure for table `event_log_hostnames` -- DROP TABLE IF EXISTS `event_log_hostnames`; SET @saved_cs_client = @@character_set_client; SET character_set_client = utf8; CREATE TABLE `event_log_hostnames` ( `event_id` int(10) unsigned NOT NULL, `hostname` varchar(255) NOT NULL, PRIMARY KEY (`event_id`,`hostname`), KEY `event_hostname` (`hostname`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1; SET character_set_client = @saved_cs_client; -- -- Dumping data for table `event_log_hostnames` -- LOCK TABLES `event_log_hostnames` WRITE; /*!40000 ALTER TABLE `event_log_hostnames` DISABLE KEYS */; /*!40000 ALTER TABLE `event_log_hostnames` ENABLE KEYS */; UNLOCK TABLES; -- -- Table structure for table `event_logs` -- DROP TABLE IF EXISTS `event_logs`; SET @saved_cs_client = @@character_set_client; SET character_set_client = utf8; CREATE TABLE `event_logs` ( `event_id` int(10) unsigned NOT NULL auto_increment, `type` varchar(50) NOT NULL, `job_id` int(10) unsigned NOT NULL, `date` int(10) unsigned NOT NULL, `description` varchar(255) NOT NULL, `to_check` enum('YES','NO') NOT NULL default 'YES', PRIMARY KEY (`event_id`), KEY `event_type` (`type`), KEY `event_check` (`to_check`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1; SET character_set_client = @saved_cs_client; -- -- Dumping data for table `event_logs` -- LOCK TABLES `event_logs` WRITE; /*!40000 ALTER TABLE `event_logs` DISABLE KEYS */; /*!40000 ALTER TABLE `event_logs` ENABLE KEYS */; UNLOCK TABLES; -- -- Table structure for table `files` -- DROP TABLE IF EXISTS `files`; SET @saved_cs_client = @@character_set_client; SET character_set_client = utf8; CREATE TABLE `files` ( `file_id` int(10) unsigned NOT NULL auto_increment, `md5sum` varchar(255) default NULL, `location` varchar(255) default NULL, `method` varchar(255) default NULL, `compression` varchar(255) default NULL, `size` int(10) unsigned NOT NULL, PRIMARY KEY (`file_id`), KEY `md5sum` (`md5sum`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1; SET character_set_client = @saved_cs_client; -- -- Dumping data for table `files` -- LOCK TABLES `files` WRITE; /*!40000 ALTER TABLE `files` DISABLE KEYS */; /*!40000 ALTER TABLE `files` ENABLE KEYS */; UNLOCK TABLES; -- -- Table structure for table `frag_jobs` -- DROP TABLE IF EXISTS `frag_jobs`; SET @saved_cs_client = @@character_set_client; SET character_set_client = utf8; CREATE TABLE `frag_jobs` ( `frag_id_job` int(10) unsigned NOT NULL, `frag_date` int(10) unsigned NOT NULL, `frag_state` enum('LEON','TIMER_ARMED','LEON_EXTERMINATE','FRAGGED') NOT NULL default 'LEON', PRIMARY KEY (`frag_id_job`), KEY `frag_state` (`frag_state`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1; SET character_set_client = @saved_cs_client; -- -- Dumping data for table `frag_jobs` -- LOCK TABLES `frag_jobs` WRITE; /*!40000 ALTER TABLE `frag_jobs` DISABLE KEYS */; /*!40000 ALTER TABLE `frag_jobs` ENABLE KEYS */; UNLOCK TABLES; -- -- Table structure for table `gantt_jobs_predictions` -- DROP TABLE IF EXISTS `gantt_jobs_predictions`; SET @saved_cs_client = @@character_set_client; SET character_set_client = utf8; CREATE TABLE `gantt_jobs_predictions` ( `moldable_job_id` int(10) unsigned NOT NULL, `start_time` int(10) unsigned NOT NULL, PRIMARY KEY (`moldable_job_id`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1; SET character_set_client = @saved_cs_client; -- -- Dumping data for table `gantt_jobs_predictions` -- LOCK TABLES `gantt_jobs_predictions` WRITE; /*!40000 ALTER TABLE `gantt_jobs_predictions` DISABLE KEYS */; INSERT INTO `gantt_jobs_predictions` VALUES (0,1223567271),(1,1223575200); /*!40000 ALTER TABLE `gantt_jobs_predictions` ENABLE KEYS */; UNLOCK TABLES; -- -- Table structure for table `gantt_jobs_predictions_log` -- DROP TABLE IF EXISTS `gantt_jobs_predictions_log`; SET @saved_cs_client = @@character_set_client; SET character_set_client = utf8; CREATE TABLE `gantt_jobs_predictions_log` ( `sched_date` int(10) unsigned NOT NULL, `moldable_job_id` int(10) unsigned NOT NULL, `start_time` int(10) unsigned NOT NULL, PRIMARY KEY (`sched_date`,`moldable_job_id`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1; SET character_set_client = @saved_cs_client; -- -- Dumping data for table `gantt_jobs_predictions_log` -- LOCK TABLES `gantt_jobs_predictions_log` WRITE; /*!40000 ALTER TABLE `gantt_jobs_predictions_log` DISABLE KEYS */; /*!40000 ALTER TABLE `gantt_jobs_predictions_log` ENABLE KEYS */; UNLOCK TABLES; -- -- Table structure for table `gantt_jobs_predictions_visu` -- DROP TABLE IF EXISTS `gantt_jobs_predictions_visu`; SET @saved_cs_client = @@character_set_client; SET character_set_client = utf8; CREATE TABLE `gantt_jobs_predictions_visu` ( `moldable_job_id` int(10) unsigned NOT NULL, `start_time` int(10) unsigned NOT NULL, PRIMARY KEY (`moldable_job_id`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1; SET character_set_client = @saved_cs_client; -- -- Dumping data for table `gantt_jobs_predictions_visu` -- LOCK TABLES `gantt_jobs_predictions_visu` WRITE; /*!40000 ALTER TABLE `gantt_jobs_predictions_visu` DISABLE KEYS */; INSERT INTO `gantt_jobs_predictions_visu` VALUES (0,1223567271),(1,1223575200); /*!40000 ALTER TABLE `gantt_jobs_predictions_visu` ENABLE KEYS */; UNLOCK TABLES; -- -- Table structure for table `gantt_jobs_resources` -- DROP TABLE IF EXISTS `gantt_jobs_resources`; SET @saved_cs_client = @@character_set_client; SET character_set_client = utf8; CREATE TABLE `gantt_jobs_resources` ( `moldable_job_id` int(10) unsigned NOT NULL, `resource_id` int(10) unsigned NOT NULL, PRIMARY KEY (`moldable_job_id`,`resource_id`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1; SET character_set_client = @saved_cs_client; -- -- Dumping data for table `gantt_jobs_resources` -- LOCK TABLES `gantt_jobs_resources` WRITE; /*!40000 ALTER TABLE `gantt_jobs_resources` DISABLE KEYS */; INSERT INTO `gantt_jobs_resources` VALUES (1,1),(1,2),(1,3); /*!40000 ALTER TABLE `gantt_jobs_resources` ENABLE KEYS */; UNLOCK TABLES; -- -- Table structure for table `gantt_jobs_resources_log` -- DROP TABLE IF EXISTS `gantt_jobs_resources_log`; SET @saved_cs_client = @@character_set_client; SET character_set_client = utf8; CREATE TABLE `gantt_jobs_resources_log` ( `sched_date` int(10) unsigned NOT NULL, `moldable_job_id` int(10) unsigned NOT NULL, `resource_id` int(10) unsigned NOT NULL, PRIMARY KEY (`sched_date`,`moldable_job_id`,`resource_id`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1; SET character_set_client = @saved_cs_client; -- -- Dumping data for table `gantt_jobs_resources_log` -- LOCK TABLES `gantt_jobs_resources_log` WRITE; /*!40000 ALTER TABLE `gantt_jobs_resources_log` DISABLE KEYS */; /*!40000 ALTER TABLE `gantt_jobs_resources_log` ENABLE KEYS */; UNLOCK TABLES; -- -- Table structure for table `gantt_jobs_resources_visu` -- DROP TABLE IF EXISTS `gantt_jobs_resources_visu`; SET @saved_cs_client = @@character_set_client; SET character_set_client = utf8; CREATE TABLE `gantt_jobs_resources_visu` ( `moldable_job_id` int(10) unsigned NOT NULL, `resource_id` int(10) unsigned NOT NULL, PRIMARY KEY (`moldable_job_id`,`resource_id`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1; SET character_set_client = @saved_cs_client; -- -- Dumping data for table `gantt_jobs_resources_visu` -- LOCK TABLES `gantt_jobs_resources_visu` WRITE; /*!40000 ALTER TABLE `gantt_jobs_resources_visu` DISABLE KEYS */; INSERT INTO `gantt_jobs_resources_visu` VALUES (1,1),(1,2),(1,3); /*!40000 ALTER TABLE `gantt_jobs_resources_visu` ENABLE KEYS */; UNLOCK TABLES; -- -- Table structure for table `job_dependencies` -- DROP TABLE IF EXISTS `job_dependencies`; SET @saved_cs_client = @@character_set_client; SET character_set_client = utf8; CREATE TABLE `job_dependencies` ( `job_id` int(10) unsigned NOT NULL, `job_id_required` int(10) unsigned NOT NULL, `job_dependency_index` enum('CURRENT','LOG') NOT NULL default 'CURRENT', PRIMARY KEY (`job_id`,`job_id_required`), KEY `id` (`job_id`), KEY `log` (`job_dependency_index`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1; SET character_set_client = @saved_cs_client; -- -- Dumping data for table `job_dependencies` -- LOCK TABLES `job_dependencies` WRITE; /*!40000 ALTER TABLE `job_dependencies` DISABLE KEYS */; /*!40000 ALTER TABLE `job_dependencies` ENABLE KEYS */; UNLOCK TABLES; -- -- Table structure for table `job_resource_descriptions` -- DROP TABLE IF EXISTS `job_resource_descriptions`; SET @saved_cs_client = @@character_set_client; SET character_set_client = utf8; CREATE TABLE `job_resource_descriptions` ( `res_job_group_id` int(10) unsigned NOT NULL, `res_job_resource_type` varchar(255) NOT NULL, `res_job_value` int(11) NOT NULL, `res_job_order` int(10) unsigned NOT NULL default '0', `res_job_index` enum('CURRENT','LOG') NOT NULL default 'CURRENT', PRIMARY KEY (`res_job_group_id`,`res_job_resource_type`,`res_job_order`), KEY `resgroup` (`res_job_group_id`), KEY `log` (`res_job_index`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1; SET character_set_client = @saved_cs_client; -- -- Dumping data for table `job_resource_descriptions` -- LOCK TABLES `job_resource_descriptions` WRITE; /*!40000 ALTER TABLE `job_resource_descriptions` DISABLE KEYS */; INSERT INTO `job_resource_descriptions` VALUES (1,'resource_id',3,0,'CURRENT'); /*!40000 ALTER TABLE `job_resource_descriptions` ENABLE KEYS */; UNLOCK TABLES; -- -- Table structure for table `job_resource_groups` -- DROP TABLE IF EXISTS `job_resource_groups`; SET @saved_cs_client = @@character_set_client; SET character_set_client = utf8; CREATE TABLE `job_resource_groups` ( `res_group_id` int(10) unsigned NOT NULL auto_increment, `res_group_moldable_id` int(10) unsigned NOT NULL, `res_group_property` text, `res_group_index` enum('CURRENT','LOG') NOT NULL default 'CURRENT', PRIMARY KEY (`res_group_id`), KEY `moldable_job` (`res_group_moldable_id`), KEY `log` (`res_group_index`) ) ENGINE=MyISAM AUTO_INCREMENT=2 DEFAULT CHARSET=latin1; SET character_set_client = @saved_cs_client; -- -- Dumping data for table `job_resource_groups` -- LOCK TABLES `job_resource_groups` WRITE; /*!40000 ALTER TABLE `job_resource_groups` DISABLE KEYS */; INSERT INTO `job_resource_groups` VALUES (1,1,'type = \'default\'','CURRENT'); /*!40000 ALTER TABLE `job_resource_groups` ENABLE KEYS */; UNLOCK TABLES; -- -- Table structure for table `job_state_logs` -- DROP TABLE IF EXISTS `job_state_logs`; SET @saved_cs_client = @@character_set_client; SET character_set_client = utf8; CREATE TABLE `job_state_logs` ( `job_state_log_id` int(10) unsigned NOT NULL auto_increment, `job_id` int(10) unsigned NOT NULL, `job_state` enum('Waiting','Hold','toLaunch','toError','toAckReservation','Launching','Finishing','Running','Suspended','Resuming','Terminated','Error') NOT NULL, `date_start` int(10) unsigned NOT NULL, `date_stop` int(10) unsigned default '0', PRIMARY KEY (`job_state_log_id`), KEY `id` (`job_id`), KEY `state` (`job_state`) ) ENGINE=MyISAM AUTO_INCREMENT=4 DEFAULT CHARSET=latin1; SET character_set_client = @saved_cs_client; -- -- Dumping data for table `job_state_logs` -- LOCK TABLES `job_state_logs` WRITE; /*!40000 ALTER TABLE `job_state_logs` DISABLE KEYS */; INSERT INTO `job_state_logs` VALUES (1,1,'Waiting',1223567218,1223567219),(2,1,'toAckReservation',1223567219,1223567219),(3,1,'Waiting',1223567219,0); /*!40000 ALTER TABLE `job_state_logs` ENABLE KEYS */; UNLOCK TABLES; -- -- Table structure for table `job_types` -- DROP TABLE IF EXISTS `job_types`; SET @saved_cs_client = @@character_set_client; SET character_set_client = utf8; CREATE TABLE `job_types` ( `job_type_id` int(10) unsigned NOT NULL auto_increment, `job_id` int(10) unsigned NOT NULL, `type` varchar(255) NOT NULL, `types_index` enum('CURRENT','LOG') NOT NULL default 'CURRENT', PRIMARY KEY (`job_type_id`), KEY `log` (`types_index`), KEY `type` (`type`), KEY `id_types` (`job_id`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1; SET character_set_client = @saved_cs_client; -- -- Dumping data for table `job_types` -- LOCK TABLES `job_types` WRITE; /*!40000 ALTER TABLE `job_types` DISABLE KEYS */; /*!40000 ALTER TABLE `job_types` ENABLE KEYS */; UNLOCK TABLES; -- -- Table structure for table `jobs` -- DROP TABLE IF EXISTS `jobs`; SET @saved_cs_client = @@character_set_client; SET character_set_client = utf8; CREATE TABLE `jobs` ( `job_id` int(10) unsigned NOT NULL auto_increment, `initial_request` text, `job_name` varchar(100) default NULL, `job_env` text, `job_type` enum('INTERACTIVE','PASSIVE') NOT NULL default 'PASSIVE', `info_type` varchar(255) default NULL, `state` enum('Waiting','Hold','toLaunch','toError','toAckReservation','Launching','Running','Suspended','Resuming','Finishing','Terminated','Error') NOT NULL, `reservation` enum('None','toSchedule','Scheduled') NOT NULL default 'None', `message` varchar(255) NOT NULL, `scheduler_info` varchar(255) NOT NULL, `job_user` varchar(255) NOT NULL, `project` varchar(255) NOT NULL, `job_group` varchar(255) NOT NULL, `command` text, `exit_code` int(11) default NULL, `queue_name` varchar(100) NOT NULL, `properties` text, `launching_directory` text NOT NULL, `submission_time` int(10) unsigned NOT NULL, `start_time` int(10) unsigned NOT NULL, `stop_time` int(10) unsigned NOT NULL, `file_id` int(10) unsigned default NULL, `accounted` enum('YES','NO') NOT NULL default 'NO', `notify` varchar(255) default NULL, `assigned_moldable_job` int(10) unsigned default '0', `checkpoint` int(10) unsigned NOT NULL default '0', `checkpoint_signal` int(11) NOT NULL, `stdout_file` text, `stderr_file` text, `resubmit_job_id` int(10) unsigned default '0', `suspended` enum('YES','NO') NOT NULL default 'NO', PRIMARY KEY (`job_id`), KEY `state` (`state`), KEY `state_id` (`state`,`job_id`), KEY `reservation` (`reservation`), KEY `queue_name` (`queue_name`), KEY `accounted` (`accounted`), KEY `suspended` (`suspended`) ) ENGINE=MyISAM AUTO_INCREMENT=2 DEFAULT CHARSET=latin1; SET character_set_client = @saved_cs_client; -- -- Dumping data for table `jobs` -- LOCK TABLES `jobs` WRITE; /*!40000 ALTER TABLE `jobs` DISABLE KEYS */; INSERT INTO `jobs` VALUES (1,'oarsub -r 2008-10-09 20:00:00 -l nodes=3',NULL,NULL,'INTERACTIVE','grelon-41.nancy.grid5000.fr:43469','Waiting','Scheduled','','','pneyron','default','','',NULL,'default','desktop_computing = \'NO\'','/home/grenoble/pneyron',1223567218,1223575200,0,NULL,'NO',NULL,0,0,12,'OAR.%jobid%.stdout','OAR.%jobid%.stderr',0,'NO'); /*!40000 ALTER TABLE `jobs` ENABLE KEYS */; UNLOCK TABLES; -- -- Table structure for table `moldable_job_descriptions` -- DROP TABLE IF EXISTS `moldable_job_descriptions`; SET @saved_cs_client = @@character_set_client; SET character_set_client = utf8; CREATE TABLE `moldable_job_descriptions` ( `moldable_id` int(10) unsigned NOT NULL auto_increment, `moldable_job_id` int(10) unsigned NOT NULL, `moldable_walltime` int(10) unsigned NOT NULL, `moldable_index` enum('CURRENT','LOG') NOT NULL default 'CURRENT', PRIMARY KEY (`moldable_id`), KEY `job` (`moldable_job_id`), KEY `log` (`moldable_index`) ) ENGINE=MyISAM AUTO_INCREMENT=2 DEFAULT CHARSET=latin1; SET character_set_client = @saved_cs_client; -- -- Dumping data for table `moldable_job_descriptions` -- LOCK TABLES `moldable_job_descriptions` WRITE; /*!40000 ALTER TABLE `moldable_job_descriptions` DISABLE KEYS */; INSERT INTO `moldable_job_descriptions` VALUES (1,1,7200,'CURRENT'); /*!40000 ALTER TABLE `moldable_job_descriptions` ENABLE KEYS */; UNLOCK TABLES; -- -- Table structure for table `queues` -- DROP TABLE IF EXISTS `queues`; SET @saved_cs_client = @@character_set_client; SET character_set_client = utf8; CREATE TABLE `queues` ( `queue_name` varchar(100) NOT NULL, `priority` int(10) unsigned NOT NULL, `scheduler_policy` varchar(100) NOT NULL, `state` enum('Active','notActive') NOT NULL default 'Active', PRIMARY KEY (`queue_name`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1; SET character_set_client = @saved_cs_client; -- -- Dumping data for table `queues` -- LOCK TABLES `queues` WRITE; /*!40000 ALTER TABLE `queues` DISABLE KEYS */; INSERT INTO `queues` VALUES ('admin',10,'oar_sched_gantt_with_timesharing','Active'),('default',2,'oar_sched_gantt_with_timesharing','Active'),('besteffort',0,'oar_sched_gantt_with_timesharing','Active'); /*!40000 ALTER TABLE `queues` ENABLE KEYS */; UNLOCK TABLES; -- -- Table structure for table `resource_logs` -- DROP TABLE IF EXISTS `resource_logs`; SET @saved_cs_client = @@character_set_client; SET character_set_client = utf8; CREATE TABLE `resource_logs` ( `resource_log_id` int(10) unsigned NOT NULL auto_increment, `resource_id` int(10) unsigned NOT NULL, `attribute` varchar(255) NOT NULL, `value` varchar(255) NOT NULL, `date_start` int(10) unsigned NOT NULL, `date_stop` int(10) unsigned default '0', `finaud_decision` enum('YES','NO') NOT NULL default 'NO', PRIMARY KEY (`resource_log_id`), KEY `resource` (`resource_id`), KEY `attribute` (`attribute`), KEY `finaud` (`finaud_decision`), KEY `val` (`value`) ) ENGINE=MyISAM AUTO_INCREMENT=4 DEFAULT CHARSET=latin1; SET character_set_client = @saved_cs_client; -- -- Dumping data for table `resource_logs` -- LOCK TABLES `resource_logs` WRITE; /*!40000 ALTER TABLE `resource_logs` DISABLE KEYS */; INSERT INTO `resource_logs` VALUES (1,1,'state','Alive',1223566377,0,'NO'),(2,2,'state','Alive',1223566380,0,'NO'),(3,3,'state','Alive',1223566381,0,'NO'); /*!40000 ALTER TABLE `resource_logs` ENABLE KEYS */; UNLOCK TABLES; -- -- Table structure for table `resources` -- DROP TABLE IF EXISTS `resources`; SET @saved_cs_client = @@character_set_client; SET character_set_client = utf8; CREATE TABLE `resources` ( `resource_id` int(10) unsigned NOT NULL auto_increment, `type` varchar(100) NOT NULL default 'default', `network_address` varchar(100) NOT NULL, `state` enum('Alive','Dead','Suspected','Absent') NOT NULL, `next_state` enum('UnChanged','Alive','Dead','Absent','Suspected') NOT NULL default 'UnChanged', `finaud_decision` enum('YES','NO') NOT NULL default 'NO', `next_finaud_decision` enum('YES','NO') NOT NULL default 'NO', `state_num` int(11) NOT NULL default '0', `suspended_jobs` enum('YES','NO') NOT NULL default 'NO', `scheduler_priority` int(10) unsigned NOT NULL default '0', `cpuset` int(10) unsigned NOT NULL default '0', `besteffort` enum('YES','NO') NOT NULL default 'YES', `deploy` enum('YES','NO') NOT NULL default 'NO', `expiry_date` int(10) unsigned NOT NULL, `desktop_computing` enum('YES','NO') NOT NULL default 'NO', `last_job_date` int(10) unsigned default '0', `available_upto` int(10) unsigned NOT NULL default '0', PRIMARY KEY (`resource_id`), KEY `state` (`state`), KEY `next_state` (`next_state`), KEY `suspended_jobs` (`suspended_jobs`), KEY `type` (`type`), KEY `network_address` (`network_address`) ) ENGINE=MyISAM AUTO_INCREMENT=4 DEFAULT CHARSET=latin1; SET character_set_client = @saved_cs_client; -- -- Dumping data for table `resources` -- LOCK TABLES `resources` WRITE; /*!40000 ALTER TABLE `resources` DISABLE KEYS */; INSERT INTO `resources` VALUES (1,'default','127.0.2.1','Alive','Absent','NO','NO',1,'NO',0,0,'YES','NO',0,'NO',0,0),(2,'default','127.0.2.2','Alive','UnChanged','NO','NO',1,'NO',0,0,'YES','NO',0,'NO',0,0),(3,'default','127.0.2.3','Alive','UnChanged','NO','NO',1,'NO',0,0,'YES','NO',0,'NO',0,0); /*!40000 ALTER TABLE `resources` ENABLE KEYS */; UNLOCK TABLES; -- -- Table structure for table `schema` -- DROP TABLE IF EXISTS `schema`; SET @saved_cs_client = @@character_set_client; SET character_set_client = utf8; CREATE TABLE `schema` ( `version` varchar(255) NOT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1; SET character_set_client = @saved_cs_client; -- -- Dumping data for table `schema` -- LOCK TABLES `schema` WRITE; /*!40000 ALTER TABLE `schema` DISABLE KEYS */; INSERT INTO `schema` VALUES ('2.3.0+svn1369'); /*!40000 ALTER TABLE `schema` ENABLE KEYS */; UNLOCK TABLES; /*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; /*!40101 SET SQL_MODE=@OLD_SQL_MODE */; /*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; /*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; /*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; /*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; -- Dump completed on 2008-10-09 15:49:48 oar-2.5.7/tests/scheduler/data/000_mysql_structure.sql0000644015014700017500000002520612677211234022351 0ustar neyronneyron# $Id: mysql_structure.sql 1416 2008-05-23 16:19:56Z neyron $ # Creation de la base de donnees #CREATE DATABASE IF NOT EXISTS oar; # Creation de l utilisateur oar #CONNECT mysql; #INSERT INTO user (Host,User,Password) VALUES('localhost','oar',PASSWORD('oar')); #INSERT INTO user (Host,User,Password) VALUES('%','oar',PASSWORD('oar')); #INSERT INTO db (Host,Db,User,Select_priv,Insert_priv,Update_priv,Delete_priv, Create_priv,Drop_priv) VALUES # ('localhost','oar','oar','Y','Y','Y','Y','Y','Y'); #INSERT INTO db (Host,Db,User,Select_priv,Insert_priv,Update_priv,Delete_priv, Create_priv,Drop_priv) VALUES # ('%','oar','oar','Y','Y','Y','Y','Y','Y'); #FLUSH PRIVILEGES; #GRANT ALL ON oar.* TO oar@localhost; #GRANT ALL ON oar.* TO oar@"%"; #GRANT SELECT ON oar.* TO oarreader@localhost; #GRANT SELECT ON oar.* TO oarreader@"%"; #FLUSH PRIVILEGES; #CONNECT oar; # Creation des tables dans la base de donnees oar # schema version, change here if you have updated the db schema CREATE TABLE IF NOT EXISTS `schema` ( version VARCHAR( 255 ) NOT NULL ); INSERT INTO `schema` VALUES ('2.3.0+svn1369'); #DROP TABLE IF EXISTS jobs; CREATE TABLE IF NOT EXISTS jobs ( job_id INT UNSIGNED NOT NULL AUTO_INCREMENT, initial_request TEXT, job_name VARCHAR( 100 ) , job_env TEXT , job_type ENUM('INTERACTIVE','PASSIVE') DEFAULT 'PASSIVE' NOT NULL , info_type VARCHAR( 255 ) , state ENUM('Waiting','Hold','toLaunch','toError','toAckReservation','Launching','Running','Suspended','Resuming','Finishing','Terminated','Error') NOT NULL , reservation ENUM('None','toSchedule','Scheduled') DEFAULT 'None' NOT NULL , message VARCHAR( 255 ) NOT NULL , scheduler_info VARCHAR( 255 ) NOT NULL , job_user VARCHAR( 255 ) NOT NULL , project VARCHAR( 255 ) NOT NULL , job_group VARCHAR( 255 ) NOT NULL , command TEXT , exit_code INT DEFAULT NULL , queue_name VARCHAR( 100 ) NOT NULL , properties TEXT , launching_directory TEXT NOT NULL , submission_time INT UNSIGNED NOT NULL , start_time INT UNSIGNED NOT NULL , stop_time INT UNSIGNED NOT NULL , file_id INT UNSIGNED, accounted ENUM("YES","NO") NOT NULL DEFAULT "NO" , notify VARCHAR( 255 ) DEFAULT NULL , assigned_moldable_job INT UNSIGNED DEFAULT 0 , checkpoint INT UNSIGNED NOT NULL DEFAULT 0 , checkpoint_signal INT NOT NULL, stdout_file TEXT , stderr_file TEXT , resubmit_job_id INT UNSIGNED DEFAULT 0, suspended ENUM("YES","NO") NOT NULL DEFAULT "NO" , INDEX state (state), INDEX state_id (state,job_id), INDEX reservation (reservation), INDEX queue_name (queue_name), INDEX accounted (accounted), INDEX suspended (suspended), PRIMARY KEY (job_id) ); #DROP TABLE IF EXISTS job_types; CREATE TABLE IF NOT EXISTS job_types ( job_type_id INT UNSIGNED NOT NULL AUTO_INCREMENT, job_id INT UNSIGNED NOT NULL , type VARCHAR(255) NOT NULL , types_index ENUM('CURRENT','LOG') DEFAULT 'CURRENT' NOT NULL , INDEX log (types_index), INDEX type (type), INDEX id_types (job_id), PRIMARY KEY (job_type_id) ); #DROP TABLE IF EXISTS challenges; CREATE TABLE IF NOT EXISTS challenges ( job_id INT UNSIGNED NOT NULL , challenge VARCHAR(255) NOT NULL , ssh_private_key TEXT NOT NULL DEFAULT "" , ssh_public_key TEXT NOT NULL DEFAULT "" , PRIMARY KEY (job_id) ); #DROP TABLE IF EXISTS moldable_job_descriptions; CREATE TABLE IF NOT EXISTS moldable_job_descriptions ( moldable_id INT UNSIGNED NOT NULL AUTO_INCREMENT, moldable_job_id INT UNSIGNED NOT NULL , moldable_walltime INT UNSIGNED NOT NULL , moldable_index ENUM('CURRENT','LOG') DEFAULT 'CURRENT' NOT NULL , INDEX job (moldable_job_id) , INDEX log (moldable_index) , PRIMARY KEY (moldable_id) ); #DROP TABLE IF EXISTS job_resource_groups; CREATE TABLE IF NOT EXISTS job_resource_groups ( res_group_id INT UNSIGNED NOT NULL AUTO_INCREMENT , res_group_moldable_id INT UNSIGNED NOT NULL , res_group_property TEXT , res_group_index ENUM('CURRENT','LOG') DEFAULT 'CURRENT' NOT NULL , INDEX moldable_job (res_group_moldable_id), INDEX log (res_group_index) , PRIMARY KEY (res_group_id) ); #DROP TABLE IF EXISTS job_resource_descriptions; CREATE TABLE IF NOT EXISTS job_resource_descriptions ( res_job_group_id INT UNSIGNED NOT NULL, res_job_resource_type VARCHAR(255) NOT NULL, res_job_value INT NOT NULL, res_job_order INT UNSIGNED NOT NULL DEFAULT 0, res_job_index ENUM('CURRENT','LOG') DEFAULT 'CURRENT' NOT NULL , INDEX resgroup (res_job_group_id), INDEX log (res_job_index) , PRIMARY KEY (res_job_group_id,res_job_resource_type,res_job_order) ); #DROP TABLE IF EXISTS job_state_logs; CREATE TABLE IF NOT EXISTS job_state_logs ( job_state_log_id INT UNSIGNED NOT NULL AUTO_INCREMENT, job_id INT UNSIGNED NOT NULL , job_state ENUM('Waiting','Hold','toLaunch','toError','toAckReservation','Launching','Finishing','Running','Suspended','Resuming','Terminated','Error') NOT NULL , date_start INT UNSIGNED NOT NULL, date_stop INT UNSIGNED DEFAULT 0, INDEX id (job_id), INDEX state (job_state), PRIMARY KEY (job_state_log_id) ); #DROP TABLE IF EXISTS frag_jobs; CREATE TABLE IF NOT EXISTS frag_jobs ( frag_id_job INT UNSIGNED NOT NULL , frag_date INT UNSIGNED NOT NULL , frag_state ENUM('LEON','TIMER_ARMED','LEON_EXTERMINATE','FRAGGED') DEFAULT 'LEON' NOT NULL , INDEX frag_state (frag_state), PRIMARY KEY (frag_id_job) ); #DROP TABLE IF EXISTS assigned_resources; CREATE TABLE IF NOT EXISTS assigned_resources ( moldable_job_id INT UNSIGNED NOT NULL , resource_id INT UNSIGNED NOT NULL , assigned_resource_index ENUM('CURRENT','LOG') DEFAULT 'CURRENT' NOT NULL , INDEX mjob_id (moldable_job_id), INDEX log (assigned_resource_index), PRIMARY KEY (moldable_job_id,resource_id) ); #DROP TABLE IF EXISTS resources; CREATE TABLE IF NOT EXISTS resources ( resource_id INT UNSIGNED NOT NULL AUTO_INCREMENT, type VARCHAR( 100 ) NOT NULL DEFAULT "default" , network_address VARCHAR( 100 ) NOT NULL , state ENUM('Alive','Dead','Suspected','Absent') NOT NULL , next_state ENUM('UnChanged','Alive','Dead','Absent','Suspected') DEFAULT 'UnChanged' NOT NULL , finaud_decision ENUM('YES','NO') DEFAULT 'NO' NOT NULL , next_finaud_decision ENUM('YES','NO') DEFAULT 'NO' NOT NULL , state_num INT NOT NULL DEFAULT 0 , suspended_jobs ENUM('YES','NO') DEFAULT 'NO' NOT NULL , scheduler_priority INT UNSIGNED NOT NULL DEFAULT 0 , cpuset INT UNSIGNED NOT NULL DEFAULT 0 , besteffort ENUM('YES','NO') DEFAULT 'YES' NOT NULL , deploy ENUM('YES','NO') DEFAULT 'NO' NOT NULL , expiry_date INT UNSIGNED NOT NULL , desktop_computing ENUM('YES','NO') DEFAULT 'NO' NOT NULL, last_job_date INT UNSIGNED DEFAULT 0, available_upto INT UNSIGNED DEFAULT 0 NOT NULL , INDEX state (state), INDEX next_state (next_state), INDEX suspended_jobs (suspended_jobs), INDEX type (type), INDEX network_address (network_address), PRIMARY KEY (resource_id) ); #DROP TABLE IF EXISTS resource_logs; CREATE TABLE IF NOT EXISTS resource_logs ( resource_log_id INT UNSIGNED NOT NULL AUTO_INCREMENT, resource_id INT UNSIGNED NOT NULL , attribute VARCHAR( 255 ) NOT NULL , value VARCHAR( 255 ) NOT NULL , date_start INT UNSIGNED NOT NULL, date_stop INT UNSIGNED DEFAULT 0 , finaud_decision ENUM('YES','NO') DEFAULT 'NO' NOT NULL , INDEX resource (resource_id), INDEX attribute (attribute), INDEX finaud (finaud_decision), INDEX val (value), PRIMARY KEY (resource_log_id) ); #DROP TABLE IF EXISTS queues; CREATE TABLE IF NOT EXISTS queues ( queue_name VARCHAR( 100 ) NOT NULL , priority INT UNSIGNED NOT NULL , scheduler_policy VARCHAR( 100 ) NOT NULL , state ENUM('Active','notActive') NOT NULL DEFAULT 'Active', PRIMARY KEY (queue_name) ); #DROP TABLE IF EXISTS admission_rules; CREATE TABLE IF NOT EXISTS admission_rules ( id INT UNSIGNED NOT NULL AUTO_INCREMENT, rule TEXT NOT NULL, PRIMARY KEY (id) ); #DROP TABLE IF EXISTS gantt_jobs_predictions; CREATE TABLE IF NOT EXISTS gantt_jobs_predictions ( moldable_job_id INT UNSIGNED NOT NULL , start_time INT UNSIGNED NOT NULL , PRIMARY KEY (moldable_job_id) ); #DROP TABLE IF EXISTS gantt_jobs_predictions_visu; CREATE TABLE IF NOT EXISTS gantt_jobs_predictions_visu ( moldable_job_id INT UNSIGNED NOT NULL , start_time INT UNSIGNED NOT NULL , PRIMARY KEY (moldable_job_id) ); #DROP TABLE IF EXISTS gantt_jobs_predictions_log; CREATE TABLE IF NOT EXISTS gantt_jobs_predictions_log ( sched_date INT UNSIGNED NOT NULL , moldable_job_id INT UNSIGNED NOT NULL , start_time INT UNSIGNED NOT NULL , PRIMARY KEY (sched_date,moldable_job_id) ); #DROP TABLE IF EXISTS gantt_jobs_resources; CREATE TABLE IF NOT EXISTS gantt_jobs_resources ( moldable_job_id INT UNSIGNED NOT NULL , resource_id INT UNSIGNED NOT NULL , PRIMARY KEY (moldable_job_id,resource_id) ); #DROP TABLE IF EXISTS gantt_jobs_resources_visu; CREATE TABLE IF NOT EXISTS gantt_jobs_resources_visu ( moldable_job_id INT UNSIGNED NOT NULL , resource_id INT UNSIGNED NOT NULL , PRIMARY KEY (moldable_job_id,resource_id) ); #DROP TABLE IF EXISTS gantt_jobs_resources_log; CREATE TABLE IF NOT EXISTS gantt_jobs_resources_log ( sched_date INT UNSIGNED NOT NULL , moldable_job_id INT UNSIGNED NOT NULL , resource_id INT UNSIGNED NOT NULL , PRIMARY KEY (sched_date,moldable_job_id,resource_id) ); #DROP TABLE IF EXISTS files; CREATE TABLE IF NOT EXISTS files ( file_id INT UNSIGNED NOT NULL AUTO_INCREMENT, md5sum VARCHAR( 255 ) , location VARCHAR( 255 ) , method VARCHAR( 255 ) , compression VARCHAR( 255 ) , size INT UNSIGNED NOT NULL , INDEX md5sum (md5sum), PRIMARY KEY (file_id) ); #DROP TABLE IF EXISTS event_logs; CREATE TABLE IF NOT EXISTS event_logs ( event_id INT UNSIGNED NOT NULL AUTO_INCREMENT, type VARCHAR(50) NOT NULL, job_id INT UNSIGNED NOT NULL , date INT UNSIGNED NOT NULL , description VARCHAR(255) NOT NULL, to_check ENUM('YES','NO') NOT NULL DEFAULT 'YES', INDEX event_type (type), INDEX event_check (to_check), PRIMARY KEY (event_id) ); #DROP TABLE IF EXISTS event_log_hostnames; CREATE TABLE IF NOT EXISTS event_log_hostnames ( event_id INT UNSIGNED NOT NULL, hostname VARCHAR( 255 ) NOT NULL , INDEX event_hostname (hostname), PRIMARY KEY (event_id, hostname) ); #DROP TABLE IF EXISTS accounting; CREATE TABLE IF NOT EXISTS accounting ( window_start INT UNSIGNED NOT NULL , window_stop INT UNSIGNED NOT NULL , accounting_user VARCHAR( 255 ) NOT NULL , accounting_project VARCHAR( 255 ) NOT NULL , queue_name VARCHAR( 100 ) NOT NULL , consumption_type ENUM("ASKED","USED") NOT NULL , consumption INT UNSIGNED NOT NULL , INDEX accounting_user (accounting_user), INDEX accounting_project (accounting_project), INDEX accounting_queue (queue_name), INDEX accounting_type (consumption_type), PRIMARY KEY (window_start,window_stop,accounting_user,accounting_project,queue_name,consumption_type) ); #DROP TABLE IF EXISTS job_dependencies; CREATE TABLE IF NOT EXISTS job_dependencies ( job_id INT UNSIGNED NOT NULL , job_id_required INT UNSIGNED NOT NULL, job_dependency_index ENUM('CURRENT','LOG') DEFAULT 'CURRENT' NOT NULL , INDEX id (job_id), INDEX log (job_dependency_index), PRIMARY KEY (job_id,job_id_required) ); oar-2.5.7/tests/scheduler/data/002_oar.conf0000777015014700017500000000000012677211234021774 2000_oar.confustar neyronneyronoar-2.5.7/tests/scheduler/data/000_mysql_default_admission_rules.sql0000644015014700017500000002032512677211234025212 0ustar neyronneyron# Default admission rules for OAR 2 # $Id: mysql_default_admission_rules.sql 1680 2008-09-25 17:22:25Z neyron $ DROP TABLE IF EXISTS admission_rules; CREATE TABLE IF NOT EXISTS admission_rules ( id INT UNSIGNED NOT NULL AUTO_INCREMENT, rule TEXT NOT NULL, PRIMARY KEY (id) ); # Default admission rules # Specify the default value for queue parameter INSERT IGNORE INTO admission_rules (rule) VALUES ('if (not defined($queue_name)) {$queue_name="default";}'); # Prevent root and oar to submit jobs. INSERT IGNORE INTO admission_rules (rule) VALUES ('die ("[ADMISSION RULE] root and oar users are not allowed to submit jobs.\\n") if ( $user eq "root" or $user eq "oar" );'); # Avoid users except admin to go in the admin queue INSERT IGNORE INTO admission_rules (rule) VALUES (' my $admin_group = "admin"; if ($queue_name eq "admin") { my $members; (undef,undef,undef, $members) = getgrnam($admin_group); my %h = map { $_ => 1 } split(/\\s+/,$members); if ( $h{$user} ne 1 ) { {die("[ADMISSION RULE] Only member of the group ".$admin_group." can submit jobs in the admin queue\\n");} } } '); # Prevent the use of system properties INSERT IGNORE INTO admission_rules (rule) VALUES (' my @bad_resources = ("type","state","next_state","finaud_decision","next_finaud_decision","state_num","suspended_jobs","besteffort","deploy","expiry_date","desktop_computing","last_job_date","available_upto","scheduler_priority"); foreach my $mold (@{$ref_resource_list}){ foreach my $r (@{$mold->[0]}){ my $i = 0; while (($i <= $#{$r->{resources}})){ if (grep(/^$r->{resources}->[$i]->{resource}$/i, @bad_resources)){ die("[ADMISSION RULE] \'$r->{resources}->[$i]->{resource}\' resource is not allowed\\n"); } $i++; } } } '); # Force besteffort jobs to run in the besteffort queue # Force job of the besteffort queue to be of the besteffort type # Force besteffort jobs to run on nodes with the besteffort property INSERT IGNORE INTO admission_rules (rule) VALUES (' if (grep(/^besteffort$/, @{$type_list}) and not $queue_name eq "besteffort"){ $queue_name = "besteffort"; print("[ADMISSION RULE] Automatically redirect in the besteffort queue\\n"); } if ($queue_name eq "besteffort" and not grep(/^besteffort$/, @{$type_list})) { push(@{$type_list},"besteffort"); print("[ADMISSION RULE] Automatically add the besteffort type\\n"); } if (grep(/^besteffort$/, @{$type_list})){ if ($jobproperties ne ""){ $jobproperties = "($jobproperties) AND besteffort = \\\'YES\\\'"; }else{ $jobproperties = "besteffort = \\\'YES\\\'"; } print("[ADMISSION RULE] Automatically add the besteffort constraint on the resources\\n"); } '); # Verify if besteffort jobs are not reservations INSERT IGNORE INTO admission_rules (rule) VALUES (' if ((grep(/^besteffort$/, @{$type_list})) and ($reservationField ne "None")){ die("[ADMISSION RULE] Error: a job cannot both be of type besteffort and be a reservation.\\n"); } '); # Force deploy jobs to go on resources with the deploy property INSERT IGNORE INTO admission_rules (rule) VALUES (' if (grep(/^deploy$/, @{$type_list})){ if ($jobproperties ne ""){ $jobproperties = "($jobproperties) AND deploy = \\\'YES\\\'"; }else{ $jobproperties = "deploy = \\\'YES\\\'"; } } '); # Prevent deploy and allow_classic_ssh type jobs on none entire nodes INSERT IGNORE INTO admission_rules (rule) VALUES (' my @bad_resources = ("core","cpu","resource_id",); if (grep(/^(deploy|allow_classic_ssh)$/, @{$type_list})){ foreach my $mold (@{$ref_resource_list}){ foreach my $r (@{$mold->[0]}){ my $i = 0; while (($i <= $#{$r->{resources}})){ if (grep(/^$r->{resources}->[$i]->{resource}$/i, @bad_resources)){ die("[ADMISSION RULE] \'$r->{resources}->[$i]->{resource}\' resource is not allowed with a deploy or allow_classic_ssh type job\\n"); } $i++; } } } } '); # Force desktop_computing jobs to go on nodes with the desktop_computing property INSERT IGNORE INTO admission_rules (rule) VALUES (' if (grep(/^desktop_computing$/, @{$type_list})){ print("[ADMISSION RULE] Added automatically desktop_computing resource constraints\\n"); if ($jobproperties ne ""){ $jobproperties = "($jobproperties) AND desktop_computing = \\\'YES\\\'"; }else{ $jobproperties = "desktop_computing = \\\'YES\\\'"; } }else{ if ($jobproperties ne ""){ $jobproperties = "($jobproperties) AND desktop_computing = \\\'NO\\\'"; }else{ $jobproperties = "desktop_computing = \\\'NO\\\'"; } } '); # Limit the number of reservations that a user can do. # (overrided on user basis using the file: ~oar/unlimited_reservation.users) INSERT IGNORE INTO admission_rules (rule) VALUES (' if ($reservationField eq "toSchedule") { my $unlimited=0; if (open(FILE, "< $ENV{HOME}/unlimited_reservation.users")) { while (){ if (m/^\\s*$user\\s*$/m){ $unlimited=1; } } close(FILE); } if ($unlimited > 0) { print("[ADMISSION RULE] $user is granted the privilege to do unlimited reservations\\n"); } else { my $max_nb_resa = 2; my $nb_resa = $dbh->do(" SELECT job_id FROM jobs WHERE job_user = \\\'$user\\\' AND (reservation = \\\'toSchedule\\\' OR reservation = \\\'Scheduled\\\') AND (state = \\\'Waiting\\\' OR state = \\\'Hold\\\') "); if ($nb_resa >= $max_nb_resa){ die("[ADMISSION RULE] Error : you cannot have more than $max_nb_resa waiting reservations.\\n"); } } } '); ## How to perform actions if the user name is in a file #INSERT IGNORE INTO admission_rules (rule) VALUES (' #open(FILE, "/tmp/users.txt"); #while (($queue_name ne "admin") and ($_ = )){ # if ($_ =~ m/^\\s*$user\\s*$/m){ # print("[ADMISSION RULE] Change assigned queue into admin\\n"); # $queue_name = "admin"; # } #} #close(FILE); #'); # Limit walltime for interactive jobs INSERT IGNORE INTO admission_rules (rule) VALUES (' my $max_walltime = OAR::IO::sql_to_duration("12:00:00"); if (($jobType eq "INTERACTIVE") and ($reservationField eq "None")){ foreach my $mold (@{$ref_resource_list}){ if ((defined($mold->[1])) and ($max_walltime < $mold->[1])){ print("[ADMISSION RULE] Walltime to big for an INTERACTIVE job so it is set to $max_walltime.\\n"); $mold->[1] = $max_walltime; } } } '); # specify the default walltime if it is not specified INSERT IGNORE INTO admission_rules (rule) VALUES (' my $default_wall = OAR::IO::sql_to_duration("2:00:00"); foreach my $mold (@{$ref_resource_list}){ if (!defined($mold->[1])){ print("[ADMISSION RULE] Set default walltime to $default_wall.\\n"); $mold->[1] = $default_wall; } } '); # Check if types given by the user are right INSERT IGNORE INTO admission_rules (rule) VALUES (' my @types = ("container","inner","deploy","desktop_computing","besteffort","cosystem","idempotent","timesharing","allow_classic_ssh"); foreach my $t (@{$type_list}){ my $i = 0; while (($types[$i] ne $t) and ($i <= $#types)){ $i++; } if (($i > $#types) and ($t !~ /^(timesharing|inner)/)){ die("[ADMISSION RULE] The job type $t is not handled by OAR; Right values are : @types\\n"); } } '); # If resource types are not specified, then we force them to default INSERT IGNORE INTO admission_rules (rule) VALUES (' foreach my $mold (@{$ref_resource_list}){ foreach my $r (@{$mold->[0]}){ my $prop = $r->{property}; if (($prop !~ /[\\s\\(]type[\\s=]/) and ($prop !~ /^type[\\s=]/)){ if (!defined($prop)){ $r->{property} = "type = \\\'default\\\'"; }else{ $r->{property} = "($r->{property}) AND type = \\\'default\\\'"; } } } } print("[ADMISSION RULE] Modify resource description with type constraints\\n"); '); oar-2.5.7/tests/scheduler/data/002_advance_reservation_with_dead_resource.sql0000644015014700017500000007456412677211234027042 0ustar neyronneyron-- MySQL dump 10.11 -- -- Host: localhost Database: oar -- ------------------------------------------------------ -- Server version 5.0.51a-15 /*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; /*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; /*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; /*!40101 SET NAMES utf8 */; /*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; /*!40103 SET TIME_ZONE='+00:00' */; /*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; -- -- Table structure for table `accounting` -- DROP TABLE IF EXISTS `accounting`; SET @saved_cs_client = @@character_set_client; SET character_set_client = utf8; CREATE TABLE `accounting` ( `window_start` int(10) unsigned NOT NULL, `window_stop` int(10) unsigned NOT NULL, `accounting_user` varchar(255) NOT NULL, `accounting_project` varchar(255) NOT NULL, `queue_name` varchar(100) NOT NULL, `consumption_type` enum('ASKED','USED') NOT NULL, `consumption` int(10) unsigned NOT NULL, PRIMARY KEY (`window_start`,`window_stop`,`accounting_user`,`accounting_project`,`queue_name`,`consumption_type`), KEY `accounting_user` (`accounting_user`), KEY `accounting_project` (`accounting_project`), KEY `accounting_queue` (`queue_name`), KEY `accounting_type` (`consumption_type`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1; SET character_set_client = @saved_cs_client; -- -- Dumping data for table `accounting` -- LOCK TABLES `accounting` WRITE; /*!40000 ALTER TABLE `accounting` DISABLE KEYS */; /*!40000 ALTER TABLE `accounting` ENABLE KEYS */; UNLOCK TABLES; -- -- Table structure for table `admission_rules` -- DROP TABLE IF EXISTS `admission_rules`; SET @saved_cs_client = @@character_set_client; SET character_set_client = utf8; CREATE TABLE `admission_rules` ( `id` int(10) unsigned NOT NULL auto_increment, `rule` text NOT NULL, PRIMARY KEY (`id`) ) ENGINE=MyISAM AUTO_INCREMENT=15 DEFAULT CHARSET=latin1; SET character_set_client = @saved_cs_client; -- -- Dumping data for table `admission_rules` -- LOCK TABLES `admission_rules` WRITE; /*!40000 ALTER TABLE `admission_rules` DISABLE KEYS */; INSERT INTO `admission_rules` VALUES (1,'if (not defined($queue_name)) {$queue_name=\"default\";}'),(2,'die (\"[ADMISSION RULE] root and oar users are not allowed to submit jobs.\\n\") if ( $user eq \"root\" or $user eq \"oar\" );'),(3,'\nmy $admin_group = \"admin\";\nif ($queue_name eq \"admin\") {\n my $members; \n (undef,undef,undef, $members) = getgrnam($admin_group);\n my %h = map { $_ => 1 } split(/\\s+/,$members);\n if ( $h{$user} ne 1 ) {\n {die(\"[ADMISSION RULE] Only member of the group \".$admin_group.\" can submit jobs in the admin queue\\n\");}\n }\n}\n'),(4,'\nmy @bad_resources = (\"type\",\"state\",\"next_state\",\"finaud_decision\",\"next_finaud_decision\",\"state_num\",\"suspended_jobs\",\"besteffort\",\"deploy\",\"expiry_date\",\"desktop_computing\",\"last_job_date\",\"available_upto\",\"scheduler_priority\");\nforeach my $mold (@{$ref_resource_list}){\n foreach my $r (@{$mold->[0]}){\n my $i = 0;\n while (($i <= $#{$r->{resources}})){\n if (grep(/^$r->{resources}->[$i]->{resource}$/, @bad_resources)){\n die(\"[ADMISSION RULE] \'$r->{resources}->[$i]->{resource}\' resource is not allowed\\n\");\n }\n $i++;\n }\n }\n}\n'),(5,'\nif (grep(/^besteffort$/, @{$type_list}) and not $queue_name eq \"besteffort\"){\n $queue_name = \"besteffort\";\n print(\"[ADMISSION RULE] Automatically redirect in the besteffort queue\\n\");\n}\nif ($queue_name eq \"besteffort\" and not grep(/^besteffort$/, @{$type_list})) {\n push(@{$type_list},\"besteffort\");\n print(\"[ADMISSION RULE] Automatically add the besteffort type\\n\");\n}\nif (grep(/^besteffort$/, @{$type_list})){\n if ($jobproperties ne \"\"){\n $jobproperties = \"($jobproperties) AND besteffort = \\\'YES\\\'\";\n }else{\n $jobproperties = \"besteffort = \\\'YES\\\'\";\n }\n print(\"[ADMISSION RULE] Automatically add the besteffort constraint on the resources\\n\");\n}\n'),(6,'\nif ((grep(/^besteffort$/, @{$type_list})) and ($reservationField ne \"None\")){\n die(\"[ADMISSION RULE] Error: a job cannot both be of type besteffort and be a reservation.\\n\");\n}\n'),(7,'\nif (grep(/^deploy$/, @{$type_list})){\n if ($jobproperties ne \"\"){\n $jobproperties = \"($jobproperties) AND deploy = \\\'YES\\\'\";\n }else{\n $jobproperties = \"deploy = \\\'YES\\\'\";\n }\n}\n'),(8,'\nmy @bad_resources = (\"core\",\"cpu\",\"resource_id\",);\nif (grep(/^(deploy|allow_classic_ssh)$/, @{$type_list})){\n foreach my $mold (@{$ref_resource_list}){\n foreach my $r (@{$mold->[0]}){\n my $i = 0;\n while (($i <= $#{$r->{resources}})){\n if (grep(/^$r->{resources}->[$i]->{resource}$/, @bad_resources)){\n die(\"[ADMISSION RULE] \'$r->{resources}->[$i]->{resource}\' resource is not allowed with a deploy or allow_classic_ssh type job\\n\");\n }\n $i++;\n }\n }\n }\n}\n'),(9,'\nif (grep(/^desktop_computing$/, @{$type_list})){\n print(\"[ADMISSION RULE] Added automatically desktop_computing resource constraints\\n\");\n if ($jobproperties ne \"\"){\n $jobproperties = \"($jobproperties) AND desktop_computing = \\\'YES\\\'\";\n }else{\n $jobproperties = \"desktop_computing = \\\'YES\\\'\";\n }\n}else{\n if ($jobproperties ne \"\"){\n $jobproperties = \"($jobproperties) AND desktop_computing = \\\'NO\\\'\";\n }else{\n $jobproperties = \"desktop_computing = \\\'NO\\\'\";\n }\n}\n'),(10,'\nif ($reservationField eq \"toSchedule\") {\n my $unlimited=0;\n if (open(FILE, \"< $ENV{HOME}/unlimited_reservation.users\")) {\n while (){\n if (m/^\\s*$user\\s*$/m){\n $unlimited=1;\n }\n }\n close(FILE);\n }\n if ($unlimited > 0) {\n print(\"[ADMISSION RULE] $user is granted the privilege to do unlimited reservations\\n\");\n } else {\n my $max_nb_resa = 2;\n my $nb_resa = $dbh->do(\" SELECT job_id\n FROM jobs\n WHERE\n job_user = \\\'$user\\\' AND\n (reservation = \\\'toSchedule\\\' OR\n reservation = \\\'Scheduled\\\') AND\n (state = \\\'Waiting\\\' OR state = \\\'Hold\\\')\n \");\n if ($nb_resa >= $max_nb_resa){\n die(\"[ADMISSION RULE] Error : you cannot have more than $max_nb_resa waiting reservations.\\n\");\n }\n }\n}\n'),(11,'\nmy $max_walltime = OAR::IO::sql_to_duration(\"12:00:00\");\nif (($jobType eq \"INTERACTIVE\") and ($reservationField eq \"None\")){ \n foreach my $mold (@{$ref_resource_list}){\n if ((defined($mold->[1])) and ($max_walltime < $mold->[1])){\n print(\"[ADMISSION RULE] Walltime to big for an INTERACTIVE job so it is set to $max_walltime.\\n\");\n $mold->[1] = $max_walltime;\n }\n }\n}\n'),(12,'\nmy $default_wall = OAR::IO::sql_to_duration(\"2:00:00\");\nforeach my $mold (@{$ref_resource_list}){\n if (!defined($mold->[1])){\n print(\"[ADMISSION RULE] Set default walltime to $default_wall.\\n\");\n $mold->[1] = $default_wall;\n }\n}\n'),(13,'\nmy @types = (\"container\",\"inner\",\"deploy\",\"desktop_computing\",\"besteffort\",\"cosystem\",\"idempotent\",\"timesharing\",\"allow_classic_ssh\");\nforeach my $t (@{$type_list}){\n my $i = 0;\n while (($types[$i] ne $t) and ($i <= $#types)){\n $i++;\n }\n if (($i > $#types) and ($t !~ /^(timesharing|inner)/)){\n die(\"[ADMISSION RULE] The job type $t is not handled by OAR; Right values are : @types\\n\");\n }\n}\n'),(14,'\nforeach my $mold (@{$ref_resource_list}){\n foreach my $r (@{$mold->[0]}){\n my $prop = $r->{property};\n if (($prop !~ /[\\s\\(]type[\\s=]/) and ($prop !~ /^type[\\s=]/)){\n if (!defined($prop)){\n $r->{property} = \"type = \\\'default\\\'\";\n }else{\n $r->{property} = \"($r->{property}) AND type = \\\'default\\\'\";\n }\n }\n }\n}\nprint(\"[ADMISSION RULE] Modify resource description with type constraints\\n\");\n'); /*!40000 ALTER TABLE `admission_rules` ENABLE KEYS */; UNLOCK TABLES; -- -- Table structure for table `assigned_resources` -- DROP TABLE IF EXISTS `assigned_resources`; SET @saved_cs_client = @@character_set_client; SET character_set_client = utf8; CREATE TABLE `assigned_resources` ( `moldable_job_id` int(10) unsigned NOT NULL, `resource_id` int(10) unsigned NOT NULL, `assigned_resource_index` enum('CURRENT','LOG') NOT NULL default 'CURRENT', PRIMARY KEY (`moldable_job_id`,`resource_id`), KEY `mjob_id` (`moldable_job_id`), KEY `log` (`assigned_resource_index`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1; SET character_set_client = @saved_cs_client; -- -- Dumping data for table `assigned_resources` -- LOCK TABLES `assigned_resources` WRITE; /*!40000 ALTER TABLE `assigned_resources` DISABLE KEYS */; /*!40000 ALTER TABLE `assigned_resources` ENABLE KEYS */; UNLOCK TABLES; -- -- Table structure for table `challenges` -- DROP TABLE IF EXISTS `challenges`; SET @saved_cs_client = @@character_set_client; SET character_set_client = utf8; CREATE TABLE `challenges` ( `job_id` int(10) unsigned NOT NULL, `challenge` varchar(255) NOT NULL, `ssh_private_key` text NOT NULL, `ssh_public_key` text NOT NULL, PRIMARY KEY (`job_id`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1; SET character_set_client = @saved_cs_client; -- -- Dumping data for table `challenges` -- LOCK TABLES `challenges` WRITE; /*!40000 ALTER TABLE `challenges` DISABLE KEYS */; INSERT INTO `challenges` VALUES (1,'841021991175','',''); /*!40000 ALTER TABLE `challenges` ENABLE KEYS */; UNLOCK TABLES; -- -- Table structure for table `event_log_hostnames` -- DROP TABLE IF EXISTS `event_log_hostnames`; SET @saved_cs_client = @@character_set_client; SET character_set_client = utf8; CREATE TABLE `event_log_hostnames` ( `event_id` int(10) unsigned NOT NULL, `hostname` varchar(255) NOT NULL, PRIMARY KEY (`event_id`,`hostname`), KEY `event_hostname` (`hostname`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1; SET character_set_client = @saved_cs_client; -- -- Dumping data for table `event_log_hostnames` -- LOCK TABLES `event_log_hostnames` WRITE; /*!40000 ALTER TABLE `event_log_hostnames` DISABLE KEYS */; /*!40000 ALTER TABLE `event_log_hostnames` ENABLE KEYS */; UNLOCK TABLES; -- -- Table structure for table `event_logs` -- DROP TABLE IF EXISTS `event_logs`; SET @saved_cs_client = @@character_set_client; SET character_set_client = utf8; CREATE TABLE `event_logs` ( `event_id` int(10) unsigned NOT NULL auto_increment, `type` varchar(50) NOT NULL, `job_id` int(10) unsigned NOT NULL, `date` int(10) unsigned NOT NULL, `description` varchar(255) NOT NULL, `to_check` enum('YES','NO') NOT NULL default 'YES', PRIMARY KEY (`event_id`), KEY `event_type` (`type`), KEY `event_check` (`to_check`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1; SET character_set_client = @saved_cs_client; -- -- Dumping data for table `event_logs` -- LOCK TABLES `event_logs` WRITE; /*!40000 ALTER TABLE `event_logs` DISABLE KEYS */; /*!40000 ALTER TABLE `event_logs` ENABLE KEYS */; UNLOCK TABLES; -- -- Table structure for table `files` -- DROP TABLE IF EXISTS `files`; SET @saved_cs_client = @@character_set_client; SET character_set_client = utf8; CREATE TABLE `files` ( `file_id` int(10) unsigned NOT NULL auto_increment, `md5sum` varchar(255) default NULL, `location` varchar(255) default NULL, `method` varchar(255) default NULL, `compression` varchar(255) default NULL, `size` int(10) unsigned NOT NULL, PRIMARY KEY (`file_id`), KEY `md5sum` (`md5sum`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1; SET character_set_client = @saved_cs_client; -- -- Dumping data for table `files` -- LOCK TABLES `files` WRITE; /*!40000 ALTER TABLE `files` DISABLE KEYS */; /*!40000 ALTER TABLE `files` ENABLE KEYS */; UNLOCK TABLES; -- -- Table structure for table `frag_jobs` -- DROP TABLE IF EXISTS `frag_jobs`; SET @saved_cs_client = @@character_set_client; SET character_set_client = utf8; CREATE TABLE `frag_jobs` ( `frag_id_job` int(10) unsigned NOT NULL, `frag_date` int(10) unsigned NOT NULL, `frag_state` enum('LEON','TIMER_ARMED','LEON_EXTERMINATE','FRAGGED') NOT NULL default 'LEON', PRIMARY KEY (`frag_id_job`), KEY `frag_state` (`frag_state`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1; SET character_set_client = @saved_cs_client; -- -- Dumping data for table `frag_jobs` -- LOCK TABLES `frag_jobs` WRITE; /*!40000 ALTER TABLE `frag_jobs` DISABLE KEYS */; /*!40000 ALTER TABLE `frag_jobs` ENABLE KEYS */; UNLOCK TABLES; -- -- Table structure for table `gantt_jobs_predictions` -- DROP TABLE IF EXISTS `gantt_jobs_predictions`; SET @saved_cs_client = @@character_set_client; SET character_set_client = utf8; CREATE TABLE `gantt_jobs_predictions` ( `moldable_job_id` int(10) unsigned NOT NULL, `start_time` int(10) unsigned NOT NULL, PRIMARY KEY (`moldable_job_id`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1; SET character_set_client = @saved_cs_client; -- -- Dumping data for table `gantt_jobs_predictions` -- LOCK TABLES `gantt_jobs_predictions` WRITE; /*!40000 ALTER TABLE `gantt_jobs_predictions` DISABLE KEYS */; INSERT INTO `gantt_jobs_predictions` VALUES (0,1223567271),(1,1223575200); /*!40000 ALTER TABLE `gantt_jobs_predictions` ENABLE KEYS */; UNLOCK TABLES; -- -- Table structure for table `gantt_jobs_predictions_log` -- DROP TABLE IF EXISTS `gantt_jobs_predictions_log`; SET @saved_cs_client = @@character_set_client; SET character_set_client = utf8; CREATE TABLE `gantt_jobs_predictions_log` ( `sched_date` int(10) unsigned NOT NULL, `moldable_job_id` int(10) unsigned NOT NULL, `start_time` int(10) unsigned NOT NULL, PRIMARY KEY (`sched_date`,`moldable_job_id`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1; SET character_set_client = @saved_cs_client; -- -- Dumping data for table `gantt_jobs_predictions_log` -- LOCK TABLES `gantt_jobs_predictions_log` WRITE; /*!40000 ALTER TABLE `gantt_jobs_predictions_log` DISABLE KEYS */; /*!40000 ALTER TABLE `gantt_jobs_predictions_log` ENABLE KEYS */; UNLOCK TABLES; -- -- Table structure for table `gantt_jobs_predictions_visu` -- DROP TABLE IF EXISTS `gantt_jobs_predictions_visu`; SET @saved_cs_client = @@character_set_client; SET character_set_client = utf8; CREATE TABLE `gantt_jobs_predictions_visu` ( `moldable_job_id` int(10) unsigned NOT NULL, `start_time` int(10) unsigned NOT NULL, PRIMARY KEY (`moldable_job_id`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1; SET character_set_client = @saved_cs_client; -- -- Dumping data for table `gantt_jobs_predictions_visu` -- LOCK TABLES `gantt_jobs_predictions_visu` WRITE; /*!40000 ALTER TABLE `gantt_jobs_predictions_visu` DISABLE KEYS */; INSERT INTO `gantt_jobs_predictions_visu` VALUES (0,1223567271),(1,1223575200); /*!40000 ALTER TABLE `gantt_jobs_predictions_visu` ENABLE KEYS */; UNLOCK TABLES; -- -- Table structure for table `gantt_jobs_resources` -- DROP TABLE IF EXISTS `gantt_jobs_resources`; SET @saved_cs_client = @@character_set_client; SET character_set_client = utf8; CREATE TABLE `gantt_jobs_resources` ( `moldable_job_id` int(10) unsigned NOT NULL, `resource_id` int(10) unsigned NOT NULL, PRIMARY KEY (`moldable_job_id`,`resource_id`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1; SET character_set_client = @saved_cs_client; -- -- Dumping data for table `gantt_jobs_resources` -- LOCK TABLES `gantt_jobs_resources` WRITE; /*!40000 ALTER TABLE `gantt_jobs_resources` DISABLE KEYS */; INSERT INTO `gantt_jobs_resources` VALUES (1,1),(1,2),(1,3); /*!40000 ALTER TABLE `gantt_jobs_resources` ENABLE KEYS */; UNLOCK TABLES; -- -- Table structure for table `gantt_jobs_resources_log` -- DROP TABLE IF EXISTS `gantt_jobs_resources_log`; SET @saved_cs_client = @@character_set_client; SET character_set_client = utf8; CREATE TABLE `gantt_jobs_resources_log` ( `sched_date` int(10) unsigned NOT NULL, `moldable_job_id` int(10) unsigned NOT NULL, `resource_id` int(10) unsigned NOT NULL, PRIMARY KEY (`sched_date`,`moldable_job_id`,`resource_id`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1; SET character_set_client = @saved_cs_client; -- -- Dumping data for table `gantt_jobs_resources_log` -- LOCK TABLES `gantt_jobs_resources_log` WRITE; /*!40000 ALTER TABLE `gantt_jobs_resources_log` DISABLE KEYS */; /*!40000 ALTER TABLE `gantt_jobs_resources_log` ENABLE KEYS */; UNLOCK TABLES; -- -- Table structure for table `gantt_jobs_resources_visu` -- DROP TABLE IF EXISTS `gantt_jobs_resources_visu`; SET @saved_cs_client = @@character_set_client; SET character_set_client = utf8; CREATE TABLE `gantt_jobs_resources_visu` ( `moldable_job_id` int(10) unsigned NOT NULL, `resource_id` int(10) unsigned NOT NULL, PRIMARY KEY (`moldable_job_id`,`resource_id`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1; SET character_set_client = @saved_cs_client; -- -- Dumping data for table `gantt_jobs_resources_visu` -- LOCK TABLES `gantt_jobs_resources_visu` WRITE; /*!40000 ALTER TABLE `gantt_jobs_resources_visu` DISABLE KEYS */; INSERT INTO `gantt_jobs_resources_visu` VALUES (1,1),(1,2),(1,3); /*!40000 ALTER TABLE `gantt_jobs_resources_visu` ENABLE KEYS */; UNLOCK TABLES; -- -- Table structure for table `job_dependencies` -- DROP TABLE IF EXISTS `job_dependencies`; SET @saved_cs_client = @@character_set_client; SET character_set_client = utf8; CREATE TABLE `job_dependencies` ( `job_id` int(10) unsigned NOT NULL, `job_id_required` int(10) unsigned NOT NULL, `job_dependency_index` enum('CURRENT','LOG') NOT NULL default 'CURRENT', PRIMARY KEY (`job_id`,`job_id_required`), KEY `id` (`job_id`), KEY `log` (`job_dependency_index`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1; SET character_set_client = @saved_cs_client; -- -- Dumping data for table `job_dependencies` -- LOCK TABLES `job_dependencies` WRITE; /*!40000 ALTER TABLE `job_dependencies` DISABLE KEYS */; /*!40000 ALTER TABLE `job_dependencies` ENABLE KEYS */; UNLOCK TABLES; -- -- Table structure for table `job_resource_descriptions` -- DROP TABLE IF EXISTS `job_resource_descriptions`; SET @saved_cs_client = @@character_set_client; SET character_set_client = utf8; CREATE TABLE `job_resource_descriptions` ( `res_job_group_id` int(10) unsigned NOT NULL, `res_job_resource_type` varchar(255) NOT NULL, `res_job_value` int(11) NOT NULL, `res_job_order` int(10) unsigned NOT NULL default '0', `res_job_index` enum('CURRENT','LOG') NOT NULL default 'CURRENT', PRIMARY KEY (`res_job_group_id`,`res_job_resource_type`,`res_job_order`), KEY `resgroup` (`res_job_group_id`), KEY `log` (`res_job_index`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1; SET character_set_client = @saved_cs_client; -- -- Dumping data for table `job_resource_descriptions` -- LOCK TABLES `job_resource_descriptions` WRITE; /*!40000 ALTER TABLE `job_resource_descriptions` DISABLE KEYS */; INSERT INTO `job_resource_descriptions` VALUES (1,'resource_id',3,0,'CURRENT'); /*!40000 ALTER TABLE `job_resource_descriptions` ENABLE KEYS */; UNLOCK TABLES; -- -- Table structure for table `job_resource_groups` -- DROP TABLE IF EXISTS `job_resource_groups`; SET @saved_cs_client = @@character_set_client; SET character_set_client = utf8; CREATE TABLE `job_resource_groups` ( `res_group_id` int(10) unsigned NOT NULL auto_increment, `res_group_moldable_id` int(10) unsigned NOT NULL, `res_group_property` text, `res_group_index` enum('CURRENT','LOG') NOT NULL default 'CURRENT', PRIMARY KEY (`res_group_id`), KEY `moldable_job` (`res_group_moldable_id`), KEY `log` (`res_group_index`) ) ENGINE=MyISAM AUTO_INCREMENT=2 DEFAULT CHARSET=latin1; SET character_set_client = @saved_cs_client; -- -- Dumping data for table `job_resource_groups` -- LOCK TABLES `job_resource_groups` WRITE; /*!40000 ALTER TABLE `job_resource_groups` DISABLE KEYS */; INSERT INTO `job_resource_groups` VALUES (1,1,'type = \'default\'','CURRENT'); /*!40000 ALTER TABLE `job_resource_groups` ENABLE KEYS */; UNLOCK TABLES; -- -- Table structure for table `job_state_logs` -- DROP TABLE IF EXISTS `job_state_logs`; SET @saved_cs_client = @@character_set_client; SET character_set_client = utf8; CREATE TABLE `job_state_logs` ( `job_state_log_id` int(10) unsigned NOT NULL auto_increment, `job_id` int(10) unsigned NOT NULL, `job_state` enum('Waiting','Hold','toLaunch','toError','toAckReservation','Launching','Finishing','Running','Suspended','Resuming','Terminated','Error') NOT NULL, `date_start` int(10) unsigned NOT NULL, `date_stop` int(10) unsigned default '0', PRIMARY KEY (`job_state_log_id`), KEY `id` (`job_id`), KEY `state` (`job_state`) ) ENGINE=MyISAM AUTO_INCREMENT=4 DEFAULT CHARSET=latin1; SET character_set_client = @saved_cs_client; -- -- Dumping data for table `job_state_logs` -- LOCK TABLES `job_state_logs` WRITE; /*!40000 ALTER TABLE `job_state_logs` DISABLE KEYS */; INSERT INTO `job_state_logs` VALUES (1,1,'Waiting',1223567218,1223567219),(2,1,'toAckReservation',1223567219,1223567219),(3,1,'Waiting',1223567219,0); /*!40000 ALTER TABLE `job_state_logs` ENABLE KEYS */; UNLOCK TABLES; -- -- Table structure for table `job_types` -- DROP TABLE IF EXISTS `job_types`; SET @saved_cs_client = @@character_set_client; SET character_set_client = utf8; CREATE TABLE `job_types` ( `job_type_id` int(10) unsigned NOT NULL auto_increment, `job_id` int(10) unsigned NOT NULL, `type` varchar(255) NOT NULL, `types_index` enum('CURRENT','LOG') NOT NULL default 'CURRENT', PRIMARY KEY (`job_type_id`), KEY `log` (`types_index`), KEY `type` (`type`), KEY `id_types` (`job_id`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1; SET character_set_client = @saved_cs_client; -- -- Dumping data for table `job_types` -- LOCK TABLES `job_types` WRITE; /*!40000 ALTER TABLE `job_types` DISABLE KEYS */; /*!40000 ALTER TABLE `job_types` ENABLE KEYS */; UNLOCK TABLES; -- -- Table structure for table `jobs` -- DROP TABLE IF EXISTS `jobs`; SET @saved_cs_client = @@character_set_client; SET character_set_client = utf8; CREATE TABLE `jobs` ( `job_id` int(10) unsigned NOT NULL auto_increment, `initial_request` text, `job_name` varchar(100) default NULL, `job_env` text, `job_type` enum('INTERACTIVE','PASSIVE') NOT NULL default 'PASSIVE', `info_type` varchar(255) default NULL, `state` enum('Waiting','Hold','toLaunch','toError','toAckReservation','Launching','Running','Suspended','Resuming','Finishing','Terminated','Error') NOT NULL, `reservation` enum('None','toSchedule','Scheduled') NOT NULL default 'None', `message` varchar(255) NOT NULL, `scheduler_info` varchar(255) NOT NULL, `job_user` varchar(255) NOT NULL, `project` varchar(255) NOT NULL, `job_group` varchar(255) NOT NULL, `command` text, `exit_code` int(11) default NULL, `queue_name` varchar(100) NOT NULL, `properties` text, `launching_directory` text NOT NULL, `submission_time` int(10) unsigned NOT NULL, `start_time` int(10) unsigned NOT NULL, `stop_time` int(10) unsigned NOT NULL, `file_id` int(10) unsigned default NULL, `accounted` enum('YES','NO') NOT NULL default 'NO', `notify` varchar(255) default NULL, `assigned_moldable_job` int(10) unsigned default '0', `checkpoint` int(10) unsigned NOT NULL default '0', `checkpoint_signal` int(11) NOT NULL, `stdout_file` text, `stderr_file` text, `resubmit_job_id` int(10) unsigned default '0', `suspended` enum('YES','NO') NOT NULL default 'NO', PRIMARY KEY (`job_id`), KEY `state` (`state`), KEY `state_id` (`state`,`job_id`), KEY `reservation` (`reservation`), KEY `queue_name` (`queue_name`), KEY `accounted` (`accounted`), KEY `suspended` (`suspended`) ) ENGINE=MyISAM AUTO_INCREMENT=2 DEFAULT CHARSET=latin1; SET character_set_client = @saved_cs_client; -- -- Dumping data for table `jobs` -- LOCK TABLES `jobs` WRITE; /*!40000 ALTER TABLE `jobs` DISABLE KEYS */; INSERT INTO `jobs` VALUES (1,'oarsub -r 2008-10-09 20:00:00 -l nodes=3',NULL,NULL,'INTERACTIVE','grelon-41.nancy.grid5000.fr:43469','Waiting','Scheduled','','','pneyron','default','','',NULL,'default','desktop_computing = \'NO\'','/home/grenoble/pneyron',1223567218,1223575200,0,NULL,'NO',NULL,0,0,12,'OAR.%jobid%.stdout','OAR.%jobid%.stderr',0,'NO'); /*!40000 ALTER TABLE `jobs` ENABLE KEYS */; UNLOCK TABLES; -- -- Table structure for table `moldable_job_descriptions` -- DROP TABLE IF EXISTS `moldable_job_descriptions`; SET @saved_cs_client = @@character_set_client; SET character_set_client = utf8; CREATE TABLE `moldable_job_descriptions` ( `moldable_id` int(10) unsigned NOT NULL auto_increment, `moldable_job_id` int(10) unsigned NOT NULL, `moldable_walltime` int(10) unsigned NOT NULL, `moldable_index` enum('CURRENT','LOG') NOT NULL default 'CURRENT', PRIMARY KEY (`moldable_id`), KEY `job` (`moldable_job_id`), KEY `log` (`moldable_index`) ) ENGINE=MyISAM AUTO_INCREMENT=2 DEFAULT CHARSET=latin1; SET character_set_client = @saved_cs_client; -- -- Dumping data for table `moldable_job_descriptions` -- LOCK TABLES `moldable_job_descriptions` WRITE; /*!40000 ALTER TABLE `moldable_job_descriptions` DISABLE KEYS */; INSERT INTO `moldable_job_descriptions` VALUES (1,1,7200,'CURRENT'); /*!40000 ALTER TABLE `moldable_job_descriptions` ENABLE KEYS */; UNLOCK TABLES; -- -- Table structure for table `queues` -- DROP TABLE IF EXISTS `queues`; SET @saved_cs_client = @@character_set_client; SET character_set_client = utf8; CREATE TABLE `queues` ( `queue_name` varchar(100) NOT NULL, `priority` int(10) unsigned NOT NULL, `scheduler_policy` varchar(100) NOT NULL, `state` enum('Active','notActive') NOT NULL default 'Active', PRIMARY KEY (`queue_name`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1; SET character_set_client = @saved_cs_client; -- -- Dumping data for table `queues` -- LOCK TABLES `queues` WRITE; /*!40000 ALTER TABLE `queues` DISABLE KEYS */; INSERT INTO `queues` VALUES ('admin',10,'oar_sched_gantt_with_timesharing','Active'),('default',2,'oar_sched_gantt_with_timesharing','Active'),('besteffort',0,'oar_sched_gantt_with_timesharing','Active'); /*!40000 ALTER TABLE `queues` ENABLE KEYS */; UNLOCK TABLES; -- -- Table structure for table `resource_logs` -- DROP TABLE IF EXISTS `resource_logs`; SET @saved_cs_client = @@character_set_client; SET character_set_client = utf8; CREATE TABLE `resource_logs` ( `resource_log_id` int(10) unsigned NOT NULL auto_increment, `resource_id` int(10) unsigned NOT NULL, `attribute` varchar(255) NOT NULL, `value` varchar(255) NOT NULL, `date_start` int(10) unsigned NOT NULL, `date_stop` int(10) unsigned default '0', `finaud_decision` enum('YES','NO') NOT NULL default 'NO', PRIMARY KEY (`resource_log_id`), KEY `resource` (`resource_id`), KEY `attribute` (`attribute`), KEY `finaud` (`finaud_decision`), KEY `val` (`value`) ) ENGINE=MyISAM AUTO_INCREMENT=4 DEFAULT CHARSET=latin1; SET character_set_client = @saved_cs_client; -- -- Dumping data for table `resource_logs` -- LOCK TABLES `resource_logs` WRITE; /*!40000 ALTER TABLE `resource_logs` DISABLE KEYS */; INSERT INTO `resource_logs` VALUES (1,1,'state','Alive',1223566377,0,'NO'),(2,2,'state','Alive',1223566380,0,'NO'),(3,3,'state','Alive',1223566381,0,'NO'); /*!40000 ALTER TABLE `resource_logs` ENABLE KEYS */; UNLOCK TABLES; -- -- Table structure for table `resources` -- DROP TABLE IF EXISTS `resources`; SET @saved_cs_client = @@character_set_client; SET character_set_client = utf8; CREATE TABLE `resources` ( `resource_id` int(10) unsigned NOT NULL auto_increment, `type` varchar(100) NOT NULL default 'default', `network_address` varchar(100) NOT NULL, `state` enum('Alive','Dead','Suspected','Absent') NOT NULL, `next_state` enum('UnChanged','Alive','Dead','Absent','Suspected') NOT NULL default 'UnChanged', `finaud_decision` enum('YES','NO') NOT NULL default 'NO', `next_finaud_decision` enum('YES','NO') NOT NULL default 'NO', `state_num` int(11) NOT NULL default '0', `suspended_jobs` enum('YES','NO') NOT NULL default 'NO', `scheduler_priority` int(10) unsigned NOT NULL default '0', `cpuset` int(10) unsigned NOT NULL default '0', `besteffort` enum('YES','NO') NOT NULL default 'YES', `deploy` enum('YES','NO') NOT NULL default 'NO', `expiry_date` int(10) unsigned NOT NULL, `desktop_computing` enum('YES','NO') NOT NULL default 'NO', `last_job_date` int(10) unsigned default '0', `available_upto` int(10) unsigned NOT NULL default '0', PRIMARY KEY (`resource_id`), KEY `state` (`state`), KEY `next_state` (`next_state`), KEY `suspended_jobs` (`suspended_jobs`), KEY `type` (`type`), KEY `network_address` (`network_address`) ) ENGINE=MyISAM AUTO_INCREMENT=4 DEFAULT CHARSET=latin1; SET character_set_client = @saved_cs_client; -- -- Dumping data for table `resources` -- LOCK TABLES `resources` WRITE; /*!40000 ALTER TABLE `resources` DISABLE KEYS */; INSERT INTO `resources` VALUES (1,'default','127.0.2.1','Alive','Dead','NO','NO',1,'NO',0,0,'YES','NO',0,'NO',0,0),(2,'default','127.0.2.2','Alive','UnChanged','NO','NO',1,'NO',0,0,'YES','NO',0,'NO',0,0),(3,'default','127.0.2.3','Alive','UnChanged','NO','NO',1,'NO',0,0,'YES','NO',0,'NO',0,0); /*!40000 ALTER TABLE `resources` ENABLE KEYS */; UNLOCK TABLES; -- -- Table structure for table `schema` -- DROP TABLE IF EXISTS `schema`; SET @saved_cs_client = @@character_set_client; SET character_set_client = utf8; CREATE TABLE `schema` ( `version` varchar(255) NOT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1; SET character_set_client = @saved_cs_client; -- -- Dumping data for table `schema` -- LOCK TABLES `schema` WRITE; /*!40000 ALTER TABLE `schema` DISABLE KEYS */; INSERT INTO `schema` VALUES ('2.3.0+svn1369'); /*!40000 ALTER TABLE `schema` ENABLE KEYS */; UNLOCK TABLES; /*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; /*!40101 SET SQL_MODE=@OLD_SQL_MODE */; /*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; /*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; /*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; /*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; -- Dump completed on 2008-10-09 15:50:05 oar-2.5.7/tests/scheduler/data/000_my.cnf0000644015014700017500000000706612677211234017464 0ustar neyronneyron# # The MySQL database server configuration file. # # You can copy this to one of: # - "/etc/mysql/my.cnf" to set global options, # - "~/.my.cnf" to set user-specific options. # # One can use all long options that the program supports. # Run program with --help to get a list of available options and with # --print-defaults to see which it would actually understand and use. # # For explanations see # http://dev.mysql.com/doc/mysql/en/server-system-variables.html # This will be passed to all mysql clients # It has been reported that passwords should be enclosed with ticks/quotes # escpecially if they contain "#" chars... # Remember to edit /etc/mysql/debian.cnf when changing the socket location. [client] port = 3306 socket = /var/run/mysqld/mysqld.sock # Here is entries for some specific programs # The following values assume you have at least 32M ram # This was formally known as [safe_mysqld]. Both versions are currently parsed. [mysqld_safe] socket = /var/run/mysqld/mysqld.sock nice = 0 [mysqld] # # * Basic Settings # user = mysql pid-file = /var/run/mysqld/mysqld.pid socket = /var/run/mysqld/mysqld.sock port = 3306 basedir = /usr datadir = /var/lib/mysql tmpdir = /tmp language = /usr/share/mysql/english skip-external-locking # # Instead of skip-networking the default is now to listen only on # localhost which is more compatible and is not less secure. bind-address = 127.0.0.1 # # * Fine Tuning # key_buffer = 16M max_allowed_packet = 16M thread_stack = 128K thread_cache_size = 8 #max_connections = 100 #table_cache = 64 #thread_concurrency = 10 # # * Query Cache Configuration # query_cache_limit = 1M query_cache_size = 16M # # * Logging and Replication # # Both location gets rotated by the cronjob. # Be aware that this log type is a performance killer. #log = /var/log/mysql/mysql.log # # Error logging goes to syslog. This is a Debian improvement :) # # Here you can see queries with especially long duration #log_slow_queries = /var/log/mysql/mysql-slow.log #long_query_time = 2 #log-queries-not-using-indexes # # The following can be used as easy to replay backup logs or for replication. # note: if you are setting up a replication slave, see README.Debian about # other settings you may need to change. #server-id = 1 #log_bin = /var/log/mysql/mysql-bin.log #expire_logs_days = 10 #max_binlog_size = 100M #binlog_do_db = oar #binlog_ignore_db = oar2 # # * BerkeleyDB # # Using BerkeleyDB is now discouraged as its support will cease in 5.1.12. skip-bdb # # * InnoDB # # InnoDB is enabled by default with a 10MB datafile in /var/lib/mysql/. # Read the manual for more InnoDB related options. There are many! # You might want to disable InnoDB to shrink the mysqld process by circa 100MB. #skip-innodb # # * Security Features # # Read the manual, too, if you want chroot! # chroot = /var/lib/mysql/ # # For generating SSL certificates I recommend the OpenSSL GUI "tinyca". # # ssl-ca=/etc/mysql/cacert.pem # ssl-cert=/etc/mysql/server-cert.pem # ssl-key=/etc/mysql/server-key.pem [mysqldump] quick quote-names max_allowed_packet = 16M [mysql] #no-auto-rehash # faster start of mysql but no tab completition [isamchk] key_buffer = 16M # # * NDB Cluster # # See /usr/share/doc/mysql-server-*/README.Debian for more information. # # The following configuration is read by the NDB Data Nodes (ndbd processes) # not from the NDB Management Nodes (ndb_mgmd processes). # # [MYSQL_CLUSTER] # ndb-connectstring=127.0.0.1 # # * IMPORTANT: Additional settings that can override those from this file! # #!includedir /etc/mysql/conf.d/ oar-2.5.7/tests/scheduler/data/000_default_data.sql0000644015014700017500000000067312677211234021502 0ustar neyronneyronINSERT INTO queues (queue_name, priority, scheduler_policy) VALUES ('admin','10','oar_sched_gantt_with_timesharing'); INSERT INTO queues (queue_name, priority, scheduler_policy) VALUES ('default','2','oar_sched_gantt_with_timesharing'); INSERT INTO queues (queue_name, priority, scheduler_policy) VALUES ('besteffort','0','oar_sched_gantt_with_timesharing'); INSERT INTO gantt_jobs_predictions (moldable_job_id , start_time) VALUES ('0','0'); oar-2.5.7/tests/scheduler/data/001_oar.conf0000777015014700017500000000000012677211234021773 2000_oar.confustar neyronneyronoar-2.5.7/tests/scheduler/data/000_oar.conf0000644015014700017500000003251112677211234017770 0ustar neyronneyron# This file must have the bash variable assignment syntax # $Id: oar.conf 1535 2008-07-28 10:35:09Z neyron $ ######################### # General configuration # ############################################################################### # # Database type ("mysql" or "Pg") DB_TYPE="mysql" # DataBase hostname DB_HOSTNAME="127.0.0.1" # Database port DB_PORT="3307" # Database base name DB_BASE_NAME="oar" # DataBase user name DB_BASE_LOGIN="oar" # DataBase user password DB_BASE_PASSWD="oar" # DataBase read only user name #DB_BASE_LOGIN_RO="oar_ro" # DataBase read only user password #DB_BASE_PASSWD_RO="oar_ro" # OAR server hostname SERVER_HOSTNAME="localhost" # OAR server port SERVER_PORT="6666" # when the user does not specify a -l option then oar use this OARSUB_DEFAULT_RESOURCES="/resource_id=1" # force use of job key even if --use-job-key or -k is not set. OARSUB_FORCE_JOB_KEY="no" # OAR log level: 3(debug+warnings+errors), 2(warnings+errors), 1(errors) LOG_LEVEL="3" # If you want to debug oarexec on nodes then affect 1 (only effective if # DETACH_JOB_FROM_SERVER = 1) OAREXEC_DEBUG_MODE="0" # oarexec default temporary directory # This value MUST be the same in all oar.conf on all nodes of the cluster OAR_RUNTIME_DIRECTORY="/var/lib/oar" # OAR log file LOG_FILE="/var/log/oar.log" # OAR Allowed networks # Networks or hosts allowed to submit jobs to OAR and compute nodes may be # specified here ALLOWED_NETWORKS="127.0.0.1/32 0.0.0.0/0" # Specify where we are connected with a job of the deploy type DEPLOY_HOSTNAME="127.0.0.1" # Specify where we are connected with a job of the cosystem type COSYSTEM_HOSTNAME="127.0.0.1" # Specify the database field to use to fill the file on the first node of the # job in $OAR_NODE_FILE (default is 'network_address'). Only resources with # type=default are displayed in this file. #NODE_FILE_DB_FIELD="network_address" # Specify the database field that will be considered to fill the node file used # by the user on the first node of the job. for each different value of this # field then OAR will put 1 line in the node file(by default "cpu"). #NODE_FILE_DB_FIELD_DISTINCT_VALUES="cpu" # If you want to free a process per job on the server you can change this tag # into 1 (you must enable all nodes to connect to SERVER_PORT on the # SERVER_HOSTNAME) DETACH_JOB_FROM_SERVER="0" # Command to use to connect to other nodes (default is "ssh" in the PATH) OPENSSH_CMD="/usr/bin/ssh -p 6667" # Set the timeout value for each ssh connection (default is 120) #OAR_SSH_CONNECTION_TIMEOUT="200" # If you have installed taktuk and want to use it to manage remote # admnistration commands then give the full command path # (with your options except "-m" and "-o"). # You don t also have to give any taktuk command. # (taktuk version must be >= 3.6) #TAKTUK_CMD="/usr/bin/taktuk -s" ############################################################################### ######################################################################## # Pingchecker options: # # How to check if the nodes have a good health or not. This choice is # # directly linked to the Suspected state of the resources. # # By default OAR uses only "ping". it requests no configuration but it # # is not accurate about the state of the nodes and it is slow # ############################################################################### # # Set the frequency for checking Alive and Suspected resources (0 means never) FINAUD_FREQUENCY="300" # Set time after which Suspected resources become Dead (default is 0 and it # means never) #DEAD_SWITCH_TIME="600" # Uncomment only one of the following PINGCHECKER configuration # sentinelle.pl # If you want to use sentinelle.pl then you must use this tag. # (sentinelle.pl is like a "for" of ssh but it adds timeout and window to # avoid overloading the server) # (sentinelle.pl is provided with OAR in the install directory) #PINGCHECKER_SENTINELLE_SCRIPT_COMMAND="/usr/lib/oar/sentinelle.pl -t 5 -w 20" # Taktuk # taktuk may be used to check aliveness of nodes. # Give the arguments of the taktuk command WITHOUT format outputs # (DO NOT use "-o" option). # See TAKTUK_CMD tag in this file to specify the path of the taktuk command #PINGCHECKER_TAKTUK_ARG_COMMAND="-t 3 broadcast exec [ true ]" #PINGCHECKER_TAKTUK_ARG_COMMAND="-t 3 broadcast exec [ oarnodecheckquery ] #PINGCHECKER_TAKTUK_ARG_COMMAND="-t 3 broadcast exec [ /path/on/nodes/to/my/check/script.sh ]" # fping # fping may be used instead of ping to check aliveness of nodes. # uncomment next line to use fping. Give the complete command path. #PINGCHECKER_FPING_COMMAND="/usr/bin/fping -q" # nmap # nmap may be used instead of ping to check aliveness of nodes. # uncomment next line to use nmap. Give the complete command path. # It will test to connect on the ssh port (22) #PINGCHECKER_NMAP_COMMAND="/usr/bin/nmap -p 22 -n -T5" # GENERIC command # a specific script may be used instead of ping to check aliveness of nodes. # uncomment next line and give the complete command path and its arguments. # The script must return bad nodes on STDERR (1 line for a bad node and it must # have exactly the same name that OAR has given in argument of the command) #PINGCHECKER_GENERIC_COMMAND="/path/to/command arg1 arg2" ############################################################################### ###################### # Mail configuration # ############################################################################### # # OAR information may be notified by email to the administror # set accordingly to your configuration and uncomment the next lines to # activate the feature. # (If this tag is right configured then users can use "--notify" option of oarsub # to receive mails about their jobs) #MAIL_SMTP_SERVER="smtp.serveur.com" # You can specify several recipients with a comma between each email address #MAIL_RECIPIENT="user@domain.com" #MAIL_SENDER="oar@domain.com" ############################################################################### ########### # Scripts # ############################################################################### # # Set the timeout for the prologue and epilogue execution on computing nodes #PROLOGUE_EPILOGUE_TIMEOUT="60" # Files to execute before and after each job on the first computing node # (by default nothing is executed) #PROLOGUE_EXEC_FILE="/path/to/prog" #EPILOGUE_EXEC_FILE="/path/to/prog" # Set the timeout for the prologue and epilogue execution on the OAR server #SERVER_PROLOGUE_EPILOGUE_TIMEOUT="60" # Files to execute before and after each job on the OAR server (by default # nothing is executed) #SERVER_PROLOGUE_EXEC_FILE="/path/to/prog" #SERVER_EPILOGUE_EXEC_FILE="/path/to/prog" ######################## # Scheduler parameters # ############################################################################### # # Maximum of seconds used by a scheduler SCHEDULER_TIMEOUT="120" # Time to add between each jobs (for example: time for administration tasks or # time to let computers to reboot) SCHEDULER_JOB_SECURITY_TIME="1" # Minimum time in seconds that can be considered like a hole where a job could # be scheduled in (if you have performance problems, you can try to increase # this) SCHEDULER_GANTT_HOLE_MINIMUM_TIME="300" # You can add an order preference on resources assigned by the # system(SQL ORDER syntax) SCHEDULER_RESOURCE_ORDER="scheduler_priority ASC, suspended_jobs ASC, switch ASC, network_address DESC, resource_id ASC" # If next line is uncommented then OAR will automatically update the value of # "scheduler_priority" field corresponding to the besteffort jobs. # The syntax is field names separated by "/". The value affected to # "scheduler_priority" depends of the position of the field name. SCHEDULER_PRIORITY_HIERARCHY_ORDER="switch/network_address/cpu" # You can specify a type of resources that will be always assigned for each job # (for exemple: enable all jobs to be able to log on the cluster frontales) # For more information, see the FAQ #SCHEDULER_RESOURCES_ALWAYS_ASSIGNED_TYPE="frontal" # This says to the scheduler to treate resources of these types, where there is # a suspended job, like free ones. So some other jobs can be scheduled on these # resources. (list resource types separate with spaces; Default value is # nothing so no other job can be scheduled on suspended job resources) #SCHEDULER_AVAILABLE_SUSPENDED_RESOURCE_TYPE="default licence VLAN" SCHEDULER_AVAILABLE_SUSPENDED_RESOURCE_TYPE="default" # For a debug purpose, scheduler decisions can be logged into the database # Uncomment the next line in order to activate the logging mechanism SCHEDULER_LOG_DECISIONS="no" # Time to wait when a reservation has not got all resources that it has reserved # (some resources may have become Suspected or Absent since the job submission) # before to launch the job on the remaining resources (default is 300s) #RESERVATION_WAITING_RESOURCES_TIMEOUT="300" # Set the granularity of the OAR accounting feature (in seconds) # Used by the oaraccounting command and the # oar_sched_gantt_with_timesharing_and_fairsharing to calculate the timesharing # policy. Default is 1 day (86400s) #ACCOUNTING_WINDOW="86400" ############################################################################### ########################################################################### # If you want to manage starting and stopping node feature. OAR gives you # # this API: # ############################################################################### # # When OAR scheduler wants some nodes to wake up then it launches this command # and puts on its STDIN the list of nodes to wake up (one hostname by line). # The scheduler looks at the available_upto field in the resources table to know # if the node will be started for enough time. #SCHEDULER_NODE_MANAGER_WAKE_UP_CMD="/path/to/the/command with your args" # When OAR considers that some nodes can be shut down, it launches this command # and puts the node list on its STDIN(one hostname by line). #SCHEDULER_NODE_MANAGER_SLEEP_CMD="/path/to/the/command args" #SCHEDULER_NODE_MANAGER_SLEEP_CMD="taktuk -s -f - -t 3 b e t 3 k 9 [ sudo halt ]" #SCHEDULER_NODE_MANAGER_SLEEP_CMD="/usr/local/oar/sentinelle.pl -f - -t 3 -p 'sudo halt'" # Parameters for the scheduler to decide when a node is idle. # Number of seconds since the last job was terminated on nodes #SCHEDULER_NODE_MANAGER_IDLE_TIME="600" # Parameters for the scheduler to decide if a node will have enough time to sleep. # Number of seconds before the next job #SCHEDULER_NODE_MANAGER_SLEEP_TIME="600" ################################################################################ ############################## # Suspend/Resume job feature # ############################################################################### # # Name of the perl script that manages suspend/resume. # (default is /etc/oar/suspend_resume_manager.pl) #SUSPEND_RESUME_FILE="/etc/oar/suspend_resume_manager.pl" # Files to execute just after a job was suspended and just before a job was resumed #JUST_AFTER_SUSPEND_EXEC_FILE="/path/to/prog" #JUST_BEFORE_RESUME_EXEC_FILE="/path/to/prog" # Timeout for the two previous scripts #SUSPEND_RESUME_SCRIPT_TIMEOUT="60" ############################################################################### ################## # CPUSET feature # ############################################################################### # Indicate the name of the database field that contains the cpu number of the node. # If this option is set then users must use oarsh instead of ssh to walk on # each nodes that they have reserved via oarsub. # Look at Tools/oarsh/README # (if defined, this otion turn on the cpuset feature in OAR) #CPUSET_RESOURCE_PROPERTY_DB_FIELD="cpuset" # Name of the perl script that manages cpuset. # (default is /etc/oar/cpuset_manager.pl which handles the linux kernel cpuset) CPUSET_FILE="/etc/oar/cpuset_manager.pl" # Path of the relative directory where the cpusets will be created on each # nodes(same value than in /proc/self/cpuset) # If you change the default value (/oar) then you have to edit the file # cpuset_manager.pl and change it accordingly. CPUSET_PATH="/oar" ############################################################################### ######### # OARSH # ############################################################################### # # This variable must be set to enable the use of oarsh from a frontale node # Otherwise you must not set this variable if you are not on a frontale #OARSH_OARSTAT_CMD="/usr/bin/oarstat" # The following variable adds options to ssh (or OPENSSH_CMD if configured). # If one option is not handled by your ssh version just remove it BUT be # careful because these options are there for security reasons OARSH_OPENSSH_DEFAULT_OPTIONS="-oProxyCommand=none -oPermitLocalCommand=no" # If you set this variable to something different from 0 then oarsh will act # like a normal ssh **without** CPUSET restriction. # WARNING: this is a critical functionality (this is only useful if users want # to have a command to connect on every nodes without taking care of there ssh # configuration and act like a ssh) #OARSH_BYPASS_WHOLE_SECURITY="0" ############################################################################### #DESKTOP_COMPUTING_ALLOW_CREATE_NODE="0" #DESKTOP_COMPUTING_EXPIRY="300" #STAGEOUT_DIR="/var/lib/oar/stageouts/" #STAGEIN_DIR="/var/lib/oar/stageins" #STAGEIN_CACHE_EXPIRY="144" oar-2.5.7/tests/scheduler/data/003_my.cnf0000777015014700017500000000000012677211234021147 2000_my.cnfustar neyronneyronoar-2.5.7/tests/scheduler/data/002_my.cnf0000777015014700017500000000000012677211234021146 2000_my.cnfustar neyronneyronoar-2.5.7/tests/scheduler/data/003_heavy_load.sql0000644015014700017500000111276412677211234021211 0ustar neyronneyron-- MySQL dump 10.11 -- -- Host: localhost Database: oar -- ------------------------------------------------------ -- Server version 5.0.51a-15-log /*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; /*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; /*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; /*!40101 SET NAMES utf8 */; /*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; /*!40103 SET TIME_ZONE='+00:00' */; /*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; -- -- Table structure for table `accounting` -- DROP TABLE IF EXISTS `accounting`; SET @saved_cs_client = @@character_set_client; SET character_set_client = utf8; CREATE TABLE `accounting` ( `window_start` int(10) unsigned NOT NULL, `window_stop` int(10) unsigned NOT NULL, `accounting_user` varchar(255) NOT NULL, `accounting_project` varchar(255) NOT NULL, `queue_name` varchar(100) NOT NULL, `consumption_type` enum('ASKED','USED') NOT NULL, `consumption` int(10) unsigned NOT NULL, PRIMARY KEY (`window_start`,`window_stop`,`accounting_user`,`accounting_project`,`queue_name`,`consumption_type`), KEY `accounting_user` (`accounting_user`), KEY `accounting_project` (`accounting_project`), KEY `accounting_queue` (`queue_name`), KEY `accounting_type` (`consumption_type`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1; SET character_set_client = @saved_cs_client; -- -- Dumping data for table `accounting` -- LOCK TABLES `accounting` WRITE; /*!40000 ALTER TABLE `accounting` DISABLE KEYS */; /*!40000 ALTER TABLE `accounting` ENABLE KEYS */; UNLOCK TABLES; -- -- Table structure for table `admission_rules` -- DROP TABLE IF EXISTS `admission_rules`; SET @saved_cs_client = @@character_set_client; SET character_set_client = utf8; CREATE TABLE `admission_rules` ( `id` int(10) unsigned NOT NULL auto_increment, `rule` text NOT NULL, PRIMARY KEY (`id`) ) ENGINE=MyISAM AUTO_INCREMENT=15 DEFAULT CHARSET=latin1; SET character_set_client = @saved_cs_client; -- -- Dumping data for table `admission_rules` -- LOCK TABLES `admission_rules` WRITE; /*!40000 ALTER TABLE `admission_rules` DISABLE KEYS */; INSERT INTO `admission_rules` VALUES (1,'if (not defined($queue_name)) {$queue_name=\"default\";}'),(2,'die (\"[ADMISSION RULE] root and oar users are not allowed to submit jobs.\\n\") if ( $user eq \"root\" or $user eq \"oar\" );'),(3,'\nmy $admin_group = \"admin\";\nif ($queue_name eq \"admin\") {\n my $members; \n (undef,undef,undef, $members) = getgrnam($admin_group);\n my %h = map { $_ => 1 } split(/\\s+/,$members);\n if ( $h{$user} ne 1 ) {\n {die(\"[ADMISSION RULE] Only member of the group \".$admin_group.\" can submit jobs in the admin queue\\n\");}\n }\n}\n'),(4,'\nmy @bad_resources = (\"type\",\"state\",\"next_state\",\"finaud_decision\",\"next_finaud_decision\",\"state_num\",\"suspended_jobs\",\"besteffort\",\"deploy\",\"expiry_date\",\"desktop_computing\",\"last_job_date\",\"available_upto\",\"scheduler_priority\");\nforeach my $mold (@{$ref_resource_list}){\n foreach my $r (@{$mold->[0]}){\n my $i = 0;\n while (($i <= $#{$r->{resources}})){\n if (grep(/^$r->{resources}->[$i]->{resource}$/, @bad_resources)){\n die(\"[ADMISSION RULE] \'$r->{resources}->[$i]->{resource}\' resource is not allowed\\n\");\n }\n $i++;\n }\n }\n}\n'),(5,'\nif (grep(/^besteffort$/, @{$type_list}) and not $queue_name eq \"besteffort\"){\n $queue_name = \"besteffort\";\n print(\"[ADMISSION RULE] Automatically redirect in the besteffort queue\\n\");\n}\nif ($queue_name eq \"besteffort\" and not grep(/^besteffort$/, @{$type_list})) {\n push(@{$type_list},\"besteffort\");\n print(\"[ADMISSION RULE] Automatically add the besteffort type\\n\");\n}\nif (grep(/^besteffort$/, @{$type_list})){\n if ($jobproperties ne \"\"){\n $jobproperties = \"($jobproperties) AND besteffort = \\\'YES\\\'\";\n }else{\n $jobproperties = \"besteffort = \\\'YES\\\'\";\n }\n print(\"[ADMISSION RULE] Automatically add the besteffort constraint on the resources\\n\");\n}\n'),(6,'\nif ((grep(/^besteffort$/, @{$type_list})) and ($reservationField ne \"None\")){\n die(\"[ADMISSION RULE] Error: a job cannot both be of type besteffort and be a reservation.\\n\");\n}\n'),(7,'\nif (grep(/^deploy$/, @{$type_list})){\n if ($jobproperties ne \"\"){\n $jobproperties = \"($jobproperties) AND deploy = \\\'YES\\\'\";\n }else{\n $jobproperties = \"deploy = \\\'YES\\\'\";\n }\n}\n'),(8,'\nmy @bad_resources = (\"core\",\"cpu\",\"resource_id\",);\nif (grep(/^(deploy|allow_classic_ssh)$/, @{$type_list})){\n foreach my $mold (@{$ref_resource_list}){\n foreach my $r (@{$mold->[0]}){\n my $i = 0;\n while (($i <= $#{$r->{resources}})){\n if (grep(/^$r->{resources}->[$i]->{resource}$/, @bad_resources)){\n die(\"[ADMISSION RULE] \'$r->{resources}->[$i]->{resource}\' resource is not allowed with a deploy or allow_classic_ssh type job\\n\");\n }\n $i++;\n }\n }\n }\n}\n'),(9,'\nif (grep(/^desktop_computing$/, @{$type_list})){\n print(\"[ADMISSION RULE] Added automatically desktop_computing resource constraints\\n\");\n if ($jobproperties ne \"\"){\n $jobproperties = \"($jobproperties) AND desktop_computing = \\\'YES\\\'\";\n }else{\n $jobproperties = \"desktop_computing = \\\'YES\\\'\";\n }\n}else{\n if ($jobproperties ne \"\"){\n $jobproperties = \"($jobproperties) AND desktop_computing = \\\'NO\\\'\";\n }else{\n $jobproperties = \"desktop_computing = \\\'NO\\\'\";\n }\n}\n'),(10,'\nif ($reservationField eq \"toSchedule\") {\n my $unlimited=0;\n if (open(FILE, \"< $ENV{HOME}/unlimited_reservation.users\")) {\n while (){\n if (m/^\\s*$user\\s*$/m){\n $unlimited=1;\n }\n }\n close(FILE);\n }\n if ($unlimited > 0) {\n print(\"[ADMISSION RULE] $user is granted the privilege to do unlimited reservations\\n\");\n } else {\n my $max_nb_resa = 2;\n my $nb_resa = $dbh->do(\" SELECT job_id\n FROM jobs\n WHERE\n job_user = \\\'$user\\\' AND\n (reservation = \\\'toSchedule\\\' OR\n reservation = \\\'Scheduled\\\') AND\n (state = \\\'Waiting\\\' OR state = \\\'Hold\\\')\n \");\n if ($nb_resa >= $max_nb_resa){\n die(\"[ADMISSION RULE] Error : you cannot have more than $max_nb_resa waiting reservations.\\n\");\n }\n }\n}\n'),(11,'\nmy $max_walltime = OAR::IO::sql_to_duration(\"12:00:00\");\nif (($jobType eq \"INTERACTIVE\") and ($reservationField eq \"None\")){ \n foreach my $mold (@{$ref_resource_list}){\n if ((defined($mold->[1])) and ($max_walltime < $mold->[1])){\n print(\"[ADMISSION RULE] Walltime to big for an INTERACTIVE job so it is set to $max_walltime.\\n\");\n $mold->[1] = $max_walltime;\n }\n }\n}\n'),(12,'\nmy $default_wall = OAR::IO::sql_to_duration(\"2:00:00\");\nforeach my $mold (@{$ref_resource_list}){\n if (!defined($mold->[1])){\n print(\"[ADMISSION RULE] Set default walltime to $default_wall.\\n\");\n $mold->[1] = $default_wall;\n }\n}\n'),(13,'\nmy @types = (\"container\",\"inner\",\"deploy\",\"desktop_computing\",\"besteffort\",\"cosystem\",\"idempotent\",\"timesharing\",\"allow_classic_ssh\");\nforeach my $t (@{$type_list}){\n my $i = 0;\n while (($types[$i] ne $t) and ($i <= $#types)){\n $i++;\n }\n if (($i > $#types) and ($t !~ /^(timesharing|inner)/)){\n die(\"[ADMISSION RULE] The job type $t is not handled by OAR; Right values are : @types\\n\");\n }\n}\n'),(14,'\nforeach my $mold (@{$ref_resource_list}){\n foreach my $r (@{$mold->[0]}){\n my $prop = $r->{property};\n if (($prop !~ /[\\s\\(]type[\\s=]/) and ($prop !~ /^type[\\s=]/)){\n if (!defined($prop)){\n $r->{property} = \"type = \\\'default\\\'\";\n }else{\n $r->{property} = \"($r->{property}) AND type = \\\'default\\\'\";\n }\n }\n }\n}\nprint(\"[ADMISSION RULE] Modify resource description with type constraints\\n\");\n'); /*!40000 ALTER TABLE `admission_rules` ENABLE KEYS */; UNLOCK TABLES; -- -- Table structure for table `assigned_resources` -- DROP TABLE IF EXISTS `assigned_resources`; SET @saved_cs_client = @@character_set_client; SET character_set_client = utf8; CREATE TABLE `assigned_resources` ( `moldable_job_id` int(10) unsigned NOT NULL, `resource_id` int(10) unsigned NOT NULL, `assigned_resource_index` enum('CURRENT','LOG') NOT NULL default 'CURRENT', PRIMARY KEY (`moldable_job_id`,`resource_id`), KEY `mjob_id` (`moldable_job_id`), KEY `log` (`assigned_resource_index`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1; SET character_set_client = @saved_cs_client; -- -- Dumping data for table `assigned_resources` -- LOCK TABLES `assigned_resources` WRITE; /*!40000 ALTER TABLE `assigned_resources` DISABLE KEYS */; INSERT INTO `assigned_resources` VALUES (1,1,'CURRENT'),(1,2,'CURRENT'),(1,3,'CURRENT'),(1,4,'CURRENT'),(1,5,'CURRENT'),(1,6,'CURRENT'),(1,7,'CURRENT'),(1,8,'CURRENT'),(1,9,'CURRENT'),(1,10,'CURRENT'),(1,11,'CURRENT'),(1,12,'CURRENT'),(1,13,'CURRENT'),(1,14,'CURRENT'),(1,15,'CURRENT'),(1,16,'CURRENT'),(1,17,'CURRENT'),(1,18,'CURRENT'),(1,19,'CURRENT'),(1,20,'CURRENT'),(1,21,'CURRENT'),(1,22,'CURRENT'),(1,23,'CURRENT'),(1,24,'CURRENT'),(1,25,'CURRENT'),(1,26,'CURRENT'),(1,27,'CURRENT'),(1,28,'CURRENT'),(1,29,'CURRENT'),(1,30,'CURRENT'),(1,31,'CURRENT'),(1,32,'CURRENT'),(1,33,'CURRENT'),(1,34,'CURRENT'),(1,35,'CURRENT'),(1,36,'CURRENT'),(1,37,'CURRENT'),(1,38,'CURRENT'),(1,39,'CURRENT'),(1,40,'CURRENT'),(1,41,'CURRENT'),(1,42,'CURRENT'),(1,43,'CURRENT'),(1,44,'CURRENT'),(1,45,'CURRENT'),(1,46,'CURRENT'),(1,47,'CURRENT'),(1,48,'CURRENT'),(1,49,'CURRENT'),(1,50,'CURRENT'),(1,51,'CURRENT'),(1,52,'CURRENT'),(1,53,'CURRENT'),(1,54,'CURRENT'),(1,55,'CURRENT'),(1,56,'CURRENT'),(1,57,'CURRENT'),(1,58,'CURRENT'),(1,59,'CURRENT'),(1,60,'CURRENT'),(1,61,'CURRENT'),(1,62,'CURRENT'),(1,63,'CURRENT'),(1,64,'CURRENT'),(1,65,'CURRENT'),(1,66,'CURRENT'),(1,67,'CURRENT'),(1,68,'CURRENT'),(1,69,'CURRENT'),(1,70,'CURRENT'),(1,71,'CURRENT'),(1,72,'CURRENT'),(1,73,'CURRENT'),(1,74,'CURRENT'),(1,75,'CURRENT'),(1,76,'CURRENT'),(1,77,'CURRENT'),(1,78,'CURRENT'),(1,79,'CURRENT'),(1,80,'CURRENT'),(1,81,'CURRENT'),(1,82,'CURRENT'),(1,83,'CURRENT'),(1,84,'CURRENT'),(1,85,'CURRENT'),(1,86,'CURRENT'),(1,87,'CURRENT'),(1,88,'CURRENT'),(1,89,'CURRENT'),(1,90,'CURRENT'),(1,91,'CURRENT'),(1,92,'CURRENT'),(1,93,'CURRENT'),(1,94,'CURRENT'),(1,95,'CURRENT'),(1,96,'CURRENT'),(1,97,'CURRENT'),(1,98,'CURRENT'),(1,99,'CURRENT'),(1,100,'CURRENT'),(1,101,'CURRENT'),(1,102,'CURRENT'),(1,103,'CURRENT'),(1,104,'CURRENT'),(1,105,'CURRENT'),(1,106,'CURRENT'),(1,107,'CURRENT'),(1,108,'CURRENT'),(1,109,'CURRENT'),(1,110,'CURRENT'),(1,111,'CURRENT'),(1,112,'CURRENT'),(1,113,'CURRENT'),(1,114,'CURRENT'),(1,115,'CURRENT'),(1,116,'CURRENT'),(1,117,'CURRENT'),(1,118,'CURRENT'),(1,119,'CURRENT'),(1,120,'CURRENT'),(1,121,'CURRENT'),(1,122,'CURRENT'),(1,123,'CURRENT'),(1,124,'CURRENT'),(1,125,'CURRENT'),(1,126,'CURRENT'),(1,127,'CURRENT'),(1,128,'CURRENT'),(1,129,'CURRENT'),(1,130,'CURRENT'),(1,131,'CURRENT'),(1,132,'CURRENT'),(1,133,'CURRENT'),(1,134,'CURRENT'),(1,135,'CURRENT'),(1,136,'CURRENT'),(1,137,'CURRENT'),(1,138,'CURRENT'),(1,139,'CURRENT'),(1,140,'CURRENT'),(1,141,'CURRENT'),(1,142,'CURRENT'),(1,143,'CURRENT'),(1,144,'CURRENT'),(1,145,'CURRENT'),(1,146,'CURRENT'),(1,147,'CURRENT'),(1,148,'CURRENT'),(1,149,'CURRENT'),(1,150,'CURRENT'),(1,151,'CURRENT'),(1,152,'CURRENT'),(1,153,'CURRENT'),(1,154,'CURRENT'),(1,155,'CURRENT'),(1,156,'CURRENT'),(1,157,'CURRENT'),(1,158,'CURRENT'),(1,159,'CURRENT'),(1,160,'CURRENT'),(1,161,'CURRENT'),(1,162,'CURRENT'),(1,163,'CURRENT'),(1,164,'CURRENT'),(1,165,'CURRENT'),(1,166,'CURRENT'),(1,167,'CURRENT'),(1,168,'CURRENT'),(1,169,'CURRENT'),(1,170,'CURRENT'),(1,171,'CURRENT'),(1,172,'CURRENT'),(1,173,'CURRENT'),(1,174,'CURRENT'),(1,175,'CURRENT'),(1,176,'CURRENT'),(1,177,'CURRENT'),(1,178,'CURRENT'),(1,179,'CURRENT'),(1,180,'CURRENT'),(1,181,'CURRENT'),(1,182,'CURRENT'),(1,183,'CURRENT'),(1,184,'CURRENT'),(1,185,'CURRENT'),(1,186,'CURRENT'),(1,187,'CURRENT'),(1,188,'CURRENT'),(1,189,'CURRENT'),(1,190,'CURRENT'),(1,191,'CURRENT'),(1,192,'CURRENT'),(1,193,'CURRENT'),(1,194,'CURRENT'),(1,195,'CURRENT'),(1,196,'CURRENT'),(1,197,'CURRENT'),(1,198,'CURRENT'),(1,199,'CURRENT'),(1,200,'CURRENT'),(1,201,'CURRENT'),(1,202,'CURRENT'),(1,203,'CURRENT'),(1,204,'CURRENT'),(1,205,'CURRENT'),(1,206,'CURRENT'),(1,207,'CURRENT'),(1,208,'CURRENT'),(1,209,'CURRENT'),(1,210,'CURRENT'),(1,211,'CURRENT'),(1,212,'CURRENT'),(1,213,'CURRENT'),(1,214,'CURRENT'),(1,215,'CURRENT'),(1,216,'CURRENT'),(1,217,'CURRENT'),(1,218,'CURRENT'),(1,219,'CURRENT'),(1,220,'CURRENT'),(1,221,'CURRENT'),(1,222,'CURRENT'),(1,223,'CURRENT'),(1,224,'CURRENT'),(1,225,'CURRENT'),(1,226,'CURRENT'),(1,227,'CURRENT'),(1,228,'CURRENT'),(1,229,'CURRENT'),(1,230,'CURRENT'),(1,231,'CURRENT'),(1,232,'CURRENT'),(1,233,'CURRENT'),(1,234,'CURRENT'),(1,235,'CURRENT'),(1,236,'CURRENT'),(1,237,'CURRENT'),(1,238,'CURRENT'),(1,239,'CURRENT'),(1,240,'CURRENT'),(1,241,'CURRENT'),(1,242,'CURRENT'),(1,243,'CURRENT'),(1,244,'CURRENT'),(1,245,'CURRENT'),(1,246,'CURRENT'),(1,247,'CURRENT'),(1,248,'CURRENT'),(1,249,'CURRENT'),(1,250,'CURRENT'),(1,251,'CURRENT'),(1,252,'CURRENT'),(1,253,'CURRENT'),(1,254,'CURRENT'),(1,255,'CURRENT'),(1,256,'CURRENT'),(1,257,'CURRENT'),(1,258,'CURRENT'),(1,259,'CURRENT'),(1,260,'CURRENT'),(1,261,'CURRENT'),(1,262,'CURRENT'),(1,263,'CURRENT'),(1,264,'CURRENT'),(1,265,'CURRENT'),(1,266,'CURRENT'),(1,267,'CURRENT'),(1,268,'CURRENT'),(1,269,'CURRENT'),(1,270,'CURRENT'),(1,271,'CURRENT'),(1,272,'CURRENT'),(1,273,'CURRENT'),(1,274,'CURRENT'),(1,275,'CURRENT'),(1,276,'CURRENT'),(1,277,'CURRENT'),(1,278,'CURRENT'),(1,279,'CURRENT'),(1,280,'CURRENT'),(1,281,'CURRENT'),(1,282,'CURRENT'),(1,283,'CURRENT'),(1,284,'CURRENT'),(1,285,'CURRENT'),(1,286,'CURRENT'),(1,287,'CURRENT'),(1,288,'CURRENT'),(1,289,'CURRENT'),(1,290,'CURRENT'),(1,291,'CURRENT'),(1,292,'CURRENT'),(1,293,'CURRENT'),(1,294,'CURRENT'),(1,295,'CURRENT'),(1,296,'CURRENT'),(1,297,'CURRENT'),(1,298,'CURRENT'),(1,299,'CURRENT'),(1,300,'CURRENT'),(1,301,'CURRENT'),(1,302,'CURRENT'),(1,303,'CURRENT'),(1,304,'CURRENT'),(1,305,'CURRENT'),(1,306,'CURRENT'),(1,307,'CURRENT'),(1,308,'CURRENT'),(1,309,'CURRENT'),(1,310,'CURRENT'),(1,311,'CURRENT'),(1,312,'CURRENT'),(1,313,'CURRENT'),(1,314,'CURRENT'),(1,315,'CURRENT'),(1,316,'CURRENT'),(1,317,'CURRENT'),(1,318,'CURRENT'),(1,319,'CURRENT'),(1,320,'CURRENT'),(1,321,'CURRENT'),(1,322,'CURRENT'),(1,323,'CURRENT'),(1,324,'CURRENT'),(1,325,'CURRENT'),(1,326,'CURRENT'),(1,327,'CURRENT'),(1,328,'CURRENT'),(1,329,'CURRENT'),(1,330,'CURRENT'),(1,331,'CURRENT'),(1,332,'CURRENT'),(1,333,'CURRENT'),(1,334,'CURRENT'),(1,335,'CURRENT'),(1,336,'CURRENT'),(1,337,'CURRENT'),(1,338,'CURRENT'),(1,339,'CURRENT'),(1,340,'CURRENT'),(1,341,'CURRENT'),(1,342,'CURRENT'),(1,343,'CURRENT'),(1,344,'CURRENT'),(1,345,'CURRENT'),(1,346,'CURRENT'),(1,347,'CURRENT'),(1,348,'CURRENT'),(1,349,'CURRENT'),(1,350,'CURRENT'),(1,351,'CURRENT'),(1,352,'CURRENT'),(1,353,'CURRENT'),(1,354,'CURRENT'),(1,355,'CURRENT'),(1,356,'CURRENT'),(1,357,'CURRENT'),(1,358,'CURRENT'),(1,359,'CURRENT'),(1,360,'CURRENT'),(1,361,'CURRENT'),(1,362,'CURRENT'),(1,363,'CURRENT'),(1,364,'CURRENT'),(1,365,'CURRENT'),(1,366,'CURRENT'),(1,367,'CURRENT'),(1,368,'CURRENT'),(1,369,'CURRENT'),(1,370,'CURRENT'),(1,371,'CURRENT'),(1,372,'CURRENT'),(1,373,'CURRENT'),(1,374,'CURRENT'),(1,375,'CURRENT'),(1,376,'CURRENT'),(1,377,'CURRENT'),(1,378,'CURRENT'),(1,379,'CURRENT'),(1,380,'CURRENT'),(1,381,'CURRENT'),(1,382,'CURRENT'),(1,383,'CURRENT'),(1,384,'CURRENT'); /*!40000 ALTER TABLE `assigned_resources` ENABLE KEYS */; UNLOCK TABLES; -- -- Table structure for table `challenges` -- DROP TABLE IF EXISTS `challenges`; SET @saved_cs_client = @@character_set_client; SET character_set_client = utf8; CREATE TABLE `challenges` ( `job_id` int(10) unsigned NOT NULL, `challenge` varchar(255) NOT NULL, `ssh_private_key` text NOT NULL, `ssh_public_key` text NOT NULL, PRIMARY KEY (`job_id`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1; SET character_set_client = @saved_cs_client; -- -- Dumping data for table `challenges` -- LOCK TABLES `challenges` WRITE; /*!40000 ALTER TABLE `challenges` DISABLE KEYS */; INSERT INTO `challenges` VALUES (1,'985377625403','',''),(2,'667427831868','',''),(3,'328575936452','',''),(4,'526436358531','',''),(5,'339450127053','',''),(6,'352902324711','',''),(7,'439787935539','',''),(8,'433177980900','',''),(9,'412158820386','',''),(10,'889567426013','',''),(11,'123787477918','',''),(12,'437301955259','',''),(13,'687474423394','',''),(14,'746288048177','',''),(15,'14582702730','',''),(16,'997663565985','',''),(17,'674879145649','',''),(18,'690024722441','',''),(19,'16737794344','',''),(20,'321956478365','',''),(21,'198102593728','',''),(22,'567295823087','',''),(23,'347901824469','',''),(24,'358981637823','',''),(25,'963363095260','',''),(26,'312087497049','',''),(27,'529815651084','',''),(28,'741712139294','',''),(29,'722662389119','',''),(30,'456581414983','',''),(31,'564700135802','',''),(32,'930923546039','',''),(33,'618351217432','',''),(34,'253933886838','',''),(35,'919951469012','',''),(36,'631391253628','',''),(37,'479817063155','',''),(38,'113409831727','',''),(39,'460256586390','',''),(40,'888637919751','',''),(41,'612698466823','',''),(42,'244960600118','',''),(43,'986237258258','',''),(44,'764762977211','',''),(45,'522188644464','',''),(46,'557689930153','',''),(47,'482398586654','',''),(48,'426850456119','',''),(49,'445779774178','',''),(50,'382228959891','',''),(51,'306016431962','',''),(52,'496333322328','',''),(53,'936094115561','',''),(54,'950104920267','',''),(55,'210750320534','',''),(56,'760070355682','',''),(57,'34628360140','',''),(58,'45393074936','',''),(59,'778923778169','',''),(60,'416225297915','',''),(61,'540753317139','',''),(62,'822269853045','',''),(63,'794077736864','',''),(64,'199294504317','',''),(65,'383396045145','',''),(66,'919667708761','',''),(67,'387379707609','',''),(68,'666955499284','',''),(69,'429983211987','',''),(70,'266966335083','',''),(71,'67774423238','',''),(72,'379797035436','',''),(73,'632539517319','',''),(74,'718921154345','',''),(75,'281791602102','',''),(76,'760220841345','',''),(77,'634989993487','',''),(78,'727849559000','',''),(79,'952572563271','',''),(80,'144459665128','',''),(81,'526982657917','',''),(82,'504834232227','',''),(83,'332923251510','',''),(84,'943013631579','',''),(85,'930543974814','',''),(86,'625359243786','',''),(87,'3119980291','',''),(88,'276668661347','',''),(89,'323375521301','',''),(90,'123581744804','',''),(91,'460708778890','',''),(92,'639891122774','',''),(93,'329620894118','',''),(94,'28464907388','',''),(95,'135332705526','',''),(96,'396811226922','',''),(97,'645932971806','',''),(98,'576291043152','',''),(99,'151294307624','',''),(100,'30598331782','',''),(101,'27490717898','',''); /*!40000 ALTER TABLE `challenges` ENABLE KEYS */; UNLOCK TABLES; -- -- Table structure for table `event_log_hostnames` -- DROP TABLE IF EXISTS `event_log_hostnames`; SET @saved_cs_client = @@character_set_client; SET character_set_client = utf8; CREATE TABLE `event_log_hostnames` ( `event_id` int(10) unsigned NOT NULL, `hostname` varchar(255) NOT NULL, PRIMARY KEY (`event_id`,`hostname`), KEY `event_hostname` (`hostname`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1; SET character_set_client = @saved_cs_client; -- -- Dumping data for table `event_log_hostnames` -- LOCK TABLES `event_log_hostnames` WRITE; /*!40000 ALTER TABLE `event_log_hostnames` DISABLE KEYS */; /*!40000 ALTER TABLE `event_log_hostnames` ENABLE KEYS */; UNLOCK TABLES; -- -- Table structure for table `event_logs` -- DROP TABLE IF EXISTS `event_logs`; SET @saved_cs_client = @@character_set_client; SET character_set_client = utf8; CREATE TABLE `event_logs` ( `event_id` int(10) unsigned NOT NULL auto_increment, `type` varchar(50) NOT NULL, `job_id` int(10) unsigned NOT NULL, `date` int(10) unsigned NOT NULL, `description` varchar(255) NOT NULL, `to_check` enum('YES','NO') NOT NULL default 'YES', PRIMARY KEY (`event_id`), KEY `event_type` (`type`), KEY `event_check` (`to_check`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1; SET character_set_client = @saved_cs_client; -- -- Dumping data for table `event_logs` -- LOCK TABLES `event_logs` WRITE; /*!40000 ALTER TABLE `event_logs` DISABLE KEYS */; /*!40000 ALTER TABLE `event_logs` ENABLE KEYS */; UNLOCK TABLES; -- -- Table structure for table `files` -- DROP TABLE IF EXISTS `files`; SET @saved_cs_client = @@character_set_client; SET character_set_client = utf8; CREATE TABLE `files` ( `file_id` int(10) unsigned NOT NULL auto_increment, `md5sum` varchar(255) default NULL, `location` varchar(255) default NULL, `method` varchar(255) default NULL, `compression` varchar(255) default NULL, `size` int(10) unsigned NOT NULL, PRIMARY KEY (`file_id`), KEY `md5sum` (`md5sum`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1; SET character_set_client = @saved_cs_client; -- -- Dumping data for table `files` -- LOCK TABLES `files` WRITE; /*!40000 ALTER TABLE `files` DISABLE KEYS */; /*!40000 ALTER TABLE `files` ENABLE KEYS */; UNLOCK TABLES; -- -- Table structure for table `frag_jobs` -- DROP TABLE IF EXISTS `frag_jobs`; SET @saved_cs_client = @@character_set_client; SET character_set_client = utf8; CREATE TABLE `frag_jobs` ( `frag_id_job` int(10) unsigned NOT NULL, `frag_date` int(10) unsigned NOT NULL, `frag_state` enum('LEON','TIMER_ARMED','LEON_EXTERMINATE','FRAGGED') NOT NULL default 'LEON', PRIMARY KEY (`frag_id_job`), KEY `frag_state` (`frag_state`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1; SET character_set_client = @saved_cs_client; -- -- Dumping data for table `frag_jobs` -- LOCK TABLES `frag_jobs` WRITE; /*!40000 ALTER TABLE `frag_jobs` DISABLE KEYS */; /*!40000 ALTER TABLE `frag_jobs` ENABLE KEYS */; UNLOCK TABLES; -- -- Table structure for table `gantt_jobs_predictions` -- DROP TABLE IF EXISTS `gantt_jobs_predictions`; SET @saved_cs_client = @@character_set_client; SET character_set_client = utf8; CREATE TABLE `gantt_jobs_predictions` ( `moldable_job_id` int(10) unsigned NOT NULL, `start_time` int(10) unsigned NOT NULL, PRIMARY KEY (`moldable_job_id`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1; SET character_set_client = @saved_cs_client; -- -- Dumping data for table `gantt_jobs_predictions` -- LOCK TABLES `gantt_jobs_predictions` WRITE; /*!40000 ALTER TABLE `gantt_jobs_predictions` DISABLE KEYS */; INSERT INTO `gantt_jobs_predictions` VALUES (0,1224778714),(1,1224778628),(2,1224793089),(3,1224825550),(4,1224843611),(5,1224879672),(6,1224901333),(7,1224908594),(8,1224937455),(9,1224793089),(10,1224948316),(11,1224793089),(12,1224966377),(13,1224793089),(14,1224988038),(15,1224793089),(16,1225016899),(17,1224800350); /*!40000 ALTER TABLE `gantt_jobs_predictions` ENABLE KEYS */; UNLOCK TABLES; -- -- Table structure for table `gantt_jobs_predictions_log` -- DROP TABLE IF EXISTS `gantt_jobs_predictions_log`; SET @saved_cs_client = @@character_set_client; SET character_set_client = utf8; CREATE TABLE `gantt_jobs_predictions_log` ( `sched_date` int(10) unsigned NOT NULL, `moldable_job_id` int(10) unsigned NOT NULL, `start_time` int(10) unsigned NOT NULL, PRIMARY KEY (`sched_date`,`moldable_job_id`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1; SET character_set_client = @saved_cs_client; -- -- Dumping data for table `gantt_jobs_predictions_log` -- LOCK TABLES `gantt_jobs_predictions_log` WRITE; /*!40000 ALTER TABLE `gantt_jobs_predictions_log` DISABLE KEYS */; /*!40000 ALTER TABLE `gantt_jobs_predictions_log` ENABLE KEYS */; UNLOCK TABLES; -- -- Table structure for table `gantt_jobs_predictions_visu` -- DROP TABLE IF EXISTS `gantt_jobs_predictions_visu`; SET @saved_cs_client = @@character_set_client; SET character_set_client = utf8; CREATE TABLE `gantt_jobs_predictions_visu` ( `moldable_job_id` int(10) unsigned NOT NULL, `start_time` int(10) unsigned NOT NULL, PRIMARY KEY (`moldable_job_id`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1; SET character_set_client = @saved_cs_client; -- -- Dumping data for table `gantt_jobs_predictions_visu` -- LOCK TABLES `gantt_jobs_predictions_visu` WRITE; /*!40000 ALTER TABLE `gantt_jobs_predictions_visu` DISABLE KEYS */; INSERT INTO `gantt_jobs_predictions_visu` VALUES (0,1224778679),(1,1224778628),(2,1224793089),(3,1224825550),(4,1224843611),(5,1224879672),(6,1224901333),(7,1224908594),(8,1224937455),(9,1224793089),(10,1224948316),(11,1224793089),(12,1224966377),(13,1224793089),(14,1224988038),(15,1224793089),(16,1225016899),(17,1224800350),(18,1225049360),(19,1224843611); /*!40000 ALTER TABLE `gantt_jobs_predictions_visu` ENABLE KEYS */; UNLOCK TABLES; -- -- Table structure for table `gantt_jobs_resources` -- DROP TABLE IF EXISTS `gantt_jobs_resources`; SET @saved_cs_client = @@character_set_client; SET character_set_client = utf8; CREATE TABLE `gantt_jobs_resources` ( `moldable_job_id` int(10) unsigned NOT NULL, `resource_id` int(10) unsigned NOT NULL, PRIMARY KEY (`moldable_job_id`,`resource_id`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1; SET character_set_client = @saved_cs_client; -- -- Dumping data for table `gantt_jobs_resources` -- LOCK TABLES `gantt_jobs_resources` WRITE; /*!40000 ALTER TABLE `gantt_jobs_resources` DISABLE KEYS */; INSERT INTO `gantt_jobs_resources` VALUES (1,1),(1,2),(1,3),(1,4),(1,5),(1,6),(1,7),(1,8),(1,9),(1,10),(1,11),(1,12),(1,13),(1,14),(1,15),(1,16),(1,17),(1,18),(1,19),(1,20),(1,21),(1,22),(1,23),(1,24),(1,25),(1,26),(1,27),(1,28),(1,29),(1,30),(1,31),(1,32),(1,33),(1,34),(1,35),(1,36),(1,37),(1,38),(1,39),(1,40),(1,41),(1,42),(1,43),(1,44),(1,45),(1,46),(1,47),(1,48),(1,49),(1,50),(1,51),(1,52),(1,53),(1,54),(1,55),(1,56),(1,57),(1,58),(1,59),(1,60),(1,61),(1,62),(1,63),(1,64),(1,65),(1,66),(1,67),(1,68),(1,69),(1,70),(1,71),(1,72),(1,73),(1,74),(1,75),(1,76),(1,77),(1,78),(1,79),(1,80),(1,81),(1,82),(1,83),(1,84),(1,85),(1,86),(1,87),(1,88),(1,89),(1,90),(1,91),(1,92),(1,93),(1,94),(1,95),(1,96),(1,97),(1,98),(1,99),(1,100),(1,101),(1,102),(1,103),(1,104),(1,105),(1,106),(1,107),(1,108),(1,109),(1,110),(1,111),(1,112),(1,113),(1,114),(1,115),(1,116),(1,117),(1,118),(1,119),(1,120),(1,121),(1,122),(1,123),(1,124),(1,125),(1,126),(1,127),(1,128),(1,129),(1,130),(1,131),(1,132),(1,133),(1,134),(1,135),(1,136),(1,137),(1,138),(1,139),(1,140),(1,141),(1,142),(1,143),(1,144),(1,145),(1,146),(1,147),(1,148),(1,149),(1,150),(1,151),(1,152),(1,153),(1,154),(1,155),(1,156),(1,157),(1,158),(1,159),(1,160),(1,161),(1,162),(1,163),(1,164),(1,165),(1,166),(1,167),(1,168),(1,169),(1,170),(1,171),(1,172),(1,173),(1,174),(1,175),(1,176),(1,177),(1,178),(1,179),(1,180),(1,181),(1,182),(1,183),(1,184),(1,185),(1,186),(1,187),(1,188),(1,189),(1,190),(1,191),(1,192),(1,193),(1,194),(1,195),(1,196),(1,197),(1,198),(1,199),(1,200),(1,201),(1,202),(1,203),(1,204),(1,205),(1,206),(1,207),(1,208),(1,209),(1,210),(1,211),(1,212),(1,213),(1,214),(1,215),(1,216),(1,217),(1,218),(1,219),(1,220),(1,221),(1,222),(1,223),(1,224),(1,225),(1,226),(1,227),(1,228),(1,229),(1,230),(1,231),(1,232),(1,233),(1,234),(1,235),(1,236),(1,237),(1,238),(1,239),(1,240),(1,241),(1,242),(1,243),(1,244),(1,245),(1,246),(1,247),(1,248),(1,249),(1,250),(1,251),(1,252),(1,253),(1,254),(1,255),(1,256),(1,257),(1,258),(1,259),(1,260),(1,261),(1,262),(1,263),(1,264),(1,265),(1,266),(1,267),(1,268),(1,269),(1,270),(1,271),(1,272),(1,273),(1,274),(1,275),(1,276),(1,277),(1,278),(1,279),(1,280),(1,281),(1,282),(1,283),(1,284),(1,285),(1,286),(1,287),(1,288),(1,289),(1,290),(1,291),(1,292),(1,293),(1,294),(1,295),(1,296),(1,297),(1,298),(1,299),(1,300),(1,301),(1,302),(1,303),(1,304),(1,305),(1,306),(1,307),(1,308),(1,309),(1,310),(1,311),(1,312),(1,313),(1,314),(1,315),(1,316),(1,317),(1,318),(1,319),(1,320),(1,321),(1,322),(1,323),(1,324),(1,325),(1,326),(1,327),(1,328),(1,329),(1,330),(1,331),(1,332),(1,333),(1,334),(1,335),(1,336),(1,337),(1,338),(1,339),(1,340),(1,341),(1,342),(1,343),(1,344),(1,345),(1,346),(1,347),(1,348),(1,349),(1,350),(1,351),(1,352),(1,353),(1,354),(1,355),(1,356),(1,357),(1,358),(1,359),(1,360),(1,361),(1,362),(1,363),(1,364),(1,365),(1,366),(1,367),(1,368),(1,369),(1,370),(1,371),(1,372),(1,373),(1,374),(1,375),(1,376),(1,377),(1,378),(1,379),(1,380),(1,381),(1,382),(1,383),(1,384),(2,21),(2,22),(2,23),(2,24),(2,25),(2,26),(2,27),(2,28),(2,29),(2,30),(2,31),(2,32),(2,33),(2,34),(2,35),(2,36),(2,209),(2,210),(2,211),(2,212),(2,213),(2,214),(2,215),(2,216),(2,217),(2,218),(2,219),(2,220),(2,221),(2,222),(2,223),(2,224),(2,225),(2,226),(2,227),(2,228),(2,229),(2,230),(2,231),(2,232),(2,233),(2,234),(2,235),(2,236),(2,237),(2,238),(2,239),(2,240),(2,241),(2,242),(2,243),(2,244),(2,245),(2,246),(2,247),(2,248),(2,249),(2,250),(2,251),(2,252),(2,253),(2,254),(2,255),(2,256),(2,257),(2,258),(2,259),(2,260),(2,261),(2,262),(2,263),(2,264),(2,265),(2,266),(2,267),(2,268),(2,269),(2,270),(2,271),(2,272),(2,273),(2,274),(2,275),(2,276),(2,277),(2,278),(2,279),(2,280),(2,281),(2,282),(2,283),(2,284),(2,285),(2,286),(2,287),(2,288),(2,289),(2,290),(2,291),(2,292),(2,293),(2,294),(2,295),(2,296),(2,297),(2,298),(2,299),(2,300),(2,301),(2,302),(2,303),(2,304),(2,305),(2,306),(2,307),(2,308),(2,309),(2,310),(2,311),(2,312),(2,313),(2,314),(2,315),(2,316),(2,317),(2,318),(2,319),(2,320),(2,321),(2,322),(2,323),(2,324),(2,325),(2,326),(2,327),(2,328),(2,329),(2,330),(2,331),(2,332),(2,333),(2,334),(2,335),(2,336),(2,337),(2,338),(2,339),(2,340),(2,341),(2,342),(2,343),(2,344),(2,345),(2,346),(2,347),(2,348),(2,349),(2,350),(2,351),(2,352),(2,353),(2,354),(2,355),(2,356),(2,357),(2,358),(2,359),(2,360),(2,361),(2,362),(2,363),(2,364),(2,365),(2,366),(2,367),(2,368),(2,369),(2,370),(2,371),(2,372),(2,373),(2,374),(2,375),(2,376),(2,377),(2,378),(2,379),(2,380),(2,381),(2,382),(2,383),(2,384),(3,9),(3,10),(3,11),(3,12),(3,13),(3,14),(3,15),(3,16),(3,17),(3,18),(3,19),(3,20),(3,21),(3,22),(3,23),(3,24),(3,25),(3,26),(3,27),(3,28),(3,29),(3,30),(3,31),(3,32),(3,33),(3,34),(3,35),(3,36),(3,81),(3,82),(3,83),(3,84),(3,85),(3,86),(3,87),(3,88),(3,89),(3,90),(3,91),(3,92),(3,93),(3,94),(3,95),(3,96),(3,97),(3,98),(3,99),(3,100),(3,101),(3,102),(3,103),(3,104),(3,105),(3,106),(3,107),(3,108),(3,109),(3,110),(3,111),(3,112),(3,113),(3,114),(3,115),(3,116),(3,117),(3,118),(3,119),(3,120),(3,121),(3,122),(3,123),(3,124),(3,125),(3,126),(3,127),(3,128),(3,129),(3,130),(3,131),(3,132),(3,133),(3,134),(3,135),(3,136),(3,137),(3,138),(3,139),(3,140),(3,141),(3,142),(3,143),(3,144),(3,145),(3,146),(3,147),(3,148),(3,149),(3,150),(3,151),(3,152),(3,153),(3,154),(3,155),(3,156),(3,157),(3,158),(3,159),(3,160),(3,161),(3,162),(3,163),(3,164),(3,165),(3,166),(3,167),(3,168),(3,169),(3,170),(3,171),(3,172),(3,173),(3,174),(3,175),(3,176),(3,177),(3,178),(3,179),(3,180),(3,181),(3,182),(3,183),(3,184),(3,185),(3,186),(3,187),(3,188),(3,189),(3,190),(3,191),(3,192),(3,193),(3,194),(3,195),(3,196),(3,197),(3,198),(3,199),(3,200),(3,201),(3,202),(3,203),(3,204),(3,205),(3,206),(3,207),(3,208),(3,209),(3,210),(3,211),(3,212),(3,213),(3,214),(3,215),(3,216),(3,217),(3,218),(3,219),(3,220),(3,221),(3,222),(3,223),(3,224),(3,225),(3,226),(3,227),(3,228),(3,229),(3,230),(3,231),(3,232),(3,233),(3,234),(3,235),(3,236),(3,237),(3,238),(3,239),(3,240),(3,241),(3,242),(3,243),(3,244),(3,245),(3,246),(3,247),(3,248),(3,249),(3,250),(3,251),(3,252),(3,253),(3,254),(3,255),(3,256),(3,257),(3,258),(3,259),(3,260),(3,261),(3,262),(3,263),(3,264),(3,265),(3,266),(3,267),(3,268),(3,269),(3,270),(3,271),(3,272),(3,273),(3,274),(3,275),(3,276),(3,277),(3,278),(3,279),(3,280),(3,281),(3,282),(3,283),(3,284),(3,285),(3,286),(3,287),(3,288),(3,289),(3,290),(3,291),(3,292),(3,293),(3,294),(3,295),(3,296),(3,297),(3,298),(3,299),(3,300),(3,301),(3,302),(3,303),(3,304),(3,305),(3,306),(3,307),(3,308),(3,309),(3,310),(3,311),(3,312),(3,313),(3,314),(3,315),(3,316),(3,317),(3,318),(3,319),(3,320),(3,321),(3,322),(3,323),(3,324),(3,325),(3,326),(3,327),(3,328),(3,329),(3,330),(3,331),(3,332),(3,333),(3,334),(3,335),(3,336),(3,337),(3,338),(3,339),(3,340),(3,341),(3,342),(3,343),(3,344),(3,345),(3,346),(3,347),(3,348),(3,349),(3,350),(3,351),(3,352),(3,353),(3,354),(3,355),(3,356),(3,357),(3,358),(3,359),(3,360),(3,361),(3,362),(3,363),(3,364),(3,365),(3,366),(3,367),(3,368),(3,369),(3,370),(3,371),(3,372),(3,373),(3,374),(3,375),(3,376),(3,377),(3,378),(3,379),(3,380),(3,381),(3,382),(3,383),(3,384),(4,17),(4,18),(4,19),(4,20),(4,21),(4,22),(4,23),(4,24),(4,25),(4,26),(4,27),(4,28),(4,29),(4,30),(4,31),(4,32),(4,33),(4,34),(4,35),(4,36),(4,189),(4,190),(4,191),(4,192),(4,193),(4,194),(4,195),(4,196),(4,197),(4,198),(4,199),(4,200),(4,201),(4,202),(4,203),(4,204),(4,205),(4,206),(4,207),(4,208),(4,209),(4,210),(4,211),(4,212),(4,213),(4,214),(4,215),(4,216),(4,217),(4,218),(4,219),(4,220),(4,221),(4,222),(4,223),(4,224),(4,225),(4,226),(4,227),(4,228),(4,229),(4,230),(4,231),(4,232),(4,233),(4,234),(4,235),(4,236),(4,237),(4,238),(4,239),(4,240),(4,241),(4,242),(4,243),(4,244),(4,245),(4,246),(4,247),(4,248),(4,249),(4,250),(4,251),(4,252),(4,253),(4,254),(4,255),(4,256),(4,257),(4,258),(4,259),(4,260),(4,261),(4,262),(4,263),(4,264),(4,265),(4,266),(4,267),(4,268),(4,269),(4,270),(4,271),(4,272),(4,273),(4,274),(4,275),(4,276),(4,277),(4,278),(4,279),(4,280),(4,281),(4,282),(4,283),(4,284),(4,285),(4,286),(4,287),(4,288),(4,289),(4,290),(4,291),(4,292),(4,293),(4,294),(4,295),(4,296),(4,297),(4,298),(4,299),(4,300),(4,301),(4,302),(4,303),(4,304),(4,305),(4,306),(4,307),(4,308),(4,309),(4,310),(4,311),(4,312),(4,313),(4,314),(4,315),(4,316),(4,317),(4,318),(4,319),(4,320),(4,321),(4,322),(4,323),(4,324),(4,325),(4,326),(4,327),(4,328),(4,329),(4,330),(4,331),(4,332),(4,333),(4,334),(4,335),(4,336),(4,337),(4,338),(4,339),(4,340),(4,341),(4,342),(4,343),(4,344),(4,345),(4,346),(4,347),(4,348),(4,349),(4,350),(4,351),(4,352),(4,353),(4,354),(4,355),(4,356),(4,357),(4,358),(4,359),(4,360),(4,361),(4,362),(4,363),(4,364),(4,365),(4,366),(4,367),(4,368),(4,369),(4,370),(4,371),(4,372),(4,373),(4,374),(4,375),(4,376),(4,377),(4,378),(4,379),(4,380),(4,381),(4,382),(4,383),(4,384),(5,5),(5,6),(5,7),(5,8),(5,9),(5,10),(5,11),(5,12),(5,13),(5,14),(5,15),(5,16),(5,17),(5,18),(5,19),(5,20),(5,21),(5,22),(5,23),(5,24),(5,25),(5,26),(5,27),(5,28),(5,29),(5,30),(5,31),(5,32),(5,33),(5,34),(5,35),(5,36),(5,65),(5,66),(5,67),(5,68),(5,69),(5,70),(5,71),(5,72),(5,73),(5,74),(5,75),(5,76),(5,77),(5,78),(5,79),(5,80),(5,81),(5,82),(5,83),(5,84),(5,85),(5,86),(5,87),(5,88),(5,89),(5,90),(5,91),(5,92),(5,93),(5,94),(5,95),(5,96),(5,97),(5,98),(5,99),(5,100),(5,101),(5,102),(5,103),(5,104),(5,105),(5,106),(5,107),(5,108),(5,109),(5,110),(5,111),(5,112),(5,113),(5,114),(5,115),(5,116),(5,117),(5,118),(5,119),(5,120),(5,121),(5,122),(5,123),(5,124),(5,125),(5,126),(5,127),(5,128),(5,129),(5,130),(5,131),(5,132),(5,133),(5,134),(5,135),(5,136),(5,137),(5,138),(5,139),(5,140),(5,141),(5,142),(5,143),(5,144),(5,145),(5,146),(5,147),(5,148),(5,149),(5,150),(5,151),(5,152),(5,153),(5,154),(5,155),(5,156),(5,157),(5,158),(5,159),(5,160),(5,161),(5,162),(5,163),(5,164),(5,165),(5,166),(5,167),(5,168),(5,169),(5,170),(5,171),(5,172),(5,173),(5,174),(5,175),(5,176),(5,177),(5,178),(5,179),(5,180),(5,181),(5,182),(5,183),(5,184),(5,185),(5,186),(5,187),(5,188),(5,189),(5,190),(5,191),(5,192),(5,193),(5,194),(5,195),(5,196),(5,197),(5,198),(5,199),(5,200),(5,201),(5,202),(5,203),(5,204),(5,205),(5,206),(5,207),(5,208),(5,209),(5,210),(5,211),(5,212),(5,213),(5,214),(5,215),(5,216),(5,217),(5,218),(5,219),(5,220),(5,221),(5,222),(5,223),(5,224),(5,225),(5,226),(5,227),(5,228),(5,229),(5,230),(5,231),(5,232),(5,233),(5,234),(5,235),(5,236),(5,237),(5,238),(5,239),(5,240),(5,241),(5,242),(5,243),(5,244),(5,245),(5,246),(5,247),(5,248),(5,249),(5,250),(5,251),(5,252),(5,253),(5,254),(5,255),(5,256),(5,257),(5,258),(5,259),(5,260),(5,261),(5,262),(5,263),(5,264),(5,265),(5,266),(5,267),(5,268),(5,269),(5,270),(5,271),(5,272),(5,273),(5,274),(5,275),(5,276),(5,277),(5,278),(5,279),(5,280),(5,281),(5,282),(5,283),(5,284),(5,285),(5,286),(5,287),(5,288),(5,289),(5,290),(5,291),(5,292),(5,293),(5,294),(5,295),(5,296),(5,297),(5,298),(5,299),(5,300),(5,301),(5,302),(5,303),(5,304),(5,305),(5,306),(5,307),(5,308),(5,309),(5,310),(5,311),(5,312),(5,313),(5,314),(5,315),(5,316),(5,317),(5,318),(5,319),(5,320),(5,321),(5,322),(5,323),(5,324),(5,325),(5,326),(5,327),(5,328),(5,329),(5,330),(5,331),(5,332),(5,333),(5,334),(5,335),(5,336),(5,337),(5,338),(5,339),(5,340),(5,341),(5,342),(5,343),(5,344),(5,345),(5,346),(5,347),(5,348),(5,349),(5,350),(5,351),(5,352),(5,353),(5,354),(5,355),(5,356),(5,357),(5,358),(5,359),(5,360),(5,361),(5,362),(5,363),(5,364),(5,365),(5,366),(5,367),(5,368),(5,369),(5,370),(5,371),(5,372),(5,373),(5,374),(5,375),(5,376),(5,377),(5,378),(5,379),(5,380),(5,381),(5,382),(5,383),(5,384),(6,17),(6,18),(6,19),(6,20),(6,21),(6,22),(6,23),(6,24),(6,25),(6,26),(6,27),(6,28),(6,29),(6,30),(6,31),(6,32),(6,33),(6,34),(6,35),(6,36),(6,169),(6,170),(6,171),(6,172),(6,173),(6,174),(6,175),(6,176),(6,177),(6,178),(6,179),(6,180),(6,181),(6,182),(6,183),(6,184),(6,185),(6,186),(6,187),(6,188),(6,189),(6,190),(6,191),(6,192),(6,193),(6,194),(6,195),(6,196),(6,197),(6,198),(6,199),(6,200),(6,201),(6,202),(6,203),(6,204),(6,205),(6,206),(6,207),(6,208),(6,209),(6,210),(6,211),(6,212),(6,213),(6,214),(6,215),(6,216),(6,217),(6,218),(6,219),(6,220),(6,221),(6,222),(6,223),(6,224),(6,225),(6,226),(6,227),(6,228),(6,229),(6,230),(6,231),(6,232),(6,233),(6,234),(6,235),(6,236),(6,237),(6,238),(6,239),(6,240),(6,241),(6,242),(6,243),(6,244),(6,245),(6,246),(6,247),(6,248),(6,249),(6,250),(6,251),(6,252),(6,253),(6,254),(6,255),(6,256),(6,257),(6,258),(6,259),(6,260),(6,261),(6,262),(6,263),(6,264),(6,265),(6,266),(6,267),(6,268),(6,269),(6,270),(6,271),(6,272),(6,273),(6,274),(6,275),(6,276),(6,277),(6,278),(6,279),(6,280),(6,281),(6,282),(6,283),(6,284),(6,285),(6,286),(6,287),(6,288),(6,289),(6,290),(6,291),(6,292),(6,293),(6,294),(6,295),(6,296),(6,297),(6,298),(6,299),(6,300),(6,301),(6,302),(6,303),(6,304),(6,305),(6,306),(6,307),(6,308),(6,309),(6,310),(6,311),(6,312),(6,313),(6,314),(6,315),(6,316),(6,317),(6,318),(6,319),(6,320),(6,321),(6,322),(6,323),(6,324),(6,325),(6,326),(6,327),(6,328),(6,329),(6,330),(6,331),(6,332),(6,333),(6,334),(6,335),(6,336),(6,337),(6,338),(6,339),(6,340),(6,341),(6,342),(6,343),(6,344),(6,345),(6,346),(6,347),(6,348),(6,349),(6,350),(6,351),(6,352),(6,353),(6,354),(6,355),(6,356),(6,357),(6,358),(6,359),(6,360),(6,361),(6,362),(6,363),(6,364),(6,365),(6,366),(6,367),(6,368),(6,369),(6,370),(6,371),(6,372),(6,373),(6,374),(6,375),(6,376),(6,377),(6,378),(6,379),(6,380),(6,381),(6,382),(6,383),(6,384),(7,5),(7,6),(7,7),(7,8),(7,9),(7,10),(7,11),(7,12),(7,13),(7,14),(7,15),(7,16),(7,17),(7,18),(7,19),(7,20),(7,21),(7,22),(7,23),(7,24),(7,25),(7,26),(7,27),(7,28),(7,29),(7,30),(7,31),(7,32),(7,33),(7,34),(7,35),(7,36),(7,45),(7,46),(7,47),(7,48),(7,49),(7,50),(7,51),(7,52),(7,53),(7,54),(7,55),(7,56),(7,57),(7,58),(7,59),(7,60),(7,61),(7,62),(7,63),(7,64),(7,65),(7,66),(7,67),(7,68),(7,69),(7,70),(7,71),(7,72),(7,73),(7,74),(7,75),(7,76),(7,77),(7,78),(7,79),(7,80),(7,81),(7,82),(7,83),(7,84),(7,85),(7,86),(7,87),(7,88),(7,89),(7,90),(7,91),(7,92),(7,93),(7,94),(7,95),(7,96),(7,97),(7,98),(7,99),(7,100),(7,101),(7,102),(7,103),(7,104),(7,105),(7,106),(7,107),(7,108),(7,109),(7,110),(7,111),(7,112),(7,113),(7,114),(7,115),(7,116),(7,117),(7,118),(7,119),(7,120),(7,121),(7,122),(7,123),(7,124),(7,125),(7,126),(7,127),(7,128),(7,129),(7,130),(7,131),(7,132),(7,133),(7,134),(7,135),(7,136),(7,137),(7,138),(7,139),(7,140),(7,141),(7,142),(7,143),(7,144),(7,145),(7,146),(7,147),(7,148),(7,149),(7,150),(7,151),(7,152),(7,153),(7,154),(7,155),(7,156),(7,157),(7,158),(7,159),(7,160),(7,161),(7,162),(7,163),(7,164),(7,165),(7,166),(7,167),(7,168),(7,169),(7,170),(7,171),(7,172),(7,173),(7,174),(7,175),(7,176),(7,177),(7,178),(7,179),(7,180),(7,181),(7,182),(7,183),(7,184),(7,185),(7,186),(7,187),(7,188),(7,189),(7,190),(7,191),(7,192),(7,193),(7,194),(7,195),(7,196),(7,197),(7,198),(7,199),(7,200),(7,201),(7,202),(7,203),(7,204),(7,205),(7,206),(7,207),(7,208),(7,209),(7,210),(7,211),(7,212),(7,213),(7,214),(7,215),(7,216),(7,217),(7,218),(7,219),(7,220),(7,221),(7,222),(7,223),(7,224),(7,225),(7,226),(7,227),(7,228),(7,229),(7,230),(7,231),(7,232),(7,233),(7,234),(7,235),(7,236),(7,237),(7,238),(7,239),(7,240),(7,241),(7,242),(7,243),(7,244),(7,245),(7,246),(7,247),(7,248),(7,249),(7,250),(7,251),(7,252),(7,253),(7,254),(7,255),(7,256),(7,257),(7,258),(7,259),(7,260),(7,261),(7,262),(7,263),(7,264),(7,265),(7,266),(7,267),(7,268),(7,269),(7,270),(7,271),(7,272),(7,273),(7,274),(7,275),(7,276),(7,277),(7,278),(7,279),(7,280),(7,281),(7,282),(7,283),(7,284),(7,285),(7,286),(7,287),(7,288),(7,289),(7,290),(7,291),(7,292),(7,293),(7,294),(7,295),(7,296),(7,297),(7,298),(7,299),(7,300),(7,301),(7,302),(7,303),(7,304),(7,305),(7,306),(7,307),(7,308),(7,309),(7,310),(7,311),(7,312),(7,313),(7,314),(7,315),(7,316),(7,317),(7,318),(7,319),(7,320),(7,321),(7,322),(7,323),(7,324),(7,325),(7,326),(7,327),(7,328),(7,329),(7,330),(7,331),(7,332),(7,333),(7,334),(7,335),(7,336),(7,337),(7,338),(7,339),(7,340),(7,341),(7,342),(7,343),(7,344),(7,345),(7,346),(7,347),(7,348),(7,349),(7,350),(7,351),(7,352),(7,353),(7,354),(7,355),(7,356),(7,357),(7,358),(7,359),(7,360),(7,361),(7,362),(7,363),(7,364),(7,365),(7,366),(7,367),(7,368),(7,369),(7,370),(7,371),(7,372),(7,373),(7,374),(7,375),(7,376),(7,377),(7,378),(7,379),(7,380),(7,381),(7,382),(7,383),(7,384),(8,13),(8,14),(8,15),(8,16),(8,17),(8,18),(8,19),(8,20),(8,21),(8,22),(8,23),(8,24),(8,25),(8,26),(8,27),(8,28),(8,29),(8,30),(8,31),(8,32),(8,33),(8,34),(8,35),(8,36),(8,153),(8,154),(8,155),(8,156),(8,157),(8,158),(8,159),(8,160),(8,161),(8,162),(8,163),(8,164),(8,165),(8,166),(8,167),(8,168),(8,169),(8,170),(8,171),(8,172),(8,173),(8,174),(8,175),(8,176),(8,177),(8,178),(8,179),(8,180),(8,181),(8,182),(8,183),(8,184),(8,185),(8,186),(8,187),(8,188),(8,189),(8,190),(8,191),(8,192),(8,193),(8,194),(8,195),(8,196),(8,197),(8,198),(8,199),(8,200),(8,201),(8,202),(8,203),(8,204),(8,205),(8,206),(8,207),(8,208),(8,209),(8,210),(8,211),(8,212),(8,213),(8,214),(8,215),(8,216),(8,217),(8,218),(8,219),(8,220),(8,221),(8,222),(8,223),(8,224),(8,225),(8,226),(8,227),(8,228),(8,229),(8,230),(8,231),(8,232),(8,233),(8,234),(8,235),(8,236),(8,237),(8,238),(8,239),(8,240),(8,241),(8,242),(8,243),(8,244),(8,245),(8,246),(8,247),(8,248),(8,249),(8,250),(8,251),(8,252),(8,253),(8,254),(8,255),(8,256),(8,257),(8,258),(8,259),(8,260),(8,261),(8,262),(8,263),(8,264),(8,265),(8,266),(8,267),(8,268),(8,269),(8,270),(8,271),(8,272),(8,273),(8,274),(8,275),(8,276),(8,277),(8,278),(8,279),(8,280),(8,281),(8,282),(8,283),(8,284),(8,285),(8,286),(8,287),(8,288),(8,289),(8,290),(8,291),(8,292),(8,293),(8,294),(8,295),(8,296),(8,297),(8,298),(8,299),(8,300),(8,301),(8,302),(8,303),(8,304),(8,305),(8,306),(8,307),(8,308),(8,309),(8,310),(8,311),(8,312),(8,313),(8,314),(8,315),(8,316),(8,317),(8,318),(8,319),(8,320),(8,321),(8,322),(8,323),(8,324),(8,325),(8,326),(8,327),(8,328),(8,329),(8,330),(8,331),(8,332),(8,333),(8,334),(8,335),(8,336),(8,337),(8,338),(8,339),(8,340),(8,341),(8,342),(8,343),(8,344),(8,345),(8,346),(8,347),(8,348),(8,349),(8,350),(8,351),(8,352),(8,353),(8,354),(8,355),(8,356),(8,357),(8,358),(8,359),(8,360),(8,361),(8,362),(8,363),(8,364),(8,365),(8,366),(8,367),(8,368),(8,369),(8,370),(8,371),(8,372),(8,373),(8,374),(8,375),(8,376),(8,377),(8,378),(8,379),(8,380),(8,381),(8,382),(8,383),(8,384),(9,197),(9,198),(9,199),(9,200),(9,201),(9,202),(9,203),(9,204),(9,205),(9,206),(9,207),(9,208),(10,13),(10,14),(10,15),(10,16),(10,17),(10,18),(10,19),(10,20),(10,21),(10,22),(10,23),(10,24),(10,25),(10,26),(10,27),(10,28),(10,29),(10,30),(10,31),(10,32),(10,33),(10,34),(10,35),(10,36),(10,133),(10,134),(10,135),(10,136),(10,137),(10,138),(10,139),(10,140),(10,141),(10,142),(10,143),(10,144),(10,145),(10,146),(10,147),(10,148),(10,149),(10,150),(10,151),(10,152),(10,153),(10,154),(10,155),(10,156),(10,157),(10,158),(10,159),(10,160),(10,161),(10,162),(10,163),(10,164),(10,165),(10,166),(10,167),(10,168),(10,169),(10,170),(10,171),(10,172),(10,173),(10,174),(10,175),(10,176),(10,177),(10,178),(10,179),(10,180),(10,181),(10,182),(10,183),(10,184),(10,185),(10,186),(10,187),(10,188),(10,189),(10,190),(10,191),(10,192),(10,193),(10,194),(10,195),(10,196),(10,197),(10,198),(10,199),(10,200),(10,201),(10,202),(10,203),(10,204),(10,205),(10,206),(10,207),(10,208),(10,209),(10,210),(10,211),(10,212),(10,213),(10,214),(10,215),(10,216),(10,217),(10,218),(10,219),(10,220),(10,221),(10,222),(10,223),(10,224),(10,225),(10,226),(10,227),(10,228),(10,229),(10,230),(10,231),(10,232),(10,233),(10,234),(10,235),(10,236),(10,237),(10,238),(10,239),(10,240),(10,241),(10,242),(10,243),(10,244),(10,245),(10,246),(10,247),(10,248),(10,249),(10,250),(10,251),(10,252),(10,253),(10,254),(10,255),(10,256),(10,257),(10,258),(10,259),(10,260),(10,261),(10,262),(10,263),(10,264),(10,265),(10,266),(10,267),(10,268),(10,269),(10,270),(10,271),(10,272),(10,273),(10,274),(10,275),(10,276),(10,277),(10,278),(10,279),(10,280),(10,281),(10,282),(10,283),(10,284),(10,285),(10,286),(10,287),(10,288),(10,289),(10,290),(10,291),(10,292),(10,293),(10,294),(10,295),(10,296),(10,297),(10,298),(10,299),(10,300),(10,301),(10,302),(10,303),(10,304),(10,305),(10,306),(10,307),(10,308),(10,309),(10,310),(10,311),(10,312),(10,313),(10,314),(10,315),(10,316),(10,317),(10,318),(10,319),(10,320),(10,321),(10,322),(10,323),(10,324),(10,325),(10,326),(10,327),(10,328),(10,329),(10,330),(10,331),(10,332),(10,333),(10,334),(10,335),(10,336),(10,337),(10,338),(10,339),(10,340),(10,341),(10,342),(10,343),(10,344),(10,345),(10,346),(10,347),(10,348),(10,349),(10,350),(10,351),(10,352),(10,353),(10,354),(10,355),(10,356),(10,357),(10,358),(10,359),(10,360),(10,361),(10,362),(10,363),(10,364),(10,365),(10,366),(10,367),(10,368),(10,369),(10,370),(10,371),(10,372),(10,373),(10,374),(10,375),(10,376),(10,377),(10,378),(10,379),(10,380),(10,381),(10,382),(10,383),(10,384),(11,17),(11,18),(11,19),(11,20),(11,169),(11,170),(11,171),(11,172),(11,173),(11,174),(11,175),(11,176),(11,177),(11,178),(11,179),(11,180),(11,181),(11,182),(11,183),(11,184),(11,185),(11,186),(11,187),(11,188),(11,189),(11,190),(11,191),(11,192),(11,193),(11,194),(11,195),(11,196),(12,9),(12,10),(12,11),(12,12),(12,13),(12,14),(12,15),(12,16),(12,17),(12,18),(12,19),(12,20),(12,21),(12,22),(12,23),(12,24),(12,25),(12,26),(12,27),(12,28),(12,29),(12,30),(12,31),(12,32),(12,33),(12,34),(12,35),(12,36),(12,117),(12,118),(12,119),(12,120),(12,121),(12,122),(12,123),(12,124),(12,125),(12,126),(12,127),(12,128),(12,129),(12,130),(12,131),(12,132),(12,133),(12,134),(12,135),(12,136),(12,137),(12,138),(12,139),(12,140),(12,141),(12,142),(12,143),(12,144),(12,145),(12,146),(12,147),(12,148),(12,149),(12,150),(12,151),(12,152),(12,153),(12,154),(12,155),(12,156),(12,157),(12,158),(12,159),(12,160),(12,161),(12,162),(12,163),(12,164),(12,165),(12,166),(12,167),(12,168),(12,169),(12,170),(12,171),(12,172),(12,173),(12,174),(12,175),(12,176),(12,177),(12,178),(12,179),(12,180),(12,181),(12,182),(12,183),(12,184),(12,185),(12,186),(12,187),(12,188),(12,189),(12,190),(12,191),(12,192),(12,193),(12,194),(12,195),(12,196),(12,197),(12,198),(12,199),(12,200),(12,201),(12,202),(12,203),(12,204),(12,205),(12,206),(12,207),(12,208),(12,209),(12,210),(12,211),(12,212),(12,213),(12,214),(12,215),(12,216),(12,217),(12,218),(12,219),(12,220),(12,221),(12,222),(12,223),(12,224),(12,225),(12,226),(12,227),(12,228),(12,229),(12,230),(12,231),(12,232),(12,233),(12,234),(12,235),(12,236),(12,237),(12,238),(12,239),(12,240),(12,241),(12,242),(12,243),(12,244),(12,245),(12,246),(12,247),(12,248),(12,249),(12,250),(12,251),(12,252),(12,253),(12,254),(12,255),(12,256),(12,257),(12,258),(12,259),(12,260),(12,261),(12,262),(12,263),(12,264),(12,265),(12,266),(12,267),(12,268),(12,269),(12,270),(12,271),(12,272),(12,273),(12,274),(12,275),(12,276),(12,277),(12,278),(12,279),(12,280),(12,281),(12,282),(12,283),(12,284),(12,285),(12,286),(12,287),(12,288),(12,289),(12,290),(12,291),(12,292),(12,293),(12,294),(12,295),(12,296),(12,297),(12,298),(12,299),(12,300),(12,301),(12,302),(12,303),(12,304),(12,305),(12,306),(12,307),(12,308),(12,309),(12,310),(12,311),(12,312),(12,313),(12,314),(12,315),(12,316),(12,317),(12,318),(12,319),(12,320),(12,321),(12,322),(12,323),(12,324),(12,325),(12,326),(12,327),(12,328),(12,329),(12,330),(12,331),(12,332),(12,333),(12,334),(12,335),(12,336),(12,337),(12,338),(12,339),(12,340),(12,341),(12,342),(12,343),(12,344),(12,345),(12,346),(12,347),(12,348),(12,349),(12,350),(12,351),(12,352),(12,353),(12,354),(12,355),(12,356),(12,357),(12,358),(12,359),(12,360),(12,361),(12,362),(12,363),(12,364),(12,365),(12,366),(12,367),(12,368),(12,369),(12,370),(12,371),(12,372),(12,373),(12,374),(12,375),(12,376),(12,377),(12,378),(12,379),(12,380),(12,381),(12,382),(12,383),(12,384),(13,13),(13,14),(13,15),(13,16),(13,121),(13,122),(13,123),(13,124),(13,125),(13,126),(13,127),(13,128),(13,129),(13,130),(13,131),(13,132),(13,133),(13,134),(13,135),(13,136),(13,137),(13,138),(13,139),(13,140),(13,141),(13,142),(13,143),(13,144),(13,145),(13,146),(13,147),(13,148),(13,149),(13,150),(13,151),(13,152),(13,153),(13,154),(13,155),(13,156),(13,157),(13,158),(13,159),(13,160),(13,161),(13,162),(13,163),(13,164),(13,165),(13,166),(13,167),(13,168),(14,9),(14,10),(14,11),(14,12),(14,13),(14,14),(14,15),(14,16),(14,17),(14,18),(14,19),(14,20),(14,21),(14,22),(14,23),(14,24),(14,25),(14,26),(14,27),(14,28),(14,29),(14,30),(14,31),(14,32),(14,33),(14,34),(14,35),(14,36),(14,93),(14,94),(14,95),(14,96),(14,97),(14,98),(14,99),(14,100),(14,101),(14,102),(14,103),(14,104),(14,105),(14,106),(14,107),(14,108),(14,109),(14,110),(14,111),(14,112),(14,113),(14,114),(14,115),(14,116),(14,117),(14,118),(14,119),(14,120),(14,121),(14,122),(14,123),(14,124),(14,125),(14,126),(14,127),(14,128),(14,129),(14,130),(14,131),(14,132),(14,133),(14,134),(14,135),(14,136),(14,137),(14,138),(14,139),(14,140),(14,141),(14,142),(14,143),(14,144),(14,145),(14,146),(14,147),(14,148),(14,149),(14,150),(14,151),(14,152),(14,153),(14,154),(14,155),(14,156),(14,157),(14,158),(14,159),(14,160),(14,161),(14,162),(14,163),(14,164),(14,165),(14,166),(14,167),(14,168),(14,169),(14,170),(14,171),(14,172),(14,173),(14,174),(14,175),(14,176),(14,177),(14,178),(14,179),(14,180),(14,181),(14,182),(14,183),(14,184),(14,185),(14,186),(14,187),(14,188),(14,189),(14,190),(14,191),(14,192),(14,193),(14,194),(14,195),(14,196),(14,197),(14,198),(14,199),(14,200),(14,201),(14,202),(14,203),(14,204),(14,205),(14,206),(14,207),(14,208),(14,209),(14,210),(14,211),(14,212),(14,213),(14,214),(14,215),(14,216),(14,217),(14,218),(14,219),(14,220),(14,221),(14,222),(14,223),(14,224),(14,225),(14,226),(14,227),(14,228),(14,229),(14,230),(14,231),(14,232),(14,233),(14,234),(14,235),(14,236),(14,237),(14,238),(14,239),(14,240),(14,241),(14,242),(14,243),(14,244),(14,245),(14,246),(14,247),(14,248),(14,249),(14,250),(14,251),(14,252),(14,253),(14,254),(14,255),(14,256),(14,257),(14,258),(14,259),(14,260),(14,261),(14,262),(14,263),(14,264),(14,265),(14,266),(14,267),(14,268),(14,269),(14,270),(14,271),(14,272),(14,273),(14,274),(14,275),(14,276),(14,277),(14,278),(14,279),(14,280),(14,281),(14,282),(14,283),(14,284),(14,285),(14,286),(14,287),(14,288),(14,289),(14,290),(14,291),(14,292),(14,293),(14,294),(14,295),(14,296),(14,297),(14,298),(14,299),(14,300),(14,301),(14,302),(14,303),(14,304),(14,305),(14,306),(14,307),(14,308),(14,309),(14,310),(14,311),(14,312),(14,313),(14,314),(14,315),(14,316),(14,317),(14,318),(14,319),(14,320),(14,321),(14,322),(14,323),(14,324),(14,325),(14,326),(14,327),(14,328),(14,329),(14,330),(14,331),(14,332),(14,333),(14,334),(14,335),(14,336),(14,337),(14,338),(14,339),(14,340),(14,341),(14,342),(14,343),(14,344),(14,345),(14,346),(14,347),(14,348),(14,349),(14,350),(14,351),(14,352),(14,353),(14,354),(14,355),(14,356),(14,357),(14,358),(14,359),(14,360),(14,361),(14,362),(14,363),(14,364),(14,365),(14,366),(14,367),(14,368),(14,369),(14,370),(14,371),(14,372),(14,373),(14,374),(14,375),(14,376),(14,377),(14,378),(14,379),(14,380),(14,381),(14,382),(14,383),(14,384),(15,5),(15,6),(15,7),(15,8),(15,9),(15,10),(15,11),(15,12),(15,57),(15,58),(15,59),(15,60),(15,61),(15,62),(15,63),(15,64),(15,65),(15,66),(15,67),(15,68),(15,69),(15,70),(15,71),(15,72),(15,73),(15,74),(15,75),(15,76),(15,77),(15,78),(15,79),(15,80),(15,81),(15,82),(15,83),(15,84),(15,85),(15,86),(15,87),(15,88),(15,89),(15,90),(15,91),(15,92),(15,93),(15,94),(15,95),(15,96),(15,97),(15,98),(15,99),(15,100),(15,101),(15,102),(15,103),(15,104),(15,105),(15,106),(15,107),(15,108),(15,109),(15,110),(15,111),(15,112),(15,113),(15,114),(15,115),(15,116),(15,117),(15,118),(15,119),(15,120),(16,5),(16,6),(16,7),(16,8),(16,9),(16,10),(16,11),(16,12),(16,13),(16,14),(16,15),(16,16),(16,17),(16,18),(16,19),(16,20),(16,21),(16,22),(16,23),(16,24),(16,25),(16,26),(16,27),(16,28),(16,29),(16,30),(16,31),(16,32),(16,33),(16,34),(16,35),(16,36),(16,77),(16,78),(16,79),(16,80),(16,81),(16,82),(16,83),(16,84),(16,85),(16,86),(16,87),(16,88),(16,89),(16,90),(16,91),(16,92),(16,93),(16,94),(16,95),(16,96),(16,97),(16,98),(16,99),(16,100),(16,101),(16,102),(16,103),(16,104),(16,105),(16,106),(16,107),(16,108),(16,109),(16,110),(16,111),(16,112),(16,113),(16,114),(16,115),(16,116),(16,117),(16,118),(16,119),(16,120),(16,121),(16,122),(16,123),(16,124),(16,125),(16,126),(16,127),(16,128),(16,129),(16,130),(16,131),(16,132),(16,133),(16,134),(16,135),(16,136),(16,137),(16,138),(16,139),(16,140),(16,141),(16,142),(16,143),(16,144),(16,145),(16,146),(16,147),(16,148),(16,149),(16,150),(16,151),(16,152),(16,153),(16,154),(16,155),(16,156),(16,157),(16,158),(16,159),(16,160),(16,161),(16,162),(16,163),(16,164),(16,165),(16,166),(16,167),(16,168),(16,169),(16,170),(16,171),(16,172),(16,173),(16,174),(16,175),(16,176),(16,177),(16,178),(16,179),(16,180),(16,181),(16,182),(16,183),(16,184),(16,185),(16,186),(16,187),(16,188),(16,189),(16,190),(16,191),(16,192),(16,193),(16,194),(16,195),(16,196),(16,197),(16,198),(16,199),(16,200),(16,201),(16,202),(16,203),(16,204),(16,205),(16,206),(16,207),(16,208),(16,209),(16,210),(16,211),(16,212),(16,213),(16,214),(16,215),(16,216),(16,217),(16,218),(16,219),(16,220),(16,221),(16,222),(16,223),(16,224),(16,225),(16,226),(16,227),(16,228),(16,229),(16,230),(16,231),(16,232),(16,233),(16,234),(16,235),(16,236),(16,237),(16,238),(16,239),(16,240),(16,241),(16,242),(16,243),(16,244),(16,245),(16,246),(16,247),(16,248),(16,249),(16,250),(16,251),(16,252),(16,253),(16,254),(16,255),(16,256),(16,257),(16,258),(16,259),(16,260),(16,261),(16,262),(16,263),(16,264),(16,265),(16,266),(16,267),(16,268),(16,269),(16,270),(16,271),(16,272),(16,273),(16,274),(16,275),(16,276),(16,277),(16,278),(16,279),(16,280),(16,281),(16,282),(16,283),(16,284),(16,285),(16,286),(16,287),(16,288),(16,289),(16,290),(16,291),(16,292),(16,293),(16,294),(16,295),(16,296),(16,297),(16,298),(16,299),(16,300),(16,301),(16,302),(16,303),(16,304),(16,305),(16,306),(16,307),(16,308),(16,309),(16,310),(16,311),(16,312),(16,313),(16,314),(16,315),(16,316),(16,317),(16,318),(16,319),(16,320),(16,321),(16,322),(16,323),(16,324),(16,325),(16,326),(16,327),(16,328),(16,329),(16,330),(16,331),(16,332),(16,333),(16,334),(16,335),(16,336),(16,337),(16,338),(16,339),(16,340),(16,341),(16,342),(16,343),(16,344),(16,345),(16,346),(16,347),(16,348),(16,349),(16,350),(16,351),(16,352),(16,353),(16,354),(16,355),(16,356),(16,357),(16,358),(16,359),(16,360),(16,361),(16,362),(16,363),(16,364),(16,365),(16,366),(16,367),(16,368),(16,369),(16,370),(16,371),(16,372),(16,373),(16,374),(16,375),(16,376),(16,377),(16,378),(16,379),(16,380),(16,381),(16,382),(16,383),(16,384),(17,13),(17,14),(17,15),(17,16),(17,17),(17,18),(17,19),(17,20),(17,49),(17,50),(17,51),(17,52),(17,53),(17,54),(17,55),(17,56),(17,121),(17,122),(17,123),(17,124),(17,125),(17,126),(17,127),(17,128),(17,129),(17,130),(17,131),(17,132),(17,133),(17,134),(17,135),(17,136),(17,137),(17,138),(17,139),(17,140),(17,141),(17,142),(17,143),(17,144),(17,145),(17,146),(17,147),(17,148),(17,149),(17,150),(17,151),(17,152),(17,153),(17,154),(17,155),(17,156),(17,157),(17,158),(17,159),(17,160),(17,161),(17,162),(17,163),(17,164),(17,165),(17,166),(17,167),(17,168),(17,169),(17,170),(17,171),(17,172),(17,173),(17,174),(17,175),(17,176),(17,177),(17,178),(17,179),(17,180),(17,181),(17,182),(17,183),(17,184),(17,185),(17,186),(17,187),(17,188),(17,189),(17,190),(17,191),(17,192),(17,193),(17,194),(17,195),(17,196); /*!40000 ALTER TABLE `gantt_jobs_resources` ENABLE KEYS */; UNLOCK TABLES; -- -- Table structure for table `gantt_jobs_resources_log` -- DROP TABLE IF EXISTS `gantt_jobs_resources_log`; SET @saved_cs_client = @@character_set_client; SET character_set_client = utf8; CREATE TABLE `gantt_jobs_resources_log` ( `sched_date` int(10) unsigned NOT NULL, `moldable_job_id` int(10) unsigned NOT NULL, `resource_id` int(10) unsigned NOT NULL, PRIMARY KEY (`sched_date`,`moldable_job_id`,`resource_id`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1; SET character_set_client = @saved_cs_client; -- -- Dumping data for table `gantt_jobs_resources_log` -- LOCK TABLES `gantt_jobs_resources_log` WRITE; /*!40000 ALTER TABLE `gantt_jobs_resources_log` DISABLE KEYS */; /*!40000 ALTER TABLE `gantt_jobs_resources_log` ENABLE KEYS */; UNLOCK TABLES; -- -- Table structure for table `gantt_jobs_resources_visu` -- DROP TABLE IF EXISTS `gantt_jobs_resources_visu`; SET @saved_cs_client = @@character_set_client; SET character_set_client = utf8; CREATE TABLE `gantt_jobs_resources_visu` ( `moldable_job_id` int(10) unsigned NOT NULL, `resource_id` int(10) unsigned NOT NULL, PRIMARY KEY (`moldable_job_id`,`resource_id`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1; SET character_set_client = @saved_cs_client; -- -- Dumping data for table `gantt_jobs_resources_visu` -- LOCK TABLES `gantt_jobs_resources_visu` WRITE; /*!40000 ALTER TABLE `gantt_jobs_resources_visu` DISABLE KEYS */; INSERT INTO `gantt_jobs_resources_visu` VALUES (1,1),(1,2),(1,3),(1,4),(1,5),(1,6),(1,7),(1,8),(1,9),(1,10),(1,11),(1,12),(1,13),(1,14),(1,15),(1,16),(1,17),(1,18),(1,19),(1,20),(1,21),(1,22),(1,23),(1,24),(1,25),(1,26),(1,27),(1,28),(1,29),(1,30),(1,31),(1,32),(1,33),(1,34),(1,35),(1,36),(1,37),(1,38),(1,39),(1,40),(1,41),(1,42),(1,43),(1,44),(1,45),(1,46),(1,47),(1,48),(1,49),(1,50),(1,51),(1,52),(1,53),(1,54),(1,55),(1,56),(1,57),(1,58),(1,59),(1,60),(1,61),(1,62),(1,63),(1,64),(1,65),(1,66),(1,67),(1,68),(1,69),(1,70),(1,71),(1,72),(1,73),(1,74),(1,75),(1,76),(1,77),(1,78),(1,79),(1,80),(1,81),(1,82),(1,83),(1,84),(1,85),(1,86),(1,87),(1,88),(1,89),(1,90),(1,91),(1,92),(1,93),(1,94),(1,95),(1,96),(1,97),(1,98),(1,99),(1,100),(1,101),(1,102),(1,103),(1,104),(1,105),(1,106),(1,107),(1,108),(1,109),(1,110),(1,111),(1,112),(1,113),(1,114),(1,115),(1,116),(1,117),(1,118),(1,119),(1,120),(1,121),(1,122),(1,123),(1,124),(1,125),(1,126),(1,127),(1,128),(1,129),(1,130),(1,131),(1,132),(1,133),(1,134),(1,135),(1,136),(1,137),(1,138),(1,139),(1,140),(1,141),(1,142),(1,143),(1,144),(1,145),(1,146),(1,147),(1,148),(1,149),(1,150),(1,151),(1,152),(1,153),(1,154),(1,155),(1,156),(1,157),(1,158),(1,159),(1,160),(1,161),(1,162),(1,163),(1,164),(1,165),(1,166),(1,167),(1,168),(1,169),(1,170),(1,171),(1,172),(1,173),(1,174),(1,175),(1,176),(1,177),(1,178),(1,179),(1,180),(1,181),(1,182),(1,183),(1,184),(1,185),(1,186),(1,187),(1,188),(1,189),(1,190),(1,191),(1,192),(1,193),(1,194),(1,195),(1,196),(1,197),(1,198),(1,199),(1,200),(1,201),(1,202),(1,203),(1,204),(1,205),(1,206),(1,207),(1,208),(1,209),(1,210),(1,211),(1,212),(1,213),(1,214),(1,215),(1,216),(1,217),(1,218),(1,219),(1,220),(1,221),(1,222),(1,223),(1,224),(1,225),(1,226),(1,227),(1,228),(1,229),(1,230),(1,231),(1,232),(1,233),(1,234),(1,235),(1,236),(1,237),(1,238),(1,239),(1,240),(1,241),(1,242),(1,243),(1,244),(1,245),(1,246),(1,247),(1,248),(1,249),(1,250),(1,251),(1,252),(1,253),(1,254),(1,255),(1,256),(1,257),(1,258),(1,259),(1,260),(1,261),(1,262),(1,263),(1,264),(1,265),(1,266),(1,267),(1,268),(1,269),(1,270),(1,271),(1,272),(1,273),(1,274),(1,275),(1,276),(1,277),(1,278),(1,279),(1,280),(1,281),(1,282),(1,283),(1,284),(1,285),(1,286),(1,287),(1,288),(1,289),(1,290),(1,291),(1,292),(1,293),(1,294),(1,295),(1,296),(1,297),(1,298),(1,299),(1,300),(1,301),(1,302),(1,303),(1,304),(1,305),(1,306),(1,307),(1,308),(1,309),(1,310),(1,311),(1,312),(1,313),(1,314),(1,315),(1,316),(1,317),(1,318),(1,319),(1,320),(1,321),(1,322),(1,323),(1,324),(1,325),(1,326),(1,327),(1,328),(1,329),(1,330),(1,331),(1,332),(1,333),(1,334),(1,335),(1,336),(1,337),(1,338),(1,339),(1,340),(1,341),(1,342),(1,343),(1,344),(1,345),(1,346),(1,347),(1,348),(1,349),(1,350),(1,351),(1,352),(1,353),(1,354),(1,355),(1,356),(1,357),(1,358),(1,359),(1,360),(1,361),(1,362),(1,363),(1,364),(1,365),(1,366),(1,367),(1,368),(1,369),(1,370),(1,371),(1,372),(1,373),(1,374),(1,375),(1,376),(1,377),(1,378),(1,379),(1,380),(1,381),(1,382),(1,383),(1,384),(2,21),(2,22),(2,23),(2,24),(2,25),(2,26),(2,27),(2,28),(2,29),(2,30),(2,31),(2,32),(2,33),(2,34),(2,35),(2,36),(2,209),(2,210),(2,211),(2,212),(2,213),(2,214),(2,215),(2,216),(2,217),(2,218),(2,219),(2,220),(2,221),(2,222),(2,223),(2,224),(2,225),(2,226),(2,227),(2,228),(2,229),(2,230),(2,231),(2,232),(2,233),(2,234),(2,235),(2,236),(2,237),(2,238),(2,239),(2,240),(2,241),(2,242),(2,243),(2,244),(2,245),(2,246),(2,247),(2,248),(2,249),(2,250),(2,251),(2,252),(2,253),(2,254),(2,255),(2,256),(2,257),(2,258),(2,259),(2,260),(2,261),(2,262),(2,263),(2,264),(2,265),(2,266),(2,267),(2,268),(2,269),(2,270),(2,271),(2,272),(2,273),(2,274),(2,275),(2,276),(2,277),(2,278),(2,279),(2,280),(2,281),(2,282),(2,283),(2,284),(2,285),(2,286),(2,287),(2,288),(2,289),(2,290),(2,291),(2,292),(2,293),(2,294),(2,295),(2,296),(2,297),(2,298),(2,299),(2,300),(2,301),(2,302),(2,303),(2,304),(2,305),(2,306),(2,307),(2,308),(2,309),(2,310),(2,311),(2,312),(2,313),(2,314),(2,315),(2,316),(2,317),(2,318),(2,319),(2,320),(2,321),(2,322),(2,323),(2,324),(2,325),(2,326),(2,327),(2,328),(2,329),(2,330),(2,331),(2,332),(2,333),(2,334),(2,335),(2,336),(2,337),(2,338),(2,339),(2,340),(2,341),(2,342),(2,343),(2,344),(2,345),(2,346),(2,347),(2,348),(2,349),(2,350),(2,351),(2,352),(2,353),(2,354),(2,355),(2,356),(2,357),(2,358),(2,359),(2,360),(2,361),(2,362),(2,363),(2,364),(2,365),(2,366),(2,367),(2,368),(2,369),(2,370),(2,371),(2,372),(2,373),(2,374),(2,375),(2,376),(2,377),(2,378),(2,379),(2,380),(2,381),(2,382),(2,383),(2,384),(3,9),(3,10),(3,11),(3,12),(3,13),(3,14),(3,15),(3,16),(3,17),(3,18),(3,19),(3,20),(3,21),(3,22),(3,23),(3,24),(3,25),(3,26),(3,27),(3,28),(3,29),(3,30),(3,31),(3,32),(3,33),(3,34),(3,35),(3,36),(3,81),(3,82),(3,83),(3,84),(3,85),(3,86),(3,87),(3,88),(3,89),(3,90),(3,91),(3,92),(3,93),(3,94),(3,95),(3,96),(3,97),(3,98),(3,99),(3,100),(3,101),(3,102),(3,103),(3,104),(3,105),(3,106),(3,107),(3,108),(3,109),(3,110),(3,111),(3,112),(3,113),(3,114),(3,115),(3,116),(3,117),(3,118),(3,119),(3,120),(3,121),(3,122),(3,123),(3,124),(3,125),(3,126),(3,127),(3,128),(3,129),(3,130),(3,131),(3,132),(3,133),(3,134),(3,135),(3,136),(3,137),(3,138),(3,139),(3,140),(3,141),(3,142),(3,143),(3,144),(3,145),(3,146),(3,147),(3,148),(3,149),(3,150),(3,151),(3,152),(3,153),(3,154),(3,155),(3,156),(3,157),(3,158),(3,159),(3,160),(3,161),(3,162),(3,163),(3,164),(3,165),(3,166),(3,167),(3,168),(3,169),(3,170),(3,171),(3,172),(3,173),(3,174),(3,175),(3,176),(3,177),(3,178),(3,179),(3,180),(3,181),(3,182),(3,183),(3,184),(3,185),(3,186),(3,187),(3,188),(3,189),(3,190),(3,191),(3,192),(3,193),(3,194),(3,195),(3,196),(3,197),(3,198),(3,199),(3,200),(3,201),(3,202),(3,203),(3,204),(3,205),(3,206),(3,207),(3,208),(3,209),(3,210),(3,211),(3,212),(3,213),(3,214),(3,215),(3,216),(3,217),(3,218),(3,219),(3,220),(3,221),(3,222),(3,223),(3,224),(3,225),(3,226),(3,227),(3,228),(3,229),(3,230),(3,231),(3,232),(3,233),(3,234),(3,235),(3,236),(3,237),(3,238),(3,239),(3,240),(3,241),(3,242),(3,243),(3,244),(3,245),(3,246),(3,247),(3,248),(3,249),(3,250),(3,251),(3,252),(3,253),(3,254),(3,255),(3,256),(3,257),(3,258),(3,259),(3,260),(3,261),(3,262),(3,263),(3,264),(3,265),(3,266),(3,267),(3,268),(3,269),(3,270),(3,271),(3,272),(3,273),(3,274),(3,275),(3,276),(3,277),(3,278),(3,279),(3,280),(3,281),(3,282),(3,283),(3,284),(3,285),(3,286),(3,287),(3,288),(3,289),(3,290),(3,291),(3,292),(3,293),(3,294),(3,295),(3,296),(3,297),(3,298),(3,299),(3,300),(3,301),(3,302),(3,303),(3,304),(3,305),(3,306),(3,307),(3,308),(3,309),(3,310),(3,311),(3,312),(3,313),(3,314),(3,315),(3,316),(3,317),(3,318),(3,319),(3,320),(3,321),(3,322),(3,323),(3,324),(3,325),(3,326),(3,327),(3,328),(3,329),(3,330),(3,331),(3,332),(3,333),(3,334),(3,335),(3,336),(3,337),(3,338),(3,339),(3,340),(3,341),(3,342),(3,343),(3,344),(3,345),(3,346),(3,347),(3,348),(3,349),(3,350),(3,351),(3,352),(3,353),(3,354),(3,355),(3,356),(3,357),(3,358),(3,359),(3,360),(3,361),(3,362),(3,363),(3,364),(3,365),(3,366),(3,367),(3,368),(3,369),(3,370),(3,371),(3,372),(3,373),(3,374),(3,375),(3,376),(3,377),(3,378),(3,379),(3,380),(3,381),(3,382),(3,383),(3,384),(4,17),(4,18),(4,19),(4,20),(4,21),(4,22),(4,23),(4,24),(4,25),(4,26),(4,27),(4,28),(4,29),(4,30),(4,31),(4,32),(4,33),(4,34),(4,35),(4,36),(4,189),(4,190),(4,191),(4,192),(4,193),(4,194),(4,195),(4,196),(4,197),(4,198),(4,199),(4,200),(4,201),(4,202),(4,203),(4,204),(4,205),(4,206),(4,207),(4,208),(4,209),(4,210),(4,211),(4,212),(4,213),(4,214),(4,215),(4,216),(4,217),(4,218),(4,219),(4,220),(4,221),(4,222),(4,223),(4,224),(4,225),(4,226),(4,227),(4,228),(4,229),(4,230),(4,231),(4,232),(4,233),(4,234),(4,235),(4,236),(4,237),(4,238),(4,239),(4,240),(4,241),(4,242),(4,243),(4,244),(4,245),(4,246),(4,247),(4,248),(4,249),(4,250),(4,251),(4,252),(4,253),(4,254),(4,255),(4,256),(4,257),(4,258),(4,259),(4,260),(4,261),(4,262),(4,263),(4,264),(4,265),(4,266),(4,267),(4,268),(4,269),(4,270),(4,271),(4,272),(4,273),(4,274),(4,275),(4,276),(4,277),(4,278),(4,279),(4,280),(4,281),(4,282),(4,283),(4,284),(4,285),(4,286),(4,287),(4,288),(4,289),(4,290),(4,291),(4,292),(4,293),(4,294),(4,295),(4,296),(4,297),(4,298),(4,299),(4,300),(4,301),(4,302),(4,303),(4,304),(4,305),(4,306),(4,307),(4,308),(4,309),(4,310),(4,311),(4,312),(4,313),(4,314),(4,315),(4,316),(4,317),(4,318),(4,319),(4,320),(4,321),(4,322),(4,323),(4,324),(4,325),(4,326),(4,327),(4,328),(4,329),(4,330),(4,331),(4,332),(4,333),(4,334),(4,335),(4,336),(4,337),(4,338),(4,339),(4,340),(4,341),(4,342),(4,343),(4,344),(4,345),(4,346),(4,347),(4,348),(4,349),(4,350),(4,351),(4,352),(4,353),(4,354),(4,355),(4,356),(4,357),(4,358),(4,359),(4,360),(4,361),(4,362),(4,363),(4,364),(4,365),(4,366),(4,367),(4,368),(4,369),(4,370),(4,371),(4,372),(4,373),(4,374),(4,375),(4,376),(4,377),(4,378),(4,379),(4,380),(4,381),(4,382),(4,383),(4,384),(5,5),(5,6),(5,7),(5,8),(5,9),(5,10),(5,11),(5,12),(5,13),(5,14),(5,15),(5,16),(5,17),(5,18),(5,19),(5,20),(5,21),(5,22),(5,23),(5,24),(5,25),(5,26),(5,27),(5,28),(5,29),(5,30),(5,31),(5,32),(5,33),(5,34),(5,35),(5,36),(5,65),(5,66),(5,67),(5,68),(5,69),(5,70),(5,71),(5,72),(5,73),(5,74),(5,75),(5,76),(5,77),(5,78),(5,79),(5,80),(5,81),(5,82),(5,83),(5,84),(5,85),(5,86),(5,87),(5,88),(5,89),(5,90),(5,91),(5,92),(5,93),(5,94),(5,95),(5,96),(5,97),(5,98),(5,99),(5,100),(5,101),(5,102),(5,103),(5,104),(5,105),(5,106),(5,107),(5,108),(5,109),(5,110),(5,111),(5,112),(5,113),(5,114),(5,115),(5,116),(5,117),(5,118),(5,119),(5,120),(5,121),(5,122),(5,123),(5,124),(5,125),(5,126),(5,127),(5,128),(5,129),(5,130),(5,131),(5,132),(5,133),(5,134),(5,135),(5,136),(5,137),(5,138),(5,139),(5,140),(5,141),(5,142),(5,143),(5,144),(5,145),(5,146),(5,147),(5,148),(5,149),(5,150),(5,151),(5,152),(5,153),(5,154),(5,155),(5,156),(5,157),(5,158),(5,159),(5,160),(5,161),(5,162),(5,163),(5,164),(5,165),(5,166),(5,167),(5,168),(5,169),(5,170),(5,171),(5,172),(5,173),(5,174),(5,175),(5,176),(5,177),(5,178),(5,179),(5,180),(5,181),(5,182),(5,183),(5,184),(5,185),(5,186),(5,187),(5,188),(5,189),(5,190),(5,191),(5,192),(5,193),(5,194),(5,195),(5,196),(5,197),(5,198),(5,199),(5,200),(5,201),(5,202),(5,203),(5,204),(5,205),(5,206),(5,207),(5,208),(5,209),(5,210),(5,211),(5,212),(5,213),(5,214),(5,215),(5,216),(5,217),(5,218),(5,219),(5,220),(5,221),(5,222),(5,223),(5,224),(5,225),(5,226),(5,227),(5,228),(5,229),(5,230),(5,231),(5,232),(5,233),(5,234),(5,235),(5,236),(5,237),(5,238),(5,239),(5,240),(5,241),(5,242),(5,243),(5,244),(5,245),(5,246),(5,247),(5,248),(5,249),(5,250),(5,251),(5,252),(5,253),(5,254),(5,255),(5,256),(5,257),(5,258),(5,259),(5,260),(5,261),(5,262),(5,263),(5,264),(5,265),(5,266),(5,267),(5,268),(5,269),(5,270),(5,271),(5,272),(5,273),(5,274),(5,275),(5,276),(5,277),(5,278),(5,279),(5,280),(5,281),(5,282),(5,283),(5,284),(5,285),(5,286),(5,287),(5,288),(5,289),(5,290),(5,291),(5,292),(5,293),(5,294),(5,295),(5,296),(5,297),(5,298),(5,299),(5,300),(5,301),(5,302),(5,303),(5,304),(5,305),(5,306),(5,307),(5,308),(5,309),(5,310),(5,311),(5,312),(5,313),(5,314),(5,315),(5,316),(5,317),(5,318),(5,319),(5,320),(5,321),(5,322),(5,323),(5,324),(5,325),(5,326),(5,327),(5,328),(5,329),(5,330),(5,331),(5,332),(5,333),(5,334),(5,335),(5,336),(5,337),(5,338),(5,339),(5,340),(5,341),(5,342),(5,343),(5,344),(5,345),(5,346),(5,347),(5,348),(5,349),(5,350),(5,351),(5,352),(5,353),(5,354),(5,355),(5,356),(5,357),(5,358),(5,359),(5,360),(5,361),(5,362),(5,363),(5,364),(5,365),(5,366),(5,367),(5,368),(5,369),(5,370),(5,371),(5,372),(5,373),(5,374),(5,375),(5,376),(5,377),(5,378),(5,379),(5,380),(5,381),(5,382),(5,383),(5,384),(6,17),(6,18),(6,19),(6,20),(6,21),(6,22),(6,23),(6,24),(6,25),(6,26),(6,27),(6,28),(6,29),(6,30),(6,31),(6,32),(6,33),(6,34),(6,35),(6,36),(6,169),(6,170),(6,171),(6,172),(6,173),(6,174),(6,175),(6,176),(6,177),(6,178),(6,179),(6,180),(6,181),(6,182),(6,183),(6,184),(6,185),(6,186),(6,187),(6,188),(6,189),(6,190),(6,191),(6,192),(6,193),(6,194),(6,195),(6,196),(6,197),(6,198),(6,199),(6,200),(6,201),(6,202),(6,203),(6,204),(6,205),(6,206),(6,207),(6,208),(6,209),(6,210),(6,211),(6,212),(6,213),(6,214),(6,215),(6,216),(6,217),(6,218),(6,219),(6,220),(6,221),(6,222),(6,223),(6,224),(6,225),(6,226),(6,227),(6,228),(6,229),(6,230),(6,231),(6,232),(6,233),(6,234),(6,235),(6,236),(6,237),(6,238),(6,239),(6,240),(6,241),(6,242),(6,243),(6,244),(6,245),(6,246),(6,247),(6,248),(6,249),(6,250),(6,251),(6,252),(6,253),(6,254),(6,255),(6,256),(6,257),(6,258),(6,259),(6,260),(6,261),(6,262),(6,263),(6,264),(6,265),(6,266),(6,267),(6,268),(6,269),(6,270),(6,271),(6,272),(6,273),(6,274),(6,275),(6,276),(6,277),(6,278),(6,279),(6,280),(6,281),(6,282),(6,283),(6,284),(6,285),(6,286),(6,287),(6,288),(6,289),(6,290),(6,291),(6,292),(6,293),(6,294),(6,295),(6,296),(6,297),(6,298),(6,299),(6,300),(6,301),(6,302),(6,303),(6,304),(6,305),(6,306),(6,307),(6,308),(6,309),(6,310),(6,311),(6,312),(6,313),(6,314),(6,315),(6,316),(6,317),(6,318),(6,319),(6,320),(6,321),(6,322),(6,323),(6,324),(6,325),(6,326),(6,327),(6,328),(6,329),(6,330),(6,331),(6,332),(6,333),(6,334),(6,335),(6,336),(6,337),(6,338),(6,339),(6,340),(6,341),(6,342),(6,343),(6,344),(6,345),(6,346),(6,347),(6,348),(6,349),(6,350),(6,351),(6,352),(6,353),(6,354),(6,355),(6,356),(6,357),(6,358),(6,359),(6,360),(6,361),(6,362),(6,363),(6,364),(6,365),(6,366),(6,367),(6,368),(6,369),(6,370),(6,371),(6,372),(6,373),(6,374),(6,375),(6,376),(6,377),(6,378),(6,379),(6,380),(6,381),(6,382),(6,383),(6,384),(7,5),(7,6),(7,7),(7,8),(7,9),(7,10),(7,11),(7,12),(7,13),(7,14),(7,15),(7,16),(7,17),(7,18),(7,19),(7,20),(7,21),(7,22),(7,23),(7,24),(7,25),(7,26),(7,27),(7,28),(7,29),(7,30),(7,31),(7,32),(7,33),(7,34),(7,35),(7,36),(7,45),(7,46),(7,47),(7,48),(7,49),(7,50),(7,51),(7,52),(7,53),(7,54),(7,55),(7,56),(7,57),(7,58),(7,59),(7,60),(7,61),(7,62),(7,63),(7,64),(7,65),(7,66),(7,67),(7,68),(7,69),(7,70),(7,71),(7,72),(7,73),(7,74),(7,75),(7,76),(7,77),(7,78),(7,79),(7,80),(7,81),(7,82),(7,83),(7,84),(7,85),(7,86),(7,87),(7,88),(7,89),(7,90),(7,91),(7,92),(7,93),(7,94),(7,95),(7,96),(7,97),(7,98),(7,99),(7,100),(7,101),(7,102),(7,103),(7,104),(7,105),(7,106),(7,107),(7,108),(7,109),(7,110),(7,111),(7,112),(7,113),(7,114),(7,115),(7,116),(7,117),(7,118),(7,119),(7,120),(7,121),(7,122),(7,123),(7,124),(7,125),(7,126),(7,127),(7,128),(7,129),(7,130),(7,131),(7,132),(7,133),(7,134),(7,135),(7,136),(7,137),(7,138),(7,139),(7,140),(7,141),(7,142),(7,143),(7,144),(7,145),(7,146),(7,147),(7,148),(7,149),(7,150),(7,151),(7,152),(7,153),(7,154),(7,155),(7,156),(7,157),(7,158),(7,159),(7,160),(7,161),(7,162),(7,163),(7,164),(7,165),(7,166),(7,167),(7,168),(7,169),(7,170),(7,171),(7,172),(7,173),(7,174),(7,175),(7,176),(7,177),(7,178),(7,179),(7,180),(7,181),(7,182),(7,183),(7,184),(7,185),(7,186),(7,187),(7,188),(7,189),(7,190),(7,191),(7,192),(7,193),(7,194),(7,195),(7,196),(7,197),(7,198),(7,199),(7,200),(7,201),(7,202),(7,203),(7,204),(7,205),(7,206),(7,207),(7,208),(7,209),(7,210),(7,211),(7,212),(7,213),(7,214),(7,215),(7,216),(7,217),(7,218),(7,219),(7,220),(7,221),(7,222),(7,223),(7,224),(7,225),(7,226),(7,227),(7,228),(7,229),(7,230),(7,231),(7,232),(7,233),(7,234),(7,235),(7,236),(7,237),(7,238),(7,239),(7,240),(7,241),(7,242),(7,243),(7,244),(7,245),(7,246),(7,247),(7,248),(7,249),(7,250),(7,251),(7,252),(7,253),(7,254),(7,255),(7,256),(7,257),(7,258),(7,259),(7,260),(7,261),(7,262),(7,263),(7,264),(7,265),(7,266),(7,267),(7,268),(7,269),(7,270),(7,271),(7,272),(7,273),(7,274),(7,275),(7,276),(7,277),(7,278),(7,279),(7,280),(7,281),(7,282),(7,283),(7,284),(7,285),(7,286),(7,287),(7,288),(7,289),(7,290),(7,291),(7,292),(7,293),(7,294),(7,295),(7,296),(7,297),(7,298),(7,299),(7,300),(7,301),(7,302),(7,303),(7,304),(7,305),(7,306),(7,307),(7,308),(7,309),(7,310),(7,311),(7,312),(7,313),(7,314),(7,315),(7,316),(7,317),(7,318),(7,319),(7,320),(7,321),(7,322),(7,323),(7,324),(7,325),(7,326),(7,327),(7,328),(7,329),(7,330),(7,331),(7,332),(7,333),(7,334),(7,335),(7,336),(7,337),(7,338),(7,339),(7,340),(7,341),(7,342),(7,343),(7,344),(7,345),(7,346),(7,347),(7,348),(7,349),(7,350),(7,351),(7,352),(7,353),(7,354),(7,355),(7,356),(7,357),(7,358),(7,359),(7,360),(7,361),(7,362),(7,363),(7,364),(7,365),(7,366),(7,367),(7,368),(7,369),(7,370),(7,371),(7,372),(7,373),(7,374),(7,375),(7,376),(7,377),(7,378),(7,379),(7,380),(7,381),(7,382),(7,383),(7,384),(8,13),(8,14),(8,15),(8,16),(8,17),(8,18),(8,19),(8,20),(8,21),(8,22),(8,23),(8,24),(8,25),(8,26),(8,27),(8,28),(8,29),(8,30),(8,31),(8,32),(8,33),(8,34),(8,35),(8,36),(8,153),(8,154),(8,155),(8,156),(8,157),(8,158),(8,159),(8,160),(8,161),(8,162),(8,163),(8,164),(8,165),(8,166),(8,167),(8,168),(8,169),(8,170),(8,171),(8,172),(8,173),(8,174),(8,175),(8,176),(8,177),(8,178),(8,179),(8,180),(8,181),(8,182),(8,183),(8,184),(8,185),(8,186),(8,187),(8,188),(8,189),(8,190),(8,191),(8,192),(8,193),(8,194),(8,195),(8,196),(8,197),(8,198),(8,199),(8,200),(8,201),(8,202),(8,203),(8,204),(8,205),(8,206),(8,207),(8,208),(8,209),(8,210),(8,211),(8,212),(8,213),(8,214),(8,215),(8,216),(8,217),(8,218),(8,219),(8,220),(8,221),(8,222),(8,223),(8,224),(8,225),(8,226),(8,227),(8,228),(8,229),(8,230),(8,231),(8,232),(8,233),(8,234),(8,235),(8,236),(8,237),(8,238),(8,239),(8,240),(8,241),(8,242),(8,243),(8,244),(8,245),(8,246),(8,247),(8,248),(8,249),(8,250),(8,251),(8,252),(8,253),(8,254),(8,255),(8,256),(8,257),(8,258),(8,259),(8,260),(8,261),(8,262),(8,263),(8,264),(8,265),(8,266),(8,267),(8,268),(8,269),(8,270),(8,271),(8,272),(8,273),(8,274),(8,275),(8,276),(8,277),(8,278),(8,279),(8,280),(8,281),(8,282),(8,283),(8,284),(8,285),(8,286),(8,287),(8,288),(8,289),(8,290),(8,291),(8,292),(8,293),(8,294),(8,295),(8,296),(8,297),(8,298),(8,299),(8,300),(8,301),(8,302),(8,303),(8,304),(8,305),(8,306),(8,307),(8,308),(8,309),(8,310),(8,311),(8,312),(8,313),(8,314),(8,315),(8,316),(8,317),(8,318),(8,319),(8,320),(8,321),(8,322),(8,323),(8,324),(8,325),(8,326),(8,327),(8,328),(8,329),(8,330),(8,331),(8,332),(8,333),(8,334),(8,335),(8,336),(8,337),(8,338),(8,339),(8,340),(8,341),(8,342),(8,343),(8,344),(8,345),(8,346),(8,347),(8,348),(8,349),(8,350),(8,351),(8,352),(8,353),(8,354),(8,355),(8,356),(8,357),(8,358),(8,359),(8,360),(8,361),(8,362),(8,363),(8,364),(8,365),(8,366),(8,367),(8,368),(8,369),(8,370),(8,371),(8,372),(8,373),(8,374),(8,375),(8,376),(8,377),(8,378),(8,379),(8,380),(8,381),(8,382),(8,383),(8,384),(9,197),(9,198),(9,199),(9,200),(9,201),(9,202),(9,203),(9,204),(9,205),(9,206),(9,207),(9,208),(10,13),(10,14),(10,15),(10,16),(10,17),(10,18),(10,19),(10,20),(10,21),(10,22),(10,23),(10,24),(10,25),(10,26),(10,27),(10,28),(10,29),(10,30),(10,31),(10,32),(10,33),(10,34),(10,35),(10,36),(10,133),(10,134),(10,135),(10,136),(10,137),(10,138),(10,139),(10,140),(10,141),(10,142),(10,143),(10,144),(10,145),(10,146),(10,147),(10,148),(10,149),(10,150),(10,151),(10,152),(10,153),(10,154),(10,155),(10,156),(10,157),(10,158),(10,159),(10,160),(10,161),(10,162),(10,163),(10,164),(10,165),(10,166),(10,167),(10,168),(10,169),(10,170),(10,171),(10,172),(10,173),(10,174),(10,175),(10,176),(10,177),(10,178),(10,179),(10,180),(10,181),(10,182),(10,183),(10,184),(10,185),(10,186),(10,187),(10,188),(10,189),(10,190),(10,191),(10,192),(10,193),(10,194),(10,195),(10,196),(10,197),(10,198),(10,199),(10,200),(10,201),(10,202),(10,203),(10,204),(10,205),(10,206),(10,207),(10,208),(10,209),(10,210),(10,211),(10,212),(10,213),(10,214),(10,215),(10,216),(10,217),(10,218),(10,219),(10,220),(10,221),(10,222),(10,223),(10,224),(10,225),(10,226),(10,227),(10,228),(10,229),(10,230),(10,231),(10,232),(10,233),(10,234),(10,235),(10,236),(10,237),(10,238),(10,239),(10,240),(10,241),(10,242),(10,243),(10,244),(10,245),(10,246),(10,247),(10,248),(10,249),(10,250),(10,251),(10,252),(10,253),(10,254),(10,255),(10,256),(10,257),(10,258),(10,259),(10,260),(10,261),(10,262),(10,263),(10,264),(10,265),(10,266),(10,267),(10,268),(10,269),(10,270),(10,271),(10,272),(10,273),(10,274),(10,275),(10,276),(10,277),(10,278),(10,279),(10,280),(10,281),(10,282),(10,283),(10,284),(10,285),(10,286),(10,287),(10,288),(10,289),(10,290),(10,291),(10,292),(10,293),(10,294),(10,295),(10,296),(10,297),(10,298),(10,299),(10,300),(10,301),(10,302),(10,303),(10,304),(10,305),(10,306),(10,307),(10,308),(10,309),(10,310),(10,311),(10,312),(10,313),(10,314),(10,315),(10,316),(10,317),(10,318),(10,319),(10,320),(10,321),(10,322),(10,323),(10,324),(10,325),(10,326),(10,327),(10,328),(10,329),(10,330),(10,331),(10,332),(10,333),(10,334),(10,335),(10,336),(10,337),(10,338),(10,339),(10,340),(10,341),(10,342),(10,343),(10,344),(10,345),(10,346),(10,347),(10,348),(10,349),(10,350),(10,351),(10,352),(10,353),(10,354),(10,355),(10,356),(10,357),(10,358),(10,359),(10,360),(10,361),(10,362),(10,363),(10,364),(10,365),(10,366),(10,367),(10,368),(10,369),(10,370),(10,371),(10,372),(10,373),(10,374),(10,375),(10,376),(10,377),(10,378),(10,379),(10,380),(10,381),(10,382),(10,383),(10,384),(11,17),(11,18),(11,19),(11,20),(11,169),(11,170),(11,171),(11,172),(11,173),(11,174),(11,175),(11,176),(11,177),(11,178),(11,179),(11,180),(11,181),(11,182),(11,183),(11,184),(11,185),(11,186),(11,187),(11,188),(11,189),(11,190),(11,191),(11,192),(11,193),(11,194),(11,195),(11,196),(12,9),(12,10),(12,11),(12,12),(12,13),(12,14),(12,15),(12,16),(12,17),(12,18),(12,19),(12,20),(12,21),(12,22),(12,23),(12,24),(12,25),(12,26),(12,27),(12,28),(12,29),(12,30),(12,31),(12,32),(12,33),(12,34),(12,35),(12,36),(12,117),(12,118),(12,119),(12,120),(12,121),(12,122),(12,123),(12,124),(12,125),(12,126),(12,127),(12,128),(12,129),(12,130),(12,131),(12,132),(12,133),(12,134),(12,135),(12,136),(12,137),(12,138),(12,139),(12,140),(12,141),(12,142),(12,143),(12,144),(12,145),(12,146),(12,147),(12,148),(12,149),(12,150),(12,151),(12,152),(12,153),(12,154),(12,155),(12,156),(12,157),(12,158),(12,159),(12,160),(12,161),(12,162),(12,163),(12,164),(12,165),(12,166),(12,167),(12,168),(12,169),(12,170),(12,171),(12,172),(12,173),(12,174),(12,175),(12,176),(12,177),(12,178),(12,179),(12,180),(12,181),(12,182),(12,183),(12,184),(12,185),(12,186),(12,187),(12,188),(12,189),(12,190),(12,191),(12,192),(12,193),(12,194),(12,195),(12,196),(12,197),(12,198),(12,199),(12,200),(12,201),(12,202),(12,203),(12,204),(12,205),(12,206),(12,207),(12,208),(12,209),(12,210),(12,211),(12,212),(12,213),(12,214),(12,215),(12,216),(12,217),(12,218),(12,219),(12,220),(12,221),(12,222),(12,223),(12,224),(12,225),(12,226),(12,227),(12,228),(12,229),(12,230),(12,231),(12,232),(12,233),(12,234),(12,235),(12,236),(12,237),(12,238),(12,239),(12,240),(12,241),(12,242),(12,243),(12,244),(12,245),(12,246),(12,247),(12,248),(12,249),(12,250),(12,251),(12,252),(12,253),(12,254),(12,255),(12,256),(12,257),(12,258),(12,259),(12,260),(12,261),(12,262),(12,263),(12,264),(12,265),(12,266),(12,267),(12,268),(12,269),(12,270),(12,271),(12,272),(12,273),(12,274),(12,275),(12,276),(12,277),(12,278),(12,279),(12,280),(12,281),(12,282),(12,283),(12,284),(12,285),(12,286),(12,287),(12,288),(12,289),(12,290),(12,291),(12,292),(12,293),(12,294),(12,295),(12,296),(12,297),(12,298),(12,299),(12,300),(12,301),(12,302),(12,303),(12,304),(12,305),(12,306),(12,307),(12,308),(12,309),(12,310),(12,311),(12,312),(12,313),(12,314),(12,315),(12,316),(12,317),(12,318),(12,319),(12,320),(12,321),(12,322),(12,323),(12,324),(12,325),(12,326),(12,327),(12,328),(12,329),(12,330),(12,331),(12,332),(12,333),(12,334),(12,335),(12,336),(12,337),(12,338),(12,339),(12,340),(12,341),(12,342),(12,343),(12,344),(12,345),(12,346),(12,347),(12,348),(12,349),(12,350),(12,351),(12,352),(12,353),(12,354),(12,355),(12,356),(12,357),(12,358),(12,359),(12,360),(12,361),(12,362),(12,363),(12,364),(12,365),(12,366),(12,367),(12,368),(12,369),(12,370),(12,371),(12,372),(12,373),(12,374),(12,375),(12,376),(12,377),(12,378),(12,379),(12,380),(12,381),(12,382),(12,383),(12,384),(13,13),(13,14),(13,15),(13,16),(13,121),(13,122),(13,123),(13,124),(13,125),(13,126),(13,127),(13,128),(13,129),(13,130),(13,131),(13,132),(13,133),(13,134),(13,135),(13,136),(13,137),(13,138),(13,139),(13,140),(13,141),(13,142),(13,143),(13,144),(13,145),(13,146),(13,147),(13,148),(13,149),(13,150),(13,151),(13,152),(13,153),(13,154),(13,155),(13,156),(13,157),(13,158),(13,159),(13,160),(13,161),(13,162),(13,163),(13,164),(13,165),(13,166),(13,167),(13,168),(14,9),(14,10),(14,11),(14,12),(14,13),(14,14),(14,15),(14,16),(14,17),(14,18),(14,19),(14,20),(14,21),(14,22),(14,23),(14,24),(14,25),(14,26),(14,27),(14,28),(14,29),(14,30),(14,31),(14,32),(14,33),(14,34),(14,35),(14,36),(14,93),(14,94),(14,95),(14,96),(14,97),(14,98),(14,99),(14,100),(14,101),(14,102),(14,103),(14,104),(14,105),(14,106),(14,107),(14,108),(14,109),(14,110),(14,111),(14,112),(14,113),(14,114),(14,115),(14,116),(14,117),(14,118),(14,119),(14,120),(14,121),(14,122),(14,123),(14,124),(14,125),(14,126),(14,127),(14,128),(14,129),(14,130),(14,131),(14,132),(14,133),(14,134),(14,135),(14,136),(14,137),(14,138),(14,139),(14,140),(14,141),(14,142),(14,143),(14,144),(14,145),(14,146),(14,147),(14,148),(14,149),(14,150),(14,151),(14,152),(14,153),(14,154),(14,155),(14,156),(14,157),(14,158),(14,159),(14,160),(14,161),(14,162),(14,163),(14,164),(14,165),(14,166),(14,167),(14,168),(14,169),(14,170),(14,171),(14,172),(14,173),(14,174),(14,175),(14,176),(14,177),(14,178),(14,179),(14,180),(14,181),(14,182),(14,183),(14,184),(14,185),(14,186),(14,187),(14,188),(14,189),(14,190),(14,191),(14,192),(14,193),(14,194),(14,195),(14,196),(14,197),(14,198),(14,199),(14,200),(14,201),(14,202),(14,203),(14,204),(14,205),(14,206),(14,207),(14,208),(14,209),(14,210),(14,211),(14,212),(14,213),(14,214),(14,215),(14,216),(14,217),(14,218),(14,219),(14,220),(14,221),(14,222),(14,223),(14,224),(14,225),(14,226),(14,227),(14,228),(14,229),(14,230),(14,231),(14,232),(14,233),(14,234),(14,235),(14,236),(14,237),(14,238),(14,239),(14,240),(14,241),(14,242),(14,243),(14,244),(14,245),(14,246),(14,247),(14,248),(14,249),(14,250),(14,251),(14,252),(14,253),(14,254),(14,255),(14,256),(14,257),(14,258),(14,259),(14,260),(14,261),(14,262),(14,263),(14,264),(14,265),(14,266),(14,267),(14,268),(14,269),(14,270),(14,271),(14,272),(14,273),(14,274),(14,275),(14,276),(14,277),(14,278),(14,279),(14,280),(14,281),(14,282),(14,283),(14,284),(14,285),(14,286),(14,287),(14,288),(14,289),(14,290),(14,291),(14,292),(14,293),(14,294),(14,295),(14,296),(14,297),(14,298),(14,299),(14,300),(14,301),(14,302),(14,303),(14,304),(14,305),(14,306),(14,307),(14,308),(14,309),(14,310),(14,311),(14,312),(14,313),(14,314),(14,315),(14,316),(14,317),(14,318),(14,319),(14,320),(14,321),(14,322),(14,323),(14,324),(14,325),(14,326),(14,327),(14,328),(14,329),(14,330),(14,331),(14,332),(14,333),(14,334),(14,335),(14,336),(14,337),(14,338),(14,339),(14,340),(14,341),(14,342),(14,343),(14,344),(14,345),(14,346),(14,347),(14,348),(14,349),(14,350),(14,351),(14,352),(14,353),(14,354),(14,355),(14,356),(14,357),(14,358),(14,359),(14,360),(14,361),(14,362),(14,363),(14,364),(14,365),(14,366),(14,367),(14,368),(14,369),(14,370),(14,371),(14,372),(14,373),(14,374),(14,375),(14,376),(14,377),(14,378),(14,379),(14,380),(14,381),(14,382),(14,383),(14,384),(15,5),(15,6),(15,7),(15,8),(15,9),(15,10),(15,11),(15,12),(15,57),(15,58),(15,59),(15,60),(15,61),(15,62),(15,63),(15,64),(15,65),(15,66),(15,67),(15,68),(15,69),(15,70),(15,71),(15,72),(15,73),(15,74),(15,75),(15,76),(15,77),(15,78),(15,79),(15,80),(15,81),(15,82),(15,83),(15,84),(15,85),(15,86),(15,87),(15,88),(15,89),(15,90),(15,91),(15,92),(15,93),(15,94),(15,95),(15,96),(15,97),(15,98),(15,99),(15,100),(15,101),(15,102),(15,103),(15,104),(15,105),(15,106),(15,107),(15,108),(15,109),(15,110),(15,111),(15,112),(15,113),(15,114),(15,115),(15,116),(15,117),(15,118),(15,119),(15,120),(16,5),(16,6),(16,7),(16,8),(16,9),(16,10),(16,11),(16,12),(16,13),(16,14),(16,15),(16,16),(16,17),(16,18),(16,19),(16,20),(16,21),(16,22),(16,23),(16,24),(16,25),(16,26),(16,27),(16,28),(16,29),(16,30),(16,31),(16,32),(16,33),(16,34),(16,35),(16,36),(16,77),(16,78),(16,79),(16,80),(16,81),(16,82),(16,83),(16,84),(16,85),(16,86),(16,87),(16,88),(16,89),(16,90),(16,91),(16,92),(16,93),(16,94),(16,95),(16,96),(16,97),(16,98),(16,99),(16,100),(16,101),(16,102),(16,103),(16,104),(16,105),(16,106),(16,107),(16,108),(16,109),(16,110),(16,111),(16,112),(16,113),(16,114),(16,115),(16,116),(16,117),(16,118),(16,119),(16,120),(16,121),(16,122),(16,123),(16,124),(16,125),(16,126),(16,127),(16,128),(16,129),(16,130),(16,131),(16,132),(16,133),(16,134),(16,135),(16,136),(16,137),(16,138),(16,139),(16,140),(16,141),(16,142),(16,143),(16,144),(16,145),(16,146),(16,147),(16,148),(16,149),(16,150),(16,151),(16,152),(16,153),(16,154),(16,155),(16,156),(16,157),(16,158),(16,159),(16,160),(16,161),(16,162),(16,163),(16,164),(16,165),(16,166),(16,167),(16,168),(16,169),(16,170),(16,171),(16,172),(16,173),(16,174),(16,175),(16,176),(16,177),(16,178),(16,179),(16,180),(16,181),(16,182),(16,183),(16,184),(16,185),(16,186),(16,187),(16,188),(16,189),(16,190),(16,191),(16,192),(16,193),(16,194),(16,195),(16,196),(16,197),(16,198),(16,199),(16,200),(16,201),(16,202),(16,203),(16,204),(16,205),(16,206),(16,207),(16,208),(16,209),(16,210),(16,211),(16,212),(16,213),(16,214),(16,215),(16,216),(16,217),(16,218),(16,219),(16,220),(16,221),(16,222),(16,223),(16,224),(16,225),(16,226),(16,227),(16,228),(16,229),(16,230),(16,231),(16,232),(16,233),(16,234),(16,235),(16,236),(16,237),(16,238),(16,239),(16,240),(16,241),(16,242),(16,243),(16,244),(16,245),(16,246),(16,247),(16,248),(16,249),(16,250),(16,251),(16,252),(16,253),(16,254),(16,255),(16,256),(16,257),(16,258),(16,259),(16,260),(16,261),(16,262),(16,263),(16,264),(16,265),(16,266),(16,267),(16,268),(16,269),(16,270),(16,271),(16,272),(16,273),(16,274),(16,275),(16,276),(16,277),(16,278),(16,279),(16,280),(16,281),(16,282),(16,283),(16,284),(16,285),(16,286),(16,287),(16,288),(16,289),(16,290),(16,291),(16,292),(16,293),(16,294),(16,295),(16,296),(16,297),(16,298),(16,299),(16,300),(16,301),(16,302),(16,303),(16,304),(16,305),(16,306),(16,307),(16,308),(16,309),(16,310),(16,311),(16,312),(16,313),(16,314),(16,315),(16,316),(16,317),(16,318),(16,319),(16,320),(16,321),(16,322),(16,323),(16,324),(16,325),(16,326),(16,327),(16,328),(16,329),(16,330),(16,331),(16,332),(16,333),(16,334),(16,335),(16,336),(16,337),(16,338),(16,339),(16,340),(16,341),(16,342),(16,343),(16,344),(16,345),(16,346),(16,347),(16,348),(16,349),(16,350),(16,351),(16,352),(16,353),(16,354),(16,355),(16,356),(16,357),(16,358),(16,359),(16,360),(16,361),(16,362),(16,363),(16,364),(16,365),(16,366),(16,367),(16,368),(16,369),(16,370),(16,371),(16,372),(16,373),(16,374),(16,375),(16,376),(16,377),(16,378),(16,379),(16,380),(16,381),(16,382),(16,383),(16,384),(17,13),(17,14),(17,15),(17,16),(17,17),(17,18),(17,19),(17,20),(17,49),(17,50),(17,51),(17,52),(17,53),(17,54),(17,55),(17,56),(17,121),(17,122),(17,123),(17,124),(17,125),(17,126),(17,127),(17,128),(17,129),(17,130),(17,131),(17,132),(17,133),(17,134),(17,135),(17,136),(17,137),(17,138),(17,139),(17,140),(17,141),(17,142),(17,143),(17,144),(17,145),(17,146),(17,147),(17,148),(17,149),(17,150),(17,151),(17,152),(17,153),(17,154),(17,155),(17,156),(17,157),(17,158),(17,159),(17,160),(17,161),(17,162),(17,163),(17,164),(17,165),(17,166),(17,167),(17,168),(17,169),(17,170),(17,171),(17,172),(17,173),(17,174),(17,175),(17,176),(17,177),(17,178),(17,179),(17,180),(17,181),(17,182),(17,183),(17,184),(17,185),(17,186),(17,187),(17,188),(17,189),(17,190),(17,191),(17,192),(17,193),(17,194),(17,195),(17,196),(18,5),(18,6),(18,7),(18,8),(18,9),(18,10),(18,11),(18,12),(18,13),(18,14),(18,15),(18,16),(18,17),(18,18),(18,19),(18,20),(18,21),(18,22),(18,23),(18,24),(18,25),(18,26),(18,27),(18,28),(18,29),(18,30),(18,31),(18,32),(18,33),(18,34),(18,35),(18,36),(18,57),(18,58),(18,59),(18,60),(18,61),(18,62),(18,63),(18,64),(18,65),(18,66),(18,67),(18,68),(18,69),(18,70),(18,71),(18,72),(18,73),(18,74),(18,75),(18,76),(18,77),(18,78),(18,79),(18,80),(18,81),(18,82),(18,83),(18,84),(18,85),(18,86),(18,87),(18,88),(18,89),(18,90),(18,91),(18,92),(18,93),(18,94),(18,95),(18,96),(18,97),(18,98),(18,99),(18,100),(18,101),(18,102),(18,103),(18,104),(18,105),(18,106),(18,107),(18,108),(18,109),(18,110),(18,111),(18,112),(18,113),(18,114),(18,115),(18,116),(18,117),(18,118),(18,119),(18,120),(18,121),(18,122),(18,123),(18,124),(18,125),(18,126),(18,127),(18,128),(18,129),(18,130),(18,131),(18,132),(18,133),(18,134),(18,135),(18,136),(18,137),(18,138),(18,139),(18,140),(18,141),(18,142),(18,143),(18,144),(18,145),(18,146),(18,147),(18,148),(18,149),(18,150),(18,151),(18,152),(18,153),(18,154),(18,155),(18,156),(18,157),(18,158),(18,159),(18,160),(18,161),(18,162),(18,163),(18,164),(18,165),(18,166),(18,167),(18,168),(18,169),(18,170),(18,171),(18,172),(18,173),(18,174),(18,175),(18,176),(18,177),(18,178),(18,179),(18,180),(18,181),(18,182),(18,183),(18,184),(18,185),(18,186),(18,187),(18,188),(18,189),(18,190),(18,191),(18,192),(18,193),(18,194),(18,195),(18,196),(18,197),(18,198),(18,199),(18,200),(18,201),(18,202),(18,203),(18,204),(18,205),(18,206),(18,207),(18,208),(18,209),(18,210),(18,211),(18,212),(18,213),(18,214),(18,215),(18,216),(18,217),(18,218),(18,219),(18,220),(18,221),(18,222),(18,223),(18,224),(18,225),(18,226),(18,227),(18,228),(18,229),(18,230),(18,231),(18,232),(18,233),(18,234),(18,235),(18,236),(18,237),(18,238),(18,239),(18,240),(18,241),(18,242),(18,243),(18,244),(18,245),(18,246),(18,247),(18,248),(18,249),(18,250),(18,251),(18,252),(18,253),(18,254),(18,255),(18,256),(18,257),(18,258),(18,259),(18,260),(18,261),(18,262),(18,263),(18,264),(18,265),(18,266),(18,267),(18,268),(18,269),(18,270),(18,271),(18,272),(18,273),(18,274),(18,275),(18,276),(18,277),(18,278),(18,279),(18,280),(18,281),(18,282),(18,283),(18,284),(18,285),(18,286),(18,287),(18,288),(18,289),(18,290),(18,291),(18,292),(18,293),(18,294),(18,295),(18,296),(18,297),(18,298),(18,299),(18,300),(18,301),(18,302),(18,303),(18,304),(18,305),(18,306),(18,307),(18,308),(18,309),(18,310),(18,311),(18,312),(18,313),(18,314),(18,315),(18,316),(18,317),(18,318),(18,319),(18,320),(18,321),(18,322),(18,323),(18,324),(18,325),(18,326),(18,327),(18,328),(18,329),(18,330),(18,331),(18,332),(18,333),(18,334),(18,335),(18,336),(18,337),(18,338),(18,339),(18,340),(18,341),(18,342),(18,343),(18,344),(18,345),(18,346),(18,347),(18,348),(18,349),(18,350),(18,351),(18,352),(18,353),(18,354),(18,355),(18,356),(18,357),(18,358),(18,359),(18,360),(18,361),(18,362),(18,363),(18,364),(18,365),(18,366),(18,367),(18,368),(18,369),(18,370),(18,371),(18,372),(18,373),(18,374),(18,375),(18,376),(18,377),(18,378),(18,379),(18,380),(18,381),(18,382),(18,383),(18,384),(19,9),(19,10),(19,11),(19,12),(19,13),(19,14),(19,15),(19,16),(19,81),(19,82),(19,83),(19,84),(19,85),(19,86),(19,87),(19,88),(19,89),(19,90),(19,91),(19,92),(19,93),(19,94),(19,95),(19,96),(19,97),(19,98),(19,99),(19,100),(19,101),(19,102),(19,103),(19,104),(19,105),(19,106),(19,107),(19,108),(19,109),(19,110),(19,111),(19,112),(19,113),(19,114),(19,115),(19,116),(19,117),(19,118),(19,119),(19,120),(19,121),(19,122),(19,123),(19,124),(19,125),(19,126),(19,127),(19,128),(19,129),(19,130),(19,131),(19,132),(19,133),(19,134),(19,135),(19,136),(19,137),(19,138),(19,139),(19,140),(19,141),(19,142),(19,143),(19,144),(19,145),(19,146),(19,147),(19,148),(19,149),(19,150),(19,151),(19,152),(19,153),(19,154),(19,155),(19,156),(19,157),(19,158),(19,159),(19,160),(19,161),(19,162),(19,163),(19,164),(19,165),(19,166),(19,167),(19,168),(19,169),(19,170),(19,171),(19,172),(19,173),(19,174),(19,175),(19,176),(19,177),(19,178),(19,179),(19,180),(19,181),(19,182),(19,183),(19,184),(19,185),(19,186),(19,187),(19,188); /*!40000 ALTER TABLE `gantt_jobs_resources_visu` ENABLE KEYS */; UNLOCK TABLES; -- -- Table structure for table `job_dependencies` -- DROP TABLE IF EXISTS `job_dependencies`; SET @saved_cs_client = @@character_set_client; SET character_set_client = utf8; CREATE TABLE `job_dependencies` ( `job_id` int(10) unsigned NOT NULL, `job_id_required` int(10) unsigned NOT NULL, `job_dependency_index` enum('CURRENT','LOG') NOT NULL default 'CURRENT', PRIMARY KEY (`job_id`,`job_id_required`), KEY `id` (`job_id`), KEY `log` (`job_dependency_index`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1; SET character_set_client = @saved_cs_client; -- -- Dumping data for table `job_dependencies` -- LOCK TABLES `job_dependencies` WRITE; /*!40000 ALTER TABLE `job_dependencies` DISABLE KEYS */; /*!40000 ALTER TABLE `job_dependencies` ENABLE KEYS */; UNLOCK TABLES; -- -- Table structure for table `job_resource_descriptions` -- DROP TABLE IF EXISTS `job_resource_descriptions`; SET @saved_cs_client = @@character_set_client; SET character_set_client = utf8; CREATE TABLE `job_resource_descriptions` ( `res_job_group_id` int(10) unsigned NOT NULL, `res_job_resource_type` varchar(255) NOT NULL, `res_job_value` int(11) NOT NULL, `res_job_order` int(10) unsigned NOT NULL default '0', `res_job_index` enum('CURRENT','LOG') NOT NULL default 'CURRENT', PRIMARY KEY (`res_job_group_id`,`res_job_resource_type`,`res_job_order`), KEY `resgroup` (`res_job_group_id`), KEY `log` (`res_job_index`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1; SET character_set_client = @saved_cs_client; -- -- Dumping data for table `job_resource_descriptions` -- LOCK TABLES `job_resource_descriptions` WRITE; /*!40000 ALTER TABLE `job_resource_descriptions` DISABLE KEYS */; INSERT INTO `job_resource_descriptions` VALUES (1,'resource_id',-1,0,'CURRENT'),(2,'host',48,0,'CURRENT'),(3,'host',83,0,'CURRENT'),(4,'host',54,0,'CURRENT'),(5,'host',88,0,'CURRENT'),(6,'host',59,0,'CURRENT'),(7,'host',93,0,'CURRENT'),(8,'host',64,0,'CURRENT'),(9,'host',3,0,'CURRENT'),(10,'host',69,0,'CURRENT'),(11,'host',8,0,'CURRENT'),(12,'host',74,0,'CURRENT'),(13,'host',13,0,'CURRENT'),(14,'host',80,0,'CURRENT'),(15,'host',18,0,'CURRENT'),(16,'host',85,0,'CURRENT'),(17,'host',23,0,'CURRENT'),(18,'host',90,0,'CURRENT'),(19,'host',29,0,'CURRENT'),(20,'host',95,0,'CURRENT'),(21,'host',34,0,'CURRENT'),(22,'host',5,0,'CURRENT'),(23,'host',39,0,'CURRENT'),(24,'host',10,0,'CURRENT'),(25,'host',44,0,'CURRENT'),(26,'host',79,0,'CURRENT'),(27,'host',50,0,'CURRENT'),(28,'host',55,0,'CURRENT'),(29,'host',89,0,'CURRENT'),(30,'host',60,0,'CURRENT'),(31,'host',95,0,'CURRENT'),(32,'host',65,0,'CURRENT'),(33,'host',4,0,'CURRENT'),(34,'host',70,0,'CURRENT'),(35,'host',9,0,'CURRENT'),(36,'host',76,0,'CURRENT'),(37,'host',14,0,'CURRENT'),(38,'host',81,0,'CURRENT'),(39,'host',19,0,'CURRENT'),(40,'host',86,0,'CURRENT'),(41,'host',25,0,'CURRENT'),(42,'host',91,0,'CURRENT'),(43,'host',30,0,'CURRENT'),(44,'host',96,0,'CURRENT'),(45,'host',35,0,'CURRENT'),(46,'host',6,0,'CURRENT'),(47,'host',40,0,'CURRENT'),(48,'host',75,0,'CURRENT'),(49,'host',45,0,'CURRENT'),(50,'host',80,0,'CURRENT'),(51,'host',51,0,'CURRENT'),(52,'host',85,0,'CURRENT'),(53,'host',56,0,'CURRENT'),(54,'host',90,0,'CURRENT'),(55,'host',61,0,'CURRENT'),(56,'host',96,0,'CURRENT'),(57,'host',66,0,'CURRENT'),(58,'host',5,0,'CURRENT'),(59,'host',71,0,'CURRENT'),(60,'host',10,0,'CURRENT'),(61,'host',77,0,'CURRENT'),(62,'host',15,0,'CURRENT'),(63,'host',82,0,'CURRENT'),(64,'host',20,0,'CURRENT'),(65,'host',87,0,'CURRENT'),(66,'host',26,0,'CURRENT'),(67,'host',92,0,'CURRENT'),(68,'host',31,0,'CURRENT'),(69,'host',1,0,'CURRENT'),(70,'host',36,0,'CURRENT'),(71,'host',7,0,'CURRENT'),(72,'host',41,0,'CURRENT'),(73,'host',76,0,'CURRENT'),(74,'host',46,0,'CURRENT'),(75,'host',81,0,'CURRENT'),(76,'host',52,0,'CURRENT'),(77,'host',86,0,'CURRENT'),(78,'host',57,0,'CURRENT'),(79,'host',91,0,'CURRENT'),(80,'host',62,0,'CURRENT'),(81,'host',1,0,'CURRENT'),(82,'host',67,0,'CURRENT'),(83,'host',6,0,'CURRENT'),(84,'host',73,0,'CURRENT'),(85,'host',11,0,'CURRENT'),(86,'host',78,0,'CURRENT'),(87,'host',16,0,'CURRENT'),(88,'host',83,0,'CURRENT'),(89,'host',22,0,'CURRENT'),(90,'host',88,0,'CURRENT'),(91,'host',27,0,'CURRENT'),(92,'host',93,0,'CURRENT'),(93,'host',32,0,'CURRENT'),(94,'host',3,0,'CURRENT'),(95,'host',37,0,'CURRENT'),(96,'host',8,0,'CURRENT'),(97,'host',42,0,'CURRENT'),(98,'host',77,0,'CURRENT'),(99,'host',48,0,'CURRENT'),(100,'host',82,0,'CURRENT'),(101,'host',53,0,'CURRENT'); /*!40000 ALTER TABLE `job_resource_descriptions` ENABLE KEYS */; UNLOCK TABLES; -- -- Table structure for table `job_resource_groups` -- DROP TABLE IF EXISTS `job_resource_groups`; SET @saved_cs_client = @@character_set_client; SET character_set_client = utf8; CREATE TABLE `job_resource_groups` ( `res_group_id` int(10) unsigned NOT NULL auto_increment, `res_group_moldable_id` int(10) unsigned NOT NULL, `res_group_property` text, `res_group_index` enum('CURRENT','LOG') NOT NULL default 'CURRENT', PRIMARY KEY (`res_group_id`), KEY `moldable_job` (`res_group_moldable_id`), KEY `log` (`res_group_index`) ) ENGINE=MyISAM AUTO_INCREMENT=102 DEFAULT CHARSET=latin1; SET character_set_client = @saved_cs_client; -- -- Dumping data for table `job_resource_groups` -- LOCK TABLES `job_resource_groups` WRITE; /*!40000 ALTER TABLE `job_resource_groups` DISABLE KEYS */; INSERT INTO `job_resource_groups` VALUES (1,1,'type = \'default\'','CURRENT'),(2,2,'type = \'default\'','CURRENT'),(3,3,'type = \'default\'','CURRENT'),(4,4,'type = \'default\'','CURRENT'),(5,5,'type = \'default\'','CURRENT'),(6,6,'type = \'default\'','CURRENT'),(7,7,'type = \'default\'','CURRENT'),(8,8,'type = \'default\'','CURRENT'),(9,9,'type = \'default\'','CURRENT'),(10,10,'type = \'default\'','CURRENT'),(11,11,'type = \'default\'','CURRENT'),(12,12,'type = \'default\'','CURRENT'),(13,13,'type = \'default\'','CURRENT'),(14,14,'type = \'default\'','CURRENT'),(15,15,'type = \'default\'','CURRENT'),(16,16,'type = \'default\'','CURRENT'),(17,17,'type = \'default\'','CURRENT'),(18,18,'type = \'default\'','CURRENT'),(19,19,'type = \'default\'','CURRENT'),(20,20,'type = \'default\'','CURRENT'),(21,21,'type = \'default\'','CURRENT'),(22,22,'type = \'default\'','CURRENT'),(23,23,'type = \'default\'','CURRENT'),(24,24,'type = \'default\'','CURRENT'),(25,25,'type = \'default\'','CURRENT'),(26,26,'type = \'default\'','CURRENT'),(27,27,'type = \'default\'','CURRENT'),(28,28,'type = \'default\'','CURRENT'),(29,29,'type = \'default\'','CURRENT'),(30,30,'type = \'default\'','CURRENT'),(31,31,'type = \'default\'','CURRENT'),(32,32,'type = \'default\'','CURRENT'),(33,33,'type = \'default\'','CURRENT'),(34,34,'type = \'default\'','CURRENT'),(35,35,'type = \'default\'','CURRENT'),(36,36,'type = \'default\'','CURRENT'),(37,37,'type = \'default\'','CURRENT'),(38,38,'type = \'default\'','CURRENT'),(39,39,'type = \'default\'','CURRENT'),(40,40,'type = \'default\'','CURRENT'),(41,41,'type = \'default\'','CURRENT'),(42,42,'type = \'default\'','CURRENT'),(43,43,'type = \'default\'','CURRENT'),(44,44,'type = \'default\'','CURRENT'),(45,45,'type = \'default\'','CURRENT'),(46,46,'type = \'default\'','CURRENT'),(47,47,'type = \'default\'','CURRENT'),(48,48,'type = \'default\'','CURRENT'),(49,49,'type = \'default\'','CURRENT'),(50,50,'type = \'default\'','CURRENT'),(51,51,'type = \'default\'','CURRENT'),(52,52,'type = \'default\'','CURRENT'),(53,53,'type = \'default\'','CURRENT'),(54,54,'type = \'default\'','CURRENT'),(55,55,'type = \'default\'','CURRENT'),(56,56,'type = \'default\'','CURRENT'),(57,57,'type = \'default\'','CURRENT'),(58,58,'type = \'default\'','CURRENT'),(59,59,'type = \'default\'','CURRENT'),(60,60,'type = \'default\'','CURRENT'),(61,61,'type = \'default\'','CURRENT'),(62,62,'type = \'default\'','CURRENT'),(63,63,'type = \'default\'','CURRENT'),(64,64,'type = \'default\'','CURRENT'),(65,65,'type = \'default\'','CURRENT'),(66,66,'type = \'default\'','CURRENT'),(67,67,'type = \'default\'','CURRENT'),(68,68,'type = \'default\'','CURRENT'),(69,69,'type = \'default\'','CURRENT'),(70,70,'type = \'default\'','CURRENT'),(71,71,'type = \'default\'','CURRENT'),(72,72,'type = \'default\'','CURRENT'),(73,73,'type = \'default\'','CURRENT'),(74,74,'type = \'default\'','CURRENT'),(75,75,'type = \'default\'','CURRENT'),(76,76,'type = \'default\'','CURRENT'),(77,77,'type = \'default\'','CURRENT'),(78,78,'type = \'default\'','CURRENT'),(79,79,'type = \'default\'','CURRENT'),(80,80,'type = \'default\'','CURRENT'),(81,81,'type = \'default\'','CURRENT'),(82,82,'type = \'default\'','CURRENT'),(83,83,'type = \'default\'','CURRENT'),(84,84,'type = \'default\'','CURRENT'),(85,85,'type = \'default\'','CURRENT'),(86,86,'type = \'default\'','CURRENT'),(87,87,'type = \'default\'','CURRENT'),(88,88,'type = \'default\'','CURRENT'),(89,89,'type = \'default\'','CURRENT'),(90,90,'type = \'default\'','CURRENT'),(91,91,'type = \'default\'','CURRENT'),(92,92,'type = \'default\'','CURRENT'),(93,93,'type = \'default\'','CURRENT'),(94,94,'type = \'default\'','CURRENT'),(95,95,'type = \'default\'','CURRENT'),(96,96,'type = \'default\'','CURRENT'),(97,97,'type = \'default\'','CURRENT'),(98,98,'type = \'default\'','CURRENT'),(99,99,'type = \'default\'','CURRENT'),(100,100,'type = \'default\'','CURRENT'),(101,101,'type = \'default\'','CURRENT'); /*!40000 ALTER TABLE `job_resource_groups` ENABLE KEYS */; UNLOCK TABLES; -- -- Table structure for table `job_state_logs` -- DROP TABLE IF EXISTS `job_state_logs`; SET @saved_cs_client = @@character_set_client; SET character_set_client = utf8; CREATE TABLE `job_state_logs` ( `job_state_log_id` int(10) unsigned NOT NULL auto_increment, `job_id` int(10) unsigned NOT NULL, `job_state` enum('Waiting','Hold','toLaunch','toError','toAckReservation','Launching','Finishing','Running','Suspended','Resuming','Terminated','Error') NOT NULL, `date_start` int(10) unsigned NOT NULL, `date_stop` int(10) unsigned default '0', PRIMARY KEY (`job_state_log_id`), KEY `id` (`job_id`), KEY `state` (`job_state`) ) ENGINE=MyISAM AUTO_INCREMENT=105 DEFAULT CHARSET=latin1; SET character_set_client = @saved_cs_client; -- -- Dumping data for table `job_state_logs` -- LOCK TABLES `job_state_logs` WRITE; /*!40000 ALTER TABLE `job_state_logs` DISABLE KEYS */; INSERT INTO `job_state_logs` VALUES (1,1,'Waiting',1224778627,1224778628),(2,1,'toLaunch',1224778628,1224778628),(3,1,'Launching',1224778628,1224778629),(4,1,'Running',1224778629,0),(5,2,'Waiting',1224778637,0),(6,3,'Waiting',1224778638,0),(7,4,'Waiting',1224778639,0),(8,5,'Waiting',1224778640,0),(9,6,'Waiting',1224778640,0),(10,7,'Waiting',1224778641,0),(11,8,'Waiting',1224778642,0),(12,9,'Waiting',1224778642,0),(13,10,'Waiting',1224778643,0),(14,11,'Waiting',1224778644,0),(15,12,'Waiting',1224778645,0),(16,13,'Waiting',1224778645,0),(17,14,'Waiting',1224778646,0),(18,15,'Waiting',1224778647,0),(19,16,'Waiting',1224778647,0),(20,17,'Waiting',1224778648,0),(21,18,'Waiting',1224778648,0),(22,19,'Waiting',1224778649,0),(23,20,'Waiting',1224778650,0),(24,21,'Waiting',1224778650,0),(25,22,'Waiting',1224778651,0),(26,23,'Waiting',1224778652,0),(27,24,'Waiting',1224778652,0),(28,25,'Waiting',1224778653,0),(29,26,'Waiting',1224778653,0),(30,27,'Waiting',1224778654,0),(31,28,'Waiting',1224778655,0),(32,29,'Waiting',1224778655,0),(33,30,'Waiting',1224778656,0),(34,31,'Waiting',1224778657,0),(35,32,'Waiting',1224778657,0),(36,33,'Waiting',1224778658,0),(37,34,'Waiting',1224778658,0),(38,35,'Waiting',1224778659,0),(39,36,'Waiting',1224778660,0),(40,37,'Waiting',1224778660,0),(41,38,'Waiting',1224778661,0),(42,39,'Waiting',1224778661,0),(43,40,'Waiting',1224778662,0),(44,41,'Waiting',1224778663,0),(45,42,'Waiting',1224778663,0),(46,43,'Waiting',1224778664,0),(47,44,'Waiting',1224778665,0),(48,45,'Waiting',1224778665,0),(49,46,'Waiting',1224778666,0),(50,47,'Waiting',1224778666,0),(51,48,'Waiting',1224778667,0),(52,49,'Waiting',1224778668,0),(53,50,'Waiting',1224778668,0),(54,51,'Waiting',1224778669,0),(55,52,'Waiting',1224778669,0),(56,53,'Waiting',1224778670,0),(57,54,'Waiting',1224778671,0),(58,55,'Waiting',1224778671,0),(59,56,'Waiting',1224778672,0),(60,57,'Waiting',1224778673,0),(61,58,'Waiting',1224778673,0),(62,59,'Waiting',1224778674,0),(63,60,'Waiting',1224778674,0),(64,61,'Waiting',1224778675,0),(65,62,'Waiting',1224778676,0),(66,63,'Waiting',1224778676,0),(67,64,'Waiting',1224778677,0),(68,65,'Waiting',1224778678,0),(69,66,'Waiting',1224778678,0),(70,67,'Waiting',1224778679,0),(71,68,'Waiting',1224778680,0),(72,69,'Waiting',1224778680,0),(73,70,'Waiting',1224778681,0),(74,71,'Waiting',1224778681,0),(75,72,'Waiting',1224778682,0),(76,73,'Waiting',1224778683,0),(77,74,'Waiting',1224778683,0),(78,75,'Waiting',1224778684,0),(79,76,'Waiting',1224778684,0),(80,77,'Waiting',1224778685,0),(81,78,'Waiting',1224778686,0),(82,79,'Waiting',1224778686,0),(83,80,'Waiting',1224778687,0),(84,81,'Waiting',1224778688,0),(85,82,'Waiting',1224778688,0),(86,83,'Waiting',1224778689,0),(87,84,'Waiting',1224778689,0),(88,85,'Waiting',1224778690,0),(89,86,'Waiting',1224778691,0),(90,87,'Waiting',1224778691,0),(91,88,'Waiting',1224778692,0),(92,89,'Waiting',1224778692,0),(93,90,'Waiting',1224778693,0),(94,91,'Waiting',1224778694,0),(95,92,'Waiting',1224778694,0),(96,93,'Waiting',1224778695,0),(97,94,'Waiting',1224778696,0),(98,95,'Waiting',1224778696,0),(99,96,'Waiting',1224778697,0),(100,97,'Waiting',1224778697,0),(101,98,'Waiting',1224778698,0),(102,99,'Waiting',1224778699,0),(103,100,'Waiting',1224778699,0),(104,101,'Waiting',1224778700,0); /*!40000 ALTER TABLE `job_state_logs` ENABLE KEYS */; UNLOCK TABLES; -- -- Table structure for table `job_types` -- DROP TABLE IF EXISTS `job_types`; SET @saved_cs_client = @@character_set_client; SET character_set_client = utf8; CREATE TABLE `job_types` ( `job_type_id` int(10) unsigned NOT NULL auto_increment, `job_id` int(10) unsigned NOT NULL, `type` varchar(255) NOT NULL, `types_index` enum('CURRENT','LOG') NOT NULL default 'CURRENT', PRIMARY KEY (`job_type_id`), KEY `log` (`types_index`), KEY `type` (`type`), KEY `id_types` (`job_id`) ) ENGINE=MyISAM AUTO_INCREMENT=2 DEFAULT CHARSET=latin1; SET character_set_client = @saved_cs_client; -- -- Dumping data for table `job_types` -- LOCK TABLES `job_types` WRITE; /*!40000 ALTER TABLE `job_types` DISABLE KEYS */; INSERT INTO `job_types` VALUES (1,1,'cosystem','CURRENT'); /*!40000 ALTER TABLE `job_types` ENABLE KEYS */; UNLOCK TABLES; -- -- Table structure for table `jobs` -- DROP TABLE IF EXISTS `jobs`; SET @saved_cs_client = @@character_set_client; SET character_set_client = utf8; CREATE TABLE `jobs` ( `job_id` int(10) unsigned NOT NULL auto_increment, `initial_request` text, `job_name` varchar(100) default NULL, `job_env` text, `job_type` enum('INTERACTIVE','PASSIVE') NOT NULL default 'PASSIVE', `info_type` varchar(255) default NULL, `state` enum('Waiting','Hold','toLaunch','toError','toAckReservation','Launching','Running','Suspended','Resuming','Finishing','Terminated','Error') NOT NULL, `reservation` enum('None','toSchedule','Scheduled') NOT NULL default 'None', `message` varchar(255) NOT NULL, `scheduler_info` varchar(255) NOT NULL, `job_user` varchar(255) NOT NULL, `project` varchar(255) NOT NULL, `job_group` varchar(255) NOT NULL, `command` text, `exit_code` int(11) default NULL, `queue_name` varchar(100) NOT NULL, `properties` text, `launching_directory` text NOT NULL, `submission_time` int(10) unsigned NOT NULL, `start_time` int(10) unsigned NOT NULL, `stop_time` int(10) unsigned NOT NULL, `file_id` int(10) unsigned default NULL, `accounted` enum('YES','NO') NOT NULL default 'NO', `notify` varchar(255) default NULL, `assigned_moldable_job` int(10) unsigned default '0', `checkpoint` int(10) unsigned NOT NULL default '0', `checkpoint_signal` int(11) NOT NULL, `stdout_file` text, `stderr_file` text, `resubmit_job_id` int(10) unsigned default '0', `suspended` enum('YES','NO') NOT NULL default 'NO', PRIMARY KEY (`job_id`), KEY `state` (`state`), KEY `state_id` (`state`,`job_id`), KEY `reservation` (`reservation`), KEY `queue_name` (`queue_name`), KEY `accounted` (`accounted`), KEY `suspended` (`suspended`) ) ENGINE=MyISAM AUTO_INCREMENT=102 DEFAULT CHARSET=latin1; SET character_set_client = @saved_cs_client; -- -- Dumping data for table `jobs` -- LOCK TABLES `jobs` WRITE; /*!40000 ALTER TABLE `jobs` DISABLE KEYS */; INSERT INTO `jobs` VALUES (1,'oarsub -l nodes=ALL,walltime=4 -t cosystem sleep 14400',NULL,NULL,'PASSIVE','caigang:','Running','None','FIFO scheduling OK','FIFO scheduling OK','neyron','default','','sleep 14400',NULL,'default','desktop_computing = \'NO\'','/home/neyron',1224778627,1224778628,0,NULL,'NO',NULL,1,0,12,'OAR.%jobid%.stdout','OAR.%jobid%.stderr',0,'NO'),(2,'oarsub -l host=48,walltime=9 sleep 3600',NULL,NULL,'PASSIVE','caigang:','Waiting','None','FIFO scheduling OK','FIFO scheduling OK','neyron','default','','sleep 3600',NULL,'default','desktop_computing = \'NO\'','/home/neyron',1224778637,0,0,NULL,'NO',NULL,0,0,12,'OAR.%jobid%.stdout','OAR.%jobid%.stderr',0,'NO'),(3,'oarsub -l host=83,walltime=5 sleep 3600',NULL,NULL,'PASSIVE','caigang:','Waiting','None','FIFO scheduling OK','FIFO scheduling OK','neyron','default','','sleep 3600',NULL,'default','desktop_computing = \'NO\'','/home/neyron',1224778638,0,0,NULL,'NO',NULL,0,0,12,'OAR.%jobid%.stdout','OAR.%jobid%.stderr',0,'NO'),(4,'oarsub -l host=54,walltime=10 sleep 3600',NULL,NULL,'PASSIVE','caigang:','Waiting','None','FIFO scheduling OK','FIFO scheduling OK','neyron','default','','sleep 3600',NULL,'default','desktop_computing = \'NO\'','/home/neyron',1224778639,0,0,NULL,'NO',NULL,0,0,12,'OAR.%jobid%.stdout','OAR.%jobid%.stderr',0,'NO'),(5,'oarsub -l host=88,walltime=6 sleep 3600',NULL,NULL,'PASSIVE','caigang:','Waiting','None','FIFO scheduling OK','FIFO scheduling OK','neyron','default','','sleep 3600',NULL,'default','desktop_computing = \'NO\'','/home/neyron',1224778640,0,0,NULL,'NO',NULL,0,0,12,'OAR.%jobid%.stdout','OAR.%jobid%.stderr',0,'NO'),(6,'oarsub -l host=59,walltime=2 sleep 3600',NULL,NULL,'PASSIVE','caigang:','Waiting','None','FIFO scheduling OK','FIFO scheduling OK','neyron','default','','sleep 3600',NULL,'default','desktop_computing = \'NO\'','/home/neyron',1224778640,0,0,NULL,'NO',NULL,0,0,12,'OAR.%jobid%.stdout','OAR.%jobid%.stderr',0,'NO'),(7,'oarsub -l host=93,walltime=8 sleep 3600',NULL,NULL,'PASSIVE','caigang:','Waiting','None','FIFO scheduling OK','FIFO scheduling OK','neyron','default','','sleep 3600',NULL,'default','desktop_computing = \'NO\'','/home/neyron',1224778641,0,0,NULL,'NO',NULL,0,0,12,'OAR.%jobid%.stdout','OAR.%jobid%.stderr',0,'NO'),(8,'oarsub -l host=64,walltime=3 sleep 3600',NULL,NULL,'PASSIVE','caigang:','Waiting','None','FIFO scheduling OK','FIFO scheduling OK','neyron','default','','sleep 3600',NULL,'default','desktop_computing = \'NO\'','/home/neyron',1224778642,0,0,NULL,'NO',NULL,0,0,12,'OAR.%jobid%.stdout','OAR.%jobid%.stderr',0,'NO'),(9,'oarsub -l host=3,walltime=9 sleep 3600',NULL,NULL,'PASSIVE','caigang:','Waiting','None','FIFO scheduling OK','FIFO scheduling OK','neyron','default','','sleep 3600',NULL,'default','desktop_computing = \'NO\'','/home/neyron',1224778642,0,0,NULL,'NO',NULL,0,0,12,'OAR.%jobid%.stdout','OAR.%jobid%.stderr',0,'NO'),(10,'oarsub -l host=69,walltime=5 sleep 3600',NULL,NULL,'PASSIVE','caigang:','Waiting','None','FIFO scheduling OK','FIFO scheduling OK','neyron','default','','sleep 3600',NULL,'default','desktop_computing = \'NO\'','/home/neyron',1224778643,0,0,NULL,'NO',NULL,0,0,12,'OAR.%jobid%.stdout','OAR.%jobid%.stderr',0,'NO'),(11,'oarsub -l host=8,walltime=1 sleep 3600',NULL,NULL,'PASSIVE','caigang:','Waiting','None','FIFO scheduling OK','FIFO scheduling OK','neyron','default','','sleep 3600',NULL,'default','desktop_computing = \'NO\'','/home/neyron',1224778644,0,0,NULL,'NO',NULL,0,0,12,'OAR.%jobid%.stdout','OAR.%jobid%.stderr',0,'NO'),(12,'oarsub -l host=74,walltime=6 sleep 3600',NULL,NULL,'PASSIVE','caigang:','Waiting','None','FIFO scheduling OK','FIFO scheduling OK','neyron','default','','sleep 3600',NULL,'default','desktop_computing = \'NO\'','/home/neyron',1224778645,0,0,NULL,'NO',NULL,0,0,12,'OAR.%jobid%.stdout','OAR.%jobid%.stderr',0,'NO'),(13,'oarsub -l host=13,walltime=2 sleep 3600',NULL,NULL,'PASSIVE','caigang:','Waiting','None','FIFO scheduling OK','FIFO scheduling OK','neyron','default','','sleep 3600',NULL,'default','desktop_computing = \'NO\'','/home/neyron',1224778645,0,0,NULL,'NO',NULL,0,0,12,'OAR.%jobid%.stdout','OAR.%jobid%.stderr',0,'NO'),(14,'oarsub -l host=80,walltime=8 sleep 3600',NULL,NULL,'PASSIVE','caigang:','Waiting','None','FIFO scheduling OK','FIFO scheduling OK','neyron','default','','sleep 3600',NULL,'default','desktop_computing = \'NO\'','/home/neyron',1224778646,0,0,NULL,'NO',NULL,0,0,12,'OAR.%jobid%.stdout','OAR.%jobid%.stderr',0,'NO'),(15,'oarsub -l host=18,walltime=4 sleep 3600',NULL,NULL,'PASSIVE','caigang:','Waiting','None','FIFO scheduling OK','FIFO scheduling OK','neyron','default','','sleep 3600',NULL,'default','desktop_computing = \'NO\'','/home/neyron',1224778647,0,0,NULL,'NO',NULL,0,0,12,'OAR.%jobid%.stdout','OAR.%jobid%.stderr',0,'NO'),(16,'oarsub -l host=85,walltime=9 sleep 3600',NULL,NULL,'PASSIVE','caigang:','Waiting','None','FIFO scheduling OK','FIFO scheduling OK','neyron','default','','sleep 3600',NULL,'default','desktop_computing = \'NO\'','/home/neyron',1224778647,0,0,NULL,'NO',NULL,0,0,12,'OAR.%jobid%.stdout','OAR.%jobid%.stderr',0,'NO'),(17,'oarsub -l host=23,walltime=5 sleep 3600',NULL,NULL,'PASSIVE','caigang:','Waiting','None','FIFO scheduling OK','FIFO scheduling OK','neyron','default','','sleep 3600',NULL,'default','desktop_computing = \'NO\'','/home/neyron',1224778648,0,0,NULL,'NO',NULL,0,0,12,'OAR.%jobid%.stdout','OAR.%jobid%.stderr',0,'NO'),(18,'oarsub -l host=90,walltime=1 sleep 3600',NULL,NULL,'PASSIVE','caigang:','Waiting','None','FIFO scheduling OK','FIFO scheduling OK','neyron','default','','sleep 3600',NULL,'default','desktop_computing = \'NO\'','/home/neyron',1224778648,0,0,NULL,'NO',NULL,0,0,12,'OAR.%jobid%.stdout','OAR.%jobid%.stderr',0,'NO'),(19,'oarsub -l host=29,walltime=6 sleep 3600',NULL,NULL,'PASSIVE','caigang:','Waiting','None','FIFO scheduling OK','FIFO scheduling OK','neyron','default','','sleep 3600',NULL,'default','desktop_computing = \'NO\'','/home/neyron',1224778649,0,0,NULL,'NO',NULL,0,0,12,'OAR.%jobid%.stdout','OAR.%jobid%.stderr',0,'NO'),(20,'oarsub -l host=95,walltime=2 sleep 3600',NULL,NULL,'PASSIVE','caigang:','Waiting','None','Cannot find enough resources which fit for the job 20','Cannot find enough resources which fit for the job 20','neyron','default','','sleep 3600',NULL,'default','desktop_computing = \'NO\'','/home/neyron',1224778650,0,0,NULL,'NO',NULL,0,0,12,'OAR.%jobid%.stdout','OAR.%jobid%.stderr',0,'NO'),(21,'oarsub -l host=34,walltime=8 sleep 3600',NULL,NULL,'PASSIVE','caigang:','Waiting','None','Cannot find enough resources which fit for the job 21','Cannot find enough resources which fit for the job 21','neyron','default','','sleep 3600',NULL,'default','desktop_computing = \'NO\'','/home/neyron',1224778650,0,0,NULL,'NO',NULL,0,0,12,'OAR.%jobid%.stdout','OAR.%jobid%.stderr',0,'NO'),(22,'oarsub -l host=5,walltime=4 sleep 3600',NULL,NULL,'PASSIVE','caigang:','Waiting','None','Cannot find enough resources which fit for the job 22','Cannot find enough resources which fit for the job 22','neyron','default','','sleep 3600',NULL,'default','desktop_computing = \'NO\'','/home/neyron',1224778651,0,0,NULL,'NO',NULL,0,0,12,'OAR.%jobid%.stdout','OAR.%jobid%.stderr',0,'NO'),(23,'oarsub -l host=39,walltime=9 sleep 3600',NULL,NULL,'PASSIVE','caigang:','Waiting','None','Cannot find enough resources which fit for the job 23','Cannot find enough resources which fit for the job 23','neyron','default','','sleep 3600',NULL,'default','desktop_computing = \'NO\'','/home/neyron',1224778652,0,0,NULL,'NO',NULL,0,0,12,'OAR.%jobid%.stdout','OAR.%jobid%.stderr',0,'NO'),(24,'oarsub -l host=10,walltime=5 sleep 3600',NULL,NULL,'PASSIVE','caigang:','Waiting','None','Cannot find enough resources which fit for the job 24','Cannot find enough resources which fit for the job 24','neyron','default','','sleep 3600',NULL,'default','desktop_computing = \'NO\'','/home/neyron',1224778652,0,0,NULL,'NO',NULL,0,0,12,'OAR.%jobid%.stdout','OAR.%jobid%.stderr',0,'NO'),(25,'oarsub -l host=44,walltime=1 sleep 3600',NULL,NULL,'PASSIVE','caigang:','Waiting','None','Cannot find enough resources which fit for the job 25','Cannot find enough resources which fit for the job 25','neyron','default','','sleep 3600',NULL,'default','desktop_computing = \'NO\'','/home/neyron',1224778653,0,0,NULL,'NO',NULL,0,0,12,'OAR.%jobid%.stdout','OAR.%jobid%.stderr',0,'NO'),(26,'oarsub -l host=79,walltime=7 sleep 3600',NULL,NULL,'PASSIVE','caigang:','Waiting','None','Cannot find enough resources which fit for the job 26','Cannot find enough resources which fit for the job 26','neyron','default','','sleep 3600',NULL,'default','desktop_computing = \'NO\'','/home/neyron',1224778653,0,0,NULL,'NO',NULL,0,0,12,'OAR.%jobid%.stdout','OAR.%jobid%.stderr',0,'NO'),(27,'oarsub -l host=50,walltime=2 sleep 3600',NULL,NULL,'PASSIVE','caigang:','Waiting','None','Cannot find enough resources which fit for the job 27','Cannot find enough resources which fit for the job 27','neyron','default','','sleep 3600',NULL,'default','desktop_computing = \'NO\'','/home/neyron',1224778654,0,0,NULL,'NO',NULL,0,0,12,'OAR.%jobid%.stdout','OAR.%jobid%.stderr',0,'NO'),(28,'oarsub -l host=55,walltime=4 sleep 3600',NULL,NULL,'PASSIVE','caigang:','Waiting','None','Cannot find enough resources which fit for the job 28','Cannot find enough resources which fit for the job 28','neyron','default','','sleep 3600',NULL,'default','desktop_computing = \'NO\'','/home/neyron',1224778655,0,0,NULL,'NO',NULL,0,0,12,'OAR.%jobid%.stdout','OAR.%jobid%.stderr',0,'NO'),(29,'oarsub -l host=89,walltime=10 sleep 3600',NULL,NULL,'PASSIVE','caigang:','Waiting','None','Cannot find enough resources which fit for the job 29','Cannot find enough resources which fit for the job 29','neyron','default','','sleep 3600',NULL,'default','desktop_computing = \'NO\'','/home/neyron',1224778655,0,0,NULL,'NO',NULL,0,0,12,'OAR.%jobid%.stdout','OAR.%jobid%.stderr',0,'NO'),(30,'oarsub -l host=60,walltime=5 sleep 3600',NULL,NULL,'PASSIVE','caigang:','Waiting','None','Cannot find enough resources which fit for the job 30','Cannot find enough resources which fit for the job 30','neyron','default','','sleep 3600',NULL,'default','desktop_computing = \'NO\'','/home/neyron',1224778656,0,0,NULL,'NO',NULL,0,0,12,'OAR.%jobid%.stdout','OAR.%jobid%.stderr',0,'NO'),(31,'oarsub -l host=95,walltime=1 sleep 3600',NULL,NULL,'PASSIVE','caigang:','Waiting','None','Cannot find enough resources which fit for the job 31','Cannot find enough resources which fit for the job 31','neyron','default','','sleep 3600',NULL,'default','desktop_computing = \'NO\'','/home/neyron',1224778657,0,0,NULL,'NO',NULL,0,0,12,'OAR.%jobid%.stdout','OAR.%jobid%.stderr',0,'NO'),(32,'oarsub -l host=65,walltime=7 sleep 3600',NULL,NULL,'PASSIVE','caigang:','Waiting','None','Cannot find enough resources which fit for the job 32','Cannot find enough resources which fit for the job 32','neyron','default','','sleep 3600',NULL,'default','desktop_computing = \'NO\'','/home/neyron',1224778657,0,0,NULL,'NO',NULL,0,0,12,'OAR.%jobid%.stdout','OAR.%jobid%.stderr',0,'NO'),(33,'oarsub -l host=4,walltime=5 sleep 3600',NULL,NULL,'PASSIVE','caigang:','Waiting','None','Cannot find enough resources which fit for the job 33','Cannot find enough resources which fit for the job 33','neyron','default','','sleep 3600',NULL,'default','desktop_computing = \'NO\'','/home/neyron',1224778658,0,0,NULL,'NO',NULL,0,0,12,'OAR.%jobid%.stdout','OAR.%jobid%.stderr',0,'NO'),(34,'oarsub -l host=70,walltime=10 sleep 3600',NULL,NULL,'PASSIVE','caigang:','Waiting','None','Cannot find enough resources which fit for the job 34','Cannot find enough resources which fit for the job 34','neyron','default','','sleep 3600',NULL,'default','desktop_computing = \'NO\'','/home/neyron',1224778658,0,0,NULL,'NO',NULL,0,0,12,'OAR.%jobid%.stdout','OAR.%jobid%.stderr',0,'NO'),(35,'oarsub -l host=9,walltime=6 sleep 3600',NULL,NULL,'PASSIVE','caigang:','Waiting','None','Cannot find enough resources which fit for the job 35','Cannot find enough resources which fit for the job 35','neyron','default','','sleep 3600',NULL,'default','desktop_computing = \'NO\'','/home/neyron',1224778659,0,0,NULL,'NO',NULL,0,0,12,'OAR.%jobid%.stdout','OAR.%jobid%.stderr',0,'NO'),(36,'oarsub -l host=76,walltime=2 sleep 3600',NULL,NULL,'PASSIVE','caigang:','Waiting','None','Cannot find enough resources which fit for the job 36','Cannot find enough resources which fit for the job 36','neyron','default','','sleep 3600',NULL,'default','desktop_computing = \'NO\'','/home/neyron',1224778660,0,0,NULL,'NO',NULL,0,0,12,'OAR.%jobid%.stdout','OAR.%jobid%.stderr',0,'NO'),(37,'oarsub -l host=14,walltime=7 sleep 3600',NULL,NULL,'PASSIVE','caigang:','Waiting','None','Cannot find enough resources which fit for the job 37','Cannot find enough resources which fit for the job 37','neyron','default','','sleep 3600',NULL,'default','desktop_computing = \'NO\'','/home/neyron',1224778660,0,0,NULL,'NO',NULL,0,0,12,'OAR.%jobid%.stdout','OAR.%jobid%.stderr',0,'NO'),(38,'oarsub -l host=81,walltime=3 sleep 3600',NULL,NULL,'PASSIVE','caigang:','Waiting','None','Cannot find enough resources which fit for the job 38','Cannot find enough resources which fit for the job 38','neyron','default','','sleep 3600',NULL,'default','desktop_computing = \'NO\'','/home/neyron',1224778661,0,0,NULL,'NO',NULL,0,0,12,'OAR.%jobid%.stdout','OAR.%jobid%.stderr',0,'NO'),(39,'oarsub -l host=19,walltime=9 sleep 3600',NULL,NULL,'PASSIVE','caigang:','Waiting','None','Cannot find enough resources which fit for the job 39','Cannot find enough resources which fit for the job 39','neyron','default','','sleep 3600',NULL,'default','desktop_computing = \'NO\'','/home/neyron',1224778661,0,0,NULL,'NO',NULL,0,0,12,'OAR.%jobid%.stdout','OAR.%jobid%.stderr',0,'NO'),(40,'oarsub -l host=86,walltime=5 sleep 3600',NULL,NULL,'PASSIVE','caigang:','Waiting','None','Cannot find enough resources which fit for the job 40','Cannot find enough resources which fit for the job 40','neyron','default','','sleep 3600',NULL,'default','desktop_computing = \'NO\'','/home/neyron',1224778662,0,0,NULL,'NO',NULL,0,0,12,'OAR.%jobid%.stdout','OAR.%jobid%.stderr',0,'NO'),(41,'oarsub -l host=25,walltime=10 sleep 3600',NULL,NULL,'PASSIVE','caigang:','Waiting','None','Cannot find enough resources which fit for the job 41','Cannot find enough resources which fit for the job 41','neyron','default','','sleep 3600',NULL,'default','desktop_computing = \'NO\'','/home/neyron',1224778663,0,0,NULL,'NO',NULL,0,0,12,'OAR.%jobid%.stdout','OAR.%jobid%.stderr',0,'NO'),(42,'oarsub -l host=91,walltime=6 sleep 3600',NULL,NULL,'PASSIVE','caigang:','Waiting','None','Cannot find enough resources which fit for the job 42','Cannot find enough resources which fit for the job 42','neyron','default','','sleep 3600',NULL,'default','desktop_computing = \'NO\'','/home/neyron',1224778663,0,0,NULL,'NO',NULL,0,0,12,'OAR.%jobid%.stdout','OAR.%jobid%.stderr',0,'NO'),(43,'oarsub -l host=30,walltime=2 sleep 3600',NULL,NULL,'PASSIVE','caigang:','Waiting','None','Cannot find enough resources which fit for the job 43','Cannot find enough resources which fit for the job 43','neyron','default','','sleep 3600',NULL,'default','desktop_computing = \'NO\'','/home/neyron',1224778664,0,0,NULL,'NO',NULL,0,0,12,'OAR.%jobid%.stdout','OAR.%jobid%.stderr',0,'NO'),(44,'oarsub -l host=96,walltime=8 sleep 3600',NULL,NULL,'PASSIVE','caigang:','Waiting','None','Cannot find enough resources which fit for the job 44','Cannot find enough resources which fit for the job 44','neyron','default','','sleep 3600',NULL,'default','desktop_computing = \'NO\'','/home/neyron',1224778665,0,0,NULL,'NO',NULL,0,0,12,'OAR.%jobid%.stdout','OAR.%jobid%.stderr',0,'NO'),(45,'oarsub -l host=35,walltime=3 sleep 3600',NULL,NULL,'PASSIVE','caigang:','Waiting','None','Cannot find enough resources which fit for the job 45','Cannot find enough resources which fit for the job 45','neyron','default','','sleep 3600',NULL,'default','desktop_computing = \'NO\'','/home/neyron',1224778665,0,0,NULL,'NO',NULL,0,0,12,'OAR.%jobid%.stdout','OAR.%jobid%.stderr',0,'NO'),(46,'oarsub -l host=6,walltime=9 sleep 3600',NULL,NULL,'PASSIVE','caigang:','Waiting','None','Cannot find enough resources which fit for the job 46','Cannot find enough resources which fit for the job 46','neyron','default','','sleep 3600',NULL,'default','desktop_computing = \'NO\'','/home/neyron',1224778666,0,0,NULL,'NO',NULL,0,0,12,'OAR.%jobid%.stdout','OAR.%jobid%.stderr',0,'NO'),(47,'oarsub -l host=40,walltime=5 sleep 3600',NULL,NULL,'PASSIVE','caigang:','Waiting','None','Cannot find enough resources which fit for the job 47','Cannot find enough resources which fit for the job 47','neyron','default','','sleep 3600',NULL,'default','desktop_computing = \'NO\'','/home/neyron',1224778666,0,0,NULL,'NO',NULL,0,0,12,'OAR.%jobid%.stdout','OAR.%jobid%.stderr',0,'NO'),(48,'oarsub -l host=75,walltime=1 sleep 3600',NULL,NULL,'PASSIVE','caigang:','Waiting','None','Cannot find enough resources which fit for the job 48','Cannot find enough resources which fit for the job 48','neyron','default','','sleep 3600',NULL,'default','desktop_computing = \'NO\'','/home/neyron',1224778667,0,0,NULL,'NO',NULL,0,0,12,'OAR.%jobid%.stdout','OAR.%jobid%.stderr',0,'NO'),(49,'oarsub -l host=45,walltime=6 sleep 3600',NULL,NULL,'PASSIVE','caigang:','Waiting','None','Cannot find enough resources which fit for the job 49','Cannot find enough resources which fit for the job 49','neyron','default','','sleep 3600',NULL,'default','desktop_computing = \'NO\'','/home/neyron',1224778668,0,0,NULL,'NO',NULL,0,0,12,'OAR.%jobid%.stdout','OAR.%jobid%.stderr',0,'NO'),(50,'oarsub -l host=80,walltime=2 sleep 3600',NULL,NULL,'PASSIVE','caigang:','Waiting','None','Cannot find enough resources which fit for the job 50','Cannot find enough resources which fit for the job 50','neyron','default','','sleep 3600',NULL,'default','desktop_computing = \'NO\'','/home/neyron',1224778668,0,0,NULL,'NO',NULL,0,0,12,'OAR.%jobid%.stdout','OAR.%jobid%.stderr',0,'NO'),(51,'oarsub -l host=51,walltime=8 sleep 3600',NULL,NULL,'PASSIVE','caigang:','Waiting','None','Cannot find enough resources which fit for the job 51','Cannot find enough resources which fit for the job 51','neyron','default','','sleep 3600',NULL,'default','desktop_computing = \'NO\'','/home/neyron',1224778669,0,0,NULL,'NO',NULL,0,0,12,'OAR.%jobid%.stdout','OAR.%jobid%.stderr',0,'NO'),(52,'oarsub -l host=85,walltime=4 sleep 3600',NULL,NULL,'PASSIVE','caigang:','Waiting','None','Cannot find enough resources which fit for the job 52','Cannot find enough resources which fit for the job 52','neyron','default','','sleep 3600',NULL,'default','desktop_computing = \'NO\'','/home/neyron',1224778669,0,0,NULL,'NO',NULL,0,0,12,'OAR.%jobid%.stdout','OAR.%jobid%.stderr',0,'NO'),(53,'oarsub -l host=56,walltime=9 sleep 3600',NULL,NULL,'PASSIVE','caigang:','Waiting','None','Cannot find enough resources which fit for the job 53','Cannot find enough resources which fit for the job 53','neyron','default','','sleep 3600',NULL,'default','desktop_computing = \'NO\'','/home/neyron',1224778670,0,0,NULL,'NO',NULL,0,0,12,'OAR.%jobid%.stdout','OAR.%jobid%.stderr',0,'NO'),(54,'oarsub -l host=90,walltime=5 sleep 3600',NULL,NULL,'PASSIVE','caigang:','Waiting','None','Cannot find enough resources which fit for the job 54','Cannot find enough resources which fit for the job 54','neyron','default','','sleep 3600',NULL,'default','desktop_computing = \'NO\'','/home/neyron',1224778671,0,0,NULL,'NO',NULL,0,0,12,'OAR.%jobid%.stdout','OAR.%jobid%.stderr',0,'NO'),(55,'oarsub -l host=61,walltime=1 sleep 3600',NULL,NULL,'PASSIVE','caigang:','Waiting','None','Cannot find enough resources which fit for the job 55','Cannot find enough resources which fit for the job 55','neyron','default','','sleep 3600',NULL,'default','desktop_computing = \'NO\'','/home/neyron',1224778671,0,0,NULL,'NO',NULL,0,0,12,'OAR.%jobid%.stdout','OAR.%jobid%.stderr',0,'NO'),(56,'oarsub -l host=96,walltime=6 sleep 3600',NULL,NULL,'PASSIVE','caigang:','Waiting','None','Cannot find enough resources which fit for the job 56','Cannot find enough resources which fit for the job 56','neyron','default','','sleep 3600',NULL,'default','desktop_computing = \'NO\'','/home/neyron',1224778672,0,0,NULL,'NO',NULL,0,0,12,'OAR.%jobid%.stdout','OAR.%jobid%.stderr',0,'NO'),(57,'oarsub -l host=66,walltime=2 sleep 3600',NULL,NULL,'PASSIVE','caigang:','Waiting','None','Cannot find enough resources which fit for the job 57','Cannot find enough resources which fit for the job 57','neyron','default','','sleep 3600',NULL,'default','desktop_computing = \'NO\'','/home/neyron',1224778673,0,0,NULL,'NO',NULL,0,0,12,'OAR.%jobid%.stdout','OAR.%jobid%.stderr',0,'NO'),(58,'oarsub -l host=5,walltime=8 sleep 3600',NULL,NULL,'PASSIVE','caigang:','Waiting','None','Cannot find enough resources which fit for the job 58','Cannot find enough resources which fit for the job 58','neyron','default','','sleep 3600',NULL,'default','desktop_computing = \'NO\'','/home/neyron',1224778673,0,0,NULL,'NO',NULL,0,0,12,'OAR.%jobid%.stdout','OAR.%jobid%.stderr',0,'NO'),(59,'oarsub -l host=71,walltime=4 sleep 3600',NULL,NULL,'PASSIVE','caigang:','Waiting','None','Cannot find enough resources which fit for the job 59','Cannot find enough resources which fit for the job 59','neyron','default','','sleep 3600',NULL,'default','desktop_computing = \'NO\'','/home/neyron',1224778674,0,0,NULL,'NO',NULL,0,0,12,'OAR.%jobid%.stdout','OAR.%jobid%.stderr',0,'NO'),(60,'oarsub -l host=10,walltime=9 sleep 3600',NULL,NULL,'PASSIVE','caigang:','Waiting','None','Cannot find enough resources which fit for the job 60','Cannot find enough resources which fit for the job 60','neyron','default','','sleep 3600',NULL,'default','desktop_computing = \'NO\'','/home/neyron',1224778674,0,0,NULL,'NO',NULL,0,0,12,'OAR.%jobid%.stdout','OAR.%jobid%.stderr',0,'NO'),(61,'oarsub -l host=77,walltime=5 sleep 3600',NULL,NULL,'PASSIVE','caigang:','Waiting','None','Cannot find enough resources which fit for the job 61','Cannot find enough resources which fit for the job 61','neyron','default','','sleep 3600',NULL,'default','desktop_computing = \'NO\'','/home/neyron',1224778675,0,0,NULL,'NO',NULL,0,0,12,'OAR.%jobid%.stdout','OAR.%jobid%.stderr',0,'NO'),(62,'oarsub -l host=15,walltime=1 sleep 3600',NULL,NULL,'PASSIVE','caigang:','Waiting','None','Cannot find enough resources which fit for the job 62','Cannot find enough resources which fit for the job 62','neyron','default','','sleep 3600',NULL,'default','desktop_computing = \'NO\'','/home/neyron',1224778676,0,0,NULL,'NO',NULL,0,0,12,'OAR.%jobid%.stdout','OAR.%jobid%.stderr',0,'NO'),(63,'oarsub -l host=82,walltime=7 sleep 3600',NULL,NULL,'PASSIVE','caigang:','Waiting','None','Cannot find enough resources which fit for the job 63','Cannot find enough resources which fit for the job 63','neyron','default','','sleep 3600',NULL,'default','desktop_computing = \'NO\'','/home/neyron',1224778676,0,0,NULL,'NO',NULL,0,0,12,'OAR.%jobid%.stdout','OAR.%jobid%.stderr',0,'NO'),(64,'oarsub -l host=20,walltime=2 sleep 3600',NULL,NULL,'PASSIVE','caigang:','Waiting','None','Cannot find enough resources which fit for the job 64','Cannot find enough resources which fit for the job 64','neyron','default','','sleep 3600',NULL,'default','desktop_computing = \'NO\'','/home/neyron',1224778677,0,0,NULL,'NO',NULL,0,0,12,'OAR.%jobid%.stdout','OAR.%jobid%.stderr',0,'NO'),(65,'oarsub -l host=87,walltime=8 sleep 3600',NULL,NULL,'PASSIVE','caigang:','Waiting','None','Cannot find enough resources which fit for the job 65','Cannot find enough resources which fit for the job 65','neyron','default','','sleep 3600',NULL,'default','desktop_computing = \'NO\'','/home/neyron',1224778678,0,0,NULL,'NO',NULL,0,0,12,'OAR.%jobid%.stdout','OAR.%jobid%.stderr',0,'NO'),(66,'oarsub -l host=26,walltime=4 sleep 3600',NULL,NULL,'PASSIVE','caigang:','Waiting','None','Cannot find enough resources which fit for the job 66','Cannot find enough resources which fit for the job 66','neyron','default','','sleep 3600',NULL,'default','desktop_computing = \'NO\'','/home/neyron',1224778678,0,0,NULL,'NO',NULL,0,0,12,'OAR.%jobid%.stdout','OAR.%jobid%.stderr',0,'NO'),(67,'oarsub -l host=92,walltime=10 sleep 3600',NULL,NULL,'PASSIVE','caigang:','Waiting','None','','','neyron','default','','sleep 3600',NULL,'default','desktop_computing = \'NO\'','/home/neyron',1224778679,0,0,NULL,'NO',NULL,0,0,12,'OAR.%jobid%.stdout','OAR.%jobid%.stderr',0,'NO'),(68,'oarsub -l host=31,walltime=5 sleep 3600',NULL,NULL,'PASSIVE','caigang:','Waiting','None','','','neyron','default','','sleep 3600',NULL,'default','desktop_computing = \'NO\'','/home/neyron',1224778680,0,0,NULL,'NO',NULL,0,0,12,'OAR.%jobid%.stdout','OAR.%jobid%.stderr',0,'NO'),(69,'oarsub -l host=1,walltime=1 sleep 3600',NULL,NULL,'PASSIVE','caigang:','Waiting','None','','','neyron','default','','sleep 3600',NULL,'default','desktop_computing = \'NO\'','/home/neyron',1224778680,0,0,NULL,'NO',NULL,0,0,12,'OAR.%jobid%.stdout','OAR.%jobid%.stderr',0,'NO'),(70,'oarsub -l host=36,walltime=7 sleep 3600',NULL,NULL,'PASSIVE','caigang:','Waiting','None','','','neyron','default','','sleep 3600',NULL,'default','desktop_computing = \'NO\'','/home/neyron',1224778681,0,0,NULL,'NO',NULL,0,0,12,'OAR.%jobid%.stdout','OAR.%jobid%.stderr',0,'NO'),(71,'oarsub -l host=7,walltime=3 sleep 3600',NULL,NULL,'PASSIVE','caigang:','Waiting','None','','','neyron','default','','sleep 3600',NULL,'default','desktop_computing = \'NO\'','/home/neyron',1224778681,0,0,NULL,'NO',NULL,0,0,12,'OAR.%jobid%.stdout','OAR.%jobid%.stderr',0,'NO'),(72,'oarsub -l host=41,walltime=8 sleep 3600',NULL,NULL,'PASSIVE','caigang:','Waiting','None','','','neyron','default','','sleep 3600',NULL,'default','desktop_computing = \'NO\'','/home/neyron',1224778682,0,0,NULL,'NO',NULL,0,0,12,'OAR.%jobid%.stdout','OAR.%jobid%.stderr',0,'NO'),(73,'oarsub -l host=76,walltime=4 sleep 3600',NULL,NULL,'PASSIVE','caigang:','Waiting','None','','','neyron','default','','sleep 3600',NULL,'default','desktop_computing = \'NO\'','/home/neyron',1224778683,0,0,NULL,'NO',NULL,0,0,12,'OAR.%jobid%.stdout','OAR.%jobid%.stderr',0,'NO'),(74,'oarsub -l host=46,walltime=10 sleep 3600',NULL,NULL,'PASSIVE','caigang:','Waiting','None','','','neyron','default','','sleep 3600',NULL,'default','desktop_computing = \'NO\'','/home/neyron',1224778683,0,0,NULL,'NO',NULL,0,0,12,'OAR.%jobid%.stdout','OAR.%jobid%.stderr',0,'NO'),(75,'oarsub -l host=81,walltime=5 sleep 3600',NULL,NULL,'PASSIVE','caigang:','Waiting','None','','','neyron','default','','sleep 3600',NULL,'default','desktop_computing = \'NO\'','/home/neyron',1224778684,0,0,NULL,'NO',NULL,0,0,12,'OAR.%jobid%.stdout','OAR.%jobid%.stderr',0,'NO'),(76,'oarsub -l host=52,walltime=1 sleep 3600',NULL,NULL,'PASSIVE','caigang:','Waiting','None','','','neyron','default','','sleep 3600',NULL,'default','desktop_computing = \'NO\'','/home/neyron',1224778684,0,0,NULL,'NO',NULL,0,0,12,'OAR.%jobid%.stdout','OAR.%jobid%.stderr',0,'NO'),(77,'oarsub -l host=86,walltime=7 sleep 3600',NULL,NULL,'PASSIVE','caigang:','Waiting','None','','','neyron','default','','sleep 3600',NULL,'default','desktop_computing = \'NO\'','/home/neyron',1224778685,0,0,NULL,'NO',NULL,0,0,12,'OAR.%jobid%.stdout','OAR.%jobid%.stderr',0,'NO'),(78,'oarsub -l host=57,walltime=3 sleep 3600',NULL,NULL,'PASSIVE','caigang:','Waiting','None','','','neyron','default','','sleep 3600',NULL,'default','desktop_computing = \'NO\'','/home/neyron',1224778686,0,0,NULL,'NO',NULL,0,0,12,'OAR.%jobid%.stdout','OAR.%jobid%.stderr',0,'NO'),(79,'oarsub -l host=91,walltime=8 sleep 3600',NULL,NULL,'PASSIVE','caigang:','Waiting','None','','','neyron','default','','sleep 3600',NULL,'default','desktop_computing = \'NO\'','/home/neyron',1224778686,0,0,NULL,'NO',NULL,0,0,12,'OAR.%jobid%.stdout','OAR.%jobid%.stderr',0,'NO'),(80,'oarsub -l host=62,walltime=4 sleep 3600',NULL,NULL,'PASSIVE','caigang:','Waiting','None','','','neyron','default','','sleep 3600',NULL,'default','desktop_computing = \'NO\'','/home/neyron',1224778687,0,0,NULL,'NO',NULL,0,0,12,'OAR.%jobid%.stdout','OAR.%jobid%.stderr',0,'NO'),(81,'oarsub -l host=1,walltime=10 sleep 3600',NULL,NULL,'PASSIVE','caigang:','Waiting','None','','','neyron','default','','sleep 3600',NULL,'default','desktop_computing = \'NO\'','/home/neyron',1224778688,0,0,NULL,'NO',NULL,0,0,12,'OAR.%jobid%.stdout','OAR.%jobid%.stderr',0,'NO'),(82,'oarsub -l host=67,walltime=6 sleep 3600',NULL,NULL,'PASSIVE','caigang:','Waiting','None','','','neyron','default','','sleep 3600',NULL,'default','desktop_computing = \'NO\'','/home/neyron',1224778688,0,0,NULL,'NO',NULL,0,0,12,'OAR.%jobid%.stdout','OAR.%jobid%.stderr',0,'NO'),(83,'oarsub -l host=6,walltime=1 sleep 3600',NULL,NULL,'PASSIVE','caigang:','Waiting','None','','','neyron','default','','sleep 3600',NULL,'default','desktop_computing = \'NO\'','/home/neyron',1224778689,0,0,NULL,'NO',NULL,0,0,12,'OAR.%jobid%.stdout','OAR.%jobid%.stderr',0,'NO'),(84,'oarsub -l host=73,walltime=7 sleep 3600',NULL,NULL,'PASSIVE','caigang:','Waiting','None','','','neyron','default','','sleep 3600',NULL,'default','desktop_computing = \'NO\'','/home/neyron',1224778689,0,0,NULL,'NO',NULL,0,0,12,'OAR.%jobid%.stdout','OAR.%jobid%.stderr',0,'NO'),(85,'oarsub -l host=11,walltime=3 sleep 3600',NULL,NULL,'PASSIVE','caigang:','Waiting','None','','','neyron','default','','sleep 3600',NULL,'default','desktop_computing = \'NO\'','/home/neyron',1224778690,0,0,NULL,'NO',NULL,0,0,12,'OAR.%jobid%.stdout','OAR.%jobid%.stderr',0,'NO'),(86,'oarsub -l host=78,walltime=9 sleep 3600',NULL,NULL,'PASSIVE','caigang:','Waiting','None','','','neyron','default','','sleep 3600',NULL,'default','desktop_computing = \'NO\'','/home/neyron',1224778691,0,0,NULL,'NO',NULL,0,0,12,'OAR.%jobid%.stdout','OAR.%jobid%.stderr',0,'NO'),(87,'oarsub -l host=16,walltime=4 sleep 3600',NULL,NULL,'PASSIVE','caigang:','Waiting','None','','','neyron','default','','sleep 3600',NULL,'default','desktop_computing = \'NO\'','/home/neyron',1224778691,0,0,NULL,'NO',NULL,0,0,12,'OAR.%jobid%.stdout','OAR.%jobid%.stderr',0,'NO'),(88,'oarsub -l host=83,walltime=10 sleep 3600',NULL,NULL,'PASSIVE','caigang:','Waiting','None','','','neyron','default','','sleep 3600',NULL,'default','desktop_computing = \'NO\'','/home/neyron',1224778692,0,0,NULL,'NO',NULL,0,0,12,'OAR.%jobid%.stdout','OAR.%jobid%.stderr',0,'NO'),(89,'oarsub -l host=22,walltime=6 sleep 3600',NULL,NULL,'PASSIVE','caigang:','Waiting','None','','','neyron','default','','sleep 3600',NULL,'default','desktop_computing = \'NO\'','/home/neyron',1224778692,0,0,NULL,'NO',NULL,0,0,12,'OAR.%jobid%.stdout','OAR.%jobid%.stderr',0,'NO'),(90,'oarsub -l host=88,walltime=2 sleep 3600',NULL,NULL,'PASSIVE','caigang:','Waiting','None','','','neyron','default','','sleep 3600',NULL,'default','desktop_computing = \'NO\'','/home/neyron',1224778693,0,0,NULL,'NO',NULL,0,0,12,'OAR.%jobid%.stdout','OAR.%jobid%.stderr',0,'NO'),(91,'oarsub -l host=27,walltime=7 sleep 3600',NULL,NULL,'PASSIVE','caigang:','Waiting','None','','','neyron','default','','sleep 3600',NULL,'default','desktop_computing = \'NO\'','/home/neyron',1224778694,0,0,NULL,'NO',NULL,0,0,12,'OAR.%jobid%.stdout','OAR.%jobid%.stderr',0,'NO'),(92,'oarsub -l host=93,walltime=3 sleep 3600',NULL,NULL,'PASSIVE','caigang:','Waiting','None','','','neyron','default','','sleep 3600',NULL,'default','desktop_computing = \'NO\'','/home/neyron',1224778694,0,0,NULL,'NO',NULL,0,0,12,'OAR.%jobid%.stdout','OAR.%jobid%.stderr',0,'NO'),(93,'oarsub -l host=32,walltime=9 sleep 3600',NULL,NULL,'PASSIVE','caigang:','Waiting','None','','','neyron','default','','sleep 3600',NULL,'default','desktop_computing = \'NO\'','/home/neyron',1224778695,0,0,NULL,'NO',NULL,0,0,12,'OAR.%jobid%.stdout','OAR.%jobid%.stderr',0,'NO'),(94,'oarsub -l host=3,walltime=4 sleep 3600',NULL,NULL,'PASSIVE','caigang:','Waiting','None','','','neyron','default','','sleep 3600',NULL,'default','desktop_computing = \'NO\'','/home/neyron',1224778696,0,0,NULL,'NO',NULL,0,0,12,'OAR.%jobid%.stdout','OAR.%jobid%.stderr',0,'NO'),(95,'oarsub -l host=37,walltime=10 sleep 3600',NULL,NULL,'PASSIVE','caigang:','Waiting','None','','','neyron','default','','sleep 3600',NULL,'default','desktop_computing = \'NO\'','/home/neyron',1224778696,0,0,NULL,'NO',NULL,0,0,12,'OAR.%jobid%.stdout','OAR.%jobid%.stderr',0,'NO'),(96,'oarsub -l host=8,walltime=6 sleep 3600',NULL,NULL,'PASSIVE','caigang:','Waiting','None','','','neyron','default','','sleep 3600',NULL,'default','desktop_computing = \'NO\'','/home/neyron',1224778697,0,0,NULL,'NO',NULL,0,0,12,'OAR.%jobid%.stdout','OAR.%jobid%.stderr',0,'NO'),(97,'oarsub -l host=42,walltime=2 sleep 3600',NULL,NULL,'PASSIVE','caigang:','Waiting','None','','','neyron','default','','sleep 3600',NULL,'default','desktop_computing = \'NO\'','/home/neyron',1224778697,0,0,NULL,'NO',NULL,0,0,12,'OAR.%jobid%.stdout','OAR.%jobid%.stderr',0,'NO'),(98,'oarsub -l host=77,walltime=7 sleep 3600',NULL,NULL,'PASSIVE','caigang:','Waiting','None','','','neyron','default','','sleep 3600',NULL,'default','desktop_computing = \'NO\'','/home/neyron',1224778698,0,0,NULL,'NO',NULL,0,0,12,'OAR.%jobid%.stdout','OAR.%jobid%.stderr',0,'NO'),(99,'oarsub -l host=48,walltime=3 sleep 3600',NULL,NULL,'PASSIVE','caigang:','Waiting','None','','','neyron','default','','sleep 3600',NULL,'default','desktop_computing = \'NO\'','/home/neyron',1224778699,0,0,NULL,'NO',NULL,0,0,12,'OAR.%jobid%.stdout','OAR.%jobid%.stderr',0,'NO'),(100,'oarsub -l host=82,walltime=9 sleep 3600',NULL,NULL,'PASSIVE','caigang:','Waiting','None','','','neyron','default','','sleep 3600',NULL,'default','desktop_computing = \'NO\'','/home/neyron',1224778699,0,0,NULL,'NO',NULL,0,0,12,'OAR.%jobid%.stdout','OAR.%jobid%.stderr',0,'NO'),(101,'oarsub -l host=53,walltime=5 sleep 3600',NULL,NULL,'PASSIVE','caigang:','Waiting','None','','','neyron','default','','sleep 3600',NULL,'default','desktop_computing = \'NO\'','/home/neyron',1224778700,0,0,NULL,'NO',NULL,0,0,12,'OAR.%jobid%.stdout','OAR.%jobid%.stderr',0,'NO'); /*!40000 ALTER TABLE `jobs` ENABLE KEYS */; UNLOCK TABLES; -- -- Table structure for table `moldable_job_descriptions` -- DROP TABLE IF EXISTS `moldable_job_descriptions`; SET @saved_cs_client = @@character_set_client; SET character_set_client = utf8; CREATE TABLE `moldable_job_descriptions` ( `moldable_id` int(10) unsigned NOT NULL auto_increment, `moldable_job_id` int(10) unsigned NOT NULL, `moldable_walltime` int(10) unsigned NOT NULL, `moldable_index` enum('CURRENT','LOG') NOT NULL default 'CURRENT', PRIMARY KEY (`moldable_id`), KEY `job` (`moldable_job_id`), KEY `log` (`moldable_index`) ) ENGINE=MyISAM AUTO_INCREMENT=102 DEFAULT CHARSET=latin1; SET character_set_client = @saved_cs_client; -- -- Dumping data for table `moldable_job_descriptions` -- LOCK TABLES `moldable_job_descriptions` WRITE; /*!40000 ALTER TABLE `moldable_job_descriptions` DISABLE KEYS */; INSERT INTO `moldable_job_descriptions` VALUES (1,1,14400,'CURRENT'),(2,2,32400,'CURRENT'),(3,3,18000,'CURRENT'),(4,4,36000,'CURRENT'),(5,5,21600,'CURRENT'),(6,6,7200,'CURRENT'),(7,7,28800,'CURRENT'),(8,8,10800,'CURRENT'),(9,9,32400,'CURRENT'),(10,10,18000,'CURRENT'),(11,11,3600,'CURRENT'),(12,12,21600,'CURRENT'),(13,13,7200,'CURRENT'),(14,14,28800,'CURRENT'),(15,15,14400,'CURRENT'),(16,16,32400,'CURRENT'),(17,17,18000,'CURRENT'),(18,18,3600,'CURRENT'),(19,19,21600,'CURRENT'),(20,20,7200,'CURRENT'),(21,21,28800,'CURRENT'),(22,22,14400,'CURRENT'),(23,23,32400,'CURRENT'),(24,24,18000,'CURRENT'),(25,25,3600,'CURRENT'),(26,26,25200,'CURRENT'),(27,27,7200,'CURRENT'),(28,28,14400,'CURRENT'),(29,29,36000,'CURRENT'),(30,30,18000,'CURRENT'),(31,31,3600,'CURRENT'),(32,32,25200,'CURRENT'),(33,33,18000,'CURRENT'),(34,34,36000,'CURRENT'),(35,35,21600,'CURRENT'),(36,36,7200,'CURRENT'),(37,37,25200,'CURRENT'),(38,38,10800,'CURRENT'),(39,39,32400,'CURRENT'),(40,40,18000,'CURRENT'),(41,41,36000,'CURRENT'),(42,42,21600,'CURRENT'),(43,43,7200,'CURRENT'),(44,44,28800,'CURRENT'),(45,45,10800,'CURRENT'),(46,46,32400,'CURRENT'),(47,47,18000,'CURRENT'),(48,48,3600,'CURRENT'),(49,49,21600,'CURRENT'),(50,50,7200,'CURRENT'),(51,51,28800,'CURRENT'),(52,52,14400,'CURRENT'),(53,53,32400,'CURRENT'),(54,54,18000,'CURRENT'),(55,55,3600,'CURRENT'),(56,56,21600,'CURRENT'),(57,57,7200,'CURRENT'),(58,58,28800,'CURRENT'),(59,59,14400,'CURRENT'),(60,60,32400,'CURRENT'),(61,61,18000,'CURRENT'),(62,62,3600,'CURRENT'),(63,63,25200,'CURRENT'),(64,64,7200,'CURRENT'),(65,65,28800,'CURRENT'),(66,66,14400,'CURRENT'),(67,67,36000,'CURRENT'),(68,68,18000,'CURRENT'),(69,69,3600,'CURRENT'),(70,70,25200,'CURRENT'),(71,71,10800,'CURRENT'),(72,72,28800,'CURRENT'),(73,73,14400,'CURRENT'),(74,74,36000,'CURRENT'),(75,75,18000,'CURRENT'),(76,76,3600,'CURRENT'),(77,77,25200,'CURRENT'),(78,78,10800,'CURRENT'),(79,79,28800,'CURRENT'),(80,80,14400,'CURRENT'),(81,81,36000,'CURRENT'),(82,82,21600,'CURRENT'),(83,83,3600,'CURRENT'),(84,84,25200,'CURRENT'),(85,85,10800,'CURRENT'),(86,86,32400,'CURRENT'),(87,87,14400,'CURRENT'),(88,88,36000,'CURRENT'),(89,89,21600,'CURRENT'),(90,90,7200,'CURRENT'),(91,91,25200,'CURRENT'),(92,92,10800,'CURRENT'),(93,93,32400,'CURRENT'),(94,94,14400,'CURRENT'),(95,95,36000,'CURRENT'),(96,96,21600,'CURRENT'),(97,97,7200,'CURRENT'),(98,98,25200,'CURRENT'),(99,99,10800,'CURRENT'),(100,100,32400,'CURRENT'),(101,101,18000,'CURRENT'); /*!40000 ALTER TABLE `moldable_job_descriptions` ENABLE KEYS */; UNLOCK TABLES; -- -- Table structure for table `queues` -- DROP TABLE IF EXISTS `queues`; SET @saved_cs_client = @@character_set_client; SET character_set_client = utf8; CREATE TABLE `queues` ( `queue_name` varchar(100) NOT NULL, `priority` int(10) unsigned NOT NULL, `scheduler_policy` varchar(100) NOT NULL, `state` enum('Active','notActive') NOT NULL default 'Active', PRIMARY KEY (`queue_name`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1; SET character_set_client = @saved_cs_client; -- -- Dumping data for table `queues` -- LOCK TABLES `queues` WRITE; /*!40000 ALTER TABLE `queues` DISABLE KEYS */; INSERT INTO `queues` VALUES ('admin',10,'oar_sched_gantt_with_timesharing','Active'),('default',2,'oar_sched_gantt_with_timesharing','Active'),('besteffort',0,'oar_sched_gantt_with_timesharing','Active'); /*!40000 ALTER TABLE `queues` ENABLE KEYS */; UNLOCK TABLES; -- -- Table structure for table `resource_logs` -- DROP TABLE IF EXISTS `resource_logs`; SET @saved_cs_client = @@character_set_client; SET character_set_client = utf8; CREATE TABLE `resource_logs` ( `resource_log_id` int(10) unsigned NOT NULL auto_increment, `resource_id` int(10) unsigned NOT NULL, `attribute` varchar(255) NOT NULL, `value` varchar(255) NOT NULL, `date_start` int(10) unsigned NOT NULL, `date_stop` int(10) unsigned default '0', `finaud_decision` enum('YES','NO') NOT NULL default 'NO', PRIMARY KEY (`resource_log_id`), KEY `resource` (`resource_id`), KEY `attribute` (`attribute`), KEY `finaud` (`finaud_decision`), KEY `val` (`value`) ) ENGINE=MyISAM AUTO_INCREMENT=2305 DEFAULT CHARSET=latin1; SET character_set_client = @saved_cs_client; -- -- Dumping data for table `resource_logs` -- LOCK TABLES `resource_logs` WRITE; /*!40000 ALTER TABLE `resource_logs` DISABLE KEYS */; INSERT INTO `resource_logs` VALUES (1,1,'state','Alive',1224778461,0,'NO'),(2,1,'core ','1',1224778461,0,'NO'),(3,1,'cpu ','1',1224778461,0,'NO'),(4,1,'host ','node-1',1224778461,0,'NO'),(5,1,'cpuset','0',1224778461,0,'NO'),(6,1,'network_address','127.0.2.1',1224778461,0,'NO'),(7,2,'state','Alive',1224778461,0,'NO'),(8,2,'core ','2',1224778461,0,'NO'),(9,2,'cpu ','1',1224778461,0,'NO'),(10,2,'host ','node-1',1224778461,0,'NO'),(11,2,'cpuset','1',1224778461,0,'NO'),(12,2,'network_address','127.0.2.1',1224778461,0,'NO'),(13,3,'state','Alive',1224778462,0,'NO'),(14,3,'core ','3',1224778462,0,'NO'),(15,3,'cpu ','2',1224778462,0,'NO'),(16,3,'host ','node-1',1224778462,0,'NO'),(17,3,'cpuset','2',1224778462,0,'NO'),(18,3,'network_address','127.0.2.1',1224778462,0,'NO'),(19,4,'state','Alive',1224778462,0,'NO'),(20,4,'core ','4',1224778462,0,'NO'),(21,4,'cpu ','2',1224778462,0,'NO'),(22,4,'host ','node-1',1224778462,0,'NO'),(23,4,'cpuset','3',1224778462,0,'NO'),(24,4,'network_address','127.0.2.1',1224778462,0,'NO'),(25,5,'state','Alive',1224778462,0,'NO'),(26,5,'core ','5',1224778462,0,'NO'),(27,5,'cpu ','3',1224778462,0,'NO'),(28,5,'host ','node-2',1224778462,0,'NO'),(29,5,'cpuset','0',1224778462,0,'NO'),(30,5,'network_address','127.0.2.2',1224778462,0,'NO'),(31,6,'state','Alive',1224778462,0,'NO'),(32,6,'core ','6',1224778462,0,'NO'),(33,6,'cpu ','3',1224778462,0,'NO'),(34,6,'host ','node-2',1224778462,0,'NO'),(35,6,'cpuset','1',1224778462,0,'NO'),(36,6,'network_address','127.0.2.2',1224778462,0,'NO'),(37,7,'state','Alive',1224778462,0,'NO'),(38,7,'core ','7',1224778462,0,'NO'),(39,7,'cpu ','4',1224778462,0,'NO'),(40,7,'host ','node-2',1224778462,0,'NO'),(41,7,'cpuset','2',1224778462,0,'NO'),(42,7,'network_address','127.0.2.2',1224778462,0,'NO'),(43,8,'state','Alive',1224778462,0,'NO'),(44,8,'core ','8',1224778462,0,'NO'),(45,8,'cpu ','4',1224778462,0,'NO'),(46,8,'host ','node-2',1224778462,0,'NO'),(47,8,'cpuset','3',1224778462,0,'NO'),(48,8,'network_address','127.0.2.2',1224778462,0,'NO'),(49,9,'state','Alive',1224778463,0,'NO'),(50,9,'core ','9',1224778463,0,'NO'),(51,9,'cpu ','5',1224778463,0,'NO'),(52,9,'host ','node-3',1224778463,0,'NO'),(53,9,'cpuset','0',1224778463,0,'NO'),(54,9,'network_address','127.0.2.3',1224778463,0,'NO'),(55,10,'state','Alive',1224778463,0,'NO'),(56,10,'core ','10',1224778463,0,'NO'),(57,10,'cpu ','5',1224778463,0,'NO'),(58,10,'host ','node-3',1224778463,0,'NO'),(59,10,'cpuset','1',1224778463,0,'NO'),(60,10,'network_address','127.0.2.3',1224778463,0,'NO'),(61,11,'state','Alive',1224778463,0,'NO'),(62,11,'core ','11',1224778463,0,'NO'),(63,11,'cpu ','6',1224778463,0,'NO'),(64,11,'host ','node-3',1224778463,0,'NO'),(65,11,'cpuset','2',1224778463,0,'NO'),(66,11,'network_address','127.0.2.3',1224778463,0,'NO'),(67,12,'state','Alive',1224778463,0,'NO'),(68,12,'core ','12',1224778463,0,'NO'),(69,12,'cpu ','6',1224778463,0,'NO'),(70,12,'host ','node-3',1224778463,0,'NO'),(71,12,'cpuset','3',1224778463,0,'NO'),(72,12,'network_address','127.0.2.3',1224778463,0,'NO'),(73,13,'state','Alive',1224778463,0,'NO'),(74,13,'core ','13',1224778463,0,'NO'),(75,13,'cpu ','7',1224778463,0,'NO'),(76,13,'host ','node-4',1224778463,0,'NO'),(77,13,'cpuset','0',1224778463,0,'NO'),(78,13,'network_address','127.0.2.4',1224778463,0,'NO'),(79,14,'state','Alive',1224778464,0,'NO'),(80,14,'core ','14',1224778464,0,'NO'),(81,14,'cpu ','7',1224778464,0,'NO'),(82,14,'host ','node-4',1224778464,0,'NO'),(83,14,'cpuset','1',1224778464,0,'NO'),(84,14,'network_address','127.0.2.4',1224778464,0,'NO'),(85,15,'state','Alive',1224778464,0,'NO'),(86,15,'core ','15',1224778464,0,'NO'),(87,15,'cpu ','8',1224778464,0,'NO'),(88,15,'host ','node-4',1224778464,0,'NO'),(89,15,'cpuset','2',1224778464,0,'NO'),(90,15,'network_address','127.0.2.4',1224778464,0,'NO'),(91,16,'state','Alive',1224778464,0,'NO'),(92,16,'core ','16',1224778464,0,'NO'),(93,16,'cpu ','8',1224778464,0,'NO'),(94,16,'host ','node-4',1224778464,0,'NO'),(95,16,'cpuset','3',1224778464,0,'NO'),(96,16,'network_address','127.0.2.4',1224778464,0,'NO'),(97,17,'state','Alive',1224778464,0,'NO'),(98,17,'core ','17',1224778464,0,'NO'),(99,17,'cpu ','9',1224778464,0,'NO'),(100,17,'host ','node-5',1224778464,0,'NO'),(101,17,'cpuset','0',1224778464,0,'NO'),(102,17,'network_address','127.0.2.5',1224778464,0,'NO'),(103,18,'state','Alive',1224778464,0,'NO'),(104,18,'core ','18',1224778464,0,'NO'),(105,18,'cpu ','9',1224778464,0,'NO'),(106,18,'host ','node-5',1224778464,0,'NO'),(107,18,'cpuset','1',1224778464,0,'NO'),(108,18,'network_address','127.0.2.5',1224778464,0,'NO'),(109,19,'state','Alive',1224778465,0,'NO'),(110,19,'core ','19',1224778465,0,'NO'),(111,19,'cpu ','10',1224778465,0,'NO'),(112,19,'host ','node-5',1224778465,0,'NO'),(113,19,'cpuset','2',1224778465,0,'NO'),(114,19,'network_address','127.0.2.5',1224778465,0,'NO'),(115,20,'state','Alive',1224778465,0,'NO'),(116,20,'core ','20',1224778465,0,'NO'),(117,20,'cpu ','10',1224778465,0,'NO'),(118,20,'host ','node-5',1224778465,0,'NO'),(119,20,'cpuset','3',1224778465,0,'NO'),(120,20,'network_address','127.0.2.5',1224778465,0,'NO'),(121,21,'state','Alive',1224778465,0,'NO'),(122,21,'core ','21',1224778465,0,'NO'),(123,21,'cpu ','11',1224778465,0,'NO'),(124,21,'host ','node-6',1224778465,0,'NO'),(125,21,'cpuset','0',1224778465,0,'NO'),(126,21,'network_address','127.0.2.6',1224778465,0,'NO'),(127,22,'state','Alive',1224778465,0,'NO'),(128,22,'core ','22',1224778465,0,'NO'),(129,22,'cpu ','11',1224778465,0,'NO'),(130,22,'host ','node-6',1224778465,0,'NO'),(131,22,'cpuset','1',1224778465,0,'NO'),(132,22,'network_address','127.0.2.6',1224778465,0,'NO'),(133,23,'state','Alive',1224778465,0,'NO'),(134,23,'core ','23',1224778465,0,'NO'),(135,23,'cpu ','12',1224778465,0,'NO'),(136,23,'host ','node-6',1224778465,0,'NO'),(137,23,'cpuset','2',1224778465,0,'NO'),(138,23,'network_address','127.0.2.6',1224778465,0,'NO'),(139,24,'state','Alive',1224778466,0,'NO'),(140,24,'core ','24',1224778466,0,'NO'),(141,24,'cpu ','12',1224778466,0,'NO'),(142,24,'host ','node-6',1224778466,0,'NO'),(143,24,'cpuset','3',1224778466,0,'NO'),(144,24,'network_address','127.0.2.6',1224778466,0,'NO'),(145,25,'state','Alive',1224778466,0,'NO'),(146,25,'core ','25',1224778466,0,'NO'),(147,25,'cpu ','13',1224778466,0,'NO'),(148,25,'host ','node-7',1224778466,0,'NO'),(149,25,'cpuset','0',1224778466,0,'NO'),(150,25,'network_address','127.0.2.7',1224778466,0,'NO'),(151,26,'state','Alive',1224778466,0,'NO'),(152,26,'core ','26',1224778466,0,'NO'),(153,26,'cpu ','13',1224778466,0,'NO'),(154,26,'host ','node-7',1224778466,0,'NO'),(155,26,'cpuset','1',1224778466,0,'NO'),(156,26,'network_address','127.0.2.7',1224778466,0,'NO'),(157,27,'state','Alive',1224778466,0,'NO'),(158,27,'core ','27',1224778466,0,'NO'),(159,27,'cpu ','14',1224778466,0,'NO'),(160,27,'host ','node-7',1224778466,0,'NO'),(161,27,'cpuset','2',1224778466,0,'NO'),(162,27,'network_address','127.0.2.7',1224778466,0,'NO'),(163,28,'state','Alive',1224778466,0,'NO'),(164,28,'core ','28',1224778466,0,'NO'),(165,28,'cpu ','14',1224778466,0,'NO'),(166,28,'host ','node-7',1224778466,0,'NO'),(167,28,'cpuset','3',1224778466,0,'NO'),(168,28,'network_address','127.0.2.7',1224778466,0,'NO'),(169,29,'state','Alive',1224778466,0,'NO'),(170,29,'core ','29',1224778466,0,'NO'),(171,29,'cpu ','15',1224778466,0,'NO'),(172,29,'host ','node-8',1224778466,0,'NO'),(173,29,'cpuset','0',1224778466,0,'NO'),(174,29,'network_address','127.0.2.8',1224778466,0,'NO'),(175,30,'state','Alive',1224778467,0,'NO'),(176,30,'core ','30',1224778467,0,'NO'),(177,30,'cpu ','15',1224778467,0,'NO'),(178,30,'host ','node-8',1224778467,0,'NO'),(179,30,'cpuset','1',1224778467,0,'NO'),(180,30,'network_address','127.0.2.8',1224778467,0,'NO'),(181,31,'state','Alive',1224778467,0,'NO'),(182,31,'core ','31',1224778467,0,'NO'),(183,31,'cpu ','16',1224778467,0,'NO'),(184,31,'host ','node-8',1224778467,0,'NO'),(185,31,'cpuset','2',1224778467,0,'NO'),(186,31,'network_address','127.0.2.8',1224778467,0,'NO'),(187,32,'state','Alive',1224778467,0,'NO'),(188,32,'core ','32',1224778467,0,'NO'),(189,32,'cpu ','16',1224778467,0,'NO'),(190,32,'host ','node-8',1224778467,0,'NO'),(191,32,'cpuset','3',1224778467,0,'NO'),(192,32,'network_address','127.0.2.8',1224778467,0,'NO'),(193,33,'state','Alive',1224778467,0,'NO'),(194,33,'core ','33',1224778467,0,'NO'),(195,33,'cpu ','17',1224778467,0,'NO'),(196,33,'host ','node-9',1224778467,0,'NO'),(197,33,'cpuset','0',1224778467,0,'NO'),(198,33,'network_address','127.0.2.9',1224778467,0,'NO'),(199,34,'state','Alive',1224778467,0,'NO'),(200,34,'core ','34',1224778467,0,'NO'),(201,34,'cpu ','17',1224778467,0,'NO'),(202,34,'host ','node-9',1224778467,0,'NO'),(203,34,'cpuset','1',1224778467,0,'NO'),(204,34,'network_address','127.0.2.9',1224778467,0,'NO'),(205,35,'state','Alive',1224778468,0,'NO'),(206,35,'core ','35',1224778468,0,'NO'),(207,35,'cpu ','18',1224778468,0,'NO'),(208,35,'host ','node-9',1224778468,0,'NO'),(209,35,'cpuset','2',1224778468,0,'NO'),(210,35,'network_address','127.0.2.9',1224778468,0,'NO'),(211,36,'state','Alive',1224778468,0,'NO'),(212,36,'core ','36',1224778468,0,'NO'),(213,36,'cpu ','18',1224778468,0,'NO'),(214,36,'host ','node-9',1224778468,0,'NO'),(215,36,'cpuset','3',1224778468,0,'NO'),(216,36,'network_address','127.0.2.9',1224778468,0,'NO'),(217,37,'state','Alive',1224778468,0,'NO'),(218,37,'core ','37',1224778468,0,'NO'),(219,37,'cpu ','19',1224778468,0,'NO'),(220,37,'host ','node-10',1224778468,0,'NO'),(221,37,'cpuset','0',1224778468,0,'NO'),(222,37,'network_address','127.0.2.10',1224778468,0,'NO'),(223,38,'state','Alive',1224778468,0,'NO'),(224,38,'core ','38',1224778468,0,'NO'),(225,38,'cpu ','19',1224778468,0,'NO'),(226,38,'host ','node-10',1224778468,0,'NO'),(227,38,'cpuset','1',1224778468,0,'NO'),(228,38,'network_address','127.0.2.10',1224778468,0,'NO'),(229,39,'state','Alive',1224778468,0,'NO'),(230,39,'core ','39',1224778468,0,'NO'),(231,39,'cpu ','20',1224778468,0,'NO'),(232,39,'host ','node-10',1224778468,0,'NO'),(233,39,'cpuset','2',1224778468,0,'NO'),(234,39,'network_address','127.0.2.10',1224778468,0,'NO'),(235,40,'state','Alive',1224778469,0,'NO'),(236,40,'core ','40',1224778469,0,'NO'),(237,40,'cpu ','20',1224778469,0,'NO'),(238,40,'host ','node-10',1224778469,0,'NO'),(239,40,'cpuset','3',1224778469,0,'NO'),(240,40,'network_address','127.0.2.10',1224778469,0,'NO'),(241,41,'state','Alive',1224778469,0,'NO'),(242,41,'core ','41',1224778469,0,'NO'),(243,41,'cpu ','21',1224778469,0,'NO'),(244,41,'host ','node-11',1224778469,0,'NO'),(245,41,'cpuset','0',1224778469,0,'NO'),(246,41,'network_address','127.0.2.11',1224778469,0,'NO'),(247,42,'state','Alive',1224778469,0,'NO'),(248,42,'core ','42',1224778469,0,'NO'),(249,42,'cpu ','21',1224778469,0,'NO'),(250,42,'host ','node-11',1224778469,0,'NO'),(251,42,'cpuset','1',1224778469,0,'NO'),(252,42,'network_address','127.0.2.11',1224778469,0,'NO'),(253,43,'state','Alive',1224778469,0,'NO'),(254,43,'core ','43',1224778469,0,'NO'),(255,43,'cpu ','22',1224778469,0,'NO'),(256,43,'host ','node-11',1224778469,0,'NO'),(257,43,'cpuset','2',1224778469,0,'NO'),(258,43,'network_address','127.0.2.11',1224778469,0,'NO'),(259,44,'state','Alive',1224778469,0,'NO'),(260,44,'core ','44',1224778469,0,'NO'),(261,44,'cpu ','22',1224778469,0,'NO'),(262,44,'host ','node-11',1224778469,0,'NO'),(263,44,'cpuset','3',1224778469,0,'NO'),(264,44,'network_address','127.0.2.11',1224778469,0,'NO'),(265,45,'state','Alive',1224778470,0,'NO'),(266,45,'core ','45',1224778470,0,'NO'),(267,45,'cpu ','23',1224778470,0,'NO'),(268,45,'host ','node-12',1224778470,0,'NO'),(269,45,'cpuset','0',1224778470,0,'NO'),(270,45,'network_address','127.0.2.12',1224778470,0,'NO'),(271,46,'state','Alive',1224778470,0,'NO'),(272,46,'core ','46',1224778470,0,'NO'),(273,46,'cpu ','23',1224778470,0,'NO'),(274,46,'host ','node-12',1224778470,0,'NO'),(275,46,'cpuset','1',1224778470,0,'NO'),(276,46,'network_address','127.0.2.12',1224778470,0,'NO'),(277,47,'state','Alive',1224778470,0,'NO'),(278,47,'core ','47',1224778470,0,'NO'),(279,47,'cpu ','24',1224778470,0,'NO'),(280,47,'host ','node-12',1224778470,0,'NO'),(281,47,'cpuset','2',1224778470,0,'NO'),(282,47,'network_address','127.0.2.12',1224778470,0,'NO'),(283,48,'state','Alive',1224778470,0,'NO'),(284,48,'core ','48',1224778470,0,'NO'),(285,48,'cpu ','24',1224778470,0,'NO'),(286,48,'host ','node-12',1224778470,0,'NO'),(287,48,'cpuset','3',1224778470,0,'NO'),(288,48,'network_address','127.0.2.12',1224778470,0,'NO'),(289,49,'state','Alive',1224778471,0,'NO'),(290,49,'core ','49',1224778471,0,'NO'),(291,49,'cpu ','25',1224778471,0,'NO'),(292,49,'host ','node-13',1224778471,0,'NO'),(293,49,'cpuset','0',1224778471,0,'NO'),(294,49,'network_address','127.0.2.13',1224778471,0,'NO'),(295,50,'state','Alive',1224778471,0,'NO'),(296,50,'core ','50',1224778471,0,'NO'),(297,50,'cpu ','25',1224778471,0,'NO'),(298,50,'host ','node-13',1224778471,0,'NO'),(299,50,'cpuset','1',1224778471,0,'NO'),(300,50,'network_address','127.0.2.13',1224778471,0,'NO'),(301,51,'state','Alive',1224778471,0,'NO'),(302,51,'core ','51',1224778471,0,'NO'),(303,51,'cpu ','26',1224778471,0,'NO'),(304,51,'host ','node-13',1224778471,0,'NO'),(305,51,'cpuset','2',1224778471,0,'NO'),(306,51,'network_address','127.0.2.13',1224778471,0,'NO'),(307,52,'state','Alive',1224778472,0,'NO'),(308,52,'core ','52',1224778472,0,'NO'),(309,52,'cpu ','26',1224778472,0,'NO'),(310,52,'host ','node-13',1224778472,0,'NO'),(311,52,'cpuset','3',1224778472,0,'NO'),(312,52,'network_address','127.0.2.13',1224778472,0,'NO'),(313,53,'state','Alive',1224778472,0,'NO'),(314,53,'core ','53',1224778472,0,'NO'),(315,53,'cpu ','27',1224778472,0,'NO'),(316,53,'host ','node-14',1224778472,0,'NO'),(317,53,'cpuset','0',1224778472,0,'NO'),(318,53,'network_address','127.0.2.14',1224778472,0,'NO'),(319,54,'state','Alive',1224778472,0,'NO'),(320,54,'core ','54',1224778472,0,'NO'),(321,54,'cpu ','27',1224778472,0,'NO'),(322,54,'host ','node-14',1224778472,0,'NO'),(323,54,'cpuset','1',1224778472,0,'NO'),(324,54,'network_address','127.0.2.14',1224778472,0,'NO'),(325,55,'state','Alive',1224778472,0,'NO'),(326,55,'core ','55',1224778472,0,'NO'),(327,55,'cpu ','28',1224778472,0,'NO'),(328,55,'host ','node-14',1224778472,0,'NO'),(329,55,'cpuset','2',1224778472,0,'NO'),(330,55,'network_address','127.0.2.14',1224778472,0,'NO'),(331,56,'state','Alive',1224778472,0,'NO'),(332,56,'core ','56',1224778472,0,'NO'),(333,56,'cpu ','28',1224778472,0,'NO'),(334,56,'host ','node-14',1224778472,0,'NO'),(335,56,'cpuset','3',1224778472,0,'NO'),(336,56,'network_address','127.0.2.14',1224778472,0,'NO'),(337,57,'state','Alive',1224778473,0,'NO'),(338,57,'core ','57',1224778473,0,'NO'),(339,57,'cpu ','29',1224778473,0,'NO'),(340,57,'host ','node-15',1224778473,0,'NO'),(341,57,'cpuset','0',1224778473,0,'NO'),(342,57,'network_address','127.0.2.15',1224778473,0,'NO'),(343,58,'state','Alive',1224778473,0,'NO'),(344,58,'core ','58',1224778473,0,'NO'),(345,58,'cpu ','29',1224778473,0,'NO'),(346,58,'host ','node-15',1224778473,0,'NO'),(347,58,'cpuset','1',1224778473,0,'NO'),(348,58,'network_address','127.0.2.15',1224778473,0,'NO'),(349,59,'state','Alive',1224778473,0,'NO'),(350,59,'core ','59',1224778473,0,'NO'),(351,59,'cpu ','30',1224778473,0,'NO'),(352,59,'host ','node-15',1224778473,0,'NO'),(353,59,'cpuset','2',1224778473,0,'NO'),(354,59,'network_address','127.0.2.15',1224778473,0,'NO'),(355,60,'state','Alive',1224778473,0,'NO'),(356,60,'core ','60',1224778473,0,'NO'),(357,60,'cpu ','30',1224778473,0,'NO'),(358,60,'host ','node-15',1224778473,0,'NO'),(359,60,'cpuset','3',1224778473,0,'NO'),(360,60,'network_address','127.0.2.15',1224778473,0,'NO'),(361,61,'state','Alive',1224778473,0,'NO'),(362,61,'core ','61',1224778473,0,'NO'),(363,61,'cpu ','31',1224778473,0,'NO'),(364,61,'host ','node-16',1224778473,0,'NO'),(365,61,'cpuset','0',1224778473,0,'NO'),(366,61,'network_address','127.0.2.16',1224778473,0,'NO'),(367,62,'state','Alive',1224778473,0,'NO'),(368,62,'core ','62',1224778473,0,'NO'),(369,62,'cpu ','31',1224778473,0,'NO'),(370,62,'host ','node-16',1224778473,0,'NO'),(371,62,'cpuset','1',1224778473,0,'NO'),(372,62,'network_address','127.0.2.16',1224778473,0,'NO'),(373,63,'state','Alive',1224778474,0,'NO'),(374,63,'core ','63',1224778474,0,'NO'),(375,63,'cpu ','32',1224778474,0,'NO'),(376,63,'host ','node-16',1224778474,0,'NO'),(377,63,'cpuset','2',1224778474,0,'NO'),(378,63,'network_address','127.0.2.16',1224778474,0,'NO'),(379,64,'state','Alive',1224778474,0,'NO'),(380,64,'core ','64',1224778474,0,'NO'),(381,64,'cpu ','32',1224778474,0,'NO'),(382,64,'host ','node-16',1224778474,0,'NO'),(383,64,'cpuset','3',1224778474,0,'NO'),(384,64,'network_address','127.0.2.16',1224778474,0,'NO'),(385,65,'state','Alive',1224778474,0,'NO'),(386,65,'core ','65',1224778474,0,'NO'),(387,65,'cpu ','33',1224778474,0,'NO'),(388,65,'host ','node-17',1224778474,0,'NO'),(389,65,'cpuset','0',1224778474,0,'NO'),(390,65,'network_address','127.0.2.17',1224778474,0,'NO'),(391,66,'state','Alive',1224778474,0,'NO'),(392,66,'core ','66',1224778474,0,'NO'),(393,66,'cpu ','33',1224778474,0,'NO'),(394,66,'host ','node-17',1224778474,0,'NO'),(395,66,'cpuset','1',1224778474,0,'NO'),(396,66,'network_address','127.0.2.17',1224778474,0,'NO'),(397,67,'state','Alive',1224778474,0,'NO'),(398,67,'core ','67',1224778474,0,'NO'),(399,67,'cpu ','34',1224778474,0,'NO'),(400,67,'host ','node-17',1224778474,0,'NO'),(401,67,'cpuset','2',1224778474,0,'NO'),(402,67,'network_address','127.0.2.17',1224778474,0,'NO'),(403,68,'state','Alive',1224778475,0,'NO'),(404,68,'core ','68',1224778475,0,'NO'),(405,68,'cpu ','34',1224778475,0,'NO'),(406,68,'host ','node-17',1224778475,0,'NO'),(407,68,'cpuset','3',1224778475,0,'NO'),(408,68,'network_address','127.0.2.17',1224778475,0,'NO'),(409,69,'state','Alive',1224778475,0,'NO'),(410,69,'core ','69',1224778475,0,'NO'),(411,69,'cpu ','35',1224778475,0,'NO'),(412,69,'host ','node-18',1224778475,0,'NO'),(413,69,'cpuset','0',1224778475,0,'NO'),(414,69,'network_address','127.0.2.18',1224778475,0,'NO'),(415,70,'state','Alive',1224778475,0,'NO'),(416,70,'core ','70',1224778475,0,'NO'),(417,70,'cpu ','35',1224778475,0,'NO'),(418,70,'host ','node-18',1224778475,0,'NO'),(419,70,'cpuset','1',1224778475,0,'NO'),(420,70,'network_address','127.0.2.18',1224778475,0,'NO'),(421,71,'state','Alive',1224778475,0,'NO'),(422,71,'core ','71',1224778475,0,'NO'),(423,71,'cpu ','36',1224778475,0,'NO'),(424,71,'host ','node-18',1224778475,0,'NO'),(425,71,'cpuset','2',1224778475,0,'NO'),(426,71,'network_address','127.0.2.18',1224778475,0,'NO'),(427,72,'state','Alive',1224778475,0,'NO'),(428,72,'core ','72',1224778475,0,'NO'),(429,72,'cpu ','36',1224778475,0,'NO'),(430,72,'host ','node-18',1224778475,0,'NO'),(431,72,'cpuset','3',1224778475,0,'NO'),(432,72,'network_address','127.0.2.18',1224778475,0,'NO'),(433,73,'state','Alive',1224778476,0,'NO'),(434,73,'core ','73',1224778476,0,'NO'),(435,73,'cpu ','37',1224778476,0,'NO'),(436,73,'host ','node-19',1224778476,0,'NO'),(437,73,'cpuset','0',1224778476,0,'NO'),(438,73,'network_address','127.0.2.19',1224778476,0,'NO'),(439,74,'state','Alive',1224778476,0,'NO'),(440,74,'core ','74',1224778476,0,'NO'),(441,74,'cpu ','37',1224778476,0,'NO'),(442,74,'host ','node-19',1224778476,0,'NO'),(443,74,'cpuset','1',1224778476,0,'NO'),(444,74,'network_address','127.0.2.19',1224778476,0,'NO'),(445,75,'state','Alive',1224778476,0,'NO'),(446,75,'core ','75',1224778476,0,'NO'),(447,75,'cpu ','38',1224778476,0,'NO'),(448,75,'host ','node-19',1224778476,0,'NO'),(449,75,'cpuset','2',1224778476,0,'NO'),(450,75,'network_address','127.0.2.19',1224778476,0,'NO'),(451,76,'state','Alive',1224778476,0,'NO'),(452,76,'core ','76',1224778476,0,'NO'),(453,76,'cpu ','38',1224778476,0,'NO'),(454,76,'host ','node-19',1224778476,0,'NO'),(455,76,'cpuset','3',1224778476,0,'NO'),(456,76,'network_address','127.0.2.19',1224778476,0,'NO'),(457,77,'state','Alive',1224778476,0,'NO'),(458,77,'core ','77',1224778476,0,'NO'),(459,77,'cpu ','39',1224778476,0,'NO'),(460,77,'host ','node-20',1224778476,0,'NO'),(461,77,'cpuset','0',1224778476,0,'NO'),(462,77,'network_address','127.0.2.20',1224778476,0,'NO'),(463,78,'state','Alive',1224778477,0,'NO'),(464,78,'core ','78',1224778477,0,'NO'),(465,78,'cpu ','39',1224778477,0,'NO'),(466,78,'host ','node-20',1224778477,0,'NO'),(467,78,'cpuset','1',1224778477,0,'NO'),(468,78,'network_address','127.0.2.20',1224778477,0,'NO'),(469,79,'state','Alive',1224778477,0,'NO'),(470,79,'core ','79',1224778477,0,'NO'),(471,79,'cpu ','40',1224778477,0,'NO'),(472,79,'host ','node-20',1224778477,0,'NO'),(473,79,'cpuset','2',1224778477,0,'NO'),(474,79,'network_address','127.0.2.20',1224778477,0,'NO'),(475,80,'state','Alive',1224778477,0,'NO'),(476,80,'core ','80',1224778477,0,'NO'),(477,80,'cpu ','40',1224778477,0,'NO'),(478,80,'host ','node-20',1224778477,0,'NO'),(479,80,'cpuset','3',1224778477,0,'NO'),(480,80,'network_address','127.0.2.20',1224778477,0,'NO'),(481,81,'state','Alive',1224778477,0,'NO'),(482,81,'core ','81',1224778477,0,'NO'),(483,81,'cpu ','41',1224778477,0,'NO'),(484,81,'host ','node-21',1224778477,0,'NO'),(485,81,'cpuset','0',1224778477,0,'NO'),(486,81,'network_address','127.0.2.21',1224778477,0,'NO'),(487,82,'state','Alive',1224778477,0,'NO'),(488,82,'core ','82',1224778477,0,'NO'),(489,82,'cpu ','41',1224778477,0,'NO'),(490,82,'host ','node-21',1224778477,0,'NO'),(491,82,'cpuset','1',1224778477,0,'NO'),(492,82,'network_address','127.0.2.21',1224778477,0,'NO'),(493,83,'state','Alive',1224778478,0,'NO'),(494,83,'core ','83',1224778478,0,'NO'),(495,83,'cpu ','42',1224778478,0,'NO'),(496,83,'host ','node-21',1224778478,0,'NO'),(497,83,'cpuset','2',1224778478,0,'NO'),(498,83,'network_address','127.0.2.21',1224778478,0,'NO'),(499,84,'state','Alive',1224778478,0,'NO'),(500,84,'core ','84',1224778478,0,'NO'),(501,84,'cpu ','42',1224778478,0,'NO'),(502,84,'host ','node-21',1224778478,0,'NO'),(503,84,'cpuset','3',1224778478,0,'NO'),(504,84,'network_address','127.0.2.21',1224778478,0,'NO'),(505,85,'state','Alive',1224778478,0,'NO'),(506,85,'core ','85',1224778478,0,'NO'),(507,85,'cpu ','43',1224778478,0,'NO'),(508,85,'host ','node-22',1224778478,0,'NO'),(509,85,'cpuset','0',1224778478,0,'NO'),(510,85,'network_address','127.0.2.22',1224778478,0,'NO'),(511,86,'state','Alive',1224778478,0,'NO'),(512,86,'core ','86',1224778478,0,'NO'),(513,86,'cpu ','43',1224778478,0,'NO'),(514,86,'host ','node-22',1224778478,0,'NO'),(515,86,'cpuset','1',1224778478,0,'NO'),(516,86,'network_address','127.0.2.22',1224778478,0,'NO'),(517,87,'state','Alive',1224778478,0,'NO'),(518,87,'core ','87',1224778478,0,'NO'),(519,87,'cpu ','44',1224778478,0,'NO'),(520,87,'host ','node-22',1224778478,0,'NO'),(521,87,'cpuset','2',1224778478,0,'NO'),(522,87,'network_address','127.0.2.22',1224778478,0,'NO'),(523,88,'state','Alive',1224778478,0,'NO'),(524,88,'core ','88',1224778479,0,'NO'),(525,88,'cpu ','44',1224778479,0,'NO'),(526,88,'host ','node-22',1224778479,0,'NO'),(527,88,'cpuset','3',1224778479,0,'NO'),(528,88,'network_address','127.0.2.22',1224778479,0,'NO'),(529,89,'state','Alive',1224778479,0,'NO'),(530,89,'core ','89',1224778479,0,'NO'),(531,89,'cpu ','45',1224778479,0,'NO'),(532,89,'host ','node-23',1224778479,0,'NO'),(533,89,'cpuset','0',1224778479,0,'NO'),(534,89,'network_address','127.0.2.23',1224778479,0,'NO'),(535,90,'state','Alive',1224778479,0,'NO'),(536,90,'core ','90',1224778479,0,'NO'),(537,90,'cpu ','45',1224778479,0,'NO'),(538,90,'host ','node-23',1224778479,0,'NO'),(539,90,'cpuset','1',1224778479,0,'NO'),(540,90,'network_address','127.0.2.23',1224778479,0,'NO'),(541,91,'state','Alive',1224778479,0,'NO'),(542,91,'core ','91',1224778479,0,'NO'),(543,91,'cpu ','46',1224778479,0,'NO'),(544,91,'host ','node-23',1224778479,0,'NO'),(545,91,'cpuset','2',1224778479,0,'NO'),(546,91,'network_address','127.0.2.23',1224778479,0,'NO'),(547,92,'state','Alive',1224778479,0,'NO'),(548,92,'core ','92',1224778479,0,'NO'),(549,92,'cpu ','46',1224778479,0,'NO'),(550,92,'host ','node-23',1224778479,0,'NO'),(551,92,'cpuset','3',1224778479,0,'NO'),(552,92,'network_address','127.0.2.23',1224778479,0,'NO'),(553,93,'state','Alive',1224778479,0,'NO'),(554,93,'core ','93',1224778479,0,'NO'),(555,93,'cpu ','47',1224778479,0,'NO'),(556,93,'host ','node-24',1224778479,0,'NO'),(557,93,'cpuset','0',1224778479,0,'NO'),(558,93,'network_address','127.0.2.24',1224778479,0,'NO'),(559,94,'state','Alive',1224778480,0,'NO'),(560,94,'core ','94',1224778480,0,'NO'),(561,94,'cpu ','47',1224778480,0,'NO'),(562,94,'host ','node-24',1224778480,0,'NO'),(563,94,'cpuset','1',1224778480,0,'NO'),(564,94,'network_address','127.0.2.24',1224778480,0,'NO'),(565,95,'state','Alive',1224778480,0,'NO'),(566,95,'core ','95',1224778480,0,'NO'),(567,95,'cpu ','48',1224778480,0,'NO'),(568,95,'host ','node-24',1224778480,0,'NO'),(569,95,'cpuset','2',1224778480,0,'NO'),(570,95,'network_address','127.0.2.24',1224778480,0,'NO'),(571,96,'state','Alive',1224778480,0,'NO'),(572,96,'core ','96',1224778480,0,'NO'),(573,96,'cpu ','48',1224778480,0,'NO'),(574,96,'host ','node-24',1224778480,0,'NO'),(575,96,'cpuset','3',1224778480,0,'NO'),(576,96,'network_address','127.0.2.24',1224778480,0,'NO'),(577,97,'state','Alive',1224778480,0,'NO'),(578,97,'core ','97',1224778480,0,'NO'),(579,97,'cpu ','49',1224778480,0,'NO'),(580,97,'host ','node-25',1224778480,0,'NO'),(581,97,'cpuset','0',1224778480,0,'NO'),(582,97,'network_address','127.0.2.25',1224778480,0,'NO'),(583,98,'state','Alive',1224778480,0,'NO'),(584,98,'core ','98',1224778480,0,'NO'),(585,98,'cpu ','49',1224778480,0,'NO'),(586,98,'host ','node-25',1224778480,0,'NO'),(587,98,'cpuset','1',1224778480,0,'NO'),(588,98,'network_address','127.0.2.25',1224778480,0,'NO'),(589,99,'state','Alive',1224778481,0,'NO'),(590,99,'core ','99',1224778481,0,'NO'),(591,99,'cpu ','50',1224778481,0,'NO'),(592,99,'host ','node-25',1224778481,0,'NO'),(593,99,'cpuset','2',1224778481,0,'NO'),(594,99,'network_address','127.0.2.25',1224778481,0,'NO'),(595,100,'state','Alive',1224778481,0,'NO'),(596,100,'core ','100',1224778481,0,'NO'),(597,100,'cpu ','50',1224778481,0,'NO'),(598,100,'host ','node-25',1224778481,0,'NO'),(599,100,'cpuset','3',1224778481,0,'NO'),(600,100,'network_address','127.0.2.25',1224778481,0,'NO'),(601,101,'state','Alive',1224778481,0,'NO'),(602,101,'core ','101',1224778481,0,'NO'),(603,101,'cpu ','51',1224778481,0,'NO'),(604,101,'host ','node-26',1224778481,0,'NO'),(605,101,'cpuset','0',1224778481,0,'NO'),(606,101,'network_address','127.0.2.26',1224778481,0,'NO'),(607,102,'state','Alive',1224778481,0,'NO'),(608,102,'core ','102',1224778481,0,'NO'),(609,102,'cpu ','51',1224778481,0,'NO'),(610,102,'host ','node-26',1224778481,0,'NO'),(611,102,'cpuset','1',1224778481,0,'NO'),(612,102,'network_address','127.0.2.26',1224778481,0,'NO'),(613,103,'state','Alive',1224778482,0,'NO'),(614,103,'core ','103',1224778482,0,'NO'),(615,103,'cpu ','52',1224778482,0,'NO'),(616,103,'host ','node-26',1224778482,0,'NO'),(617,103,'cpuset','2',1224778482,0,'NO'),(618,103,'network_address','127.0.2.26',1224778482,0,'NO'),(619,104,'state','Alive',1224778482,0,'NO'),(620,104,'core ','104',1224778482,0,'NO'),(621,104,'cpu ','52',1224778482,0,'NO'),(622,104,'host ','node-26',1224778482,0,'NO'),(623,104,'cpuset','3',1224778482,0,'NO'),(624,104,'network_address','127.0.2.26',1224778482,0,'NO'),(625,105,'state','Alive',1224778482,0,'NO'),(626,105,'core ','105',1224778482,0,'NO'),(627,105,'cpu ','53',1224778482,0,'NO'),(628,105,'host ','node-27',1224778482,0,'NO'),(629,105,'cpuset','0',1224778482,0,'NO'),(630,105,'network_address','127.0.2.27',1224778482,0,'NO'),(631,106,'state','Alive',1224778482,0,'NO'),(632,106,'core ','106',1224778482,0,'NO'),(633,106,'cpu ','53',1224778482,0,'NO'),(634,106,'host ','node-27',1224778482,0,'NO'),(635,106,'cpuset','1',1224778482,0,'NO'),(636,106,'network_address','127.0.2.27',1224778482,0,'NO'),(637,107,'state','Alive',1224778482,0,'NO'),(638,107,'core ','107',1224778482,0,'NO'),(639,107,'cpu ','54',1224778482,0,'NO'),(640,107,'host ','node-27',1224778482,0,'NO'),(641,107,'cpuset','2',1224778482,0,'NO'),(642,107,'network_address','127.0.2.27',1224778482,0,'NO'),(643,108,'state','Alive',1224778483,0,'NO'),(644,108,'core ','108',1224778483,0,'NO'),(645,108,'cpu ','54',1224778483,0,'NO'),(646,108,'host ','node-27',1224778483,0,'NO'),(647,108,'cpuset','3',1224778483,0,'NO'),(648,108,'network_address','127.0.2.27',1224778483,0,'NO'),(649,109,'state','Alive',1224778483,0,'NO'),(650,109,'core ','109',1224778483,0,'NO'),(651,109,'cpu ','55',1224778483,0,'NO'),(652,109,'host ','node-28',1224778483,0,'NO'),(653,109,'cpuset','0',1224778483,0,'NO'),(654,109,'network_address','127.0.2.28',1224778483,0,'NO'),(655,110,'state','Alive',1224778483,0,'NO'),(656,110,'core ','110',1224778483,0,'NO'),(657,110,'cpu ','55',1224778483,0,'NO'),(658,110,'host ','node-28',1224778483,0,'NO'),(659,110,'cpuset','1',1224778483,0,'NO'),(660,110,'network_address','127.0.2.28',1224778483,0,'NO'),(661,111,'state','Alive',1224778483,0,'NO'),(662,111,'core ','111',1224778483,0,'NO'),(663,111,'cpu ','56',1224778483,0,'NO'),(664,111,'host ','node-28',1224778483,0,'NO'),(665,111,'cpuset','2',1224778483,0,'NO'),(666,111,'network_address','127.0.2.28',1224778483,0,'NO'),(667,112,'state','Alive',1224778484,0,'NO'),(668,112,'core ','112',1224778484,0,'NO'),(669,112,'cpu ','56',1224778484,0,'NO'),(670,112,'host ','node-28',1224778484,0,'NO'),(671,112,'cpuset','3',1224778484,0,'NO'),(672,112,'network_address','127.0.2.28',1224778484,0,'NO'),(673,113,'state','Alive',1224778484,0,'NO'),(674,113,'core ','113',1224778484,0,'NO'),(675,113,'cpu ','57',1224778484,0,'NO'),(676,113,'host ','node-29',1224778484,0,'NO'),(677,113,'cpuset','0',1224778484,0,'NO'),(678,113,'network_address','127.0.2.29',1224778484,0,'NO'),(679,114,'state','Alive',1224778484,0,'NO'),(680,114,'core ','114',1224778484,0,'NO'),(681,114,'cpu ','57',1224778484,0,'NO'),(682,114,'host ','node-29',1224778484,0,'NO'),(683,114,'cpuset','1',1224778484,0,'NO'),(684,114,'network_address','127.0.2.29',1224778484,0,'NO'),(685,115,'state','Alive',1224778484,0,'NO'),(686,115,'core ','115',1224778484,0,'NO'),(687,115,'cpu ','58',1224778484,0,'NO'),(688,115,'host ','node-29',1224778484,0,'NO'),(689,115,'cpuset','2',1224778484,0,'NO'),(690,115,'network_address','127.0.2.29',1224778484,0,'NO'),(691,116,'state','Alive',1224778484,0,'NO'),(692,116,'core ','116',1224778484,0,'NO'),(693,116,'cpu ','58',1224778484,0,'NO'),(694,116,'host ','node-29',1224778484,0,'NO'),(695,116,'cpuset','3',1224778484,0,'NO'),(696,116,'network_address','127.0.2.29',1224778484,0,'NO'),(697,117,'state','Alive',1224778485,0,'NO'),(698,117,'core ','117',1224778485,0,'NO'),(699,117,'cpu ','59',1224778485,0,'NO'),(700,117,'host ','node-30',1224778485,0,'NO'),(701,117,'cpuset','0',1224778485,0,'NO'),(702,117,'network_address','127.0.2.30',1224778485,0,'NO'),(703,118,'state','Alive',1224778485,0,'NO'),(704,118,'core ','118',1224778485,0,'NO'),(705,118,'cpu ','59',1224778485,0,'NO'),(706,118,'host ','node-30',1224778485,0,'NO'),(707,118,'cpuset','1',1224778485,0,'NO'),(708,118,'network_address','127.0.2.30',1224778485,0,'NO'),(709,119,'state','Alive',1224778485,0,'NO'),(710,119,'core ','119',1224778485,0,'NO'),(711,119,'cpu ','60',1224778485,0,'NO'),(712,119,'host ','node-30',1224778485,0,'NO'),(713,119,'cpuset','2',1224778485,0,'NO'),(714,119,'network_address','127.0.2.30',1224778485,0,'NO'),(715,120,'state','Alive',1224778485,0,'NO'),(716,120,'core ','120',1224778485,0,'NO'),(717,120,'cpu ','60',1224778485,0,'NO'),(718,120,'host ','node-30',1224778485,0,'NO'),(719,120,'cpuset','3',1224778485,0,'NO'),(720,120,'network_address','127.0.2.30',1224778485,0,'NO'),(721,121,'state','Alive',1224778485,0,'NO'),(722,121,'core ','121',1224778485,0,'NO'),(723,121,'cpu ','61',1224778485,0,'NO'),(724,121,'host ','node-31',1224778485,0,'NO'),(725,121,'cpuset','0',1224778485,0,'NO'),(726,121,'network_address','127.0.2.31',1224778485,0,'NO'),(727,122,'state','Alive',1224778486,0,'NO'),(728,122,'core ','122',1224778486,0,'NO'),(729,122,'cpu ','61',1224778486,0,'NO'),(730,122,'host ','node-31',1224778486,0,'NO'),(731,122,'cpuset','1',1224778486,0,'NO'),(732,122,'network_address','127.0.2.31',1224778486,0,'NO'),(733,123,'state','Alive',1224778486,0,'NO'),(734,123,'core ','123',1224778486,0,'NO'),(735,123,'cpu ','62',1224778486,0,'NO'),(736,123,'host ','node-31',1224778486,0,'NO'),(737,123,'cpuset','2',1224778486,0,'NO'),(738,123,'network_address','127.0.2.31',1224778486,0,'NO'),(739,124,'state','Alive',1224778486,0,'NO'),(740,124,'core ','124',1224778486,0,'NO'),(741,124,'cpu ','62',1224778486,0,'NO'),(742,124,'host ','node-31',1224778486,0,'NO'),(743,124,'cpuset','3',1224778486,0,'NO'),(744,124,'network_address','127.0.2.31',1224778486,0,'NO'),(745,125,'state','Alive',1224778486,0,'NO'),(746,125,'core ','125',1224778486,0,'NO'),(747,125,'cpu ','63',1224778486,0,'NO'),(748,125,'host ','node-32',1224778486,0,'NO'),(749,125,'cpuset','0',1224778486,0,'NO'),(750,125,'network_address','127.0.2.32',1224778486,0,'NO'),(751,126,'state','Alive',1224778486,0,'NO'),(752,126,'core ','126',1224778486,0,'NO'),(753,126,'cpu ','63',1224778486,0,'NO'),(754,126,'host ','node-32',1224778486,0,'NO'),(755,126,'cpuset','1',1224778486,0,'NO'),(756,126,'network_address','127.0.2.32',1224778486,0,'NO'),(757,127,'state','Alive',1224778487,0,'NO'),(758,127,'core ','127',1224778487,0,'NO'),(759,127,'cpu ','64',1224778487,0,'NO'),(760,127,'host ','node-32',1224778487,0,'NO'),(761,127,'cpuset','2',1224778487,0,'NO'),(762,127,'network_address','127.0.2.32',1224778487,0,'NO'),(763,128,'state','Alive',1224778487,0,'NO'),(764,128,'core ','128',1224778487,0,'NO'),(765,128,'cpu ','64',1224778487,0,'NO'),(766,128,'host ','node-32',1224778487,0,'NO'),(767,128,'cpuset','3',1224778487,0,'NO'),(768,128,'network_address','127.0.2.32',1224778487,0,'NO'),(769,129,'state','Alive',1224778487,0,'NO'),(770,129,'core ','129',1224778487,0,'NO'),(771,129,'cpu ','65',1224778487,0,'NO'),(772,129,'host ','node-33',1224778487,0,'NO'),(773,129,'cpuset','0',1224778487,0,'NO'),(774,129,'network_address','127.0.2.33',1224778487,0,'NO'),(775,130,'state','Alive',1224778487,0,'NO'),(776,130,'core ','130',1224778487,0,'NO'),(777,130,'cpu ','65',1224778487,0,'NO'),(778,130,'host ','node-33',1224778487,0,'NO'),(779,130,'cpuset','1',1224778487,0,'NO'),(780,130,'network_address','127.0.2.33',1224778487,0,'NO'),(781,131,'state','Alive',1224778487,0,'NO'),(782,131,'core ','131',1224778487,0,'NO'),(783,131,'cpu ','66',1224778487,0,'NO'),(784,131,'host ','node-33',1224778487,0,'NO'),(785,131,'cpuset','2',1224778487,0,'NO'),(786,131,'network_address','127.0.2.33',1224778487,0,'NO'),(787,132,'state','Alive',1224778487,0,'NO'),(788,132,'core ','132',1224778487,0,'NO'),(789,132,'cpu ','66',1224778487,0,'NO'),(790,132,'host ','node-33',1224778487,0,'NO'),(791,132,'cpuset','3',1224778487,0,'NO'),(792,132,'network_address','127.0.2.33',1224778487,0,'NO'),(793,133,'state','Alive',1224778488,0,'NO'),(794,133,'core ','133',1224778488,0,'NO'),(795,133,'cpu ','67',1224778488,0,'NO'),(796,133,'host ','node-34',1224778488,0,'NO'),(797,133,'cpuset','0',1224778488,0,'NO'),(798,133,'network_address','127.0.2.34',1224778488,0,'NO'),(799,134,'state','Alive',1224778488,0,'NO'),(800,134,'core ','134',1224778488,0,'NO'),(801,134,'cpu ','67',1224778488,0,'NO'),(802,134,'host ','node-34',1224778488,0,'NO'),(803,134,'cpuset','1',1224778488,0,'NO'),(804,134,'network_address','127.0.2.34',1224778488,0,'NO'),(805,135,'state','Alive',1224778488,0,'NO'),(806,135,'core ','135',1224778488,0,'NO'),(807,135,'cpu ','68',1224778488,0,'NO'),(808,135,'host ','node-34',1224778488,0,'NO'),(809,135,'cpuset','2',1224778488,0,'NO'),(810,135,'network_address','127.0.2.34',1224778488,0,'NO'),(811,136,'state','Alive',1224778488,0,'NO'),(812,136,'core ','136',1224778488,0,'NO'),(813,136,'cpu ','68',1224778488,0,'NO'),(814,136,'host ','node-34',1224778488,0,'NO'),(815,136,'cpuset','3',1224778488,0,'NO'),(816,136,'network_address','127.0.2.34',1224778488,0,'NO'),(817,137,'state','Alive',1224778488,0,'NO'),(818,137,'core ','137',1224778488,0,'NO'),(819,137,'cpu ','69',1224778488,0,'NO'),(820,137,'host ','node-35',1224778488,0,'NO'),(821,137,'cpuset','0',1224778488,0,'NO'),(822,137,'network_address','127.0.2.35',1224778488,0,'NO'),(823,138,'state','Alive',1224778489,0,'NO'),(824,138,'core ','138',1224778489,0,'NO'),(825,138,'cpu ','69',1224778489,0,'NO'),(826,138,'host ','node-35',1224778489,0,'NO'),(827,138,'cpuset','1',1224778489,0,'NO'),(828,138,'network_address','127.0.2.35',1224778489,0,'NO'),(829,139,'state','Alive',1224778489,0,'NO'),(830,139,'core ','139',1224778489,0,'NO'),(831,139,'cpu ','70',1224778489,0,'NO'),(832,139,'host ','node-35',1224778489,0,'NO'),(833,139,'cpuset','2',1224778489,0,'NO'),(834,139,'network_address','127.0.2.35',1224778489,0,'NO'),(835,140,'state','Alive',1224778489,0,'NO'),(836,140,'core ','140',1224778489,0,'NO'),(837,140,'cpu ','70',1224778489,0,'NO'),(838,140,'host ','node-35',1224778489,0,'NO'),(839,140,'cpuset','3',1224778489,0,'NO'),(840,140,'network_address','127.0.2.35',1224778489,0,'NO'),(841,141,'state','Alive',1224778489,0,'NO'),(842,141,'core ','141',1224778489,0,'NO'),(843,141,'cpu ','71',1224778489,0,'NO'),(844,141,'host ','node-36',1224778489,0,'NO'),(845,141,'cpuset','0',1224778489,0,'NO'),(846,141,'network_address','127.0.2.36',1224778489,0,'NO'),(847,142,'state','Alive',1224778489,0,'NO'),(848,142,'core ','142',1224778489,0,'NO'),(849,142,'cpu ','71',1224778489,0,'NO'),(850,142,'host ','node-36',1224778489,0,'NO'),(851,142,'cpuset','1',1224778489,0,'NO'),(852,142,'network_address','127.0.2.36',1224778489,0,'NO'),(853,143,'state','Alive',1224778490,0,'NO'),(854,143,'core ','143',1224778490,0,'NO'),(855,143,'cpu ','72',1224778490,0,'NO'),(856,143,'host ','node-36',1224778490,0,'NO'),(857,143,'cpuset','2',1224778490,0,'NO'),(858,143,'network_address','127.0.2.36',1224778490,0,'NO'),(859,144,'state','Alive',1224778490,0,'NO'),(860,144,'core ','144',1224778490,0,'NO'),(861,144,'cpu ','72',1224778490,0,'NO'),(862,144,'host ','node-36',1224778490,0,'NO'),(863,144,'cpuset','3',1224778490,0,'NO'),(864,144,'network_address','127.0.2.36',1224778490,0,'NO'),(865,145,'state','Alive',1224778490,0,'NO'),(866,145,'core ','145',1224778490,0,'NO'),(867,145,'cpu ','73',1224778490,0,'NO'),(868,145,'host ','node-37',1224778490,0,'NO'),(869,145,'cpuset','0',1224778490,0,'NO'),(870,145,'network_address','127.0.2.37',1224778490,0,'NO'),(871,146,'state','Alive',1224778490,0,'NO'),(872,146,'core ','146',1224778490,0,'NO'),(873,146,'cpu ','73',1224778490,0,'NO'),(874,146,'host ','node-37',1224778490,0,'NO'),(875,146,'cpuset','1',1224778490,0,'NO'),(876,146,'network_address','127.0.2.37',1224778490,0,'NO'),(877,147,'state','Alive',1224778490,0,'NO'),(878,147,'core ','147',1224778490,0,'NO'),(879,147,'cpu ','74',1224778490,0,'NO'),(880,147,'host ','node-37',1224778490,0,'NO'),(881,147,'cpuset','2',1224778490,0,'NO'),(882,147,'network_address','127.0.2.37',1224778490,0,'NO'),(883,148,'state','Alive',1224778491,0,'NO'),(884,148,'core ','148',1224778491,0,'NO'),(885,148,'cpu ','74',1224778491,0,'NO'),(886,148,'host ','node-37',1224778491,0,'NO'),(887,148,'cpuset','3',1224778491,0,'NO'),(888,148,'network_address','127.0.2.37',1224778491,0,'NO'),(889,149,'state','Alive',1224778491,0,'NO'),(890,149,'core ','149',1224778491,0,'NO'),(891,149,'cpu ','75',1224778491,0,'NO'),(892,149,'host ','node-38',1224778491,0,'NO'),(893,149,'cpuset','0',1224778491,0,'NO'),(894,149,'network_address','127.0.2.38',1224778491,0,'NO'),(895,150,'state','Alive',1224778491,0,'NO'),(896,150,'core ','150',1224778491,0,'NO'),(897,150,'cpu ','75',1224778491,0,'NO'),(898,150,'host ','node-38',1224778491,0,'NO'),(899,150,'cpuset','1',1224778491,0,'NO'),(900,150,'network_address','127.0.2.38',1224778491,0,'NO'),(901,151,'state','Alive',1224778491,0,'NO'),(902,151,'core ','151',1224778491,0,'NO'),(903,151,'cpu ','76',1224778491,0,'NO'),(904,151,'host ','node-38',1224778491,0,'NO'),(905,151,'cpuset','2',1224778491,0,'NO'),(906,151,'network_address','127.0.2.38',1224778491,0,'NO'),(907,152,'state','Alive',1224778491,0,'NO'),(908,152,'core ','152',1224778491,0,'NO'),(909,152,'cpu ','76',1224778491,0,'NO'),(910,152,'host ','node-38',1224778491,0,'NO'),(911,152,'cpuset','3',1224778491,0,'NO'),(912,152,'network_address','127.0.2.38',1224778491,0,'NO'),(913,153,'state','Alive',1224778491,0,'NO'),(914,153,'core ','153',1224778491,0,'NO'),(915,153,'cpu ','77',1224778491,0,'NO'),(916,153,'host ','node-39',1224778491,0,'NO'),(917,153,'cpuset','0',1224778491,0,'NO'),(918,153,'network_address','127.0.2.39',1224778491,0,'NO'),(919,154,'state','Alive',1224778492,0,'NO'),(920,154,'core ','154',1224778492,0,'NO'),(921,154,'cpu ','77',1224778492,0,'NO'),(922,154,'host ','node-39',1224778492,0,'NO'),(923,154,'cpuset','1',1224778492,0,'NO'),(924,154,'network_address','127.0.2.39',1224778492,0,'NO'),(925,155,'state','Alive',1224778492,0,'NO'),(926,155,'core ','155',1224778492,0,'NO'),(927,155,'cpu ','78',1224778492,0,'NO'),(928,155,'host ','node-39',1224778492,0,'NO'),(929,155,'cpuset','2',1224778492,0,'NO'),(930,155,'network_address','127.0.2.39',1224778492,0,'NO'),(931,156,'state','Alive',1224778492,0,'NO'),(932,156,'core ','156',1224778492,0,'NO'),(933,156,'cpu ','78',1224778492,0,'NO'),(934,156,'host ','node-39',1224778492,0,'NO'),(935,156,'cpuset','3',1224778492,0,'NO'),(936,156,'network_address','127.0.2.39',1224778492,0,'NO'),(937,157,'state','Alive',1224778492,0,'NO'),(938,157,'core ','157',1224778492,0,'NO'),(939,157,'cpu ','79',1224778492,0,'NO'),(940,157,'host ','node-40',1224778492,0,'NO'),(941,157,'cpuset','0',1224778492,0,'NO'),(942,157,'network_address','127.0.2.40',1224778492,0,'NO'),(943,158,'state','Alive',1224778492,0,'NO'),(944,158,'core ','158',1224778492,0,'NO'),(945,158,'cpu ','79',1224778492,0,'NO'),(946,158,'host ','node-40',1224778492,0,'NO'),(947,158,'cpuset','1',1224778492,0,'NO'),(948,158,'network_address','127.0.2.40',1224778492,0,'NO'),(949,159,'state','Alive',1224778493,0,'NO'),(950,159,'core ','159',1224778493,0,'NO'),(951,159,'cpu ','80',1224778493,0,'NO'),(952,159,'host ','node-40',1224778493,0,'NO'),(953,159,'cpuset','2',1224778493,0,'NO'),(954,159,'network_address','127.0.2.40',1224778493,0,'NO'),(955,160,'state','Alive',1224778493,0,'NO'),(956,160,'core ','160',1224778493,0,'NO'),(957,160,'cpu ','80',1224778493,0,'NO'),(958,160,'host ','node-40',1224778493,0,'NO'),(959,160,'cpuset','3',1224778493,0,'NO'),(960,160,'network_address','127.0.2.40',1224778493,0,'NO'),(961,161,'state','Alive',1224778493,0,'NO'),(962,161,'core ','161',1224778493,0,'NO'),(963,161,'cpu ','81',1224778493,0,'NO'),(964,161,'host ','node-41',1224778493,0,'NO'),(965,161,'cpuset','0',1224778493,0,'NO'),(966,161,'network_address','127.0.2.41',1224778493,0,'NO'),(967,162,'state','Alive',1224778493,0,'NO'),(968,162,'core ','162',1224778493,0,'NO'),(969,162,'cpu ','81',1224778493,0,'NO'),(970,162,'host ','node-41',1224778493,0,'NO'),(971,162,'cpuset','1',1224778493,0,'NO'),(972,162,'network_address','127.0.2.41',1224778493,0,'NO'),(973,163,'state','Alive',1224778493,0,'NO'),(974,163,'core ','163',1224778493,0,'NO'),(975,163,'cpu ','82',1224778493,0,'NO'),(976,163,'host ','node-41',1224778493,0,'NO'),(977,163,'cpuset','2',1224778493,0,'NO'),(978,163,'network_address','127.0.2.41',1224778493,0,'NO'),(979,164,'state','Alive',1224778494,0,'NO'),(980,164,'core ','164',1224778494,0,'NO'),(981,164,'cpu ','82',1224778494,0,'NO'),(982,164,'host ','node-41',1224778494,0,'NO'),(983,164,'cpuset','3',1224778494,0,'NO'),(984,164,'network_address','127.0.2.41',1224778494,0,'NO'),(985,165,'state','Alive',1224778494,0,'NO'),(986,165,'core ','165',1224778494,0,'NO'),(987,165,'cpu ','83',1224778494,0,'NO'),(988,165,'host ','node-42',1224778494,0,'NO'),(989,165,'cpuset','0',1224778494,0,'NO'),(990,165,'network_address','127.0.2.42',1224778494,0,'NO'),(991,166,'state','Alive',1224778494,0,'NO'),(992,166,'core ','166',1224778494,0,'NO'),(993,166,'cpu ','83',1224778494,0,'NO'),(994,166,'host ','node-42',1224778494,0,'NO'),(995,166,'cpuset','1',1224778494,0,'NO'),(996,166,'network_address','127.0.2.42',1224778494,0,'NO'),(997,167,'state','Alive',1224778494,0,'NO'),(998,167,'core ','167',1224778494,0,'NO'),(999,167,'cpu ','84',1224778494,0,'NO'),(1000,167,'host ','node-42',1224778494,0,'NO'),(1001,167,'cpuset','2',1224778494,0,'NO'),(1002,167,'network_address','127.0.2.42',1224778494,0,'NO'),(1003,168,'state','Alive',1224778494,0,'NO'),(1004,168,'core ','168',1224778494,0,'NO'),(1005,168,'cpu ','84',1224778494,0,'NO'),(1006,168,'host ','node-42',1224778494,0,'NO'),(1007,168,'cpuset','3',1224778494,0,'NO'),(1008,168,'network_address','127.0.2.42',1224778494,0,'NO'),(1009,169,'state','Alive',1224778495,0,'NO'),(1010,169,'core ','169',1224778495,0,'NO'),(1011,169,'cpu ','85',1224778495,0,'NO'),(1012,169,'host ','node-43',1224778495,0,'NO'),(1013,169,'cpuset','0',1224778495,0,'NO'),(1014,169,'network_address','127.0.2.43',1224778495,0,'NO'),(1015,170,'state','Alive',1224778495,0,'NO'),(1016,170,'core ','170',1224778495,0,'NO'),(1017,170,'cpu ','85',1224778495,0,'NO'),(1018,170,'host ','node-43',1224778495,0,'NO'),(1019,170,'cpuset','1',1224778495,0,'NO'),(1020,170,'network_address','127.0.2.43',1224778495,0,'NO'),(1021,171,'state','Alive',1224778495,0,'NO'),(1022,171,'core ','171',1224778495,0,'NO'),(1023,171,'cpu ','86',1224778495,0,'NO'),(1024,171,'host ','node-43',1224778495,0,'NO'),(1025,171,'cpuset','2',1224778495,0,'NO'),(1026,171,'network_address','127.0.2.43',1224778495,0,'NO'),(1027,172,'state','Alive',1224778495,0,'NO'),(1028,172,'core ','172',1224778495,0,'NO'),(1029,172,'cpu ','86',1224778495,0,'NO'),(1030,172,'host ','node-43',1224778495,0,'NO'),(1031,172,'cpuset','3',1224778495,0,'NO'),(1032,172,'network_address','127.0.2.43',1224778495,0,'NO'),(1033,173,'state','Alive',1224778495,0,'NO'),(1034,173,'core ','173',1224778495,0,'NO'),(1035,173,'cpu ','87',1224778495,0,'NO'),(1036,173,'host ','node-44',1224778495,0,'NO'),(1037,173,'cpuset','0',1224778495,0,'NO'),(1038,173,'network_address','127.0.2.44',1224778495,0,'NO'),(1039,174,'state','Alive',1224778496,0,'NO'),(1040,174,'core ','174',1224778496,0,'NO'),(1041,174,'cpu ','87',1224778496,0,'NO'),(1042,174,'host ','node-44',1224778496,0,'NO'),(1043,174,'cpuset','1',1224778496,0,'NO'),(1044,174,'network_address','127.0.2.44',1224778496,0,'NO'),(1045,175,'state','Alive',1224778496,0,'NO'),(1046,175,'core ','175',1224778496,0,'NO'),(1047,175,'cpu ','88',1224778496,0,'NO'),(1048,175,'host ','node-44',1224778496,0,'NO'),(1049,175,'cpuset','2',1224778496,0,'NO'),(1050,175,'network_address','127.0.2.44',1224778496,0,'NO'),(1051,176,'state','Alive',1224778496,0,'NO'),(1052,176,'core ','176',1224778496,0,'NO'),(1053,176,'cpu ','88',1224778496,0,'NO'),(1054,176,'host ','node-44',1224778496,0,'NO'),(1055,176,'cpuset','3',1224778496,0,'NO'),(1056,176,'network_address','127.0.2.44',1224778496,0,'NO'),(1057,177,'state','Alive',1224778496,0,'NO'),(1058,177,'core ','177',1224778496,0,'NO'),(1059,177,'cpu ','89',1224778496,0,'NO'),(1060,177,'host ','node-45',1224778496,0,'NO'),(1061,177,'cpuset','0',1224778496,0,'NO'),(1062,177,'network_address','127.0.2.45',1224778496,0,'NO'),(1063,178,'state','Alive',1224778497,0,'NO'),(1064,178,'core ','178',1224778497,0,'NO'),(1065,178,'cpu ','89',1224778497,0,'NO'),(1066,178,'host ','node-45',1224778497,0,'NO'),(1067,178,'cpuset','1',1224778497,0,'NO'),(1068,178,'network_address','127.0.2.45',1224778497,0,'NO'),(1069,179,'state','Alive',1224778497,0,'NO'),(1070,179,'core ','179',1224778497,0,'NO'),(1071,179,'cpu ','90',1224778497,0,'NO'),(1072,179,'host ','node-45',1224778497,0,'NO'),(1073,179,'cpuset','2',1224778497,0,'NO'),(1074,179,'network_address','127.0.2.45',1224778497,0,'NO'),(1075,180,'state','Alive',1224778497,0,'NO'),(1076,180,'core ','180',1224778497,0,'NO'),(1077,180,'cpu ','90',1224778497,0,'NO'),(1078,180,'host ','node-45',1224778497,0,'NO'),(1079,180,'cpuset','3',1224778497,0,'NO'),(1080,180,'network_address','127.0.2.45',1224778497,0,'NO'),(1081,181,'state','Alive',1224778497,0,'NO'),(1082,181,'core ','181',1224778497,0,'NO'),(1083,181,'cpu ','91',1224778497,0,'NO'),(1084,181,'host ','node-46',1224778497,0,'NO'),(1085,181,'cpuset','0',1224778497,0,'NO'),(1086,181,'network_address','127.0.2.46',1224778497,0,'NO'),(1087,182,'state','Alive',1224778497,0,'NO'),(1088,182,'core ','182',1224778497,0,'NO'),(1089,182,'cpu ','91',1224778497,0,'NO'),(1090,182,'host ','node-46',1224778497,0,'NO'),(1091,182,'cpuset','1',1224778497,0,'NO'),(1092,182,'network_address','127.0.2.46',1224778497,0,'NO'),(1093,183,'state','Alive',1224778497,0,'NO'),(1094,183,'core ','183',1224778497,0,'NO'),(1095,183,'cpu ','92',1224778497,0,'NO'),(1096,183,'host ','node-46',1224778497,0,'NO'),(1097,183,'cpuset','2',1224778497,0,'NO'),(1098,183,'network_address','127.0.2.46',1224778497,0,'NO'),(1099,184,'state','Alive',1224778498,0,'NO'),(1100,184,'core ','184',1224778498,0,'NO'),(1101,184,'cpu ','92',1224778498,0,'NO'),(1102,184,'host ','node-46',1224778498,0,'NO'),(1103,184,'cpuset','3',1224778498,0,'NO'),(1104,184,'network_address','127.0.2.46',1224778498,0,'NO'),(1105,185,'state','Alive',1224778498,0,'NO'),(1106,185,'core ','185',1224778498,0,'NO'),(1107,185,'cpu ','93',1224778498,0,'NO'),(1108,185,'host ','node-47',1224778498,0,'NO'),(1109,185,'cpuset','0',1224778498,0,'NO'),(1110,185,'network_address','127.0.2.47',1224778498,0,'NO'),(1111,186,'state','Alive',1224778498,0,'NO'),(1112,186,'core ','186',1224778498,0,'NO'),(1113,186,'cpu ','93',1224778498,0,'NO'),(1114,186,'host ','node-47',1224778498,0,'NO'),(1115,186,'cpuset','1',1224778498,0,'NO'),(1116,186,'network_address','127.0.2.47',1224778498,0,'NO'),(1117,187,'state','Alive',1224778498,0,'NO'),(1118,187,'core ','187',1224778498,0,'NO'),(1119,187,'cpu ','94',1224778498,0,'NO'),(1120,187,'host ','node-47',1224778498,0,'NO'),(1121,187,'cpuset','2',1224778498,0,'NO'),(1122,187,'network_address','127.0.2.47',1224778498,0,'NO'),(1123,188,'state','Alive',1224778498,0,'NO'),(1124,188,'core ','188',1224778498,0,'NO'),(1125,188,'cpu ','94',1224778498,0,'NO'),(1126,188,'host ','node-47',1224778498,0,'NO'),(1127,188,'cpuset','3',1224778498,0,'NO'),(1128,188,'network_address','127.0.2.47',1224778498,0,'NO'),(1129,189,'state','Alive',1224778499,0,'NO'),(1130,189,'core ','189',1224778499,0,'NO'),(1131,189,'cpu ','95',1224778499,0,'NO'),(1132,189,'host ','node-48',1224778499,0,'NO'),(1133,189,'cpuset','0',1224778499,0,'NO'),(1134,189,'network_address','127.0.2.48',1224778499,0,'NO'),(1135,190,'state','Alive',1224778499,0,'NO'),(1136,190,'core ','190',1224778499,0,'NO'),(1137,190,'cpu ','95',1224778499,0,'NO'),(1138,190,'host ','node-48',1224778499,0,'NO'),(1139,190,'cpuset','1',1224778499,0,'NO'),(1140,190,'network_address','127.0.2.48',1224778499,0,'NO'),(1141,191,'state','Alive',1224778499,0,'NO'),(1142,191,'core ','191',1224778499,0,'NO'),(1143,191,'cpu ','96',1224778499,0,'NO'),(1144,191,'host ','node-48',1224778499,0,'NO'),(1145,191,'cpuset','2',1224778499,0,'NO'),(1146,191,'network_address','127.0.2.48',1224778499,0,'NO'),(1147,192,'state','Alive',1224778499,0,'NO'),(1148,192,'core ','192',1224778499,0,'NO'),(1149,192,'cpu ','96',1224778499,0,'NO'),(1150,192,'host ','node-48',1224778499,0,'NO'),(1151,192,'cpuset','3',1224778499,0,'NO'),(1152,192,'network_address','127.0.2.48',1224778499,0,'NO'),(1153,193,'state','Alive',1224778499,0,'NO'),(1154,193,'core ','193',1224778499,0,'NO'),(1155,193,'cpu ','97',1224778499,0,'NO'),(1156,193,'host ','node-49',1224778499,0,'NO'),(1157,193,'cpuset','0',1224778499,0,'NO'),(1158,193,'network_address','127.0.2.49',1224778499,0,'NO'),(1159,194,'state','Alive',1224778500,0,'NO'),(1160,194,'core ','194',1224778500,0,'NO'),(1161,194,'cpu ','97',1224778500,0,'NO'),(1162,194,'host ','node-49',1224778500,0,'NO'),(1163,194,'cpuset','1',1224778500,0,'NO'),(1164,194,'network_address','127.0.2.49',1224778500,0,'NO'),(1165,195,'state','Alive',1224778500,0,'NO'),(1166,195,'core ','195',1224778500,0,'NO'),(1167,195,'cpu ','98',1224778500,0,'NO'),(1168,195,'host ','node-49',1224778500,0,'NO'),(1169,195,'cpuset','2',1224778500,0,'NO'),(1170,195,'network_address','127.0.2.49',1224778500,0,'NO'),(1171,196,'state','Alive',1224778500,0,'NO'),(1172,196,'core ','196',1224778500,0,'NO'),(1173,196,'cpu ','98',1224778500,0,'NO'),(1174,196,'host ','node-49',1224778500,0,'NO'),(1175,196,'cpuset','3',1224778500,0,'NO'),(1176,196,'network_address','127.0.2.49',1224778500,0,'NO'),(1177,197,'state','Alive',1224778500,0,'NO'),(1178,197,'core ','197',1224778500,0,'NO'),(1179,197,'cpu ','99',1224778500,0,'NO'),(1180,197,'host ','node-50',1224778500,0,'NO'),(1181,197,'cpuset','0',1224778500,0,'NO'),(1182,197,'network_address','127.0.2.50',1224778500,0,'NO'),(1183,198,'state','Alive',1224778500,0,'NO'),(1184,198,'core ','198',1224778500,0,'NO'),(1185,198,'cpu ','99',1224778500,0,'NO'),(1186,198,'host ','node-50',1224778500,0,'NO'),(1187,198,'cpuset','1',1224778500,0,'NO'),(1188,198,'network_address','127.0.2.50',1224778500,0,'NO'),(1189,199,'state','Alive',1224778501,0,'NO'),(1190,199,'core ','199',1224778501,0,'NO'),(1191,199,'cpu ','100',1224778501,0,'NO'),(1192,199,'host ','node-50',1224778501,0,'NO'),(1193,199,'cpuset','2',1224778501,0,'NO'),(1194,199,'network_address','127.0.2.50',1224778501,0,'NO'),(1195,200,'state','Alive',1224778501,0,'NO'),(1196,200,'core ','200',1224778501,0,'NO'),(1197,200,'cpu ','100',1224778501,0,'NO'),(1198,200,'host ','node-50',1224778501,0,'NO'),(1199,200,'cpuset','3',1224778501,0,'NO'),(1200,200,'network_address','127.0.2.50',1224778501,0,'NO'),(1201,201,'state','Alive',1224778501,0,'NO'),(1202,201,'core ','201',1224778501,0,'NO'),(1203,201,'cpu ','101',1224778501,0,'NO'),(1204,201,'host ','node-51',1224778501,0,'NO'),(1205,201,'cpuset','0',1224778501,0,'NO'),(1206,201,'network_address','127.0.2.51',1224778501,0,'NO'),(1207,202,'state','Alive',1224778501,0,'NO'),(1208,202,'core ','202',1224778501,0,'NO'),(1209,202,'cpu ','101',1224778501,0,'NO'),(1210,202,'host ','node-51',1224778501,0,'NO'),(1211,202,'cpuset','1',1224778501,0,'NO'),(1212,202,'network_address','127.0.2.51',1224778501,0,'NO'),(1213,203,'state','Alive',1224778501,0,'NO'),(1214,203,'core ','203',1224778501,0,'NO'),(1215,203,'cpu ','102',1224778501,0,'NO'),(1216,203,'host ','node-51',1224778501,0,'NO'),(1217,203,'cpuset','2',1224778501,0,'NO'),(1218,203,'network_address','127.0.2.51',1224778501,0,'NO'),(1219,204,'state','Alive',1224778502,0,'NO'),(1220,204,'core ','204',1224778502,0,'NO'),(1221,204,'cpu ','102',1224778502,0,'NO'),(1222,204,'host ','node-51',1224778502,0,'NO'),(1223,204,'cpuset','3',1224778502,0,'NO'),(1224,204,'network_address','127.0.2.51',1224778502,0,'NO'),(1225,205,'state','Alive',1224778502,0,'NO'),(1226,205,'core ','205',1224778502,0,'NO'),(1227,205,'cpu ','103',1224778502,0,'NO'),(1228,205,'host ','node-52',1224778502,0,'NO'),(1229,205,'cpuset','0',1224778502,0,'NO'),(1230,205,'network_address','127.0.2.52',1224778502,0,'NO'),(1231,206,'state','Alive',1224778502,0,'NO'),(1232,206,'core ','206',1224778502,0,'NO'),(1233,206,'cpu ','103',1224778502,0,'NO'),(1234,206,'host ','node-52',1224778502,0,'NO'),(1235,206,'cpuset','1',1224778502,0,'NO'),(1236,206,'network_address','127.0.2.52',1224778502,0,'NO'),(1237,207,'state','Alive',1224778502,0,'NO'),(1238,207,'core ','207',1224778502,0,'NO'),(1239,207,'cpu ','104',1224778502,0,'NO'),(1240,207,'host ','node-52',1224778502,0,'NO'),(1241,207,'cpuset','2',1224778502,0,'NO'),(1242,207,'network_address','127.0.2.52',1224778502,0,'NO'),(1243,208,'state','Alive',1224778502,0,'NO'),(1244,208,'core ','208',1224778502,0,'NO'),(1245,208,'cpu ','104',1224778502,0,'NO'),(1246,208,'host ','node-52',1224778502,0,'NO'),(1247,208,'cpuset','3',1224778502,0,'NO'),(1248,208,'network_address','127.0.2.52',1224778502,0,'NO'),(1249,209,'state','Alive',1224778502,0,'NO'),(1250,209,'core ','209',1224778502,0,'NO'),(1251,209,'cpu ','105',1224778502,0,'NO'),(1252,209,'host ','node-53',1224778502,0,'NO'),(1253,209,'cpuset','0',1224778502,0,'NO'),(1254,209,'network_address','127.0.2.53',1224778502,0,'NO'),(1255,210,'state','Alive',1224778503,0,'NO'),(1256,210,'core ','210',1224778503,0,'NO'),(1257,210,'cpu ','105',1224778503,0,'NO'),(1258,210,'host ','node-53',1224778503,0,'NO'),(1259,210,'cpuset','1',1224778503,0,'NO'),(1260,210,'network_address','127.0.2.53',1224778503,0,'NO'),(1261,211,'state','Alive',1224778503,0,'NO'),(1262,211,'core ','211',1224778503,0,'NO'),(1263,211,'cpu ','106',1224778503,0,'NO'),(1264,211,'host ','node-53',1224778503,0,'NO'),(1265,211,'cpuset','2',1224778503,0,'NO'),(1266,211,'network_address','127.0.2.53',1224778503,0,'NO'),(1267,212,'state','Alive',1224778503,0,'NO'),(1268,212,'core ','212',1224778503,0,'NO'),(1269,212,'cpu ','106',1224778503,0,'NO'),(1270,212,'host ','node-53',1224778503,0,'NO'),(1271,212,'cpuset','3',1224778503,0,'NO'),(1272,212,'network_address','127.0.2.53',1224778503,0,'NO'),(1273,213,'state','Alive',1224778503,0,'NO'),(1274,213,'core ','213',1224778503,0,'NO'),(1275,213,'cpu ','107',1224778503,0,'NO'),(1276,213,'host ','node-54',1224778503,0,'NO'),(1277,213,'cpuset','0',1224778503,0,'NO'),(1278,213,'network_address','127.0.2.54',1224778503,0,'NO'),(1279,214,'state','Alive',1224778503,0,'NO'),(1280,214,'core ','214',1224778503,0,'NO'),(1281,214,'cpu ','107',1224778503,0,'NO'),(1282,214,'host ','node-54',1224778503,0,'NO'),(1283,214,'cpuset','1',1224778503,0,'NO'),(1284,214,'network_address','127.0.2.54',1224778503,0,'NO'),(1285,215,'state','Alive',1224778504,0,'NO'),(1286,215,'core ','215',1224778504,0,'NO'),(1287,215,'cpu ','108',1224778504,0,'NO'),(1288,215,'host ','node-54',1224778504,0,'NO'),(1289,215,'cpuset','2',1224778504,0,'NO'),(1290,215,'network_address','127.0.2.54',1224778504,0,'NO'),(1291,216,'state','Alive',1224778504,0,'NO'),(1292,216,'core ','216',1224778504,0,'NO'),(1293,216,'cpu ','108',1224778504,0,'NO'),(1294,216,'host ','node-54',1224778504,0,'NO'),(1295,216,'cpuset','3',1224778504,0,'NO'),(1296,216,'network_address','127.0.2.54',1224778504,0,'NO'),(1297,217,'state','Alive',1224778504,0,'NO'),(1298,217,'core ','217',1224778504,0,'NO'),(1299,217,'cpu ','109',1224778504,0,'NO'),(1300,217,'host ','node-55',1224778504,0,'NO'),(1301,217,'cpuset','0',1224778504,0,'NO'),(1302,217,'network_address','127.0.2.55',1224778504,0,'NO'),(1303,218,'state','Alive',1224778504,0,'NO'),(1304,218,'core ','218',1224778504,0,'NO'),(1305,218,'cpu ','109',1224778504,0,'NO'),(1306,218,'host ','node-55',1224778504,0,'NO'),(1307,218,'cpuset','1',1224778504,0,'NO'),(1308,218,'network_address','127.0.2.55',1224778504,0,'NO'),(1309,219,'state','Alive',1224778504,0,'NO'),(1310,219,'core ','219',1224778504,0,'NO'),(1311,219,'cpu ','110',1224778504,0,'NO'),(1312,219,'host ','node-55',1224778504,0,'NO'),(1313,219,'cpuset','2',1224778504,0,'NO'),(1314,219,'network_address','127.0.2.55',1224778504,0,'NO'),(1315,220,'state','Alive',1224778505,0,'NO'),(1316,220,'core ','220',1224778505,0,'NO'),(1317,220,'cpu ','110',1224778505,0,'NO'),(1318,220,'host ','node-55',1224778505,0,'NO'),(1319,220,'cpuset','3',1224778505,0,'NO'),(1320,220,'network_address','127.0.2.55',1224778505,0,'NO'),(1321,221,'state','Alive',1224778505,0,'NO'),(1322,221,'core ','221',1224778505,0,'NO'),(1323,221,'cpu ','111',1224778505,0,'NO'),(1324,221,'host ','node-56',1224778505,0,'NO'),(1325,221,'cpuset','0',1224778505,0,'NO'),(1326,221,'network_address','127.0.2.56',1224778505,0,'NO'),(1327,222,'state','Alive',1224778505,0,'NO'),(1328,222,'core ','222',1224778505,0,'NO'),(1329,222,'cpu ','111',1224778505,0,'NO'),(1330,222,'host ','node-56',1224778505,0,'NO'),(1331,222,'cpuset','1',1224778505,0,'NO'),(1332,222,'network_address','127.0.2.56',1224778505,0,'NO'),(1333,223,'state','Alive',1224778505,0,'NO'),(1334,223,'core ','223',1224778505,0,'NO'),(1335,223,'cpu ','112',1224778505,0,'NO'),(1336,223,'host ','node-56',1224778505,0,'NO'),(1337,223,'cpuset','2',1224778505,0,'NO'),(1338,223,'network_address','127.0.2.56',1224778505,0,'NO'),(1339,224,'state','Alive',1224778505,0,'NO'),(1340,224,'core ','224',1224778505,0,'NO'),(1341,224,'cpu ','112',1224778505,0,'NO'),(1342,224,'host ','node-56',1224778505,0,'NO'),(1343,224,'cpuset','3',1224778505,0,'NO'),(1344,224,'network_address','127.0.2.56',1224778505,0,'NO'),(1345,225,'state','Alive',1224778506,0,'NO'),(1346,225,'core ','225',1224778506,0,'NO'),(1347,225,'cpu ','113',1224778506,0,'NO'),(1348,225,'host ','node-57',1224778506,0,'NO'),(1349,225,'cpuset','0',1224778506,0,'NO'),(1350,225,'network_address','127.0.2.57',1224778506,0,'NO'),(1351,226,'state','Alive',1224778506,0,'NO'),(1352,226,'core ','226',1224778506,0,'NO'),(1353,226,'cpu ','113',1224778506,0,'NO'),(1354,226,'host ','node-57',1224778506,0,'NO'),(1355,226,'cpuset','1',1224778506,0,'NO'),(1356,226,'network_address','127.0.2.57',1224778506,0,'NO'),(1357,227,'state','Alive',1224778506,0,'NO'),(1358,227,'core ','227',1224778506,0,'NO'),(1359,227,'cpu ','114',1224778506,0,'NO'),(1360,227,'host ','node-57',1224778506,0,'NO'),(1361,227,'cpuset','2',1224778506,0,'NO'),(1362,227,'network_address','127.0.2.57',1224778506,0,'NO'),(1363,228,'state','Alive',1224778506,0,'NO'),(1364,228,'core ','228',1224778506,0,'NO'),(1365,228,'cpu ','114',1224778506,0,'NO'),(1366,228,'host ','node-57',1224778506,0,'NO'),(1367,228,'cpuset','3',1224778506,0,'NO'),(1368,228,'network_address','127.0.2.57',1224778506,0,'NO'),(1369,229,'state','Alive',1224778506,0,'NO'),(1370,229,'core ','229',1224778506,0,'NO'),(1371,229,'cpu ','115',1224778506,0,'NO'),(1372,229,'host ','node-58',1224778506,0,'NO'),(1373,229,'cpuset','0',1224778506,0,'NO'),(1374,229,'network_address','127.0.2.58',1224778506,0,'NO'),(1375,230,'state','Alive',1224778507,0,'NO'),(1376,230,'core ','230',1224778507,0,'NO'),(1377,230,'cpu ','115',1224778507,0,'NO'),(1378,230,'host ','node-58',1224778507,0,'NO'),(1379,230,'cpuset','1',1224778507,0,'NO'),(1380,230,'network_address','127.0.2.58',1224778507,0,'NO'),(1381,231,'state','Alive',1224778507,0,'NO'),(1382,231,'core ','231',1224778507,0,'NO'),(1383,231,'cpu ','116',1224778507,0,'NO'),(1384,231,'host ','node-58',1224778507,0,'NO'),(1385,231,'cpuset','2',1224778507,0,'NO'),(1386,231,'network_address','127.0.2.58',1224778507,0,'NO'),(1387,232,'state','Alive',1224778507,0,'NO'),(1388,232,'core ','232',1224778507,0,'NO'),(1389,232,'cpu ','116',1224778507,0,'NO'),(1390,232,'host ','node-58',1224778507,0,'NO'),(1391,232,'cpuset','3',1224778507,0,'NO'),(1392,232,'network_address','127.0.2.58',1224778507,0,'NO'),(1393,233,'state','Alive',1224778507,0,'NO'),(1394,233,'core ','233',1224778507,0,'NO'),(1395,233,'cpu ','117',1224778507,0,'NO'),(1396,233,'host ','node-59',1224778507,0,'NO'),(1397,233,'cpuset','0',1224778507,0,'NO'),(1398,233,'network_address','127.0.2.59',1224778507,0,'NO'),(1399,234,'state','Alive',1224778507,0,'NO'),(1400,234,'core ','234',1224778507,0,'NO'),(1401,234,'cpu ','117',1224778507,0,'NO'),(1402,234,'host ','node-59',1224778507,0,'NO'),(1403,234,'cpuset','1',1224778507,0,'NO'),(1404,234,'network_address','127.0.2.59',1224778507,0,'NO'),(1405,235,'state','Alive',1224778507,0,'NO'),(1406,235,'core ','235',1224778507,0,'NO'),(1407,235,'cpu ','118',1224778507,0,'NO'),(1408,235,'host ','node-59',1224778507,0,'NO'),(1409,235,'cpuset','2',1224778507,0,'NO'),(1410,235,'network_address','127.0.2.59',1224778507,0,'NO'),(1411,236,'state','Alive',1224778508,0,'NO'),(1412,236,'core ','236',1224778508,0,'NO'),(1413,236,'cpu ','118',1224778508,0,'NO'),(1414,236,'host ','node-59',1224778508,0,'NO'),(1415,236,'cpuset','3',1224778508,0,'NO'),(1416,236,'network_address','127.0.2.59',1224778508,0,'NO'),(1417,237,'state','Alive',1224778508,0,'NO'),(1418,237,'core ','237',1224778508,0,'NO'),(1419,237,'cpu ','119',1224778508,0,'NO'),(1420,237,'host ','node-60',1224778508,0,'NO'),(1421,237,'cpuset','0',1224778508,0,'NO'),(1422,237,'network_address','127.0.2.60',1224778508,0,'NO'),(1423,238,'state','Alive',1224778508,0,'NO'),(1424,238,'core ','238',1224778508,0,'NO'),(1425,238,'cpu ','119',1224778508,0,'NO'),(1426,238,'host ','node-60',1224778508,0,'NO'),(1427,238,'cpuset','1',1224778508,0,'NO'),(1428,238,'network_address','127.0.2.60',1224778508,0,'NO'),(1429,239,'state','Alive',1224778508,0,'NO'),(1430,239,'core ','239',1224778508,0,'NO'),(1431,239,'cpu ','120',1224778508,0,'NO'),(1432,239,'host ','node-60',1224778508,0,'NO'),(1433,239,'cpuset','2',1224778508,0,'NO'),(1434,239,'network_address','127.0.2.60',1224778508,0,'NO'),(1435,240,'state','Alive',1224778508,0,'NO'),(1436,240,'core ','240',1224778508,0,'NO'),(1437,240,'cpu ','120',1224778508,0,'NO'),(1438,240,'host ','node-60',1224778508,0,'NO'),(1439,240,'cpuset','3',1224778508,0,'NO'),(1440,240,'network_address','127.0.2.60',1224778508,0,'NO'),(1441,241,'state','Alive',1224778509,0,'NO'),(1442,241,'core ','241',1224778509,0,'NO'),(1443,241,'cpu ','121',1224778509,0,'NO'),(1444,241,'host ','node-61',1224778509,0,'NO'),(1445,241,'cpuset','0',1224778509,0,'NO'),(1446,241,'network_address','127.0.2.61',1224778509,0,'NO'),(1447,242,'state','Alive',1224778509,0,'NO'),(1448,242,'core ','242',1224778509,0,'NO'),(1449,242,'cpu ','121',1224778509,0,'NO'),(1450,242,'host ','node-61',1224778509,0,'NO'),(1451,242,'cpuset','1',1224778509,0,'NO'),(1452,242,'network_address','127.0.2.61',1224778509,0,'NO'),(1453,243,'state','Alive',1224778509,0,'NO'),(1454,243,'core ','243',1224778509,0,'NO'),(1455,243,'cpu ','122',1224778509,0,'NO'),(1456,243,'host ','node-61',1224778509,0,'NO'),(1457,243,'cpuset','2',1224778509,0,'NO'),(1458,243,'network_address','127.0.2.61',1224778509,0,'NO'),(1459,244,'state','Alive',1224778509,0,'NO'),(1460,244,'core ','244',1224778509,0,'NO'),(1461,244,'cpu ','122',1224778509,0,'NO'),(1462,244,'host ','node-61',1224778509,0,'NO'),(1463,244,'cpuset','3',1224778509,0,'NO'),(1464,244,'network_address','127.0.2.61',1224778509,0,'NO'),(1465,245,'state','Alive',1224778509,0,'NO'),(1466,245,'core ','245',1224778509,0,'NO'),(1467,245,'cpu ','123',1224778509,0,'NO'),(1468,245,'host ','node-62',1224778509,0,'NO'),(1469,245,'cpuset','0',1224778509,0,'NO'),(1470,245,'network_address','127.0.2.62',1224778509,0,'NO'),(1471,246,'state','Alive',1224778510,0,'NO'),(1472,246,'core ','246',1224778510,0,'NO'),(1473,246,'cpu ','123',1224778510,0,'NO'),(1474,246,'host ','node-62',1224778510,0,'NO'),(1475,246,'cpuset','1',1224778510,0,'NO'),(1476,246,'network_address','127.0.2.62',1224778510,0,'NO'),(1477,247,'state','Alive',1224778510,0,'NO'),(1478,247,'core ','247',1224778510,0,'NO'),(1479,247,'cpu ','124',1224778510,0,'NO'),(1480,247,'host ','node-62',1224778510,0,'NO'),(1481,247,'cpuset','2',1224778510,0,'NO'),(1482,247,'network_address','127.0.2.62',1224778510,0,'NO'),(1483,248,'state','Alive',1224778510,0,'NO'),(1484,248,'core ','248',1224778510,0,'NO'),(1485,248,'cpu ','124',1224778510,0,'NO'),(1486,248,'host ','node-62',1224778510,0,'NO'),(1487,248,'cpuset','3',1224778510,0,'NO'),(1488,248,'network_address','127.0.2.62',1224778510,0,'NO'),(1489,249,'state','Alive',1224778510,0,'NO'),(1490,249,'core ','249',1224778510,0,'NO'),(1491,249,'cpu ','125',1224778510,0,'NO'),(1492,249,'host ','node-63',1224778510,0,'NO'),(1493,249,'cpuset','0',1224778510,0,'NO'),(1494,249,'network_address','127.0.2.63',1224778510,0,'NO'),(1495,250,'state','Alive',1224778510,0,'NO'),(1496,250,'core ','250',1224778510,0,'NO'),(1497,250,'cpu ','125',1224778510,0,'NO'),(1498,250,'host ','node-63',1224778510,0,'NO'),(1499,250,'cpuset','1',1224778510,0,'NO'),(1500,250,'network_address','127.0.2.63',1224778510,0,'NO'),(1501,251,'state','Alive',1224778511,0,'NO'),(1502,251,'core ','251',1224778511,0,'NO'),(1503,251,'cpu ','126',1224778511,0,'NO'),(1504,251,'host ','node-63',1224778511,0,'NO'),(1505,251,'cpuset','2',1224778511,0,'NO'),(1506,251,'network_address','127.0.2.63',1224778511,0,'NO'),(1507,252,'state','Alive',1224778511,0,'NO'),(1508,252,'core ','252',1224778511,0,'NO'),(1509,252,'cpu ','126',1224778511,0,'NO'),(1510,252,'host ','node-63',1224778511,0,'NO'),(1511,252,'cpuset','3',1224778511,0,'NO'),(1512,252,'network_address','127.0.2.63',1224778511,0,'NO'),(1513,253,'state','Alive',1224778511,0,'NO'),(1514,253,'core ','253',1224778511,0,'NO'),(1515,253,'cpu ','127',1224778511,0,'NO'),(1516,253,'host ','node-64',1224778511,0,'NO'),(1517,253,'cpuset','0',1224778511,0,'NO'),(1518,253,'network_address','127.0.2.64',1224778511,0,'NO'),(1519,254,'state','Alive',1224778511,0,'NO'),(1520,254,'core ','254',1224778511,0,'NO'),(1521,254,'cpu ','127',1224778511,0,'NO'),(1522,254,'host ','node-64',1224778511,0,'NO'),(1523,254,'cpuset','1',1224778511,0,'NO'),(1524,254,'network_address','127.0.2.64',1224778511,0,'NO'),(1525,255,'state','Alive',1224778511,0,'NO'),(1526,255,'core ','255',1224778511,0,'NO'),(1527,255,'cpu ','128',1224778511,0,'NO'),(1528,255,'host ','node-64',1224778511,0,'NO'),(1529,255,'cpuset','2',1224778511,0,'NO'),(1530,255,'network_address','127.0.2.64',1224778511,0,'NO'),(1531,256,'state','Alive',1224778512,0,'NO'),(1532,256,'core ','256',1224778512,0,'NO'),(1533,256,'cpu ','128',1224778512,0,'NO'),(1534,256,'host ','node-64',1224778512,0,'NO'),(1535,256,'cpuset','3',1224778512,0,'NO'),(1536,256,'network_address','127.0.2.64',1224778512,0,'NO'),(1537,257,'state','Alive',1224778512,0,'NO'),(1538,257,'core ','257',1224778512,0,'NO'),(1539,257,'cpu ','129',1224778512,0,'NO'),(1540,257,'host ','node-65',1224778512,0,'NO'),(1541,257,'cpuset','0',1224778512,0,'NO'),(1542,257,'network_address','127.0.2.65',1224778512,0,'NO'),(1543,258,'state','Alive',1224778512,0,'NO'),(1544,258,'core ','258',1224778512,0,'NO'),(1545,258,'cpu ','129',1224778512,0,'NO'),(1546,258,'host ','node-65',1224778512,0,'NO'),(1547,258,'cpuset','1',1224778512,0,'NO'),(1548,258,'network_address','127.0.2.65',1224778512,0,'NO'),(1549,259,'state','Alive',1224778512,0,'NO'),(1550,259,'core ','259',1224778512,0,'NO'),(1551,259,'cpu ','130',1224778512,0,'NO'),(1552,259,'host ','node-65',1224778512,0,'NO'),(1553,259,'cpuset','2',1224778512,0,'NO'),(1554,259,'network_address','127.0.2.65',1224778512,0,'NO'),(1555,260,'state','Alive',1224778512,0,'NO'),(1556,260,'core ','260',1224778512,0,'NO'),(1557,260,'cpu ','130',1224778512,0,'NO'),(1558,260,'host ','node-65',1224778512,0,'NO'),(1559,260,'cpuset','3',1224778512,0,'NO'),(1560,260,'network_address','127.0.2.65',1224778512,0,'NO'),(1561,261,'state','Alive',1224778512,0,'NO'),(1562,261,'core ','261',1224778512,0,'NO'),(1563,261,'cpu ','131',1224778512,0,'NO'),(1564,261,'host ','node-66',1224778512,0,'NO'),(1565,261,'cpuset','0',1224778512,0,'NO'),(1566,261,'network_address','127.0.2.66',1224778512,0,'NO'),(1567,262,'state','Alive',1224778513,0,'NO'),(1568,262,'core ','262',1224778513,0,'NO'),(1569,262,'cpu ','131',1224778513,0,'NO'),(1570,262,'host ','node-66',1224778513,0,'NO'),(1571,262,'cpuset','1',1224778513,0,'NO'),(1572,262,'network_address','127.0.2.66',1224778513,0,'NO'),(1573,263,'state','Alive',1224778513,0,'NO'),(1574,263,'core ','263',1224778513,0,'NO'),(1575,263,'cpu ','132',1224778513,0,'NO'),(1576,263,'host ','node-66',1224778513,0,'NO'),(1577,263,'cpuset','2',1224778513,0,'NO'),(1578,263,'network_address','127.0.2.66',1224778513,0,'NO'),(1579,264,'state','Alive',1224778513,0,'NO'),(1580,264,'core ','264',1224778513,0,'NO'),(1581,264,'cpu ','132',1224778513,0,'NO'),(1582,264,'host ','node-66',1224778513,0,'NO'),(1583,264,'cpuset','3',1224778513,0,'NO'),(1584,264,'network_address','127.0.2.66',1224778513,0,'NO'),(1585,265,'state','Alive',1224778513,0,'NO'),(1586,265,'core ','265',1224778513,0,'NO'),(1587,265,'cpu ','133',1224778513,0,'NO'),(1588,265,'host ','node-67',1224778513,0,'NO'),(1589,265,'cpuset','0',1224778513,0,'NO'),(1590,265,'network_address','127.0.2.67',1224778513,0,'NO'),(1591,266,'state','Alive',1224778513,0,'NO'),(1592,266,'core ','266',1224778513,0,'NO'),(1593,266,'cpu ','133',1224778513,0,'NO'),(1594,266,'host ','node-67',1224778513,0,'NO'),(1595,266,'cpuset','1',1224778513,0,'NO'),(1596,266,'network_address','127.0.2.67',1224778513,0,'NO'),(1597,267,'state','Alive',1224778514,0,'NO'),(1598,267,'core ','267',1224778514,0,'NO'),(1599,267,'cpu ','134',1224778514,0,'NO'),(1600,267,'host ','node-67',1224778514,0,'NO'),(1601,267,'cpuset','2',1224778514,0,'NO'),(1602,267,'network_address','127.0.2.67',1224778514,0,'NO'),(1603,268,'state','Alive',1224778514,0,'NO'),(1604,268,'core ','268',1224778514,0,'NO'),(1605,268,'cpu ','134',1224778514,0,'NO'),(1606,268,'host ','node-67',1224778514,0,'NO'),(1607,268,'cpuset','3',1224778514,0,'NO'),(1608,268,'network_address','127.0.2.67',1224778514,0,'NO'),(1609,269,'state','Alive',1224778514,0,'NO'),(1610,269,'core ','269',1224778514,0,'NO'),(1611,269,'cpu ','135',1224778514,0,'NO'),(1612,269,'host ','node-68',1224778514,0,'NO'),(1613,269,'cpuset','0',1224778514,0,'NO'),(1614,269,'network_address','127.0.2.68',1224778514,0,'NO'),(1615,270,'state','Alive',1224778514,0,'NO'),(1616,270,'core ','270',1224778514,0,'NO'),(1617,270,'cpu ','135',1224778514,0,'NO'),(1618,270,'host ','node-68',1224778514,0,'NO'),(1619,270,'cpuset','1',1224778514,0,'NO'),(1620,270,'network_address','127.0.2.68',1224778514,0,'NO'),(1621,271,'state','Alive',1224778514,0,'NO'),(1622,271,'core ','271',1224778514,0,'NO'),(1623,271,'cpu ','136',1224778514,0,'NO'),(1624,271,'host ','node-68',1224778514,0,'NO'),(1625,271,'cpuset','2',1224778514,0,'NO'),(1626,271,'network_address','127.0.2.68',1224778514,0,'NO'),(1627,272,'state','Alive',1224778515,0,'NO'),(1628,272,'core ','272',1224778515,0,'NO'),(1629,272,'cpu ','136',1224778515,0,'NO'),(1630,272,'host ','node-68',1224778515,0,'NO'),(1631,272,'cpuset','3',1224778515,0,'NO'),(1632,272,'network_address','127.0.2.68',1224778515,0,'NO'),(1633,273,'state','Alive',1224778515,0,'NO'),(1634,273,'core ','273',1224778515,0,'NO'),(1635,273,'cpu ','137',1224778515,0,'NO'),(1636,273,'host ','node-69',1224778515,0,'NO'),(1637,273,'cpuset','0',1224778515,0,'NO'),(1638,273,'network_address','127.0.2.69',1224778515,0,'NO'),(1639,274,'state','Alive',1224778515,0,'NO'),(1640,274,'core ','274',1224778515,0,'NO'),(1641,274,'cpu ','137',1224778515,0,'NO'),(1642,274,'host ','node-69',1224778515,0,'NO'),(1643,274,'cpuset','1',1224778515,0,'NO'),(1644,274,'network_address','127.0.2.69',1224778515,0,'NO'),(1645,275,'state','Alive',1224778515,0,'NO'),(1646,275,'core ','275',1224778515,0,'NO'),(1647,275,'cpu ','138',1224778515,0,'NO'),(1648,275,'host ','node-69',1224778515,0,'NO'),(1649,275,'cpuset','2',1224778515,0,'NO'),(1650,275,'network_address','127.0.2.69',1224778515,0,'NO'),(1651,276,'state','Alive',1224778515,0,'NO'),(1652,276,'core ','276',1224778515,0,'NO'),(1653,276,'cpu ','138',1224778515,0,'NO'),(1654,276,'host ','node-69',1224778515,0,'NO'),(1655,276,'cpuset','3',1224778515,0,'NO'),(1656,276,'network_address','127.0.2.69',1224778515,0,'NO'),(1657,277,'state','Alive',1224778516,0,'NO'),(1658,277,'core ','277',1224778516,0,'NO'),(1659,277,'cpu ','139',1224778516,0,'NO'),(1660,277,'host ','node-70',1224778516,0,'NO'),(1661,277,'cpuset','0',1224778516,0,'NO'),(1662,277,'network_address','127.0.2.70',1224778516,0,'NO'),(1663,278,'state','Alive',1224778516,0,'NO'),(1664,278,'core ','278',1224778516,0,'NO'),(1665,278,'cpu ','139',1224778516,0,'NO'),(1666,278,'host ','node-70',1224778516,0,'NO'),(1667,278,'cpuset','1',1224778516,0,'NO'),(1668,278,'network_address','127.0.2.70',1224778516,0,'NO'),(1669,279,'state','Alive',1224778516,0,'NO'),(1670,279,'core ','279',1224778516,0,'NO'),(1671,279,'cpu ','140',1224778516,0,'NO'),(1672,279,'host ','node-70',1224778516,0,'NO'),(1673,279,'cpuset','2',1224778516,0,'NO'),(1674,279,'network_address','127.0.2.70',1224778516,0,'NO'),(1675,280,'state','Alive',1224778516,0,'NO'),(1676,280,'core ','280',1224778516,0,'NO'),(1677,280,'cpu ','140',1224778516,0,'NO'),(1678,280,'host ','node-70',1224778516,0,'NO'),(1679,280,'cpuset','3',1224778516,0,'NO'),(1680,280,'network_address','127.0.2.70',1224778516,0,'NO'),(1681,281,'state','Alive',1224778516,0,'NO'),(1682,281,'core ','281',1224778516,0,'NO'),(1683,281,'cpu ','141',1224778516,0,'NO'),(1684,281,'host ','node-71',1224778516,0,'NO'),(1685,281,'cpuset','0',1224778516,0,'NO'),(1686,281,'network_address','127.0.2.71',1224778516,0,'NO'),(1687,282,'state','Alive',1224778516,0,'NO'),(1688,282,'core ','282',1224778516,0,'NO'),(1689,282,'cpu ','141',1224778516,0,'NO'),(1690,282,'host ','node-71',1224778516,0,'NO'),(1691,282,'cpuset','1',1224778516,0,'NO'),(1692,282,'network_address','127.0.2.71',1224778516,0,'NO'),(1693,283,'state','Alive',1224778517,0,'NO'),(1694,283,'core ','283',1224778517,0,'NO'),(1695,283,'cpu ','142',1224778517,0,'NO'),(1696,283,'host ','node-71',1224778517,0,'NO'),(1697,283,'cpuset','2',1224778517,0,'NO'),(1698,283,'network_address','127.0.2.71',1224778517,0,'NO'),(1699,284,'state','Alive',1224778517,0,'NO'),(1700,284,'core ','284',1224778517,0,'NO'),(1701,284,'cpu ','142',1224778517,0,'NO'),(1702,284,'host ','node-71',1224778517,0,'NO'),(1703,284,'cpuset','3',1224778517,0,'NO'),(1704,284,'network_address','127.0.2.71',1224778517,0,'NO'),(1705,285,'state','Alive',1224778517,0,'NO'),(1706,285,'core ','285',1224778517,0,'NO'),(1707,285,'cpu ','143',1224778517,0,'NO'),(1708,285,'host ','node-72',1224778517,0,'NO'),(1709,285,'cpuset','0',1224778517,0,'NO'),(1710,285,'network_address','127.0.2.72',1224778517,0,'NO'),(1711,286,'state','Alive',1224778517,0,'NO'),(1712,286,'core ','286',1224778517,0,'NO'),(1713,286,'cpu ','143',1224778517,0,'NO'),(1714,286,'host ','node-72',1224778517,0,'NO'),(1715,286,'cpuset','1',1224778517,0,'NO'),(1716,286,'network_address','127.0.2.72',1224778517,0,'NO'),(1717,287,'state','Alive',1224778517,0,'NO'),(1718,287,'core ','287',1224778517,0,'NO'),(1719,287,'cpu ','144',1224778517,0,'NO'),(1720,287,'host ','node-72',1224778517,0,'NO'),(1721,287,'cpuset','2',1224778517,0,'NO'),(1722,287,'network_address','127.0.2.72',1224778517,0,'NO'),(1723,288,'state','Alive',1224778518,0,'NO'),(1724,288,'core ','288',1224778518,0,'NO'),(1725,288,'cpu ','144',1224778518,0,'NO'),(1726,288,'host ','node-72',1224778518,0,'NO'),(1727,288,'cpuset','3',1224778518,0,'NO'),(1728,288,'network_address','127.0.2.72',1224778518,0,'NO'),(1729,289,'state','Alive',1224778518,0,'NO'),(1730,289,'core ','289',1224778518,0,'NO'),(1731,289,'cpu ','145',1224778518,0,'NO'),(1732,289,'host ','node-73',1224778518,0,'NO'),(1733,289,'cpuset','0',1224778518,0,'NO'),(1734,289,'network_address','127.0.2.73',1224778518,0,'NO'),(1735,290,'state','Alive',1224778518,0,'NO'),(1736,290,'core ','290',1224778518,0,'NO'),(1737,290,'cpu ','145',1224778518,0,'NO'),(1738,290,'host ','node-73',1224778518,0,'NO'),(1739,290,'cpuset','1',1224778518,0,'NO'),(1740,290,'network_address','127.0.2.73',1224778518,0,'NO'),(1741,291,'state','Alive',1224778518,0,'NO'),(1742,291,'core ','291',1224778518,0,'NO'),(1743,291,'cpu ','146',1224778518,0,'NO'),(1744,291,'host ','node-73',1224778518,0,'NO'),(1745,291,'cpuset','2',1224778518,0,'NO'),(1746,291,'network_address','127.0.2.73',1224778518,0,'NO'),(1747,292,'state','Alive',1224778518,0,'NO'),(1748,292,'core ','292',1224778518,0,'NO'),(1749,292,'cpu ','146',1224778518,0,'NO'),(1750,292,'host ','node-73',1224778518,0,'NO'),(1751,292,'cpuset','3',1224778518,0,'NO'),(1752,292,'network_address','127.0.2.73',1224778518,0,'NO'),(1753,293,'state','Alive',1224778519,0,'NO'),(1754,293,'core ','293',1224778519,0,'NO'),(1755,293,'cpu ','147',1224778519,0,'NO'),(1756,293,'host ','node-74',1224778519,0,'NO'),(1757,293,'cpuset','0',1224778519,0,'NO'),(1758,293,'network_address','127.0.2.74',1224778519,0,'NO'),(1759,294,'state','Alive',1224778519,0,'NO'),(1760,294,'core ','294',1224778519,0,'NO'),(1761,294,'cpu ','147',1224778519,0,'NO'),(1762,294,'host ','node-74',1224778519,0,'NO'),(1763,294,'cpuset','1',1224778519,0,'NO'),(1764,294,'network_address','127.0.2.74',1224778519,0,'NO'),(1765,295,'state','Alive',1224778519,0,'NO'),(1766,295,'core ','295',1224778519,0,'NO'),(1767,295,'cpu ','148',1224778519,0,'NO'),(1768,295,'host ','node-74',1224778519,0,'NO'),(1769,295,'cpuset','2',1224778519,0,'NO'),(1770,295,'network_address','127.0.2.74',1224778519,0,'NO'),(1771,296,'state','Alive',1224778519,0,'NO'),(1772,296,'core ','296',1224778519,0,'NO'),(1773,296,'cpu ','148',1224778519,0,'NO'),(1774,296,'host ','node-74',1224778519,0,'NO'),(1775,296,'cpuset','3',1224778519,0,'NO'),(1776,296,'network_address','127.0.2.74',1224778519,0,'NO'),(1777,297,'state','Alive',1224778519,0,'NO'),(1778,297,'core ','297',1224778519,0,'NO'),(1779,297,'cpu ','149',1224778519,0,'NO'),(1780,297,'host ','node-75',1224778519,0,'NO'),(1781,297,'cpuset','0',1224778519,0,'NO'),(1782,297,'network_address','127.0.2.75',1224778519,0,'NO'),(1783,298,'state','Alive',1224778520,0,'NO'),(1784,298,'core ','298',1224778520,0,'NO'),(1785,298,'cpu ','149',1224778520,0,'NO'),(1786,298,'host ','node-75',1224778520,0,'NO'),(1787,298,'cpuset','1',1224778520,0,'NO'),(1788,298,'network_address','127.0.2.75',1224778520,0,'NO'),(1789,299,'state','Alive',1224778520,0,'NO'),(1790,299,'core ','299',1224778520,0,'NO'),(1791,299,'cpu ','150',1224778520,0,'NO'),(1792,299,'host ','node-75',1224778520,0,'NO'),(1793,299,'cpuset','2',1224778520,0,'NO'),(1794,299,'network_address','127.0.2.75',1224778520,0,'NO'),(1795,300,'state','Alive',1224778520,0,'NO'),(1796,300,'core ','300',1224778520,0,'NO'),(1797,300,'cpu ','150',1224778520,0,'NO'),(1798,300,'host ','node-75',1224778520,0,'NO'),(1799,300,'cpuset','3',1224778520,0,'NO'),(1800,300,'network_address','127.0.2.75',1224778520,0,'NO'),(1801,301,'state','Alive',1224778520,0,'NO'),(1802,301,'core ','301',1224778520,0,'NO'),(1803,301,'cpu ','151',1224778520,0,'NO'),(1804,301,'host ','node-76',1224778520,0,'NO'),(1805,301,'cpuset','0',1224778520,0,'NO'),(1806,301,'network_address','127.0.2.76',1224778520,0,'NO'),(1807,302,'state','Alive',1224778520,0,'NO'),(1808,302,'core ','302',1224778520,0,'NO'),(1809,302,'cpu ','151',1224778520,0,'NO'),(1810,302,'host ','node-76',1224778520,0,'NO'),(1811,302,'cpuset','1',1224778520,0,'NO'),(1812,302,'network_address','127.0.2.76',1224778520,0,'NO'),(1813,303,'state','Alive',1224778521,0,'NO'),(1814,303,'core ','303',1224778521,0,'NO'),(1815,303,'cpu ','152',1224778521,0,'NO'),(1816,303,'host ','node-76',1224778521,0,'NO'),(1817,303,'cpuset','2',1224778521,0,'NO'),(1818,303,'network_address','127.0.2.76',1224778521,0,'NO'),(1819,304,'state','Alive',1224778521,0,'NO'),(1820,304,'core ','304',1224778521,0,'NO'),(1821,304,'cpu ','152',1224778521,0,'NO'),(1822,304,'host ','node-76',1224778521,0,'NO'),(1823,304,'cpuset','3',1224778521,0,'NO'),(1824,304,'network_address','127.0.2.76',1224778521,0,'NO'),(1825,305,'state','Alive',1224778521,0,'NO'),(1826,305,'core ','305',1224778521,0,'NO'),(1827,305,'cpu ','153',1224778521,0,'NO'),(1828,305,'host ','node-77',1224778521,0,'NO'),(1829,305,'cpuset','0',1224778521,0,'NO'),(1830,305,'network_address','127.0.2.77',1224778521,0,'NO'),(1831,306,'state','Alive',1224778521,0,'NO'),(1832,306,'core ','306',1224778521,0,'NO'),(1833,306,'cpu ','153',1224778521,0,'NO'),(1834,306,'host ','node-77',1224778521,0,'NO'),(1835,306,'cpuset','1',1224778521,0,'NO'),(1836,306,'network_address','127.0.2.77',1224778521,0,'NO'),(1837,307,'state','Alive',1224778521,0,'NO'),(1838,307,'core ','307',1224778521,0,'NO'),(1839,307,'cpu ','154',1224778521,0,'NO'),(1840,307,'host ','node-77',1224778521,0,'NO'),(1841,307,'cpuset','2',1224778521,0,'NO'),(1842,307,'network_address','127.0.2.77',1224778521,0,'NO'),(1843,308,'state','Alive',1224778521,0,'NO'),(1844,308,'core ','308',1224778521,0,'NO'),(1845,308,'cpu ','154',1224778521,0,'NO'),(1846,308,'host ','node-77',1224778521,0,'NO'),(1847,308,'cpuset','3',1224778521,0,'NO'),(1848,308,'network_address','127.0.2.77',1224778521,0,'NO'),(1849,309,'state','Alive',1224778522,0,'NO'),(1850,309,'core ','309',1224778522,0,'NO'),(1851,309,'cpu ','155',1224778522,0,'NO'),(1852,309,'host ','node-78',1224778522,0,'NO'),(1853,309,'cpuset','0',1224778522,0,'NO'),(1854,309,'network_address','127.0.2.78',1224778522,0,'NO'),(1855,310,'state','Alive',1224778522,0,'NO'),(1856,310,'core ','310',1224778522,0,'NO'),(1857,310,'cpu ','155',1224778522,0,'NO'),(1858,310,'host ','node-78',1224778522,0,'NO'),(1859,310,'cpuset','1',1224778522,0,'NO'),(1860,310,'network_address','127.0.2.78',1224778522,0,'NO'),(1861,311,'state','Alive',1224778522,0,'NO'),(1862,311,'core ','311',1224778522,0,'NO'),(1863,311,'cpu ','156',1224778522,0,'NO'),(1864,311,'host ','node-78',1224778522,0,'NO'),(1865,311,'cpuset','2',1224778522,0,'NO'),(1866,311,'network_address','127.0.2.78',1224778522,0,'NO'),(1867,312,'state','Alive',1224778522,0,'NO'),(1868,312,'core ','312',1224778522,0,'NO'),(1869,312,'cpu ','156',1224778522,0,'NO'),(1870,312,'host ','node-78',1224778522,0,'NO'),(1871,312,'cpuset','3',1224778522,0,'NO'),(1872,312,'network_address','127.0.2.78',1224778522,0,'NO'),(1873,313,'state','Alive',1224778522,0,'NO'),(1874,313,'core ','313',1224778522,0,'NO'),(1875,313,'cpu ','157',1224778522,0,'NO'),(1876,313,'host ','node-79',1224778522,0,'NO'),(1877,313,'cpuset','0',1224778522,0,'NO'),(1878,313,'network_address','127.0.2.79',1224778522,0,'NO'),(1879,314,'state','Alive',1224778523,0,'NO'),(1880,314,'core ','314',1224778523,0,'NO'),(1881,314,'cpu ','157',1224778523,0,'NO'),(1882,314,'host ','node-79',1224778523,0,'NO'),(1883,314,'cpuset','1',1224778523,0,'NO'),(1884,314,'network_address','127.0.2.79',1224778523,0,'NO'),(1885,315,'state','Alive',1224778523,0,'NO'),(1886,315,'core ','315',1224778523,0,'NO'),(1887,315,'cpu ','158',1224778523,0,'NO'),(1888,315,'host ','node-79',1224778523,0,'NO'),(1889,315,'cpuset','2',1224778523,0,'NO'),(1890,315,'network_address','127.0.2.79',1224778523,0,'NO'),(1891,316,'state','Alive',1224778523,0,'NO'),(1892,316,'core ','316',1224778523,0,'NO'),(1893,316,'cpu ','158',1224778523,0,'NO'),(1894,316,'host ','node-79',1224778523,0,'NO'),(1895,316,'cpuset','3',1224778523,0,'NO'),(1896,316,'network_address','127.0.2.79',1224778523,0,'NO'),(1897,317,'state','Alive',1224778523,0,'NO'),(1898,317,'core ','317',1224778523,0,'NO'),(1899,317,'cpu ','159',1224778523,0,'NO'),(1900,317,'host ','node-80',1224778523,0,'NO'),(1901,317,'cpuset','0',1224778523,0,'NO'),(1902,317,'network_address','127.0.2.80',1224778523,0,'NO'),(1903,318,'state','Alive',1224778524,0,'NO'),(1904,318,'core ','318',1224778524,0,'NO'),(1905,318,'cpu ','159',1224778524,0,'NO'),(1906,318,'host ','node-80',1224778524,0,'NO'),(1907,318,'cpuset','1',1224778524,0,'NO'),(1908,318,'network_address','127.0.2.80',1224778524,0,'NO'),(1909,319,'state','Alive',1224778524,0,'NO'),(1910,319,'core ','319',1224778524,0,'NO'),(1911,319,'cpu ','160',1224778524,0,'NO'),(1912,319,'host ','node-80',1224778524,0,'NO'),(1913,319,'cpuset','2',1224778524,0,'NO'),(1914,319,'network_address','127.0.2.80',1224778524,0,'NO'),(1915,320,'state','Alive',1224778524,0,'NO'),(1916,320,'core ','320',1224778524,0,'NO'),(1917,320,'cpu ','160',1224778524,0,'NO'),(1918,320,'host ','node-80',1224778524,0,'NO'),(1919,320,'cpuset','3',1224778524,0,'NO'),(1920,320,'network_address','127.0.2.80',1224778524,0,'NO'),(1921,321,'state','Alive',1224778524,0,'NO'),(1922,321,'core ','321',1224778524,0,'NO'),(1923,321,'cpu ','161',1224778524,0,'NO'),(1924,321,'host ','node-81',1224778524,0,'NO'),(1925,321,'cpuset','0',1224778524,0,'NO'),(1926,321,'network_address','127.0.2.81',1224778524,0,'NO'),(1927,322,'state','Alive',1224778525,0,'NO'),(1928,322,'core ','322',1224778525,0,'NO'),(1929,322,'cpu ','161',1224778525,0,'NO'),(1930,322,'host ','node-81',1224778525,0,'NO'),(1931,322,'cpuset','1',1224778525,0,'NO'),(1932,322,'network_address','127.0.2.81',1224778525,0,'NO'),(1933,323,'state','Alive',1224778525,0,'NO'),(1934,323,'core ','323',1224778525,0,'NO'),(1935,323,'cpu ','162',1224778525,0,'NO'),(1936,323,'host ','node-81',1224778525,0,'NO'),(1937,323,'cpuset','2',1224778525,0,'NO'),(1938,323,'network_address','127.0.2.81',1224778525,0,'NO'),(1939,324,'state','Alive',1224778525,0,'NO'),(1940,324,'core ','324',1224778525,0,'NO'),(1941,324,'cpu ','162',1224778525,0,'NO'),(1942,324,'host ','node-81',1224778525,0,'NO'),(1943,324,'cpuset','3',1224778525,0,'NO'),(1944,324,'network_address','127.0.2.81',1224778525,0,'NO'),(1945,325,'state','Alive',1224778525,0,'NO'),(1946,325,'core ','325',1224778525,0,'NO'),(1947,325,'cpu ','163',1224778525,0,'NO'),(1948,325,'host ','node-82',1224778525,0,'NO'),(1949,325,'cpuset','0',1224778525,0,'NO'),(1950,325,'network_address','127.0.2.82',1224778525,0,'NO'),(1951,326,'state','Alive',1224778525,0,'NO'),(1952,326,'core ','326',1224778525,0,'NO'),(1953,326,'cpu ','163',1224778525,0,'NO'),(1954,326,'host ','node-82',1224778525,0,'NO'),(1955,326,'cpuset','1',1224778525,0,'NO'),(1956,326,'network_address','127.0.2.82',1224778525,0,'NO'),(1957,327,'state','Alive',1224778525,0,'NO'),(1958,327,'core ','327',1224778525,0,'NO'),(1959,327,'cpu ','164',1224778525,0,'NO'),(1960,327,'host ','node-82',1224778525,0,'NO'),(1961,327,'cpuset','2',1224778526,0,'NO'),(1962,327,'network_address','127.0.2.82',1224778526,0,'NO'),(1963,328,'state','Alive',1224778526,0,'NO'),(1964,328,'core ','328',1224778526,0,'NO'),(1965,328,'cpu ','164',1224778526,0,'NO'),(1966,328,'host ','node-82',1224778526,0,'NO'),(1967,328,'cpuset','3',1224778526,0,'NO'),(1968,328,'network_address','127.0.2.82',1224778526,0,'NO'),(1969,329,'state','Alive',1224778526,0,'NO'),(1970,329,'core ','329',1224778526,0,'NO'),(1971,329,'cpu ','165',1224778526,0,'NO'),(1972,329,'host ','node-83',1224778526,0,'NO'),(1973,329,'cpuset','0',1224778526,0,'NO'),(1974,329,'network_address','127.0.2.83',1224778526,0,'NO'),(1975,330,'state','Alive',1224778526,0,'NO'),(1976,330,'core ','330',1224778526,0,'NO'),(1977,330,'cpu ','165',1224778526,0,'NO'),(1978,330,'host ','node-83',1224778526,0,'NO'),(1979,330,'cpuset','1',1224778526,0,'NO'),(1980,330,'network_address','127.0.2.83',1224778526,0,'NO'),(1981,331,'state','Alive',1224778526,0,'NO'),(1982,331,'core ','331',1224778526,0,'NO'),(1983,331,'cpu ','166',1224778526,0,'NO'),(1984,331,'host ','node-83',1224778526,0,'NO'),(1985,331,'cpuset','2',1224778526,0,'NO'),(1986,331,'network_address','127.0.2.83',1224778526,0,'NO'),(1987,332,'state','Alive',1224778526,0,'NO'),(1988,332,'core ','332',1224778526,0,'NO'),(1989,332,'cpu ','166',1224778526,0,'NO'),(1990,332,'host ','node-83',1224778526,0,'NO'),(1991,332,'cpuset','3',1224778526,0,'NO'),(1992,332,'network_address','127.0.2.83',1224778526,0,'NO'),(1993,333,'state','Alive',1224778527,0,'NO'),(1994,333,'core ','333',1224778527,0,'NO'),(1995,333,'cpu ','167',1224778527,0,'NO'),(1996,333,'host ','node-84',1224778527,0,'NO'),(1997,333,'cpuset','0',1224778527,0,'NO'),(1998,333,'network_address','127.0.2.84',1224778527,0,'NO'),(1999,334,'state','Alive',1224778527,0,'NO'),(2000,334,'core ','334',1224778527,0,'NO'),(2001,334,'cpu ','167',1224778527,0,'NO'),(2002,334,'host ','node-84',1224778527,0,'NO'),(2003,334,'cpuset','1',1224778527,0,'NO'),(2004,334,'network_address','127.0.2.84',1224778527,0,'NO'),(2005,335,'state','Alive',1224778527,0,'NO'),(2006,335,'core ','335',1224778527,0,'NO'),(2007,335,'cpu ','168',1224778527,0,'NO'),(2008,335,'host ','node-84',1224778527,0,'NO'),(2009,335,'cpuset','2',1224778527,0,'NO'),(2010,335,'network_address','127.0.2.84',1224778527,0,'NO'),(2011,336,'state','Alive',1224778527,0,'NO'),(2012,336,'core ','336',1224778527,0,'NO'),(2013,336,'cpu ','168',1224778527,0,'NO'),(2014,336,'host ','node-84',1224778527,0,'NO'),(2015,336,'cpuset','3',1224778527,0,'NO'),(2016,336,'network_address','127.0.2.84',1224778527,0,'NO'),(2017,337,'state','Alive',1224778527,0,'NO'),(2018,337,'core ','337',1224778527,0,'NO'),(2019,337,'cpu ','169',1224778527,0,'NO'),(2020,337,'host ','node-85',1224778527,0,'NO'),(2021,337,'cpuset','0',1224778527,0,'NO'),(2022,337,'network_address','127.0.2.85',1224778527,0,'NO'),(2023,338,'state','Alive',1224778528,0,'NO'),(2024,338,'core ','338',1224778528,0,'NO'),(2025,338,'cpu ','169',1224778528,0,'NO'),(2026,338,'host ','node-85',1224778528,0,'NO'),(2027,338,'cpuset','1',1224778528,0,'NO'),(2028,338,'network_address','127.0.2.85',1224778528,0,'NO'),(2029,339,'state','Alive',1224778528,0,'NO'),(2030,339,'core ','339',1224778528,0,'NO'),(2031,339,'cpu ','170',1224778528,0,'NO'),(2032,339,'host ','node-85',1224778528,0,'NO'),(2033,339,'cpuset','2',1224778528,0,'NO'),(2034,339,'network_address','127.0.2.85',1224778528,0,'NO'),(2035,340,'state','Alive',1224778528,0,'NO'),(2036,340,'core ','340',1224778528,0,'NO'),(2037,340,'cpu ','170',1224778528,0,'NO'),(2038,340,'host ','node-85',1224778528,0,'NO'),(2039,340,'cpuset','3',1224778528,0,'NO'),(2040,340,'network_address','127.0.2.85',1224778528,0,'NO'),(2041,341,'state','Alive',1224778528,0,'NO'),(2042,341,'core ','341',1224778528,0,'NO'),(2043,341,'cpu ','171',1224778528,0,'NO'),(2044,341,'host ','node-86',1224778528,0,'NO'),(2045,341,'cpuset','0',1224778528,0,'NO'),(2046,341,'network_address','127.0.2.86',1224778528,0,'NO'),(2047,342,'state','Alive',1224778528,0,'NO'),(2048,342,'core ','342',1224778528,0,'NO'),(2049,342,'cpu ','171',1224778528,0,'NO'),(2050,342,'host ','node-86',1224778528,0,'NO'),(2051,342,'cpuset','1',1224778528,0,'NO'),(2052,342,'network_address','127.0.2.86',1224778528,0,'NO'),(2053,343,'state','Alive',1224778529,0,'NO'),(2054,343,'core ','343',1224778529,0,'NO'),(2055,343,'cpu ','172',1224778529,0,'NO'),(2056,343,'host ','node-86',1224778529,0,'NO'),(2057,343,'cpuset','2',1224778529,0,'NO'),(2058,343,'network_address','127.0.2.86',1224778529,0,'NO'),(2059,344,'state','Alive',1224778529,0,'NO'),(2060,344,'core ','344',1224778529,0,'NO'),(2061,344,'cpu ','172',1224778529,0,'NO'),(2062,344,'host ','node-86',1224778529,0,'NO'),(2063,344,'cpuset','3',1224778529,0,'NO'),(2064,344,'network_address','127.0.2.86',1224778529,0,'NO'),(2065,345,'state','Alive',1224778529,0,'NO'),(2066,345,'core ','345',1224778529,0,'NO'),(2067,345,'cpu ','173',1224778529,0,'NO'),(2068,345,'host ','node-87',1224778529,0,'NO'),(2069,345,'cpuset','0',1224778529,0,'NO'),(2070,345,'network_address','127.0.2.87',1224778529,0,'NO'),(2071,346,'state','Alive',1224778529,0,'NO'),(2072,346,'core ','346',1224778529,0,'NO'),(2073,346,'cpu ','173',1224778529,0,'NO'),(2074,346,'host ','node-87',1224778529,0,'NO'),(2075,346,'cpuset','1',1224778529,0,'NO'),(2076,346,'network_address','127.0.2.87',1224778529,0,'NO'),(2077,347,'state','Alive',1224778529,0,'NO'),(2078,347,'core ','347',1224778529,0,'NO'),(2079,347,'cpu ','174',1224778529,0,'NO'),(2080,347,'host ','node-87',1224778529,0,'NO'),(2081,347,'cpuset','2',1224778529,0,'NO'),(2082,347,'network_address','127.0.2.87',1224778529,0,'NO'),(2083,348,'state','Alive',1224778530,0,'NO'),(2084,348,'core ','348',1224778530,0,'NO'),(2085,348,'cpu ','174',1224778530,0,'NO'),(2086,348,'host ','node-87',1224778530,0,'NO'),(2087,348,'cpuset','3',1224778530,0,'NO'),(2088,348,'network_address','127.0.2.87',1224778530,0,'NO'),(2089,349,'state','Alive',1224778530,0,'NO'),(2090,349,'core ','349',1224778530,0,'NO'),(2091,349,'cpu ','175',1224778530,0,'NO'),(2092,349,'host ','node-88',1224778530,0,'NO'),(2093,349,'cpuset','0',1224778530,0,'NO'),(2094,349,'network_address','127.0.2.88',1224778530,0,'NO'),(2095,350,'state','Alive',1224778530,0,'NO'),(2096,350,'core ','350',1224778530,0,'NO'),(2097,350,'cpu ','175',1224778530,0,'NO'),(2098,350,'host ','node-88',1224778530,0,'NO'),(2099,350,'cpuset','1',1224778530,0,'NO'),(2100,350,'network_address','127.0.2.88',1224778530,0,'NO'),(2101,351,'state','Alive',1224778530,0,'NO'),(2102,351,'core ','351',1224778530,0,'NO'),(2103,351,'cpu ','176',1224778530,0,'NO'),(2104,351,'host ','node-88',1224778530,0,'NO'),(2105,351,'cpuset','2',1224778530,0,'NO'),(2106,351,'network_address','127.0.2.88',1224778530,0,'NO'),(2107,352,'state','Alive',1224778530,0,'NO'),(2108,352,'core ','352',1224778530,0,'NO'),(2109,352,'cpu ','176',1224778530,0,'NO'),(2110,352,'host ','node-88',1224778530,0,'NO'),(2111,352,'cpuset','3',1224778530,0,'NO'),(2112,352,'network_address','127.0.2.88',1224778530,0,'NO'),(2113,353,'state','Alive',1224778530,0,'NO'),(2114,353,'core ','353',1224778530,0,'NO'),(2115,353,'cpu ','177',1224778530,0,'NO'),(2116,353,'host ','node-89',1224778530,0,'NO'),(2117,353,'cpuset','0',1224778530,0,'NO'),(2118,353,'network_address','127.0.2.89',1224778530,0,'NO'),(2119,354,'state','Alive',1224778531,0,'NO'),(2120,354,'core ','354',1224778531,0,'NO'),(2121,354,'cpu ','177',1224778531,0,'NO'),(2122,354,'host ','node-89',1224778531,0,'NO'),(2123,354,'cpuset','1',1224778531,0,'NO'),(2124,354,'network_address','127.0.2.89',1224778531,0,'NO'),(2125,355,'state','Alive',1224778531,0,'NO'),(2126,355,'core ','355',1224778531,0,'NO'),(2127,355,'cpu ','178',1224778531,0,'NO'),(2128,355,'host ','node-89',1224778531,0,'NO'),(2129,355,'cpuset','2',1224778531,0,'NO'),(2130,355,'network_address','127.0.2.89',1224778531,0,'NO'),(2131,356,'state','Alive',1224778531,0,'NO'),(2132,356,'core ','356',1224778531,0,'NO'),(2133,356,'cpu ','178',1224778531,0,'NO'),(2134,356,'host ','node-89',1224778531,0,'NO'),(2135,356,'cpuset','3',1224778531,0,'NO'),(2136,356,'network_address','127.0.2.89',1224778531,0,'NO'),(2137,357,'state','Alive',1224778531,0,'NO'),(2138,357,'core ','357',1224778531,0,'NO'),(2139,357,'cpu ','179',1224778531,0,'NO'),(2140,357,'host ','node-90',1224778531,0,'NO'),(2141,357,'cpuset','0',1224778531,0,'NO'),(2142,357,'network_address','127.0.2.90',1224778531,0,'NO'),(2143,358,'state','Alive',1224778531,0,'NO'),(2144,358,'core ','358',1224778531,0,'NO'),(2145,358,'cpu ','179',1224778531,0,'NO'),(2146,358,'host ','node-90',1224778531,0,'NO'),(2147,358,'cpuset','1',1224778531,0,'NO'),(2148,358,'network_address','127.0.2.90',1224778531,0,'NO'),(2149,359,'state','Alive',1224778532,0,'NO'),(2150,359,'core ','359',1224778532,0,'NO'),(2151,359,'cpu ','180',1224778532,0,'NO'),(2152,359,'host ','node-90',1224778532,0,'NO'),(2153,359,'cpuset','2',1224778532,0,'NO'),(2154,359,'network_address','127.0.2.90',1224778532,0,'NO'),(2155,360,'state','Alive',1224778532,0,'NO'),(2156,360,'core ','360',1224778532,0,'NO'),(2157,360,'cpu ','180',1224778532,0,'NO'),(2158,360,'host ','node-90',1224778532,0,'NO'),(2159,360,'cpuset','3',1224778532,0,'NO'),(2160,360,'network_address','127.0.2.90',1224778532,0,'NO'),(2161,361,'state','Alive',1224778532,0,'NO'),(2162,361,'core ','361',1224778532,0,'NO'),(2163,361,'cpu ','181',1224778532,0,'NO'),(2164,361,'host ','node-91',1224778532,0,'NO'),(2165,361,'cpuset','0',1224778532,0,'NO'),(2166,361,'network_address','127.0.2.91',1224778532,0,'NO'),(2167,362,'state','Alive',1224778532,0,'NO'),(2168,362,'core ','362',1224778532,0,'NO'),(2169,362,'cpu ','181',1224778532,0,'NO'),(2170,362,'host ','node-91',1224778532,0,'NO'),(2171,362,'cpuset','1',1224778532,0,'NO'),(2172,362,'network_address','127.0.2.91',1224778532,0,'NO'),(2173,363,'state','Alive',1224778532,0,'NO'),(2174,363,'core ','363',1224778532,0,'NO'),(2175,363,'cpu ','182',1224778532,0,'NO'),(2176,363,'host ','node-91',1224778532,0,'NO'),(2177,363,'cpuset','2',1224778532,0,'NO'),(2178,363,'network_address','127.0.2.91',1224778532,0,'NO'),(2179,364,'state','Alive',1224778533,0,'NO'),(2180,364,'core ','364',1224778533,0,'NO'),(2181,364,'cpu ','182',1224778533,0,'NO'),(2182,364,'host ','node-91',1224778533,0,'NO'),(2183,364,'cpuset','3',1224778533,0,'NO'),(2184,364,'network_address','127.0.2.91',1224778533,0,'NO'),(2185,365,'state','Alive',1224778533,0,'NO'),(2186,365,'core ','365',1224778533,0,'NO'),(2187,365,'cpu ','183',1224778533,0,'NO'),(2188,365,'host ','node-92',1224778533,0,'NO'),(2189,365,'cpuset','0',1224778533,0,'NO'),(2190,365,'network_address','127.0.2.92',1224778533,0,'NO'),(2191,366,'state','Alive',1224778533,0,'NO'),(2192,366,'core ','366',1224778533,0,'NO'),(2193,366,'cpu ','183',1224778533,0,'NO'),(2194,366,'host ','node-92',1224778533,0,'NO'),(2195,366,'cpuset','1',1224778533,0,'NO'),(2196,366,'network_address','127.0.2.92',1224778533,0,'NO'),(2197,367,'state','Alive',1224778533,0,'NO'),(2198,367,'core ','367',1224778533,0,'NO'),(2199,367,'cpu ','184',1224778533,0,'NO'),(2200,367,'host ','node-92',1224778533,0,'NO'),(2201,367,'cpuset','2',1224778533,0,'NO'),(2202,367,'network_address','127.0.2.92',1224778533,0,'NO'),(2203,368,'state','Alive',1224778533,0,'NO'),(2204,368,'core ','368',1224778533,0,'NO'),(2205,368,'cpu ','184',1224778533,0,'NO'),(2206,368,'host ','node-92',1224778533,0,'NO'),(2207,368,'cpuset','3',1224778533,0,'NO'),(2208,368,'network_address','127.0.2.92',1224778533,0,'NO'),(2209,369,'state','Alive',1224778534,0,'NO'),(2210,369,'core ','369',1224778534,0,'NO'),(2211,369,'cpu ','185',1224778534,0,'NO'),(2212,369,'host ','node-93',1224778534,0,'NO'),(2213,369,'cpuset','0',1224778534,0,'NO'),(2214,369,'network_address','127.0.2.93',1224778534,0,'NO'),(2215,370,'state','Alive',1224778534,0,'NO'),(2216,370,'core ','370',1224778534,0,'NO'),(2217,370,'cpu ','185',1224778534,0,'NO'),(2218,370,'host ','node-93',1224778534,0,'NO'),(2219,370,'cpuset','1',1224778534,0,'NO'),(2220,370,'network_address','127.0.2.93',1224778534,0,'NO'),(2221,371,'state','Alive',1224778534,0,'NO'),(2222,371,'core ','371',1224778534,0,'NO'),(2223,371,'cpu ','186',1224778534,0,'NO'),(2224,371,'host ','node-93',1224778534,0,'NO'),(2225,371,'cpuset','2',1224778534,0,'NO'),(2226,371,'network_address','127.0.2.93',1224778534,0,'NO'),(2227,372,'state','Alive',1224778534,0,'NO'),(2228,372,'core ','372',1224778534,0,'NO'),(2229,372,'cpu ','186',1224778534,0,'NO'),(2230,372,'host ','node-93',1224778534,0,'NO'),(2231,372,'cpuset','3',1224778534,0,'NO'),(2232,372,'network_address','127.0.2.93',1224778534,0,'NO'),(2233,373,'state','Alive',1224778534,0,'NO'),(2234,373,'core ','373',1224778534,0,'NO'),(2235,373,'cpu ','187',1224778534,0,'NO'),(2236,373,'host ','node-94',1224778534,0,'NO'),(2237,373,'cpuset','0',1224778534,0,'NO'),(2238,373,'network_address','127.0.2.94',1224778534,0,'NO'),(2239,374,'state','Alive',1224778535,0,'NO'),(2240,374,'core ','374',1224778535,0,'NO'),(2241,374,'cpu ','187',1224778535,0,'NO'),(2242,374,'host ','node-94',1224778535,0,'NO'),(2243,374,'cpuset','1',1224778535,0,'NO'),(2244,374,'network_address','127.0.2.94',1224778535,0,'NO'),(2245,375,'state','Alive',1224778535,0,'NO'),(2246,375,'core ','375',1224778535,0,'NO'),(2247,375,'cpu ','188',1224778535,0,'NO'),(2248,375,'host ','node-94',1224778535,0,'NO'),(2249,375,'cpuset','2',1224778535,0,'NO'),(2250,375,'network_address','127.0.2.94',1224778535,0,'NO'),(2251,376,'state','Alive',1224778535,0,'NO'),(2252,376,'core ','376',1224778535,0,'NO'),(2253,376,'cpu ','188',1224778535,0,'NO'),(2254,376,'host ','node-94',1224778535,0,'NO'),(2255,376,'cpuset','3',1224778535,0,'NO'),(2256,376,'network_address','127.0.2.94',1224778535,0,'NO'),(2257,377,'state','Alive',1224778535,0,'NO'),(2258,377,'core ','377',1224778535,0,'NO'),(2259,377,'cpu ','189',1224778535,0,'NO'),(2260,377,'host ','node-95',1224778535,0,'NO'),(2261,377,'cpuset','0',1224778535,0,'NO'),(2262,377,'network_address','127.0.2.95',1224778535,0,'NO'),(2263,378,'state','Alive',1224778535,0,'NO'),(2264,378,'core ','378',1224778535,0,'NO'),(2265,378,'cpu ','189',1224778535,0,'NO'),(2266,378,'host ','node-95',1224778535,0,'NO'),(2267,378,'cpuset','1',1224778535,0,'NO'),(2268,378,'network_address','127.0.2.95',1224778535,0,'NO'),(2269,379,'state','Alive',1224778535,0,'NO'),(2270,379,'core ','379',1224778535,0,'NO'),(2271,379,'cpu ','190',1224778535,0,'NO'),(2272,379,'host ','node-95',1224778535,0,'NO'),(2273,379,'cpuset','2',1224778535,0,'NO'),(2274,379,'network_address','127.0.2.95',1224778535,0,'NO'),(2275,380,'state','Alive',1224778536,0,'NO'),(2276,380,'core ','380',1224778536,0,'NO'),(2277,380,'cpu ','190',1224778536,0,'NO'),(2278,380,'host ','node-95',1224778536,0,'NO'),(2279,380,'cpuset','3',1224778536,0,'NO'),(2280,380,'network_address','127.0.2.95',1224778536,0,'NO'),(2281,381,'state','Alive',1224778536,0,'NO'),(2282,381,'core ','381',1224778536,0,'NO'),(2283,381,'cpu ','191',1224778536,0,'NO'),(2284,381,'host ','node-96',1224778536,0,'NO'),(2285,381,'cpuset','0',1224778536,0,'NO'),(2286,381,'network_address','127.0.2.96',1224778536,0,'NO'),(2287,382,'state','Alive',1224778536,0,'NO'),(2288,382,'core ','382',1224778536,0,'NO'),(2289,382,'cpu ','191',1224778536,0,'NO'),(2290,382,'host ','node-96',1224778536,0,'NO'),(2291,382,'cpuset','1',1224778536,0,'NO'),(2292,382,'network_address','127.0.2.96',1224778536,0,'NO'),(2293,383,'state','Alive',1224778536,0,'NO'),(2294,383,'core ','383',1224778536,0,'NO'),(2295,383,'cpu ','192',1224778536,0,'NO'),(2296,383,'host ','node-96',1224778536,0,'NO'),(2297,383,'cpuset','2',1224778536,0,'NO'),(2298,383,'network_address','127.0.2.96',1224778536,0,'NO'),(2299,384,'state','Alive',1224778536,0,'NO'),(2300,384,'core ','384',1224778536,0,'NO'),(2301,384,'cpu ','192',1224778536,0,'NO'),(2302,384,'host ','node-96',1224778536,0,'NO'),(2303,384,'cpuset','3',1224778536,0,'NO'),(2304,384,'network_address','127.0.2.96',1224778536,0,'NO'); /*!40000 ALTER TABLE `resource_logs` ENABLE KEYS */; UNLOCK TABLES; -- -- Table structure for table `resources` -- DROP TABLE IF EXISTS `resources`; SET @saved_cs_client = @@character_set_client; SET character_set_client = utf8; CREATE TABLE `resources` ( `resource_id` int(10) unsigned NOT NULL auto_increment, `type` varchar(100) NOT NULL default 'default', `network_address` varchar(100) NOT NULL, `state` enum('Alive','Dead','Suspected','Absent') NOT NULL, `next_state` enum('UnChanged','Alive','Dead','Absent','Suspected') NOT NULL default 'UnChanged', `finaud_decision` enum('YES','NO') NOT NULL default 'NO', `next_finaud_decision` enum('YES','NO') NOT NULL default 'NO', `state_num` int(11) NOT NULL default '0', `suspended_jobs` enum('YES','NO') NOT NULL default 'NO', `scheduler_priority` int(10) unsigned NOT NULL default '0', `cpuset` int(10) unsigned NOT NULL default '0', `besteffort` enum('YES','NO') NOT NULL default 'YES', `deploy` enum('YES','NO') NOT NULL default 'NO', `expiry_date` int(10) unsigned NOT NULL, `desktop_computing` enum('YES','NO') NOT NULL default 'NO', `last_job_date` int(10) unsigned default '0', `available_upto` int(10) unsigned NOT NULL default '0', `host` varchar(255) default NULL, `cpu` int(11) default NULL, `core` int(11) default NULL, PRIMARY KEY (`resource_id`), KEY `state` (`state`), KEY `next_state` (`next_state`), KEY `suspended_jobs` (`suspended_jobs`), KEY `type` (`type`), KEY `network_address` (`network_address`) ) ENGINE=MyISAM AUTO_INCREMENT=385 DEFAULT CHARSET=latin1; SET character_set_client = @saved_cs_client; -- -- Dumping data for table `resources` -- LOCK TABLES `resources` WRITE; /*!40000 ALTER TABLE `resources` DISABLE KEYS */; INSERT INTO `resources` VALUES (1,'default','127.0.2.1','Alive','UnChanged','NO','NO',1,'NO',0,0,'YES','NO',0,'NO',0,0,'node-1',1,1),(2,'default','127.0.2.1','Alive','UnChanged','NO','NO',1,'NO',0,1,'YES','NO',0,'NO',0,0,'node-1',1,2),(3,'default','127.0.2.1','Alive','UnChanged','NO','NO',1,'NO',0,2,'YES','NO',0,'NO',0,0,'node-1',2,3),(4,'default','127.0.2.1','Alive','UnChanged','NO','NO',1,'NO',0,3,'YES','NO',0,'NO',0,0,'node-1',2,4),(5,'default','127.0.2.2','Alive','UnChanged','NO','NO',1,'NO',0,0,'YES','NO',0,'NO',0,0,'node-2',3,5),(6,'default','127.0.2.2','Alive','UnChanged','NO','NO',1,'NO',0,1,'YES','NO',0,'NO',0,0,'node-2',3,6),(7,'default','127.0.2.2','Alive','UnChanged','NO','NO',1,'NO',0,2,'YES','NO',0,'NO',0,0,'node-2',4,7),(8,'default','127.0.2.2','Alive','UnChanged','NO','NO',1,'NO',0,3,'YES','NO',0,'NO',0,0,'node-2',4,8),(9,'default','127.0.2.3','Alive','UnChanged','NO','NO',1,'NO',0,0,'YES','NO',0,'NO',0,0,'node-3',5,9),(10,'default','127.0.2.3','Alive','UnChanged','NO','NO',1,'NO',0,1,'YES','NO',0,'NO',0,0,'node-3',5,10),(11,'default','127.0.2.3','Alive','UnChanged','NO','NO',1,'NO',0,2,'YES','NO',0,'NO',0,0,'node-3',6,11),(12,'default','127.0.2.3','Alive','UnChanged','NO','NO',1,'NO',0,3,'YES','NO',0,'NO',0,0,'node-3',6,12),(13,'default','127.0.2.4','Alive','UnChanged','NO','NO',1,'NO',0,0,'YES','NO',0,'NO',0,0,'node-4',7,13),(14,'default','127.0.2.4','Alive','UnChanged','NO','NO',1,'NO',0,1,'YES','NO',0,'NO',0,0,'node-4',7,14),(15,'default','127.0.2.4','Alive','UnChanged','NO','NO',1,'NO',0,2,'YES','NO',0,'NO',0,0,'node-4',8,15),(16,'default','127.0.2.4','Alive','UnChanged','NO','NO',1,'NO',0,3,'YES','NO',0,'NO',0,0,'node-4',8,16),(17,'default','127.0.2.5','Alive','UnChanged','NO','NO',1,'NO',0,0,'YES','NO',0,'NO',0,0,'node-5',9,17),(18,'default','127.0.2.5','Alive','UnChanged','NO','NO',1,'NO',0,1,'YES','NO',0,'NO',0,0,'node-5',9,18),(19,'default','127.0.2.5','Alive','UnChanged','NO','NO',1,'NO',0,2,'YES','NO',0,'NO',0,0,'node-5',10,19),(20,'default','127.0.2.5','Alive','UnChanged','NO','NO',1,'NO',0,3,'YES','NO',0,'NO',0,0,'node-5',10,20),(21,'default','127.0.2.6','Alive','UnChanged','NO','NO',1,'NO',0,0,'YES','NO',0,'NO',0,0,'node-6',11,21),(22,'default','127.0.2.6','Alive','UnChanged','NO','NO',1,'NO',0,1,'YES','NO',0,'NO',0,0,'node-6',11,22),(23,'default','127.0.2.6','Alive','UnChanged','NO','NO',1,'NO',0,2,'YES','NO',0,'NO',0,0,'node-6',12,23),(24,'default','127.0.2.6','Alive','UnChanged','NO','NO',1,'NO',0,3,'YES','NO',0,'NO',0,0,'node-6',12,24),(25,'default','127.0.2.7','Alive','UnChanged','NO','NO',1,'NO',0,0,'YES','NO',0,'NO',0,0,'node-7',13,25),(26,'default','127.0.2.7','Alive','UnChanged','NO','NO',1,'NO',0,1,'YES','NO',0,'NO',0,0,'node-7',13,26),(27,'default','127.0.2.7','Alive','UnChanged','NO','NO',1,'NO',0,2,'YES','NO',0,'NO',0,0,'node-7',14,27),(28,'default','127.0.2.7','Alive','UnChanged','NO','NO',1,'NO',0,3,'YES','NO',0,'NO',0,0,'node-7',14,28),(29,'default','127.0.2.8','Alive','UnChanged','NO','NO',1,'NO',0,0,'YES','NO',0,'NO',0,0,'node-8',15,29),(30,'default','127.0.2.8','Alive','UnChanged','NO','NO',1,'NO',0,1,'YES','NO',0,'NO',0,0,'node-8',15,30),(31,'default','127.0.2.8','Alive','UnChanged','NO','NO',1,'NO',0,2,'YES','NO',0,'NO',0,0,'node-8',16,31),(32,'default','127.0.2.8','Alive','UnChanged','NO','NO',1,'NO',0,3,'YES','NO',0,'NO',0,0,'node-8',16,32),(33,'default','127.0.2.9','Alive','UnChanged','NO','NO',1,'NO',0,0,'YES','NO',0,'NO',0,0,'node-9',17,33),(34,'default','127.0.2.9','Alive','UnChanged','NO','NO',1,'NO',0,1,'YES','NO',0,'NO',0,0,'node-9',17,34),(35,'default','127.0.2.9','Alive','UnChanged','NO','NO',1,'NO',0,2,'YES','NO',0,'NO',0,0,'node-9',18,35),(36,'default','127.0.2.9','Alive','UnChanged','NO','NO',1,'NO',0,3,'YES','NO',0,'NO',0,0,'node-9',18,36),(37,'default','127.0.2.10','Alive','UnChanged','NO','NO',1,'NO',0,0,'YES','NO',0,'NO',0,0,'node-10',19,37),(38,'default','127.0.2.10','Alive','UnChanged','NO','NO',1,'NO',0,1,'YES','NO',0,'NO',0,0,'node-10',19,38),(39,'default','127.0.2.10','Alive','UnChanged','NO','NO',1,'NO',0,2,'YES','NO',0,'NO',0,0,'node-10',20,39),(40,'default','127.0.2.10','Alive','UnChanged','NO','NO',1,'NO',0,3,'YES','NO',0,'NO',0,0,'node-10',20,40),(41,'default','127.0.2.11','Alive','UnChanged','NO','NO',1,'NO',0,0,'YES','NO',0,'NO',0,0,'node-11',21,41),(42,'default','127.0.2.11','Alive','UnChanged','NO','NO',1,'NO',0,1,'YES','NO',0,'NO',0,0,'node-11',21,42),(43,'default','127.0.2.11','Alive','UnChanged','NO','NO',1,'NO',0,2,'YES','NO',0,'NO',0,0,'node-11',22,43),(44,'default','127.0.2.11','Alive','UnChanged','NO','NO',1,'NO',0,3,'YES','NO',0,'NO',0,0,'node-11',22,44),(45,'default','127.0.2.12','Alive','UnChanged','NO','NO',1,'NO',0,0,'YES','NO',0,'NO',0,0,'node-12',23,45),(46,'default','127.0.2.12','Alive','UnChanged','NO','NO',1,'NO',0,1,'YES','NO',0,'NO',0,0,'node-12',23,46),(47,'default','127.0.2.12','Alive','UnChanged','NO','NO',1,'NO',0,2,'YES','NO',0,'NO',0,0,'node-12',24,47),(48,'default','127.0.2.12','Alive','UnChanged','NO','NO',1,'NO',0,3,'YES','NO',0,'NO',0,0,'node-12',24,48),(49,'default','127.0.2.13','Alive','UnChanged','NO','NO',1,'NO',0,0,'YES','NO',0,'NO',0,0,'node-13',25,49),(50,'default','127.0.2.13','Alive','UnChanged','NO','NO',1,'NO',0,1,'YES','NO',0,'NO',0,0,'node-13',25,50),(51,'default','127.0.2.13','Alive','UnChanged','NO','NO',1,'NO',0,2,'YES','NO',0,'NO',0,0,'node-13',26,51),(52,'default','127.0.2.13','Alive','UnChanged','NO','NO',1,'NO',0,3,'YES','NO',0,'NO',0,0,'node-13',26,52),(53,'default','127.0.2.14','Alive','UnChanged','NO','NO',1,'NO',0,0,'YES','NO',0,'NO',0,0,'node-14',27,53),(54,'default','127.0.2.14','Alive','UnChanged','NO','NO',1,'NO',0,1,'YES','NO',0,'NO',0,0,'node-14',27,54),(55,'default','127.0.2.14','Alive','UnChanged','NO','NO',1,'NO',0,2,'YES','NO',0,'NO',0,0,'node-14',28,55),(56,'default','127.0.2.14','Alive','UnChanged','NO','NO',1,'NO',0,3,'YES','NO',0,'NO',0,0,'node-14',28,56),(57,'default','127.0.2.15','Alive','UnChanged','NO','NO',1,'NO',0,0,'YES','NO',0,'NO',0,0,'node-15',29,57),(58,'default','127.0.2.15','Alive','UnChanged','NO','NO',1,'NO',0,1,'YES','NO',0,'NO',0,0,'node-15',29,58),(59,'default','127.0.2.15','Alive','UnChanged','NO','NO',1,'NO',0,2,'YES','NO',0,'NO',0,0,'node-15',30,59),(60,'default','127.0.2.15','Alive','UnChanged','NO','NO',1,'NO',0,3,'YES','NO',0,'NO',0,0,'node-15',30,60),(61,'default','127.0.2.16','Alive','UnChanged','NO','NO',1,'NO',0,0,'YES','NO',0,'NO',0,0,'node-16',31,61),(62,'default','127.0.2.16','Alive','UnChanged','NO','NO',1,'NO',0,1,'YES','NO',0,'NO',0,0,'node-16',31,62),(63,'default','127.0.2.16','Alive','UnChanged','NO','NO',1,'NO',0,2,'YES','NO',0,'NO',0,0,'node-16',32,63),(64,'default','127.0.2.16','Alive','UnChanged','NO','NO',1,'NO',0,3,'YES','NO',0,'NO',0,0,'node-16',32,64),(65,'default','127.0.2.17','Alive','UnChanged','NO','NO',1,'NO',0,0,'YES','NO',0,'NO',0,0,'node-17',33,65),(66,'default','127.0.2.17','Alive','UnChanged','NO','NO',1,'NO',0,1,'YES','NO',0,'NO',0,0,'node-17',33,66),(67,'default','127.0.2.17','Alive','UnChanged','NO','NO',1,'NO',0,2,'YES','NO',0,'NO',0,0,'node-17',34,67),(68,'default','127.0.2.17','Alive','UnChanged','NO','NO',1,'NO',0,3,'YES','NO',0,'NO',0,0,'node-17',34,68),(69,'default','127.0.2.18','Alive','UnChanged','NO','NO',1,'NO',0,0,'YES','NO',0,'NO',0,0,'node-18',35,69),(70,'default','127.0.2.18','Alive','UnChanged','NO','NO',1,'NO',0,1,'YES','NO',0,'NO',0,0,'node-18',35,70),(71,'default','127.0.2.18','Alive','UnChanged','NO','NO',1,'NO',0,2,'YES','NO',0,'NO',0,0,'node-18',36,71),(72,'default','127.0.2.18','Alive','UnChanged','NO','NO',1,'NO',0,3,'YES','NO',0,'NO',0,0,'node-18',36,72),(73,'default','127.0.2.19','Alive','UnChanged','NO','NO',1,'NO',0,0,'YES','NO',0,'NO',0,0,'node-19',37,73),(74,'default','127.0.2.19','Alive','UnChanged','NO','NO',1,'NO',0,1,'YES','NO',0,'NO',0,0,'node-19',37,74),(75,'default','127.0.2.19','Alive','UnChanged','NO','NO',1,'NO',0,2,'YES','NO',0,'NO',0,0,'node-19',38,75),(76,'default','127.0.2.19','Alive','UnChanged','NO','NO',1,'NO',0,3,'YES','NO',0,'NO',0,0,'node-19',38,76),(77,'default','127.0.2.20','Alive','UnChanged','NO','NO',1,'NO',0,0,'YES','NO',0,'NO',0,0,'node-20',39,77),(78,'default','127.0.2.20','Alive','UnChanged','NO','NO',1,'NO',0,1,'YES','NO',0,'NO',0,0,'node-20',39,78),(79,'default','127.0.2.20','Alive','UnChanged','NO','NO',1,'NO',0,2,'YES','NO',0,'NO',0,0,'node-20',40,79),(80,'default','127.0.2.20','Alive','UnChanged','NO','NO',1,'NO',0,3,'YES','NO',0,'NO',0,0,'node-20',40,80),(81,'default','127.0.2.21','Alive','UnChanged','NO','NO',1,'NO',0,0,'YES','NO',0,'NO',0,0,'node-21',41,81),(82,'default','127.0.2.21','Alive','UnChanged','NO','NO',1,'NO',0,1,'YES','NO',0,'NO',0,0,'node-21',41,82),(83,'default','127.0.2.21','Alive','UnChanged','NO','NO',1,'NO',0,2,'YES','NO',0,'NO',0,0,'node-21',42,83),(84,'default','127.0.2.21','Alive','UnChanged','NO','NO',1,'NO',0,3,'YES','NO',0,'NO',0,0,'node-21',42,84),(85,'default','127.0.2.22','Alive','UnChanged','NO','NO',1,'NO',0,0,'YES','NO',0,'NO',0,0,'node-22',43,85),(86,'default','127.0.2.22','Alive','UnChanged','NO','NO',1,'NO',0,1,'YES','NO',0,'NO',0,0,'node-22',43,86),(87,'default','127.0.2.22','Alive','UnChanged','NO','NO',1,'NO',0,2,'YES','NO',0,'NO',0,0,'node-22',44,87),(88,'default','127.0.2.22','Alive','UnChanged','NO','NO',1,'NO',0,3,'YES','NO',0,'NO',0,0,'node-22',44,88),(89,'default','127.0.2.23','Alive','UnChanged','NO','NO',1,'NO',0,0,'YES','NO',0,'NO',0,0,'node-23',45,89),(90,'default','127.0.2.23','Alive','UnChanged','NO','NO',1,'NO',0,1,'YES','NO',0,'NO',0,0,'node-23',45,90),(91,'default','127.0.2.23','Alive','UnChanged','NO','NO',1,'NO',0,2,'YES','NO',0,'NO',0,0,'node-23',46,91),(92,'default','127.0.2.23','Alive','UnChanged','NO','NO',1,'NO',0,3,'YES','NO',0,'NO',0,0,'node-23',46,92),(93,'default','127.0.2.24','Alive','UnChanged','NO','NO',1,'NO',0,0,'YES','NO',0,'NO',0,0,'node-24',47,93),(94,'default','127.0.2.24','Alive','UnChanged','NO','NO',1,'NO',0,1,'YES','NO',0,'NO',0,0,'node-24',47,94),(95,'default','127.0.2.24','Alive','UnChanged','NO','NO',1,'NO',0,2,'YES','NO',0,'NO',0,0,'node-24',48,95),(96,'default','127.0.2.24','Alive','UnChanged','NO','NO',1,'NO',0,3,'YES','NO',0,'NO',0,0,'node-24',48,96),(97,'default','127.0.2.25','Alive','UnChanged','NO','NO',1,'NO',0,0,'YES','NO',0,'NO',0,0,'node-25',49,97),(98,'default','127.0.2.25','Alive','UnChanged','NO','NO',1,'NO',0,1,'YES','NO',0,'NO',0,0,'node-25',49,98),(99,'default','127.0.2.25','Alive','UnChanged','NO','NO',1,'NO',0,2,'YES','NO',0,'NO',0,0,'node-25',50,99),(100,'default','127.0.2.25','Alive','UnChanged','NO','NO',1,'NO',0,3,'YES','NO',0,'NO',0,0,'node-25',50,100),(101,'default','127.0.2.26','Alive','UnChanged','NO','NO',1,'NO',0,0,'YES','NO',0,'NO',0,0,'node-26',51,101),(102,'default','127.0.2.26','Alive','UnChanged','NO','NO',1,'NO',0,1,'YES','NO',0,'NO',0,0,'node-26',51,102),(103,'default','127.0.2.26','Alive','UnChanged','NO','NO',1,'NO',0,2,'YES','NO',0,'NO',0,0,'node-26',52,103),(104,'default','127.0.2.26','Alive','UnChanged','NO','NO',1,'NO',0,3,'YES','NO',0,'NO',0,0,'node-26',52,104),(105,'default','127.0.2.27','Alive','UnChanged','NO','NO',1,'NO',0,0,'YES','NO',0,'NO',0,0,'node-27',53,105),(106,'default','127.0.2.27','Alive','UnChanged','NO','NO',1,'NO',0,1,'YES','NO',0,'NO',0,0,'node-27',53,106),(107,'default','127.0.2.27','Alive','UnChanged','NO','NO',1,'NO',0,2,'YES','NO',0,'NO',0,0,'node-27',54,107),(108,'default','127.0.2.27','Alive','UnChanged','NO','NO',1,'NO',0,3,'YES','NO',0,'NO',0,0,'node-27',54,108),(109,'default','127.0.2.28','Alive','UnChanged','NO','NO',1,'NO',0,0,'YES','NO',0,'NO',0,0,'node-28',55,109),(110,'default','127.0.2.28','Alive','UnChanged','NO','NO',1,'NO',0,1,'YES','NO',0,'NO',0,0,'node-28',55,110),(111,'default','127.0.2.28','Alive','UnChanged','NO','NO',1,'NO',0,2,'YES','NO',0,'NO',0,0,'node-28',56,111),(112,'default','127.0.2.28','Alive','UnChanged','NO','NO',1,'NO',0,3,'YES','NO',0,'NO',0,0,'node-28',56,112),(113,'default','127.0.2.29','Alive','UnChanged','NO','NO',1,'NO',0,0,'YES','NO',0,'NO',0,0,'node-29',57,113),(114,'default','127.0.2.29','Alive','UnChanged','NO','NO',1,'NO',0,1,'YES','NO',0,'NO',0,0,'node-29',57,114),(115,'default','127.0.2.29','Alive','UnChanged','NO','NO',1,'NO',0,2,'YES','NO',0,'NO',0,0,'node-29',58,115),(116,'default','127.0.2.29','Alive','UnChanged','NO','NO',1,'NO',0,3,'YES','NO',0,'NO',0,0,'node-29',58,116),(117,'default','127.0.2.30','Alive','UnChanged','NO','NO',1,'NO',0,0,'YES','NO',0,'NO',0,0,'node-30',59,117),(118,'default','127.0.2.30','Alive','UnChanged','NO','NO',1,'NO',0,1,'YES','NO',0,'NO',0,0,'node-30',59,118),(119,'default','127.0.2.30','Alive','UnChanged','NO','NO',1,'NO',0,2,'YES','NO',0,'NO',0,0,'node-30',60,119),(120,'default','127.0.2.30','Alive','UnChanged','NO','NO',1,'NO',0,3,'YES','NO',0,'NO',0,0,'node-30',60,120),(121,'default','127.0.2.31','Alive','UnChanged','NO','NO',1,'NO',0,0,'YES','NO',0,'NO',0,0,'node-31',61,121),(122,'default','127.0.2.31','Alive','UnChanged','NO','NO',1,'NO',0,1,'YES','NO',0,'NO',0,0,'node-31',61,122),(123,'default','127.0.2.31','Alive','UnChanged','NO','NO',1,'NO',0,2,'YES','NO',0,'NO',0,0,'node-31',62,123),(124,'default','127.0.2.31','Alive','UnChanged','NO','NO',1,'NO',0,3,'YES','NO',0,'NO',0,0,'node-31',62,124),(125,'default','127.0.2.32','Alive','UnChanged','NO','NO',1,'NO',0,0,'YES','NO',0,'NO',0,0,'node-32',63,125),(126,'default','127.0.2.32','Alive','UnChanged','NO','NO',1,'NO',0,1,'YES','NO',0,'NO',0,0,'node-32',63,126),(127,'default','127.0.2.32','Alive','UnChanged','NO','NO',1,'NO',0,2,'YES','NO',0,'NO',0,0,'node-32',64,127),(128,'default','127.0.2.32','Alive','UnChanged','NO','NO',1,'NO',0,3,'YES','NO',0,'NO',0,0,'node-32',64,128),(129,'default','127.0.2.33','Alive','UnChanged','NO','NO',1,'NO',0,0,'YES','NO',0,'NO',0,0,'node-33',65,129),(130,'default','127.0.2.33','Alive','UnChanged','NO','NO',1,'NO',0,1,'YES','NO',0,'NO',0,0,'node-33',65,130),(131,'default','127.0.2.33','Alive','UnChanged','NO','NO',1,'NO',0,2,'YES','NO',0,'NO',0,0,'node-33',66,131),(132,'default','127.0.2.33','Alive','UnChanged','NO','NO',1,'NO',0,3,'YES','NO',0,'NO',0,0,'node-33',66,132),(133,'default','127.0.2.34','Alive','UnChanged','NO','NO',1,'NO',0,0,'YES','NO',0,'NO',0,0,'node-34',67,133),(134,'default','127.0.2.34','Alive','UnChanged','NO','NO',1,'NO',0,1,'YES','NO',0,'NO',0,0,'node-34',67,134),(135,'default','127.0.2.34','Alive','UnChanged','NO','NO',1,'NO',0,2,'YES','NO',0,'NO',0,0,'node-34',68,135),(136,'default','127.0.2.34','Alive','UnChanged','NO','NO',1,'NO',0,3,'YES','NO',0,'NO',0,0,'node-34',68,136),(137,'default','127.0.2.35','Alive','UnChanged','NO','NO',1,'NO',0,0,'YES','NO',0,'NO',0,0,'node-35',69,137),(138,'default','127.0.2.35','Alive','UnChanged','NO','NO',1,'NO',0,1,'YES','NO',0,'NO',0,0,'node-35',69,138),(139,'default','127.0.2.35','Alive','UnChanged','NO','NO',1,'NO',0,2,'YES','NO',0,'NO',0,0,'node-35',70,139),(140,'default','127.0.2.35','Alive','UnChanged','NO','NO',1,'NO',0,3,'YES','NO',0,'NO',0,0,'node-35',70,140),(141,'default','127.0.2.36','Alive','UnChanged','NO','NO',1,'NO',0,0,'YES','NO',0,'NO',0,0,'node-36',71,141),(142,'default','127.0.2.36','Alive','UnChanged','NO','NO',1,'NO',0,1,'YES','NO',0,'NO',0,0,'node-36',71,142),(143,'default','127.0.2.36','Alive','UnChanged','NO','NO',1,'NO',0,2,'YES','NO',0,'NO',0,0,'node-36',72,143),(144,'default','127.0.2.36','Alive','UnChanged','NO','NO',1,'NO',0,3,'YES','NO',0,'NO',0,0,'node-36',72,144),(145,'default','127.0.2.37','Alive','UnChanged','NO','NO',1,'NO',0,0,'YES','NO',0,'NO',0,0,'node-37',73,145),(146,'default','127.0.2.37','Alive','UnChanged','NO','NO',1,'NO',0,1,'YES','NO',0,'NO',0,0,'node-37',73,146),(147,'default','127.0.2.37','Alive','UnChanged','NO','NO',1,'NO',0,2,'YES','NO',0,'NO',0,0,'node-37',74,147),(148,'default','127.0.2.37','Alive','UnChanged','NO','NO',1,'NO',0,3,'YES','NO',0,'NO',0,0,'node-37',74,148),(149,'default','127.0.2.38','Alive','UnChanged','NO','NO',1,'NO',0,0,'YES','NO',0,'NO',0,0,'node-38',75,149),(150,'default','127.0.2.38','Alive','UnChanged','NO','NO',1,'NO',0,1,'YES','NO',0,'NO',0,0,'node-38',75,150),(151,'default','127.0.2.38','Alive','UnChanged','NO','NO',1,'NO',0,2,'YES','NO',0,'NO',0,0,'node-38',76,151),(152,'default','127.0.2.38','Alive','UnChanged','NO','NO',1,'NO',0,3,'YES','NO',0,'NO',0,0,'node-38',76,152),(153,'default','127.0.2.39','Alive','UnChanged','NO','NO',1,'NO',0,0,'YES','NO',0,'NO',0,0,'node-39',77,153),(154,'default','127.0.2.39','Alive','UnChanged','NO','NO',1,'NO',0,1,'YES','NO',0,'NO',0,0,'node-39',77,154),(155,'default','127.0.2.39','Alive','UnChanged','NO','NO',1,'NO',0,2,'YES','NO',0,'NO',0,0,'node-39',78,155),(156,'default','127.0.2.39','Alive','UnChanged','NO','NO',1,'NO',0,3,'YES','NO',0,'NO',0,0,'node-39',78,156),(157,'default','127.0.2.40','Alive','UnChanged','NO','NO',1,'NO',0,0,'YES','NO',0,'NO',0,0,'node-40',79,157),(158,'default','127.0.2.40','Alive','UnChanged','NO','NO',1,'NO',0,1,'YES','NO',0,'NO',0,0,'node-40',79,158),(159,'default','127.0.2.40','Alive','UnChanged','NO','NO',1,'NO',0,2,'YES','NO',0,'NO',0,0,'node-40',80,159),(160,'default','127.0.2.40','Alive','UnChanged','NO','NO',1,'NO',0,3,'YES','NO',0,'NO',0,0,'node-40',80,160),(161,'default','127.0.2.41','Alive','UnChanged','NO','NO',1,'NO',0,0,'YES','NO',0,'NO',0,0,'node-41',81,161),(162,'default','127.0.2.41','Alive','UnChanged','NO','NO',1,'NO',0,1,'YES','NO',0,'NO',0,0,'node-41',81,162),(163,'default','127.0.2.41','Alive','UnChanged','NO','NO',1,'NO',0,2,'YES','NO',0,'NO',0,0,'node-41',82,163),(164,'default','127.0.2.41','Alive','UnChanged','NO','NO',1,'NO',0,3,'YES','NO',0,'NO',0,0,'node-41',82,164),(165,'default','127.0.2.42','Alive','UnChanged','NO','NO',1,'NO',0,0,'YES','NO',0,'NO',0,0,'node-42',83,165),(166,'default','127.0.2.42','Alive','UnChanged','NO','NO',1,'NO',0,1,'YES','NO',0,'NO',0,0,'node-42',83,166),(167,'default','127.0.2.42','Alive','UnChanged','NO','NO',1,'NO',0,2,'YES','NO',0,'NO',0,0,'node-42',84,167),(168,'default','127.0.2.42','Alive','UnChanged','NO','NO',1,'NO',0,3,'YES','NO',0,'NO',0,0,'node-42',84,168),(169,'default','127.0.2.43','Alive','UnChanged','NO','NO',1,'NO',0,0,'YES','NO',0,'NO',0,0,'node-43',85,169),(170,'default','127.0.2.43','Alive','UnChanged','NO','NO',1,'NO',0,1,'YES','NO',0,'NO',0,0,'node-43',85,170),(171,'default','127.0.2.43','Alive','UnChanged','NO','NO',1,'NO',0,2,'YES','NO',0,'NO',0,0,'node-43',86,171),(172,'default','127.0.2.43','Alive','UnChanged','NO','NO',1,'NO',0,3,'YES','NO',0,'NO',0,0,'node-43',86,172),(173,'default','127.0.2.44','Alive','UnChanged','NO','NO',1,'NO',0,0,'YES','NO',0,'NO',0,0,'node-44',87,173),(174,'default','127.0.2.44','Alive','UnChanged','NO','NO',1,'NO',0,1,'YES','NO',0,'NO',0,0,'node-44',87,174),(175,'default','127.0.2.44','Alive','UnChanged','NO','NO',1,'NO',0,2,'YES','NO',0,'NO',0,0,'node-44',88,175),(176,'default','127.0.2.44','Alive','UnChanged','NO','NO',1,'NO',0,3,'YES','NO',0,'NO',0,0,'node-44',88,176),(177,'default','127.0.2.45','Alive','UnChanged','NO','NO',1,'NO',0,0,'YES','NO',0,'NO',0,0,'node-45',89,177),(178,'default','127.0.2.45','Alive','UnChanged','NO','NO',1,'NO',0,1,'YES','NO',0,'NO',0,0,'node-45',89,178),(179,'default','127.0.2.45','Alive','UnChanged','NO','NO',1,'NO',0,2,'YES','NO',0,'NO',0,0,'node-45',90,179),(180,'default','127.0.2.45','Alive','UnChanged','NO','NO',1,'NO',0,3,'YES','NO',0,'NO',0,0,'node-45',90,180),(181,'default','127.0.2.46','Alive','UnChanged','NO','NO',1,'NO',0,0,'YES','NO',0,'NO',0,0,'node-46',91,181),(182,'default','127.0.2.46','Alive','UnChanged','NO','NO',1,'NO',0,1,'YES','NO',0,'NO',0,0,'node-46',91,182),(183,'default','127.0.2.46','Alive','UnChanged','NO','NO',1,'NO',0,2,'YES','NO',0,'NO',0,0,'node-46',92,183),(184,'default','127.0.2.46','Alive','UnChanged','NO','NO',1,'NO',0,3,'YES','NO',0,'NO',0,0,'node-46',92,184),(185,'default','127.0.2.47','Alive','UnChanged','NO','NO',1,'NO',0,0,'YES','NO',0,'NO',0,0,'node-47',93,185),(186,'default','127.0.2.47','Alive','UnChanged','NO','NO',1,'NO',0,1,'YES','NO',0,'NO',0,0,'node-47',93,186),(187,'default','127.0.2.47','Alive','UnChanged','NO','NO',1,'NO',0,2,'YES','NO',0,'NO',0,0,'node-47',94,187),(188,'default','127.0.2.47','Alive','UnChanged','NO','NO',1,'NO',0,3,'YES','NO',0,'NO',0,0,'node-47',94,188),(189,'default','127.0.2.48','Alive','UnChanged','NO','NO',1,'NO',0,0,'YES','NO',0,'NO',0,0,'node-48',95,189),(190,'default','127.0.2.48','Alive','UnChanged','NO','NO',1,'NO',0,1,'YES','NO',0,'NO',0,0,'node-48',95,190),(191,'default','127.0.2.48','Alive','UnChanged','NO','NO',1,'NO',0,2,'YES','NO',0,'NO',0,0,'node-48',96,191),(192,'default','127.0.2.48','Alive','UnChanged','NO','NO',1,'NO',0,3,'YES','NO',0,'NO',0,0,'node-48',96,192),(193,'default','127.0.2.49','Alive','UnChanged','NO','NO',1,'NO',0,0,'YES','NO',0,'NO',0,0,'node-49',97,193),(194,'default','127.0.2.49','Alive','UnChanged','NO','NO',1,'NO',0,1,'YES','NO',0,'NO',0,0,'node-49',97,194),(195,'default','127.0.2.49','Alive','UnChanged','NO','NO',1,'NO',0,2,'YES','NO',0,'NO',0,0,'node-49',98,195),(196,'default','127.0.2.49','Alive','UnChanged','NO','NO',1,'NO',0,3,'YES','NO',0,'NO',0,0,'node-49',98,196),(197,'default','127.0.2.50','Alive','UnChanged','NO','NO',1,'NO',0,0,'YES','NO',0,'NO',0,0,'node-50',99,197),(198,'default','127.0.2.50','Alive','UnChanged','NO','NO',1,'NO',0,1,'YES','NO',0,'NO',0,0,'node-50',99,198),(199,'default','127.0.2.50','Alive','UnChanged','NO','NO',1,'NO',0,2,'YES','NO',0,'NO',0,0,'node-50',100,199),(200,'default','127.0.2.50','Alive','UnChanged','NO','NO',1,'NO',0,3,'YES','NO',0,'NO',0,0,'node-50',100,200),(201,'default','127.0.2.51','Alive','UnChanged','NO','NO',1,'NO',0,0,'YES','NO',0,'NO',0,0,'node-51',101,201),(202,'default','127.0.2.51','Alive','UnChanged','NO','NO',1,'NO',0,1,'YES','NO',0,'NO',0,0,'node-51',101,202),(203,'default','127.0.2.51','Alive','UnChanged','NO','NO',1,'NO',0,2,'YES','NO',0,'NO',0,0,'node-51',102,203),(204,'default','127.0.2.51','Alive','UnChanged','NO','NO',1,'NO',0,3,'YES','NO',0,'NO',0,0,'node-51',102,204),(205,'default','127.0.2.52','Alive','UnChanged','NO','NO',1,'NO',0,0,'YES','NO',0,'NO',0,0,'node-52',103,205),(206,'default','127.0.2.52','Alive','UnChanged','NO','NO',1,'NO',0,1,'YES','NO',0,'NO',0,0,'node-52',103,206),(207,'default','127.0.2.52','Alive','UnChanged','NO','NO',1,'NO',0,2,'YES','NO',0,'NO',0,0,'node-52',104,207),(208,'default','127.0.2.52','Alive','UnChanged','NO','NO',1,'NO',0,3,'YES','NO',0,'NO',0,0,'node-52',104,208),(209,'default','127.0.2.53','Alive','UnChanged','NO','NO',1,'NO',0,0,'YES','NO',0,'NO',0,0,'node-53',105,209),(210,'default','127.0.2.53','Alive','UnChanged','NO','NO',1,'NO',0,1,'YES','NO',0,'NO',0,0,'node-53',105,210),(211,'default','127.0.2.53','Alive','UnChanged','NO','NO',1,'NO',0,2,'YES','NO',0,'NO',0,0,'node-53',106,211),(212,'default','127.0.2.53','Alive','UnChanged','NO','NO',1,'NO',0,3,'YES','NO',0,'NO',0,0,'node-53',106,212),(213,'default','127.0.2.54','Alive','UnChanged','NO','NO',1,'NO',0,0,'YES','NO',0,'NO',0,0,'node-54',107,213),(214,'default','127.0.2.54','Alive','UnChanged','NO','NO',1,'NO',0,1,'YES','NO',0,'NO',0,0,'node-54',107,214),(215,'default','127.0.2.54','Alive','UnChanged','NO','NO',1,'NO',0,2,'YES','NO',0,'NO',0,0,'node-54',108,215),(216,'default','127.0.2.54','Alive','UnChanged','NO','NO',1,'NO',0,3,'YES','NO',0,'NO',0,0,'node-54',108,216),(217,'default','127.0.2.55','Alive','UnChanged','NO','NO',1,'NO',0,0,'YES','NO',0,'NO',0,0,'node-55',109,217),(218,'default','127.0.2.55','Alive','UnChanged','NO','NO',1,'NO',0,1,'YES','NO',0,'NO',0,0,'node-55',109,218),(219,'default','127.0.2.55','Alive','UnChanged','NO','NO',1,'NO',0,2,'YES','NO',0,'NO',0,0,'node-55',110,219),(220,'default','127.0.2.55','Alive','UnChanged','NO','NO',1,'NO',0,3,'YES','NO',0,'NO',0,0,'node-55',110,220),(221,'default','127.0.2.56','Alive','UnChanged','NO','NO',1,'NO',0,0,'YES','NO',0,'NO',0,0,'node-56',111,221),(222,'default','127.0.2.56','Alive','UnChanged','NO','NO',1,'NO',0,1,'YES','NO',0,'NO',0,0,'node-56',111,222),(223,'default','127.0.2.56','Alive','UnChanged','NO','NO',1,'NO',0,2,'YES','NO',0,'NO',0,0,'node-56',112,223),(224,'default','127.0.2.56','Alive','UnChanged','NO','NO',1,'NO',0,3,'YES','NO',0,'NO',0,0,'node-56',112,224),(225,'default','127.0.2.57','Alive','UnChanged','NO','NO',1,'NO',0,0,'YES','NO',0,'NO',0,0,'node-57',113,225),(226,'default','127.0.2.57','Alive','UnChanged','NO','NO',1,'NO',0,1,'YES','NO',0,'NO',0,0,'node-57',113,226),(227,'default','127.0.2.57','Alive','UnChanged','NO','NO',1,'NO',0,2,'YES','NO',0,'NO',0,0,'node-57',114,227),(228,'default','127.0.2.57','Alive','UnChanged','NO','NO',1,'NO',0,3,'YES','NO',0,'NO',0,0,'node-57',114,228),(229,'default','127.0.2.58','Alive','UnChanged','NO','NO',1,'NO',0,0,'YES','NO',0,'NO',0,0,'node-58',115,229),(230,'default','127.0.2.58','Alive','UnChanged','NO','NO',1,'NO',0,1,'YES','NO',0,'NO',0,0,'node-58',115,230),(231,'default','127.0.2.58','Alive','UnChanged','NO','NO',1,'NO',0,2,'YES','NO',0,'NO',0,0,'node-58',116,231),(232,'default','127.0.2.58','Alive','UnChanged','NO','NO',1,'NO',0,3,'YES','NO',0,'NO',0,0,'node-58',116,232),(233,'default','127.0.2.59','Alive','UnChanged','NO','NO',1,'NO',0,0,'YES','NO',0,'NO',0,0,'node-59',117,233),(234,'default','127.0.2.59','Alive','UnChanged','NO','NO',1,'NO',0,1,'YES','NO',0,'NO',0,0,'node-59',117,234),(235,'default','127.0.2.59','Alive','UnChanged','NO','NO',1,'NO',0,2,'YES','NO',0,'NO',0,0,'node-59',118,235),(236,'default','127.0.2.59','Alive','UnChanged','NO','NO',1,'NO',0,3,'YES','NO',0,'NO',0,0,'node-59',118,236),(237,'default','127.0.2.60','Alive','UnChanged','NO','NO',1,'NO',0,0,'YES','NO',0,'NO',0,0,'node-60',119,237),(238,'default','127.0.2.60','Alive','UnChanged','NO','NO',1,'NO',0,1,'YES','NO',0,'NO',0,0,'node-60',119,238),(239,'default','127.0.2.60','Alive','UnChanged','NO','NO',1,'NO',0,2,'YES','NO',0,'NO',0,0,'node-60',120,239),(240,'default','127.0.2.60','Alive','UnChanged','NO','NO',1,'NO',0,3,'YES','NO',0,'NO',0,0,'node-60',120,240),(241,'default','127.0.2.61','Alive','UnChanged','NO','NO',1,'NO',0,0,'YES','NO',0,'NO',0,0,'node-61',121,241),(242,'default','127.0.2.61','Alive','UnChanged','NO','NO',1,'NO',0,1,'YES','NO',0,'NO',0,0,'node-61',121,242),(243,'default','127.0.2.61','Alive','UnChanged','NO','NO',1,'NO',0,2,'YES','NO',0,'NO',0,0,'node-61',122,243),(244,'default','127.0.2.61','Alive','UnChanged','NO','NO',1,'NO',0,3,'YES','NO',0,'NO',0,0,'node-61',122,244),(245,'default','127.0.2.62','Alive','UnChanged','NO','NO',1,'NO',0,0,'YES','NO',0,'NO',0,0,'node-62',123,245),(246,'default','127.0.2.62','Alive','UnChanged','NO','NO',1,'NO',0,1,'YES','NO',0,'NO',0,0,'node-62',123,246),(247,'default','127.0.2.62','Alive','UnChanged','NO','NO',1,'NO',0,2,'YES','NO',0,'NO',0,0,'node-62',124,247),(248,'default','127.0.2.62','Alive','UnChanged','NO','NO',1,'NO',0,3,'YES','NO',0,'NO',0,0,'node-62',124,248),(249,'default','127.0.2.63','Alive','UnChanged','NO','NO',1,'NO',0,0,'YES','NO',0,'NO',0,0,'node-63',125,249),(250,'default','127.0.2.63','Alive','UnChanged','NO','NO',1,'NO',0,1,'YES','NO',0,'NO',0,0,'node-63',125,250),(251,'default','127.0.2.63','Alive','UnChanged','NO','NO',1,'NO',0,2,'YES','NO',0,'NO',0,0,'node-63',126,251),(252,'default','127.0.2.63','Alive','UnChanged','NO','NO',1,'NO',0,3,'YES','NO',0,'NO',0,0,'node-63',126,252),(253,'default','127.0.2.64','Alive','UnChanged','NO','NO',1,'NO',0,0,'YES','NO',0,'NO',0,0,'node-64',127,253),(254,'default','127.0.2.64','Alive','UnChanged','NO','NO',1,'NO',0,1,'YES','NO',0,'NO',0,0,'node-64',127,254),(255,'default','127.0.2.64','Alive','UnChanged','NO','NO',1,'NO',0,2,'YES','NO',0,'NO',0,0,'node-64',128,255),(256,'default','127.0.2.64','Alive','UnChanged','NO','NO',1,'NO',0,3,'YES','NO',0,'NO',0,0,'node-64',128,256),(257,'default','127.0.2.65','Alive','UnChanged','NO','NO',1,'NO',0,0,'YES','NO',0,'NO',0,0,'node-65',129,257),(258,'default','127.0.2.65','Alive','UnChanged','NO','NO',1,'NO',0,1,'YES','NO',0,'NO',0,0,'node-65',129,258),(259,'default','127.0.2.65','Alive','UnChanged','NO','NO',1,'NO',0,2,'YES','NO',0,'NO',0,0,'node-65',130,259),(260,'default','127.0.2.65','Alive','UnChanged','NO','NO',1,'NO',0,3,'YES','NO',0,'NO',0,0,'node-65',130,260),(261,'default','127.0.2.66','Alive','UnChanged','NO','NO',1,'NO',0,0,'YES','NO',0,'NO',0,0,'node-66',131,261),(262,'default','127.0.2.66','Alive','UnChanged','NO','NO',1,'NO',0,1,'YES','NO',0,'NO',0,0,'node-66',131,262),(263,'default','127.0.2.66','Alive','UnChanged','NO','NO',1,'NO',0,2,'YES','NO',0,'NO',0,0,'node-66',132,263),(264,'default','127.0.2.66','Alive','UnChanged','NO','NO',1,'NO',0,3,'YES','NO',0,'NO',0,0,'node-66',132,264),(265,'default','127.0.2.67','Alive','UnChanged','NO','NO',1,'NO',0,0,'YES','NO',0,'NO',0,0,'node-67',133,265),(266,'default','127.0.2.67','Alive','UnChanged','NO','NO',1,'NO',0,1,'YES','NO',0,'NO',0,0,'node-67',133,266),(267,'default','127.0.2.67','Alive','UnChanged','NO','NO',1,'NO',0,2,'YES','NO',0,'NO',0,0,'node-67',134,267),(268,'default','127.0.2.67','Alive','UnChanged','NO','NO',1,'NO',0,3,'YES','NO',0,'NO',0,0,'node-67',134,268),(269,'default','127.0.2.68','Alive','UnChanged','NO','NO',1,'NO',0,0,'YES','NO',0,'NO',0,0,'node-68',135,269),(270,'default','127.0.2.68','Alive','UnChanged','NO','NO',1,'NO',0,1,'YES','NO',0,'NO',0,0,'node-68',135,270),(271,'default','127.0.2.68','Alive','UnChanged','NO','NO',1,'NO',0,2,'YES','NO',0,'NO',0,0,'node-68',136,271),(272,'default','127.0.2.68','Alive','UnChanged','NO','NO',1,'NO',0,3,'YES','NO',0,'NO',0,0,'node-68',136,272),(273,'default','127.0.2.69','Alive','UnChanged','NO','NO',1,'NO',0,0,'YES','NO',0,'NO',0,0,'node-69',137,273),(274,'default','127.0.2.69','Alive','UnChanged','NO','NO',1,'NO',0,1,'YES','NO',0,'NO',0,0,'node-69',137,274),(275,'default','127.0.2.69','Alive','UnChanged','NO','NO',1,'NO',0,2,'YES','NO',0,'NO',0,0,'node-69',138,275),(276,'default','127.0.2.69','Alive','UnChanged','NO','NO',1,'NO',0,3,'YES','NO',0,'NO',0,0,'node-69',138,276),(277,'default','127.0.2.70','Alive','UnChanged','NO','NO',1,'NO',0,0,'YES','NO',0,'NO',0,0,'node-70',139,277),(278,'default','127.0.2.70','Alive','UnChanged','NO','NO',1,'NO',0,1,'YES','NO',0,'NO',0,0,'node-70',139,278),(279,'default','127.0.2.70','Alive','UnChanged','NO','NO',1,'NO',0,2,'YES','NO',0,'NO',0,0,'node-70',140,279),(280,'default','127.0.2.70','Alive','UnChanged','NO','NO',1,'NO',0,3,'YES','NO',0,'NO',0,0,'node-70',140,280),(281,'default','127.0.2.71','Alive','UnChanged','NO','NO',1,'NO',0,0,'YES','NO',0,'NO',0,0,'node-71',141,281),(282,'default','127.0.2.71','Alive','UnChanged','NO','NO',1,'NO',0,1,'YES','NO',0,'NO',0,0,'node-71',141,282),(283,'default','127.0.2.71','Alive','UnChanged','NO','NO',1,'NO',0,2,'YES','NO',0,'NO',0,0,'node-71',142,283),(284,'default','127.0.2.71','Alive','UnChanged','NO','NO',1,'NO',0,3,'YES','NO',0,'NO',0,0,'node-71',142,284),(285,'default','127.0.2.72','Alive','UnChanged','NO','NO',1,'NO',0,0,'YES','NO',0,'NO',0,0,'node-72',143,285),(286,'default','127.0.2.72','Alive','UnChanged','NO','NO',1,'NO',0,1,'YES','NO',0,'NO',0,0,'node-72',143,286),(287,'default','127.0.2.72','Alive','UnChanged','NO','NO',1,'NO',0,2,'YES','NO',0,'NO',0,0,'node-72',144,287),(288,'default','127.0.2.72','Alive','UnChanged','NO','NO',1,'NO',0,3,'YES','NO',0,'NO',0,0,'node-72',144,288),(289,'default','127.0.2.73','Alive','UnChanged','NO','NO',1,'NO',0,0,'YES','NO',0,'NO',0,0,'node-73',145,289),(290,'default','127.0.2.73','Alive','UnChanged','NO','NO',1,'NO',0,1,'YES','NO',0,'NO',0,0,'node-73',145,290),(291,'default','127.0.2.73','Alive','UnChanged','NO','NO',1,'NO',0,2,'YES','NO',0,'NO',0,0,'node-73',146,291),(292,'default','127.0.2.73','Alive','UnChanged','NO','NO',1,'NO',0,3,'YES','NO',0,'NO',0,0,'node-73',146,292),(293,'default','127.0.2.74','Alive','UnChanged','NO','NO',1,'NO',0,0,'YES','NO',0,'NO',0,0,'node-74',147,293),(294,'default','127.0.2.74','Alive','UnChanged','NO','NO',1,'NO',0,1,'YES','NO',0,'NO',0,0,'node-74',147,294),(295,'default','127.0.2.74','Alive','UnChanged','NO','NO',1,'NO',0,2,'YES','NO',0,'NO',0,0,'node-74',148,295),(296,'default','127.0.2.74','Alive','UnChanged','NO','NO',1,'NO',0,3,'YES','NO',0,'NO',0,0,'node-74',148,296),(297,'default','127.0.2.75','Alive','UnChanged','NO','NO',1,'NO',0,0,'YES','NO',0,'NO',0,0,'node-75',149,297),(298,'default','127.0.2.75','Alive','UnChanged','NO','NO',1,'NO',0,1,'YES','NO',0,'NO',0,0,'node-75',149,298),(299,'default','127.0.2.75','Alive','UnChanged','NO','NO',1,'NO',0,2,'YES','NO',0,'NO',0,0,'node-75',150,299),(300,'default','127.0.2.75','Alive','UnChanged','NO','NO',1,'NO',0,3,'YES','NO',0,'NO',0,0,'node-75',150,300),(301,'default','127.0.2.76','Alive','UnChanged','NO','NO',1,'NO',0,0,'YES','NO',0,'NO',0,0,'node-76',151,301),(302,'default','127.0.2.76','Alive','UnChanged','NO','NO',1,'NO',0,1,'YES','NO',0,'NO',0,0,'node-76',151,302),(303,'default','127.0.2.76','Alive','UnChanged','NO','NO',1,'NO',0,2,'YES','NO',0,'NO',0,0,'node-76',152,303),(304,'default','127.0.2.76','Alive','UnChanged','NO','NO',1,'NO',0,3,'YES','NO',0,'NO',0,0,'node-76',152,304),(305,'default','127.0.2.77','Alive','UnChanged','NO','NO',1,'NO',0,0,'YES','NO',0,'NO',0,0,'node-77',153,305),(306,'default','127.0.2.77','Alive','UnChanged','NO','NO',1,'NO',0,1,'YES','NO',0,'NO',0,0,'node-77',153,306),(307,'default','127.0.2.77','Alive','UnChanged','NO','NO',1,'NO',0,2,'YES','NO',0,'NO',0,0,'node-77',154,307),(308,'default','127.0.2.77','Alive','UnChanged','NO','NO',1,'NO',0,3,'YES','NO',0,'NO',0,0,'node-77',154,308),(309,'default','127.0.2.78','Alive','UnChanged','NO','NO',1,'NO',0,0,'YES','NO',0,'NO',0,0,'node-78',155,309),(310,'default','127.0.2.78','Alive','UnChanged','NO','NO',1,'NO',0,1,'YES','NO',0,'NO',0,0,'node-78',155,310),(311,'default','127.0.2.78','Alive','UnChanged','NO','NO',1,'NO',0,2,'YES','NO',0,'NO',0,0,'node-78',156,311),(312,'default','127.0.2.78','Alive','UnChanged','NO','NO',1,'NO',0,3,'YES','NO',0,'NO',0,0,'node-78',156,312),(313,'default','127.0.2.79','Alive','UnChanged','NO','NO',1,'NO',0,0,'YES','NO',0,'NO',0,0,'node-79',157,313),(314,'default','127.0.2.79','Alive','UnChanged','NO','NO',1,'NO',0,1,'YES','NO',0,'NO',0,0,'node-79',157,314),(315,'default','127.0.2.79','Alive','UnChanged','NO','NO',1,'NO',0,2,'YES','NO',0,'NO',0,0,'node-79',158,315),(316,'default','127.0.2.79','Alive','UnChanged','NO','NO',1,'NO',0,3,'YES','NO',0,'NO',0,0,'node-79',158,316),(317,'default','127.0.2.80','Alive','UnChanged','NO','NO',1,'NO',0,0,'YES','NO',0,'NO',0,0,'node-80',159,317),(318,'default','127.0.2.80','Alive','UnChanged','NO','NO',1,'NO',0,1,'YES','NO',0,'NO',0,0,'node-80',159,318),(319,'default','127.0.2.80','Alive','UnChanged','NO','NO',1,'NO',0,2,'YES','NO',0,'NO',0,0,'node-80',160,319),(320,'default','127.0.2.80','Alive','UnChanged','NO','NO',1,'NO',0,3,'YES','NO',0,'NO',0,0,'node-80',160,320),(321,'default','127.0.2.81','Alive','UnChanged','NO','NO',1,'NO',0,0,'YES','NO',0,'NO',0,0,'node-81',161,321),(322,'default','127.0.2.81','Alive','UnChanged','NO','NO',1,'NO',0,1,'YES','NO',0,'NO',0,0,'node-81',161,322),(323,'default','127.0.2.81','Alive','UnChanged','NO','NO',1,'NO',0,2,'YES','NO',0,'NO',0,0,'node-81',162,323),(324,'default','127.0.2.81','Alive','UnChanged','NO','NO',1,'NO',0,3,'YES','NO',0,'NO',0,0,'node-81',162,324),(325,'default','127.0.2.82','Alive','UnChanged','NO','NO',1,'NO',0,0,'YES','NO',0,'NO',0,0,'node-82',163,325),(326,'default','127.0.2.82','Alive','UnChanged','NO','NO',1,'NO',0,1,'YES','NO',0,'NO',0,0,'node-82',163,326),(327,'default','127.0.2.82','Alive','UnChanged','NO','NO',1,'NO',0,2,'YES','NO',0,'NO',0,0,'node-82',164,327),(328,'default','127.0.2.82','Alive','UnChanged','NO','NO',1,'NO',0,3,'YES','NO',0,'NO',0,0,'node-82',164,328),(329,'default','127.0.2.83','Alive','UnChanged','NO','NO',1,'NO',0,0,'YES','NO',0,'NO',0,0,'node-83',165,329),(330,'default','127.0.2.83','Alive','UnChanged','NO','NO',1,'NO',0,1,'YES','NO',0,'NO',0,0,'node-83',165,330),(331,'default','127.0.2.83','Alive','UnChanged','NO','NO',1,'NO',0,2,'YES','NO',0,'NO',0,0,'node-83',166,331),(332,'default','127.0.2.83','Alive','UnChanged','NO','NO',1,'NO',0,3,'YES','NO',0,'NO',0,0,'node-83',166,332),(333,'default','127.0.2.84','Alive','UnChanged','NO','NO',1,'NO',0,0,'YES','NO',0,'NO',0,0,'node-84',167,333),(334,'default','127.0.2.84','Alive','UnChanged','NO','NO',1,'NO',0,1,'YES','NO',0,'NO',0,0,'node-84',167,334),(335,'default','127.0.2.84','Alive','UnChanged','NO','NO',1,'NO',0,2,'YES','NO',0,'NO',0,0,'node-84',168,335),(336,'default','127.0.2.84','Alive','UnChanged','NO','NO',1,'NO',0,3,'YES','NO',0,'NO',0,0,'node-84',168,336),(337,'default','127.0.2.85','Alive','UnChanged','NO','NO',1,'NO',0,0,'YES','NO',0,'NO',0,0,'node-85',169,337),(338,'default','127.0.2.85','Alive','UnChanged','NO','NO',1,'NO',0,1,'YES','NO',0,'NO',0,0,'node-85',169,338),(339,'default','127.0.2.85','Alive','UnChanged','NO','NO',1,'NO',0,2,'YES','NO',0,'NO',0,0,'node-85',170,339),(340,'default','127.0.2.85','Alive','UnChanged','NO','NO',1,'NO',0,3,'YES','NO',0,'NO',0,0,'node-85',170,340),(341,'default','127.0.2.86','Alive','UnChanged','NO','NO',1,'NO',0,0,'YES','NO',0,'NO',0,0,'node-86',171,341),(342,'default','127.0.2.86','Alive','UnChanged','NO','NO',1,'NO',0,1,'YES','NO',0,'NO',0,0,'node-86',171,342),(343,'default','127.0.2.86','Alive','UnChanged','NO','NO',1,'NO',0,2,'YES','NO',0,'NO',0,0,'node-86',172,343),(344,'default','127.0.2.86','Alive','UnChanged','NO','NO',1,'NO',0,3,'YES','NO',0,'NO',0,0,'node-86',172,344),(345,'default','127.0.2.87','Alive','UnChanged','NO','NO',1,'NO',0,0,'YES','NO',0,'NO',0,0,'node-87',173,345),(346,'default','127.0.2.87','Alive','UnChanged','NO','NO',1,'NO',0,1,'YES','NO',0,'NO',0,0,'node-87',173,346),(347,'default','127.0.2.87','Alive','UnChanged','NO','NO',1,'NO',0,2,'YES','NO',0,'NO',0,0,'node-87',174,347),(348,'default','127.0.2.87','Alive','UnChanged','NO','NO',1,'NO',0,3,'YES','NO',0,'NO',0,0,'node-87',174,348),(349,'default','127.0.2.88','Alive','UnChanged','NO','NO',1,'NO',0,0,'YES','NO',0,'NO',0,0,'node-88',175,349),(350,'default','127.0.2.88','Alive','UnChanged','NO','NO',1,'NO',0,1,'YES','NO',0,'NO',0,0,'node-88',175,350),(351,'default','127.0.2.88','Alive','UnChanged','NO','NO',1,'NO',0,2,'YES','NO',0,'NO',0,0,'node-88',176,351),(352,'default','127.0.2.88','Alive','UnChanged','NO','NO',1,'NO',0,3,'YES','NO',0,'NO',0,0,'node-88',176,352),(353,'default','127.0.2.89','Alive','UnChanged','NO','NO',1,'NO',0,0,'YES','NO',0,'NO',0,0,'node-89',177,353),(354,'default','127.0.2.89','Alive','UnChanged','NO','NO',1,'NO',0,1,'YES','NO',0,'NO',0,0,'node-89',177,354),(355,'default','127.0.2.89','Alive','UnChanged','NO','NO',1,'NO',0,2,'YES','NO',0,'NO',0,0,'node-89',178,355),(356,'default','127.0.2.89','Alive','UnChanged','NO','NO',1,'NO',0,3,'YES','NO',0,'NO',0,0,'node-89',178,356),(357,'default','127.0.2.90','Alive','UnChanged','NO','NO',1,'NO',0,0,'YES','NO',0,'NO',0,0,'node-90',179,357),(358,'default','127.0.2.90','Alive','UnChanged','NO','NO',1,'NO',0,1,'YES','NO',0,'NO',0,0,'node-90',179,358),(359,'default','127.0.2.90','Alive','UnChanged','NO','NO',1,'NO',0,2,'YES','NO',0,'NO',0,0,'node-90',180,359),(360,'default','127.0.2.90','Alive','UnChanged','NO','NO',1,'NO',0,3,'YES','NO',0,'NO',0,0,'node-90',180,360),(361,'default','127.0.2.91','Alive','UnChanged','NO','NO',1,'NO',0,0,'YES','NO',0,'NO',0,0,'node-91',181,361),(362,'default','127.0.2.91','Alive','UnChanged','NO','NO',1,'NO',0,1,'YES','NO',0,'NO',0,0,'node-91',181,362),(363,'default','127.0.2.91','Alive','UnChanged','NO','NO',1,'NO',0,2,'YES','NO',0,'NO',0,0,'node-91',182,363),(364,'default','127.0.2.91','Alive','UnChanged','NO','NO',1,'NO',0,3,'YES','NO',0,'NO',0,0,'node-91',182,364),(365,'default','127.0.2.92','Alive','UnChanged','NO','NO',1,'NO',0,0,'YES','NO',0,'NO',0,0,'node-92',183,365),(366,'default','127.0.2.92','Alive','UnChanged','NO','NO',1,'NO',0,1,'YES','NO',0,'NO',0,0,'node-92',183,366),(367,'default','127.0.2.92','Alive','UnChanged','NO','NO',1,'NO',0,2,'YES','NO',0,'NO',0,0,'node-92',184,367),(368,'default','127.0.2.92','Alive','UnChanged','NO','NO',1,'NO',0,3,'YES','NO',0,'NO',0,0,'node-92',184,368),(369,'default','127.0.2.93','Alive','UnChanged','NO','NO',1,'NO',0,0,'YES','NO',0,'NO',0,0,'node-93',185,369),(370,'default','127.0.2.93','Alive','UnChanged','NO','NO',1,'NO',0,1,'YES','NO',0,'NO',0,0,'node-93',185,370),(371,'default','127.0.2.93','Alive','UnChanged','NO','NO',1,'NO',0,2,'YES','NO',0,'NO',0,0,'node-93',186,371),(372,'default','127.0.2.93','Alive','UnChanged','NO','NO',1,'NO',0,3,'YES','NO',0,'NO',0,0,'node-93',186,372),(373,'default','127.0.2.94','Alive','UnChanged','NO','NO',1,'NO',0,0,'YES','NO',0,'NO',0,0,'node-94',187,373),(374,'default','127.0.2.94','Alive','UnChanged','NO','NO',1,'NO',0,1,'YES','NO',0,'NO',0,0,'node-94',187,374),(375,'default','127.0.2.94','Alive','UnChanged','NO','NO',1,'NO',0,2,'YES','NO',0,'NO',0,0,'node-94',188,375),(376,'default','127.0.2.94','Alive','UnChanged','NO','NO',1,'NO',0,3,'YES','NO',0,'NO',0,0,'node-94',188,376),(377,'default','127.0.2.95','Alive','UnChanged','NO','NO',1,'NO',0,0,'YES','NO',0,'NO',0,0,'node-95',189,377),(378,'default','127.0.2.95','Alive','UnChanged','NO','NO',1,'NO',0,1,'YES','NO',0,'NO',0,0,'node-95',189,378),(379,'default','127.0.2.95','Alive','UnChanged','NO','NO',1,'NO',0,2,'YES','NO',0,'NO',0,0,'node-95',190,379),(380,'default','127.0.2.95','Alive','UnChanged','NO','NO',1,'NO',0,3,'YES','NO',0,'NO',0,0,'node-95',190,380),(381,'default','127.0.2.96','Alive','UnChanged','NO','NO',1,'NO',0,0,'YES','NO',0,'NO',0,0,'node-96',191,381),(382,'default','127.0.2.96','Alive','UnChanged','NO','NO',1,'NO',0,1,'YES','NO',0,'NO',0,0,'node-96',191,382),(383,'default','127.0.2.96','Alive','UnChanged','NO','NO',1,'NO',0,2,'YES','NO',0,'NO',0,0,'node-96',192,383),(384,'default','127.0.2.96','Alive','UnChanged','NO','NO',1,'NO',0,3,'YES','NO',0,'NO',0,0,'node-96',192,384); /*!40000 ALTER TABLE `resources` ENABLE KEYS */; UNLOCK TABLES; -- -- Table structure for table `schema` -- DROP TABLE IF EXISTS `schema`; SET @saved_cs_client = @@character_set_client; SET character_set_client = utf8; CREATE TABLE `schema` ( `version` varchar(255) NOT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1; SET character_set_client = @saved_cs_client; -- -- Dumping data for table `schema` -- LOCK TABLES `schema` WRITE; /*!40000 ALTER TABLE `schema` DISABLE KEYS */; INSERT INTO `schema` VALUES ('2.3.0+svn1369'); /*!40000 ALTER TABLE `schema` ENABLE KEYS */; UNLOCK TABLES; /*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; /*!40101 SET SQL_MODE=@OLD_SQL_MODE */; /*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; /*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; /*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; /*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; -- Dump completed on 2008-10-23 16:18:51 oar-2.5.7/tests/scheduler/data/003_oar.conf0000644015014700017500000003243512677211234020000 0ustar neyronneyron# This file must have the bash variable assignment syntax # $Id: oar.conf 1535 2008-07-28 10:35:09Z neyron $ ######################### # General configuration # ############################################################################### # # Database type ("mysql" or "Pg") DB_TYPE="mysql" # DataBase hostname DB_HOSTNAME="127.0.0.1" # Database port DB_PORT="3307" # Database base name DB_BASE_NAME="oar" # DataBase user name DB_BASE_LOGIN="oar" # DataBase user password DB_BASE_PASSWD="oar" # DataBase read only user name #DB_BASE_LOGIN_RO="oar_ro" # DataBase read only user password #DB_BASE_PASSWD_RO="oar_ro" # OAR server hostname SERVER_HOSTNAME="localhost" # OAR server port SERVER_PORT="6666" # when the user does not specify a -l option then oar use this OARSUB_DEFAULT_RESOURCES="/resource_id=1" # force use of job key even if --use-job-key or -k is not set. OARSUB_FORCE_JOB_KEY="no" # OAR log level: 3(debug+warnings+errors), 2(warnings+errors), 1(errors) LOG_LEVEL="3" # If you want to debug oarexec on nodes then affect 1 (only effective if # DETACH_JOB_FROM_SERVER = 1) OAREXEC_DEBUG_MODE="0" # oarexec default temporary directory # This value MUST be the same in all oar.conf on all nodes of the cluster OAR_RUNTIME_DIRECTORY="/var/lib/oar" # OAR log file LOG_FILE="/var/log/oar.log" # OAR Allowed networks # Networks or hosts allowed to submit jobs to OAR and compute nodes may be # specified here ALLOWED_NETWORKS="127.0.0.1/32 0.0.0.0/0" # Specify where we are connected with a job of the deploy type DEPLOY_HOSTNAME="127.0.0.1" # Specify where we are connected with a job of the cosystem type COSYSTEM_HOSTNAME="127.0.0.1" # Specify the database field to use to fill the file on the first node of the # job in $OAR_NODE_FILE (default is 'network_address'). Only resources with # type=default are displayed in this file. #NODE_FILE_DB_FIELD="network_address" # Specify the database field that will be considered to fill the node file used # by the user on the first node of the job. for each different value of this # field then OAR will put 1 line in the node file(by default "cpu"). #NODE_FILE_DB_FIELD_DISTINCT_VALUES="cpu" # If you want to free a process per job on the server you can change this tag # into 1 (you must enable all nodes to connect to SERVER_PORT on the # SERVER_HOSTNAME) DETACH_JOB_FROM_SERVER="0" # Command to use to connect to other nodes (default is "ssh" in the PATH) OPENSSH_CMD="/usr/bin/ssh -p 6667" # Set the timeout value for each ssh connection (default is 120) #OAR_SSH_CONNECTION_TIMEOUT="200" # If you have installed taktuk and want to use it to manage remote # admnistration commands then give the full command path # (with your options except "-m" and "-o"). # You don t also have to give any taktuk command. # (taktuk version must be >= 3.6) #TAKTUK_CMD="/usr/bin/taktuk -s" ############################################################################### ######################################################################## # Pingchecker options: # # How to check if the nodes have a good health or not. This choice is # # directly linked to the Suspected state of the resources. # # By default OAR uses only "ping". it requests no configuration but it # # is not accurate about the state of the nodes and it is slow # ############################################################################### # # Set the frequency for checking Alive and Suspected resources (0 means never) FINAUD_FREQUENCY="0" # Set time after which Suspected resources become Dead (default is 0 and it # means never) #DEAD_SWITCH_TIME="600" # Uncomment only one of the following PINGCHECKER configuration # sentinelle.pl # If you want to use sentinelle.pl then you must use this tag. # (sentinelle.pl is like a "for" of ssh but it adds timeout and window to # avoid overloading the server) # (sentinelle.pl is provided with OAR in the install directory) #PINGCHECKER_SENTINELLE_SCRIPT_COMMAND="/usr/lib/oar/sentinelle.pl -t 5 -w 20" # Taktuk # taktuk may be used to check aliveness of nodes. # Give the arguments of the taktuk command WITHOUT format outputs # (DO NOT use "-o" option). # See TAKTUK_CMD tag in this file to specify the path of the taktuk command #PINGCHECKER_TAKTUK_ARG_COMMAND="-t 3 broadcast exec [ true ]" #PINGCHECKER_TAKTUK_ARG_COMMAND="-t 3 broadcast exec [ oarnodecheckquery ] #PINGCHECKER_TAKTUK_ARG_COMMAND="-t 3 broadcast exec [ /path/on/nodes/to/my/check/script.sh ]" # fping # fping may be used instead of ping to check aliveness of nodes. # uncomment next line to use fping. Give the complete command path. #PINGCHECKER_FPING_COMMAND="/usr/bin/fping -q" # nmap # nmap may be used instead of ping to check aliveness of nodes. # uncomment next line to use nmap. Give the complete command path. # It will test to connect on the ssh port (22) #PINGCHECKER_NMAP_COMMAND="/usr/bin/nmap -p 22 -n -T5" # GENERIC command # a specific script may be used instead of ping to check aliveness of nodes. # uncomment next line and give the complete command path and its arguments. # The script must return bad nodes on STDERR (1 line for a bad node and it must # have exactly the same name that OAR has given in argument of the command) PINGCHECKER_GENERIC_COMMAND="/bin/true" ############################################################################### ###################### # Mail configuration # ############################################################################### # # OAR information may be notified by email to the administror # set accordingly to your configuration and uncomment the next lines to # activate the feature. # (If this tag is right configured then users can use "--notify" option of oarsub # to receive mails about their jobs) #MAIL_SMTP_SERVER="smtp.serveur.com" # You can specify several recipients with a comma between each email address #MAIL_RECIPIENT="user@domain.com" #MAIL_SENDER="oar@domain.com" ############################################################################### ########### # Scripts # ############################################################################### # # Set the timeout for the prologue and epilogue execution on computing nodes #PROLOGUE_EPILOGUE_TIMEOUT="60" # Files to execute before and after each job on the first computing node # (by default nothing is executed) #PROLOGUE_EXEC_FILE="/path/to/prog" #EPILOGUE_EXEC_FILE="/path/to/prog" # Set the timeout for the prologue and epilogue execution on the OAR server #SERVER_PROLOGUE_EPILOGUE_TIMEOUT="60" # Files to execute before and after each job on the OAR server (by default # nothing is executed) #SERVER_PROLOGUE_EXEC_FILE="/path/to/prog" #SERVER_EPILOGUE_EXEC_FILE="/path/to/prog" ######################## # Scheduler parameters # ############################################################################### # # Maximum of seconds used by a scheduler SCHEDULER_TIMEOUT="60" # Time to add between each jobs (for example: time for administration tasks or # time to let computers to reboot) SCHEDULER_JOB_SECURITY_TIME="1" # Minimum time in seconds that can be considered like a hole where a job could # be scheduled in (if you have performance problems, you can try to increase # this) SCHEDULER_GANTT_HOLE_MINIMUM_TIME="300" # You can add an order preference on resources assigned by the # system(SQL ORDER syntax) SCHEDULER_RESOURCE_ORDER="scheduler_priority ASC, suspended_jobs ASC, network_address DESC, resource_id ASC" # If next line is uncommented then OAR will automatically update the value of # "scheduler_priority" field corresponding to the besteffort jobs. # The syntax is field names separated by "/". The value affected to # "scheduler_priority" depends of the position of the field name. SCHEDULER_PRIORITY_HIERARCHY_ORDER="/host/cpu/core/" # You can specify a type of resources that will be always assigned for each job # (for exemple: enable all jobs to be able to log on the cluster frontales) # For more information, see the FAQ #SCHEDULER_RESOURCES_ALWAYS_ASSIGNED_TYPE="frontal" # This says to the scheduler to treate resources of these types, where there is # a suspended job, like free ones. So some other jobs can be scheduled on these # resources. (list resource types separate with spaces; Default value is # nothing so no other job can be scheduled on suspended job resources) #SCHEDULER_AVAILABLE_SUSPENDED_RESOURCE_TYPE="default licence VLAN" SCHEDULER_AVAILABLE_SUSPENDED_RESOURCE_TYPE="default" # For a debug purpose, scheduler decisions can be logged into the database # Uncomment the next line in order to activate the logging mechanism SCHEDULER_LOG_DECISIONS="no" # Time to wait when a reservation has not got all resources that it has reserved # (some resources may have become Suspected or Absent since the job submission) # before to launch the job on the remaining resources (default is 300s) #RESERVATION_WAITING_RESOURCES_TIMEOUT="300" # Set the granularity of the OAR accounting feature (in seconds) # Used by the oaraccounting command and the # oar_sched_gantt_with_timesharing_and_fairsharing to calculate the timesharing # policy. Default is 1 day (86400s) #ACCOUNTING_WINDOW="86400" ############################################################################### ########################################################################### # If you want to manage starting and stopping node feature. OAR gives you # # this API: # ############################################################################### # # When OAR scheduler wants some nodes to wake up then it launches this command # and puts on its STDIN the list of nodes to wake up (one hostname by line). # The scheduler looks at the available_upto field in the resources table to know # if the node will be started for enough time. #SCHEDULER_NODE_MANAGER_WAKE_UP_CMD="/path/to/the/command with your args" # When OAR considers that some nodes can be shut down, it launches this command # and puts the node list on its STDIN(one hostname by line). #SCHEDULER_NODE_MANAGER_SLEEP_CMD="/path/to/the/command args" #SCHEDULER_NODE_MANAGER_SLEEP_CMD="taktuk -s -f - -t 3 b e t 3 k 9 [ sudo halt ]" #SCHEDULER_NODE_MANAGER_SLEEP_CMD="/usr/local/oar/sentinelle.pl -f - -t 3 -p 'sudo halt'" # Parameters for the scheduler to decide when a node is idle. # Number of seconds since the last job was terminated on nodes #SCHEDULER_NODE_MANAGER_IDLE_TIME="600" # Parameters for the scheduler to decide if a node will have enough time to sleep. # Number of seconds before the next job #SCHEDULER_NODE_MANAGER_SLEEP_TIME="600" ################################################################################ ############################## # Suspend/Resume job feature # ############################################################################### # # Name of the perl script that manages suspend/resume. # (default is /etc/oar/suspend_resume_manager.pl) #SUSPEND_RESUME_FILE="/etc/oar/suspend_resume_manager.pl" # Files to execute just after a job was suspended and just before a job was resumed #JUST_AFTER_SUSPEND_EXEC_FILE="/path/to/prog" #JUST_BEFORE_RESUME_EXEC_FILE="/path/to/prog" # Timeout for the two previous scripts #SUSPEND_RESUME_SCRIPT_TIMEOUT="60" ############################################################################### ################## # CPUSET feature # ############################################################################### # Indicate the name of the database field that contains the cpu number of the node. # If this option is set then users must use oarsh instead of ssh to walk on # each nodes that they have reserved via oarsub. # Look at Tools/oarsh/README # (if defined, this otion turn on the cpuset feature in OAR) #CPUSET_RESOURCE_PROPERTY_DB_FIELD="cpuset" # Name of the perl script that manages cpuset. # (default is /etc/oar/cpuset_manager.pl which handles the linux kernel cpuset) CPUSET_FILE="/etc/oar/cpuset_manager.pl" # Path of the relative directory where the cpusets will be created on each # nodes(same value than in /proc/self/cpuset) # If you change the default value (/oar) then you have to edit the file # cpuset_manager.pl and change it accordingly. CPUSET_PATH="/oar" ############################################################################### ######### # OARSH # ############################################################################### # # This variable must be set to enable the use of oarsh from a frontale node # Otherwise you must not set this variable if you are not on a frontale #OARSH_OARSTAT_CMD="/usr/bin/oarstat" # The following variable adds options to ssh (or OPENSSH_CMD if configured). # If one option is not handled by your ssh version just remove it BUT be # careful because these options are there for security reasons OARSH_OPENSSH_DEFAULT_OPTIONS="-oProxyCommand=none -oPermitLocalCommand=no" # If you set this variable to something different from 0 then oarsh will act # like a normal ssh **without** CPUSET restriction. # WARNING: this is a critical functionality (this is only useful if users want # to have a command to connect on every nodes without taking care of there ssh # configuration and act like a ssh) #OARSH_BYPASS_WHOLE_SECURITY="0" ############################################################################### #DESKTOP_COMPUTING_ALLOW_CREATE_NODE="0" #DESKTOP_COMPUTING_EXPIRY="300" #STAGEOUT_DIR="/var/lib/oar/stageouts/" #STAGEIN_DIR="/var/lib/oar/stageins" #STAGEIN_CACHE_EXPIRY="144" oar-2.5.7/tests/scheduler/README0000644015014700017500000001057312677211234015734 0ustar neyronneyron= About = This directory proposes a unit tests suite for OAR's scheduler. It basically consists of a framework to help writing little scripts that will check the scheduler's decisions. Since OAR's API comes down to the Database, input and output data for the unit tests are SQL data. Input data are SQL file to be generated using mysqldump on a live OAR installation, or on a fake installation where resources aren't real (e.g. all resources targets are on the single test machine), then injected in the test database. Output data is actually the test database as it is let once the scheduler ran. Unit test results are to be computed using SQL statements on that database. Several ideas behind this test framework come from Perl unit test packages mechanism (Test::More). = Notes = As a matter of implementation, it was needed to be able to run the Database server with a faked time, so that input SQL files are not outdated once inserted later after their creation. This is achieved using the faketime program, and tranparent thanks to the framework functions. Only the MySQL database is supported for now. A dedicated MySQL server is run for tests, hence you must watch out which TCP port is available: by default the dedicated MySQL server run on the 3307 port in order to avoid an obvious conflict with the default MySQL server instance which might be run on system startup. = Files = Any test is a file which is prefixed by 3 digits, e.g. 001_advance_reservation_with_absent_resource.sh . A test file uses file with the same prefix in the "data" directory, e.g. 001_oar.conf . Tests use bash functions that are defined in the "scripts" directory. Upon a test script execution, the execution environement is created in the "build" directory. Finally the "src" symlink is pointing to OAR source directory where the installation Makefile is located, e.g. /trunk . = Configuration = Running those tests requires: * MySQL server * MySQL client * faketime * perl, aso... The src symlink pointing to OAR source directory, e.g. /trunk . = Running tests = Running a test is only the matter of running the 3 digit prefixed bash script. The test might output to stderr a lot of verbose information, but only tests results goes to stdout. A test is successful if it outputs only "OK: ..." lines. A test fails as soon as it outputs one "KO: ..." line. = Writing tests = The easiest way to write a test is to copy one of the existing one, and adapt it. The test script process begins with the test_cleanup call, everthing above should be left as it is. 3 kinds of functions are provided: * base, which provides the framework base functions, related to the actual testing * mysql, which provides functions to handle the MySQL database process * oar, which provides functions to handle OAR mechanisms == base == * debug(message) Print (to stderr) debug info if debug is activated (DEBUG variable) * test_print_ok(message) Print the OK flag, along with a message * test_print_ko(message) Print the KO flag, along with a message * test_exit_status(message, command) { Print the OK or KO flag depending on the exit status of command, along with a message * test_preparer() Prepare the test environment * test_cleanup() Clean-up the test environment == MySQL == * mysql_check_oar_conf() Check that the oar.conf used if ok for the test * mysql_copy_config(file=my.cnf) Fetch mysql config file from the data directory, by adding the test prefix to file. file defaults to "my.cnf". * mysql_init() Initialize the dedicated MySQL server own data. * mysql_start(date=null) Start the dedicated MySQL server, possibily a the specified date, or now if no date is given. * mysql_stop() Stop the dedicated MySQL server. * mysql_create_oar_db() Create the oar DB, as given in oar.conf, and grant privilegies. * mysql_query(query) Run the SQL query that is provided as parameter. * mysql_query_from_file(file) Run the SQL query from file, looked up in the data directory after prepending the test prefix. == OAR == * oar_copy_config(file=oar.conf) Fetch OAR config file from the data directory, by adding the test prefix to file. file defaults to "oar.conf". * oar_source_conf() Source OAR parameters, making then available for the test functions. * oar_install() Perform OAR installation within the test enviroment. oar_run_scheduler() Run one pass of OAR meta scheduler, i.e. one pass of the queue's scheduler on each queue. oar-2.5.7/tests/scheduler/scripts/0000755015014700017500000000000012677211234016535 5ustar neyronneyronoar-2.5.7/tests/scheduler/scripts/oar.sh0000644015014700017500000000242712677211234017657 0ustar neyronneyron#!/bin/bash # $Id$ # Function set to handle oar setup within tests BUILDDIR=${BUILDDIR:-build} DATADIR=${DATADIR:-data} oar_copy_config() { local FILE=${1:-oar.conf} if [ -r "$DATADIR/${BASEPREFIX}_$FILE" ]; then debug "Copying OAR config file from $FILE" mkdir -p $BUILDDIR/etc/oar cp $DATADIR/${BASEPREFIX}_$FILE $BUILDDIR/etc/oar/oar.conf debug "done" else echo "Can't read file: $FILE" exit 1 fi } oar_source_config() { debug "Sourcing OAR config" . $BUILDDIR/etc/oar/oar.conf debug "done" } oar_install() { debug "Installing OAR in the build dir" ( cd $SRCDIR make server-install server-setup \ ETCDIR=$BUILDDIR/etc \ VARLIBDIR=$BUILDDIR/var \ RUNDIR=$BUILDDIR/var/run \ LOGDIR=$BUILDDIR/var/log \ OARUSER=$(id -un) \ OAROWNERGROUP=$(id -gn) \ PREFIX=$BUILDDIR/usr/local \ ROOTUSER=$(id -un) \ ROOTGROUP=$(id -gn) \ > /dev/null ) debug "done" } oar_run_scheduler() { debug "Starting OAR Meta-Scheduler" ( cd $BUILDDIR/usr/local/oar OARCONFFILE=$BUILDDIR/etc/oar/oar.conf OARDIR=$BUILDDIR/usr/local/oar ./oar_meta_sched 1>&2 ) debug "done" } oar-2.5.7/tests/scheduler/scripts/base.sh0000644015014700017500000000127212677211234020005 0ustar neyronneyron#!/bin/bash # $Id$ # function set for the test base setup DEBUG=${DEBUG:-0} BUILDDIR=${BUILDDIR:-build} debug() { if [ $DEBUG -gt 0 ]; then echo $* 1>&2 fi } test_print_ok() { echo OK: $* } test_print_ko() { echo KO: $* } test_exit_status () { local TXT=$1 shift if eval $*; then test_print_ok $TXT else test_print_ko $TXT fi } test_prepare() { debug "Create base directories in the build directory" mkdir -p $BUILDDIR/etc mkdir -p $BUILDDIR/tmp mkdir -p $BUILDDIR/usr/local/lib mkdir -p $BUILDDIR/usr/local/bin mkdir -p $BUILDDIR/var/lib mkdir -p $BUILDDIR/var/run debug "done" } test_cleanup() { debug "Clean-up build directory" rm $BUILDDIR/* -rf debug "done" } oar-2.5.7/tests/scheduler/scripts/mysql.sh0000644015014700017500000000607412677211234020245 0ustar neyronneyron#!/bin/bash # $Id$ # function set to handle mysql within tests BUILDDIR=${BUILDDIR:-build} DATADIR=${DATADIR:-data} mysql_check_oar_conf() { if [ "x$DB_HOSTNAME" != "x127.0.0.1" ]; then echo "Please set DB_HOSTNAME=\"127.0.0.1\" in oar.conf (localhost means unix-socket)" exit 1 fi debug "OAR config is ok" } mysql_copy_config() { local FILE=${1:-my.cnf} if [ -r "$DATADIR/${BASEPREFIX}_$FILE" ]; then debug "Copying MySQL config file from $FILE" mkdir -p $BUILDDIR/etc/mysql cp $DATADIR/${BASEPREFIX}_$FILE $BUILDDIR/etc/mysql/my.cnf debug "done" else echo "Can't read file: $FILE" exit 1 fi } mysql_init() { debug "Initializing MySQL data..." mysql_install_db --no-defaults --datadir=$BUILDDIR/var/lib/mysql > /dev/null 2>&1 debug "done" } mysql_start() { if ! [ -r $BUILDDIR/var/run/mysqld.pid ]; then if [ -z "$1" ]; then debug "Starting MySQL..." mysqld_safe --defaults-file=$BUILDDIR/etc/mysql/my.cnf \ --user=$USER \ --pid-file=$BUILDDIR/var/run/mysqld.pid \ --socket=$BUILDDIR/var/run/mysqld.sock \ --port=${DB_PORT:-3306} \ --datadir=$BUILDDIR/var/lib/mysql \ > /dev/null 2>&1 & else debug "Starting MySQL at time $@..." faketime -f "$@" mysqld_safe --defaults-file=$BUILDDIR/etc/mysql/my.cnf \ --user=$USER \ --pid-file=$BUILDDIR/var/run/mysqld.pid \ --socket=$BUILDDIR/var/run/mysqld.sock \ --port=${DB_PORT:-3306} \ --datadir=$BUILDDIR/var/lib/mysql \ > /dev/null 2>&1 & fi sleep 1 while ! mysqladmin --no-defaults \ --socket=$BUILDDIR/var/run/mysqld.sock \ ping > /dev/null 2>&1 ; do sleep 1 debug "Not there yet..." done debug "done" else debug "MySQL is already running (pid file found)" fi } mysql_create_oar_db() { debug "Creating OAR database..." cat < /dev/null 2>&1 ; do debug "MySQL still there..." sleep 1 done while [ -e "$BUILDDIR/var/run/mysqld.pid" ]; do debug "Pidfile still there..." sleep 1 done debug "done" else echo "No pid found, is MySQL really running ?" exit 1 fi } oar-2.5.7/tests/scheduler/003_heavy_load.sh0000755015014700017500000000145312677211234020105 0ustar neyronneyron#!/bin/bash # $Id: 001_advance_reservation_with_absent_resource.sh 1712 2008-10-17 08:41:53Z neyron $ # Basic example of test scenario BASENAME=${0#$PWD/} BASEPREFIX=${BASENAME%%_*} BASEDIR=$PWD/${BASENAME%/*} BUILDDIR=$BASEDIR/build DATADIR=$BASEDIR/data SCRIPTDIR=$BASEDIR/scripts SRCDIR=$BASEDIR/src DEBUG=1 . $SCRIPTDIR/base.sh . $SCRIPTDIR/oar.sh . $SCRIPTDIR/mysql.sh test_cleanup test_prepare oar_install oar_copy_config oar_source_config mysql_check_oar_conf mysql_copy_config mysql_init mysql_start "2008-10-23 15:00:00" mysql_create_oar_db mysql_query_from_file heavy_load.sql oar_run_scheduler THRESHOLD=42 test_exit_status "Scheduler performance test (threshold = $THRESHOLD)" \ mysql_query "SELECT count\(*\) FROM gantt_jobs_predictions" \| \( read \; test \$REPLY -ge $THRESHOLD \) mysql_stop oar-2.5.7/tests/scheduler/001_advance_reservation_with_absent_resource.sh0000755015014700017500000000173612677211234026314 0ustar neyronneyron#!/bin/bash # $Id$ # Basic example of test scenario BASENAME=${0#$PWD/} BASEPREFIX=${BASENAME%%_*} BASEDIR=$PWD/${BASENAME%/*} BUILDDIR=$BASEDIR/build DATADIR=$BASEDIR/data SCRIPTDIR=$BASEDIR/scripts SRCDIR=$BASEDIR/src DEBUG=1 . $SCRIPTDIR/base.sh . $SCRIPTDIR/oar.sh . $SCRIPTDIR/mysql.sh test_cleanup test_prepare oar_install oar_copy_config oar_source_config mysql_check_oar_conf mysql_copy_config mysql_init mysql_start "2008-10-09 18:00:00" mysql_create_oar_db mysql_query_from_file advance_reservation_with_absent_resource.sql oar_run_scheduler test_exit_status "Scheduler before advance reseration start time" \ mysql_query "SELECT state, reservation FROM jobs WHERE job_id = 1" \| grep -q -e "^Waiting[[:space:]]Scheduled$" mysql_stop mysql_start "2008-10-09 20:01:00" oar_run_scheduler test_exit_status "Scheduler at advance reseration start time" \ mysql_query "SELECT state, reservation FROM jobs WHERE job_id = 1" \| grep -q -e "^toLaunch[[:space:]]Scheduled$" mysql_stop oar-2.5.7/tests/scheduler/000_basic.sh0000755015014700017500000000121212677211234017041 0ustar neyronneyron#!/bin/bash # $Id$ # Basic example of test scenario BASENAME=${0#$PWD/} BASEPREFIX=${BASENAME%%_*} BASEDIR=$PWD/${BASENAME%/*} BUILDDIR=$BASEDIR/build DATADIR=$BASEDIR/data SCRIPTDIR=$BASEDIR/scripts SRCDIR=$BASEDIR/src DEBUG=1 . $SCRIPTDIR/base.sh . $SCRIPTDIR/oar.sh . $SCRIPTDIR/mysql.sh test_cleanup test_prepare oar_install oar_copy_config oar_source_config mysql_check_oar_conf mysql_copy_config mysql_init mysql_start mysql_create_oar_db mysql_query_from_file mysql_structure.sql mysql_query_from_file default_data.sql mysql_query_from_file mysql_default_admission_rules.sql oar_run_scheduler mysql_stop test_print_ok "Sanity test is ok" oar-2.5.7/tests/scheduler/002_advance_reservation_with_dead_resource.sh0000755015014700017500000000173412677211234025734 0ustar neyronneyron#!/bin/bash # $Id$ # Basic example of test scenario BASENAME=${0#$PWD/} BASEPREFIX=${BASENAME%%_*} BASEDIR=$PWD/${BASENAME%/*} BUILDDIR=$BASEDIR/build DATADIR=$BASEDIR/data SCRIPTDIR=$BASEDIR/scripts SRCDIR=$BASEDIR/src DEBUG=1 . $SCRIPTDIR/base.sh . $SCRIPTDIR/oar.sh . $SCRIPTDIR/mysql.sh test_cleanup test_prepare oar_install oar_copy_config oar_source_config mysql_check_oar_conf mysql_copy_config mysql_init mysql_start "2008-10-09 18:00:00" mysql_create_oar_db mysql_query_from_file advance_reservation_with_dead_resource.sql oar_run_scheduler test_exit_status "Scheduler before advance reseration start time" \ mysql_query "SELECT state, reservation FROM jobs WHERE job_id = 1" \| grep -q -e "^Waiting[[:space:]]Scheduled$" mysql_stop mysql_start "2008-10-09 20:01:00" oar_run_scheduler test_exit_status "Scheduler at advance reseration start time" \ mysql_query "SELECT state, reservation FROM jobs WHERE job_id = 1" \| grep -q -e "^toLaunch[[:space:]]Scheduled$" mysql_stop oar-2.5.7/tests/oarsub.expect0000755015014700017500000000112012677211234015572 0ustar neyronneyron#!/usr/bin/expect set user "pneyron" set prompt "${user}@\\w+-\\d+:.+\$$" log_user 0 spawn ssh -t genepi.g5k oarsub -I set timeout 60 expect "Generate a job key..." { send_user "OK generate job key\n" } expect -re "OAR_JOB_ID=\(\\d+\)" { set jobid $expect_out(1,string) send_user "OK got jobid: $jobid\n" } expect -re $prompt send "ls -l /var/lib/oar/${jobid}\n" expect -re "-rw-r--r-- 1 oar oar" { send_user "OK nodefile is readable\n" } expect -re $prompt send "cat /proc/self/cpuset\n" expect "/oar/${user}_${jobid}" { send_user "OK got correct cpuset\n" } #interact send eof oar-2.5.7/tests/oarsub.expect.pl0000755015014700017500000000470612677211234016221 0ustar neyronneyron#!/usr/bin/perl -w # $Id$ use strict; use warnings; use Data::Dumper; use Expect; my $prompt = qr/^\w+@\w+-\d+:.+\$\s$/m; my $timeout = 10; my $command = "ssh -t rennes.g5k oarsub -I -l core=1,walltime=0:05:00"; my $exp = new Expect; $exp->raw_pty(0); $exp->log_user(1); $exp->exp_internal(0); $exp->restart_timeout_upon_receive(1); my $jobid; my $nodefile; my $cpuset; $exp ->spawn($command) or die "Cannot spawn $command: $!\n"; $exp->expect($timeout, [ qr/^Generate a job key...\r\n$/m => sub { my $exp = shift; print "--> OK generate job key\n"; exp_continue; } ], [ qr/^OAR_JOB_ID=(\d+)\r\n$/m => sub { my $exp = shift; $jobid = ($exp->matchlist())[0]; print "--> OK got job id: $jobid\n"; exp_continue; } ], [ $prompt => sub { my $exp = shift; # print "--> OK got prompt\n"; } ], [ eof => sub { my $exp = shift; die "--> Premature EOF !\n"; } ], [ timeout => sub { my $exp = shift; die "--> Timeout !\n"; } ] ); $exp->send("echo \$OAR_NODEFILE\n"); $exp->expect($timeout, [ qr/^(.+\/$jobid)\r$/m => sub { my $exp = shift; $nodefile = ($exp->matchlist())[0]; print "--> OK got nodefile: $nodefile\n"; exp_continue; } ], [ $prompt => sub { my $exp = shift; # print "--> OK got prompt\n"; } ], [ eof => sub { my $exp = shift; die "--> Premature EOF !\n"; } ], [ timeout => sub { my $exp = shift; die "--> Timeout !\n"; } ] ); $exp->send("cat /proc/self/cpuset\n"); $exp->expect($timeout, [ qr/^(\/oar\/\w+_$jobid)\r$/m => sub { my $exp = shift; $cpuset = ($exp->matchlist())[0]; print "--> OK got cpuset: $cpuset\n"; exp_continue; } ], [ $prompt => sub { my $exp = shift; # print "--> OK got prompt\n"; } ], [ eof => sub { my $exp = shift; die "--> Premature EOF !\n"; } ], [ timeout => sub { my $exp = shift; die "--> Timeout !\n"; } ] ); #print "--> Entering interactive session\n"; #$exp->interact(\*STDIN, '\cq' ); #print "--> Interactive session ended\n"; $exp->send(eof); oar-2.5.7/sources/0000755015014700017500000000000012677211234013411 5ustar neyronneyronoar-2.5.7/sources/extra/0000755015014700017500000000000012677211234014534 5ustar neyronneyronoar-2.5.7/sources/extra/cpp-scheduler/0000755015014700017500000000000012677211234017272 5ustar neyronneyronoar-2.5.7/sources/extra/cpp-scheduler/Oar_iolib.H0000644015014700017500000002674212677211234021315 0ustar neyronneyron#ifndef OAR_IOLIB_H #define OAR_IOLIB_H #include #include "Oar_resource_tree.H" using namespace std; /* Type utilisé pour l'extraction de des données (pas de hashref par query) Version prise de la doc OAR le 8 octobre 2008 (OAR >= 2.3.0) */ namespace iolib { struct resources_iolib { unsigned int resource_id; // INT UNSIGNED resource identifier string type; // VARCHAR(100) DEFAULT "default" resource type (used // for licence resources for example) string network_address; // VARCHAR(100) node name (used to connect // via SSH) string state; // ENUM('Alive', 'Dead' , 'Suspected', 'Absent') // resource state string next_state;// ENUM('UnChanged', 'Alive', 'Dead', 'Absent', // 'Suspected') DEFAULT 'UnChanged' state for the // resource to switch bool finaud_decision; // ENUM('YES', 'NO') DEFAULT 'NO' tell if // the actual state results in a "finaud" // module decision bool next_finaud_decision; // ENUM('YES', 'NO') DEFAULT 'NO' tell // if the next node state results in a // "finaud" module decision int state_num; // INT corresponding state number (useful with the // SQL "ORDER" query) bool suspended_jobs; // ENUM('YES','NO') specify if there is // at least one suspended job on the // resource unsigned int scheduler_priority;// INT UNSIGNED arbitrary number // given by the system to select // resources with more // intelligence string switch_name; // VARCHAR(50) name of the switch unsigned int cpu; // INT UNSIGNED global cluster cpu number unsigned int cpuset; // INT UNSIGNED field used with the // JOB_RESOURCE_MANAGER_PROPERTY_DB_FIELD bool besteffort; // ENUM('YES','NO') accept or not besteffort jobs bool deploy; // ENUM('YES','NO') specify if the resource is deployable unsigned int expiry_date; // INT UNSIGNED field used for the desktop // computing feature bool desktop_computing; // ENUM('YES','NO') tell if it is a desktop // computing resource (with an agent) unsigned int last_job_date; // INT UNSIGNED store the date when the // resource was used for the last time unsigned int available_upto; //INT UNSIGNED used with compute mode //features to know if an Absent //resource can be switch on }; struct gantt_sched_jobs { unsigned int job_id; unsigned int start_time; unsigned int moldable_walltime; vector resource_id_vec; string queue_name; string state; string job_user; string job_name; unsigned int moldable_id; bool suspended; }; /** Extraction de la table jobs (select * dans perl, limite ici) usage de - get_fairsharing_jobs_to_schedule limite a (job_id, job_user, job_name, properties) + appel a karma limite a (project, job_user) */ struct jobs_iolib_restrict { unsigned int job_id; // INT UNSIGNED job identifier string job_name; // VARCHAR(100) name given by the user string job_user; // VARCHAR(255) user name string properties; // TEXT properties that assigned nodes must match string project; // VARCHAR(255) arbitrary name given by the user or an admission rule }; /** Extraction de la table job dans get_job limite a - state ENUM('Waiting','Hold', 'toLaunch', 'toError', 'toAckReservation', 'Launching', 'Running' 'Suspended', 'Resuming', , 'Finishing', 'Terminated', 'Error') job state - job_type ENUM('INTERACTIVE', 'PASSIVE') DEFAULT 'PASSIVE' specify if the user wants to launch a program or get an interactive shell - exit_code INT DEFAULT 0 exit code for passive jobs */ struct jobs_get_job_iolib_restrict { string state; string job_type; int exit_code; }; /** # Return a data structure with the resource description of the given job # arg : database ref, job id # return a data structure (an array of moldable jobs): # example for the first moldable job of the list: # $result = [ # [ # { # property => SQL property # resources => [ # { # resource => resource name # value => number of this wanted resource # } # ] # } # ], # walltime, # moldable_job_id # ] */ struct resources_per_job { string resource; string value; }; struct property_resources_per_job { string property; vector resources; }; struct resources_data_moldable { vector prop_res; unsigned int walltime; unsigned int moldable_job_id; }; /** # Get start_time for a given job # args : base, job id */ struct gantt_job_start_time { unsigned int start_time; unsigned int moldable_job_id; }; /** listes des fonctions */ /** # connect_db # Connects to database and returns the base identifier # return value : base */ extern int connect_db(string dbhost, int dbport, string dbname, string dblogin, string dbpasswd, int debug_level=0); /** # connect # Connects to database and returns the base identifier # parameters : / # return value : base # side effects : opens a connection to the base specified in ConfLib */ extern bool connect(); /** # connect_ro # Connects to database and returns the base identifier # parameters : / # return value : base # side effects : opens a connection to the base specified in ConfLib */ extern bool connect_ro(); /** # disconnect # Disconnect from database # parameters : base # return value : / # side effects : closes a previously opened connection to the specified base */ extern void disconnect(); /* # get_specific_resource_states # returns a hashtable with each given resources and their states # parameters : base, resource type */ extern map< string, string > get_specific_resource_states(string type); /* # list_resources # gets the list of all resources # parameters : base # return value : list of resources # side effects : / */ extern vector list_resources(); /* # GANTT MANAGEMENT #get previous scheduler decisions #args : base #return a hashtable : job_id --> [start_time,walltime,queue_name,\@resources,state] # TODO commentaire PERL faux: bien plus d'information et pas de resssource ! */ extern pair< vector, map > get_gantt_scheduled_jobs(); /** # get_current_job_types # return a hash table with all types for the given job ID */ extern map get_current_job_types(unsigned int jobId); /* # get_job_current_resources # returns the list of resources associated to the job passed in parameter # parameters : base, jobid # return value : list of resources # side effects : / */ extern vector get_job_current_resources(unsigned int jobid, vector not_type_list); /** # get the amount of time in the suspended state of a job # args : base, job id, time in seconds */ extern unsigned int get_job_suspended_sum_duration(unsigned int job_id, unsigned int current_time); /** # get_resources_in_state # returns the list of resources in the state specified # parameters : base, state # return value : list of resource ref c'est une quasi-copie de list_resources, j'ai mutualiser le code */ extern vector get_resources_in_state(string state); /** # get_fairsharing_jobs_to_schedule # args : base ref, queue name */ extern vector get_fairsharing_jobs_to_schedule(string queue, unsigned int limit); extern map get_sum_accounting_window(string queue, unsigned int start_window, unsigned int stop_window); extern map, unsigned int> get_sum_accounting_for_param(string queue, string param_name, unsigned int start_window, unsigned int stop_window); /** # get_current_job_dependencies # return an array table with all dependencies for the given job ID */ extern vector get_current_job_dependencies(unsigned int jobId); /** # get_job # returns a ref to some hash containing data for the job of id passed in # parameter # parameters : base, jobid # return value : ref # side effects : / job extraction is restricted to - state - job_type - exit_code */ extern struct jobs_get_job_iolib_restrict get_job_restrict(unsigned int idJob); /** # Return a data structure with the resource description of the given job # arg : database ref, job id # return a data structure (an array of moldable jobs): # example for the first moldable job of the list: # $result = [ # [ # { # property => SQL property # resources => [ # { # resource => resource name # value => number of this wanted resource # } # ] # } # ], # walltime, # moldable_job_id # ] */ extern vector get_resources_data_structure_current_job(unsigned int job_id); /** # get_resources_that_can_be_waked_up # returns a list of resources # parameters : base, date max # return value : list of resource ref # get_resources_that_will_be_out # returns a list of resources # parameters : base, job max date # return value : list of resource ref restricted version to resource_id (the only used data in the scheduler) */ extern vector get_resources_that_can_be_waked_up_or_will_be_out(unsigned int max_date, bool waked_up); /** # Get start_time for a given job # args : base, job id WARNING: no undef are returned in this version ! */ extern struct gantt_job_start_time get_gantt_job_start_time(unsigned int job); /** # get_current_moldable_job_restrict_moldable_wall_time # returns a ref to some hash containing data for the moldable job of id passed in # parameter # parameters : base, moldable job id # return value : ref # side effects : / restricted to moldable_wall_time */ extern unsigned int get_current_moldable_job_restrict_moldable_walltime(unsigned int moldableJobId); /** # set_job_message # sets the message field of the job of id passed in parameter # parameters : base, jobid, message # return value : / # side effects : changes the field message of the job in the table Jobs */ extern int set_job_message(unsigned int idJob, string message); /** # get_possible_wanted_resources # return a tree ref : a data structure with corresponding resources with what is asked */ extern OAR::Schedulers::ResourceTree::TreeNode * get_possible_wanted_resources( vector possible_resources_vector, vector impossible_resources_vector, vector resources_to_ignore_array, string properties, vector wanted_resources_ref, /* TODO: verify type */ string order_part); /* #add scheduler decisions #args : base,moldable_job_id,start_time,\@resources #return nothing */ extern void add_gantt_scheduled_jobs(unsigned int id_moldable_job, unsigned int start_time, vector resource_list); } #endif oar-2.5.7/sources/extra/cpp-scheduler/Oar_sched_gantt_with_timesharing_and_fairsharing.cc0000644015014700017500000006257312677211234031526 0ustar neyronneyron/* #!/usr/bin/perl # $Id$ #-d:DProf use strict; use DBI(); use OAR::IO; use Data::Dumper; use OAR::Modules::Judas qw(oar_debug oar_warn oar_error set_current_log_category); use OAR::Conf qw(init_conf dump_conf get_conf is_conf); use Gantt_hole_storage; use Storable qw(dclone); use Time::HiRes qw(gettimeofday); # Log category set_current_log_category('scheduler'); */ #include "Oar_conflib.H" #include "Oar_iolib.H" #include "Oar_resource_tree.H" #include using namespace std; /* ############################################################################### # Fairsharing parameters # ########################## */ /// # Avoid problems if there are too many waiting jobs static const unsigned int Karma_max_number_of_jobs_treated_per_user = 30; ///# number of seconds to consider for the fairsharing static const unsigned int Karma_window_size = 3600 * 30 * 24; ///# specify the target percentages for project names (0 if not specified) struct karma_proj_target_t { unsigned int first; unsigned int default; }; const struct karma_proj_target_t Karma_project_targets = { 75, 25 }; ///# specify the target percentages for users (0 if not specified) map Karma_user_targets = map(pair("oar", 100)); ///# weight given to each criteria static const unsigned int Karma_coeff_project_consumption = 0; static const unsigend int Karma_coeff_user_consumption = 2; static const unsigned int Karma_coeff_user_asked_consumption = 1; //############################################################################### static time_t initial_time; static unsigned int timeout = 10; static unsigned int Minimum_timeout_per_job = 2; //# Constant duration time of a besteffort job static const unsigned int besteffort_duration = 5*60; // # $security_time_overhead is the security time (second) used to be sure there // # are no problem with overlaping jobs static unsigned int security_time_overhead = 1; static unsigned int minimum_hole_time = 0; //# You can add an order preference on resources assigned by the //# system(SQL ORDER syntax) static string Order_part; static vector Sched_available_suspended_resource_type; static string Resources_to_always_add_type; static vector Resources_to_always_add; static unsigned int current_time; static string queue; // what are timesharing gantts ? map, Gant_hole_storage::Gantt *> timesharing_gantts; // # Create the Gantt Diagrams // #Init the gantt chart with all resources Gant_hole_storage::Gantt *pgantt = 0; // variables used in real scheduling vector alive_resources_vector; vector Dead_resources; vector jobs; // variables used in karma sorting map Karma_sum_time; map, unsigned int> Karma_projects; map, unsigned int> Karma_users; void init_conf(int argc, char **argv) { initial_time = time(); init_conf(getenv("OARCONFFILE")); timeout = CONFDEFAULT_INT("SCHEDULER_TIMEOUT", "10"); // # $security_time_overhead is the security time (second) used to be sure there // # are no problem with overlaping jobs security_time_overhead = CONFDEFAULT_INT("SCHEDULER_JOB_SECURITY_TIME", "1"); minimum_hole_time = CONFDEFAULT_INT("SCHEDULER_GANTT_HOLE_MINIMUM_TIME", "0"); Order_part = get_conf("SCHEDULER_RESOURCE_ORDER"); string sched_available_suspended_resource_type_tmp = get_conf("SCHEDULER_AVAILABLE_SUSPENDED_RESOURCE_TYPE"); if (sched_available_suspended_resource_type_tmp == "") Sched_available_suspended_resource_type.push_back("default"); else { int cur_pos = 0; int end_pos; while(cur_pos < npos ) { end_pos = sched_available_suspended_resource_type_tmp.find_first_of(" ", cur_pos); if (endpos != npos) { Sched_available_suspended_resource_type.push_back(sched_available_suspended_resource_type_tmp.substr(cur_pos, end_pos-cur_pos)); cur_pos = end_pos + 1; } else { Sched_available_suspended_resource_type.push_back(sched_available_suspended_resource_type_tmp.substr(cur_pos, npos)); cur_pos = npos; } } } // # Look at resources that we must add for each job Resources_to_always_add_type = get_conf("SCHEDULER_RESOURCES_ALWAYS_ASSIGNED_TYPE"); Resources_to_always_add; if (argc < 3) { cerr << "[oar_sched_gantt_with_timesharing_and_fairsharing] no queue specified on command line" << endl; exit(1); } else { queue = argv[1]; current_time = atoi( argv[2] ); } } void init_sched() { //# Init // my $base = OAR::IO::connect(); // my $base_ro = OAR::IO::connect_ro(); // why use two bd access ? performance ? // I translate with only one access OAR::IO::connect(); //oar_debug("[oar_sched_gantt_with_timesharing_and_fairsharing] Begining of Gantt scheduler on queue $queue at time $current_time\n"); // # First check states of resources that we must add for each job if ( Resources_to_always_add_type != "") { multimap tmp_result_state_resources = OAR::IO::get_specific_resource_states( Resources_to_always_add_type); if ( tmp_result_state_resources.count("Suspected") > 0 ) { cerr << "[oar_sched_gantt_with_timesharing] There are resources that are specified in oar.conf (SCHEDULER_RESOURCES_ALWAYS_ASSIGNED_TYPE) which are Suspected. So I cannot schedule any job now." << endl; exit(1); } else { if (tmp_result_state_resources.count("Alive") > 0) { // copy alive resource_id multimap::iterator it = tmp_result_state_resources.lower_bound("Alive"); multimap::iterator itend = tmp_result_state_resources.upper_bound("Alive"); vector res_vec; while(it != it.end) { res_vec.insert( it->second ); it++; } Resources_to_always_add = res_vec; // oar_debug("[oar_sched_gantt_with_timesharing] Assign these resources for each jobs: @Resources_to_always_add\n"); } } } } void init_gantt() { // # Create the Gantt Diagrams // #Init the gantt chart with all resources unsigned int max_resources=0 for(vector::it = res.begin(); it != res.end(); it++) { max_resources = max( max_resources, it->resource_id); } vector vec(max_resources, 0); vector res = OAR::IO::list_resources(); for(vector::it = res.begin(); it != res.end(); it++) { vec[it->resource_id] = 1; } pgantt = Gantt_hole_storage::(max_resources, minimum_hole_time); Gantt_hole_storage::add_new_resources(pgantt, vec); } static boost::regex re_plit_coma(","); static boost::regex re_user_name("^\\s*([\\w\\*]+)\\s*$"); pair parse_timesharing(string str, string job_user, string job_name ) { string user = "*"; string name = "*"; /* use boost regex instead of QtSQL (better c++ integration (string)) */ boost::sregex_token_iterator i(s.begin(), s.end(), re_split_coma, -1); boost::sregex_token_iterator j; while(i != j) { string &s =*i; cmatch user_or_name; if ( boost::regex_match(s, user_or_name, re_user_name) ) { if ( user_or_name[1] == "user" ) user = job_user; else if ( user_or_name[1] == "name" && job_name != "" ) name = job_name; } i++; } return pair(user, name); } void init_gantt_scheduled_job() { //# Take care of currently scheduled jobs (gantt in the database) // TODO: la partie order ne sert a rien ? pair< vector, map > order_and_already_scheduled = OAR::IO::get_gantt_scheduled_jobs(); for( order_and_already_scheduled.second.iterator it = order_and_already_scheduled.second.begin(); it != order_and_already_scheduled.second.end(); it++) { i = it->first; map types = OAR::IO::get_current_job_types(i); // # Do not take care of besteffort jobs if ( types.find("besteffort") == types.end() or queue == "besteffort" ) { string user; string name; if ( types.find("timesharing") != types.end() ) { pair user_name = parse_timesharing( types["timesharing"], it->second.job_user, it->second.job_name); string user = user_name.first; string name = user_name.second; if ( timesharing_gantts.find( pair( user, name) ) == timesharing_gantts.end() ) { timesharing_gantts[pair( user, name)] = dclone(pgantt); // oar_debug("[oar_sched_gantt_with_timesharing_and_fairsharing] Create new gantt for ($user, $name)\n"); } } // foreach my $i (keys(%already_scheduled_jobs)){ // my $types = OAR::IO::get_current_job_types($base,$i); // # Do not take care of besteffort jobs // if ((! defined($types->{besteffort})) or ($queue eq "besteffort")){ // my $user; // my $name; // if (defined($types->{timesharing})){ // ($user, $name) = parse_timesharing($types->{timesharing}, $already_scheduled_jobs{$i}->[5], $already_scheduled_jobs{$i}->[6]); // if (!defined($timesharing_gantts->{$user}->{$name})){ // $timesharing_gantts->{$user}->{$name} = dclone($gantt); // oar_debug("[oar_sched_gantt_with_timesharing_and_fairsharing] Create new gantt for ($user, $name)\n"); // } // } vector resource_list = it->second.resource_id_vec; job_duration = it->second.moldable_walltime; // TODO: est-ce bien moldable walltime ? if ( it->second.state == "Suspended" ) { //# Remove resources of the type specified in SCHEDULER_AVAILABLE_SUSPENDED_RESOURCE_TYPE resource_list = OAR::IO::get_job_current_resources(it->second.moldable_id, Sched_available_suspended_resource_type); if (resource_list.size() == 0) continue; } if ( it->second.state.suspended ) { //# This job was suspended so we must recalculate the walltime job_duration += OAR::IO::get_job_suspended_sum_duration(i, current_time); // TODO: i == jobid ? assert(i == it->second.job_id); } // my @resource_list = @{$already_scheduled_jobs{$i}->[3]}; // my $job_duration = $already_scheduled_jobs{$i}->[1]; // if ($already_scheduled_jobs{$i}->[4] eq "Suspended"){ // # Remove resources of the type specified in SCHEDULER_AVAILABLE_SUSPENDED_RESOURCE_TYPE // @resource_list = OAR::IO::get_job_current_resources($base, $already_scheduled_jobs{$i}->[7],\@Sched_available_suspended_resource_type); // next if ($#resource_list < 0); // } // if ($already_scheduled_jobs{$i}->[8] eq "YES"){ // # This job was suspended so we must recalculate the walltime // $job_duration += OAR::IO::get_job_suspended_sum_duration($base,$i,$current_time); // } unsigned int max_resources = *max_element(resource_list.begin() resource_list.end()); vector vec(max_resources, 0); for(resource_list.iterator r = resource_list.begin(); r != resource_list.end(); r++) vec[*r]=1; // my $vec = ''; // foreach my $r (@resource_list){ // vec($vec,$r,1) = 1; // } //#Fill all other gantts for( timesharing_gantts.iterator itts = timesharing_gantts.begin(); itts != timesharing_gantts.end(); itts++) { u = itts->first.first; n = itts->first.second; if (user == "" || name == "" || u != user || n != name) { Gantt_hole_storage::set_occupation(itts->second, it->second.start_time, job_duration + security_time_overhead, vec ); } } Gantt_hole_storage::set_occupation( pgantt, it->second.start_time, job_duration + security_time_overhead, vec); } } } // #Fill all other gantts // foreach my $u (keys(%{$timesharing_gantts})){ // foreach my $n (keys(%{$timesharing_gantts->{$u}})){ // if ((!defined($user)) or (!defined($name)) or (($u ne $user) or ($n ne $name))){ // Gantt_hole_storage::set_occupation($timesharing_gantts->{$u}->{$n}, // $already_scheduled_jobs{$i}->[0], // $job_duration + $security_time_overhead, // $vec // ); // } // } // } // Gantt_hole_storage::set_occupation( $gantt, // $already_scheduled_jobs{$i}->[0], // $job_duration + $security_time_overhead, // $vec // ); // } // } //oar_debug("[oar_sched_gantt_with_timesharing_and_fairsharing] End gantt initialization\n"); /********** # End of the initialisation ************/ void real_scheduling_begin() { //# Begining of the real scheduling //# Get list of Alive resources vector resource_list = OAR::IO::get_resources_in_state($base,"Alive"); unsigned int max_resources=0; for(resource_list.iterator r = resource_list.begin(); r != resource_list.end(); r++) max_resources = max( max_resources, r->resource_id ); alive_resources_vector = vector(max_resources, 0); for(resource_list.iterator r = resource_list.begin(); r != resource_list.end(); r++) alive_resources_vector[r->resource_id]=1; resource_list = OAR::IO::get_resources_in_state($base,"Dead"); for(resource_list.iterator r = resource_list.begin(); r != resource_list.end(); r++) Dead_resources.push_back(r->resource_id); jobs = OAR::IO::get_fairsharing_jobs_to_schedule(queue, Karma_max_number_of_jobs_treated_per_user); } /* ############################################################################### # Sort jobs depending on their previous usage # Karma sort algorithm */ void karma_sort() { Karma_sum_time = OAR::IO::get_sum_accounting_window(queue, current_time - Karma_window_size, current_time); if (Karma_sum_time.find("ASKED") == Karma_sum_time.end() ) Karma_sum_time["ASKED"] = 1; if (Karma_sum_time.find("ASKED") == Karma_sum_time.end() ) Karma_sum_time["ASKED"] = 1; Karma_projects = OAR::IO::get_sum_accounting_for_param(queue,"accounting_project", current_time - Karma_window_size, current_time); Karma_users = OAR::IO::get_sum_accounting_for_param(queue,"accounting_user", current_time - Karma_window_size, current_time); } int karma(OAR::IO::jobs_iolib_restrict j) { int note = 0; note = Karma_coeff_project_consumption * (( Karma_projects[pair(j.project,"USED")] / Karma_sum_time["USED"]) - ( Karma_project_targets[j.project] / 100)); note += Karma_coeff_user_consumption * (( Karma_users[pair(j.job_user, "USED")] / Karma_sum_time["USED"]) - (Karma_user_targets[j.project] / 100)); note += Karma_coeff_user_asked_consumption * ((Karma_users[pair(j.job_user,"ASKED")] / Karma_sum_time["ASKED"]) - (Karma_user_targets[j.project] / 100)); return(note); } struct less_jobs_iolib_restrict : public binary_function { bool operator()(OAR::IO::jobs_iolib_restrict a, OAR::IO::jobs_iolib_restrict b) { return karma(a) < karma(b); } } //############################################################################### void real_scheduler_main() { // sort jobs by karma sort(jobs.begin(), jobs.end(), less_jobs_iolib_restrict()); int job_index = 0; while ((job_index <= jobs.size() ) and ((time() - initial_time) < timeout)) { OAR::IO::jobs_iolib_restrict j = jobs[job_index]; job_index ++; oar_debug("[oar_sched_gantt_with_timesharing_and_fairsharing] [" + j.job_id + "] Start scheduling (Karma note = " + karma($j) + ")\n"); unsigned int scheduler_init_date = current_time; //# Search for dependencies int skip_job = 0; // skip jobs if it is not ready vector vjobdep = OAR::IO::get_current_job_dependencies(j.job_id); for(unisgend int d = vjobdep.begin(); d != vjobdep.end(); vjobdep++) { if (skip_job) break; jobs_get_job_iolib_restrict dep_job = OAR::IO::get_job_restrict(d); if (dep_job.state != "Terminated") { gantt_job_start_time date_tmp = OAR::IO::get_gantt_job_start_time(d); if (date_tmp.start_time != 0 || date_tmp.moldable_job_id != 0) { unsigned int mold_dep_moldable_walltime = OAR::IO::get_current_moldable_job(date_tmp.moldable_job_id); unsigned int sched_tmp = date_tmp.start_time + mold_dep_moldable_walltime; if ( scheduler_init_date < sched_tmp) { scheduler_init_date = sched_tmp; } } else { string message = "Cannot determine scheduling time due to dependency with the job "<< d; OAR::IO::set_job_message(j.job_id, message); oar_debug("[oar_sched_gantt_with_timesharing_and_fairsharing] ["+j.job_id+"] "+message+"\n"); skip_job = 1; break; } } else if ((dep_job.job_type == "PASSIVE") && (dep_job.exit_code != 0)) { string message = "Cannot determine scheduling time due to dependency with the job "+ d +<< "(exit code != 0)"; OAR::IO::set_job_message(j.job_id, message); oar_debug("[oar_sched_gantt_with_timesharing_and_fairsharing] ["+j.job_id+"] "+message+"\n"); skip_job = 1; break; } } if (skip_job == 1) continue; Gant_hole_storage::Gantt *gantt_to_use = pgantt; map types = OAR::IO::get_current_job_types(j.job_id); if ( types.find("timesharing") != types.end() ) { pair user_name = parse_timesharing(types["timesharing"], j.job_user, j.job_name); if ( timesharing_gantts.find(user_name) == timesharing_gantts.end() ) { timesharing_gantts[user_name] = OAR::Schedulers::ResourceTree::dclone(gantt); oar_debug("[oar_sched_gantt_with_timesharing_and_fairsharing] Create new gantt in phase II for ("+user_name.first+" "+user_name.second+")\n"); } gantt_to_use = timesharing_gantts[user_name]; oar_debug("[oar_sched_gantt_with_timesharing_and_fairsharing] Use gantt for ("+user_name.first+" "+user_name.second+"\n"); } //#oar_debug("[oar_sched_gantt_with_timesharing] Use gantt for $j->{job_id}:\n".Gantt_hole_storage::pretty_print($gantt_to_use)."\n"); string job_properties = "'1'"; if (j.properties != "") { job_properties = j.properties; } //# Choose the moldable job to schedule // TODO: type ??? my @moldable_results; vector job_descriptions = OAR::IO::get_resources_data_structure_current_job(j.job_id); for(vector::iterator moldable = job_descriptions[0].prop_res.begin(); moldable != job_descriptions[0].prop_res.end(); moldable++) { //#my $moldable = $job_descriptions->[0]; unsigned int duration; if (types.find("besteffort") != types.end() ) { duration = besteffort_duration; } else { duration = moldable->walltime + security_time_overhead; } //# CM part vector alive_resources_vector_store = alive_resources_vector; if ( conflib::is_conf("SCHEDULER_NODE_MANAGER_WAKE_UP_CMD") ) { /**** TODO TO DO ****/ foreach my $r (OAR::IO::get_resources_that_can_be_waked_up($base, OAR::IO::get_date($base) + $duration)){ vec($alive_resources_vector, $r->{resource_id}, 1) = 1; } foreach my $r (OAR::IO::get_resources_that_will_be_out($base, OAR::IO::get_date($base) + $duration)){ vec($alive_resources_vector, $r->{resource_id}, 1) = 0; } my $str_tmp = "state_num ASC, available_upto DESC"; if (defined($Order_part)){ $Order_part = $str_tmp.",".$Order_part; }else{ $Order_part = $str_tmp; } } # CM part my $resource_id_used_list_vector = ''; my @tree_list; foreach my $m (@{$moldable->[0]}){ my $tmp_properties = "\'1\'"; if ((defined($m->{property})) and ($m->{property} ne "")){ $tmp_properties = $m->{property}; } my $tmp_tree = OAR::IO::get_possible_wanted_resources($base_ro,$alive_resources_vector,$resource_id_used_list_vector,\@Dead_resources,"$job_properties AND $tmp_properties", $m->{resources}, $Order_part); push(@tree_list, $tmp_tree); my @leafs = OAR::Schedulers::ResourceTree::get_tree_leafs($tmp_tree); foreach my $l (@leafs){ vec($resource_id_used_list_vector, OAR::Schedulers::ResourceTree::get_current_resource_value($l), 1) = 1; } } my $gantt_timeout = ($timeout - (time() - $initial_time)) / 4; $gantt_timeout = $Minimum_timeout_per_job if ($gantt_timeout < ($timeout / 3)); oar_debug("[oar_sched_gantt_with_timesharing_and_fairsharing] [$j->{job_id}] find_first_hole with a timeout of $gantt_timeout\n"); my @hole = Gantt_hole_storage::find_first_hole($gantt_to_use, $scheduler_init_date, $duration, \@tree_list,$gantt_timeout); # print("[GANTT] 10 ".gettimeofday."\n"); my @res_trees; my @resources; foreach my $t (@{$hole[1]}){ # print("[GANTT] 11 ".gettimeofday."\n"); my $minimal_tree = OAR::Schedulers::ResourceTree::delete_unnecessary_subtrees($t); # print("[GANTT] 12 ".gettimeofday."\n"); push(@res_trees, $minimal_tree); foreach my $r (OAR::Schedulers::ResourceTree::get_tree_leafs($minimal_tree)){ push(@resources, OAR::Schedulers::ResourceTree::get_current_resource_value($r)); } # print("[GANTT] 13 ".gettimeofday."\n"); } push(@moldable_results, { resources => \@resources, start_date => $hole[0], duration => $duration, moldable_id => $moldable->[2] }); # CM part $alive_resources_vector = $alive_resources_vector_store ; # CM part } # Choose moldable job which will finish the first my $index_to_choose = -1; my $best_stop_time; # print("[GANTT] 14 ".gettimeofday."\n"); for (my $i=0; $i <= $#moldable_results; $i++){ #my @tmp_array = @{$moldable_results[$i]->{resources}}; if ($#{@{$moldable_results[$i]->{resources}}} >= 0){ my $tmp_stop_date = $moldable_results[$i]->{start_date} + $moldable_results[$i]->{duration}; if ((!defined($best_stop_time)) or ($best_stop_time > $tmp_stop_date)){ $best_stop_time = $tmp_stop_date; $index_to_choose = $i; } } } if ($index_to_choose >= 0){ # We can schedule the job # print("[GANTT] 15 ".gettimeofday."\n"); my $vec = ''; foreach my $r (@{$moldable_results[$index_to_choose]->{resources}}){ vec($vec, $r, 1) = 1; } Gantt_hole_storage::set_occupation( $gantt, $moldable_results[$index_to_choose]->{start_date}, $moldable_results[$index_to_choose]->{duration}, $vec ); #Fill all other gantts foreach my $u (keys(%{$timesharing_gantts})){ # print("[GANTT] 17 ".gettimeofday."\n"); foreach my $n (keys(%{$timesharing_gantts->{$u}})){ if (($gantt_to_use != $timesharing_gantts->{$u}->{$n})){ Gantt_hole_storage::set_occupation( $timesharing_gantts->{$u}->{$n}, $moldable_results[$index_to_choose]->{start_date}, $moldable_results[$index_to_choose]->{duration}, $vec ); } } } #update database push(@{$moldable_results[$index_to_choose]->{resources}},@Resources_to_always_add); OAR::IO::add_gantt_scheduled_jobs($base,$moldable_results[$index_to_choose]->{moldable_id}, $moldable_results[$index_to_choose]->{start_date},$moldable_results[$index_to_choose]->{resources}); OAR::IO::set_job_message($base,$j->{job_id},"Karma = ".sprintf("%.3f",karma($j))); }else{ my $message = "Cannot find enough resources which fit for the job $j->{job_id}"; OAR::IO::set_job_message($base,$j->{job_id},$message); oar_debug("[oar_sched_gantt_with_timesharing_and_fairsharing] [$j->{job_id}] $message\n"); } # print("[GANTT] 18 ".gettimeofday."\n"); oar_debug("[oar_sched_gantt_with_timesharing_and_fairsharing] [$j->{job_id}] End scheduling\n"); } OAR::IO::disconnect($base); OAR::IO::disconnect($base_ro); if ($job_index <= $#jobs){ oar_debug("[oar_sched_gantt_with_timesharing_and_fairsharing_and_fairsharing] I am not able to schedule all waiting jobs in the specified time : $timeout s\n"); } oar_debug("[oar_sched_gantt_with_timesharing_and_fairsharing] End of scheduler for queue $queue\n"); oar-2.5.7/sources/extra/cpp-scheduler/UnitaryTests/0000755015014700017500000000000012677211234021750 5ustar neyronneyronoar-2.5.7/sources/extra/cpp-scheduler/UnitaryTests/TestResourceTree.cc0000644015014700017500000001501012677211234025523 0ustar neyronneyron#include #include "TestResourceTree.H" #include "../Oar_resource_tree.H" using namespace OAR::Schedulers::ResourceTree; CPPUNIT_TEST_SUITE_REGISTRATION( TestResourceTree ); void TestResourceTree::setUp() { } void TestResourceTree::tearDown() { } void TestResourceTree::testConstructor() { TreeNode *n, *n2; // essai du constructeur avec juste le needed_children_number n = new TreeNode(123); CPPUNIT_ASSERT_EQUAL( 123, n->needed_children_number); CPPUNIT_ASSERT_EQUAL( static_cast(0), n->father ); CPPUNIT_ASSERT_EQUAL( static_cast(0), n->children.size() ); CPPUNIT_ASSERT_EQUAL( std::string(), n->name ); CPPUNIT_ASSERT_EQUAL( std::string(), n->value ); CPPUNIT_ASSERT_EQUAL( 0, n->level ); CPPUNIT_ASSERT_EQUAL( 0, n->max_available_children ); CPPUNIT_ASSERT_EQUAL( static_cast(0), n->prev_brother ); CPPUNIT_ASSERT_EQUAL( static_cast(0), n->next_brother ); CPPUNIT_ASSERT_EQUAL( static_cast(0), n->first_child ); CPPUNIT_ASSERT_EQUAL( 0, n->current_child_number ); // essai du constructeur avec l'ensemble des parametres n2 = n; n = new TreeNode(n2, static_cast(0), "toto", "tutu", 10, 11, 12, n2+1, n2+2, n2+3, 14 ); CPPUNIT_ASSERT_EQUAL( 11, n->needed_children_number); CPPUNIT_ASSERT_EQUAL( n2, n->father ); CPPUNIT_ASSERT_EQUAL( static_cast(0), n->children.size() ); CPPUNIT_ASSERT_EQUAL( std::string("toto"), n->name ); CPPUNIT_ASSERT_EQUAL( std::string("tutu"), n->value ); CPPUNIT_ASSERT_EQUAL( 10, n->level ); CPPUNIT_ASSERT_EQUAL( 12, n->max_available_children ); CPPUNIT_ASSERT_EQUAL( static_cast(n2+1), n->prev_brother ); CPPUNIT_ASSERT_EQUAL( static_cast(n2+2), n->next_brother ); CPPUNIT_ASSERT_EQUAL( static_cast(n2+3), n->first_child ); CPPUNIT_ASSERT_EQUAL( 14, n->current_child_number ); delete n; delete n2; } void TestResourceTree::testAccessor() { TreeNode *n; TreeNode *n2= (TreeNode *)123456; // essai du constructeur avec l'ensemble des parametres n = new TreeNode(static_cast((void*)5), static_cast(0), "toto", "tutu", 10, 11, 12, n2+1, n2+2, n2+3, 14 ); CPPUNIT_ASSERT_EQUAL( true, is_node_a_leaf(n) ); CPPUNIT_ASSERT_EQUAL( 21, set_needed_children_number(n, 21) ); CPPUNIT_ASSERT_EQUAL( 21, n->needed_children_number ); CPPUNIT_ASSERT_EQUAL( 21, get_needed_children_number(n) ); CPPUNIT_ASSERT_EQUAL( static_cast(0), n->children.size() ); CPPUNIT_ASSERT_EQUAL( std::string("toto"), get_current_resource_name(n) ); CPPUNIT_ASSERT_EQUAL( std::string("tutu"), get_current_resource_value(n) ); CPPUNIT_ASSERT_EQUAL( 10, n->level ); CPPUNIT_ASSERT_EQUAL( 12, n->max_available_children ); CPPUNIT_ASSERT_EQUAL( static_cast(n2+1), get_previous_brother(n) ); CPPUNIT_ASSERT_EQUAL( static_cast(n2+2), get_next_brother(n) ); CPPUNIT_ASSERT_EQUAL( static_cast(n2+3), get_initial_child(n) ); CPPUNIT_ASSERT_EQUAL( static_cast((void*)5), get_father(n) ); CPPUNIT_ASSERT_EQUAL( 14, get_current_children_number(n) ); CPPUNIT_ASSERT_EQUAL( 10, get_current_level(n) ); CPPUNIT_ASSERT_EQUAL( 12, get_max_available_children(n) ); delete n; } /** This fonction builds a tree with 5 nodes : a root (cluster, alpha) , with two childs (network, giga) (network, myri). One of the child (network, giga) with two other childs (node, p1) et (node, p2). This tree is cloned, then the subtree without child is suppressed. */ static void test1fils(TreeNode *a) { CPPUNIT_ASSERT_EQUAL( static_cast(1), a->children.size() ); CPPUNIT_ASSERT_EQUAL( a->children.find("giga")->second, get_initial_child( a ) ); CPPUNIT_ASSERT_EQUAL( a, get_father( get_initial_child( a ) ) ); CPPUNIT_ASSERT_EQUAL( static_cast(0), get_next_brother( get_initial_child ( a ) ) ); CPPUNIT_ASSERT_EQUAL( static_cast(0), get_next_brother( a ) ); CPPUNIT_ASSERT_EQUAL( static_cast(0), get_previous_brother( get_initial_child ( a ) ) ); CPPUNIT_ASSERT_EQUAL( static_cast(0), get_previous_brother( a ) ); } static void test2fils( TreeNode *a ) { CPPUNIT_ASSERT_EQUAL( static_cast(2), a->children.size() ); // le nouveau fils a ete ajoute en premier (insertion en tete) //std::cerr << " myri :" << a->children.find("myri")->second // << " giga :" << a->children.find("giga")->second << std::endl; CPPUNIT_ASSERT_EQUAL( a->children.find("myri")->second, get_initial_child( a ) ); CPPUNIT_ASSERT_EQUAL( a, get_father( get_initial_child( a ) ) ); CPPUNIT_ASSERT_EQUAL( static_cast( a->children.find("giga")->second ), get_next_brother( get_initial_child ( a ) ) ); CPPUNIT_ASSERT_EQUAL( static_cast(0), get_next_brother( get_next_brother( a ) ) ); CPPUNIT_ASSERT_EQUAL( static_cast(0), get_previous_brother( get_initial_child ( a ) ) ); CPPUNIT_ASSERT_EQUAL( static_cast(get_initial_child( a ) ), get_previous_brother( get_next_brother( get_initial_child( a ) ) ) ); CPPUNIT_ASSERT_EQUAL( static_cast(0), get_previous_brother( a ) ); } void TestResourceTree::testTreeManipulation() { TreeNode *nroot; TreeNode *cnroot; // essai du constructeur avec l'ensemble des parametres nroot = new TreeNode(static_cast(0), static_cast(0), "cluster", "alpha", 1, 0, 0, 0, 0, 0, 0); add_child(nroot, "network", "giga"); test1fils(nroot); add_child(nroot, "network", "giga"); // this should not be inserted CPPUNIT_ASSERT_EQUAL( static_cast(1), nroot->children.size() ); // ajout du deuxième fils add_child(nroot, "network", "myri"); test2fils( nroot ); // ajout de deux fils au fils giga add_child(nroot->children.find( "giga" )->second , "node", "p1"); add_child(nroot->children.find( "giga" )->second , "node", "p2"); CPPUNIT_ASSERT_EQUAL( static_cast(2), nroot->children.find("giga")->second->children.size() ); CPPUNIT_ASSERT_EQUAL( nroot, get_father( get_father( nroot->first_child->next_brother->first_child->next_brother ) ) ); // On clone cnroot = clone(nroot); // il faudrait refaire les mêmes tests CPPUNIT_ASSERT( cnroot != nroot ); test2fils(cnroot); // on efface le clone delete_subtree(cnroot); test2fils(nroot); // on efface l'original delete_subtree( nroot ); } // tester: clone, is_node_a_leaf, add_child, // delete_subtree,delete_tree_nodes_with_not_enough_resources, // get_tree_leafs, delete_unnecessary_subtree oar-2.5.7/sources/extra/cpp-scheduler/UnitaryTests/README0000644015014700017500000000006612677211234022632 0ustar neyronneyronUtilization of libcpppunit to do some test on the codeoar-2.5.7/sources/extra/cpp-scheduler/UnitaryTests/AllTest.cc0000644015014700017500000000074712677211234023637 0ustar neyronneyron#include #include #include int main(int argc, char **argv) { CppUnit::Test *suite = CppUnit::TestFactoryRegistry::getRegistry().makeTest(); CppUnit::TextUi::TestRunner runner; runner.addTest( suite ); runner.setOutputter( new CppUnit::CompilerOutputter( &runner.result(), std::cerr ) ); bool wasSuccess = runner.run(); return wasSuccess ? 0 : 1; } oar-2.5.7/sources/extra/cpp-scheduler/UnitaryTests/TestResourceTree.H0000644015014700017500000000072512677211234025334 0ustar neyronneyron#ifndef TESTRESOURCETREE_H #define TESTRESOURCETREE_H #include class TestResourceTree : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE( TestResourceTree ); CPPUNIT_TEST( testConstructor ); CPPUNIT_TEST( testAccessor ); CPPUNIT_TEST( testTreeManipulation ); CPPUNIT_TEST_SUITE_END(); public: void setUp(); void tearDown(); void testConstructor(); void testAccessor(); void testTreeManipulation(); }; #endif oar-2.5.7/sources/extra/cpp-scheduler/UnitaryTests/Makefile0000644015014700017500000000033312677211234023407 0ustar neyronneyronCC= g++ CFLAGS= -g -Wall CXXFLAGS= -g -Wall LDLIBS= -ldl -lcppunit all: AllTest AllTest: AllTest.o TestResourceTree.o ../Oar_resource_tree.H ../Oar_resource_tree.o ../Gantt_hole_storage.o clean: rm *.o ../*.o oar-2.5.7/sources/extra/cpp-scheduler/Oar_conflib.cc0000644015014700017500000000773712677211234022034 0ustar neyronneyron/** ############################################################################### ## *** ConfLib: *** ## ## Description: ## Home brewed module managing configuration file for OAR ## ## - Usage: init_conf(); ## Read the first file matching in ## . current directory ## . $OARDIR directory ## . /etc directory ## ## - Configuration file format: ## A line of the configuration file looks like that: ## > truc = 45 machin chose bidule 23 # any comment ## "truc" is a configuration entry being assigned "45 machin chose bidule 23" ## Anything placed after a dash (#) is ignored i ## (for instance lines begining with a dash are comment lines then ignored) ## Any line not matching the regexp defined below are also ignored ## ## Module must be initialized using init_conf(), then ## any entry is retrieved using get_conf(). ## is_conf() may be used to check if any entry actually exists. ## ## - Example: ## > use ConfLib qw(init_conf get_conf is_conf); ## > init_conf("oar.conf"); ## > print "toto = ".get_conf("toto")."\n" if is_conf("toto"); ## ############################################################################### # $Id$ */ #include #include #include #include #include #include #include #include "Oar_conflib.H" using namespace std; /// ## configuration file regexp (one line). /// inclusion of the quote matching in the main string static QRegExp regexp(QString("^\\s*([^#=\\s]+)\\s*=\\s*([\\\"\\']?)([^#]*)\\2")); /// unloaded conf static bool loaded_conf = 0; /// parameters container static map params; /// full conf file name static string filename; namespace conflib { /** ## Initialization of the configuration # param: configuration file pathname # Result: 0 if conf was already loaded # 1 if conf was actually loaded # 2 if conf was not found */ unsigned int init_conf (string file) { // If file already loaded, exit immediately if (loaded_conf) return 0; // try to open the various files ifstream ifile; filename = file; ifile.open(filename.c_str()); if ( ifile.fail() ) { string oarpath = getenv("OARDIR"); filename = oarpath+file; ifile.open( filename.c_str() ); if ( ifile.fail()) { filename = "/etc/"+file; ifile.open( filename.c_str() ); if ( ifile.fail()) { cerr << "Unable to open configuration file: " << filename << endl; return 2; } } } while(! ifile.eof() ) { string line; getline(ifile, line); int pos = regexp.indexIn(line.c_str()); if (pos > -1) { string key = regexp.cap(1).toStdString(); string val = regexp.cap(3).toStdString(); params[key] = val; } } ifile.close(); loaded_conf = 1; return 1; } /** ## retrieve a parameter if exists, set it to the default value otherwise ## params: arg1 param name, arg2 default value */ string get_conf_with_default_param ( string key, string defval) { map::iterator keyval; keyval = params.find(key); if (keyval == params.end() ) return defval; else return params[key]; } /** ## retrieve a parameter */ string get_conf ( string key ) { map::iterator keyval; keyval = params.find(key); if (keyval == params.end() ) return ""; else return params[key]; } /** ## check if a parameter is defined */ bool is_conf ( string key ) { map::iterator keyval; keyval = params.find(key); return (keyval != params.end() ); } /** ## debug: dump parameters */ int dump_conf () { cout << "Config file is: " << filename << endl; for(map::iterator keyval= params.begin(); keyval != params.end(); keyval++) cout << " " << keyval->first << " = " << keyval->second << endl; return 1; } /* ## reset the module state */ int reset_conf () { filename = string(); params = map(); return 1; } }; oar-2.5.7/sources/extra/cpp-scheduler/Makefile_1oct080000644015014700017500000000007412677211234022031 0ustar neyronneyron all: cd UnitaryTests; make clean; make; valgrind ./AllTestoar-2.5.7/sources/extra/cpp-scheduler/Gantt_hole_storage.cc0000644015014700017500000006730012677211234023417 0ustar neyronneyron /** \brief gant manipulation for the scheduler \author Gregory Mounié \version 0.1 \date 07 05 2008 version 0.1: Re-writing of the original perl code of OAR 2.1 to get a C++ version of the same algorithm. The use of the STL is done to be the closest possible of the perl version */ #include #include "Gantt_hole_storage.H" #include "Oar_resource_tree.H" #include // # $Id$ // package Gantt_hole_storage; // require Exporter; // use OAR::Schedulers::ResourceTree; // use Data::Dumper; // use warnings; // use strict; // # Note : All dates are in seconds // # Resources are integer so we store them in bit vectors // # Warning : this gantt cannot manage overlaping time slots // # 2^32 is infinity in 32 bits stored time //my $Infinity = 4294967296; // # Prototypes // # gantt chart management // sub new($$); // sub new_with_1_hole($$$$$); // sub add_new_resources($$); // sub set_occupation($$$$); // sub get_free_resources($$$); // sub find_first_hole($$$$$); // sub pretty_print($); // sub get_infinity_value(); namespace Gantt_hole_storage { unsigned int get_infinity_value() { // le meme que dans le code perl // BUG perl: 1 de trop assert(sizeof(unsigned int) == 4); return 4294967295UL; } // sub get_infinity_value(){ // return($Infinity); // } /** affichage des vecteurs de bool inserer dans la structure du gantt */ int pretty_print(Gantt *gantt) { } /* sub pretty_print($){ my $gantt = shift; my @bits = split(//, unpack("b*", $gantt->[0]->[2])); print("@bits\n"); foreach my $g (@{$gantt}){ print("BEGIN : $g->[0]\n"); foreach my $h (@{$g->[1]}){ @bits = split(//, unpack("b*", $h->[1])); print(" $h->[0] : @bits\n"); } print("\n"); } } */ /** Creates an empty Gantt arg : number of the max resource id */ /** fonction d'initialisation */ void Gantt::initGantt(int max_resource_number, int minimum_hole_duration) { std::vector empty_vec(max_resource_number); Hole h(0); h.holestop.push_back(StopTime(get_infinity_value(), empty_vec)); h.first_hole = true; h.all_inserted_resources = empty_vec; // zero_vec est une variable du Gant et pas du trou mantenant zero_vec = empty_vec; h.minimum_hole_duration = minimum_hole_duration; h.max_time_find_first_hole = std::pair(get_infinity_value(), get_infinity_value()); holes.push_back(h); } Gantt::Gantt(int max_resource_number, int minimum_hole_duration = 0) { initGantt(max_resource_number, minimum_hole_duration); } // # Creates an empty Gantt // # arg : number of the max resource id // sub new($$){ // my $max_resource_number = shift; // my $minimum_hole_duration = shift; // $minimum_hole_duration = 0 if (!defined($minimum_hole_duration)); // my $empty_vec = ''; // vec($empty_vec, $max_resource_number, 1) = 0; // my $result =[ // [ // 0, # start time of this hole // [ # ref of a structure which contains hole stop times and corresponding resources (ordered by end time) // [$Infinity, $empty_vec] // ], // $empty_vec, # Store all inserted resources (Only for the first Gantt hole) // $empty_vec, # Store empty vec with enough 0 (Only for the first hole) // $minimum_hole_duration, # minimum time for a hole // [$Infinity,$Infinity] # times that find_first_hole must not go after // ] // ]; // return($result); // } /** * Creates a Gantt with 1 hole * args number of the max resource id */ Gantt::Gantt(int max_resource_number, int minimum_hole_duration, int date, int duration, std::vector resources_vec) : Gantt::Gantt(max_resource_number, minimum_hole_duration) { resources_vec |= zero_vec; holes[0].start_time = date; holes[0].holestop = std::vector().push_back( StopTime(date + duration, resources_vec)); } // # Creates a Gantt with 1 hole // # arg : number of the max resource id // sub new_with_1_hole($$$$$){ // my $max_resource_number = shift; // my $minimum_hole_duration = shift; // my $date = shift; // my $duration = shift; // my $resources_vec = shift; // my $gantt = Gantt_hole_storage::new($max_resource_number, $minimum_hole_duration); // # Feed vector with enough 0 // $resources_vec |= $gantt->[0]->[3]; // $gantt->[0]->[0] = $date; // $gantt->[0]->[1] = [[($date + $duration), $resources_vec]]; // return($gantt); // } /** * Adds and initializes new resources in the gantt * args : gantt ref, bit vector of resources */ int add_new_resources(Gantt *gantt, std::vector resources_vec) { // Feed vector with enough 0 resources_vec |= gantt->zero_vec; // Verify which resources are not already inserted std::vector resource_to_add_vec = resources_vec & ( ! gantt->holes[0].all_inserted_resources); if ( resource_to_add_vec != gantt->zero_vec ) { // We need to insert new resources on all hole int i = 0; for(i=0; i < gantt->holes.size(); i++) // Add resources if ( gantt->.holes[i].holestop[ gantt->holes[i].holestop.size()-1 ].stop_time == get_infinity_value() ) { gant->holes[i].holestop[ gant->holes[i].holestop.size()-1 ].r |= resources_to_add_vec; } else { gantt->holes[i].holestop.push_back( StopTime(get_infinity_value(), resources_vec) ); } // Keep already inserted resources in mind gantt->holes[0].all_inserted_resources |= resources_vec; } return 0; } // # Adds and initializes new resources in the gantt // # args : gantt ref, bit vector of resources // sub add_new_resources($$) { // my ($gantt, $resources_vec) = @_; // # Feed vector with enough 0 // $resources_vec |= $gantt->[0]->[3]; // # Verify which resources are not already inserted // my $resources_to_add_vec = $resources_vec & (~ $gantt->[0]->[2]); // if (unpack("%32b*",$resources_to_add_vec) > 0){ // # We need to insert new resources on all hole // my $g = 0; // while ($g <= $#{@{$gantt}}){ // # Add resources // if ($gantt->[$g]->[1]->[$#{@{$gantt->[$g]->[1]}}]->[0] == $Infinity){ // $gantt->[$g]->[1]->[$#{@{$gantt->[$g]->[1]}}]->[1] |= $resources_to_add_vec; // }else{ // push(@{$gantt->[$g]->[1]}, [$Infinity, $resources_vec]); // } // $g++; // } // # Keep already inserted resources in mind // $gantt->[0]->[2] |= $resources_vec; // } // } /** Inserts in the gantt new resource occupations args : gantt ref, start slot date, slot duration, resources bit vector */ void set_occupation(Gantt *gantt, int start_date, int duration, std::vector resources_vec) { // Feed vector with enough 0 resources_vec |= gantt->zero_vec; // If a resource was not initialized add_new_resources(gantt, resources_vec); // If it is not yet done Hole new_hole = new Hole(date+duration+1); // + vecteur vide de holestop int g; for(g= 0; g <= gantt->holes.size() && gantt->holes[g].start_time <= new_hole.start_time; g++) { int slot_deleted = 0; // Look at all holes that are before the end of the occupation if (gantt->holes[g].holestop.size() >= 1 && gantt->holes[g].holestop[ gantt.holes[g].holestop.size() -1 ].stop_time >= date) { // Look at holes with a biggest slot >= $date int h = 0; int slot_date_here = 0; for(h = 0; h < gantt->holes[g].holestop.size(); h++) { // Look at all slots if (gantt->holes[g].holestop[h].stop_time == date) slot_date_here = 1; if (gantt->holes[g].holestop[h].stop_time > date) { // This slot ends after $date //print($date - $gantt->[$g]->[0]." -- $gantt->[0]->[4]\n"); if ( (gantt->holes[g].start_time < date) && (slot_date_here == 0) && ( date - gantt.holes[g].start_time > gantt.minimum_hole_duration) ) { // We must create a smaller slot (hole start time < $date) gantt->holes[g].holestop.insert(h, StopTime(date, gantt->holes[g].holestop[h].r)); h++; // Go to the slot that we were on it before the splice slot_date_here = 1; } // Add new slots in the new hole if ( (new_hole.start_time < gantt->holes[g].holestop[h].stop_time) && ( gantt->holes[g].holestop[h].stop_time - new_hole.start_time > gantt->holes[0].minimum_hole_duration ) ) { // copy slot in the new hole if needed int slot = 0; while( (slot <= new_hole.holestop.size() - 1 ) && ( new_hole.holestop[slot].stop_time < gantt->holes[g].holestop[h].stop_time ) ) { // Find right index in the sorted slot array slot++; } if (slot <= new_hole.holestop.size() - 1) { if ( new_hole.holestop[slot].stop_time == gantt->holes[g].holestop[h].stop_time ) { // If the slot already exists, binary OR vector resources new_hole.holestop[slot].r |= gantt->holes[g].holestop[h].r; } else { // Insert the new slot from the gantt // TODO: optimiser insertion new_hole.holestop.insert($slot, StopTime( gantt->holes[h].holestop[h].stop_time, gant.holes[g].holestop[h].r) ); } } else if (new_hole.start_time < gantt->holes[g].holestop[h].stop_time) { // There is no slot so we create one new_hole.holestop.push_back( StopTime(gantt->holes[g].holestop[h].stop_time, gantt->holes[g].holestop[h].r ) ); } } // Remove new occupied resources from the current slot gant.holes[g].holestop[h].r &= ( ! resources_vec ); if ( gantt->holes[g].holestop[h].r == std::vector(gantt->holes[g].holestop[h].r.size(), 0) ) { // There is no free resource on this slot so we delete it gantt->holes[g].holestop.erase(h); h --; slot_deleted = 1; } } } } if ( (slot_deleted == 1) && ( gantt->holes.holestop.size() == 0 )) { // There is no free slot on the current hole so we delete it gantt->holes.erase[g]; g--; } } } // sub set_occupation($$$$){ // my ($gantt, $date, $duration, $resources_vec) = @_; // # Feed vector with enough 0 // $resources_vec |= $gantt->[0]->[3]; // # If a resource was not initialized // add_new_resources($gantt,$resources_vec); # If it is not yet done // my $new_hole = [ // $date + $duration + 1, // [] // ]; // my $g = 0; // while (($g <= $#{@{$gantt}}) and ($gantt->[$g]->[0] <= $new_hole->[0])){ // my $slot_deleted = 0; // # Look at all holes that are before the end of the occupation // if (($#{@{$gantt->[$g]->[1]}} >= 0) and ($gantt->[$g]->[1]->[$#{@{$gantt->[$g]->[1]}}]->[0] >= $date)){ // # Look at holes with a biggest slot >= $date // my $h = 0; // my $slot_date_here = 0; // while ($h <= $#{@{$gantt->[$g]->[1]}}){ // # Look at all slots // $slot_date_here = 1 if ($gantt->[$g]->[1]->[$h]->[0] == $date); // if ($gantt->[$g]->[1]->[$h]->[0] > $date){ // # This slot ends after $date // #print($date - $gantt->[$g]->[0]." -- $gantt->[0]->[4]\n"); // if (($gantt->[$g]->[0] < $date) and ($slot_date_here == 0) and ($date - $gantt->[$g]->[0] > $gantt->[0]->[4])){ // # We must create a smaller slot (hole start time < $date) // splice(@{$gantt->[$g]->[1]}, $h, 0, [ $date , $gantt->[$g]->[1]->[$h]->[1] ]); // $h++; # Go to the slot that we were on it before the splice // $slot_date_here = 1; // } // # Add new slots in the new hole // if (($new_hole->[0] < $gantt->[$g]->[1]->[$h]->[0]) and ($gantt->[$g]->[1]->[$h]->[0] - $new_hole->[0] > $gantt->[0]->[4])){ // # copy slot in the new hole if needed // my $slot = 0; // while (($slot <= $#{@{$new_hole->[1]}}) and ($new_hole->[1]->[$slot]->[0] < $gantt->[$g]->[1]->[$h]->[0])){ // # Find right index in the sorted slot array // $slot++; // } // if ($slot <= $#{@{$new_hole->[1]}}){ // if ($new_hole->[1]->[$slot]->[0] == $gantt->[$g]->[1]->[$h]->[0]){ // # If the slot already exists // $new_hole->[1]->[$slot]->[1] |= $gantt->[$g]->[1]->[$h]->[1]; // }else{ // # Insert the new slot // splice(@{$new_hole->[1]}, $slot, 0, [$gantt->[$g]->[1]->[$h]->[0], $gantt->[$g]->[1]->[$h]->[1]]); // } // }elsif ($new_hole->[0] < $gantt->[$g]->[1]->[$h]->[0]){ // # There is no slot so we create one // push(@{$new_hole->[1]}, [ $gantt->[$g]->[1]->[$h]->[0], $gantt->[$g]->[1]->[$h]->[1] ]); // } // } // # Remove new occupied resources from the current slot // $gantt->[$g]->[1]->[$h]->[1] &= (~ $resources_vec) ; // if (unpack("%32b*",$gantt->[$g]->[1]->[$h]->[1]) == 0){ // # There is no free resource on this slot so we delete it // splice(@{$gantt->[$g]->[1]}, $h, 1); // $h--; // $slot_deleted = 1; // } // } // # Go to the next slot // $h++; // } // } // if (($slot_deleted == 1) and ($#{@{$gantt->[$g]->[1]}} < 0)){ // # There is no free slot on the current hole so we delete it // splice(@{$gantt}, $g, 1); // $g--; // } // # Go to the next hole // $g++; // } // if ($#{@{$new_hole->[1]}} >= 0){ // # Add the new hole // if (($g > 0) and ($g - 1 <= $#{@{$gantt}}) and ($gantt->[$g - 1]->[0] == $new_hole->[0])){ // # Verify if the hole does not already exist // splice(@{$gantt}, $g - 1, 1, $new_hole); // }else{ // splice(@{$gantt}, $g, 0, $new_hole); // } // } // } /** Find the first hole in the data structure that can fit the given slot */ int find_hole(Gantt *gantt, int begin_date, int duration) { int end_date = begin_date + duration; unsigned int g = 0; for(g=0; g < gantt->holes.size() && gantt->holes[g].start_time < begin_date && gantt->holes[g].holestop.rbegin()->stop_time < end_date; g++); return g; } // sub find_hole($$$){ // my ($gantt, $begin_date, $duration) = @_; // my $end_date = $begin_date + $duration; // my $g = 0; // while (($g <= $#{@{$gantt}}) and ($gantt->[$g]->[0] < $begin_date) and ($gantt->[$g]->[1]->[$#{@{$gantt->[$g]->[1]}}]->[0] < $end_date)){ // $g++ // } // return($g); // } /** Returns the vector of the maximum free resources at the given date for the given duration */ std::vector get_free_resources(Gantt *gantt, int begin_date, int duration) { int end_date = begin_date + duration; int hole_index = 0; // search the nearest hole for(hole_index=0; hole_index < gantt->holes.size() && gantt->holes[hole_index].start_time < begin_date // regarder le derner stop du trou && ( ( gantt->holes[hole_index].holestop.rbegin()->stop_time < end_date ) || (hole_index+1 < gantt->holes.size() && gantt->holes[hole_index+1].start_time < begin_date) ); hole_index++); if ( hole_index >= gantt->holes.size() ) return gantt->holes[0].minimum_hole_duration; int h = 0; for (h=0; h < gantt->holes[hole_index].holestop.size() && gantt->holes[hole_index].holestop[h].stop_time < end_date; h++); return gantt->holes[hole_index].holestop[h].r; } // sub get_free_resources($$$){ // my ($gantt, $begin_date, $duration) = @_; // my $end_date = $begin_date + $duration; // my $hole_index = 0; // # search the nearest hole // while (($hole_index <= $#{@{$gantt}}) and ($gantt->[$hole_index]->[0] < $begin_date) and // (($gantt->[$hole_index]->[1]->[$#{@{$gantt->[$hole_index]->[1]}}]->[0] < $end_date) or // (($hole_index + 1 <= $#{@{$gantt}}) and $gantt->[$hole_index + 1]->[0] < $begin_date))){ // $hole_index++; // } // return($gantt->[0]->[4]) if ($hole_index > $#{@{$gantt}}); // my $h = 0; // while (($h <= $#{@{$gantt->[$hole_index]->[1]}}) and ($gantt->[$hole_index]->[1]->[$h]->[0] < $end_date)){ // $h++; // } // return($gantt->[$hole_index]->[1]->[$h]->[1]); // } /** Take a list of resource trees and find a hole that fit args : gantt ref, initial time from which the search will begin, job duration, list of resource trees */ pair > find_first_hole(Gantt *gantt, int initial_time, int duration, vector tree_description_list, int timeout) { /* $tree_description_list->[0] --> First resource group corresponding tree $tree_description_list->[1] --> Second resource group corresponding tree ... */ if (tree_description_list.size() == 0 ) return pair >(get_infinity_value(), vector() ); vector result_tree_list; int end_loop = 0; int current_time = initial_time; int timeout_initial_time = time(NULL); // begin research at the first potential hole int current_hole_index = find_hole(gantt, initial_time, duration); int h = 0; while(end_loop == 0) { // Go to a right hole while( (current_hole_index < gantt.holes.size()) && ( // BUG ? test bizarre, comment est-on sur de h>0 ? (gantt.holes[current_hole_index].start_time + duration > gantt.holes[current_hole_index].holestop[h].stop_time) || ( (initial_time > gantt.holes[current_hole_index].start_time) && (initial_time + duration > gantt.holes[current_hole_index].holestop[h].stop_time ) ) ) ) { // BUG ? surtout que l'on ne teste h que la et il commence pas a 0 for( ; h < gant.hole[current_hole_index].holestop.size() && ( ( gantt.holes[current_hole_index].start_time + duration > gantt.holes[current_hole_index].holestop[h].stop_time ) || ( (inital_time > gantt.holes[current_hole_index].start_time) || (inital_time + duration > gantt.holes[current_hole_index].holestop[h].stop_time) ) ); h++); if (h >= gantt.holes[current_hole_index].holestop.size() ) { // in this hole no slot fits so we must search in the next hole h = 0; current_hole_index++; } } if (current_hole_index >= gantt.hole.size() ) { // no hole fits current_time = get_infinity_value(); result_tree_list = vector(0); end_loop = 1; } else { // printf("Treate hole %d, %d : %d --> %d\n", current_hole_index, h, gantt.holes[current_hole_index].start_time, gantt.holes[current_hole_index].holestop[h].stop_time); if ( inital_time < gantt.holes[current_hole_index].start_time ) current_time = gantt.holes[current_hole_index].start_time; //Check all trees TreeNode *tree_clone; int i = 0; do{ //# clone the tree, so we can work on it without damage tree_clone = OAR::Schedulers::ResourceTree::clone(tree_description_list[i]); //#Remove tree leafs that are not free vector vn = OAR::Schedulers::ResourceTree::get_tree_leafs(tree_clone); vector::iterator l = vn.begin(); while( l != vn.end() ) { if ( ! gantt.holes[current_hole_index].holestop[h].r[OAR::Schedulers::ResourceTree::get_current_resource_value(l)] ) { OAR::Schedulers::ResourceTree::delete_subtree(l); } l++; } // #print(Dumper($tree_clone)); tree_clone = OAR::Schedulers::ResourceTree::delete_tree_nodes_with_not_enough_resources(tree_clone); // #$Data::Dumper::Purity = 0; // #$Data::Dumper::Terse = 0; // #$Data::Dumper::Indent = 1; // #$Data::Dumper::Deepcopy = 0; // # print(Dumper($tree_clone)); result_tree_list[i] = tree_clone; i ++; } while(tree_clone != NULL && (i < tree_description_list.size())); if (tree_clone != NULL) { //# We find the first hole end_loop = 1; } else { //# Go to the next slot of this hole if (h >= gantt.holes[current_hole_index].holestop.size() ) { h = 0; current_hole_index++; } else { h++; } } } //# Check timeout // BUG: Gregory: I did not port the timeout for the moment // if (($current_hole_index <= $#{@{$gantt}}) and // (((time() - $timeout_initial_time) >= $timeout) or // (($gantt->[$current_hole_index]->[0] == $gantt->[0]->[5]->[0]) and ($gantt->[$current_hole_index]->[1]->[$h]->[0] >= $gantt->[0]->[5]->[1])) or // ($gantt->[$current_hole_index]->[0] > $gantt->[0]->[5]->[0]))){ // if (($gantt->[0]->[5]->[0] == $gantt->[$current_hole_index]->[0]) and // ($gantt->[0]->[5]->[1] > $gantt->[$current_hole_index]->[1]->[$h]->[0])){ // $gantt->[0]->[5]->[1] = $gantt->[$current_hole_index]->[1]->[$h]->[0]; // }elsif ($gantt->[0]->[5]->[0] > $gantt->[$current_hole_index]->[0]){ // $gantt->[0]->[5]->[0] = $gantt->[$current_hole_index]->[0]; // $gantt->[0]->[5]->[1] = $gantt->[$current_hole_index]->[1]->[$h]->[0]; // } // #print("TTTTTTT $gantt->[0]->[5]->[0] $gantt->[0]->[5]->[1] -- $gantt->[$current_hole_index]->[0] $gantt->[$current_hole_index]->[1]->[$h]->[0]\n"); // $current_time = $Infinity; // @result_tree_list = (); // $end_loop = 1; // } } return pair >(current_time, result_tree_list); } // sub find_first_hole($$$$$){ // my ($gantt, $initial_time, $duration, $tree_description_list, $timeout) = @_; // # $tree_description_list->[0] --> First resource group corresponding tree // # $tree_description_list->[1] --> Second resource group corresponding tree // # ... // return ($Infinity, ()) if (!defined($tree_description_list->[0])); // my @result_tree_list = (); // my $end_loop = 0; // my $current_time = $initial_time; // my $timeout_initial_time = time(); // # begin research at the first potential hole // my $current_hole_index = find_hole($gantt, $initial_time, $duration); // my $h = 0; // while ($end_loop == 0){ // # Go to a right hole // while (($current_hole_index <= $#{@{$gantt}}) and // (($gantt->[$current_hole_index]->[0] + $duration > $gantt->[$current_hole_index]->[1]->[$h]->[0]) or // (($initial_time > $gantt->[$current_hole_index]->[0]) and // ($initial_time + $duration > $gantt->[$current_hole_index]->[1]->[$h]->[0])))){ // while (($h <= $#{@{$gantt->[$current_hole_index]->[1]}}) and // (($gantt->[$current_hole_index]->[0] + $duration > $gantt->[$current_hole_index]->[1]->[$h]->[0]) or // (($initial_time > $gantt->[$current_hole_index]->[0]) and // ($initial_time + $duration > $gantt->[$current_hole_index]->[1]->[$h]->[0])))){ // $h++; // } // if ($h > $#{@{$gantt->[$current_hole_index]->[1]}}){ // # in this hole no slot fits so we must search in the next hole // $h = 0; // $current_hole_index++; // } // } // if ($current_hole_index > $#{@{$gantt}}){ // # no hole fits // $current_time = $Infinity; // @result_tree_list = (); // $end_loop = 1; // }else{ // #print("Treate hole $current_hole_index, $h : $gantt->[$current_hole_index]->[0] --> $gantt->[$current_hole_index]->[1]->[$h]->[0]\n"); // $current_time = $gantt->[$current_hole_index]->[0] if ($initial_time < $gantt->[$current_hole_index]->[0]); // #Check all trees // my $tree_clone; // my $i = 0; // do{ // # clone the tree, so we can work on it without damage // $tree_clone = OAR::Schedulers::ResourceTree::clone($tree_description_list->[$i]); // #Remove tree leafs that are not free // foreach my $l (OAR::Schedulers::ResourceTree::get_tree_leafs($tree_clone)){ // if (!vec($gantt->[$current_hole_index]->[1]->[$h]->[1],OAR::Schedulers::ResourceTree::get_current_resource_value($l),1)){ // OAR::Schedulers::ResourceTree::delete_subtree($l); // } // } // #print(Dumper($tree_clone)); // $tree_clone = OAR::Schedulers::ResourceTree::delete_tree_nodes_with_not_enough_resources($tree_clone); // #$Data::Dumper::Purity = 0; // #$Data::Dumper::Terse = 0; // #$Data::Dumper::Indent = 1; // #$Data::Dumper::Deepcopy = 0; // # print(Dumper($tree_clone)); // $result_tree_list[$i] = $tree_clone; // $i ++; // }while(defined($tree_clone) && ($i <= $#$tree_description_list)); // if (defined($tree_clone)){ // # We find the first hole // $end_loop = 1; // }else{ // # Go to the next slot of this hole // if ($h >= $#{@{$gantt->[$current_hole_index]->[1]}}){ // $h = 0; // $current_hole_index++; // }else{ // $h++; // } // } // } // # Check timeout // if (($current_hole_index <= $#{@{$gantt}}) and // (((time() - $timeout_initial_time) >= $timeout) or // (($gantt->[$current_hole_index]->[0] == $gantt->[0]->[5]->[0]) and ($gantt->[$current_hole_index]->[1]->[$h]->[0] >= $gantt->[0]->[5]->[1])) or // ($gantt->[$current_hole_index]->[0] > $gantt->[0]->[5]->[0]))){ // if (($gantt->[0]->[5]->[0] == $gantt->[$current_hole_index]->[0]) and // ($gantt->[0]->[5]->[1] > $gantt->[$current_hole_index]->[1]->[$h]->[0])){ // $gantt->[0]->[5]->[1] = $gantt->[$current_hole_index]->[1]->[$h]->[0]; // }elsif ($gantt->[0]->[5]->[0] > $gantt->[$current_hole_index]->[0]){ // $gantt->[0]->[5]->[0] = $gantt->[$current_hole_index]->[0]; // $gantt->[0]->[5]->[1] = $gantt->[$current_hole_index]->[1]->[$h]->[0]; // } // #print("TTTTTTT $gantt->[0]->[5]->[0] $gantt->[0]->[5]->[1] -- $gantt->[$current_hole_index]->[0] $gantt->[$current_hole_index]->[1]->[$h]->[0]\n"); // $current_time = $Infinity; // @result_tree_list = (); // $end_loop = 1; // } // } // return($current_time, \@result_tree_list); // } // return 1; } oar-2.5.7/sources/extra/cpp-scheduler/Oar_resource_tree.H0000644015014700017500000000604512677211234023057 0ustar neyronneyron#ifndef OAR_RESOURCE_TREE_H #define OAR_RESOURCE_TREE_H #include #include #include #include #include namespace OAR::Schedulers::ResourceTree { class TreeNode; class TreeNode { public: TreeNode *father; // father ref $tree_ref->[0] std::map children; // ref of a hashtable with children $tree_ref->[1 std::string name; // name of the resource $tree_ref->[2] std::string value; // value of this resource $tree_ref->[3] int level; // level indicator $tree_ref->[4] int needed_children_number; /* needed children number : $tree_ref->[5] -1 means ALL (Alive + Absent + Suspected resources) -2 means BEST (Alive resources at the time)*/ int max_available_children; // maximum available children: $tree_ref->[6]; TreeNode *prev_brother; // previous brother ref $tree_ref->[7] TreeNode *next_brother; // next brother ref $tree_ref->[8] TreeNode *first_child; // first child ref $tree_ref->[9] int current_child_number; // current children number $tree_ref->[10] = 0 ; /** # Create a tree # arg : number of needed children # return the ref of the created tree */ TreeNode(int need_child_num) : father(NULL), level(0), needed_children_number(need_child_num),max_available_children(0), prev_brother(NULL), next_brother(NULL), first_child(NULL),current_child_number(0) {}; TreeNode(TreeNode *fat, TreeNode *child, std::string res_name, std::string res_value, int lev, int need_ch_numb, int max_avai_ch, TreeNode *prev_bro, TreeNode *next_bro, TreeNode *first_ch, int cur_ch_numb ) : father(fat), name(res_name), value(res_value),level(lev), needed_children_number(need_ch_numb), max_available_children(max_avai_ch), prev_brother(prev_bro), next_brother(next_bro), first_child(first_ch), current_child_number(cur_ch_numb) { assert( child == 0 ); // not implemented }; }; TreeNode *clone(TreeNode *tree_ref); bool is_node_a_leaf(TreeNode *tree_ref); TreeNode *add_child(TreeNode *tree_ref, std::string resource_name, std::string resource_value); int set_needed_children_number(TreeNode *tree_ref, int needed_children_number); TreeNode *get_previous_brother(TreeNode *tree_ref); TreeNode *get_next_brother(TreeNode *tree_ref); TreeNode *get_initial_child(TreeNode *tree_ref); TreeNode *get_a_child(TreeNode *tree_ref, std::string child_name); TreeNode *get_father(TreeNode *tree_ref); std::string get_current_resource_name(TreeNode *tree_ref); std::string get_current_resource_value(TreeNode *tree_ref); int get_current_children_number(TreeNode *tree_ref); int get_current_level(TreeNode *tree_ref); int get_max_available_children(TreeNode *tree_ref); int get_needed_children_number(TreeNode *tree_ref); TreeNode *delete_subtree(TreeNode *tree_ref); TreeNode *delete_tree_nodes_with_not_enough_resources(TreeNode *tree_ref); std::vector get_tree_leafs(TreeNode *tree); TreeNode *delete_unnecessary_subtrees(TreeNode *tree_ref); } #endif oar-2.5.7/sources/extra/cpp-scheduler/Oar_iolib.cc0000644015014700017500000010002612677211234021477 0ustar neyronneyron/****************************************************************************** # This is the iolib, which manages the layer between the modules and the # database. This is the only base-dependent layer. # When adding a new function, the following comments are required before the code of the function: # - the name of the function # - a short description of the function # - the list of the parameters it expect # - the list of the return values # - the list of the side effects ******************************************************************************/ #include #include #include #include extern "C" { #include } #include "Oar_resource_tree.H" using namespace std; /* fonction de la iolib utilisee dans sched_gantt_... */ /* connect_db() - DONE connect() - DONE connect_ro() - DONE disconnect() - DONE get_specific_resource_states($base,$Resources_to_always_add_type); - DONE list_resources($base) - DONE OAR::IO::get_gantt_scheduled_jobs(); - DONE get_current_job_types($base,$i); - DONE get_job_current_resources($base, $already_scheduled_jobs{$i}->[7],\@Sched_available_suspended_resource_type); - DONE get_job_suspended_sum_duration($base,$i,$current_time); - DONE OAR::IO::get_resources_in_state($base,"Alive"); - DONE get_resources_in_state($base,"Dead")); - DONE get_fairsharing_jobs_to_schedule($base,$queue,$Karma_max_number_of_jobs_treated_per_user); - DONE get_sum_accounting_window($base,$queue,$current_time - $Karma_window_size,$current_time); - DONE get_sum_accounting_for_param($base,$queue,"accounting_project",$current_time - $Karma_window_size,$current_time); - DONE get_sum_accounting_for_param($base,$queue,"accounting_user",$current_time - $Karma_window_size,$current_time); - DONE get_current_job_dependencies($base,$j->{job_id})) - DONE get_job($base,$d); - DONE get_gantt_job_start_time($base,$d); - DONE get_current_moldable_job($base,$date_tmp[1]); - DONE set_job_message($base,$j->{job_id},$message); - DONE set_job_message($base,$j->{job_id},$message); - DONE IDEM PREC get_current_job_types($base,$j->{job_id}); - DONE get_resources_data_structure_current_job($base,$j->{job_id}); - DONE get_resources_that_can_be_waked_up($base, OAR::IO::get_date($base) + $duration)) - DONE get_resources_that_will_be_out($base, OAR::IO::get_date($base) + $duration)) - DONE - MERGED WITH PRECEDENT get_possible_wanted_resources($base_ro,$alive_resources_vector,$resource_id_used_list_vector,\@Dead_resources,"$job_properties AND $tmp_properties", $m->{resources}, $Order_part); - DONE add_gantt_scheduled_jobs($base,$moldable_results[$index_to_choose]->{moldable_id}, $moldable_results[$index_to_choose]->{start_date},$moldable_results[$index_to_choose]->{resources}); - DONE set_job_message($base,$j->{job_id},"Karma = ".sprintf("%.3f",karma($j))); - DONE PREV disconnect($base_ro); - DONE PREV */ /** Questions ouvertes: - dans OAR perl, il y a dans des string double-cote avec " " il y a plein de " \'CURRENT\' " qui sont equivalents a " 'CURRENT' ". Etonnant non ? C'est idem en C++, donc je les laisse :-) */ namespace iolib { QSqlDatabase db; /* # connect_db # Connects to database and returns the base identifier # return value : base */ int connect_db(string dbhost, int dbport, string dbname, string dblogin, string dbpasswd, int debug_level=0) { db = QSqlDatabase::addDatabase("oardb"); db.setHostName(QString::fromStdString( dbhost )); db.setPort(dbport); db.setDatabaseName(QString::fromStdString( dbname )); db.setUsername(QString::fromStdString( dblogin )); db.setpassword(QString::fromStdString( dbpasswd )); bool ok = db.open(); /* TODO: ajouter le traitement d'erreur if (!defined($dbh)){ oar_error("[IOlib] Cannot connect to database (type=$Db_type, host=$host, user=$user, database=$name) : $DBI::errstr\n"); if ($Timeout_db_connection < $Max_db_connection_timeout){ $Timeout_db_connection += 2; } oar_warn("[IOlib] I will retry to connect to the database in $Timeout_db_connection s\n"); send_log_by_email("OAR database connection failed","[IOlib] I will retry to connect to the database in $Timeout_db_connection s\n"); sleep($Timeout_db_connection); } */ return ok; } /** # connect # Connects to database and returns the base identifier # parameters : / # return value : base # side effects : opens a connection to the base specified in ConfLib */ bool connect() { //# Connect to the database. init_conf(getenv("OARCONFFILE")); string dbhost = get_conf("DB_HOSTNAME"); string dbport = get_conf("DB_PORT"); string dbname = get_conf("DB_BASE_NAME"); string dblogin = get_conf("DB_BASE_LOGIN"); string dbpwd = get_conf("DB_BASE_PASSWD"); string Db_type = get_conf("DB_TYPE"); string log_level = get_conf("LOG_LEVEL"); string Remote_host = get_conf("SERVER_HOSTNAME"); string Remote_port = get_conf("SERVER_PORT"); return connect_db(dbhost, dbport, dbname, dblogin, dbpasswd, debug_level); } /* # connect_ro # Connects to database and returns the base identifier # parameters : / # return value : base # side effects : opens a connection to the base specified in ConfLib */ bool connect_ro() { return connect(); } /* # disconnect # Disconnect from database # parameters : base # return value : / # side effects : closes a previously opened connection to the specified base */ void disconnect() { assert( db.isValid() ); db.close(); } /* # get_specific_resource_states # returns a hashtable with each given resources and their states # parameters : base, resource type */ multimap< string, string > get_specific_resource_states(string type) { assert( db.isValid() ); QSqlQuery query; query.setForwardOnly(true); string req = " SELECT resource_id, state\ FROM resources\ WHERE\ type = \'" +type+"\'\ "; query.exec(req); multimap< pair< string, string> > result; while( query.next() ) { string resource_id = query.value(0).toString(); string state = query.value(1).toString(); result.insert( pair(state, resource_id) ); } return result; } /* # list_resources # gets the list of all resources # parameters : base # return value : list of resources # side effects : / */ static bool yesNo2Bool(string s) { if ( s == "YES" ) return true; if ( s == "NO" ) return false; assert( s == "YES" || s == "NO" ); } static struct resources_iolib fillResourcesStruct(QSqlQuery &req) { /* the value of the structure must be given in the same order a filled by the SELECT call. */ resources_iolib result; result.resource_id = req.value(0).toUInt(); result.type = req.value(1).toString(); result.network_address = req.value(2).toString(); result.state = req.value(3).toString(); result.next_state = req.value(4).toString(); result.finaud_decision = yesNo2Bool(req.value(5).toString()); result.next_finaud_decision = yesNo2Bool(req.value(6).toString()); result.state_num = req.value(7).toUInt(); result.suspended_jobs = yesNo2Bool(req.value(8).toString()); result.scheduler_priority = req.value(9).toUInt(); result.switch_name = req.value(10).toString(); result.cpu = req.value(11).toUInt(); result.cpuset = req.value(12).toUInt(); result.besteffort = yesNo2Bool(req.value(13).toString()); result.deploy = yesNo2Bool(req.value(14).toString()); result.expiry_date = req.value(15).toUInt(); result.desktop_computing = yesNo2Bool(req.value(16).toString()); result.last_job_date = req.value(17).toUInt(); result.available_upto = req.value(18).toUInt(); return result; } /** TODO SIMPLIFICATION : l usage de cette fonction est uniquement d'obtenir la liste des ID pour remplir le vecteur de bit ! TODO RTFM: il est possible de faire semblable au caode perl avec QtSQLModel ! readonly avec */ vector resources_extractor(bool withState, string state="") { assert(db.isValid()); QSqlQuery query; query.setForwardOnly(true); vector result; string req = "SELECT resource_id, type, network_address, state, next_state, finaud_decision, next_finaud_decision, state_num, suspended_jobs, scheduler_priority, switch, cpu, cpuset, besteffort, deploy, expiry_date, desktop_computing, last_job_date, available_upto\ FROM resources\ "; if (withState) { req += "WHERE\ state = \'" << state << "\'"); } query.exec(req); while( query.next() ) { result.push_back( fillResourcesStruct(req) ); } return result; } vector list_resources() { return resources_extractor(false); } /* # GANTT MANAGEMENT #get previous scheduler decisions #args : base #return a hashtable : job_id --> [start_time,walltime,queue_name,\@resources,state] # TODO commentaire PERL faux: bien plus d'information et pas de resssource ! */ pair< vector, map > get_gantt_scheduled_jobs(){ QSqlQuery query; query.setForwardOnly(true); map result; vector order; assert(db.isValid()); string req("SELECT j.job_id, g2.start_time, m.moldable_walltime, g1.resource_id, j.queue_name, j.state, j.job_user, j.job_name,m.moldable_id,j.suspended\ FROM gantt_jobs_resources g1, gantt_jobs_predictions g2, moldable_job_descriptions m, jobs j\ WHERE\ m.moldable_index = \'CURRENT\'\ AND g1.moldable_job_id = g2.moldable_job_id\ AND m.moldable_id = g2.moldable_job_id\ AND j.job_id = m.moldable_job_id\ ORDER BY j.start_time, j.job_id\ "); query.exec(req); while( query.next() ) { struct gantt_sched_jobs val; unsigned int jid; if (result.find(query.value(0).toUint()) != result.end()) { jid = query.value(0).toUint(); val.job_id = jid; val.start_time = query.value(1).toUint(); moldable_walltime = query.value(2).toUint(); queue_name = query.value(4).toString(); state = query.value(5).toString(); job_user = query.value(6).toString(); job_name = query.value(7).toString(); moldable_id = query.value(7).toUInt(); suspended = yesNo2Bool(req.value(8).toString()); order.push_back(jid); result.insert( pair(jid, val) ); } result[jid].resource_id_vec.push_back( query.value(3).toUint() ); }; return pair< vector, map >(order, result); } /** # get_current_job_types # return a hash table with all types for the given job ID */ static regexp *rexp_get_current_job_types = 0; map get_current_job_types(unsigned int jobId){ QSqlQuery query; query.setForwardOnly(true); map res; if (rexp == 0) rexp_get_current_job_types = regcomp("^\s*(\w+)\s*=\s*(.+)$") string req = " SELECT type\ FROM job_types\ WHERE\ types_index = \'CURRENT\'\ AND job_id = $jobId\ " assert(db.isValid()); query.exec(req); while( query.next() ) { int valrec; valres = regexec(rexp_get_current_job_types, query.value(0).toString() ); if (valres) { res.insert( pair( string(startp[1], endp[1]), string(startp[2], endp[1]) ) ); } else { res.insert(pair( query.value(0).toString(), "true") ); } } return res; } /* # get_job_current_resources # returns the list of resources associated to the job passed in parameter # parameters : base, jobid # return value : list of resources # side effects : / */ static string quote_sql2(const string s) { string res=s; size_t value = std::string::npos; value = res.find_first_of("'", 0); while(value != std::string::npos) { res.replace(value, 1, "''"); value +=2; value = res.find_first_of("'", value); } return res; } vector get_job_current_resources(unsigned int jobid, vector not_type_list) { vector result; QSql query; string tmp_str; assert(db.isValid()); string req; if (not_type_list.size() == 0) { tmp_str= "FROM assigned_resources\ WHERE\ assigned_resources.assigned_resource_index = \'CURRENT\' AND\ assigned_resources.moldable_job_id = "; tmp_str << jobid; } else { string type_str; for(i=0; i< not_type_list.size(); i++) { if (i > 0) type_str << ","; type_str << quote_sql2( not_type_list[i] ); } tmp_str = "FROM assigned_resources,resources\ WHERE\ assigned_resources.assigned_resource_index = \'CURRENT\' AND\ assigned_resources.moldable_job_id ="; tmp_str << jobid << " AND\ resources.resource_id = assigned_resources.resource_id AND\ resources.type NOT IN (" << type_str << ")"; } req = "SELECT assigned_resources.resource_id as resource "; req << tmp_str << " ORDER BY assigned_resources.resource_id ASC"; query.exec(req); while( query.next() ) { unsigned int resource_id = query.value(0).toUint(); result.push_back( resource_id ); } return result; } /** # get the amount of time in the suspended state of a job # args : base, job id, time in seconds */ unsigned int get_job_suspended_sum_duration(unsigned int job_id, unsigned int current_time) { assert(db.isValid()); QSqlQuery query; query.setForwardOnly(true); unsigned int sum; string req = "SELECT date_start, date_stop\ FROM job_state_logs\ WHERE\ job_id = " << job_id<< " AND\ (job_state = \'Suspended\' OR\ job_state = \'Resuming\')"; query.exec(req); sum =0; while( query.next() ) { unsigned int tmp_sum = 0; unsigned int date_start = query.value(0).toUInt(); unsigned int date_stop = query.value(1).toUInt(); if ( date_stop == 0 ) tmp_sum = current_time - date_start; else tmp_sum = date_stop - date_start; sum += tmp_sum; } return sum; } /** # get_resources_in_state # returns the list of resources in the state specified # parameters : base, state # return value : list of resource ref c'est une quasi-copie de list_resources, j'ai mutualiser le code */ vector get_resources_in_state(string state) { return resources_extractor(true, state); } /** remplissage de la structure jobs restreinte */ static struct jobs_iolib_restrict fillJobsStructRestrict(QSqlQuery &query) { /* the value of the structure must be given in the same order a filled by the SELECT call. */ jobs_iolib_restrict result; result.job_id = query.value(0).toUInt(); result.job_name = query.value(1).toString(); result.job_user = query.value(2).toString(); result.properties = query.value(3).toString(); result.project = query.value(4).toString(); return result; } /** # get_fairsharing_jobs_to_schedule # args : base ref, queue name */ vector get_fairsharing_jobs_to_schedule(string queue, unsigned int limit) { assert(db.isValid()); QSqlQuery query; query.setForwardOnly(true); unsigned int sum; string req = "SELECT distinct(job_user)\ FROM jobs\ WHERE\ state = \'Waiting\'\ AND reservation = \'None\'\ AND queue_name = \'" << queue << "\'\ "; vector users; query.exec(req); while( query.next() ) { users.insert( string(query.value(0).toString() ) ); } vector res; for(vector::iterator u = users.begin(); u != users.end(); u++) { string req2 = "SELECT job_id,job_name,job_user,properties,project\ FROM jobs\ WHERE \ state = \'Waiting\'\ AND reservation = \'None\'\ AND queue_name = \'" << queue << "\' \ AND job_user = \'" << *u << "\' \ ORDER BY job_id \ LIMIT "<< limit <<" \ "; query.exec(req); while( query.next() ) { res.insert( fillJobsStructRestrict(query) ); } } return res; } map get_sum_accounting_window(string queue, unsigned int start_window, unsigned int stop_window) { assert(db.isValid()); QSqlQuery query; query.setForwardOnly(true); unsigned int sum; string req = "SELECT consumption_type, SUM(consumption)\ FROM accounting \ WHERE \ queue_name = \'" << queue << "\' AND \ window_start >= " << start_window << " AND \ window_start < " << stop_window << " \ GROUP BY consumption_type \ "; query.exec(req); sum =0; map results while( query.next() ) { string consumption_type = query.value(0).toString(); unsigned int sum_consumption = query.value(1).toUInt(); results.insert( pair( consumption_type, sum_consumption)); } return results; } /** TODO: no comment in perl ! */ map, unsigned int> get_sum_accounting_for_param(string queue, string param_name, unsigned int start_window, unsigned int stop_window) { assert(db.isValid()); QSqlQuery query; query.setForwardOnly(true); unsigned int sum; string req = " SELECT " << param_name<< ",consumption_type, SUM(consumption)\ FROM accounting\ WHERE\ queue_name = \'" << queue<< "\' AND\ window_start >= " << start_window<< " AND\ window_start < "<< stop_window<< "\ GROUP BY " << param_name<< ",consumption_type\ "; query.exec(req); sum =0; map< pair, unsigned int> results while( query.next() ) { string param = query.value(0).toString(); string consumption_type = query.value(1).toString(); string sum_consumption = query.value(2).toUInt(); results.insert( pair, unsigned int>( pair( param, consumption_type ), sum_consumption)); } return results; } /** # get_current_job_dependencies # return an array table with all dependencies for the given job ID */ vector get_current_job_dependencies(unsigned int jobId) { assert(db.isValid()); QSqlQuery query; query.setForwardOnly(true); string req = " SELECT job_id_required\ FROM job_dependencies\ WHERE\ job_dependency_index = \'CURRENT\'\ AND job_id = "<< jobId <<"\ "; query.exec(req); vector results while( query.next() ) { unsigned int job_id_required = query.value(0).toUInt(); results.push_back( job_id_required ); } return results; } /** # get_job # returns a ref to some hash containing data for the job of id passed in # parameter # parameters : base, jobid # return value : ref # side effects : / job extraction is restricted to - state - job_type - exit_code */ struct jobs_get_job_iolib_restrict get_job_restrict(unsigned int idJob) { assert(db.isValid()); QSqlQuery query; query.setForwardOnly(true); string req = " SELECT state, job_type, exit_code\ FROM jobs\ WHERE\ job_id = << " idJob << "\ "; query.exec(req); struct jobs_get_job_iolib_restrict results; results.state = "ONE VALUE" while( query.next() ) { string state = query.value(0).toString(); string job_type = query.value(1).toString(); int exit_code = query.value(2).toInt(); assert(results.state == "ONE VALUE"); results.state = state; results.job_type = job_type; results.exit_code = exit_code; } return results; } /** # Return a data structure with the resource description of the given job # arg : database ref, job id # return a data structure (an array of moldable jobs): # example for the first moldable job of the list: # $result = [ # [ # { # property => SQL property # resources => [ # { # resource => resource name # value => number of this wanted resource # } # ] # } # ], # walltime, # moldable_job_id # ] */ vector get_resources_data_structure_current_job(unsigned int job_id) { assert(db.isValid()); QSqlQuery query; query.setForwardOnly(true); string req = " SELECT moldable_job_descriptions.moldable_id, job_resource_groups.res_group_id, moldable_job_descriptions.moldable_walltime, job_resource_groups.res_group_property, job_resource_descriptions.res_job_resource_type, job_resource_descriptions.res_job_value\ FROM moldable_job_descriptions, job_resource_groups, job_resource_descriptions, jobs\ WHERE\ jobs.job_id = " << job_id << "\ AND jobs.job_id = moldable_job_descriptions.moldable_job_id\ AND job_resource_groups.res_group_moldable_id = moldable_job_descriptions.moldable_id\ AND job_resource_descriptions.res_job_group_id = job_resource_groups.res_group_id\ ORDER BY moldable_job_descriptions.moldable_id, job_resource_groups.res_group_id, job_resource_descriptions.res_job_order ASC\ "; query.exec(req); vector result; int group_index = -1; int moldable_index = -1; int previous_group = 0; int previous_moldable = 0; while( query.next() ) { // moldable_job_descriptions.moldable_id unsigned int moldable = query.value(0).toUInt(); // job_resource_groups.res_group_id unsigned int group = query.value(1).toUInt(); // moldable_job_descriptions.moldable_walltime unsigned int walltime = query.value(2).toUInt(); // job_resource_groups.res_group_property string property = query.value(3).toString(); // job_resource_descriptions.res_job_resource_type string resource = query.value(4).toString(); // job_resource_descriptions.res_job_value string value = query.value(5).toString(); if (previous_moldable != moldable) { moldable_index ++; previous_moldable = moldable; group_index = 0; previous_group = group; } else if (previous_group != group) { group_index++; previous_group = group; } // Store walltime if (result.size() < moldable+1) result.push_back(resources_data_moldable()); result[moldable_index].walltime = walltime; result[moldable_index].moldable_job_id = moldable; // Store properties group if (result[moldable_index].prop_res.size() < group_index+1) result[moldable_index].prop_res.push_back(property_resources_per_job()); result[moldable_index].prop_res[group_index].property = property; resources_per_job tmp_res; tmp_res.resource = resource; tmp_res.value = value; result[moldable_index].prop_res[group_index].resources.push_back(tmp_res); } return(result); } /** # get_resources_that_can_be_waked_up # returns a list of resources # parameters : base, date max # return value : list of resource ref # get_resources_that_will_be_out # returns a list of resources # parameters : base, job max date # return value : list of resource ref restricted version to resource_id (the only used data in the scheduler) */ vector get_resources_that_can_be_waked_up_or_will_be_out(unsigned int max_date, bool waked_up) { assert(db.isValid()); QSqlQuery query; query.setForwardOnly(true); string status; string compar_oper; switch(waked_up) { case true: status = "Absent"; compare_oper = ">"; break; case false: status = "Alive"; compare_oper = "<"; break; } string req = " SELECT resource_id\ FROM resources\ WHERE\ state = \'" << status << "\' AND\ resources.available_upto " << compare_oper <<" " << max_date << "\ "; query.exec(req); vector results; while( query.next() ) { unsigned int resource_id = query.value(0).toUInt(); results.push_back(resource_id); } return results; } /** # Get start_time for a given job # args : base, job id WARNING: no undef are returned in this version ! */ struct gantt_job_start_time get_gantt_job_start_time(unsigned int job) { assert(db.isValid()); QSqlQuery query; query.setForwardOnly(true); string req = " SELECT gantt_jobs_predictions.start_time, gantt_jobs_predictions.moldable_job_id\ FROM gantt_jobs_predictions,moldable_job_descriptions\ WHERE\ moldable_job_descriptions.moldable_job_id = " << job <<"\ AND gantt_jobs_predictions.moldable_job_id = moldable_job_descriptions.moldable_id\ "; query.exec(req); struct gantt_job_start_time results={}; if ( query.next() ) { results.start_time = query.value(0).toUInt(); results.moldable_job_id = query.value(1).toUInt(); } else assert(0); assert(! query.next()); /* only one answer ! */ return results; } /** # get_current_moldable_job_restrict_moldable_wall_time # returns a ref to some hash containing data for the moldable job of id passed in # parameter # parameters : base, moldable job id # return value : ref # side effects : / restricted to moldable_wall_time */ unsigned int get_current_moldable_job_restrict_moldable_walltime(unsigned int moldableJobId) { assert(db.isValid()); QSqlQuery query; query.setForwardOnly(true); string req = " SELECT moldable_walltime\ FROM moldable_job_descriptions\ WHERE\ moldable_index = \'CURRENT\'\ AND moldable_id = " << moldableJobId << "\ "; query.exec(req); unsigned int results=0; if ( query.next() ) { results = query.value(0).toUInt(); } else assert(0); assert(! query.next()); /* only one answer ! */ return results; } /** # set_job_message # sets the message field of the job of id passed in parameter # parameters : base, jobid, message # return value : / # side effects : changes the field message of the job in the table Jobs */ int set_job_message(unsigned int idJob, string message) { assert(db.isValid()); QSqlQuery query; string req = " UPDATE jobs\ SET message = " << message << "\ WHERE\ job_id = "<< idJob<<"\ "; query.exec(req); return 0; } /** # get_possible_wanted_resources # return a tree ref : a data structure with corresponding resources with what is asked */ TreeNode *get_possible_wanted_resources( vector possible_resources_vector, vector impossible_resources_vector, vector resources_to_ignore_array, string properties, vector wanted_resources_ref, /* TODO: verify type */ string order_part) { string sql_in_string= "\'1\'"; if (resources_to_ignore_array.size() > 0 ) { sql_in_string = "resource_id NOT IN ("; for(vector::iterator i = resources_to_ignore_array.begin(); i != resources_to_ignore_array.end(); i++) { static bool debut=1; switch (debut) { case 0: sql_in_string += ","; case 1: debut = 0; } sql_in_string += "" << *i; } sql_in_string = ")"; } if (order_part != "") order_part = "ORDER BY " << order_part; /* copy !*/ wanted_resources = wanted_resources_ref; int nb_res = wanted_resources.resources.size(); if (wanted_resources.resources[nb_res - 1]->resource != "resource_id") wanted_resources.resources.push_back( resources_per_job("resource_id", "-1")); string sql_where_string = "\'1\'"; if (properties != "") sql_where_string += " AND ( " << properties <<" )"; /* #Get only wanted resources */ string resource_string; for(vector::iterator i = wanted_resources.resources.begin(); i != wanted_resources.resources.end(); i++) { static bool debut=1; switch (debut) { case 0: resource_string += ","; case 1: debut = 0; break; } resource_string += "" << i->resource; } assert(db.isValid()); QSqlQuery query; query.setForwardOnly(true); string req = "SELECT " << resource_string << "\ FROM resources\ WHERE\ ("<< sql_where_string<< ") AND\ " << sql_in_string << "\ " << order_part <<"\ "; query.exec(req); /* how to send back Undef ? why ? */ /* # Initialize root */ TreeNode *result; result = new( TreeNode(0) ); int wanted_children_number = wanted_resources.resources[0].value; result->set_needed_children_number(wanted_children_number); while( query.next() ) { TreeNode *father_ref = result; for(i=0; i < wanted_resources.resources.size(); i++) { /** # Feed the tree for all resources */ father_ref = father_ref->add_child(wanted_resources.resources[i].resource, query.value(i).toString() ); int wanted_children_number; if ( i < wanted_resources.resources.size() - 1) wanted_children_number = wanted_resources.resources[i+1].value; else wanted_children_number = 0; father_ref->set_needed_children_number(wanted_children_number); /* # Verify if we must keep this child if this is resource_id resource name */ if ( wanted_resources.resources[i].resource == "resource_id" ) { if (impossible_resources_vector.size() > 0 && impossible_resources_vector[ query.value(i).toInt() ] ) { father_ref->delete_subtree(); i = wanted_resources.resources.size(); /* the end */ } else if ( possible_resources_vector.size() > 0 && ! possible_resources_vector[ query.value(i).toInt() ]) { father_ref->delete_subtree(); i = wanted_resources.resources.size(); /* the end */ } } } } result->delete_tree_nodes_with_not_enough_resources(); return result; } /** #add scheduler decisions #args : base,moldable_job_id,start_time,\@resources #return nothing */ void add_gantt_scheduled_jobs(unsigned int id_moldable_job, unsigned int start_time, vector resource_list) { assert(db.isValid()); QSqlQuery query; string req = " INSERT INTO gantt_jobs_predictions (moldable_job_id,start_time)\ VALUES ("<< id_moldable_job<< ",\'"<< start_time<<"\')\ "; query.exec(req); for(vector::iterator i = resource_list.begin(); i != resource_list.end(); i++) { QSqlQuery query2; string req2 = " INSERT INTO gantt_jobs_resources (moldable_job_id,resource_id)\ VALUES ("< #include #include #include "../Oar_iolib.H" using namespace std; /** test of database management in qt sql by default, it use a sqlite database for testing purpose right now */ int miniconnect() { QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE"); db.setDatabaseName("mydb.db"); bool ok = db.open(); cout << "connect " << ok; } int main(int argc, char **argv) { miniconnect(); } oar-2.5.7/sources/extra/cpp-scheduler/DBTests/Makefile0000644015014700017500000001544012677211234022246 0ustar neyronneyron############################################################################# # Makefile for building: qttest # Generated by qmake (2.01a) (Qt 4.4.3) on: mer. déc. 17 17:08:23 2008 # Project: qttest.pro # Template: app # Command: /usr/bin/qmake-qt4 -unix -o Makefile qttest.pro ############################################################################# ####### Compiler, tools and options CC = gcc CXX = g++ DEFINES = -DQT_SQL_LIB -DQT_CORE_LIB -DQT_SHARED CFLAGS = -pipe -g -D_REENTRANT -Wall -W $(DEFINES) CXXFLAGS = -pipe -g -D_REENTRANT -Wall -W $(DEFINES) INCPATH = -I/usr/share/qt4/mkspecs/linux-g++ -I. -I/usr/include/qt4/QtCore -I/usr/include/qt4/QtCore -I/usr/include/qt4/QtSql -I/usr/include/qt4/QtSql -I/usr/include/qt4 -I. -I. LINK = g++ LFLAGS = LIBS = $(SUBLIBS) -L/usr/lib -lQtSql -lQtCore -lpthread AR = ar cqs RANLIB = QMAKE = /usr/bin/qmake-qt4 TAR = tar -cf COMPRESS = gzip -9f COPY = cp -f SED = sed COPY_FILE = $(COPY) COPY_DIR = $(COPY) -r INSTALL_FILE = install -m 644 -p INSTALL_DIR = $(COPY_DIR) INSTALL_PROGRAM = install -m 755 -p DEL_FILE = rm -f SYMLINK = ln -sf DEL_DIR = rmdir MOVE = mv -f CHK_DIR_EXISTS= test -d MKDIR = mkdir -p ####### Output directory OBJECTS_DIR = ./ ####### Files SOURCES = qttest.cc \ ../Oar_iolib.cc \ ../Oar_resource_tree.cc \ ../Gantt_hole_storage.cc OBJECTS = qttest.o \ Oar_iolib.o \ Oar_resource_tree.o \ Gantt_hole_storage.o DIST = /usr/share/qt4/mkspecs/common/g++.conf \ /usr/share/qt4/mkspecs/common/unix.conf \ /usr/share/qt4/mkspecs/common/linux.conf \ /usr/share/qt4/mkspecs/qconfig.pri \ /usr/share/qt4/mkspecs/features/qt_functions.prf \ /usr/share/qt4/mkspecs/features/qt_config.prf \ /usr/share/qt4/mkspecs/features/exclusive_builds.prf \ /usr/share/qt4/mkspecs/features/default_pre.prf \ /usr/share/qt4/mkspecs/features/debug.prf \ /usr/share/qt4/mkspecs/features/default_post.prf \ /usr/share/qt4/mkspecs/features/qt.prf \ /usr/share/qt4/mkspecs/features/unix/thread.prf \ /usr/share/qt4/mkspecs/features/moc.prf \ /usr/share/qt4/mkspecs/features/warn_on.prf \ /usr/share/qt4/mkspecs/features/resources.prf \ /usr/share/qt4/mkspecs/features/uic.prf \ /usr/share/qt4/mkspecs/features/yacc.prf \ /usr/share/qt4/mkspecs/features/lex.prf \ qttest.pro QMAKE_TARGET = qttest DESTDIR = TARGET = qttest first: all ####### Implicit rules .SUFFIXES: .o .c .cpp .cc .cxx .C .cpp.o: $(CXX) -c $(CXXFLAGS) $(INCPATH) -o "$@" "$<" .cc.o: $(CXX) -c $(CXXFLAGS) $(INCPATH) -o "$@" "$<" .cxx.o: $(CXX) -c $(CXXFLAGS) $(INCPATH) -o "$@" "$<" .C.o: $(CXX) -c $(CXXFLAGS) $(INCPATH) -o "$@" "$<" .c.o: $(CC) -c $(CFLAGS) $(INCPATH) -o "$@" "$<" ####### Build rules all: Makefile $(TARGET) $(TARGET): $(OBJECTS) $(LINK) $(LFLAGS) -o $(TARGET) $(OBJECTS) $(OBJCOMP) $(LIBS) Makefile: qttest.pro /usr/share/qt4/mkspecs/linux-g++/qmake.conf /usr/share/qt4/mkspecs/common/g++.conf \ /usr/share/qt4/mkspecs/common/unix.conf \ /usr/share/qt4/mkspecs/common/linux.conf \ /usr/share/qt4/mkspecs/qconfig.pri \ /usr/share/qt4/mkspecs/features/qt_functions.prf \ /usr/share/qt4/mkspecs/features/qt_config.prf \ /usr/share/qt4/mkspecs/features/exclusive_builds.prf \ /usr/share/qt4/mkspecs/features/default_pre.prf \ /usr/share/qt4/mkspecs/features/debug.prf \ /usr/share/qt4/mkspecs/features/default_post.prf \ /usr/share/qt4/mkspecs/features/qt.prf \ /usr/share/qt4/mkspecs/features/unix/thread.prf \ /usr/share/qt4/mkspecs/features/moc.prf \ /usr/share/qt4/mkspecs/features/warn_on.prf \ /usr/share/qt4/mkspecs/features/resources.prf \ /usr/share/qt4/mkspecs/features/uic.prf \ /usr/share/qt4/mkspecs/features/yacc.prf \ /usr/share/qt4/mkspecs/features/lex.prf \ /usr/lib/libQtSql.prl \ /usr/lib/libQtCore.prl $(QMAKE) -unix -o Makefile qttest.pro /usr/share/qt4/mkspecs/common/g++.conf: /usr/share/qt4/mkspecs/common/unix.conf: /usr/share/qt4/mkspecs/common/linux.conf: /usr/share/qt4/mkspecs/qconfig.pri: /usr/share/qt4/mkspecs/features/qt_functions.prf: /usr/share/qt4/mkspecs/features/qt_config.prf: /usr/share/qt4/mkspecs/features/exclusive_builds.prf: /usr/share/qt4/mkspecs/features/default_pre.prf: /usr/share/qt4/mkspecs/features/debug.prf: /usr/share/qt4/mkspecs/features/default_post.prf: /usr/share/qt4/mkspecs/features/qt.prf: /usr/share/qt4/mkspecs/features/unix/thread.prf: /usr/share/qt4/mkspecs/features/moc.prf: /usr/share/qt4/mkspecs/features/warn_on.prf: /usr/share/qt4/mkspecs/features/resources.prf: /usr/share/qt4/mkspecs/features/uic.prf: /usr/share/qt4/mkspecs/features/yacc.prf: /usr/share/qt4/mkspecs/features/lex.prf: /usr/lib/libQtSql.prl: /usr/lib/libQtCore.prl: qmake: FORCE @$(QMAKE) -unix -o Makefile qttest.pro dist: @$(CHK_DIR_EXISTS) .tmp/qttest1.0.0 || $(MKDIR) .tmp/qttest1.0.0 $(COPY_FILE) --parents $(SOURCES) $(DIST) .tmp/qttest1.0.0/ && $(COPY_FILE) --parents ../Oar_iolib.H ../Gantt_hole_storage.H ../Oar_resource_tree.H .tmp/qttest1.0.0/ && $(COPY_FILE) --parents qttest.cc ../Oar_iolib.cc ../Oar_resource_tree.cc ../Gantt_hole_storage.cc .tmp/qttest1.0.0/ && (cd `dirname .tmp/qttest1.0.0` && $(TAR) qttest1.0.0.tar qttest1.0.0 && $(COMPRESS) qttest1.0.0.tar) && $(MOVE) `dirname .tmp/qttest1.0.0`/qttest1.0.0.tar.gz . && $(DEL_FILE) -r .tmp/qttest1.0.0 clean:compiler_clean -$(DEL_FILE) $(OBJECTS) -$(DEL_FILE) *~ core *.core ####### Sub-libraries distclean: clean -$(DEL_FILE) $(TARGET) -$(DEL_FILE) Makefile mocclean: compiler_moc_header_clean compiler_moc_source_clean mocables: compiler_moc_header_make_all compiler_moc_source_make_all compiler_moc_header_make_all: compiler_moc_header_clean: compiler_rcc_make_all: compiler_rcc_clean: compiler_image_collection_make_all: qmake_image_collection.cpp compiler_image_collection_clean: -$(DEL_FILE) qmake_image_collection.cpp compiler_moc_source_make_all: compiler_moc_source_clean: compiler_uic_make_all: compiler_uic_clean: compiler_yacc_decl_make_all: compiler_yacc_decl_clean: compiler_yacc_impl_make_all: compiler_yacc_impl_clean: compiler_lex_make_all: compiler_lex_clean: compiler_clean: ####### Compile qttest.o: qttest.cc ../Oar_iolib.H \ ../Oar_resource_tree.H $(CXX) -c $(CXXFLAGS) $(INCPATH) -o qttest.o qttest.cc Oar_iolib.o: ../Oar_iolib.cc ../Oar_resource_tree.H $(CXX) -c $(CXXFLAGS) $(INCPATH) -o Oar_iolib.o ../Oar_iolib.cc Oar_resource_tree.o: ../Oar_resource_tree.cc ../Oar_resource_tree.H $(CXX) -c $(CXXFLAGS) $(INCPATH) -o Oar_resource_tree.o ../Oar_resource_tree.cc Gantt_hole_storage.o: ../Gantt_hole_storage.cc ../Gantt_hole_storage.H \ ../Oar_resource_tree.H $(CXX) -c $(CXXFLAGS) $(INCPATH) -o Gantt_hole_storage.o ../Gantt_hole_storage.cc ####### Install install: FORCE uninstall: FORCE FORCE: oar-2.5.7/sources/extra/cpp-scheduler/Gantt_hole_storage.H0000644015014700017500000000301312677211234023210 0ustar neyronneyron#ifndef GANTT_HOLE_STORAGE_H #define GANTT_HOLE_STORAGE_H #include //const unsigned int INFINITY = MAX_INT; #include "Oar_resource_tree.H" namespace Gant_hole_storage { class StopTime { public: unsigned int stop_time; std::vector r; StopTime(unsigned int time, std::vector res) : stop_time(time), r(res) {}; }; class Hole { public: int start_time; // $gantt->[0]->[0] std::vector holestop; /* just for the first hole */ bool first_hole; std::vector all_inserted_resources; int minimum_hole_duration; // $gantt->[0]->[4] std::pair max_time_find_first_hole; Hole(int start) : start_time(start) {}; }; class Gantt { void initGantt(int, int); public: std::vector zero_vec; // ex-perl $gantt->[0]->[3]; std::vector holes; Gantt(int, int); Gantt(int max_resource_number, int minimum_hole_duration, int date, int duration, std::vector resources_vec); }; //int new_1_with_holes(a,b,c,d,e); int add_new_resources(Gantt *a, std::vector b); int set_occupation(Gantt *a, int b, int c, std::vector d); int get_free_resources(Gantt *gantt, int begin_date, int duration); int find_hole(Gantt *gantt, int begin_date, int duration); std::pair > find_first_hole(Gantt *gantt, int initial_time, int duration, std::vector tree_description_list, int timeout); int pretty_print(Gantt *a); unsigned int get_infinity_value(); } #endif oar-2.5.7/sources/extra/cpp-scheduler/Makefile0000644015014700017500000001736012677211234020741 0ustar neyronneyron############################################################################# # Makefile for building: Oar_sched_gantt_with_timesharing_and_fairsharing # Generated by qmake (2.01a) (Qt 4.4.3) on: lun. janv. 5 16:38:00 2009 # Project: oarsched.pro # Template: app # Command: /usr/bin/qmake-qt4 -unix -o Makefile oarsched.pro ############################################################################# ####### Compiler, tools and options CC = gcc CXX = g++ DEFINES = -DQT_SQL_LIB -DQT_CORE_LIB -DQT_SHARED CFLAGS = -pipe -g -D_REENTRANT -Wall -W $(DEFINES) CXXFLAGS = -pipe -g -D_REENTRANT -Wall -W $(DEFINES) INCPATH = -I/usr/share/qt4/mkspecs/linux-g++ -I. -I/usr/include/qt4/QtCore -I/usr/include/qt4/QtCore -I/usr/include/qt4/QtSql -I/usr/include/qt4/QtSql -I/usr/include/qt4 -I. -I. LINK = g++ LFLAGS = LIBS = $(SUBLIBS) -L/usr/lib -lQtSql -lQtCore -lpthread AR = ar cqs RANLIB = QMAKE = /usr/bin/qmake-qt4 TAR = tar -cf COMPRESS = gzip -9f COPY = cp -f SED = sed COPY_FILE = $(COPY) COPY_DIR = $(COPY) -r INSTALL_FILE = install -m 644 -p INSTALL_DIR = $(COPY_DIR) INSTALL_PROGRAM = install -m 755 -p DEL_FILE = rm -f SYMLINK = ln -sf DEL_DIR = rmdir MOVE = mv -f CHK_DIR_EXISTS= test -d MKDIR = mkdir -p ####### Output directory OBJECTS_DIR = ./ ####### Files SOURCES = Oar_iolib.cc \ Oar_conflib.cc \ Gantt_hole_storage.cc \ Oar_resource_tree.cc \ Oar_sched_gantt_with_timesharing_and_fairsharing.cc OBJECTS = Oar_iolib.o \ Oar_conflib.o \ Gantt_hole_storage.o \ Oar_resource_tree.o \ Oar_sched_gantt_with_timesharing_and_fairsharing.o DIST = /usr/share/qt4/mkspecs/common/g++.conf \ /usr/share/qt4/mkspecs/common/unix.conf \ /usr/share/qt4/mkspecs/common/linux.conf \ /usr/share/qt4/mkspecs/qconfig.pri \ /usr/share/qt4/mkspecs/features/qt_functions.prf \ /usr/share/qt4/mkspecs/features/qt_config.prf \ /usr/share/qt4/mkspecs/features/exclusive_builds.prf \ /usr/share/qt4/mkspecs/features/default_pre.prf \ /usr/share/qt4/mkspecs/features/debug.prf \ /usr/share/qt4/mkspecs/features/default_post.prf \ /usr/share/qt4/mkspecs/features/qt.prf \ /usr/share/qt4/mkspecs/features/unix/thread.prf \ /usr/share/qt4/mkspecs/features/moc.prf \ /usr/share/qt4/mkspecs/features/warn_on.prf \ /usr/share/qt4/mkspecs/features/resources.prf \ /usr/share/qt4/mkspecs/features/uic.prf \ /usr/share/qt4/mkspecs/features/yacc.prf \ /usr/share/qt4/mkspecs/features/lex.prf \ oarsched.pro QMAKE_TARGET = Oar_sched_gantt_with_timesharing_and_fairsharing DESTDIR = TARGET = Oar_sched_gantt_with_timesharing_and_fairsharing first: all ####### Implicit rules .SUFFIXES: .o .c .cpp .cc .cxx .C .cpp.o: $(CXX) -c $(CXXFLAGS) $(INCPATH) -o "$@" "$<" .cc.o: $(CXX) -c $(CXXFLAGS) $(INCPATH) -o "$@" "$<" .cxx.o: $(CXX) -c $(CXXFLAGS) $(INCPATH) -o "$@" "$<" .C.o: $(CXX) -c $(CXXFLAGS) $(INCPATH) -o "$@" "$<" .c.o: $(CC) -c $(CFLAGS) $(INCPATH) -o "$@" "$<" ####### Build rules all: Makefile $(TARGET) $(TARGET): $(OBJECTS) $(LINK) $(LFLAGS) -o $(TARGET) $(OBJECTS) $(OBJCOMP) $(LIBS) Makefile: oarsched.pro /usr/share/qt4/mkspecs/linux-g++/qmake.conf /usr/share/qt4/mkspecs/common/g++.conf \ /usr/share/qt4/mkspecs/common/unix.conf \ /usr/share/qt4/mkspecs/common/linux.conf \ /usr/share/qt4/mkspecs/qconfig.pri \ /usr/share/qt4/mkspecs/features/qt_functions.prf \ /usr/share/qt4/mkspecs/features/qt_config.prf \ /usr/share/qt4/mkspecs/features/exclusive_builds.prf \ /usr/share/qt4/mkspecs/features/default_pre.prf \ /usr/share/qt4/mkspecs/features/debug.prf \ /usr/share/qt4/mkspecs/features/default_post.prf \ /usr/share/qt4/mkspecs/features/qt.prf \ /usr/share/qt4/mkspecs/features/unix/thread.prf \ /usr/share/qt4/mkspecs/features/moc.prf \ /usr/share/qt4/mkspecs/features/warn_on.prf \ /usr/share/qt4/mkspecs/features/resources.prf \ /usr/share/qt4/mkspecs/features/uic.prf \ /usr/share/qt4/mkspecs/features/yacc.prf \ /usr/share/qt4/mkspecs/features/lex.prf \ /usr/lib/libQtSql.prl \ /usr/lib/libQtCore.prl $(QMAKE) -unix -o Makefile oarsched.pro /usr/share/qt4/mkspecs/common/g++.conf: /usr/share/qt4/mkspecs/common/unix.conf: /usr/share/qt4/mkspecs/common/linux.conf: /usr/share/qt4/mkspecs/qconfig.pri: /usr/share/qt4/mkspecs/features/qt_functions.prf: /usr/share/qt4/mkspecs/features/qt_config.prf: /usr/share/qt4/mkspecs/features/exclusive_builds.prf: /usr/share/qt4/mkspecs/features/default_pre.prf: /usr/share/qt4/mkspecs/features/debug.prf: /usr/share/qt4/mkspecs/features/default_post.prf: /usr/share/qt4/mkspecs/features/qt.prf: /usr/share/qt4/mkspecs/features/unix/thread.prf: /usr/share/qt4/mkspecs/features/moc.prf: /usr/share/qt4/mkspecs/features/warn_on.prf: /usr/share/qt4/mkspecs/features/resources.prf: /usr/share/qt4/mkspecs/features/uic.prf: /usr/share/qt4/mkspecs/features/yacc.prf: /usr/share/qt4/mkspecs/features/lex.prf: /usr/lib/libQtSql.prl: /usr/lib/libQtCore.prl: qmake: FORCE @$(QMAKE) -unix -o Makefile oarsched.pro dist: @$(CHK_DIR_EXISTS) .tmp/Oar_sched_gantt_with_timesharing_and_fairsharing1.0.0 || $(MKDIR) .tmp/Oar_sched_gantt_with_timesharing_and_fairsharing1.0.0 $(COPY_FILE) --parents $(SOURCES) $(DIST) .tmp/Oar_sched_gantt_with_timesharing_and_fairsharing1.0.0/ && $(COPY_FILE) --parents Gantt_hole_storage.H Oar_resource_tree.H .tmp/Oar_sched_gantt_with_timesharing_and_fairsharing1.0.0/ && $(COPY_FILE) --parents Oar_iolib.cc Oar_conflib.cc Gantt_hole_storage.cc Oar_resource_tree.cc Oar_sched_gantt_with_timesharing_and_fairsharing.cc .tmp/Oar_sched_gantt_with_timesharing_and_fairsharing1.0.0/ && (cd `dirname .tmp/Oar_sched_gantt_with_timesharing_and_fairsharing1.0.0` && $(TAR) Oar_sched_gantt_with_timesharing_and_fairsharing1.0.0.tar Oar_sched_gantt_with_timesharing_and_fairsharing1.0.0 && $(COMPRESS) Oar_sched_gantt_with_timesharing_and_fairsharing1.0.0.tar) && $(MOVE) `dirname .tmp/Oar_sched_gantt_with_timesharing_and_fairsharing1.0.0`/Oar_sched_gantt_with_timesharing_and_fairsharing1.0.0.tar.gz . && $(DEL_FILE) -r .tmp/Oar_sched_gantt_with_timesharing_and_fairsharing1.0.0 clean:compiler_clean -$(DEL_FILE) $(OBJECTS) -$(DEL_FILE) *~ core *.core ####### Sub-libraries distclean: clean -$(DEL_FILE) $(TARGET) -$(DEL_FILE) Makefile mocclean: compiler_moc_header_clean compiler_moc_source_clean mocables: compiler_moc_header_make_all compiler_moc_source_make_all compiler_moc_header_make_all: compiler_moc_header_clean: compiler_rcc_make_all: compiler_rcc_clean: compiler_image_collection_make_all: qmake_image_collection.cpp compiler_image_collection_clean: -$(DEL_FILE) qmake_image_collection.cpp compiler_moc_source_make_all: compiler_moc_source_clean: compiler_uic_make_all: compiler_uic_clean: compiler_yacc_decl_make_all: compiler_yacc_decl_clean: compiler_yacc_impl_make_all: compiler_yacc_impl_clean: compiler_lex_make_all: compiler_lex_clean: compiler_clean: ####### Compile Oar_iolib.o: Oar_iolib.cc Oar_resource_tree.H $(CXX) -c $(CXXFLAGS) $(INCPATH) -o Oar_iolib.o Oar_iolib.cc Oar_conflib.o: Oar_conflib.cc $(CXX) -c $(CXXFLAGS) $(INCPATH) -o Oar_conflib.o Oar_conflib.cc Gantt_hole_storage.o: Gantt_hole_storage.cc Gantt_hole_storage.H \ Oar_resource_tree.H $(CXX) -c $(CXXFLAGS) $(INCPATH) -o Gantt_hole_storage.o Gantt_hole_storage.cc Oar_resource_tree.o: Oar_resource_tree.cc Oar_resource_tree.H $(CXX) -c $(CXXFLAGS) $(INCPATH) -o Oar_resource_tree.o Oar_resource_tree.cc Oar_sched_gantt_with_timesharing_and_fairsharing.o: Oar_sched_gantt_with_timesharing_and_fairsharing.cc $(CXX) -c $(CXXFLAGS) $(INCPATH) -o Oar_sched_gantt_with_timesharing_and_fairsharing.o Oar_sched_gantt_with_timesharing_and_fairsharing.cc ####### Install install: FORCE uninstall: FORCE FORCE: oar-2.5.7/sources/extra/cpp-scheduler/Oar_conflib.H0000644015014700017500000000075512677211234021627 0ustar neyronneyron#ifndef OAR_CONFLIB_H #define OAR_CONFLIB_H #include namespace conflib { unsigned int init_conf (std::string file); std::string get_conf_with_default_param ( std::string key, std::string defval); std::string get_conf ( std::string key ); bool is_conf ( std::string key ); int dump_conf (); int reset_conf (); }; #define CONFDEFAULT_INT(x,y) ( atoi( get_conf_with_default_param(x, y).c_str()) ) #define CONFDEFAULT_STR(x,y) ( get_conf_with_default_param(x, y).c_str() ) #endif oar-2.5.7/sources/extra/cpp-scheduler/oarsched.pro0000644015014700017500000000051412677211234021604 0ustar neyronneyronCONFIG+=qt debug console QT-= gui QT+= sql SOURCES+=Oar_iolib.cc SOURCES+=Oar_conflib.cc SOURCES+=Gantt_hole_storage.cc SOURCES+=Oar_resource_tree.cc SOURCES+=Oar_sched_gantt_with_timesharing_and_fairsharing.cc HEADERS+=Gantt_hole_storage.H HEADERS+=Oar_resource_tree.H TARGET=Oar_sched_gantt_with_timesharing_and_fairsharing oar-2.5.7/sources/extra/cpp-scheduler/Oar_resource_tree.cc0000644015014700017500000007474512677211234023271 0ustar neyronneyron#include #include "Oar_resource_tree.H" namespace OAR::Schedulers::ResourceTree { // # $Id$ // package OAR::Schedulers::ResourceTree; // use warnings; // use strict; // use Data::Dumper; // use Storable qw(dclone); // use Time::HiRes qw(gettimeofday); // ############################################################################### // # RESOURCE TREE MANAGEMENT # // ############################################################################### // # Prototypes // sub new(); // sub clone($); // sub add_child($$$); // sub get_children_list($); // sub is_node_a_leaf($); // sub get_a_child($$); // sub get_father($); // sub get_current_resource_name($); // sub get_current_resource_value($); // sub get_current_children_number($); // sub get_current_level($); // sub get_max_available_children($); // sub set_needed_children_number($$); // sub get_needed_children_number($); // sub delete_subtree($); // sub get_previous_brother($); // sub get_next_brother($); // sub get_initial_child($); // ############################################################################### // sub get_tree_leafs($); // sub delete_tree_nodes_with_not_enough_resources($); // sub delete_unnecessary_subtrees($); // ############################################################################### // # Create a tree // # arg : number of needed children // # return the ref of the created tree // sub new(){ // my $needed_children_number = shift; // my $tree_ref; // $tree_ref->[0] = undef ; # father ref // $tree_ref->[1] = undef ; # ref of a hashtable with children // $tree_ref->[2] = undef ; # name of the resource // $tree_ref->[3] = undef ; # value of this resource // $tree_ref->[4] = 0 ; # level indicator // $tree_ref->[5] = 0 ; # needed children number : // # -1 means ALL (Alive + Absent + Suspected resources) // # -2 means BEST (Alive resources at the time) // $tree_ref->[6] = 0 ; # maximum available children // $tree_ref->[7] = undef ; # previous brother ref // $tree_ref->[8] = undef ; # next brother ref // $tree_ref->[9] = undef ; # first child ref // $tree_ref->[10] = 0 ; # current children number // return($tree_ref); // } /** c'est non trivial en c++ ? J'ai fait trivial : hypothese: c'est bien un arbre et pas un dag ! # clone the tree # arg : tree ref # return a copy of the tree ref */ static TreeNode *dclone(TreeNode *tree_ref) { int i; TreeNode *last_inserted_child = NULL; assert(tree_ref != 0); TreeNode *newnode = new TreeNode(tree_ref->needed_children_number); newnode->name = tree_ref->name; newnode->value = tree_ref->value; newnode->level = tree_ref->level; // pour chaque fils, creer un sous-arbre // et l'insérer comme fils dans le nouvel arbre TreeNode *current_child = tree_ref->first_child; assert( tree_ref->current_child_number == (int) tree_ref->children.size() ); for(i=0; i < tree_ref->current_child_number; i++, current_child = current_child->next_brother ) { assert( current_child != NULL ); TreeNode *newchild; newchild = dclone( current_child ); newchild->father = newnode; // on prend le name de chaque fils, et on l'insere la nouvelle ref newnode->children.insert( std::pair(current_child->value, newchild) ); if ( last_inserted_child == NULL ) { newnode->first_child = newchild; } else { newchild->prev_brother = last_inserted_child; last_inserted_child->next_brother = newchild; } last_inserted_child = newchild; newnode->current_child_number ++; } assert( newnode->current_child_number == tree_ref->current_child_number ); // std::cerr << "lvl :" << newnode->level << " newnode ch size :" // << newnode->children.size() << " tree_ref ch size :" // << tree_ref->children.size() << std::endl; assert( newnode->children.size() == tree_ref->children.size() ); return newnode; } TreeNode *clone(TreeNode *tree_ref) { if (tree_ref == NULL) return NULL; return ( dclone(tree_ref) ); } // # clone the tree // # arg : tree ref // # return a copy of the tree ref // sub clone($){ // my $tree_ref = shift; // return(dclone($tree_ref)); // } /** return 1 if node is a leaf (no child) otherwise retuurn 0 */ bool is_node_a_leaf(TreeNode *tree_ref){ if ( tree_ref->children.size() > 0 ) return false; else return true; } // # return 1 if node is a leaf (no child) // # otherwise retuurn 0 // sub is_node_a_leaf($){ // my $tree_ref = shift; // if (defined($tree_ref->[1])){ // return(0); // }else{ // return(1); // } // } /** add a child to the given tree ref (if child resource name is undef it seems that this child is a leaf of the tree) arg : tree ref, resource name, resource value return the ref of the child */ TreeNode *add_child(TreeNode *tree_ref, std::string resource_name, std::string resource_value) { TreeNode *tmp_ref; if ( tree_ref->children.find(resource_value) == tree_ref->children.end() ) { // Create a new tree node tmp_ref = new TreeNode(tree_ref, 0, resource_name, resource_value, tree_ref->level+1, 0, 0, NULL, NULL, NULL, 0 ); tree_ref->children.insert( std::pair(resource_value, tmp_ref) ); tree_ref->max_available_children++; tree_ref->current_child_number++; // Add new brother if (tree_ref->first_child != NULL) { tmp_ref->next_brother = tree_ref->first_child; tree_ref->first_child->prev_brother = tmp_ref; } tree_ref->first_child = tmp_ref; } else { tmp_ref = tree_ref->children.find(resource_value)->second; } return(tmp_ref); } // # add a child to the given tree ref (if child resource name is undef it seems // # that this child is a leaf of the tree) // # arg : tree ref, resource name, resource value // # return the ref of the child // sub add_child($$$){ // my $tree_ref = shift; // my $resource_name = shift; // my $resource_value = shift; // my $tmp_ref; // if (!defined($tree_ref->[1]->{$resource_value})){ // # Create a new tree node // $tmp_ref = [ $tree_ref, undef, $resource_name, $resource_value, $tree_ref->[4] + 1, 0, 0, undef, undef, undef, 0]; // $tree_ref->[1]->{$resource_value} = $tmp_ref; // $tree_ref->[6] = $tree_ref->[6] + 1; // $tree_ref->[10] = $tree_ref->[10] + 1; // # Add new brother // if (defined($tree_ref->[9])){ // $tmp_ref->[8] = $tree_ref->[9]; // $tree_ref->[9]->[7] = $tmp_ref; // } // $tree_ref->[9] = $tmp_ref; // }else{ // $tmp_ref = $tree_ref->[1]->{$resource_value}; // } // return($tmp_ref); // } /** Store information about the number of needed children */ int set_needed_children_number(TreeNode *tree_ref, int needed_children_number) { tree_ref->needed_children_number = needed_children_number; return needed_children_number; } // # Store information about the number of needed children // sub set_needed_children_number($$){ // my $tree_ref = shift; // my $needed_children_number = shift; // $tree_ref->[5] = $needed_children_number; // } /** Get previous brother on the same level for the same father */ TreeNode *get_previous_brother(TreeNode *tree_ref) { if ( tree_ref == NULL ) return NULL; else return tree_ref->prev_brother; } // # Get previous brother on the same level for the same father // sub get_previous_brother($){ // my $tree_ref = shift; // if (!defined($tree_ref)){ // return(undef); // }else{ // return($tree_ref->[7]); // } // } //# Get next brother on the same level for the same father TreeNode *get_next_brother(TreeNode *tree_ref) { if (tree_ref == NULL) return NULL; else return tree_ref->next_brother; } // # Get next brother on the same level for the same father // sub get_next_brother($){ // my $tree_ref = shift; // if (!defined($tree_ref)){ // return(undef); // }else{ // return($tree_ref->[8]); // } // } /** Get initial child ref */ TreeNode *get_initial_child(TreeNode *tree_ref) { if (tree_ref == NULL) return NULL; else return tree_ref->first_child; } // # Get initial child ref // sub get_initial_child($){ // my $tree_ref = shift; // if (!defined($tree_ref)){ // return(undef); // }else{ // return($tree_ref->[9]); // } // } /** Get a specific child arg : tree ref, name of a child return a ref of a tree */ TreeNode *get_a_child(TreeNode *tree_ref, std::string child_name) { std::map::iterator ch; if ( tree_ref == NULL || tree_ref->children.size() == 0 || (ch = tree_ref->children.find(child_name) ) == tree_ref->children.end() ) return NULL; else return ch->second; } // # Get a specific child // # arg : tree ref, name of a child // # return a ref of a tree // sub get_a_child($$){ // my $tree_ref = shift; // my $child_name = shift; // if (!defined($tree_ref) || !defined($tree_ref->[1]) || !defined($tree_ref->[1]->{$child_name})){ // return(undef); // }else{ // return($tree_ref->[1]->{$child_name}); // } // } /** Get the ref of the father tree arg : tree ref return a tree ref */ TreeNode *get_father(TreeNode *tree_ref) { if ( tree_ref == NULL || tree_ref->father == NULL ) return NULL; else return tree_ref->father; } // # Get the ref of the father tree // # arg : tree ref // # return a tree ref // sub get_father($){ // my $tree_ref = shift; // if (!defined($tree_ref) || !defined($tree_ref->[0])){ // return(undef); // }else{ // return($tree_ref->[0]); // } // } /** Get the current resource name arg : tree ref return the resource name */ std::string get_current_resource_name(TreeNode *tree_ref) { if (tree_ref == NULL || tree_ref->name == "" ) return ""; else return tree_ref->name; } // # Get the current resource name // # arg : tree ref // # return the resource name // sub get_current_resource_name($){ // my $tree_ref = shift; // if (!defined($tree_ref) || !defined($tree_ref->[2])){ // return(undef); // }else{ // return($tree_ref->[2]); // } // } /** Get the current resource value arg : tree ref return the resource value */ std::string get_current_resource_value(TreeNode *tree_ref) { if ( tree_ref == NULL || tree_ref->value == "" ) return ""; else return tree_ref->value; } // # Get the current resource value // # arg : tree ref // # return the resource value // sub get_current_resource_value($){ // my $tree_ref = shift; // if (!defined($tree_ref) || !defined($tree_ref->[3])){ // return(undef); // }else{ // return($tree_ref->[3]); // } // } /** Get the current children number arg : tree ref return the resource value */ int get_current_children_number(TreeNode *tree_ref) { if (tree_ref == NULL) // j'ai enleve le test non sens en C++ : // tree_ref->current_child_number est toujours definis return -1; else return tree_ref->current_child_number; } // # Get the current children number // # arg : tree ref // # return the resource value // sub get_current_children_number($){ // my $tree_ref = shift; // if (!defined($tree_ref) || !defined($tree_ref->[10])){ // return(undef); // }else{ // return($tree_ref->[10]); // } // } /** Get the current level indicator arg : tree ref return the level indicator */ int get_current_level(TreeNode *tree_ref) { if (tree_ref == NULL || tree_ref->level == 0) return 0; else return tree_ref->level; } // # Get the current level indicator // # arg : tree ref // # return the level indicator // sub get_current_level($){ // my $tree_ref = shift; // if (!defined($tree_ref) || !defined($tree_ref->[4])){ // return(0); // }else{ // return($tree_ref->[4]); // } // } /** Get the maximum available number of children (just after the creation of the tree) arg : tree ref return an integer >= 0 */ int get_max_available_children(TreeNode *tree_ref) { if ( tree_ref == NULL || tree_ref->max_available_children == 0 ) return 0; else return tree_ref->max_available_children; } // # Get the maximum available number of children // # (just after the creation of the tree) // # arg : tree ref // # return an integer >= 0 // sub get_max_available_children($){ // my $tree_ref = shift; // if (!defined($tree_ref) || !defined($tree_ref->[6])){ // return(0); // }else{ // return($tree_ref->[6]); // } // } /** Get the number of needed children arg : tree ref return the number of needed children */ int get_needed_children_number(TreeNode *tree_ref) { if ( tree_ref == NULL || tree_ref->needed_children_number == 0 ) return 0; else return tree_ref->needed_children_number; } // # Get the number of needed children // # arg : tree ref // # return the number of needed children // sub get_needed_children_number($){ // my $tree_ref = shift; // if (!defined($tree_ref) || !defined($tree_ref->[5])){ // return(0); // }else{ // return($tree_ref->[5]); // } // } /** Delete a subtree arg : tree ref to delete return father tree ref */ /** recursive delete of nodes, including Hypothesys: the graph is really a tree (a single path to a node) */ static void ddelete_subtree(TreeNode *tree_ref) { int i; TreeNode *current_child = get_initial_child( tree_ref ); TreeNode *next_child = 0; if (current_child != 0) next_child = get_next_brother( current_child ); for(i = 0; i < get_current_children_number( tree_ref ); i++, current_child = next_child) { assert(current_child != 0); get_next_brother( current_child ); ddelete_subtree( current_child ); } delete tree_ref; } TreeNode *delete_subtree(TreeNode *tree_ref) { if (tree_ref == NULL) return NULL; TreeNode *father_ref = tree_ref->father; TreeNode *prev_brother = tree_ref->prev_brother; TreeNode *next_brother = tree_ref->next_brother; if ( prev_brother == NULL ) { if (father_ref != NULL) { assert(father_ref->first_child == tree_ref); // BUG version PERL? father_ref->first_child = next_brother; } } else { prev_brother->next_brother = next_brother; } if ( next_brother != NULL ) { next_brother->prev_brother = prev_brother; } if (father_ref != NULL) // BUG PERL ? ne verifie pas si la reference est nulle if ( father_ref->children.size() > 0 ) { // s'effacer soit meme de la table assert( father_ref->children.find(tree_ref->value)->second == tree_ref); assert( father_ref->children.erase(tree_ref->value) ); // effacer les enfants et s'enlever de la mémoire soit meme ddelete_subtree(tree_ref); father_ref->current_child_number --; return father_ref; } return static_cast(0); } // # Delete a subtree // # arg : tree ref to delete // # return father tree ref // sub delete_subtree($){ // my $tree_ref = shift; // return(undef) if (!defined($tree_ref)); // my $father_ref = $tree_ref->[0]; // my $prev_brother = $tree_ref->[7]; // my $next_brother = $tree_ref->[8]; // if (!defined($prev_brother)){ // if (defined($father_ref)){ // $father_ref->[9] = $next_brother; // } // }else{ // $prev_brother->[8] = $next_brother; // } // if (defined($next_brother)){ // $next_brother->[7] = $prev_brother; // } // if (defined($father_ref->[1])){ // delete($father_ref->[1]->{$tree_ref->[3]}); // $father_ref->[10] = $father_ref->[10] - 1; // return($father_ref); // }else{ // return(undef); // } // } //############################################################################### /** # delete_tree_nodes_with_not_enough_resources # Delete subtrees that do not fit wanted resources # args: tree ref # side effect : modify tree data structure */ TreeNode *delete_tree_nodes_with_not_enough_resources(TreeNode *tree_ref) { //#print("START delete_tree_nodes_with_not_enough_resources\n"); //# Search if there are enough values for each resource //# Tremaux algorithm (Deep first) TreeNode *current_node = tree_ref; do { if ( (get_needed_children_number(current_node) > get_current_children_number(current_node) ) || ( (get_needed_children_number(current_node) == -1) // ALL && (get_max_available_children(current_node) > get_current_children_number(current_node))) || ( (get_needed_children_number(current_node) == -2) // BEST && (get_current_children_number(current_node) <= 0) ) ) { // we want to delete the root if (tree_ref == current_node) return NULL; // Delete sub tree that does not fit with wanted resources // print("DELETE ".get_current_resource_value($current_node)."\n"); current_node = delete_subtree(current_node); } if ( get_initial_child(current_node) != NULL) { // Go to child current_node = get_initial_child(current_node); //print("Go to CHILD =".get_current_resource_value($current_node)."\n"); } else { // Treate leaf while( (current_node != NULL) && ( (get_father(current_node) == 0) || (get_next_brother(current_node) == 0))) { // Step up //print("TOTO ".get_current_children_number($current_node)."\n"); //print("Go to FATHER : ".get_current_resource_value($current_node)."\n") if (defined(get_current_resource_value($current_node))); if ( (get_needed_children_number(current_node) > get_current_children_number(current_node) ) || ( (get_needed_children_number(current_node) == -1) // ALL && ( get_max_available_children(current_node) > get_current_children_number(current_node) ) ) || ( (get_needed_children_number(current_node) == -2) // BEST && (get_current_children_number(current_node) <= 0))) { // we want to delete the root if (tree_ref == current_node) return NULL; //print("DELETE 1".get_current_resource_value($current_node)."\n"); // Delete sub tree that does not fit with wanted resources current_node = delete_subtree(current_node); } else { current_node = get_father(current_node); } } if ((get_father(current_node) != NULL) && (get_next_brother(current_node) != NULL)) { // Treate brother TreeNode *brother_node = get_next_brother(current_node); if ((get_needed_children_number(current_node) > get_current_children_number(current_node)) || ((get_needed_children_number(current_node) == -1) // ALL && (get_max_available_children(current_node) > get_current_children_number(current_node))) || ((get_needed_children_number(current_node) == -2) // BEST && (get_current_children_number(current_node) <= 0))) { //print("DELETE 2".get_current_resource_value($current_node)."\n"); // Delete sub tree that does not fit with wanted resources delete_subtree(current_node); } current_node = brother_node; //print("Go to BROTHER : ".get_current_resource_value($current_node)."\n"); } } }while( (current_node != NULL) ); if ( (get_initial_child(tree_ref) == NULL) ) { return NULL; } else { return tree_ref; } } // # delete_tree_nodes_with_not_enough_resources // # Delete subtrees that do not fit wanted resources // # args: tree ref // # side effect : modify tree data structure // sub delete_tree_nodes_with_not_enough_resources($){ // my $tree_ref = shift; // #print("START delete_tree_nodes_with_not_enough_resources\n"); // # Search if there are enough values for each resource // # Tremaux algorithm (Deep first) // my $current_node = $tree_ref; // do{ // if ((get_needed_children_number($current_node) > get_current_children_number($current_node)) // or ((get_needed_children_number($current_node) == -1) # ALL // and (get_max_available_children($current_node) > get_current_children_number($current_node))) // or ((get_needed_children_number($current_node) == -2) # BEST // and (get_current_children_number($current_node) <= 0)) // ){ // # we want to delete the root // return(undef) if ($tree_ref == $current_node); // # Delete sub tree that does not fit with wanted resources // #print("DELETE ".get_current_resource_value($current_node)."\n"); // $current_node = delete_subtree($current_node); // } // if (defined(get_initial_child($current_node))){ // # Go to child // $current_node = get_initial_child($current_node); // #print("Go to CHILD =".get_current_resource_value($current_node)."\n"); // }else{ // # Treate leaf // while(defined($current_node) and (!defined(get_father($current_node)) or !defined(get_next_brother($current_node)))){ // # Step up // #print("TOTO ".get_current_children_number($current_node)."\n"); // #print("Go to FATHER : ".get_current_resource_value($current_node)."\n") if (defined(get_current_resource_value($current_node))); // if ((get_needed_children_number($current_node) > get_current_children_number($current_node)) // or ((get_needed_children_number($current_node) == -1) # ALL // and (get_max_available_children($current_node) > get_current_children_number($current_node))) // or ((get_needed_children_number($current_node) == -2) # BEST // and (get_current_children_number($current_node) <= 0)) // ){ // # we want to delete the root // return(undef) if ($tree_ref == $current_node); // #print("DELETE 1".get_current_resource_value($current_node)."\n"); // # Delete sub tree that does not fit with wanted resources // $current_node = delete_subtree($current_node); // }else{ // $current_node = get_father($current_node); // } // } // if (defined(get_father($current_node)) and defined(get_next_brother($current_node))){ // # Treate brother // my $brother_node = get_next_brother($current_node); // if ((get_needed_children_number($current_node) > get_current_children_number($current_node)) // or ((get_needed_children_number($current_node) == -1) # ALL // and (get_max_available_children($current_node) > get_current_children_number($current_node))) // or ((get_needed_children_number($current_node) == -2) # BEST // and (get_current_children_number($current_node) <= 0)) // ){ // #print("DELETE 2".get_current_resource_value($current_node)."\n"); // # Delete sub tree that does not fit with wanted resources // delete_subtree($current_node); // } // $current_node = $brother_node; // #print("Go to BROTHER : ".get_current_resource_value($current_node)."\n"); // } // } // }while(defined($current_node)); // if (!defined(get_initial_child($tree_ref))){ // return(undef); // }else{ // return($tree_ref); // } // } /** # get_tree_leaf # return a list of tree leaf # arg: tree ref */ std::vectorget_tree_leafs(TreeNode *tree) { std::vector result; if (tree == NULL) return result; // Search leafs // Tremaux algorithm (Deep first) TreeNode *current_node = tree; do { if ( (get_initial_child(current_node) != NULL) ) { // Go to child current_node = get_initial_child(current_node); //print("Go to CHILD =".get_current_resource_value($current_node)."\n"); } else { // Treate leaf if ( is_node_a_leaf(current_node) == true) { //push(@result, $node_name_pile[0]); result.push_back(current_node); //print("Leaf: ".get_current_resource_value($current_node)."\n"); } // Look at brothers while( (current_node != NULL) && ( (get_father(current_node) == NULL) || (get_next_brother(current_node) == NULL))) { // Step up current_node = get_father(current_node); //print("Go to FATHER : ".get_current_resource_value($current_node)."\n") if (defined(get_current_resource_value($current_node))); } if ( (get_father(current_node) != NULL) && (get_next_brother(current_node) != NULL)) { // Treate brother current_node = get_next_brother(current_node); //print("Go to BROTHER : ".get_current_resource_value($current_node)."\n"); } } } while( (current_node != NULL) ); return result; } // # get_tree_leaf // # return a list of tree leaf // # arg: tree ref // sub get_tree_leafs($){ // my $tree = shift; // my @result; // return(@result) if (!defined($tree)); // # Search leafs // # Tremaux algorithm (Deep first) // my $current_node = $tree; // do{ // if (defined(get_initial_child($current_node))){ // # Go to child // $current_node = get_initial_child($current_node); // #print("Go to CHILD =".get_current_resource_value($current_node)."\n"); // }else{ // # Treate leaf // if (is_node_a_leaf($current_node) == 1){ // #push(@result, $node_name_pile[0]); // push(@result, $current_node); // #print("Leaf: ".get_current_resource_value($current_node)."\n"); // } // # Look at brothers // while(defined($current_node) and (!defined(get_father($current_node)) or !defined(get_next_brother($current_node)))){ // # Step up // $current_node = get_father($current_node); // #print("Go to FATHER : ".get_current_resource_value($current_node)."\n") if (defined(get_current_resource_value($current_node))); // } // if (defined(get_father($current_node)) and defined(get_next_brother($current_node))){ // # Treate brother // $current_node = get_next_brother($current_node); // #print("Go to BROTHER : ".get_current_resource_value($current_node)."\n"); // } // } // }while(defined($current_node)); // return(@result); // } /** # delete_unnecessary_subtrees # Delete subtrees that are not necessary (watch needed_children_number) # args: tree ref # side effect : modify tree data structure */ TreeNode *delete_unnecessary_subtrees(TreeNode *tree_ref) { if (tree_ref == NULL) return tree_ref; // Search if there are enough values for each resource // Tremaux algorithm (Deep first) TreeNode *current_node = tree_ref; do { if ( (get_needed_children_number(current_node) >= 0) && (get_needed_children_number(current_node) < (get_current_children_number(current_node)))) { // Delete extra sub tree delete_subtree(get_initial_child(current_node)); } else { if ( (get_initial_child(current_node)) != NULL ) { // Go to child current_node = get_initial_child(current_node); //#print("Go to CHILD =".get_current_resource_value($current_node)."\n"); } else { // Look at brothers while( (current_node != NULL) && ( (get_father(current_node) == NULL) || (get_next_brother(current_node) == NULL))) { // Step up current_node = get_father(current_node); //print("Go to FATHER : ".get_current_resource_value($current_node)."\n") if (defined(get_current_resource_value($current_node))); } if ( (get_father(current_node) != NULL) && (get_next_brother(current_node) != NULL) ) { // Treate brother current_node = get_next_brother(current_node); //print("Go to BROTHER : ".get_current_resource_value($current_node)."\n"); } } } } while( (current_node != NULL) ); return tree_ref; } // # delete_unnecessary_subtrees // # Delete subtrees that are not necessary (watch needed_children_number) // # args: tree ref // # side effect : modify tree data structure // sub delete_unnecessary_subtrees($){ // my $tree_ref = shift; // return($tree_ref) if (!defined($tree_ref)); // # Search if there are enough values for each resource // # Tremaux algorithm (Deep first) // my $current_node = $tree_ref; // do{ // if ((get_needed_children_number($current_node) >= 0) and (get_needed_children_number($current_node) < (get_current_children_number($current_node)))){ // # Delete extra sub tree // delete_subtree(get_initial_child($current_node)); // }else{ // if (defined(get_initial_child($current_node))){ // # Go to child // $current_node = get_initial_child($current_node); // #print("Go to CHILD =".get_current_resource_value($current_node)."\n"); // }else{ // # Look at brothers // while(defined($current_node) and (!defined(get_father($current_node)) or !defined(get_next_brother($current_node)))){ // # Step up // $current_node = get_father($current_node); // #print("Go to FATHER : ".get_current_resource_value($current_node)."\n") if (defined(get_current_resource_value($current_node))); // } // if (defined(get_father($current_node)) and defined(get_next_brother($current_node))){ // # Treate brother // $current_node = get_next_brother($current_node); // #print("Go to BROTHER : ".get_current_resource_value($current_node)."\n"); // } // } // } // }while(defined($current_node)); // return($tree_ref); // } //return 1; } oar-2.5.7/sources/extra/black-maria/0000755015014700017500000000000012677211234016677 5ustar neyronneyronoar-2.5.7/sources/extra/black-maria/black-maria-sync.lua0000644015014700017500000000602712677211234022524 0ustar neyronneyronrequire "oar" require "copas" oar.conf_load() oar.connect() if not oar.conf["BKM_SYNC_PORT"] then bkm_sync_port = 2220 else bkm_sync_port = oar.conf["BKM_SYNC_PORT"] end -- -- Transform a compact node list as use in Slurm to list of individual nodes -- ex: nodes[23,45,50-52] -> {nodes23, node45, node50, node51, node52} -- TODO: this funcion must be move to an helper library -- TODO: support different named nodes function flatten_nodelist(nodelist_compact) x,y,node,desc = nodelist_compact:find("^(%S+)%[(%S+)%]") if not x then -- only one node return {nodelist_compact} end d = oar.tsplit(desc:gsub(","," ")) local nodelist = {} for i,n in ipairs(d) do x,y, b,e = n:find("(%d+)-(%d+)") if x then for i=b,e,1 do nodelist[#nodelist+1]=node..i end else nodelist[#nodelist+1]=node..n end end return nodelist end function notify_almighty() local client = socket.connect(oar.conf["SERVER_HOSTNAME"],oar.conf["SERVER_PORT"]) client:send("Scheduling\n") client:close() end function handler(c, host, port) local peer = host .. ":" .. port print("BKM-sync: connection from", peer) -- c:send("Hello\r\n") -- get data local data = (c:receive"*l") print("data from", peer, data) assert(loadstring("job_info =" .. data))() dumptable(job_info) print(job_info.node_list) -- read RJMS' node file and build resource id list -- TODO: SLURM_JOB_NODELIST= lx[15,18,32-33] -> use flatten_nodelist resource_ids = {} k = 1 -- convert node_list or node_file allocated and given by foreign RJMS to OAR's resource id list -- TODO need to uniq the node_file if job_info.node_list=='' then local f = assert(io.open(job_info.node_file, "r")) for line in f:lines() do print(line) for i,r_id in ipairs(nodes_resources_ids[line]) do resource_ids[k]=r_id k = k + 1 end end else print("BKM-sync: dump flatten_nodellist") dumptable(flatten_nodelist(job_info.node_list)) for i, node in ipairs(flatten_nodelist(job_info.node_list)) do print("BKM-sync: allocated node:"..node) for i,r_id in ipairs(nodes_resources_ids[node]) do resource_ids[k]=r_id k = k + 1 end end end print("BKM-sync: dump resource_ids") dumptable(resource_ids) oar.save_assignements_black_maria(job_info.moldable_j_id,resource_ids) -- update job's state to Running and set assigned_moldable_job field oar.sql("UPDATE jobs SET state = ".."'Running'".. ",assigned_moldable_job = ".. job_info.moldable_j_id.. " WHERE job_id = ".. job_info.j_id) -- notify almighy (schedule cycle ? will update Gantt Diagram ??) notify_almighty() -- notifiy for external tools ? end -- -- main -- -- retreive resource_ids by node nodes_resources_ids = oar.get_nodes_resources_black_maria() dumptable(nodes_resources_ids) -- add tcp server copas.addserver(assert(socket.bind("*",bkm_sync_port)), function(c) return handler(copas.wrap(c), c:getpeername()) end ) -- launch server copas.loop() oar-2.5.7/sources/extra/black-maria/black-maria-sched.lua0000644015014700017500000000503212677211234022631 0ustar neyronneyronrequire "oar" oar.conf_load() oar.connect() submitted_jobs = {} if not oar.conf["BKM_SYNC_HOST"] then bkm_sync_host = oar.conf["SERVER_HOSTNAME"] else bkm_sync_host = oar.conf["BKM_SYNC_HOST"] end if not oar.conf["BKM_SYNC_PORT"] then bkm_sync_port = 2220 else bkm_sync_port = oar.conf["BKM_SYNC_PORT"] end -- index correspondance for job's attributs in return of get_waiting_jobs_black_maria function j_id= 1 walltime = 2 nb_res = 6 modalble_id = 4 user = 7 -- Submit job on foreign LRMS -- Jobs are submitted sequentially. It's made the assumption that there not a lot of these kind of job at a given time. -- TODO: a connector for each supported JRMS (priority to SLURM) function submit_to_jrms(jobs_to_launch) local job_ids = {} -- TODO must add oardodo user local submit_cmd_part1 = " sbatch_oardodo --workdir=/tmp/ -n" local submit_cmd_part2 = " black-maria-pilot.sh " for i,job in ipairs(jobs_to_launch) do local oardodo = "export OARDO_BECOME_USER="..job[user].."; oardodo " job_ids[i] = job[j_id] print("BKM: submit job to LRMS") local nb_nodes = job[nb_res] if oar.conf["BKM_RESOURCE_FACTOR"] then nb_nodes = nb_nodes / oar.conf["BKM_RESOURCE_FACTOR"] end local cmd = oardodo .. submit_cmd_part1 .. nb_nodes .. " -t " .. job[walltime]/60 .. ":10" .. -- TODO adapt for each RJMSand parametrize timeguard 10 seconds here submit_cmd_part2 .. bkm_sync_host .. " " .. bkm_sync_port .. " " .. job[j_id] .." " .. job[modalble_id] .. " " .. job[walltime] -- cmd = "export OARDO_BECOME_USER=kameleon; oardodo yop1" print("BKM: " .. cmd) f = assert (io.popen (cmd)) -- TODO retrieve the exist status value for line in f:lines() do print(line) -- retrieve foreign_jobid -- sbatch: Submitted batch job 469 b,i,jid_jrms = line:find("sbatch.*%s(%d+)$") if b then print("Prout:" .. jid_jrms) -- save serialize job info ( break end end end -- update scheduler_info jobs' field to not to resubmit in next cycle -- TODO: build job_ids -- oar.set_scheduler_message_range(job_ids,"submitted to JRMS") end -- -- main -- queue = "default" if arg[1] then queue = arg[1] end print("BKM-sched launched with queue: "..queue) waiting_jobs = oar.get_waiting_jobs_black_maria(queue) dumptable(waiting_jobs) if #waiting_jobs>0 then submit_to_jrms(waiting_jobs) else print("BKM-sched: nothing to do") end oar-2.5.7/sources/extra/black-maria/black-maria.rst0000644015014700017500000000277612677211234021610 0ustar neyronneyron======================================= Black-Maria: a coupling with other JRMS ======================================= Black-Maria (BKM) is an extension to couple foreign resource and job management system (RJMS) with OAR. BKM is primarly developed to meet the needs of ANR-SPADES project. Principle: ---------- Workflow 1) submission to oar to a specific queue 2) oar metascheduler launch black-maria-sched 3) black-maria-sched submit to foreign RJMS and set parameter for black_maria_pilot.sh 4) black_maria_pilot.sh is launched when foreign RJMS started job 5) black_maria_pilot.sh signals black-maria-synch daemon (throught tcp via nc) 6) black-maria-synch set node allocated by foreign RJMS in oar's db and signal Almigthy (OAR?) 7) black_maria_pilot.sh sleep (default oar walltime minus a timeguard) Limitations: ------------ * Only Slurm is supported as foreign RJMS (04/03/11) * Walltime must be expressed in second Dependencies: ------------- * lua: 5.1 or higher * lua libraries: liblua5.1-copas0 blua5.1-coxpcall0 liblua5.1-sql-mysql-2 * nc for bkm-pilot script to communicate to bkm-synch (not secure !!!) Installation: ------------- * see black-maria-test.rst Running: -------- * see black-maria-test.rst Todo: ----- * an alpha version ;) * more RJMS connector * support node nodelist with slurm node list grammar ex: dev[0-8,12,13,18-25] * recette/makefile installation Comments, bugs, request: ------------------------ * Caution it's a prototype and only developed for experimentation purpose Log: ---- oar-2.5.7/sources/extra/black-maria/black-maria-pilot.sh0000644015014700017500000000102212677211234022516 0ustar neyronneyron#!/bin/bash BKM_SYNC_HOST=$1 BKM_SYNC_PORT=$2 OAR_JOB_ID=$3 OAR_MOLDABLE_JOB_ID=$4 WALLTIME=$5 echo "BKM-pilot args:" $@ echo "BKM-pilot SLURM_NODELIST: " $SLURM_NODELIST #TODO switch case depending of foreign rjms NODE_FILE= NODE_LIST=$SLURM_NODELIST # # notify black-maria-sync daemon # BKM_SYNC_DATA="{j_id=$OAR_JOB_ID, moldable_j_id=$OAR_MOLDABLE_JOB_ID, node_file='$NODE_FILE', node_list='$NODE_LIST'}" echo $BKM_SYNC_DATA echo $BKM_SYNC_DATA | nc $BKM_SYNC_HOST $BKM_SYNC_PORT # time to sleep sleep $WALLTIME sleep 2 oar-2.5.7/sources/extra/black-maria/black-maria-test.rst0000644015014700017500000001115112677211234022550 0ustar neyronneyron================== Black-Maria Test ================== Some tests conduct with oar_slurm an BKM locale: Cannot set LC_ALL to default locale: No such file or directory sudo dpkg-reconfigure locales en_US.UTF-8 locale-gen en_US.UTF-8 (a test pour le mode batch???) copy des clés (?) mkdir .ssh scp -P 2222 ~/.ssh/id_rsa.pub root@localhost:/root/.ssh/authorized_keys Install BKM =========== Get oar source --------------- apt-get install subversion svn checkout svn://scm.gforge.inria.fr/svn/oar/trunk cd ~/prog/oar/trunk/modules/scheduler scp -P 2222 -r black-maria root@localhost:/root apt-get install phpmyadmin apt-get install lua5.1 liblua5.1-copas0 blua5.1-coxpcall0 liblua5.1-sql-mysql-2 echo "lua /root/black-maria/black-maria-sched.lua \$1" > /usr/lib/oar/schedulers/black-maria-sched ln -s /root/black-maria/oar.lua /usr/share/lua/5.1/ ln -s /root/black-maria/black-maria-pilot.sh /bin/ chmod 755 /usr/lib/oar/schedulers/black-maria-sched chmod 755 /root *IMPORTANT* oardodo est sensible ! ln -s /usr/local/bin/sbatch /usr/bin/sbatch_oardodo #sync from external black-maria rsync -avL . kam:gvim /root/black-maria/ # install new oar queue (spades for instance) oarnotify --add_queue "spades,5,black-maria-sched" Multiple slurmd support: slurm must be recompiled with "--enable-multiple-slurmd" parameter at configure step. For more information, see: https://computing.llnl.gov/linux/slurm/programmer_guide.html (realized in kameleon's slurm step kameleon/steps/slurm) Running and helpers: ==================== Launch BKM-sync: ---------------- sudo -iu oar lua /root/black-maria/black-maria-sync.lua Launch manually for test purpose BKM-sched ------------------------------------------- sudo -iu oar /usr/lib/oar/schedulers/black-maria-sched spades Truncate jobs ------------- ~/trunk/modules/scheduler/ocaml-schedulers/test# irb -r oar_db_setting.rb irb(main):001:0> oar_truncate_jobs Oarsub w/o container -------------------- oarsub -q spades -l nodes=1,walltime=00:1:00 fo test oarsub container ---------------------- oarsub -t container -l nodes=1,walltime=00:10:00 "sleep 500" [ADMISSION RULE] Modify resource description with type constraints OAR_JOB_ID=1 oarsub -t inner=1 -l nodes=1,walltime=00:8:00 "sleep 200" Oarsub simple cycle: -------------------- oarsub -t container -q spades -l nodes=1,walltime=00:10:00 foo oarsub -t inner=1 -l nodes=1,walltime=00:6:00 "sleep 200" Slurm commandes: ---------------- sinfo, squeue, scancel scancel -p test cancel all job from test partition Logs tests: =========== next ---- doc / install log message multiple nodes 06/03/11 -------- simple oarsub cycle ok: oarsub -t container -q spades -l nodes=1,walltime=00:10:00 foo oarsub -t inner=1 -l nodes=1,walltime=00:6:00 "sleep 200" kameleon@kameleon:~$ squeue JOBID PARTITION NAME USER ST TIME NODES NODELIST(REASON) 138 test black-ma kameleon R 4:20 1 node1 kameleon@kameleon:~$ oarstat Job id Name User Submission Date S Queue ---------- -------------- -------------- ------------------- - ---------- 1 kameleon 2011-03-06 18:21:35 R spades 2 kameleon 2011-03-06 18:22:12 R default 05/03/11 -------- * Besoin de vider la table job OAR:... en lua ??? -> non utilisation deruby * faire test cyle complet * 02/03/11 -------- * ./kvm-tcp oar-slurm-v2.raw Notes: kvm-tcp -> sudo kvm -m 512 -redir tcp:2222::22 $1 oarsub -I sinfo OK 17/10/10 -------- * test oar_slurm.raw * user/pwd: root/kameleon * fix locales * test: oarsub -I OK * test: slurmmeleon@kameleon:~$ sinfo PARTITION AVAIL TIMELIMIT NODES STATE NODELIST local* up infinite 1 idle kameleon kameleon@kameleon:~$ squeue JOBID PARTITION NAME USER ST TIME NODES NODELIST(REASON) kameleon@kameleon:~$ scontrol show partition PartitionName=local AllocNodes=ALL AllowGroups=ALL Default=YES DefaultTime=NONE DisableRootJobs=NO Hidden=NO MaxNodes=UNLIMITED MaxTime=UNLIMITED MinNodes=1 Nodes=kameleon Priority=1 RootOnly=NO Shared=NO State=UP TotalCPUs=2 TotalNodes=1 kameleon@kameleon:~$ scontrol show node NodeName=kameleon Arch=i686 CoresPerSocket=2 CPUAlloc=0 CPUErr=0 CPUTot=2 Features=(null) OS=Linux RealMemory=2000 Sockets=1 State=IDLE ThreadsPerCore=1 TmpDisk=0 Weight=1 Reason=(null) To update node when it's in down state scontrol update NodeName=kameleon State=RESUME SLURM_JOB_NODELIST is the list of allocated node in condensed format exemple lx[15,18,32-33] dev[0-8,18-25],edev[0-25] ??? is this possible ??? "rack[0-63]_blade[0-41]" => valid but we doesn't support it in BKM oar-2.5.7/sources/extra/black-maria/sbatch0000755015014700017500000000015712677211234020074 0ustar neyronneyron#!/bin/bash echo "FAKE sbatch Slurm command" echo "ARGS:" $@ echo "sbatch: Submitted batch job " $RANDOM oar-2.5.7/sources/api/0000755015014700017500000000000012677211234014162 5ustar neyronneyronoar-2.5.7/sources/api/livecd_snapshot2.png0000644015014700017500000020012512677211234020137 0ustar neyronneyron‰PNG  IHDRÉŠBX pHYsëëqÍ• IDATxœìÝ}Œå/ú¯WÅÕSGÍUõѬÔ™Õ´E"Ú(3†3 WÇãÃj“èÄ@$lÈjm’ÕÆdWY›m€D»à6ØŠ²ÁDwŽ’€‘Àv¢LVÉ2DK2F ÌDÜ(Xnë`©[btªtÝJ=%ùþQÝÕÕõÖÕÕoÕÕßZ¤¦¦^žîžÀïW¿ç """"¢©·À•+WÆÝ """""ÃsðØ÷žPìjÕêx[CDDDDDc¤¸8ö£Ã¸ÇÑ9^«Vw}óô0.NDDDD”r/ÿÃHlý—ã‡ÿæà [Ô¼²»< ø=Øû­¾º `×7O—þ|(ˆˆˆ(åö=_}æ.½Ûëo­ÛCŠÒÝþÈi»lê—õ¦ôÚµ¦÷«MïU«ï;W9w®rîÜ[çÖßZ_ßX_ßX_}}íõµµ³kk¯®­½º «yÙ%`qƒÜà7zØHÛ+% 7¸Á nLÖ†7ؾl¶ÃìfŒ]«¾ßŒ±Ï½×°Ýç)JJ Zdó-HÈæ™–³ÌÖÿ”ÎmÜ¿RÑ«ÿ~–ä7¸Á nÄß|½ôÕý ÛïüʤgØž[§äcá7¸ÁÉÚ舲íèÚ¿ÑL!ÌÖ†ôÇîÈÒÍY‰ìÞEǾsôè¿7MÓw›æ¶´ä¶?Ùvá»Ѧ…oÿø;¿{'à` €”,í\Úþ…£¥O|gDDÔ“—¾”°û_uÿž_yNñüʳÓnØÕˆˆ¨W¦Q{æ.Õ¶õ˺-ÛaóG>òç° ¿Çt‚j«™3Ìß4øoFGé½ù»7££t' hÏJäp?XØö'ÛlÛ¶íÂï/˜ÀÇ·ÀÇ?ññ7×ß´ˆLD3""êÁK_*Øý¯5gÏî­½ô¥âK_Ê»v†þûÖ9̾NÐñþsùoo"¢êÌ .üï í`ûcÛÞ9÷Ž;+žjCH”u/Ä* ¸+‘|´„¼pႽ½ícÛ>þ±ÛÛoþîÍö1þ{·Z°ó†b³¯7¸Á np#ö†÷åü‹>pgào[ûw?QkÿÖùáWºZJ>npƒܘ¬ \ _V`Zæ;çÞùøö·³øû …Fé.\¸ðû ~ÿÎ;çÞyçÜ;ïüî˜Qº#¨+ÑeÝ93°T±mÛ6çüw~÷NGÓ=[°tëÒö/-ÜxGýÓ…ïÀ npƒ܈¿á¶ú7%KÿR Üio¸ÙGàüè9&ú^cÿ4¸Á npc"7¤ét%ª}P³ƒä|ä#ÍÇîÌÖЂfgW8½xËb³+Qx”n÷ëñ븢twW¢€Ä Ùí €%ï½ícíwô[jeN¿%ûMî¾u·6—ˆˆâ‹“øCù° Yb@DD=s'µfýö#ò{쮓HÈŸØñæ¾Ù §-rñ–%;1ˆˆÒÝîÝš‰Ax”ÞmŒAû6ÜY€ŸØÑNDœ7Þ¾ŽÙ.RXfä§EDD±þÕÙöï[÷þ8ÛÑW#"¢Ä\óMCÔ ß.@­³Zçz]¸pÁŸÄÒ["§+ ïDd÷[²·wÌïp7Ô=²Áý“å…íö{æ7¸Á nÄßð¼–¾}Àêßµ»úwÛ,}û,×9ôî`b@DDDD7šQ “”µÁ»ÀõjҳĩÜùù;#~{ê¹S]¯@D„Ö¿Lúù—FÿW˜”›Qª„ý{€ÿ~ Ç$fÒWGaÅ€ˆàÎÏßý€¢ñ$Ê<ÏÿÇ»ü_ÞêýEc%#_]ÏÍ@V&D42§ž;ÅçjD4‰œw9É€³1°­qÔçÄêšHHiù²‚΄Є4ícs®IºöH˜Í¬ 0ÛŒÌ óÏ0ìžÇˆÒÏSé,|{þSçþ­ûÿæþÿ4:û#þmxkÿñaMòÿ*BœÖvm›ÿÇ®w ûýTô~"J-ç_tÉþíDYÖõ·b‚Ù:¦òîZ^Ë×.éa·9”fçÃï9-i·¬ÌO‰2ÏþÙŸ¿Óù¯šÿ¿da¿ŠåýÇ»t¶í[G4Ϙg;ú 1[› mawñ·-ðô' þÛ1ª š ž‡ þÿo¯]‰ÁV«+ô˜¬¿½ @6àä³'bÜàÄÞ»÷73„>³ß‘ü³"Ê>'7@ïOß=‘®ûÇþÿ£v…WîÚÚAà5™Qrщã»qñw ?`ýíÕ¼–—˜ù@›}üÂÍ•åÛöÙ{bN@€8DS+æs¯±ôŒsÓ^{ »PM-ÿàãô¦÷ý efl˜˜´qøëo¯ÊŽýàXâ»}íìÙ×Î.ܼ°tÛžÀxötÍ À/Ÿˆ¢þ?{ÑÝô£ »µý´ˆ&šg´±3Þ ½¹Ab]“ ºÎAäú±ziãÄz«„±Óƒ½wï/][ŽhRœ¬œ•ˆhv¾·{ÆGÌäײַª8ØÓþ¶6Uo“ˆÒÀ?ÑT? फ~½dk¯­{,y¡ ÐÉgO¬þòLà›sµÄ/VÒ7ôDYáÎ Ü‘»ŒÎÁ UõÀsÓÄ'öÔÚ˜7ízXà§í>=~“ˆ(mü“0@" ç¬ ×1}í,€RÉW7г%KmpåÊ•Zµzì;G}ï‰+W®œ~þtâ6|þä™çÏôy"""¢ÑHc_äÿü`ò Ã*€3?=nYÁ3Ï·Ã÷þí½{qkÞ½G7ô¼–¬EúûG<-±UÞª¬üÛÉC_ùò¡¯¶ KDDDD”S0ºë¸‚AeŠ[óG¿}Ô¿_7ôàÑ ÝfMµMÈ'MDDDDÓiæf ^² ¥zicàã =õ¯OÌ’˜¾y“ÒñY%§1ä€WÂŒnÆh²Û3'ŸBôZi!Y8+eÙ¸²‚Öε×V‡ÛŸC ý]xV€Àêäó'ûoÐ@.BDDD4z c2Årn™˜Cš†(ÂüÜüÞ»÷Ü72+€ÿsÚ²eKÿ­ÈEˆˆˆˆFaLEôóFÎàÊ 6^[ º;ôÀÁÀ‘fäšÞãÉuÌÑ{ß_L佞wADDD42>M©×¬ŽíÑ— lósó 7/´çAŠ‘ ú“¸ï/î|ówÖÀÚñ‰mÌ ˆˆˆˆh¤\ÑvDÑ(•ÊÍÄ ^V€ˆÄ`r³oþîs""¢Höt|áÓ ¾x(«¡ %'(#ø²‚7ÆÓÈæîM'+@Ø›žè¬ÀÆÜ€ˆˆ(ÞüÝ…û¿¼Ï¿³×ë¤ù"4uüµ Õje\Íq‹™ 01È@V`cn@DD4…¿Œû_ÛúÙÿž&@Ç)e¸Ôqósó‡8Ô±„B·5¸ŽM‹• #8…2ÅŠñjqg©²þ±W>&""¢~ ¶0ÿ‰më®Î óŸØ`½ïî ‰Cü• ËŸ©÷ywʼIÏ 31Øñ‰mþƒên´ãÛ_ÊnX6:>M®ñbدT¡:ÛBˆOýé§â\ÐÉ æ[Aˆ'[èUŸþ™P´IÌ ¤oÞ¤X‰y÷ă=Š`Ü­ """Üþg·»ÓO>àü3Žõß]˜ÿÄ6O&0ƬÀ¹s $‘ì½{qk^7ô¼ðO΀½wïM~§¬ièJ”ªLƒˆˆˆ’yñ/:¹“!œ| ~bàpÊcÏ œKÅÌ Ï`ßógDãšô˜'·æ~ûè@š%<+@Ÿ‰ûi½ßÛ%g¿»Ô€Ö~w&àé }ºg'¥*TO&àÎò®2B4»hàl'nÏÀ‡»n ™L¢¾³‚‰Ì ÐObàñݹÿ'+ðï »¬ÿxÿ}‰ˆˆhìT¡îúvýæ?cÿèI šù@ï[âÑCšPˆ}ЍCV² cºÒ>£vÿéLˆˆˆRNñ›ÿüÝqHÓ4{#/Tû!šŠbçóÏ ç )Rø>ì¬@öò¢Ôqe 7/Œ¯Ð^Ä 0+ìt¥]þpæ¢\‡ˆˆˆ†Áô«Š*”Ž_ U=P¯ŠÛ•ÈæîP”¬n°ü™ú`멪°ÓQê¸Bm Y*•Ç»ÆYS¼¬}&£y–8,ˆˆˆÒCáÎDNsB !D¯ù€{á‚Tå©Ê †Á‰™r$Ñ™(_?œWsí°§=m!Ö•ˆñ:ÑÔÊ U(€"§ÙYA³7ÑÕù^³[àD¥‰G!$ OaV0¤žEÌ ’ðecW»¤Û1³ôS1ðŒŽS=ð㜽NYØb1O'""¢¡ëœ–4Y2àð'ý/{ÜgÝ …YA ¤ž‹0Oè.0+°`ïÝûO>;†¢ÁúÆzð}#F÷–x‚ïø…ÝûÝSż~àe™ ¥„]è3¶Ä¹A’¬ 0üÿòQIØq.ÓƒPáYÆ×›èþ/ß°·ÛtIƒŸ•ˆˆˆˆ¦Íý¿ÿëù¿þË–ÆÛÎ!þ kVŒWZq¢¤®üY½½÷îý#nÉúÆzÀ çÓªNfêJDDD©Áþ Eç©ܦ¶°–(_7ê¢Á±ÇŽ{we¦g_êÿ¾ˆˆˆ(Å>½pÿ—÷ñ"£0 Q›¿b0 ©‚˜¸<øùæ£i̾½¼£ âe˜Œ?1"""J«_<Ä‹ŒHD1¡k@çœ}dØ-úÒ¹(ÍÙE׬ÀÁG“þÚáîcC²ø¿çûþâNëƒh[*Øïˆˆˆˆ(³bNyV0(ÙEº²… §ò3`ð¡‚“Ͻwïí³ ëëí¥ŽÃ„gðÕOþèTŸmJ•Œ½"""J¿ô>”ô¯)úë§1à¤"Ƹ^Gí’þÌɧ{ëë;æwt9(2+€ÿÏASàäó'÷Þµ7Î?Üq×ý¼ """¢,¹ï/ÆÝ‚ÁšðñÐC×KVàä³'N>{âÍõ7ççæÕ„€q~þ¬À×Nït¥w~þÎ;?g̬àäó'ïü|*rb{ú³qM‚6Œ»gïQê¤~šÔan¤Ö‡ýl~ÇüŽÃ_;ÜÿÝÖ7Ö• pƒSÏŠ_18õÜ„õÕ‰ì¦0,œ:lZè¶ŸˆˆˆRjšrƒ!.¼/+°{ìØ–-[úIíðŽùƒÊ ¶ÀYüŠA‚÷@ÉlÙ²åÊ•+W®\ñDüW®\W“ˆˆˆhÚMì’mƒ×KVàpÒƒõØsÿ¬o¬þÚá-[¶tjØžð/%¸_XOc ¨'v|ßÏYvnÐõ"LˆˆˆhÌ&a‚§h°£‘?+è%):öØ1;Êwæ,:úí£îœÂBÌd Td«‚¿®øƒ”ävì…ÝÕíýÎ{Ã9¸Ÿ#ÃîÆé»3¬OÜ{Z³Ýÿ;""""švýenNÜßo¨[«²Y1ðDÞN'œ°_%>²×†Å|Øß?#¿¼#"""¢Pýt%š„j•<øðc¾c\õ‰éŒÌÇHO#ÎÚÆ1¾‹lŽ1ð„ÅñîèCá~ŠŽÁ6‰ˆˆˆ(uÆ4t!Ù ä¨ZAZ³iyße6+på]ñI™§(¬£TüÓ횀§OÑÀÚGDDD42}æÝÊ=4hGꓜ «[à>Nß!§Q× Æ<8âŽÉN†¼#"""¢ 3¸šCf²dµbgŸø]êû<ÝsVâsû=Âc ˆˆˆhZt«ô¼¾ÁägÈjÅÀŽ€žùvÜ;=G^$ðÈd1ôÀgûqšínàÎÀÆôÿŽˆˆˆˆ¦]&²dµb€^äÈ4,þYîzHO·Æ;""""š0]‰’̓”•¬Y­õf óMPVà;,³""""¢žY½•*•sg~v¦ùÇÍÿĬ)Yù8æ¼¢DDDDD©rϾÛÇÝ„IEÅ p¥a"""¢‰Ø™»§Éñi|z)üá®ðµó1¼ôí :Æ î¿d¹‘þ={Úõ‡8c,¨TÎy²Ž1 """d‹êÒ8$Xhy¢²íP-©¨¥TŒêÁ™ç_rÿ(!cdAÇ (â¼T¼ÖÌÐc\X1 """1Ùã‹Æªkõ NÄŸú¬¬¥^XnÀA #ç'7+øÐ»#E{!Þ^ˆˆˆˆh"‡LRVºÒ±T 8+eƒ´:æ'[R7Æ}Z,Œ–;ªn}¹“ž U"""¢lðÆéV럯AÞ£Æc³ïêi©ªøqá3"""šDž€K 2ˆ™„–âÄýýä,GtÑufÒ8iƒ#mœºTJ–”¦%aI)MiÉÒl9¸­áYR²òqŽ: ""¢ °C°‰¯£“Љ}[2ð¬À0tÙ0L)ÕœKf ª¦P-ææ¥eÂ’¦”Ò‚È`I)¥4¥”¦Þ0ξ²öÌOVoYö¦‘YR^1 """ÊŒøíbíaRèßÔsè)+°`JCZ06kP å„¢\.€‚Å›aI(®³¤Õ¬HË^ Mš°„4KJ@JÓ”€\%…U¤”k¯ž‘——Ê7,4)D**a]†8™ˆˆˆŠ>Ó•*LkVà”è†QÚª•ËåÒl)¯åq•3Uhs$€iµÎ€€i (Ís„Ê Ò>DiÞÈh˜¦4¤%åeÝ0 "§WÒk¯­”oXÍ |T©¨„EÿÌ ˆˆˆh ¹ŸèGÜÌ Ò)¤VP«WúúQ •|ÀÔ¤w‘vÏ!³aH) ]׆ÑÐaÉbAh9 „ ?+@J*Ž6&"""r îöÑÕ…æqò‡è¡ÏݯÀ¬ ÅŠü±U"°‹jóƒU¢ ¥”²!k›5ÙÐk›†¡º¡ C߬›†qÙÔ ÃØÔM)†465×Õ%€GþùàÞ»¬¾¶" B”ðA!_z**6v""""¤ˆ ?NΫ.1tbšrÿ̤>¦eʆa4tÝ0 £¦oõZ­¶iÔê5ãƒZåmY=/šg»¯ä½¦Ú™N´åµ¼³-@B‘ ÿ«HWÅ€ˆˆˆˆ†Î ­È“#Èz1æ aÙBÀ¯#Þz†Qè›ùlØÁ÷–•ÖNKú>Ê€Ü@4ÿ)ìïHÌÖø„°¦ÜÐYѤèm>Q_ô7Q1xútÍ Z? ¡…~UŠ û1?L@@–S‹ Š »C‘”²5CQŵ¡td€îžE]ÏîÀŠQ6xcI_tØCg  zŽ9kk¯+²¥"»‰È 3èÁ?ˆœÈkB›ÑDª¢BPP(j+¯žÌ ¡ŠÚÖ¢±)õMÝhHiIX€%eX”ßÌ„PׂhÝÖR+DDDD&:©éšiÌ"³*ÖȉâV­8 ½Q©œ¯†!]éÃE@(•Âl©4[*Šz²!¥%uC76!¥¤ ”Öàæˆ*AÐþ? <2~Å äV=ãÈc"""¢É"­æ+døk4·Î l“J‰œ(ÍjÅ­¨^ÚØxãl½^—AEÙÐÍš¸åj¥YQ˜Aik^›Ñ|OøE{•möjz# ±Ûfú>œ´T ®\¹ÂÜ€ˆˆˆhùsƒÞŠ öéC©?Œ¢‹‘„Ùµû¾i™@G¶ „(´|µúFõÝJØøÂláŽÏÜQ¾¾  z±V©lTÞ­”fËy-_¯CÝÚ…ªPPÙX]¼eOÇC²pŒ œ“*ÄÍ&¶WR׬À‚w”ò9¡P3*•ó¡YgŠ;oݹû¿ï6-T/žƒ%+ç«R"Wô-К’­KkõªÞ0ò¹Ö¢áYÒS1 """¢ì ìhä~Œß Qc÷Gêq`ƒ?t !°å­f«‹‘ª¨†Ó¡@h0ªç+݇œë4Gª‚Òliù3Ëk¯oÔ/U ”~\а³U@JÀꘕ(,+@zÆÑ4è30oŽjð¿Ò×4ê|ëZ._7ª†4 èjTE-_[^Ú¹=ÞWìaÇ€ªšBPW/¦Ž¬À÷¡'¬Ñ0 ehpoË® s˜rpVÓÜý…¨9¡oÖº7×êX¾@äÄâÂ¢È (¡–°G«Bá®*DgHUÅÀ¼eË–^“ˆˆˆˆ(ž¾s+Æv‹PP߬Ǹ¦ô ì©KúT‰fÅ@¡ ¡Úùƒ Ù5+@ÚÆpV"""""êªË H6š¹¿^Nîú€¯ªéYU ÆRÄB‘ž÷¢å´À¦¶SE¨Š€í BÚé‘‘Y‰ì©NOxÚçé}^sw'"""¢µH 2+L3Æ(‘ûïÝ¿øéEíj T¡ÐrZi¶Ôq˜°$Í{º*@ª@!TÅY9 ~éª \D´=Æ@œ9Ñp9pÏ¥ƒ®Š|™ƒ?+¿EÄõ…"¶_·}ùÖe‘TE >Nnèy­à}kΨ!p•P„PD»1Ý’“1˜DADDD4"#X¡kV`AÂéÒÓÎ ¤;è ØüÕЬ¨×ê¥*€àâ†}¢¡ˆf !xâ¦i›•hæû‰ìY+ """‘Ñ.¥–„’²0SòîŒÑãhõ—+RžñÇÂÝ>¢¹šA—•Ü2R1°£mOÌíŸãhKKœÓÙçÆÉ â_3þ‘DDDDÔUsòÑÀ庾é’Xöt¥®\Å‚Þ0‹3Ñ9ë¨iuYG¹¶Y[ù÷Ù0_æÓQ „P…€ª¬¼—R åÒuew¶Moèg~º²¾±n/–,‚–2h (BÚ«›ùæÏ ™Y‰zÕn@DDDD“"0 pïŒ=éôô& Î ü ³bEÔ6/˜Ý:[š-åµ¼–×Ê-‡5ôÌÕ_­ž~þ™ú¥ˆÕì¶©PZƒ ¬Î·ž ó³¥ËDDDD©Õìz䲂XЃðq½a!8ä5uíÝ5iIMÓJ¥ÒÒ_*•J¥Ù’·Ð }õW«'~|bã·v¹À´$¼C„sq¨Š½‚ëj‘Y¦¶bÐ~VKèÿ"DDDD4&‰²ûGËŽ aCg_?k/U\ÚZòÌGdJsãíÕWVW~¾Ry»bŸ¨XÈw4@qý³k¢â:Ö+óYAâ~DÎàã^Ãz÷ñ1W=»-M–À¬ö"A¹lþ(-Yy»R«ëom¬Þ°ZÜZ,Í–´«5iÉúûõêÅjå½Ê¹wÏÕ/Õ¥l_Á0tÏ…39©âÚg·ÅÝ$_S™­8¡¿a»Ç$c0²%ŠûADDDDCÐmí³îs•¶Ò µº>wý²¦µûÿ¨ êï†c"'`¡¶Y7>Ða‰ÒÖùÒV'‘€”¦l@6dç-Z–ºw¹<¬ BAРˆÌV cw÷ÎÄÁ}ÿYëDDD=½ÌVÝ¢¾I×—2Þ “{Æ!È .Fíɤ…ZÝÈÏ WÄn4kT`ïÍCL £aΠ½’šÓ!´<3[1˜t„@DD”MÌ &tM(¼Â™'+"rÚ¿<¸ç35ùasÈÑt<ø IDAT¦4À’NÒî/d5‡›î8Þ‚0ÈŽU¤´Ïµ'X&Ó‚”F©XŽhªGf+“ŽYQÚ$Î @ 7/´G!­B SnÝ¥õ o9BZÍîIõzÕÎ"ì4C6Lo¹ ²–•‘•ã/HœBÃh|ô5'ôƒŠ0Þw4–»Oôß<ÑTÄ:»4V/Y÷+Ü ú{ຂ{úQ Ò2aIÕée¹òËת ¬tAöJ¡ñ~)1g©âŸ Q6õš¸gŸd¯¤Ñ’‘_VTVп¨ëtÌwdÂN LiÙyˆšLϬD&{!fúÃúþo1ÔëѤ ™0Œ\·¬@]ýõš{^S@@(€P¨BEµ¿>{ë«tjS JH!àšÄ0ô†!¥¬ÕkF½&r¾‘Ç­6H˜ž}¬ŒZŸAdöÂzŠfãÌ ˆˆ¨©ëhf#gv«·ξ^qï¬^ªúâ>i™Ršº”öàcyÙªV¾¶¬ QkÔì~GR6û™ÍnHBJCšRJsõW¯èårÙ´d^ÓŠ3y!Då|õâû5q•¨_2¤™/ä‚Z” 3;Vv"fO,åÞï9Žӳ™ÿH?O˜îÜ7ðîY¶ÌÓøñ—W »¦ûÜdŸRôΞ>~n4ÀwÔõ{ïÝþëø6DD4]ºÎ”j1y¤à¬À¥‚»ç?…¨T«° T!r"ŸÓ ¨˜)g œ@(šªÀ´ *B0íB«¿zs7–7Þ®­"ƒ¦– hB¨Ð‚’ ÃÀˆ-,fuöøÏõÿ˜ìîövŸ~¾¼Z‚O)zç$Þ(ú{ïÝÃnDDD”„÷q™…ë%+Ÿ)®½¶n4 H)- Ò2MË(‹µ÷kÎ,CÍ ã‚íKé›5(bõ×g…¢òÖY¨MË -ü+Ï ™Š_‚ j€6†Ò öÊ1¯æ‰e“}¶‰èéîÿÞÇ{w""¢QcV@ȸް¬€P„È•ò9ïà„Z½V*‰³¯¯Ùc ¤”¦Õêh$;g)U ˆœß3 ¥’V,FµGé’ Ãƒ> 0VKÏsßè‡Ð]_Ü¿ ì•@ôzºûÀ«§ðîDDDÃÙQ‡!l¶%|’P×èagÞ0¤4µœP.—uÝ iÏ,Ô¬8×Q ‘ŸÑJ³ÅB± P*û/îÝãÏ 8+QL鉿=FÐÃ$ºSû°À»QxûL˜É a¬ÈáÍ LÃÈkbùsËZNT/U6^_+]» ®Rí¼Â¸lÖ6«µKõúûµZÝö2É „PK×J³%½!/¾W­^\ÕfJ²a”fK$´ÂwT A_4+mËÅ2?SÜ~Ý¡¨B„€%u£V9_ÙØXj¥ú~Ý0t³!¥4ªç«Ò:k_SBÎÍä÷|f¹<,³vIJW±"fV€©ªx:s;“º¸ç‡q⪘³žÆ=Ì4ú²Ñ·öCëèO)þÎ8}÷ßh€ï(ú{ïÝÑ㟠G,¥„ˆe?=HøCÒ̤®¬ÀþŸðš¿«]ªù陥[ ¨° ÍhšV²G€(æJÅBiéÓËÒ’° 7tÃ0t£f|`Ôêµz½ºvvCQ¾¡T­KèBÑ4{킳dµbà ž¢GŽºw&_ë?=º;JŸ’]$0è©Év&ø@bîŒóŽõ½§íîDD4)¢†yf#mè5ÊÏð OVàȃÆÔ7e}³Vy÷Œ½C7 )uûWB­µ–…²a 9%‘ćö~iZ&$ )J3%Ã(¡jZÇízÊ 0Uƒ>ùÄ2b£´á$§DD$"m˜àœ¡sÚœÞN™ÜÒ/+ð.”ø/’ÏiÈi¦«Ö Z‡ ‘wŸ(]Ç”ºÎ‰äkF˜lV †a¢ã­‰n| ñ¾£Ô~ž©mõÄÐMp’ЫÀ°5ýÙB`VàÚ3+°¹³‚ðYPãÓe¢@¸7~Å ÖM†Ï•;‰7YãSxw"""Ê&@Ÿ Qú³‚–Ð% Rœ4—QsaÅ ÃD÷ÄˆÓø‰~ƒDDDSÈßãhj“ÐDTÐï§øóKù³d¦b@q°,@DD4é& +@k5.Ï«W’]Ä)ÄyÌßs¹ ä°8å‚À¬¬ UªÏ;³ò»!DDD”\ög:røŸ…§ÙägÈLÅÀ3-¦ÓoÞæ¶ÅÅ¿Ó}ÁÀ#ý7Š¿ïþh=ghz"""³óׯDê³þ0T™È áŠûiýß¶;Ý+Iùìµý,F6öÆÑ$Š÷{Ž™È"CªªYÉ ™Š_²P~ìmH|"£"""Š˜3LdVr”øËlÅ OÝ¢ODDD#3‘S¹Yã¯T*çÎü¬¹t1>lþï$fàÊÇaò~\ÝxX= ""¢&&+°|ÛãKîÙwûØî=h¬´…=hOß;cˆG¦£ñL0ˆˆˆh2D GrÎð‡?¸â¥ÎfHßž cÌàÆ[îc¤ÿDÏžvý!Θ *•sž¬&³c üìѺg6Ïž°#܃‹­ûo¼3I‘£°ÆÑT1û{Ú¸;yMTV Ýª%›O\뚣Ž>²Ïf$;kPg¬ODDD£ç$ î§3+Uòpæù—Ü?JÈYAÐ1Šø#/o…53ô—)ªP|œä”ˆˆ¨/)œkȺÆýc(2Œ¬¤'âO}V€¬V ¨OÌ ˆˆˆ 0K[˜Ve L×¼‹YAó˜ð¬àCT â/3œækfošÑ®ïh2QJ)™Í Üzª ±z`Å~ Î$eñ§+Š;ÏŒ?g""š^qbÐ)ÈÂŒmQÿ÷’è[˜ô¬™©d@ö"fÿ;be€ˆˆ(J`<:´ÇÛ4@“˜xWO K ¦°bÐgPη«ìe>DDD#5=‘ÜÆ6jºÎL*!¥åË :“=Ò´ < PE©8·ÿ肽s¥^ gæVêç0 ³™f’áY2³ò±gÑO jÿèüÓ}ŠsBæ ËÆ_Ë,ìšžÛéÎ=zÝÙÓÒÏßQ„Á®ö@DD4Á¦,èÏŒ8YA×b‚£˜ sÇ¿0oš€‚k‹•‹ú“w‹š0rá†âÙ·j+oT,o5='ú¯˜`ÚÆøão{Û'àÙh"€³ÿèqM&à?+°ðÉ¢½QûÀ<öÕ•Ön*ú⼸Zä  !ìÈ_y¡IEž­Ö¤¨W«jç„EFÃ,ßP>þ½ãG?íì<þ¹úÛ+¡U‚ ÏJ¸äÖDß={ˆˆ&C‚Éû6dfän}¦=eF®Y.¨¾¯ïÛܸ”_Þ¹PšRŠÔM @ØK+ÔRË¥4 šÕ±š€RQ=}â¸ùÝ£NÂðп®É‹«ÑYé!ýY‰<âjMáø×ÀézÂæðIaû‰ˆˆ(ãܳô¸_™&aF¿GÏ*f¥bsðÀÚo«µ·ÅÎ…9‘ƒnHÙ0eÒ‚aB×¥.¥iH]J]Ji¢ˆü3?? Àh˜ú倻¨W«¦ óC<úãõYƒøƒ¨Ï€Ê~~‡õ‰ˆˆht¬ÈW²³Æ9ôS.è5+Ú‹RÎ__ X\(šdÃ46›é¼ ã2äeÈË0Ò¬þV7¥4ƒngÏX*-sõªñn—DY¦°b0vý/ws6O& DDDDq˜­W!xk§?+ *­qæ %L …Y!R7`Zv‹ ˆ«!®†P`7È+Åcœ)æPy{m~n~÷m»O?Z¿Œõ÷ôško×_yá™ÐqÆ‘Y2S1ðÏ¿¹Å޾¾7ýv÷0ñ—B‹Ͱyîây#îÃúyGDDDDýJÇ€„‰Ì Vίg>!iê HùÎ<[ÝswiÏ]ÅÒVUË©P iBš€PP¸F»©TÚZ8ùüêÜõsµzMoè+?_yMÀ’}ÿLoYÁ”ÌJä5ët ûUâ#{mØÈFôÆ©* äõeš²òÕõ{[ѹPó9¹¸ Õêrî¦béÚ¼”8{Ö¨]ÒáäÒ®+4O*®¿¶¡7V_^]3ŒÚÜ‹ïÖžùÉú+ÏCåÅÏTÃÚƒnY23+‘‡'þŽˆwG ÷SlKˆˆˆˆh¬í–3¿tâ{ÐòÚÒ]æþ¿Ü~ü[çV^¨© DNTÏë HHØÓI °š=Ž Q×µÊ ä`ò¡ï)óyžî'8Ý? )“ ""¢apb:  C·p-MEÁAê8Êý.zölÞ}ÀÅÙ0Œ†`~-‡Õ×ê…|íì«u!Ä3ÏV‹[µbAÔ꤅öŸÓ,)-h(ùçõÒœÀûÚÜuÅÒm♟Ԥ”âb©rÓ‘²ÜãnO̬™c(p§ïÓƒ¨ëcqÇd'Ã@Þ’AY ÙzÁó"`2;ÅÈ VÞ¨J €iÍò3ÅÊûµãß®H )¥4¡o4MxÂwÙœ¾IH³¹-rŽw-úÚbõ]¹ü™Rq« ˜Ò‚þúw{âgÈê¬Dîà;,7è³Pxr¡Äçö/z„Cª2""¢)Q7ð§ ̆Îì|õÀŸ-v&ß[‚%M Õš4?„”¦Þùœ0 Ó”ÍÃdºüŒ*rÂs:iIX€%M‰¹9­tm~þF-?ƒ}Ÿ_3ꦦ©°$.-$Ë ÕŠ;Ü¡°ó+g∙y"ŽLö|}à³ýN 6«’¿1ý¿#"""J$ +ˆÑÁˆ}FÇŒ|µÅË @¤”ª‚êE½¾iÖ6%½!UZÒî;„ڦŭ*Ñzµ/%-@¥’¨ž—+/T×^5νk0-Ô6M(–X+ð5›­È%Ëc bþj G¤añÏŠW=âwDDDD= ŽïeçÿúšŽ¬`Bú9¹hï‰Ê VÞ]“˜³·+?Ź»êŒ†i\Ê ¦¡@  cÓ,”òEiê› !„"M@äD¹µMY©gÏËŸ)¨¹æŸŒiA6MŠóKæÖ.MѬDDDDD)Ö¥GPPÐsV ÃG?'¼"…ëR+Ð(5W° Jœøáš¶•Wj%@@u¾µ:f?Šò y½£!k—L)Äö­*Sš•wê{R6@JhB5¤é¾©¼\jmèl˜ôýid¶b@DDD4¡‚By§Œ+ž—¡×¡Á“ݲ ‰Ë%{[U¨•ÔÒµ(i¥Š" Øß­pMTšÕJ³Ð Y.kº!åeT/ÊÊÛFýƒö1¦”"'`ØW6À’0f›‰A/YRR1ˆ9¯(Ñ”sO„ÚÚÄ}üßq”LgÑ ÛYw‡ûŽÇ$8+ðà‹ÃEN“ ´~¡4ÓU@Óׄ6£Š Pº‰óX{«V=/›µE@´bûö'Ð9ájYRR1\i˜ˆˆˆˆâˆß­©0Yü¡«?ü}ª>®7(mh†ïB@:Y"\ß„P…*r9¨W€Ôj²^`éî9$`…¬™²3,+@Vg%""""'Ë÷(Ïô¥S4¡éÐ>ÒäbfîLiþ˜«Íý%æþX¨IW §Pùœ€óC˜B7ÐQà~ã– :Ù…":/îkR·¬)©eÙŸa‹Þrƒ”ö'ê‹:¥—QX­àê*”2”Ö~ET¯©!ªu=/ÄülQ»•óFÞ(”¯W¡ zÉÐ )r"¯AJY½$M)H«ýý ERv$ „fD5É·ßujÎJDDDD40 o' j{ªd1-«ˆY‰r5gX€P@XÐ¥Ì ¡å@±¼S3 ¹þž‘¿¨ÁB± Š ÅæW$%¤ÙQ0Éç„n–°/(-»GÒÕUO A“Ù\ù˜ˆˆˆh‚õù¨;…ým¦g¢ÎéÚíh¥6Ã’¥™¼9UË¡øÇBË© Ÿ,ø\Iû¤¬YF­nVÏ›g_ÕP,´‚~‘ƒ¡K÷„zíª»I1³¤jŒ½ï/HDDDDÑdŒ×äQFÞÈ“ r†È (Â^áXœ-çs¢¨©ÅœÈÿ±¦åÔ¢&„‚RA;ø¹ùGžÃµ²¹r] E·ªB…ÈA¡*Z^H»Ó"DR (³•ÙÆ¢Ó¤øYRU1à¬DDDD4íÑÆ½T‚ÕÖš§¥7—ðþêpðY”Va‰ÒV!@‹;ó{o+kš–Ï‹Ù5ŸBˆ¢&„P¡ øÇê£_žßÿÕ¢>cÔ7MÃÅ‚Bˆ«„9·Bä Bh9„(Xú\ѹcOYRU1 """švý‡³IBÞžƒüñ‡þ}`=!0+°Xº> ¶‰Òµbï½y}Øy¡ˆ|NµvV`ÏR `{)üë‹Ë÷æÏ5ÙÅ­ªÈA\-DNŠBJ”®ùaH;+¥r®\ È ,_«‚¤¨bà·eËv.""""j‹Ÿ9 蹄ô¿ºö?r™JC¨Dg$L1»!Q½ˆÒµZ±€ãß«¢ž_û¥¡7¤Þ¬À±tSñø?-ÎÞ‚š¨å5U¯Q︫˜×T¦MŠ@Nî¿·XßÔ3+ðíIuÅ€=‹ˆˆˆˆfØ=j‚æiéqdDõ NV`q¡(8ñ½jå-³4›ßy›vôáÅ•jÕº˜8v/”Ž}qá.¨×{ïÕ–nË—¯PÔ|ª€P°ç‹bñúÒzÅÈ ü¬f“ÜR]1 """¢Ìi[HKnàÖ{¾dÆË ìb€"„@õ¢^¿(,ϕϼP=óoë]ïµ{¡ôÈW+Fí¡'Ö×ßÖ…j ÌÈå¯àÀ]åê¥.­¶¡CPV€”¬c`÷ò×8™ˆˆˆ([&aá„^jÁY‹;+°¸µ´6»as…«!V~nT«RJ”µ’|_?üíÓ‡î]*ó7ú°½½çÓÛåͨުW.Ö”gËEMHàä/+íƒzÌ ’•âfDDDDÃei…àôˆÑù¾CàÇ/+°-ÞTÛxµ(/ìµ:Ê× cS Q,çÔcßY+\¯¼kIUÎ|dó:¦”(j¢øÉ’lí_y£ª¿»â¿§aYÒ6Æ€£‰ˆˆˆ²Ë·D×XZ¡kŽ3+hÎ ØæÖFÝžlTä`R›"‡Âk;oZ,ZÚáOýñjíƒö¤„´LX¦”fs¸iÁ”0-¬¾Q]ÿù‰èöDgaoŽëÑÀùǤ)5ˆÎ Â~Û{V`ï™[X_;¿†‹ûoB¸ ÔæåR©¤ËÚS?Y5,9W.•¯+Ù…ìsMçš–¬\2VÎVq1¼V–øŽLÅ""""š6"UYºõ òü6fžÞOIBÎ_‹uã°ñón)jyäg4kùQD©´µh†Þ0ϾR©:U(€Þ†¥u£`EŽ+ðd)G¦ªb@DDDDcOùØ7%FÄwÐoãÊ ìùÜnXY9_ÛxýàÜ\~~NhšT…B¨Ôb!/¥¹}zC›X߯뵫N–g "zfÒ^²°b@DDDD^½Œ¯íù:“¨—5§ãgΞù™"fάÔWW~²¯øá\©T, iRËÃÐa²VGµª×äJO•¯YÔÂÖ6öÝ.~VV ˆˆˆˆhX¦gÊ#OVu@èô¦ób [k@M‡\½øP²{[ITæ”Ú5Ð`ÃÉ žŠG¥Å@VDî–HHÑñcSêÆtåÏ BúEdÎ{a„9qÀµsÑsØ0²¤§bpåÊæDDDDÙa‡¡áéA`øÏ¬À¿Ó³'IV/ÓK×:DDDD”)VÐ ;_´sLbV -ïœpŒV@­`"’„¨ ßÏ_BI< £Kù³°b@DDDD)0i=ˆZâ”â<æï¹\rXœrA`V€ôŒ1 """¢©Ðûò H&?+@ª*öøã-[¶ ðšDDDD”zùGÉDV€´U 8+Q–ÇžÑ#„ÿ×2-éDV²¤ªbлθÚÐçé}^sw'"""Ê:þŸ Ê |‡¥«b0pk#ŒxÙÜÏòQ ~Dì/:/Û;}G B¥rîÌÏÎ4øÐ¹éäeHÏÊÇ™çIX """†÷1ºgßí#¼Ûpe¼b0Œ§òý—¸Æ3Q¶ÉÎDZ"ñDõÙ6Ó¿âûUš¿žàÞ3Ø´ápuoAúöc&–ûé?ѳ§]ˆ3æÁ€Jåœ'«ÉÈ;Îö?•÷<˜ßÒçô@ñÇ„]ÓŸÄ¿;M¤¥©i€k~u3ÄbÂDeÚ= Z²\1°ç?u~tGä‰{òØ×LÄ;yÓ""¢éÅ‚Ç3¥!ý:óüKw‘1²‚ cñG^*Þ kfè1.©ôªŸ¸¼Ïsmc@DD4=¼“æX/Öøk,ñ_Ý´F'nò¢8ê³d»b@DDD”ríG×ÑA[H‘ax]ç'˜ýIެ,3¹YÁ‡ÞSZ1èG²‡ý,‘_ܧÖaOÄ]ûƒ ÓYŽèžˆadR“”ÄŸ®4óƒþ—Bö ûFŠ@DD”y]VýõüïA¸÷,‹š†WW™ô¬®8³9vÏ~[â€;ñ Bî»ÇiS"""Bäê¾…÷€©Ê º¼YÖ |×iÉlÅ 0°vïì37å‰DDDD€/p‹ÑGHúÏÀ 83é±knnEMV3‚ž¥Ùºœ´Ó7f ye X>Ð}¢?+W>N-NiJDDD^ F LaVñ))Á±CôþÙD¬Wp°rÈþÉ´ÚÇzZh¯…w憣{Þ:èù­ôÜQLX™{ji㬀_5oÚ>]nÜxºóÊÁBf+“ŽY @P”Ü1—Ñôô2ŠñNýs÷D¡[";+8òÈaÃ0ì½wÿÜõóÍÛyrÄÍ :î’ø®šedŒAü‰Sh¾æ„~PÆûŽÆr÷‰þ›'"¢ôpEèiÄýì¥àÊ æ>9÷âÊ˳³³'râÿy?\Y`ŠÎsí>EE-_¾¡4wC¹XÈCà :7»fí£]{|)Mpb0µƒ„YŒäR(ýyÿlˆˆh(\árvr€ê-S ªÒ0Œ‡¾þÐü'çÖþcíËýevn`å?WÓòåÊ ;ʳ¥b!¿ó–…¥…ùâÖ¢ý}¹: P¨ IDAT/õQ+*%e¤b@ñeoôÂxßÑÈæ®%""°©Ê ·žCg’àêj|ýæG{ÿßÝŠxèáGO9Õú­é9ZäÔò å¥[J³¥Z½n4¤´Pß4„;oYXXX,н›—€ƒÑë3ˆdŒ8m²—ÈQZX1^IçK"<+hEáÍOhï½û+oWV¹jÿ8ý<€‡¼¿}®ÅBqñ–…ÒlÉØ¬†¡*íëÛéA^ ;æ …<>ì!+èž e¤bàY^À½‚;’v¯$àßé¾`à‘~þ³"îîìŒn|×ÛÅÉ Â®éŽ2“}JÑ;{ú@ú¹Ñß‘çji»{ØFâ%5ˆˆˆ¼Âúßwë—ŸñÙâ‹^¯À‚=ÚøžwÖê5XRä´§ô4€#<ì)´|¡¨U66j›u(Á­lÀ¨y-¿´sç#W?^(ï(²VÚTÌV ìˆÍæDlW\ü;ÝÑ­ÿÈ>ïnë3Œx,˜àSŠÞ9‰7ŠþÞÇ{w""¢qêVL˜fírA·¬ÀöØ?? ;æ?¾ícÛôMcéÖå§ô´”òÈ·.n-.o½cq®\,ïû«ûîÿòõ€[:¾„±iäµüÒ­;´Íu@ò¬™©ø]I´8ñï>–+Ǽڕ¾Ó›®§DÐÓÝÞ¶ñÞˆˆh’.0ÍÝŠ$¤ýòì Ì H yü‘#K)w,n×7kK·.?~üq)åý{_í§ú§–>µãOw¸xþâ‡îôŸŽè›µÀK5/(alÅBqù¶å………âŒÖ®ðøç< Ìå8+QL½Gz•žÈoKdoõ+®.1Zòi ÛÒÓÝ£ßQ)¼; Ì0‹Þ¬Àý+×̤yL6äŽÅºQÛó¹½{L6ä‰oðœûÊ¿¯Üó…{Ö^]k6;ˆ è YÛ4Š[óË·.-Þ8Wœ)¸Úƒˆs9+Q®twsÚF2†½÷ÑtqáÝSøWGDDäÔ¹Hº^À?‚¢îR1³¡¨¥­¥ßüÇodCîøÓµzmßÝûçÇügi3ÚÁ¯š»i>"+h5[ꆬm¥kŠË·--Þ¼ïè\ÿÜGÍ5|e®|ÜöÅ|0<‚ÝÝC=Á¹‰ÏrŸëù±kkûi^ôÝõÀ>ú{ïÝ“]IQ]ïLÂŒ•µTšÍçÔ}_º€lÈ]KŸzù¿Ùwï>£ayäH«mbÏíË{÷îÏÏäãdΦÞrS/•Jå–*•JåÝjÍ0`ÅÍ ö©Ä¯LPnØYܽÓÙŽß­<ðô0îa¦Ñ—¾ÝPþ®ŸRüÑHŸ7à;ŠþÞÇ{wôøg3‚²ÑÄ‹™Ä;,4+°LOV0C¹ö¾ëó·;dž±ëÏ>õòêoþõA¡ˆ‡¿ù0€Ç¿ûdù£%(Q=ˆZ·ð÷B¨ºaHi–>Z.}´\y¯R}·ZóUÌ Õ1žàÉýÄ7¬—ˆ±Ev/Ïéa§ ¤£H²Ó‰8íìg'zù@zÝç ê{OÏÝÃ>I"""°ø%…îk4³‚J¥rϾ;=dž±kéSú¦~à‹|øAår¬Àa§µKÕr©´tëbq¦è^#9,+ÀTU úäË(ÒfØ%""¢8Ä@;ê ^œÁþczOÎÜpTêòÖåõŠùÀß>x¸aŸZj× vv×Kg^<2NVà"_ÛÔ+úYì¬áý ¬À÷9Æ ®‰Ž·&ºñÆûŽRûy¦¶aDDD/,ðDÓ΂eÀž·(m-E~×¾]×66ݶëå_¼|à‹¤”»÷ä=e° ¥yâÇO,߶Ǭ‘[A·¬™™•È•;‰7YãSxw"""Êš”— †Ê½p ŸË—JÅ_:ÐõÔz½¾ky—¾©ü냿xp÷žŽD¢×¬À¸¬û—c+/®Ì^S06uÄÈ Õ1‰Mt|§ñý‰ˆˆ(ýD÷C2Êm›öçP(6Þª\¼x1Îê—ê»–wé y談öß»ÿ޽»[Wsn/+ÐkÇ;röׯØIZmÓk§GF*³""¢ÂúY”jY½!µXÈþŸ‡ã_¦~©¾ëÏõ†|èïZ¾mÏîÏîê5+¨×ª}ó¡ßnØï~C—²áš7)òÏ’c †(U#AYùÇÝ""¢é0Í=j¦?+° ?£é†.FðY!ê—ê»——^ZY=zäQ¡àöåOÁBaë, ëõúÓ?:¥åóaͨ¼W9öØ£õz½¹Gbô rd¤bà™öÑé7osÛââßé¾`à‘þEˆßw4ksüwDDDDq1+˜!Y,hWkoU\òâÅ‹wîÙ-¥|ôÝ{÷Þ…›Öþcm}mý7ÿñæýï kÆFeýÈ#µ³àÄOˆ«5!¼íô·Ü–Ù1ör›j»çƒ÷ït¯$å?²WýÜco<Q $ÂçÉÏ´Ž¬ rêÙ³¯ôz‘û¿øåÊ»•;>‡”ò董Ϝ0 )Ì*"+@V+ž¸Ö4;Ü¿uöDÙg3’5¨Æ_é” aDDDÓ´ ½†IítäÊôÍššË‹\÷·rñâŇ<\ykÃÉ ^\yùÄNlÿÄöcß9æ?ÞùÓ*ΖN?w:,7Xþó=ÕKU×Y’1§+ÍdÅ€â×è""¢Œ‘!¯` ºÍd·\ÐñqEô°J•Î/N6d­V;zähœSëõúÃß<¼ñz{£W^~ôÈÑcß9¦zÇe;ïXº¶|ú¹Óþô£|]Y¨¢v©\+ˆ?]é¤W ¨OÌ ˆˆˆ"ðYq’gá©ÂDÄÊÓÃõ9Qxõbµ|ÃÜììlœ Ȇ<ò­#¯ürŹÔl©àÄO8A½'+°•®-Ÿzî%OnðÈ?>Ry«b4‚RÑÌ3#ƒaŒôý5³7Þ·ë;ñm""¢Éà‹øƒ‹ ÑӞø~ø›?ól÷ÜàÅ3/nüöl𯃲d¦bÓðžLöÊ1¯ÖzÓõ”ˆz½{ü‚ˆˆˆ=gÓ“¤CxV°Ó´P½X[}uMä´—ñòãÇX·8ÂÃvÏ ¶_?ÿå/~ùÌÏNJO3B²L[ÅÀ-=ÝW¢»Ý»»ùûíØqö@Bí褧»G¿#"""Š#aÝ zÓ8ó™2+HÀÿy~èË ZGꆱþÛÕWÖ„¢=}òô©3§öuœ’Ë·/?üàÃ+?_‰>ìŽÏÝáogXVÎJ4(#…îoïvú¹;ó""¢Ñè­“}Xn`17èQŒq½f{3ÝÓ7 }sC}·¢Š¥ÏåOí<À¸,ÍúáËF@Vøøñ' ×P×ò—´û?{ßãß}|ù3{ÂÚUš-yZ‘`f%AÇwŸûç&>Ë}®çÇ®­í§yÑwï? °[È\‚ˆˆ¨'ƒz³§~úò‡1Ì^š(+pŽÑ¥Ô/V+…Óµ7Ïiš–/n-œzî¥Û?»Ës§Ÿ9`ãõÚ¦!zõÓ«Ëÿcïý{ÿ“B,ݺÔ2Y«×Àj €ödY•ÈÃéâ'Hu:Ã$î“3ðÁÇ·pwæqî˜`gt;û¼QükF·¡÷Oˆˆˆˆ(«>÷’HçG RšµÍZåü¹Õ_Ÿ½X­žzîE÷Ež|êI)åê¯V««ÒÐí+Uì¹kÿ}ï[ý¥¿O‘pæ…×Ï]²dxŒ3ÔÝ÷+ß.ÁYQrœvö³½| ½î ‹ûûÿ„‰ˆˆ&J× E3§hà-“Û³ô• `Ê0?åh툿…ÇÊ ""¢üAlDˆîüjŒ‹z¥Ýx³×þ³ûŸÒ\{c½X( E¬¾ëË <Áý‡ØsûÞ'¾ÿÄß½{矷²ïbÌÁ22+‘8ì¤ß={ˆˆÂ% b»ŸåÏ-ºž3Á©FgÔë~ïÔìÏ ,çŸñ²üVJY½XuŸîú­ë͵Ö6^þ­°ÜêüÚãe˜ÂŠAü`7…aqàt=asø¤°ýDDDdXYA2 r‰ $[É Doµéû­ë{ˆ‘´wù²W¦.2R1˜aó^áZÂDDDltYAØ9]xÈBž_Ü_æà­ظñtðÑÞ{I•OŸ‰j‰o¿ôÿ¶~ÍÈKÙwµ¼ßüÔU Æ®ÿåbvòa¹€ˆˆˆÜß§säq$™àýÆy›ÍgùÞÊ€åóÝ{¤¯࿎ã‰nB®=qf&õgÈ̬Dþù7Ýç»÷À·^A?G†Ý=ŒsÙï¨'þFzÞˆû°~Þõ!"X {Ž/òÈ>ñ%&·\Ð1¯S甦³>õ—xöLDV€¬V <Ôíûáôyd¯ ÙˆÞ8ý‹òŽˆˆˆ¨£žg7žÀr—ï-ˆx#•?´f¦dÀ‘GpåÊ•‡¾qŽ|«ùãá¯? àØ·nþøµGÛç§&+@f*ž°8"Þ}(ÜgÀÿtŸˆˆˆ¦É–íÊ«ã%:K®dç«ãDÙ< yÁ–f¤guþˆàS• «¸rƒ®xü8{¼¹çé~‚Óý“2Ç ""¢ÌêX,4 –‘?v¿…+þ~ðáÇìZíÐß?b× ì#=ðHjk¶,ÏJØ#ÈÃߦëû”ª;éi µù£:oÈ3|ÜἫÿú~™È‰€&`\ï°lV âÌáÓ炉'J|nÿ¢G8¤*c!""šlvÈ5¨îø ¯3ø¬ ÙÍÆ¯§ZOñ[45Y³Æ:ì¡R9wæg­™FÛ« L^V€¬V "ÆxºE Ò>2Y =Œ’ÝN‘Ä¿3¬1îÕ*"""Ê Ý~EÿÞe~b\Ÿs+°¾gßícjÁàe³b€^äÈ4,þYîzHO·Æ;"""¢]š ‹h='¦¥\ !!ÝøÛb¬ª‡ûšÕOj‘°Â0P/ÿîBôCI‡ç•u¶³9+QF8Óàô Ÿ¬@Âj¾Lû%íLKšL4_C'âgVûëHyVà‘ÙŠQJEóè=h0®»3Ï€ðIo¿5òÞDñ>½ÿŸ½ûmÛ¼…ÿõ…rA8/¨ †ô ڡrÒ¢rÚƒYYŠYY†En†¹.P+)PËéA+§©ä\,–S,–[¬¶[¬±¼‹íâ6±$‘}ÐÌʰ,ò°,ò°¬V±¦V±¡ñ6…·Æ‘pjŒÄ[~ÿ -ËE‘%Qò÷ÇP(òùAÉÒóåóƒZ uFi¢Ç׿G!„ÐV¡¬+K°ü'ú“VIçC¹IŒ 6í–ÊóS9åŽ ¤Ô]p~óæšè1²®(B!„P-Pp…;½*£ÅYþ†ofŽ%»H/Ò¤&sT€Ã*‰a€µ¹*B!„våi´±ëOqù‡|Ôâ ¤b7? ÔŠ[5¯ËÚ] j ¢‰„B¡­&s¸v$iscÓBl •Xµ°Qå©Ý}=!„B%‘· HRü¨'É3ŒÉÍÿU‡”µnK0¨ { B!„T–ZH‰œ–ŸpŃªˆ ²”lj›ñ[MRZü¥™ê ‰U‰x"7!F!„Úrò·b¹õŸrË·þO¥WRh]X¡ŸR£r4Ôc€«!„Bm(´ê|凡ڢ¡„B!$LèZ.·ù§’tee¤pæ±Òª9s àOEi¨Ç ?²»B!´Õ•¬÷ 3¢¨Š.åë 6» E å›O¬šî1À!„BH@Îefe]îgЂò\ª¯†¨4Þc€B!„ Po ò›$HY^SäX9U(|w3õ(ì.àφnó«&z êêêgãtd„B!1jÏH.ɤ…‚íþêi:Ë i²h¢Ç _룄B!YrôùBñ¦¿jó ¤ôhòö¥ZTÃ4ÑcÆw¨›&B!„Pm’ОVeR²ršlñ£|4ÑcÀÃC!„B2(¦"¹¥®NAº„"ùj2x؂ݠµ„B!¤–ìÆ}V¼œëèkrÙ~uÔP¥4Ôc€B!„T”5Hz'@™nhÀ·C¥ô*äH_ÑWky¢¢ ª6ù–ŸÂ„B¡Z§ÐIXq¨Ì£zR £ÕÕLT ef·þ;÷€=!„B[‹ïp,ÞÈÎ6¨Ò] ȼ»‚p¿•ÑJ΋’¦BHu¥‘_ÖÙ¹£í5w¯ƒbÔ´ )6{å«õÞª‚¯ö”[‘ÈÚkÖ#qü+ޱBÕŒÌÆ™Œñ9©ÌV[¥ç(‹v hv£ª`¥2úò¬ÅÄåyœKø… ^ @{G»øïºººëW¯Ë){©dÝ^ «-•¹=ëÌ™ nÁ=se5ÓÓù æžN6+Aé÷F~{µ|if«ì,‰o”uBŠÉHÅ|Ý+›{¾×Zñ-5B•GÁû‚Én:‹\Ì®èPŸÜŠh0*¨M©ÍƒˆRÅ?yßGÁkAñ#5>ŽH°Å–¯ÍšÞ’{lî•åÎ?.òÒon-Фà,‰o¬ÆŒÄ_÷Êæž/#„B—Û2Îm± ¶á$4©5×] ¥jª¬»@ÊâT©ìI)Å×±Væ’äPШRqÀFéštê¦,1µ¬¶¬²s«xY¹«þºW6w„B[ŠÂ¨ Ì«‰"4l’ÙæÖfC¸à<‡p¥¹I¶6ÏG婨VÓÎu_ñ‹Ð‚C_2Ÿ¥€x ²rWý²ºsG!TJs}ºÒQä´Y%,iª…¨`ãåÈ*¿&¦gÊ•.?Qâþ" „i§5Ÿ¥ #Lĵ—º˜;B¡ZÂ7‹%Æ "»Âë™nºþ]ÆQF9MÈê‹ Ê/]€³'#*(UGADn&}fpIIŸ|,x¬â£r§I¨~BÓÏ]­fºøë^ÙÜ•¥†BmQY Ô”yIÓœ-Zˆ 6h'*Xœ¯•_Áó¶…ƒ¬ÁÜéE]2ׇI·«$®J$xx>™ÓLœϮԭÅÏ’ôRÆî+ÎHʼn¿î•Íò¿mDÎ-IB¡Š;jÝ]é" ­îrä ¹‡Ôf`ÕzŸ9š¹QÁüÚÜÃŇ£IY"‚ᄬr*Û¨à„HÜ(¥Fj½îZË=í7¡ßä{J¢ì/ŸB!„T¤Ê·ó öU›A)ä^…Ũâ”ýÙóº^í*>„B©H•oçt"ra` UU‡U]xA•­QíO„B¡ÿVé¨#=+·3*[á5˜;B!„Òˆ ÔRÕíc)…¯ê "„B¡ÒÁÀ` Á¨!„Båƒs J¨ 7#“.½*¥ ‚JHÁ]¥B¨6¤o2Sé‚ TùÞáê¾ók$0ÈZ3«,¸ô{îÆÌFU¾¥ëÅ×ßÌ$ýfdå)¼øš¡Ú `BH™¬Ï1‘¥äÄoN"øý*²›ô§Äob#ž¯Ä2+h"`{¡*Räí•6ä¹Ý[¹2[ä¹·°ܘy'©Ü=å ˜›‘U¼ð!T]²Z·«««²úH%(²[ÁËxù.è(n‘+®,B¨¥[t™·FM?%/­ü7®ÙÀ@qS¾²ePÚæ¬ IDAT| ~+ ^¾·Ƈ¨†å¶°ùoÐÜÞ×Üíe£ ÇJ•¹`7…`l“ï±ÈáâO)8¡Ú–dnT1‹š ŠTÕ4U]x„ª%U7P'«}Ÿ¯Ñ_LšYO v}äö·ˆD#m¹C䟿¯€‡0U>k*5Œ?(BH‰_´²®ag~TKxUN‘ËÿùªŸï©|‡K<'"㯰á¼2ÃiM~ 6ˆ *UÐÔ–>ùX¥(<¡ÚÙš™#ñCOd7Áá¬æ¬¬&lÁ2˺jXüÀƒ|µÎwÒD')ÛÓU–•B5O¤Ï­€B}¼-~¤fõNfužfî©,;µ>¼Š/¼à ‰Ù!„P Òî—2š_Á Å_"G•ùSº`GJúËEzà”;^Hð|B[MV£NÁ‡‚j30È §·çnß³Èb(;J­Âãõ„P­™jœµ[æ³¥¦Ê·µZe–>b'k ]]àé•É=<ß>E¡ê%x©WõØ 6T¤JÍŽ@ÅÃmMY#O@tTºÈ%Å"Yçn/HV™Õ•y&³Ú‚{¿/rC2ÁÃs_µ|É ž Á¼ªm‚\â‡p„äô10@°qY¥ð me"S­D6 ÆR)8}¶àߣÈrË,=S)‡H<‚OÉ=Êê"·„Õe5\Æo)þ›œ"iWzzVU§Y{j¿k¯â!„BU{ Öàà™’*~27B!„’NzGAZQ{‘IºF¹CEk¬¦!„B5 F†¯< > „B!¤M5Òc^­‰ÿ¯à%êôïÌCÒ;@žuB¥ éòwΗfæ±ùÊ)~wñ²NH1 ÖHä´H?ÉHP׫]I!„B*ªÈ·så¶¿ùÇE.·ªê½Ì Oœ¯e/ecÅ3’»’âû I!„B*ªÔ·óÖ J×$U7e‰©eµÎ”AbG‰rGEÂsŽB¡\Нwo­À “vUâÑÅïᲚqÊ"‹!ž‚¬ÜóÕ» TGµXé" „BHCÂssŠÝººÊÐäÍ—¾à, æŽQB!„–ÕþªDeX/¨˜»t)k.çæ(}š„¬rŠÜ]2_î‚5’Uͺº:\å !„B¨Ìj³Ç k±ñVfÖMæ•Ô/ÃûÜ%€”m?!Ef$H0^Y„B!¤\ $µú ÷L]›zñ¥ùŸb‹UF«ë Ðš˜«›)ÎNÁQ‚á„”r³äœ¹óÕH•“ŒŠ·ëû»k>GT ex5øV©l‘4xBBÚA/Ñô£¸¼cRy~2 ¦®MM_›vt8øŸ©kS2‹l8AuZha”´ 5_A„B(å8v…K$’öNÞ%­@§@gG§ŒT‘4µ×üU¥FµwZÊ,«…úðï_<üû¥Î…ÏHdÿô³»¾¿[nyè%º½óèÝ?Þ&uDævv…k{©=x5XŠ æ,yz£xÔºx™¯QO´ü ÅÚgÜi(s1*E0T+ÿ«…Þ9!$ѽ(lƒæ=’ ¸Çod9.öe šŸ±#'*‰s ø¨ ½£‚ׂòr( Á[nUuîµW#TNåip”­Ycj4YŸµL_›v¾¼é ÅÄ•©fK³¾žÈw J¿F‰drü£ñî7zf?¹^Ù"•M1±(BiÑ6 ‚~D›MÍÏXXŽúCÇqûËŒ @úªD|TP¤ÏjÕàüWÁåzò­á£Áò£J¼t:<4Òü¯ûšžÞÛóf/+ø¢L ¼§ú›žÞÛlÝ7~q"« éßrÞ¼ñ†;pq<+£ÉKãîã]°¹‚¹õ²ÚÐhþÙàÌ4ÿ€~@[mäW/¯tÂwæmö¶]M»­Ï˜¼6 BµfSœ·¯¿©yoSó^__?»~ág×÷w4a}~ß®ïïnï<ºJ§ÏÄãÍÖ}ìŠÂWJOQîîØƒ˜xòmO[¼³Z÷_šâK;yeÊj;°«i·ÍÞ¶p/œ™¶ýäÀ®¦Ým?{qqýœ3â®×zšžÞ»«i·³«;‘LæV6_¹'³Šk­n1r‰ÿ1îúþîÀÅ ~ï©~ßô¡Ú`Þc†vùÿ’¦F’ Ì{̪dQ 0¸~uÓµ%mvlüõûÜ{ð¢>R p!ý<6ûIðÓ¿Ü%bðݵRö0’H2wÿxûö'³áùHÖ³éQ7r¯à6=i65šB77ÊÁÓæ=S£)s7ÁzÙöÛ"÷怉Çûßä^‘{ó¶V›¢*àõx½'½ÿöEðêdô³(Õzd(ø†¹¾}÷w·i†ù ><Í~2ûðï_x^wŸÛØ>r.àzÕE*íI$“sã–õŽæ|)„çæŽvuûáw[ëº ß‰§&¿Xø´ýpûQW÷Ü\xòãÉ/>µ²÷Ÿîå÷q¾ær½êüô/w¿øË§f“©ÿì`neóe‘{2‹¡¬Öª#‹”?Æ…{‘Û¿›½ûÇÛ‰$ãÿ@µ¿V„Pu!uDÓsÖ¨Z’ L¦¬Šî1àǯ1*PEñ·;È aÀ°•ñ§E.ÌO^™öŸí3 $Aôò„n…w“žK:£ÐÌ´ïŒ_OQúʦOyr¸_w2º ÇÝo¸³ö¬—íGÖùù(Lß1}#óóQÛ­rËUeÁÓKD"Î0Ëq£Á0<8 ˜Îôißé¾ôY Íl\„î;Ó§§(°îo!ëI¾Ó€^¢#wÂ]ÇdÏõJ—sï¿î›¸41|v@¼"›¼4åíó]ž³lMo~ÇÏŸí®W;9Ž8»ñßègk½áЬµ¥…$²žðôz"ÚÓ•Í—…”“)‚Z«U ‘wŽ”?Ƶ¿)Šòî ÝP¿Ë!¤qôzñ~l!ÿ…‰…Ï¢ ÷céîqÅjä>¹ëo殚Ÿï~Åì™/÷|Ò+úÜYzš"eÜEE‹¯Ò¦‚×ããñøŸ¼PŠ\âËIÓúôÖ¬ËùE²>g!t™Ÿ·¶´DîÌ)}sNÏ©`½ZZZ|oû 8þ¥?paÜÙáXølaè=Ù-<Á)¤Y[ÆÎŽ|9 ê ¿ÏÖÚ 9’ËÉôÉ15šâËÉôSƆ†²çu·hØ~Ø>òáy×q7ßk¬¬À‰nê£qßÙþÉ/‹@¤`Æ;;M›ÏyºYÏ—-뿼…Ï¢ƒïÄîÇr‡ÀfVV0 )'S:µV«"ï)Œ™SñxvñB[›âòu B»¾Fƒ,Y-ïô œ|O)ÞSnÁÊ6£WJ¯‚*5BUÊ`0§' ê/Pch èGq¾C/{é"‹ûuwà⸵¥%pqÜõzvwä©I¦ÆÐÍI¶ÖÖ‘sð­9S£QA;[Ц=æñ_@xnÞÛç]ˆÜÍ݇Ú|–¨Ííã4ÛÁVÿÃþ¡‘…¿.Œ¾7TL©ôõ„ûu÷È…óâ)Xpj²½Ó©¯×»ŽwÉʺç__ë~YO°+Üîæ½ùöÌÍBÊÉ”NA­KQŒ,Rþ7Š÷(nÈónAÕ0Óã&H y£‚æg,R¡]/uòquY•|SÞò7…‹éHS·Hh r¾ìôö1â°ø€îy³W­”íGþ³þD2™H&ýï æî@ÔŠ[k+g‚3¡d’±íoÉÝ!_½¬­6ÿÀ ãˆG¾ŸuI&@Ï[½ôRÀ¥ç‰fÕÚqØî?ëãÏ’ïì ã°#_jÞžî"?îÙ.p1`~¼Q¼"3 Á«ÁÉkÁÀ…‰ÜôEpGèH’ ˜GñÞÓý"{æf!x2SPëR#‹”?Æ¿©³~û‘¼ï„P-Ó©#ètö) ÅU‰  VX ¤´¡¥7¸+Û4/òÎÁé`)kL[“ûõ®f‹µ½Ó¹«iwÏ›=öCJFhŽ™öœtë)rßóü¤ÍúœÀ ~÷ñ®¶Ÿ½¨øv`î×ݽÿ»·ë¸@wä¯Wëþ–ørÒqØŽÃöx<Ù*W¨ÂÞÚêz£gWÓnÿÐðèÈðZÁ6×ÚsÒ£ßaÜ÷ü}Ï0ž“ÂÕ²±ÑÐÞ¡°-¸1ÇÀº/r/:úá¨xÄ fl ‚S“Á™`àBöô\ÿö½ëßÕ´»½ÓiyNh™íüYžLÅ”ÕZõbd‘òÇØü\óŸ´í{þ€žÒ‹¾[Bµlá³(›â²&,.ÑìJbá¾Âu²†x®Dghzäƒá‘sçàúÕëíí§ó7EæwVV”ò5"Hp ¾àÕ*²£¤”-wcÖÝ pìPUã_>ú«ÅJ•–뵞öÃvûa{¥ ‚*ïÀâñ“Í›Éz‚ÜüŒ…Mq±û›npž›ëþ÷ øèà£z&à9éåÚŸcoX¿ôfq‘‡g¥øØâ‰ÏpÀ8¡6”çn¯ù®÷—®ù"Òà©6“ºçòÚ4ýˆVTË+ÜùX¼sl‹¼!Ulº·±Ž ¤Ž¾çq!‚·Å©ÍÀ@dŽAú©ôÂ;ùFшïYÌxuoœù@|U%ÁÂdþW­R¡ ª±{W0GeT,ç®ïï6 £çG+^’*¥‘3 ‘b „j A¤NFC^( ØV›È™p¬ÊžªLúQ™ý!²²(EB¥€ JÄÃwB(WÓã…çø5L"ÁÞ€ B!„ÚÊòFy``€P ÏÍUº!„ª"bÁ‚&ñ¡ð!A¸È,B!„ä(Ð… ‰ÀWÏDHü{A!„P.áK‡©Â‹4 „”Áû „B(SÆ0ãŒH@Ú]ÛköÎÇ!„B!é°Ç!„B¡š#­— ö „B!„´ˆÜ„!„B!TR pU"„B!„*ç „P`S©#Ž÷ËC¨¹^s«’N]]Ýÿ!ø~8T [kk‘)``€ÐB¯ÄLõæ’fÁ¦€ÄÏ•JH¬pýgú)=åïïSœH÷¿÷¨X$„P©ñC-Š_ºº`Ó?´ouuµøw~#´UÐÉhàóîáýŸ–4—Þ mCǃ$¡üºu©->J†æéØÿ&Á¦@¿46ög ­©R©Ùnä¥}¶þ±ðÛݶ_äü3‘`Üc)2—HçîôcÓ‡w}g:Îø‹‰ >ü‚rí?鯂§gm•lþ¾9©ôF6|kN­ ™!Ae¾•M¾þ„RÏáˆÍýüÍÍs?Z|¬‡;­‡;“å=íó¼õ†£Ãá>î2î4ù‹HusT #Aè€ÐètDÆ€?„I—“B¡ê¡‰~1"œyŒP‰,.ÏMÓÞCÃ3Ý¥ÎË?ãœì_è² ’õZê7HA÷МeOãÀ [ô«Dä+.¥¹Põ`¬'¬û›Í{L½Þ3@à7K‰D‚å8¹]|Tàš¸½0h9Ñ7?Ôk99õ»õçCsïöÒ/tÂýh‘ýì#:–"&Áâ?ã3?i€ÄJ¢¯×¸ð¾=8Üß§à3~­Â:BG0qfn~ž]Idï§ÐÆ£Åb168.Å %Ü·€’‹ý–ŽýÖ :Âü£YRßTéâØ8ãËíÒ÷Ÿ||¶t…©y‰o‘¿FâßÄÉ„¾^o0šŸi6¥ËQ†•ÎÂr(Dx‘º~”¤ùŽL†þ4y¹áè@óÀ± ^3±AàF̲§±ý`3“äŒ;H“QÀ1I6ÉO2Ÿ3fÕùo¶‘ÿ­ãÓÇ‘üuqi²£‚3Þ–³ÃÑ¡~Kï@ú·ùDßü»ªÅó43ž2~8lj4ÑhÓNÇqà:î œ xú‡û”|̯G ƒ¹ùùÎŽNý}î^4M³;77g~¢Ñò¬5+6@/þ™Ïø¤@ÿ¬ßÔ¬tqÖDÑY[ß—b ¢ž$·ml_ØAB¤¬e«% ÷"ÑXÌqÈAP $›b¹.t+dzÌdÝo-Q¦ê™÷ÀV>BÚ‰O‡¿¸‚ŽL/)ÿŒsö—§~ÐTl°¸”\xt³G>g¢_ÒÌr2™L:Òh  c³ÙÄ$ØØ×I“êzÙÎ¥@_O·Â±„Ôu~6E¯÷…ßèÖwÏ¿ÙÝòþXt¨ßrr :Ôo:î ÙØ>™··¥w`~¨¿˜Ø F™Ã)ÃØùQ¾´™É„ç¤'pqÜûvÿÀ/”L_«5Á®$ô;ô4½©ìoŒ…Ïb¶ÙºŽuN\7LFƒ€yF¬•MjusL§†‹kC'!r'ÒÞÙ/é9,ÑK_nl‚ùzÚúƒÀ6"2õ?L,d9®ïHžgG.ÅÂ÷’,¿…ΪÙò¤ÁúTõ'ôžò¿7\éR¬Y¸I®p/»×¢KI˜wRîÃŽØýhäN¤D±:s Vש’BH‘GSáø¸ûÐ0è ™¢Yà gnwî÷ÎÞð£)é)‡ï‡è¥¸sh_îoߑɉ#Ž»¦nŽ\î_è¿r4‘¬ü|ƒ¹(£§¨Á ӡ߇).f50Ï‚cÛH0ô—‘ñ+AHq¦ŠYæèo¸ä·›à8Vz#/ísMÜŽž´¼Þ~ó¨ñ„ÐÔëžð[Ý–“Ñ!¯éUOø¥v×âbä§éUOô]oKï@ò?Æi™lÎLGt¦É_ F&™=·ï7p¿ê4ï±ô¾ÝÏ*›[¢Û èH€Í?ºµŒZZlÑè|öþ¨JÞZ´t÷íy«gìü6¤`ŒOt0ð]Ôdv3_ŽWºD›LÞb§B-OrC6ö^ÿsùÛðDø€c0‘Pôц ‘HD?Ù~hëþ ÌØ[LV‹Éò„NrÞ óæ'-ô×4Ã0¥È?ŪMáG‘å ëÇ~ÐqÉ 3 ûàÎtr~âæˆmg§ÄÄMõÍazòöÈ?&~;’û»ë°'0ãuòß¼üó»GßÝ7Ð1¦§(µª¦@ìQr‘N8÷ëÍtE@$›âl)˜ÿ<>ýÛ°ãßl¤d¥ÙúÇ¢G,'úæÏôè{¸û±Îþ¾© ãëžð›ÝÍg‡ÃížÅ‡¡[!g$2ÞÔdÿÝíèYoëÙÑ‘ŸíµþNÞRQã—¦¢ŸÇ&'Æøvy>L2á9á\ôž:Û'k¾q€NàâŸÑ`Œü5)0í41Ë €‚Ñ2 ɺ«ìêìbl±ÍÞFÓtÖcÍÊ­f¥ŠYŒtTo¸§SŽÝµý´MÝÄ¥Ó~oóù0·B³\8&™ˆZ;B*0>é‰ÌìJÄC@IÂ@Ô›ŒOUrÑžð=¶çLÈÝ¡w½l5îØØÞvPo}¶“ €$Uî1`¿eC¿Åb1n…˜M---MfMÌ»P]ô~Ô~ÈøÍ¢å ƒí#¤€^æè8«'VGŒÿ!ælµ-|¶ÐfTÿO „jPh)°°rýØdRkhŽ_‡ËÿMè ÓÚSÒfú®µÏ>™ñºúF®õ¸ùGfz\7ýÜôºúÇoø.÷ÞíÚ×'?69q"wûÇ»¼½YI1ñDû~£ÍBAD=A¬â8N_O„¿ŒÑK Õ`ä·òá¬à üv·ç“OçÏôXÎ GÞê6žè›ºè|Ý=u!`<áIGöƒö‘¦]¶Ofcï{ͧ†çÏ Ú~1&«.Ãç1ziò×cA0Ë •ÿ¬®õwÓ|½g$Ç:Çè€YfG®D£°ÄZ;þÍr4·g¾O,Ï‘;‡ò%¥âç§ Ð=RIÿ[³õzá ˜"±ß²#çF¬ÏYݯ»õz=˲ô=g¾V&δ<Û²@Ç­fc=Á¥€IrÉPÛ q&IÕSq&^Ьq¹R„jMpidq%äü‘—†IÑ\ŠãR ŽKpÃq Ç%’©D’Ûø‰¯Ä˜y)ýÁ‘™g‹wäFë ?p£ÇÕšþíuµú7×~;[}›Þ±Þ»ƒ3ÝÌrRV.Þ^ý…ì6Šý»‚o5ûLŽý&ŠÒŒT¥¯§H‚àôõTp>IzÓN£¾žÐS„¾ž€ïd®¸iûÅØü¹Aó)ì¯õý1æƒAÂ`äc.θÿ¶¸Lé}æSñw¼-'úÂoK^**¾wGææçãq¦ý§ÄƒÚíÑh”‰3ýƒ2æg#"˜$Û=2’}¯r'¬æÇ™£!½±ÑDn#7戆óãcƺmuÍ–æ…è¬Y©««K?Èü/ÿxø½aý=I’®.ÿÒ¤ŸJ?ž»5g;hË}ÌcYÖõš‹ÜN’ÛI×k.–]ú¾ï[^ý½^¯~ml1MÓm‡ÛÈídݶº¶Cm‰orVdªˆH.³7g›ÌMuÛêŒÇ=.XÍÌbçK'_Áêêê†ß6>fäSÛMèL –!½1ï©L-·²™)gU<_âY5ª«« œ˜L¦ºmuMæ¦ÈÈøÄ¸é þ?^¾½à›MqÊ%D˜ˆz¹½HãZT°`@Çõ„~§ƒ¬7’õ")©øù)(ô‡(òz‹)Rè·!k‹ÕvЦ×ë€$É&s“ë5×ÚÓßAðZÐwÆç;ã Î7>%Ä·ŸöùÏúÃsaï)on޳7gýgý¾Ó¾É©ÉÌòH&’¤ É$·ð(¹ø(¹´ÌúzR_Oò×j¹‹Å©„jÊäƒ~š›·ý ^‰Ð+Ñ$Ç$9&¹’Lr?ÜJ’ã’I.ά,Å–çc˹÷7ð]kwôû®µuµ ø®9]­Ãþ™nWëðÈn×AÿÈnWëúï›ÝÎý¾Á™££¯ß¹!;6}o¨ås[~`}/ï2®ÃfŠ"ˆz‚$ˆ¬ÉÄl B÷†a&¯„&/M§Èí2BƒðÛÝ-'úbïxͧ‡cg½Ö7Åá¹°­Õ6Ò´«åãËôû>~ói™=:ðÿÜ3;uyöãË\’ã×ÿ¡ÑyCŠã8îò¯Gƒ *Z¡h=ë‘KQûc-OÑôŠ€±Zæ:¼êƒÈÛ/þCxá/ ÿü¯:Ž8º_ë†õq,éYjYÿåÍÍÍ=\|øÿçq&îíø ‡ï ü§°íG¶ìÇëúûúã_Çÿñðÿxøš¦ûßîç·ûÞö-|¾°¸°øðáÃø£µËomö6Ï[žÿüÿóŸÿùÏÆ'{þ—À _s+"’ËÑW޼3°úÏÕ…ÈBäÏájf;_:"›ÿóüâÂ"ŸšÈnΤœS—/µÜÊf¦œUq‘Ä3ká[áÈ#ÿü¯vë<`?úm(Žüó¿þéèØ8ÿ_#Áw—‚”KÇôÌ@"¡çlÆO¾[v¸¤–Œ‹p²\ÂôŒ_<5µ>?|,!ÿóDq‘b±X˳-ùžýílòÛd_o__o_ò›äìïg nçX®¯¿ÏÓë¼¾Ž÷œôøá'¶Áß”{=(ƒžb9 ê‰$Kq.端'©z‚ª'ø®_=%°XœDìæŸL8”¡ZÂ1+4IQf…æRI € ˆõ¶—â8.Å­ £O È™e þŽ`à†ÏsðrÿL[ß¡ ÷J[ßá˾™ö¾C—ý3NÏ¡±õß힃—}3m}‡®nzûŽ\¹Ñã?&gäŒÆÎ}åhô~̲Ç=;Ûc>;4ÿÊQ÷ß§g¦GSæ_ÆÎôZß[ßÇÛòÞ˜‚9 Ç;¡#LSÁ}GìÒk±.{BGDcŒí9ý|ÌÀ¡G™ŒÌÔo 'ñ±ÿ{Œ¿àçéõôôÜŸ7úá(¿^ê臣V›5½lHºyùsÄü¤™O9óqÚä•ÉÈ#|"ãçǭϯ%2~i<Ž3@ºÇ`1¶qxø—ÃßûŸß“X‘|¹ÿ:ÎÄãcÆñ áù£™ÅΗŽHÁF5š^RVl·aŒ~ ¶Üw`ÔóQÄ—9ãvˆÇã†Iiåto|ß | ª%„÷™±Ókñ6 IDATÀýžùÏB–'[i.šL1óhù`ýqæNæªó¾k퓽 =—l}‡&ûo´δ÷òqBÿ5þ÷‹}‡/÷ßxqàðõ‰¹A‡Å¸å•YOŒMŒõ¼å}XÙÓ’+@äèçÚ‰HÇAàJÈö$Å®pk}õAúàƒD’Òœ©QÆM Öæ¼uÔ|f4v¶ÇðÖÀü+Gùy¶VÛÆ|ƒ“}‘7Ö'cg{ÌgFÌ1àÁ¥¸Hg—Üè„1O|:ueŠ~°vÌô¸©ï¤‡y6È7Û„Kµ¨@,Þ¹×76D’œs㪡.ëpaé¦!I’ÒÇ5™žX‹L¦x\`XmÁ ñx|S"Ëk‰ÄÅMÙÁUd>â=åþ5*2·[°"ùr™ží?Ûï{ÛGQÔ臣m‡æ f;_:"˼á‘ÈnâgRÖ©Ë—š`eóM]I<ëN›N¸´7’Ä7›‚”KÍÔ2wœÌƒiã“­Àß„GX˜ÓÕ¼Vüç§°m@ôÉ¥$ËBÖãH ¸Kd"™h{Nà’¶²"Qõû-›Ž øx $W’é0R¿CŸ\ÿTÌ»=™L¿Ð¹ñ*¿ÃàP1÷/–åóÔ•©Î—»b_'˜gÚ±vûùø2Ç|“p4M]·X”,Wºé* Ð;<ï—ÞÔ5k"„4ƒpï¿ß¹j~Ò+Àpëý¤| éÏŽßHè(¹ Éø;‚Ã3Þ¾C“ƒ3í}G‚ý3í}‡'×~ßhÏŒ:f'æúÏy&ï ú:F•UIOQ“JZÏëÖjºÇp)0R—Œ“©„å1Šã8 €Ôd=A¦6¾¢ÆoFã+œó Œïѵƒœ¨€ŸW`þÕèFlÐëOÇ-ï_VÒck7 #,–Fþ¿Ñè’i§‰~@wëä¾å˜e&úçyY—ó7ÉúÂÐÅl G“öÆÈÍGbvʲ¾GXž¤Òw<>P ôW4ß|¤—hCƒÀE²Ð­Ðèû£¹Ó ƒ`"†z‰N·MyíŽöÑGí?µ“ÛIö[ö_þ¯‘XÎ|¹4?×<{cfoÎvwu .2˜Yì|éH,˜ÈnâgRÖ©Ë—š`eSO|‹c¹$Õh 0¯ÿqq$AY ¾ +©¢??…9š'®ÐKïkÍSša»OO3Ë· ]Ǩ¶ç„o¬ Hf³yþ¯ó¶V›à³T=•H$ø&~â›UOÉØž©OQ”ç„'³¢ÌÈíú–––ÐB}öÐgñ(ˆËQ:0êÁ}к9Í,'#ˆz¢ÙÒ,’›Ú4YNÊØá9uuuÓצ þÈ©#B¨|\{†ŒºæHtZ¯3ëu&Žã8Žkn°778¬ vkƒÜÜàh68š([l9 )¸$øgœÎýžÉ¹Á¡WoOÞ:6›þ=z,<9?Òwh²¦½ïH0p«ßañLß x¨4¶U©ô"Çq¦Ç ô7û:É¥2ÖhÒ­ýLÎÅÂQºÑ@°rn ÇÏ1ˆžé6žw¼èúËB:*hùø2ó®oc.òý˜þ„/zªÛ$wŽÁféëÁÜWKü~^÷-Ç<¢×žVÐL:„¢ï¸-cb_5S:»e'¾g‹~™ð·o:0%–H>EÑ_Ñùþ =oõ$¾I$¾Iô¼Õã<¶1뚟BšH$b_Ƭ?°f=Îä|ÙÙóæz"oö8_^KÄuÌåzÃÅ|Í$ ï[kW9Ž#‚$Hš¦ºŽJ¯H¾\œÎÅØ"?1=Ÿ'³šYÅΗŽÄ‚‰ì–ïL*8uùRË­l¾”ÅW¦àírß]Ú”ü&BPЙ€´²œž]!´‚Τ§,If¾Ò¥ð½LGô_ Çg6†®™ŒäâŒsñ·’0Ô¼µ¥íǶÈHøVx­ÿd¾Ž‹ezfšý–e¿e§oL[,–‚ÛC7B,˲,;=#Кµ¶X§®Mñy1 39%µ‹FEMO5›MSW&šw‚ç°i Ãì9lji$ƯŒG¿Œ™MöÛFΤ?È'ß\‚|„ƒëW¯;:R~ˬ&B¨LœO4ëí‘XˆÒ™Œ„…ã€KA(:º7ŠN…3~BŸOÐLÌþ„Œ¥*†Ïú.µ·?çéþ`_»ÅùÛ9Ôì>4à»Ö>пÙßnq‡cãîC}¥«iakw+’ ô$V€I€ýuâO‰ñ[tôK†Yæ˜enáA28G;ß›þC\¿Co¢Y·Š¶ ŽÍ ô´¼w9v¶§åêõIk³µÅ:Ò´«eâòÒ;½ÍޝŃÄsbÈg~g”¾0b9î (šà¨ƒµ1B©:švš ¹Ì@º—DéMÇ8ÈìHÒÉ@]ßÉ,[&f"×Âgžý•ËdГë·8È>D2O¯§©¹)ݤËú/´îoÝÕ´ë{ÿó{”žøÅ@Öáá?„m?´ñ+`f>Î408`0¾·ë{ßÛõ=ƒÑ00¸–ˆÿ~³ÙÜôtÓ®]» ;×.WMŒõ¼ÙS÷ßë¬Ï[m?¾B)(_.öìm?k«û—ºÞ·zƒSÁÜjf;_: &²›È™”{êò¥–[Ù|)‹'^"¹ï. b‹Ä6‚$Ì¢è{þèͶØœô¼Rl7$Å~#¯Ó Œ;ÈÛÛ çl,pa3Öía’W.T¡×ëÝ'܉d"p.à=åõ øÂwÂîãkwrhûiµ¤¶Séeˆl  Ž ˜L&"§gÕÖj3™L ßißä•IËSJnN_¼¦§š;_îd1á߇&.MLÿ6_Ž[Ÿ³&âL"™à8àcƒÅÏÕ|?ÔÀêê*CÓ# œ;ׯ^oïîýÉ>¸®.kgíß:¡ÚÀÿ­Ñ_XM/üh"üõ¸ù1—JëM¡Ï'F[¿(iÁè¥xðÞˆëÐ@à†×Ùâ[`Bí-]%ͱp‘%½£žãv&É‚’  —“T=¡×AìÍ,'“ß$`IAHI?XxÙdÚiÔ×SÖÌý(ÍBò?Æ[z‡çß:Úxjhþ¥[®^_z¯×|v4v¦Ç|vtáM§þ¤?1äk>?I_ð[z‡Ç»¸?¾­`ìoðfÈÙጼÖlÞg–ˆd'8Ç`üÊdûA»”Z„çæºÿ½ç‚@G #Æ? xOù6©Ô™îšÎhê 8ìzÙ)¾›‚ƒ„n…\¯©p¦‚_+®×\Í{šÝoº³W‘ò[üLf•AÅoó*}Q*ˆý&½uÀd`¢ƒúǦg‡Aô_} zÊhéc¢ƒ¦Ö Þhú«EÓMüƒ"3åÿüþ]ø "óYÛG¼6|%ñ-„~¿š‹OÏ1Àµ“èë ÷!£ãÅø˜~a©(*ž›S夠Ä7‰Àŀﴯ y©e!º87bÞcÑSzÐAäÏ‘ñóãü›'侮$üøÍqÏI/äý®^+°6Sæ$ßmY¶]„ŽšþjÄl´ä.ËS þçèë·¯u»öûéd¤âQAýubj& ÛÀñS›‘"˜e. @5˜¨€'Kq·6ò~³ï!õ:“{,p?Jÿ›k~ÈÛòþåù·ŽÚ>™íIG±3=ÍNÆN¹Š øÉ!pGŸ#’4gÚiêëèœa#å®’â@Gpd½>sΟ –eI¹>k¥o³Lá[aÏIOîã*¢…bg–a!º`0¨6Ü_ µ«.ä«ñ1G">g>8KîX‚ej wÑ÷õÙù¨@ ôÛÁy¤Éy¤ Øï€¬ž[×ÍÞ˜µýØ)˜¾1]©Åš-Íî>6€W̺¥¹ÔY•{ Ò,«ÁAèôS1¯I_ŽÏ>ß‘ÉþKG݇.f{F£ uø–þMØñ0Ë0}#ܲßJÕÉ.Éq\ ű.Å&-Q:Öò¸‘¨'å®ÒdFk¿ßW!*ÐË4—L®5øÙ$¤ï]ÐÉ»MÛš€¸GѺ¿eêÊD")v'’Ò·¶´@j}}y×rÉ\†\pIríÓB±3˰÷_÷ýRµIAZ¨]Õ\wˆÜÑÜÔZîõs_n·Þ”º³Â'JOOéG†F8Ž3ï1§‡U‘fK³ç¤gäB@OéûNª9XWê÷ÞÔµ©ÎŽN3F•MsC«þ©ÑÀç÷iRÆé;2™Úúdk²“‚ £žtýØ`Ø`Ú™œš‹P;ôÆБ\ ¸•D2™dLóc`ÖhÜAQõ)¡O㓖Ľyø7×ü·õüõùsƒ¹¿ù¨ÀõëY82%£S";/ʃµF|æ)WÖV*] ô FÇaGÆáÄæ}×Ó‡MQнxáI-ÒÏäêwxÎQ^“ÏÊØ;Rx—аî·Z÷+YîS;šžj?/|_”bHý®˜¾6]‘À w˜#?l ¿*’ÅDµ¸-—Ñ’ßÈÓwd’Õ%šwæ½Eeù)b¬·…ã8¾±k4-O$B÷–¢K±ä·À¦8¸Ìõœ¥Uo6PúÕ W@ +IÓS–è|˜zÁ5ò³½¶_Œåþtîsýz6¹’0F–ãdvpÌò<“Œpõáñ›½ð:d^Œ Ìü#ê©èÒœ±¡ÕDÙ¤­^ÊßͰrðCЈµ9mþµÿg÷È»eB!-ðÓ äv”h"òêê*Ni@HS½Ùc¹\ê\ˆzÖÔ`.u.r‘›ïaL„³l_aÙŽc9€m@貞 êõT=AÊ™]°AzŠ‚X[퉕¤eún|™q_½ME»¦n'âŒûêmn…óLßåR`$ Šú cC«±¡µùñ’-ô”6nŠ·ŽUûBH„­µµøÕHIßKü- ävð-ø"cì@HEÆú$Øi{ý>ýî‘ð;¤ÉÜG !„JE¤Ž½VO­ÃÏ[„ªN†Q`œ_{ø w{áÀ óÇ‚â_$ÒcƒÜÇ8j!„Ê¿ûªFùn>€P–ä —` Œ ¾óqZfwA¾-lßã5*„B!„J!¹ÂÑß$ FP00Èì.È·¥.GîØôG!„B¨lèo’ü”€'äëÈÚ¾š#óYŒ B!„Ò>±9EÞ»£„Jª +Q „Bh‹ êêê®_½.~dÜDЉ ÒC’2×&܈ÐÖ„SóB!¤"áÀÀÑá€õÅIóývt8Äû$¶Ú³vË\’Hqšmøç€B¡\Š/ Á«Ahïhÿ-¥c!T:¸¸$B!„23Ì8ïƒàµ ø‘ Ö-EŠ F~xÁ!„B©¥ð Îʬ¤ó•«z2tîrO•* B!„ª=bÁÔµ)ÁÆùfȺñ²Šæ—'ß’VÙ áE枤“åŸÜXdšÒ“B!„B¨¤ ¹ùº êêêr/„×­ËÝ3wcî t"¹Ç ¦)%wj‹çf$Qnï‚416@!„BWxò±£Ã‘ži Þ] ÒÖO?Ü(žfÖoÁô%æ^0#‘}Ä¡2HO³˜ ”ÆÄãÑÏcìJ"û Æ½é ³±ª@ÉzðUV æOZÍW!T…ƒÎŽÎt` kvêw(“u¬ÜŒŠŸôœÛ²—[`Œ P‘¢ŸÇ:;:õ;ô¹OÑ4ÍrìÜÜ\â1CÓ“æò—-×®ïï~ø÷/*]Š2Q±²Õõ*‹(ç@S'­×TBÕKÒr¥|§HwAAjµwµ6ä&·×¢¤«*!$Ž]IèwèizRÙÜ ŸÅl?²uëœøh\ß 76*TÆ­¥M@|•¨ù“VóD•G9<¾£ D‹I—µꉫ› ¬41*@*Ó‘›tÀq´ì·ÅbtÖîôÚÕÕÝôôÞ¦§÷ºººdï0~qb×÷w_œÈܸëû»ùŸ¦§÷:_é¦sŽZK|‰v½ÑÓܼwWÓî6Ç‹¡›ÊïÈÈgZÌá·ÙÛ²6Ú~Ò¦8ÓÒ^—ù*'–“¾·­ÏØÕ´»©y¯³«;<7¯,ç¬"~~Ô}HÌ4/™' ¾ù›÷ö¼Ù“H&‹*•Š4ó·ŸoŸôöô¿]áüƒÖçðgÕõFOd~^pÿ|'¹Ê^)„4IR`¢³ dÉ×V.ç\Á‰ÎQ6Á)Å"óŒóåR0Mé©!$ƒŽdý ÆÈ_#¡ß‡!‰ä¦Èô£x{çQÛAû§‘»ŸFîÚÚv¥Å3÷¿2Ù×ß7~e2+«‡ÿâáß¿ø4r×Úbéy«7·,ôÝÞyÔ¶ßz;|ûáß¾8;ºQà®ê•EdæÍä÷æÈz²‚åÉKæ«Ì,ÇÛíT¼:ùðo_Ü ßvsŽ_/u1µõyÒxâoþ»áÛ„Žôžö•¥…héo_d~{ú‡ßØýf—‚àÔ$VÛÛGÎ2wÎzœ«š^)„´#µéRñî‚Ì„ÄÛ÷|û˜'¥5œ¹Oæ±¹KIÉ]<Á¼Ä7f)kg)ibT€TG:H$Yß…H›'Øæ ú.DˆzÊü¸É´Óh~&{ñÈû#®ã.ç˲ž ë çË×qWàý‘ôá¹9}½Þu¬SOé¯1“õ„û¸;ö –ûÔȇçÝÇÝΗ;õ:hÞc=?šµO¾ËÏá;ó6{Û®¦ÝÖçL^›N?•uÉpxh¤ù_÷5=½·çÍ^–ãÒ‰Œ4a}~ŸÜë‚îã] ÍåÀÅ€û¸;ý_6Åyûú›š÷65ïõõõ³©ì&¯LñãÛ~öââ—1ÁªÀâý˜ÕºoüÒ0â®×zšžÞ»«i·³«;}-S Ù¯òçËNï ·Ñ`è)ÊÖÚ:91Æ?›¯$‚õÊz_”|Eß‚'M¤0é×T‹@ä^4‘Lص¦Ÿ $¾aî†oßýÝmšaF>¤ŸšŸ§'¿XøÔ~°µ÷t¿`âá¹¹£]Ýþ_ø]Ç:ÀùšËõªóÓ¿Üýâ/ŸšM¦þ³ƒ2 *óUÏ…y_‘’äÖ+ëUÈ}Q2‰¿OšHaÒ¯©x¦yÉum D~_¿z]­ñEi¥PTÕ—çë6«tq†é`äRÔþãXËS4½â`¬–¹ÎŸÆ¯D¿“ËɬùˆÆCryí2-ó(ý,f?lûa{ô³“1Ò€¿d»»yïø¥©±œ®>q½ÒE ‚HÄf9n4†÷™¼2í?Ûg4H‚è;å Ý ¥Ÿê;Ó§§”dízÕ8? WFwLߘöîÓS”¾òŸé Íl\x§ÏØ` ¢ë¸+v_àâèä¥)oŸïòĘíàZ¤ÍZ[ZH‚ ë O¯'ò§HîQy÷*gÕ)IÁz‰&.Růé™'MüÍÏK$“ƒg[~Ø"’mhfÚwÆŸ~Û¤·ç{;MÏLûÏô ²žðý¼/Oª*T°¤û"ûN;?Öh4xOûv7ïµ>À?0˜X‘!¨õJ!´…E»*‘£ÃÁ7ýA4*ÈüÞ_ŽGûKí*&X¶ÄKJ0«Òº R#tD4ÆØžÓÏÇÑJp”ÉÈLýÆ:æEQÌr<³}À,Ç©õÆÜø•Éd2¹»ioúÙñ+“¾^ÿ˜¿^Ë<Š÷œòF? Ù žP TBil0v~täÃÀȹQOøû}¶ÖÖÜ}âñøŸ¼ xx¾UÛÓ ‘|›Ž‘s#¡¡Ø—±É_e>•\NšMücS£)¾¼1øG_¿–I_• |4ÞÙáhÚ³qÝtá³èà{#±û1Nþ%RÙ¯ræW™¯{úTˆ”¤`½Ä‰¿)L‘+ñË=iâo~þìõ„í-Ãgý"ùÆ—“¦kg>ýþüo§x<™¹[é*XÒ¿}‘}ÿôÈzÂÛëñöz€^¢'zÞè™üx,wÏ\j½Rmy¢È ‚W5=/!Ä+ØkÄ¥Z T ï\Šë"IÎ Àü_üæ¿{ë­Ó3!÷ñ®ô–é™õV`SÜôµé»¼þFgÅÛíž“n2£aÜi}¸ÍÑÞºÿvVóÑúëôÍ?rFËqü™ãì›ö˜Ç= á¹yoŸw!r7÷@ƒÁœž”µcáÁ':p½êêñôzz=YçŠj èGq¾‘G/Ñ”œvjpj²½Ó©¯×»ÖOuÏ=¾þ¾Öý6²ž`W¸ÝÍ{ÅSÈ%ýU¶ýÐ6}-ä~½K(J’Ä7@y ÓxÒ ¾ù¥b2l~Û¤·ç{; ½D+‹ ¤WJü·/kŸ,¦FÓ@ŸÄ—^ÅW ¡-!TÁ5õƒ©kSÁ«ÁR¤Œ ‹ÙŽ&í-Œ‘›Äì”e!|°¿Ïh0–¨‚Pâ¿}‘}çxN¸ƒ7Bû~r`×÷w·¿ÔÎqÜØ‡bdšŠ¯BµO´»ê`uu•¡é‘†Gο~õºêeÀ„T÷âK/®®®Ò_-fn ÎL{OùX–:ž¼ŽÆ°ÈJ„ª &5ö ™î!Ü–ñþÝ× |•¨ù“VóD)‘'*Ȃղ^Ï~Ë’ÛÅîÔ˲,©Óä­|‘4ø*+Pó'­æ+ˆ*Êæ¨@d!< ª‹yâÊ›LˆìCÖë-O¸ÓÒ2|•¨ù“VóD•Gv`ðâK/–"¼!Be`l0[e,܉ª¾Ê ÔüI«ù "„’6‚(mS`ÐxRÒDj wØ(¹£Ô®âÊu ת²ÝW›s'yU²–h¾¯$1™VWõéÇó0~‘}É€éqÂ~:‘Í–é¯À7À†oA|™34¶Vèë'›Ìe&›»]J™×r¤Áÿ.º ñ8G`ÙCØZ¡óe²é)5ë¥L»q8ý8ÈxÓ:1ýAdáÎ·Ì dóþFÇ «ñ ½à@¤y¿ÁýK»Þ¸éS!üñBèRŒyÀ€±Ñhi5ZXLOm:±Êˆ¤œ.[fr·K©¿éIýðœK°ïÍÎ߈妙ÎZü È­…Ä×…j GÿØEê³+’{NB¨ªáP"Et£¥¼"¬Áî‚ Êé+(_wAá·°2”o¯®êWWõ«ÿŸþáC½ç$éëcæÙ'ã'3ß6|‹½\$Wÿ©¸¨w½J.r»ŸN¤£´^Š/ßRÌl/.ÌÑ#]Ó–ý¦áßuM>ôÿ®Ë²ßäïš^¸Ig˜><Èx‡ÃA<¡M‰¿Yøí9oŸü»wrÑë~Ï›g¼?W¡Ø¢)çÖHp»¤*0^ vP‘…5èÏ™$“LSR9eÖBúëbë°L¼©;BÕ 4mˆ¬¶ÑÎW 8MÀÊ:4p› ›ÌÛ€$ÁÚÁ©÷)ó5ô¾ÅÞý#é|ŒÆŒ"¤÷KÓ" +,3ó5xO±·CdÛ! ·lãcàz f§å]2¯—º ;u&<0ÝiíhÒï aèwÖŽ¦áéÎñ³áÄׯˆÑ¤wÿÒ›ßtCEÝ¿²ŸÐÃ6LÏÝçíª²) VçìµN¾7ßeoŸˆtž¶).§¬ZÈz]œ½ÖÅ{ñÅyFJÅB¨za` N-ÈTÙûàÔ9¬ÏÂÒ#®àn™×¹Ðonr›žØØÁ?ĺOúÙ)èw€÷„ì DPV™G>`Ý'Hr{Înûz$²H¯—º¦/ÌÛ_µdŽBá‘;HûqËôÅy‘c bÓQÜ Knß´ÅhÒ«rѺt)gUgzÎh|‚ _ÛÔi°x‡€¦£ârʪ…¼×…÷;¶‰S¡Ü`!„j 2aT¦t :*{Ë‚*Œ òWhÜ)VŠÜÑùöŸÞSl"Ï›ÐM°~Ê~æn))d–¬2‡n‚­Uv"r륮…9ÚÜj|ª¹Õ›îXaèDà‡­‡Í™-Í“g#ì·*D\YJ‘²`Òœ½¶à›: ¦Þ ;n-¦œ²j!÷uij5™ž2ÏE¤$ŽBU 9*{‡ãÊ©x‹6F21 L~ í/±¾Ÿg¿ÝêêéŸÜ/L²+ð½ÿ™h;ÄÎóõ¦gã8S£pކ@/î[fz‰3í”tx1õRWòQ¸S¸/¸SÏ<ÚT¼vã0ÿÓc§?ÛŽmš íþUÇqÝÍþW‚áŒjíxS¯Bšé)½é)Ãì¥þ¿‘›4±ƒ0Yĺ –SV-d½.¼®ÿŸ½ûmë¾÷Çÿ>_’¡ê¡cœ"™vä„f̺ë¸ÖÚ1«M©å¹\[m!R¨”jy.ÜŽÅNFc¹¡µÒòiì–Oj¥|²8…vv!›œ7µ2êYËgr¹ëœË²Ê¥>ávX" ’i†e–€¾÷øX¿%K:oé<\.ÖùùÖÑI÷z÷ûõ>'Ìþ®†…Š$”J@b7eû ”{6OÝ¢ô¿²@©öI‘qcc¬÷±ÑS¬³'y›Lå¹"¶ŽxO³Ñ%Î~ ~7ü(fÛ_Þíù´9´}¯Ì6ü7@ªÜýÍWý®·ÍÞWüAY!,Ëç›æ³ó.󾦅ÏÃýæsÃ=Sñ;¥hD鎜ý+È9^5M¾7Gâ„2ùfÀñj¶ê‚|ÚYÒë“æ¿Í,Ç:ŽµŽ RWÔ$ 7¦FÍ›¯|Ãz¹þÃ9 ‚3 ²gëˆÃNÆ?d—–8r—ôºÖÄêÐ7Ò*òÂïÝ>[HšÁÙwÓ\ÏìmÖ= þ‘í+¤Uè÷*-m†ÇÏ„ð?búéÿ‘±uİ›ï;Ý9þfrÊÖÓ3×)ËØ¼‹rîWS¥jj–#k2ü‚šÌÿ"²|‘~glÙ1õÁ|`"¤kÒñMùÖxd¿y^Ÿâ~ó>‰“´S*Ô$yÈkrÒ‚Ch¶J Ò@iAhH®ÄØùqßTì˲dô4;yamŒPgñg($ð_"ëµÚ4½ð¢kÈxyÒ¶¹³ƒJQº|®ß«´²ÌÏ Í†¹‹ôqË72wd°Äyœ¾±¹æud–E’ožX$®iÈñŸ±ì_ÁzÄ4ùþœïÝ9Ç‘Õy¶3ÿµEÿ.ÎwÌãoΕ¤£€6H #"Ú lŽë%vòÂjÎ3òAù  oœ¡Q³…hµk_Ë}„õ¾ÝJ>Bìñ¾ï;²2š~Jü“7ó] ÆG k³û;ò^š1?S‰ñÑ9Oþß«´¬/µø?¸%7/~+>ûÁÕΟ·dÙWø{L«Ûð²­Ø­ ÇÑl!šûJÐÈœGnjÖ§’ö ^ZhzX—ýÈI_!‰žçŒíM†übE·³ ëSôï¢ç9óÁ¦‰! (€špoÃ'$¹ ´@ަî UgEµ‡ÛN¬{4cÖià°Çç¯r—»$tx>îzim•þAròö±'âã’Ø-Bî’Ø-2þ!yì‰øè)V/«#8ÊöÄÆÎ1‹ˆÝ"cgÈàñXßáÿ’Ú¬œ|“m3ǧ.1=2üv¼»'~öLaeüY¾WiqzÖþ†yÐ:¼ŠßŠ“»$~+ümhpÿD×›æ¤KâwHèJØ{h2©x×ëò ×bb³Ã ±‘_ø;3T÷*û‘;_2M¼5˜ÅoÅ !ñ[ñÀ‡¡‰“s/e|ÒŸé+$q0»þ—¥TíÌÿú÷»ˆl/™þ¼™÷tÐá^ò†’H$‚0òî°o‹Q6ÑLÙiˆd=»ÊƒÙ_íM$™ÖKOÇ“†×çÈc¦!$z“«¿?cß´WpŽŒ}Ì’7V5[HÓ4ÎX×+6®÷P<0M"·Wu s;x•5¤ÌQ˜%ž7ãW?_]^&Z-i~Dã>Êše³æÓfñ ¡rb(îŸ^]¾Mt:¹xY~Wòq6ù½Šw—8¾ï\òea!6ùnpþÊÕÛqMkܽÃú²Iþ˜Ü¦–o¯¹åÒšŸk6?o WÃæ¯Ëÿˆ‘-Dÿ¾õ¹&KW þ»Ï‘CW“ï…«‘åƵ÷±üÃ:ëËFÃîõ!7ù|i›L¯HÚ écövf_›öÔùÿ.I þîvo>€Š~ÛÓÔ-\ÏQã˜í~±7ñ¯ó¦kl&ÇAïB÷7_ß/ûGÞyï4ƒÌÔšLo-P^d&·…’#1€ ³é‡óU¿øæµðõØHxÖ¡t£ v”>1ø¶»@žÐ44„*jÍ èï+ ?+(¯<š”å‘9äTôû'ß L¾?/}Lz|^n›yt]á¦Öô@•IA$¡0ð¡Mq°ÚUáÕP¼´ èЊÖwÆ6ùN@³…h8ÓsMŽ£Eͱ£ĵ ªÂ°‹ å,8Vý}¤º ¨š†*Æô ozÆ©t+rÉÜ]@0+QÊ"‚ÌÔž ‹€ÍÈšÄÉ”œT9Ôu ¯ þ¥ÀfäÊ z 6PkìEÿè—ŠfRë •„ˆã[˜†H޲ÒúÏ®xÁ1@FytkÔš¤GS\ŽD›’_V@0”(?5›P7@q°®lRÞYAèAÕÓñ £n ŽåTÿO6«¬€ Ç ˜†HhË *Nµ‘ !DéÒåP— ¯ Éæ~ s»¹Dí€Ê;=ÆïâKv¸» ˆª©Á¬€2vz¬íuQk|ªÖÒêú RÎŽWl^)6€j¨²Æ ¯Ø«6K `Úº po€r‰¤U›YuÝ(- †úƒ߸fë ¨Ë R¨:+ é‡uRÙP"µ†_4f(-PÔêÆjŠ”œ†}YϮ꾢ôo@Q]A6xeA¥ –ÃÕ%¬¦,QGT‚WÐCÁ‚côBÒe=e‡ADY¡´ ÂÒf„® ±TüÊê²LNš¤Öÿñ…2e=(-€LÔ6Ón% DM‡'j-- qt¦!’«évPÕ†‘þN$ynŸÏ–›WúsÝ£æ ‘¥¯@T»=È ä¶P4ˆHíu¥ø!èﳂ*•H$ÄÈ;Ïø»2)A™Îœ Rr€ ÈÄåj41Àtœô¨Âßo8ªÑÄ M±[¥Ç4õ•"*Ñе¥ÃÂÖ±lké°„®…’6¶í±±u,˲–Kh!yI,sö8õz=³•Ñëõ»#xeí‰;Ã0òLi—d?—¸}h!d|ÔȲ¬i·I¸.ˆ™­ŒñQ£ ™ž¥aµ9˵7¶<³¶m-v+–éZ”P>ݤ6µ>”¥n€²‚2@V&\Ú:ÛìíÑ¥ht)j?hoël® òmlûmöçíÑ›Ñèͨý ½í©6yž´%¿ƒ…B‰•Ä̧3ápø±'W¥ŽJ;v(˹ÄíO¼uÂwÞFMšlvÛ‰¡¾ó¾•oV̻ͽ¯ôf:x–†åßæì×Jܸ»§»ïp_<_Z\Ò°šnWw† P2yf„µZ®° Œ¼;ìÛb,k³*AÁÒÚú ˆÒ9 Ž%eè+ðÿjo%‡wƒª0 #Ý]»Ãü¤ÙÙã”ÖzO{ƒŸÇ?—6þÝùßÙöÙ2m°áÈ[™èÍ(ÇqâÇð×áÆï5Jç’Ÿ7í’œçbæOÁ?™ZL„Ø­Xýýõò;ãwâiž¥aù·9Ÿk5ó錹Ý,~Áh4Æbè4€Ü†ßöôu ×3vÉŠ³³Ý/ö&þ•`¾ÃtýŸ’GV ÿ›¿ï—ý#ï¼wº¶z ÊÓÿŒY”‰ÚoÝc•/±î±¦ò%ÿÑ™}Ië“­–g-é¹K!úõ…æ·9ÏezdmþPn;—ôqõŸ'äÈÒ°üۜϵjy¼Eú›çùåååŒ_ \Òôˆj(1È«¯ ˜Ò‚½\èÏ *}êÂÏ^Ì‘¿MCD‚ 5iùö²aKô úÈíˆ| [Çfß@â;ïknnvö8ÙzÖ´Û4üΰmç/÷¹¶’l3ÈÒ°üۜ׵bñO*'çü¤Ij%1Àä¤r4e¢©\wm#ˆˆÒ¿À¦i´I²áÛa]ƒN¾$gß@Âqœ÷”W„¥Å¥¾Wú&;iÛoK»eêa =WA²4,ÿ6çs­*&]VÏÒ]@j$1(OVPº³ƒZa"¨~í“&åK&/LJ£äE?²o aF ¹íœmŸmæÓÿïýÒZ­Vþ:¼~ØËiÆ#宂diXö6Ëås­hVýQmÙ¾åÇsLNZúK€²<¯{Lf“æ>õ+!dòâ¤ç-O0°á­^ƒ¯ BÌ?3“{ßnðÇŒ¯ý:Ðu`ôQ~‹Å¼ïyåcîÍíæþþÑ‘QNË? ž>u:u÷‚ÎU, ˲J.Ÿk œl}¢šè1È¡œƒˆhCS¢§ö¬o8†êÇ5šõü.~Æ?3ñÑDýýõõ÷×O|41ãŸáwñâZqÿßLüfäÔÈúŸÎð<Ÿöà3Íñ'F†a C8ö÷IkÏzÏ®ÞYmÜÙÈ~—=ñö‰³gÎJ§Èç\âIÛçù1Kò¬J:H>×JþÞƒÔ%Ê¢),J äÐWPd†aV¾Yëz…ÿІ°Þð°aêÒTÚ¥ùy2MC”ÄÜj6·fZÃmç||ò%òùrž+i² ‚>fiX–U©Óås­²,(Ü}¢jî1@i­èÏ Ê‹Â&ä2x|0~'»<>Øu°K鿀ª61([_ý¥i¾XQst–LÆÁ”ONJÐ]•õ»ó¿óOû·Õo3 M5õíWºEP9¦!JR…1âpÍä0ˆ¨ @…ÙöÙä¯uªÎ · Ýô×L} BV ‡¾ H}¢jK òjoÙb?Ú²e!+CVU®jk 2*Û4Df4¥uªÎ JY(ˆ¦Ð2'e''UYÁƳ«=+Àä¤PAcg¼J7”äìq)ݨYÕ“¨õ•éÑ”¨®T\÷‹½J7”×_@YUIP£âWP7FÁ¾‚”³ç ¥P{¨p=¤t ÆÕ^APZPe”M5Ę(-£éEfj/-(…"ïÃjø‡ ´»·áõ=(-£©=jÏ hú-²`6bYÖØl;7¦t»€: Ã(Ý„ª$]7\@¨tG7jÍ ¨ë+H9;ýYAy)8ˆ¨ÀS' †aÖÆ£ß%áÛáÀt ÿWý«ÿ\u½‚y-Êný Uî¥YFq‚YÁdÔœ½Ø¾ÊK ØŠdɶ½^ïxÞá›ô ¿;¼¹c-B !žç•nE6R‡UÒòÊ·mÿ¯úÅåž?0ôæPb%1œ~¶ÖÃdPPËÝÇÝó׿Có¡ÅÅÅÈ?"Ò&³³³‹¡Å¥ÿYŠ„#ýýÙW|K¾ÕÙÑ)^‡ð×ánW·‘ÏÎΊÝ–N‹øL}%º²c׎Þ_¤ÇœxgêšL‚ ®|³"fÑþßûƒàÊ7+Ö}ë¿W¦ëŸó ^ýÛÕ–GZÄ¿[iYør!ûò´âñøÈ»#Ò•Ͼ%9/TN欀ÂB‰DXFÞöm1V¨M™äý”³´@94fÕVpLy])iVàïۛ砈¤ØH«Õž=wÖ¶Ç&-á¶s¡¿†ôz½´$‹=fzL|zjn7¯®®z^ó˜Ÿ4“­ŽÌmçC‹ÜvNZ‡F£4@9µì2i Ã0‰%Òö«EŽãHŠ¢›ZKÆÎx»_ì/cðJ°÷pïüŸç ! ÃD£QñºÅãñmßÝ–¸› „èõúàƒü.ž"\LO˜Ä(iùÎïï©P ¬-ÝŠí4쟎ëÔ»¸­{¬úõ™Ú–EÒO/o¹üŒòí¿Z\o¶Ù$v ¥¹… ”i—©‹Sç>:ç;ï~{øÄÉÃ'†=NÛ~[×Á.Ë3ù–ñx¼ñ{âe‘Ž–úGÒé’ mÛÒÿ^®¡ß+g{Ò¢mÐÎçÅä³ïæÏ ù®‡ø]¥[Ê~ÛÓÔó%wÙÙî{ÿJ0ßaìÿç“äÕé²ý—þ¾_ö¼;<òÞéªë1@VP)5úÀ^A%í+(ìBâ[+߬ŒzGû÷ ‚ ­]^^nll”?ƒ¬¯¯n¬mà;ïknnvö8ÙzÖ´Û4üΰ4¨cùö²<+ „èô‘ÛR”~ùörÚ¬`3M­UIÃô¥ëƲ¬ô_ÿH$"ÅÜü^ú’–K‰D";¿¿síòÞ_¿|{Y\>59åŸö~dày~êâT [ùGDÞɆfG ¼¯ g~Òœ BÎ}tî7þFúœ šfÿ0í6±,Ë0̶mÛ¤ËR ?Pæß+íõÏIsŸFw¿×jµÙ—§ÿÑ÷rŸ£Ë‘ÿ¾›?/Ѓ¦Ä@­/2K¦¬@C4•ë.(j?ýÓQBðã|Áé>¾>àG× [YYIl$Dç8Î{Ê+ÂÒâRß+}“¿´í_ëmÐ6h“že†o‡u ºLg_Ýž•¶A‹¥DZtSk•ÚßÙž£~W§ÓI… Aú’–Ë·_ZZ’_aq¹ñQãÔÅ©X,6zzT÷RôyËuèä ¤m6Ù²~#Éï“Í%bëØ¦‡š|¿õi4K‡eõÞêÔÅ©¦‡šÄ Þfµõ½Ò½£çü[¨L×?çlþaóÜçsâßsŸÏ5ý )ûò´Ø:¶ïHßÜgsùï[’ó@%dD$¢&1Pñ+ Ò|1ʲ…ÚAe''Msö$A®—\“&¥ ÊÜn\È7^ šÖz«†£n;gÛg›ùtÆÿ{¿¸ª³½sò¤|ÇÉ “k处B´Z­TLI:K&æVsà²iˆd“ZÝÔš‹Å¾\0ýÔ”}3ÇsŽÞWzc·b±[±ÞWzÏ­= vtô^_.mïzÉÕÝÕ-¹KB×BRrå°;B !±fõÞª¸0‘AA-wt:9Ã_‡c±XÿáõZ‚õæîu\kvó›GNŽÄãñp8Üýb·´qq-IáugGgï+½ÎƒN±U݇º¥nÕÕUFÃjXA8d9šV«•Rš"dºþ9¿ ã Ã}̇Ãá°û˜Ûù‚3ûrùw<¿öã†ÃáÁÁÖÇ[ Ø·ðó@¥ÝË++ ´$4ÅÁj§lVP£¥´á¶sÖ=Vi’ÏëžÁcƒS—¦âñx<Ÿº4eÛozcHÚþ@×1ЉÅb#<Þ"íèrOŒÇïÄãwâããž·<žA´£¹6£®x IDATÝÜ?л#wIðJðô©Óù4ohp¨ÿXp.Hî’ÐBèÀó\/»6ÙÔš¸0?ž»šbèÄN¯kÜÙØ¸³Q§× X»\C¯i9mã÷wv¶¶¶JÛ»¹[v·˜ž01Û˜½ö½ö}vqyçÓ–g-Ì6æÈá#¾ _þí”lK$µÜ󺧩©Éð#ÃÎ;u¬÷8µînÝiØÙø½F-§z}­Ùgϼ0¹í»ÛŒ?1J5²E·„œ ¶ütí>1·›#·#öçì„ûsöH$"%gÏí}¥—ùczÂd~<ÛyûŽôŒ†‚:+ä2]ÿœ\‡\¦Ý&ƒÁ`0L»MÎgöårÖg¬{÷ïe¶1†·þó¾ü÷ÝÌy€6t—¡» *ú Ò ,GBÁñæ•©´Àß÷t>OC¥è$iãà\ð1Óc„èÍ(·® ýGûý𯮮6ý iàÕ‡}ím`6à=å \,//ët:ë«ç„Gº:rôˆøßü¤ùäÛ' ¯ÆÅnź{ºýð“{Äü3óÙÓg¿×(5F9¥6¯ÿpÿÜçsZ­Öõ’ËóÆz²QtSk†T|ììqh¬Æ7XçÓòŠÕªš[Íî×ÜæÖÂr E øXÍŠ/>ÎÕW />¦à‰hyAÁÔ¢L¡•©Å$_Åïâ}Ò?6·š³ÄL†‡ S—2Ö¡rÛ¹¤ÃÊOš%ì3µ˜Ä2ÐTE7µö¦}¿ìSºÅ ªåÙ¼F¸T¥üFI”N ,-À4DY©=+ îEfH‚ ™|j©êR½-¨&fDášâàJ¢1+@Á±œZïLzTfÈ)©x¢4hÊ è?{Íö¤?»º“4¨U>Uå—Ψ K j®ä-gý@¡”ˆDÊVmŒÒ‚Í£?+Pí4D ³€r¨xLZ¶"+(Xö +pöTßü¤PèxÁÙ˜†HªÎ JYT¯ÊF¦Ê+‡º¬}I¨›œ Ò*Øc Öiˆè‡¬€>è.€J«TLTžóПP×Wrv¼² $0ˆ*fìŒWé&€’PhåCÏÃÒ²Cô|EД“ä‰þ0YTX÷‹½J7”IÉ ¬*'*8ˆˆ¶‚cÊâr "Úkt)½urY¬–ð×ár~9Xç>ææ¶s,ËÚöÛ¤ìnêÒ”¡ÉÀleôêÇÎŒ‘o» rv2Hkãñ¸³Ç)&{Îg<¾ž7¿=,žÑÙåÌ’yýJ àXNµ}fÔý $A£ÿ{Ôû¾W¸.¤]›H$œ=N–e9Žõ_ô'màzÉÅó<˲¯\ýüªëåõË냔ÜÇÝîWÝÎ.'[Dz,kÛcó¼îñœÌ˜@ yÞðÿ ͇¢7£Úû´ý¿ê—xþÀЛC‰•Ä|p>øYÈŠLòìdŒ|YZ\ZZ\aðø ´jvvv1´¸ô?K‘p¤ ¿ _ *¤¤‰²Yr‘Y²¥…«Š¬ êJ ’pÛ9Ï ó3ç–l»¼¼œ´ÐôˆI:NÒÇÕ®J›ù§ýÖ}Vù޳ӳ›i9äÉûkïØé1ýƒz¶Žþ_ÿ—k4šÈבp$¬P?vn¬ˆ#<>zj”ÛÎqÛ¹±ÓcãK«¤å£§FÇ?Ïr \éeG!+È|vú_Y@VÀ—¤¿3Ë;kvÎ.'¹GÆ'’£·p8ì°;¸í\¶Ö­Y?~kyy¹±±Q^[__/ÜHßM¥‰Dv~çÚe¿¿~ùöZv759åŸö~dày~êâTqGæwñâßü>r;"­Ú°<I³3ÐjuãÇj*>¦7M9 PhìÌXÿ¯úc± ¯5°í·éЇþÚ| «®A·²²’ØH>$ÊG§Ó---ɯ¼¸Üø¨qêâT,==ÚÝÓý ™Ž, Bnº´*Ór ÜjÊ’R$yMNZpï3ZÚ"QE»/RO­ê‚ãýÕ[pœ¿‹wýÜåpËÎ}67ôú^¯_û¼‰Rs»Y^r@ ^ š ÅòæzÉÕÝÕ-¹KB×B¶ý6q¹Ãî-„ÄŸuõÞÚÿhµÚL'©Ï9z_éÝŠÅnÅz_éu<çVõþvùá^ÇAG–ƒ=R³Rõ=NC¤ dePcYÈýª{öʆAÿ-?méïëJáºà|1wB&ž×=ƒÇ§.MÅãñx<>uiʶß6ôÆÐ¦[ ¹¹¹[v·˜ž01Û˜½ö½ö}vqyçÓ–g-Ì6æÈá#¾ Ÿ¸°ïHŸÁhÈóÕC'†tz]ãÎÆÆ:½nèÄúÚº»u§agã÷µœvèuüÐUlÓ‰&'•£©ûBÕYú ¾%ÍJ¹aéVröÌYùßy_ävÄð#³±X-ò½’’ý#Ïó¾ó¾sgÎÕß_¿í»ÛŽ=2<2lÛg+×7„¯!ss‡¿'î&B×BÒewØÂu!q7Z™ÛÍÒ–ñ;ñ<‡±,;vn,~'¿;7Ʋ¬têþ£ý±[±x<>þḴ¨µš¡»€l6zÂä¤rÜ_[j + ™ß\kj1ÉWéõzßy_¦“’ý#!„ßÅû.øT¹ù«ó:jTdá¤Z''M¦¬@Õ}Déß  ¥P´…œü_'+Þ(—Lºb¨ªÈ h'.¡ë7T¯, î–H²™y¨ fFåµSÙ‚! ³LCTˆò–”²¨19» HÙBÚ,8¦.%HwvUg%‚¬ª‚p=¤t jä“b‚;µSYAê†T!+€rÁÈÈ_žY)8˜Âä¤r4E¢È 6}Pœ=.¥›µ©÷ÐW!ž‚ÓQH­w&@vùwB*µNNJc_Ažò‚cô@í)(+ %xó1TJ —B³’o —c«Úì+ v +Ã䤠Jcg¼J7”„B#(Ÿj³´6 ­»YAáÄ‘è‰D"‘H¬DW¦þsªéM=ñX`:Pâö•Sp.¨tjÑÆGoÅ…Zµ™ ´ ûÙóA_†ª²‚$lkl6›ÍÍͽ‡{iî7€²KéOé1@Á±MÝjÏ hú-ªùgæ…/Ä¿ÅAF‚ ØöØ8Ž?Š«B×B– [Dzu¬¥Ã"O$ÄÍB !s»™­cY–µtXB 2 ùîævsêî©'•þ¿ÈÙå”>æyäX,æìqêõzf+£×ëvGð zò²11PkÁ1Y‚““R¨D“““ ¦¯0I_Rš-¥Ÿ‰(p9Ðôƒ&ñoq¬Qï¡Þ×b7cŸø?— ×…¶Î6ûA{t)]ŠÚÚÛ:Û„ë‚|¯½û÷º¹¢7£Ñ›QûA{ÛSm‚ ¬ïþT›uŸ5ºÞŒº¹,VKøëpö“Ê>%‰±sc$e^ÎìG¶í·ñ;øP(”XIÌ|:‡{â±_>€®~¯ ˆ#ˆ*¯,Ã+ J$~'¾ð÷ÿEÿÈ»#¾ó>ùª×ŒÍFBˆ¥Ã"âîãnÏ Çawˆ8ìŽååe÷{üÃqi¯“ož´²yöò¬ï¼ã8BˆáaÃø‡ãßk,ð:Ô´ÌSzdž®4FU ÆÌÈáj”‚8g[ý6K§eáË…?ýñOæv³|Ó#Éóú§ýÖ=VùëkRɲùgæLø§ýÖ}vïì蜞Í~Ò|d?rë“­–g-é¹K!úõx@žò »js,8®Ñ¾‚î‚|Þ’»5yÁòíen;'_¢oÐGnGäKX–Í´Áòòrccò£zfãÕK9i>²ÙwÞç>îvö8#·#ÍÿÞlÝcí¹¿¸Ô ¬3€çßcPD”•ÚK JYAq´ ÚØ­˜|IøvX× “/‰ß‰gÚ@× [YYIloؾ8ÙÌqœ÷”W„¥Å¥¾Wú&;iÛoÛüIjA®÷å“ ´ "RŠ\QZ°yÈ ŠÖÙÞ9yaR¾dòÂdÒ$ÿïý™60·›—7Œ; ^ š ›oXö#3 #æ3ÜvζÏ6óéLR#T*·…æ @PZ È rS]×çuÉlÒܧ±>c%„L^œô¼å 6Lý9rj„l!ÿÑIî}»ÁƒÒî6«b~ÒL \twužÍy^mƒvþê¼ñ‡ÆÀå€ÍnKêµÈçȺŒ¾3Êïâc±˜÷=oËã-›¹ꑽǠ6K hÌ Rú PZ ¥óÃÒvÈß}ƒ¤mø]üŒf⣉úûëëﯟøhbÆ?ÃïâåÛŒ8~îܹõ >áùµ xž÷÷;s®þþúmßÝväè‘á‘aÛ>[ö“BFGF-æ;Œ£ËqöôÙÔ¯ýÈ3Íñ'F†a C8Nš @òè. Yƒ rÆ~JÇ^@/—Tβã,6L]šÊ²/ÏóS3nÀïâ}ÒåYNêxÞáxÞ‘}ã,G6·šÍ­æ´«T*¿¬€”uÞó†ç€ýÀè;£òU¯ ›d+±tXÄ0×}Üíô8ìñ¸Ãîp¿êv­ ÕØ°–e-ÏXN¾y2õŒ©‡%„$ g“eYŽãFGFýýI{¹^rñ<ϲìÀ«W?¿êzyýcàra¥Ù¿EZiÛœ¾Ã}æV3ÙJ¸íœç„G™*Ž»$ðÿæ'׃ÙÙÙÅÐâÒÿ,E‘þþÔÍ—óÿ5¿òÍŠuµ»§;õ ž?0ôæPb%1œ~LÚÝó†'øç`h>½ÕÞ§íÿUöåù4IÇGÞ‘¾ËÕ¿]my¤Eü»å‘©Ë+Ór(CI$aAywا1É×a¢b¤$J:O”×dLþâé<ÃÖõA/[ˆ®Agn5¼:`xØ ß ñ¯Ùºa/n;·Zä¶sÒ’p8l4Å1ß©kãñø¶mÛäMJ{Ø´Í˲Wš™¿uêÚìß"ýÒµ9õÈ©Í^YYaY6Ë.¥2vÆÛýboÚƒ¯{÷Îÿy^lÀâW‹ü.ž"\LfSøë°¼a ÃD£QŽãˆøó}w[ân"é úõî#në«þA}êWÓ?¨‚â)b·b; ;ÅT™–gjR*ñ¦Õ6hçƒóâöiî“o¿EÚå5I¸âwroµhømOÿQwΗÜfg»_ìMü+Á|‡±þïO²o,âÿîïûeÿÈ»Ã#ïÎØc€Ò‚‚¥¹ª:+(d%±6¼æn"OŒË³‚5)¡ðòíey®‰Ð§dªðjÔliAzô™¢Žçu{È=>1¿߉OŒ{Þòx=iÖÆã¾ ¾‘S#ù¶å§-ý}ýbÈ(\œ/–2ŒÓ6hç¯Î“»$0Geÿù3·›ûúc·bä. ^ ž>uº„Í.•Àå€ùq³|(TëîÖ†ßkÔrڡׇŠ8HçÓ–g-Ì6æÈá#¾ _ÒÆîcî–Ý-¦'LÌ6f¯}¯}Ÿ=ûò|šd}ƺwÿ^fcø‘!|;ì;¿vR×!—i·É`0 Ón“³Ç™}9aCñ±cñqFx‘YÖ³Óß]@ÿ "”ä”gñ±4ˆ?ÓÆòQþIÛ„®…Ž=">7?i>ùöIyqBh!täð‘ÀåÙBÌOšGOîܹS:B¦Ã†ÃáÞ_ôú/ùWWW›~Ð4ôÚ|žÓ¤Öfÿ˜jüÃñþ_õG"ݺÑwFmûl9¿Ež—"v+ÖÝÓíÿƒŸÜ#柙Ϟ>Ûø½Æ, ËÙÔÍÈT|ììqht½âÚÌÁKrLP °I(>V³ÊÈTáÓñ2R0+¨Ñ”€ +(©œqX– ¦.%×›®¯mÚ°V¸.èX2žé°z½^zœºeÚ÷äÓT‘ãy‡ãùäÑ)Ù¿EžÇç¶s¾ ù6;Ÿ¦–C`:Ð÷Ë>UªÀ¡D˜œ4«ŠöÔ(dÕ‚aï)¯XsZ9{œ}/# T’ †¦Í>J,ÉA J’ +ÈzvU ÊXò[dUäÿ'¾ ¾úÆzf+³wÿ^Û>[ÿÑlï«À8"ÊåÑ + ê쵨J³Õ²tX,¥[%Sµá-MYªû ˆÒ¿…ÒÔÙ]ŠËYP¨ü‚ » €(8¨8ŒÉ€rÈ#®¡0+P°I ö¤œ=O5ûÊ5gHHTÌÙS–¹Dr#+ mYA‰ + ½Ñ uY^d–„¦ß¢ÂÎ ”þúP“2‡è+È YÁ桯 4ý+€ZBc”AcV limh¼kÔW;ãUº  $Aùd4”‹?èÏ è?{Íö¤?{E“4 º_ìUº   LJe•.Ö@ü!W…¥5Ké«‚c ‚ L ÜR"”dEV€ÉIË¥PcVïmø¸qºRdYÏ®öÒ‚R@VP dP~´DÈ ²œ:O5[Z tV °Í]y†a2­ÂXÕJê+Q‘P—Ta]²‚2©¾)`Fþw  5$×›¡²‚ò¢°I*+e¶»€(žhÒ>ûÝBQwAUÔ à¸4[jarÒLã…Äå‚ 0ß® ñ;ñõß® -„Ìíf¶ŽeYÖÒa -l˜#t-dé°°u,[ÇšÛÍ¡këkc±˜³Ç©×ë™­Œ^¯wØÁ+ÁÒ|+(V¦¬€(žP§ ÇП¸TcV <Ïñ×/šiN$ü.ž­c‰Äއv|ñ×/xž“‡½û÷º¹¢7£Ñ›QûA{ÛSm‚ ˆ» ×…¶§Ú¬û¬Ñ¥hôfÔuÈe±ZÂ_‡Åµ¶ý6~ …+‰™OgÂáðcO<¦ØW€¬YQ6NßW  ”$AiR*xvÃÃr„®… !S—¦øxñoÑÉ7OZž±ˆ;ìŽååe÷q÷ø‡ã„÷q·ûU·³Ë)®µí±­ÆW='=ÞS^BÈìåYßyÇqâYÆ?oü^cå¾l”=+ öP÷àYA pWJů¼ó§÷}¯ø÷éS§ûŽöÉךf–´î±¦âßþi¿uŸU¾¶³£svzVü»õÉV˳–Àt€Ü%„ýƒz̃@3eê¦!JAiýY[\wAú “ôÕ(åP¥±?gŸøx" ‚ Ü,ùZ–Ýð3êô‘Ûñïåå寯FF¦¾¾^¸±6ÐÈwÞ×ÜÜììq²õ¬i·iøa1C€ÊËÙ]@ ChŒ¸U3n¨¦ÐÀmçL›&>žXørÁõ²+imüNœ­[Ï Â·Ãºø·®A·¸¸˜”9¬–ã¼§¼ä‰ÝŠ.FÞ™»2ç»à+Ó·€LòÉ -ÅÇ4MCDT>ˆ¨D¿J ªKWW—÷=¯ï‚¯ë…®¤Uþßûå'/LšÛ×™ÛÍËùÚà• ¡i­>a˜Ø­!„ÛÎÙöÙf>I:T@žY©|¢.+H¡ê¬@ÝuÈ R•eV"³šr’Ú€¬ È €V•Š’hŠÆTÝW@”þ-Ԍ›à[¥©‹cËa@•;ãUº  $Aù”8P¢n Žå(…¶;ª\÷‹½J7”IÉ ¬J+Q—(«FcAd4@p Bx ”[ÉÂ%ê²ô$¡.2¦? * o€¥™•ˆº¬ ²‚Íc‹ë.Ø’öìí+À ¢ÚfÚmRº µ ‰AŒ‚ÓQˆ¦ M](È ˜X–56ÇΕô$•Ã0Lš¥÷*Ú€ômȼ}ùPZ›iì+¨Â³S^pŒº‚bÐq'$ †aÖÆ£ß%áÛáÀt ÿWý«ÿ\u½R#óZç‚;—x=+v:€J*Ë Î”„Ò€L¶½^ïxÞá›ô ¿;¬tk€.›J ¨ë.@V —~pÁÐ]P Ún†L˜nüã†|IèZÈÒaaëX¶Ž5·›C×Ö'¾ˆÅbΧ^¯g¶2z½Þaw¯óÙQu#‚m㸤AMÙ!d|b\Z"î5uqÊÔbb¶2ÜvÎÙãŒß‰ËHdƒ£œ]N’nl¼I–Kj“Â_‡-Ϭm`Ûc‹ÝŠe¹V¡…¥Ã²k‡¿'mPhƒ7sµʪøÄ€º¬ …ÚK JYA1èÎ !Áσ;Ø!}® mOµY÷Y£KÑèͨëËbµH°m¿ßÁ‡B¡ÄJbæÓ™p8üØå³£8~©÷PïÀk±›±OüŸˆ wìØFÍ­fBˆÃîXZZÒjµ+++â^O?û´óçÊ7+‹_-Bº]ÝR;Å&¾%VJ$ÍÚ)\Ú:ÛìíÑ¥ht)j?hoël® ò#t÷t÷î‹GãK‹KV#?EAÚžj³´GoF£7£öçí¶ý¶¤m mpÑW ÜŠ  hÌ ,8¦0D_R(¼dÂáp`:Ð?ÐïôH ÝÇÝîWÝÒólÛÛj|ÕsÒã=å%„Ì^žõ÷qG1˲£#£Ò¹òä>îö zv‡øÑaw,//»‡ÜãŽKÛôîÓn;ç9á1yͶÇFû÷Ê·)´ÁE_m€r+¦Ç€þ¬@íp5”Bë•—F³466öþ¢wôÔ¨³Ç)­õOû­û¬òí;;:g§gÅ¿[ŸlµsþÜIÒaëØåååB¾(ñOû­{64ɺǘȗ´<Þ"ýÍó|–Sø/%­ó?:³œ=Ÿ}µÊ­&Š,-(j¿†úiˆº ŠPl_A®Ž4še囕Qïhÿá~A¤µËËËò€úúzáÆÚ¾ó¾ææfg“­gM»MÃï ‹1kÎ×lMn ¿‹×ܧÖ¯¹û8±K‡v·}½ ¡Ðoº|{™ÛÎÉ—èô‘Ûù©w¢ˆ£±uö-¢ÁE_m€r+,1HÄ”¨ÈµH)#ˆT]Z€¬@)t ’°u¬Ãîp¾àtwK u º•••ÄFñøZ-ÇqÞS^A–—ú^é›üí¤4Î>ûŽY8_pzí%„xíu½´>kªm¿Mÿ€>ô×t´B¿ ¶A›TL¾Ö5è =N¦£%}»"\ôÕ(·*ï1¨ÂñKè+(…K ªŠë%×ä…ÉXl-ä5·›—7 ¶ ^ š âß ÃˆÁ1·³í³Í|:ãÿ½?Ÿ³°ï³O^˜ŒÝŠù/ùíÏÙ¥åsŸÍ ½>¤×ë×>þ°¼³½sò¤|Éä…Is»¹à‰GëH>Zà¾o .új”[‰u¥˜œ´ £Únn;gÝcû`m ¿çuÏà±Á©KSñx<O]š²í· ½1$m ë€8±O,ywD£ŸsÇLØ:¶³½Óf·YŸ±Êç´ü´¥¿¯_r—×ç‹ÉµÚíüÕyr—¦Iƒ|¤&¹‡Üããñ;ñøøøÄ¸ç-¼Òº ŽO]œ|mP¾A .új”[¾‰ý­Ú³ÉçÈM7ü}¿ìywxä½ÓÕYc ÖX0=ô(…¶;`r„6ô÷•"BÁ1iUþ¡Úz ”AI³‚ÊQí "€rÈÝÐØ]°‘ª³ô(ˆ¶›Ô'ç0S€¬VSe p¨Ë ÐWPÈ ŠQÔ»®J•ǰ9i²’i(uY²(Ì œ†(=Õ„¾ªýWÔpö¸roP¸4aY‚““ÖhVP­gW¶»€Â› 0é» HõJ  H³’èeŒïhzF«êîdJ¡íN(XJVpoç<⚞Ѫ:+(”ÔšþUB…ñ*ÝP  dî%/È_ÐôŒVíY‚Çjî+ ôÝ È T¯ûÅ^¥›ÊÀ¤d° » R²’#Ä )þPuV€D ªÑ›ª‚ L X9FI2Wa4¥§ô¬ ”2d$cb@Y4V¹î‚-E¾¾Šþ'Ä¥+-(ï×¥…YA9ÿašv›ÊxtPFîD’t‰j³‚ÚUÒAD•ƒÉI7(êj02,ËêõzË3–±scänʦYÿK±y Ô÷¬€¬€P÷ËÕ}‘ ¥Ũ•Ž#q$z"‘H$Ñh4 v=ß5þñ¸Áh® ò-ƒsÁÍ7¨‘í•i¥„4=£UuVP"È ŠAÓ¿‚bY–çyžçmûlcgÆÌO™C ±u%Àè”ÇЀ=4EcjÏ ì+Hþ$¨Dh»JÔq”ÄÙã4·›OœË6Påã2ʳ‚ª€¬ "‚<0 ó—ù¿œxóÄÙsg•n @M©xñqµ½Ë¬¼‡QZ ”½TâÇ?ùqËîñÅgP* Fªm©†ÇÃÈ ŠAÛÍ€” yŽ€œâ?*’¨=+@,¨Ún†"ïLÅ£vÂõÒM€ZS©ø´ÚF•F)…¶¬ (è6€MЧ[X‘³‚bÑ÷„6¬ÝP8g&i€²(”Š'Är˜œT)æcÈ  âÒöˆÊÜc€‚cø^Y°² LEƒ5µg(-P …7@Åeé. åM ª­à˜¾ÇÃÉ£Fnô@ÍbåÔ=+ eL ªmÜý‡«4+PXµÝ‡yRÍïéÕÒ\¥ÙY¥›  9³R®¸ }r5›æ©ê Žéë+ IY!²(‡ŠLWªfD›…¬6%ŸîRú§Ùʾ² vžo€¬ `´Ý ¥ Œ<³RS=Æ‚¥€¬ ”(+ ÿvªäŸRöà•Iªíyy a¢ € Ê ˆò!dIÐ¥¥§ŽÀ’›¡èo!P%þÏÕ‘wGüÓH$¢¹OÓòÓçA‡©¥…²óûÿ¶øÕIÛK w~ÿߤ…⎞cný:qÕŽ‡vüSòÍOYnܸ!í»øÕò#HRÏ*Q«limPZ  ³”€º_éåä}ãút±åå¹¹àÈ{^11ÈI âcËËcŒuêúÏ߉KX ˜5·¶ŠÓ³ì}É÷ª´{Ú *¦ÐîRšeÁÂÏ®¡qÜÈl)³‚ò~Ýä“!++EVPÑßjÅÜgs¯ö‰Oú9­¶³£Ó7ñ›BÂiµ®—] _–¸~Þå}Lúèýµ×õsWI 4Øtb liÈ)=. Ç ¯”ÓòHó‘cƒóÿ}5¾ºZôAbËËÞ÷Æšÿ½YZÒÙÑ[Ïÿ÷UBHðÏWc˱ΎÖ4èPâPNÕÇA¤ ¹ðÊ(³§Ïzß÷ös߸qC× ël7»~ÙÇÝ—×=•Tf0uþwòµÎ\ÞÓccgF½ï{è.¨-›ë1@iA©!+(mY€ÒØû4ýGúþ©ÅÐãž]^]í=ԛ羋_}!þß_æÿâz¡ËýÆ |­cŸõêß®ú/ú¾\pì±–¡í ˜M$ fµ[ZPºS«&î¥-+(êæL­+QÍïeÇïà‡æ>Ÿ?êtºÐ— ò B_.ètºÔ¹û4®—\sŸ_ݰt q¾àìí;â|Á©øðE(­büïuW£¢Q%J hc³ð_òÇn/B‘ȉ“#R©€ã C,? ÷¹Gæÿûê‘£ƒÎƒŽÔƒÄÿ¹êýµ·é¡IË]?ïZüê ×Ï»Êü% ÒŠŠé”í+( å}¤ÄÝ•ƒiˆ6@iСïeרGãýƒ«ÿ\Õé´¦Ýæ³§FÅU®Ÿwi4±ü€²cÇçsÇA»´¯Tc ÑhšiývG¨yJÇ•¡²¬@5¥´Á4D@ SKK–·8Ú²L@.Ë›2­’–'m€—Tce''¥ð q) +(…wB‰²úoWPJ`v¶¬Ç/$œAVDÅÇè+ØY”Ã0å>EÞ ²‚$ˆŒ•BáÍP ô·ô§?ΔûE†·ô¿²€þ¬}Å 0+@Á1Ô„ü‚š*Œ¡ÕhVP¨r1uÊ#®Á "9LCû ðC¨XƘ€ZÜÛð)W|¬  ƒ¶›¡9($‘H(ÝP€i·9ŸÍ†Iü«Èÿ¥(,ºQuV€¾ÕÈÍP¢iˆ“¨’p=”}ƒÂÆšÞK^9Ä@_A +(Xí¼ëYP#%+ „üyî«ö¬€ºhŒþ$HIô]d@tYÉhl\LVP^4"ªŒ JVŠ ‚¬“!+ éc*Œ?è7’¬JU*³LN %ã>~bâã ùûsvÏë›?rÊP"””A•f —~öªÈ Ð]›áy} õÉVécë“­ùf÷²uäÄYAßpœýIPBVÔ=5ÜüÃ&BHó›FO —ê°ÙŠ‘l^ñ}iÎ^Ѿ‚ª›‰ˆþœ Y”«Ñœ=w¶åñ–³çβšüBŒ¬}¢ŒAGE³ !S …Y‚o8H‡ÓjÇÏ-í1éˆi‹•í+HCu„¾;(šÐñ¯ª[}¢´V0‚”@ÛÍ€º¨vygÑG2uONªpwd˜-ëñ7D‚•®+¨‘'ÄÉŒ¶; »èÂ0LÁûÒ]@²ÏJT^´Å‚È `³@YôÿÒøW"Ïÿ[Û§À¬€(ƒÐ–ÐH5Ym7CõôŒñw€TJ„„´‚„ÎîȈþ±b}Ý/öw* \"‘;ã-âë‰DqbR:³utÔNŠXÒ×[hñ«/<;”[Åþ·¾â5´Å‚È @R=ƒˆJ®²‰mYA‰ +(m7²P· Æ#5&CVPŒ¹ðzc¨ÊMWZƒ¶¬*ô¸’Â@°ßYA1h»jtÑÎïÿ›ø‡æ> ÿߺ»Åùs'§Õ–ë|PýTÙc€ÁJÁ•¯ Å¯¾Xüê‹¿ÿtòí¡ÕÕÕ¶NK8QºQPFü.Ãfv/sb°¥˜XPCãâdè.(X±}ôÝ É¥Å´°¨E`5Ú܃ö}ö‘·GÄ…ñ{«ýƒã Æ»ã÷VÅå;¿ÿoãO˜žhÛiø7˳{C_.HÇ>9büÉc†ý¸÷•#ñÕÕJ4 Áï2lò姪ì1Ø4dPuÏÙŸÅ¿GNzc·Â ÌüéÓ!ywý?"ssW}“ã_Ìÿ¥³½õȱAq¡÷}ïÕk SÿéûËýI£ÑœxkD/™m>+ åM (MŽÒ¥ÔÈÍÀVïLDúÝòò²ø÷äÅI÷±N«å´ž×ü&¥Í†ÞÐ7èX¦ëçÎ…¿­õŒ<éyc@¯Ó±ÍÀÑ>ÿ´_/HY¹µu3Ç¡ë2ý3Ï”ô ·ôÝ¡ë.+™*Ê !áÛí·ÅÇË·—ù¼ø7¿ƒÜ^–6ãî[Û†Õ¬¿H$ÒöÔÓ•j) TY)WBÛãa¢tlªtd\¥åRü¥¨Ö¾ÑøÇ>óã&ñomƒVøG„@GùÿÛ»Þ8Š0Žã³’‘ŽŽH)ŽÎ)ï (BgɈ;#!9G,™3 2Mwi.b®â¼ "ˆ£@ÂE¤¸óI±t‡Œ÷nnÿÌ=3óÌî÷SÅ—óîìÞúöùíìì ÿ¾q³äiEÝnwðÓoÞìzo%¨c*ÜzëáóS祵cŒÐD.Ýö[Vü©Í­i‰T "ÕTp1þöë£ýƒÃ£ÃþýÉ‹k«+î½Ø|°_ü[×ìmmö¶6[œÍK 3½•H[*"ú¢px QŽÐÞи€fó” Œd0PXòpÒX´ Ž~8)h¤âT {æcÄ@*˜FiÒWš ê3唨˜Zº8=´ ¦æ ôEÄSÁ¬…+—æ‚X;SL!€ôULÕ‡Œl/6®xQ÷"Ó¢¡ÚDLr†ÏO¯ýÅ?:[¬Ôv…˜T‹¶#ÁÄž² Ôg1­ Äàã\oí.0 Õ/ kA ¢sYéß܆Š8eûÚk;~úìøé³@+1ˆŸëç¥ã^Â(L<œ4mCÜ) ~ƒ'ƒp+éȲÌúzA*0ŽUŒÂÙ6©%´¥wé 8ɃãÃÁ“%€)O»Å©À„,d”_!–žÞ8PéK_Á´ˆC ~*“Ы4— ÎÖ‚ê´csöÒÄZ²š•”¶TÀcˆR£ï`HlÀ±!·¶þѺñsK*tªÒ]`ê•3¤‚òµ·&Ô_»þ;ˆÜ[H*¤&˲ñxL6hƒŠ©ÀÔ¸•H[*B*p‘`O…G¤@š²,›t Áª§Sµ¨Q˜ "8¶kMͦí`hñDw?¾ëcEóphŒ«9³&ý|óGäuç×J&Õk¿í¾^žâÐåRL÷8 ·úŠò;dNðö_sù¥ i>z¢¶4@dñ¶“Îe…f¼'ˆº'K ¡MhÉÄ+Ëò.¦Þ{·[Ì6ÉúÇâÔr±}ëFfo_ˆmÅU{–L'ÿ =ÉŸ~7=‹Öhæ*Yòb,[*uÄÎ,Çq¯^ºü^¥¨æo³ìdåZúè»B<›ˆj‹^ÙÌŠ;´ "máp¦=¤‚œè;!SAi3bŸÿdÊ,m©À¶°j5]T¶rÍrh&— Ä ±ïËü¿g¾æeƒzK^@«Sn›Yÿq¥ <¡¯ 'â”îkw‘dtÑM*ðÌçˆ]÷cÂRލÿhìuLr©@Èäj½§kí ȲìûÏî\{O8 ¬Ëk*Ðô·YxÊŠ~•ËRAmÍé8JhÂ*3µ;ˆ’à³»@jÙ5o"ªøŸäoÉXŒd1ôªì š*ÿä›ÔT ×W ³ 3§IsÚyÕoPuJl¯ßÏKæI/8ïÕÜãÝõ» 5ú¯&êo!”}ºF‚ NnÛ£ØÝ>î?¸o{½w#|k ÆÿÁ ¿³±"Z2Æìn÷b7DôöÉ¿ôLjk²ûKñIEND®B`‚oar-2.5.7/sources/api/api_html_postform_rule.pl0000644015014700017500000000044112677211234021273 0ustar neyronneyron$POSTFORM="
Admission rule submission
Rule
" oar-2.5.7/sources/api/api_html_postform.pl0000644015014700017500000000152612677211234020251 0ustar neyronneyron$POSTFORM="
Job submission
Resources
Name
Properties
Program to run
Types
Reservation dates
Directory
" oar-2.5.7/sources/api/DOC0000644015014700017500000000006612677211234014514 0ustar neyronneyronSee into ../docs/documentation/OAR-DOCUMENTATION-API* oar-2.5.7/sources/api/lib/0000755015014700017500000000000012677211234014730 5ustar neyronneyronoar-2.5.7/sources/api/lib/OAR/0000755015014700017500000000000012677211234015351 5ustar neyronneyronoar-2.5.7/sources/api/lib/OAR/API.pm0000644015014700017500000017066412677211234016336 0ustar neyronneyron#!/usr/bin/perl -w package OAR::API; require Exporter; my $VERSION="1.0.2"; use strict; #use OAR::Conf qw(init_conf dump_conf get_conf is_conf); use CGI qw/:standard/; our $ABSOLUTE_URIS; our $q; our $DEBUG_MODE; our $extension; our $HTTP_X_API_PATH_PREFIX; ############################################################################## # INIT ############################################################################## # Try to load XML module my $XMLenabled = 1; unless ( eval "use XML::Simple qw(XMLout);1" ) { $XMLenabled = 0; } # Try to load YAML module my $YAMLenabled = 1; unless ( eval "use YAML;1" ) { $YAMLenabled = 0; } # Try to load JSON module my $JSONenabled = 1; unless ( eval "use JSON;1" ) { $JSONenabled = 0; } # Try to load URI (LWP) module my $URIenabled = 1; unless ( eval "use URI;1" ) { $URIenabled = 0; } # Declared later with REST functions sub ERROR($$$); ############################################################################## # Output text formating ############################################################################## # Inserts html line breaks in a string sub nl2br { my $t = shift or return; $t =~ s/(\r\n)/
/g; return $t; } ############################################################################## # Data conversion functions ############################################################################## # Load YAML data into a hashref sub import_yaml($) { my $data = shift; check_yaml(); # Try to load the data and exit if there's an error my $hashref = eval { YAML::Load($data) }; if ($@) { ERROR 400, 'YAML data not understood', $@; exit 0; } return $hashref; } # Load JSON data into a hashref sub import_json($) { my $data = shift; check_json(); # Try to load the data and exit if there's an error my $hashref = eval { JSON::decode_json($data) }; if ($@) { ERROR 400, 'JSON data not understood', $@; exit 0; } return $hashref; } # Load Dumper data into a hashref sub import_dumper($) { my $data = shift; my $hash = eval($data); if ($@) { ERROR 400, 'Dumper data not understood', $@ . $data; exit 0; } return $hash; } # Load HTML data into a hashref sub import_html_form($) { my $data = shift; return $data; } # Load data into a hashref sub import_data($$) { (my $data, my $format) = @_; if ($format eq "yaml") { import_yaml($data); } elsif ($format eq "dumper") { import_dumper($data); } elsif ($format eq "json") { import_json($data); } else { ERROR 400, "Unknown $format format", $@; exit 0; } } # Export a hash into YAML sub export_yaml($) { my $hashref = shift; check_yaml(); return YAML::Dump($hashref) } # Export a hash into JSON sub export_json($) { my $hashref = shift; check_json(); return JSON->new->pretty(1)->encode($hashref); } # Export a hash into HTML (YAML in fact, as it is human readable) sub export_html($) { my $hashref = shift; check_yaml(); return "
\n". YAML::Dump($hashref) ."\n
"; } # Export data to the specified content_type sub export($$) { my $data = shift; my $format = shift; if ( $format eq 'yaml' ) { return export_yaml($data); }elsif ( $format eq 'json' ) { return export_json($data)."\n"; }elsif ( $format eq 'html' ) { return export_html($data)."\n"; }elsif ( $format eq 'tgz' ) { return export_yaml($data)."\n"; }else { ERROR 406, "Unknown $format format", "The $format format is not known."; exit 0; } } ############################################################################## # URI generation functions # For each structure having an uri, also add an api_timestamp giving the date # at which the entry has been generated by the api. ############################################################################## # Return the url (absolute if the third argument is 1). The .html # extension is added if the second argument is equal to "html". sub make_uri($$$) { my $path = shift; my $ext = shift; my $absolute = shift; # deprecated, left here for compatibility if (defined($ext) && $ext eq "html") { $path.=".html"; } if (our $ABSOLUTE_URIS == 1) { return "$HTTP_X_API_PATH_PREFIX".$q->url(-absolute => 1)."/".$path; } else { if ($URIenabled) { my $base = URI->new($q->url().$q->path_info); my $goal = URI->new($q->url()."/".$path); return "$HTTP_X_API_PATH_PREFIX".$goal->rel($base); } else { ERROR (500, "LWP URI module not enabled", "I cannot make relative uris without LWP URI module!" ); exit 0; } } } # Return an html href of an uri if the type is "html" sub htmlize_uri($$) { my $uri=shift; my $type=shift; if ($type eq "html") { return "$uri"; } else { return $uri; } } # Get the api uri base in relative sub get_api_uri_relative_base() { if ($URIenabled) { my $base = $q->path_info; $base =~ s/\.html$// ; $base =~ s/\/$// ; $base = "http://bidon".$base; my $goal = "http://bidon"; return URI->new($goal)->rel($base); } else { ERROR (500, "LWP URI module not enabled", "I cannot make uris without LWP URI module!" ); exit 0; } } # Add uri to a job sub add_job_uris($$) { my $job = shift; my $ext = shift; my $self=OAR::API::make_uri("jobs/".$job->{id},$ext,0); $self=OAR::API::htmlize_uri($self,$ext); my $resources=OAR::API::make_uri("jobs/".$job->{id}."/resources",$ext,0); $resources=OAR::API::htmlize_uri($resources,$ext); my $nodes=OAR::API::make_uri("jobs/".$job->{id}."/nodes",$ext,0); $nodes=OAR::API::htmlize_uri($nodes,$ext); my $links; push (@$links, { href => $self, rel => "self" }); push (@$links, { href => $resources, rel => "collection", title => "resources" }); push (@$links, { href => $nodes, rel => "collection", title => "nodes" }); $job->{links}=$links; $job->{api_timestamp}=time(); # Don't know why this function breaks the type of the id, so: $job->{"id"}=int($job->{"id"}); } # Add uris to a oar job list sub add_joblist_uris($$) { my $jobs = shift; my $ext = shift; foreach my $job (@$jobs) { if (defined($job->{Job_Id}) && !defined($job->{job_id})) { $job->{job_id}=$job->{Job_Id}; } add_job_uris($job,$ext); } } # Add uris to a oar job list for oargrid sub add_joblist_griduris($$$) { my $jobs = shift; my $ext = shift; my $site = shift; foreach my $job ( keys( %{$jobs} ) ) { $jobs->{$job}->{uri}=OAR::API::make_uri("sites/$site/jobs/$job",$ext,0); $jobs->{$job}->{uri}=OAR::API::htmlize_uri($jobs->{$job}->{uri},$ext); $jobs->{$job}->{api_timestamp}=time(); } } # Add uris to a list of jobs of a resource sub add_jobs_on_resource_uris($$) { my $jobs = shift, my $ext = shift; foreach my $job (@$jobs) { add_job_uris($job,$ext); } } # Add uris to a resources list sub add_resources_uris($$$) { my $resources = shift; my $ext = shift; my $prefix = shift; foreach my $resource (@$resources) { my $links; my $node; if (defined($resource->{network_address})) { $node=OAR::API::make_uri($prefix."resources/nodes/".$resource->{network_address},$ext,0); $node=OAR::API::htmlize_uri($node,$ext); push (@$links, { href => $node, title => "node", rel => "member" }); } my $self=OAR::API::make_uri($prefix."resources/".$resource->{id},$ext,0); my $jobs=OAR::API::make_uri($prefix."resources/".$resource->{id}."/jobs",$ext,0); $self=OAR::API::htmlize_uri($self,$ext); $jobs=OAR::API::htmlize_uri($jobs,$ext); push (@$links, { href => $self, rel => "self" }); push (@$links, { href => $jobs, title => "jobs" , rel => "collection"}); $resource->{links}=$links; $resource->{api_timestamp}=time(); $resource->{id}=int($resource->{id}); #why the hell do I need to do that?? } } # Add uris to a list of nodes sub add_nodes_uris($$$) { my $nodes = shift; my $ext = shift; my $prefix = shift; foreach my $node (@$nodes) { my $links; my $self=OAR::API::make_uri($prefix."resources/nodes/".$node->{network_address},$ext,0); $self=OAR::API::htmlize_uri($self,$ext); push (@$links, { href => $self, rel => "self" }); $node->{links}=$links; $node->{api_timestamp}=time(); } } # Add uris to resources of a job # OBSOLETE! sub add_job_resources_uris($$$) { my $resources = shift; my $ext = shift; my $prefix = shift; foreach my $assigned_resource (@{$resources->{assigned_resources}}) { $assigned_resource->{resource_uri}=OAR::API::make_uri($prefix."resources/".$assigned_resource->{id},$ext,0); $assigned_resource->{resource_uri}=htmlize_uri($assigned_resource->{resource_uri},$ext); } foreach my $reserved_resource (@{$resources->{reserved_resources}}) { $reserved_resource->{resource_uri}=OAR::API::make_uri($prefix."resources/".$reserved_resource->{id},$ext,0); $reserved_resource->{resource_uri}=htmlize_uri($reserved_resource->{resource_uri},$ext); } foreach my $assigned_node (@{$resources->{assigned_nodes}}) { $assigned_node->{node_uri}=OAR::API::make_uri($prefix."resources/nodes/".$assigned_node->{node},$ext,0); $assigned_node->{node_uri}=htmlize_uri($assigned_node->{node_uri},$ext); } $resources->{job_uri}=OAR::API::make_uri($prefix."jobs/".$resources->{job_id},$ext,0); $resources->{job_uri}=htmlize_uri($resources->{job_uri},$ext); $resources->{api_timestamp}=time(); } # Add uris to a grid sites list sub add_sites_uris($$) { my $sites = shift; my $ext = shift; foreach my $site ( keys( %{$sites} ) ) { $sites->{$site}->{uri}=OAR::API::htmlize_uri( OAR::API::make_uri("sites/$site",$ext,0), $ext ); $sites->{$site}->{resources_uri}=OAR::API::htmlize_uri( OAR::API::make_uri("sites/$site/resources",$ext,0), $ext ); $sites->{$site}->{timezone_uri}=OAR::API::htmlize_uri( OAR::API::make_uri("sites/$site/timezone",$ext,0), $ext ); $sites->{$site}->{api_timestamp}=time(); } } # Add uris to a grid job list sub add_gridjobs_uris($$) { my $jobs = shift; my $ext = shift; foreach my $job ( keys( %{$jobs} ) ) { $jobs->{$job}->{uri}=OAR::API::htmlize_uri( OAR::API::make_uri("grid/jobs/$job",$ext,0), $ext ); $jobs->{$job}->{nodes_uri}=OAR::API::htmlize_uri( OAR::API::make_uri("grid/jobs/$job/resources/nodes",$ext,0), $ext ); $jobs->{$job}->{api_timestamp}=time(); } } # Add uris to a grid job sub add_gridjob_uris($$) { my $job = shift; my $ext = shift; # Timestamp $job->{api_timestamp}=time(); # List of resources $job->{resources_uri}=OAR::API::htmlize_uri( OAR::API::make_uri("grid/jobs/". $job->{id} ."/resources",$ext,0), $ext ); # List of resources without details (nodes only) $job->{nodes_uri}=OAR::API::htmlize_uri( OAR::API::make_uri("grid/jobs/". $job->{id} ."/resources/nodes",$ext,0), $ext ); # Link to the batch job on the corresponding cluster foreach my $cluster (keys %{$job->{clusterJobs}}) { foreach my $cluster_job (keys %{$job->{clusterJobs}->{$cluster}}) { $job->{clusterJobs}->{$cluster}->{$cluster_job}->{uri}=OAR::API::htmlize_uri( OAR::API::make_uri("sites/$cluster/jobs/" .$job->{clusterJobs}->{$cluster}->{$cluster_job}->{batchId},$ext,0), $ext ); } } # Ssh keys $job->{ssh_private_key_uri}=OAR::API::htmlize_uri( OAR::API::make_uri("grid/jobs/".$job->{id}."/keys/private",$ext,0), $ext ); $job->{ssh_public_key_uri}=OAR::API::htmlize_uri( OAR::API::make_uri("grid/jobs/".$job->{id}."/keys/public",$ext,0), $ext ); } # Add uris to a single admission rule sub add_admission_rule_uris($$) { my $admission_rule = shift; my $ext = shift; $admission_rule->{uri} = OAR::API::make_uri("admission_rules/".$admission_rule->{id},$ext,0); $admission_rule->{uri} = htmlize_uri($admission_rule->{uri},$ext); $admission_rule->{api_timestamp} = time(); } # Add uris to an admission rules list sub add_admission_rules_uris($$) { my $admission_rules = shift; my $ext = shift; foreach my $admission_rule (@$admission_rules) { $admission_rule->{uri} = OAR::API::make_uri("admission_rules/".$admission_rule->{id},$ext,0); $admission_rule->{uri} = htmlize_uri($admission_rule->{uri},$ext); $admission_rule->{api_timestamp} = time(); } } # Add uris to a single config parameter sub add_config_parameter_uris($$) { my $parameter = shift; my $ext = shift; $parameter->{uri} = OAR::API::make_uri("config/".$parameter->{id},$ext,0); $parameter->{uri} = htmlize_uri($parameter->{uri},$ext); $parameter->{api_timestamp} = time(); } # Add uris to a config parameters list sub add_config_parameters_uris($$) { my $parameters = shift; my $ext = shift; foreach my $name (keys %$parameters) { $parameters->{$name}->{uri} = OAR::API::make_uri("config/".$name,$ext,0); $parameters->{$name}->{uri} = htmlize_uri($parameters->{$name}->{uri},$ext); $parameters->{$name}->{api_timestamp} = time(); } } ############################################################################## # Data structure functions # (functions for shaping data depending on $STRUCTURE) ############################################################################## # EMPTY DATA sub struct_empty($) { my $structure = shift; if ($structure eq 'oar') { return {}; } elsif ($structure eq 'simple') { return []; } } # OAR JOB sub fix_job_integers($) { my $job = shift; foreach my $key ("resubmit_job_id","Job_Id","array_index","array_id","startTime","stopTime","submissionTime","scheduledStart","exit_code") { $job->{$key}=int($job->{$key}) if defined($job->{$key}); } foreach my $event (@{$job->{"events"}}) { $event->{'job_id'}=int($event->{'job_id'}); $event->{'event_id'}=int($event->{'event_id'}); $event->{'date'}=int($event->{'date'}); } } sub struct_job($$) { my $job = shift; my $structure = shift; my $result; if ($structure eq 'oar') { return $job; } elsif ($structure eq 'simple') { if ($job->{(keys(%{$job}))[0]} and $job->{(keys(%{$job}))[0]} eq "HASH") { $job=$job->{(keys(%{$job}))[0]}; } fix_job_integers($job); $job->{id}=$job->{Job_Id}; delete $job->{Job_Id}; $job->{start_time}=$job->{startTime}; delete $job->{startTime}; $job->{stop_time}=$job->{stopTime}; delete $job->{stopTime}; $job->{scheduled_start}=$job->{scheduledStart}; delete $job->{scheduledStart}; $job->{submission_time}=$job->{submissionTime}; delete $job->{submissionTime}; $job->{type}=$job->{jobType}; delete $job->{jobType}; $job->{launching_directory}=$job->{launchingDirectory}; delete $job->{launchingDirectory}; delete $job->{job_user}; delete $job->{job_uid}; delete $job->{reserved_resources}; delete $job->{assigned_resources}; delete $job->{assigned_network_address}; return $job; } } sub struct_job_list_hash_to_array($) { my $jobs=shift; my $array=[]; foreach my $j ( sort { $a <=> $b } keys (%{$jobs}) ) { if (defined($jobs->{$j}->{Job_Id})) { $jobs->{$j}->{id}=int($jobs->{$j}->{Job_Id}); push (@$array,$jobs->{$j}); } else { $jobs->{$j}->{Job_Id} = int($j); $jobs->{$j}->{id} = int($j); push (@$array,$jobs->{$j}); } } return $array; } # OAR JOB LIST sub struct_job_list($$) { my $jobs = shift; my $structure = shift; my $result; foreach my $job (@$jobs) { my $hashref = { id => int($job->{job_id}), state => $job->{state}, owner => $job->{job_user}, name => $job->{job_name}, queue => $job->{queue_name}, submission => $job->{submission_time}, api_timestamp => int($job->{api_timestamp}), links => $job->{links} }; if ($structure eq 'oar') { $result->{$job->{job_id}} = $hashref; } elsif ($structure eq 'simple') { push (@$result,$hashref); } } return $result; } # OAR JOB LIST WITH DETAILS # TODO: need to append "resources" and "nodes" as /jobs/XXX/resources sub struct_job_list_details($$) { my $jobs = shift; my $structure = shift; my $result; if ($structure eq 'oar') { foreach my $job (@$jobs) { $result->{$job->{job_id}} = int($job); } } elsif ($structure eq 'simple') { foreach my $job (@$jobs) { $job=struct_job($job,$structure); push (@$result,$job); } } return $result; } # OAR RESOURCES OF A JOB sub struct_job_resources($$) { my $resources=shift; my $structure=shift; my $result=[]; foreach my $r (@{$resources->{assigned_resources}}) { push(@$result,{'id' => int($r), 'status' => 'assigned'}); } if (ref($resources->{reserved_resources}) eq "HASH") { foreach my $r (keys(%{$resources->{reserved_resources}})) { push(@$result,{'id' => int($r), 'status' => 'reserved'}); } } if (ref($resources->{scheduled_resources}) eq "HASH") { foreach my $r (keys(%{$resources->{scheduled_resources}})) { push(@$result,{'id' => int($r), 'status' => 'scheduled'}); } } return $result; } sub struct_job_nodes($$) { my $resources=shift; my $structure=shift; my $result=[]; my $network_addresses={}; my $network_address; foreach my $n (@{$resources->{assigned_hostnames}}) { push(@$result,{'network_address' => $n, 'status' => 'assigned'}); } if (ref($resources->{reserved_resources}) eq "HASH") { foreach my $r (keys(%{$resources->{reserved_resources}})) { $network_address=$resources->{reserved_resources}->{$r}->{network_address}; if (!defined($network_addresses->{$network_address})) {; push(@$result,{'network_address' => $network_address, 'status' => 'reserved'}); $network_addresses->{$network_address}=1; } } } $network_addresses={}; if (ref($resources->{scheduled_resources}) eq "HASH") { foreach my $r (keys(%{$resources->{scheduled_resources}})) { $network_address=$resources->{scheduled_resources}->{$r}->{network_address}; if (!defined($network_addresses->{$network_address})) {; push(@$result,{'network_address' => $network_address, 'status' => 'scheduled'}); $network_addresses->{$network_address}=1; } } } return $result; } # ACCOUNTING LIST sub struct_accounting($) { my $accounting = shift; my $result; foreach my $a (keys (%{$accounting})) { my $hashref = { project => $a, consumptions => $accounting->{$a} }; push (@$result,$hashref); } return $result; } # OAR RESOURCES sub filter_resource_list($) { my $resources = shift; my $filtered_resources; foreach my $resource (@$resources) { push(@$filtered_resources,{ id => int($resource->{resource_id}), state => $resource->{state}, available_upto => int($resource->{available_upto}), network_address => $resource->{network_address} }); } return $filtered_resources; } sub struct_resource_list_hash_to_array($) { my $resources=shift; my $array=[]; foreach my $r ( keys (%{$resources}) ){ if (defined($resources->{$r}->{resource_id})) { push (@$array,$resources->{$r}); #oarnodes -s case }else{ foreach my $id ( keys (%{$resources->{$r}})) { push (@$array,{ 'state' => $resources->{$r}->{$id}, 'id' => int($id), 'network_address' => $r}); } } } return $array; } # Replace resource_id by id sub fix_resource_id($) { my $resource=shift; if (defined($resource->{resource_id}) && !defined($resource->{id})) { $resource->{id}=int($resource->{resource_id}); delete $resource->{resource_id}; } } # Replace resource_id by id into a resources list sub fix_resource_ids($) { my $resources=shift; foreach my $resource (@$resources) { fix_resource_id($resource); } } sub struct_resource_list_fix_ints($) { my $resources = shift; foreach my $resource (@$resources) { if (defined($resource->{resource_id})) { $resource->{id}=int($resource->{resource_id}); } if (defined($resource->{id})) { $resource->{id}=int($resource->{id}); } if (defined($resource->{available_upto})) { $resource->{available_upto}=int($resource->{available_upto}); } if (defined($resource->{cpuset})) { $resource->{cpuset}=int($resource->{cpuset}); } } } sub struct_resource_list($$$) { my $resources = shift; my $structure = shift; my $compact = shift; # If true, replace a 1 element array by its element my $result; struct_resource_list_fix_ints($resources); if ($structure eq 'simple') { if (scalar @$resources == 1 && $compact == 1) { return @$resources[0]; } else { return $resources ; } } elsif ($structure eq 'oar') { foreach my $resource (@$resources) { $result->{$resource->{id}}=int($resource); } return $result; } } sub get_list_nodes($) { my $expression = shift; my $pattern = qr{/(node|nodes)=(.*?)(/|$)}; my $result; if ($expression =~ /$pattern/) { my $prefix = $1; my $value = $2; if ($value =~ /\{(.+)\}/) { for (my $i=1; $i<=$1; $i++) { push(@$result, $prefix.$i); } } else { my @params = split(/,/,$value); foreach my $param (@params) { if ($param =~ /\[(\d+)-(\d+)\]/) { for (my $i=$1; $i<=$2; $i++) { push(@$result, $prefix.$i); } } else { push(@$result, $param); } } } } return $result; } # GRID SITE LIST sub struct_sites_list($$) { my $sites = shift; my $structure = shift; my $result; my $uri; foreach my $s ( keys( %{$sites} ) ) { if ($structure eq "simple") { push(@$result,{ site => $s, uri => $sites->{$s}->{uri}, api_timestamp => $sites->{$s}->{api_timestamp} });} else { $result->{$s}->{uri} = $sites->{$s}->{uri}; $result->{$s}->{api_timestamp} = $sites->{$s}->{api_timestamp}; } } return $result; } # GRID SITE sub struct_site($$) { my $site = shift; my $structure = shift; if ($structure eq "simple") { my $s=(keys( %{$site}))[0]; $site->{$s}->{site}=$s; return $site->{$s}; } else { return $site; } } # GRID JOB sub struct_gridjob($$) { my $job = shift; my $structure = shift; my @cluster_jobs; foreach my $cluster (keys %{$job->{clusterJobs}}) { foreach my $cluster_job (keys %{$job->{clusterJobs}->{$cluster}}) { # Cleaning delete $job->{clusterJobs}->{$cluster}->{$cluster_job}->{weight}; delete $job->{clusterJobs}->{$cluster}->{$cluster_job}->{nodes}; delete $job->{clusterJobs}->{$cluster}->{$cluster_job}->{env}; delete $job->{clusterJobs}->{$cluster}->{$cluster_job}->{name}; delete $job->{clusterJobs}->{$cluster}->{$cluster_job}->{queue}; delete $job->{clusterJobs}->{$cluster}->{$cluster_job}->{part}; # For the simple data structure push (@cluster_jobs, { 'cluster' => $cluster, 'id' => $job->{clusterJobs}->{$cluster}->{$cluster_job}->{batchId}, 'properties' => $job->{clusterJobs}->{$cluster}->{$cluster_job}->{properties}, 'rdef' => $job->{clusterJobs}->{$cluster}->{$cluster_job}->{rdef}, 'uri' => $job->{clusterJobs}->{$cluster}->{$cluster_job}->{uri}, 'api_timestamp' => $job->{clusterJobs}->{$cluster}->{$cluster_job}->{api_timestamp} }) } } if ($structure eq "simple") { delete $job->{clusterJobs}; $job->{cluster_jobs}=\@cluster_jobs; } return $job; } # GRID JOB LIST sub struct_gridjobs_list($$) { my $jobs = shift; my $structure = shift; my $result; foreach my $job ( keys( %{$jobs} ) ) { my $hashref = { nodes => $jobs->{$job}->{nodes}, uri => $jobs->{$job}->{uri}, api_timestamp => $jobs->{$job}->{api_timestamp}, }; if ($structure eq 'oar') { $result->{$job} = $hashref; } elsif ($structure eq 'simple') { $hashref->{id}=$job; push (@$result,$hashref); } } return $result; } # GRID JOB RESOURCES sub struct_gridjob_resources($$) { my $resources = shift; my $structure = shift; my $result; if ($structure eq "simple") { foreach my $resource ( keys( %{$resources} ) ) { push (@$result,{ site => $resource, jobs => $resources->{$resource} }); } return $result; } else { return $resources; } } # LIST OF NODES FOR A GRID JOB sub struct_gridjob_nodes($$) { my $resources = shift; my $structure = shift; my @result; foreach my $site ( keys( %{$resources} ) ) { foreach my $job ( keys( %{$resources->{$site}} ) ) { my $nodes=$resources->{$site}->{$job}->{nodes}; foreach my $node (@$nodes) { @result=(@result,$node); } } } return \@result; } # SINGLE ADMISSION RULE sub struct_admission_rule($$) { my $admission_rule = shift; my $structure = shift; my $result; my $current_rule_link = { href => $admission_rule->{uri}, rel => "self" }; my $hashref = { priority => $admission_rule->{priority}, enabled => $admission_rule->{enabled}, rule => nl2br($admission_rule->{rule}), links => $current_rule_link }; if ($structure eq 'simple') { $hashref->{id} = int($admission_rule->{id}); push (@$result,$hashref); } elsif ($structure eq 'oar') { $result->{$admission_rule ->{id}} = $hashref; } return $result; } # LIST OF ADMISSION RULES sub struct_admission_rule_list($$) { my $admission_rules = shift; my $structure = shift; my $result; foreach my $admission_rule (@$admission_rules) { my $current_rule_link = { href => $admission_rule->{uri}, rel => "self" }; my $hashref = { priority => $admission_rule->{priority}, enabled => $admission_rule->{enabled}, rule => nl2br($admission_rule->{rule}), links => $current_rule_link }; if ($structure eq 'oar') { $result->{$admission_rule ->{id}} = $hashref; } elsif ($structure eq 'simple') { $hashref->{id} = $admission_rule->{id}; push (@$result,$hashref); } }; return $result; } # CONFIG PARAMETERS sub struct_config_parameter($$) { my $parameter = shift; my $structure = shift; my $result; my $current_rule_link = { href => $parameter->{uri}, rel => "self" }; my $hashref = { id => int($parameter->{id}), value => $parameter->{value}, links => $current_rule_link }; if ($structure eq 'oar') { $result->{$parameter->{id}} = $hashref; } elsif ($structure eq 'simple') { $hashref->{id} = $parameter->{id}; push (@$result,$hashref); } return $result; } # LIST OF CONFIG PARAMETERS sub struct_config_parameters_list($$) { my $parameters = shift; my $structure = shift; my $result; foreach my $param ( keys( %{$parameters} ) ) { my $current_rule_link = { href => $parameters->{$param}->{uri}, rel => "self" }; my $hashref = { value => $parameters->{$param}->{value}, links => $current_rule_link }; if ($structure eq 'oar') { $result->{$param} = $hashref; } elsif ($structure eq 'simple') { $hashref->{id} = $param; push (@$result,$hashref); } } return $result; } ############################################################################## # Content type functions ############################################################################## # Get a suitable extension depending on the content-type sub get_ext($) { my $content_type = shift; # content_type may be of the form "application/json; charset=UTF-8" ($content_type)=split(/\s*;\s*/,$content_type); if ($content_type eq "text/yaml") { return "yaml"; } elsif ($content_type eq "text/html") { return "html"; } elsif ($content_type eq "application/octet-stream") { return "yaml"; } elsif ($content_type eq "multipart/form-data") { return "html"; } elsif ($content_type eq "application/json") { return "json"; } elsif ($content_type eq "application/x-gzip") { return "tgz"; } #elsif ($content_type eq "application/x-www-form-urlencoded") { return "json"; } else { return "UNKNOWN_TYPE"; } } # Get a suitable content-type depending on the extension sub get_content_type($) { my $format = shift; if ( $format eq "yaml" ) { return "text/yaml"; } elsif ( $format eq "html" ) { return "text/html"; } elsif ( $format eq "json" ) { return "application/json"; } elsif ( $format eq "tgz" || $format eq "tar.gz" ) { return "application/x-gzip"; } else { return "UNKNOWN_TYPE"; } } # Set oar output option and header depending on the format given # Also add the Allow (GET[,POST]) header variable if a second argument is given sub set_output_format { my $format=shift; my $allow=shift || "GET"; my $type = get_content_type($format); my $header=$q->header( -status => 200, -type => "$type", -allow => "$allow" ); return ($header,$type); } # Return the extension (second parameter) if defined, or the # corresponding one if the content_type if set. sub set_ext($$) { my $q=shift; my $ext=shift; if (defined($ext) && $ext ne "") { $ext =~ s/^\.*//; return $ext; } else { if (defined($q->http('Accept'))) { if (get_ext($q->http('Accept')) ne "UNKNOWN_TYPE") { return get_ext($q->http('Accept')); } elsif (defined($q->content_type)) { if (get_ext($q->content_type) ne "UNKNOWN_TYPE") { return get_ext($q->content_type); } else { ERROR 406, 'Invalid content type ', "Valid types are text/yaml, application/json or text/html"; } } else { ERROR 406, 'Invalid content type required ' .$q->http('Accept'), "Valid types are text/yaml, application/json or text/html"; } } elsif (defined($q->content_type)) { if (get_ext($q->content_type) ne "UNKNOWN_TYPE") { return get_ext($q->content_type); } else { ERROR 406, 'Invalid content type ' .$q->content_type, "Valid types are text/yaml, application/json or text/html"; } } else { ERROR 406, 'Invalid content type ', "Valid types are text/yaml, application/json or text/html"; } } } ############################################################################## # REST Functions ############################################################################## sub HEAD($$); sub GET($$); sub POST($$); sub DELETE($$); sub PUT($$); sub ERROR($$$); sub HEAD($$) { ( my $q, my $path ) = @_; if ( $q->request_method eq 'HEAD' && $q->path_info =~ /$path/ ) { return 1; } else { return 0; } } sub GET($$) { ( my $q, my $path ) = @_; if ( $q->request_method eq 'GET' && $q->path_info =~ /$path/ ) { return 1; } else { return 0; } } sub POST($$) { my ( $q, $path ) = @_; if ( $q->request_method eq 'POST' && $q->path_info =~ $path ) { return 1; } else { return 0; } } sub DELETE($$) { my ( $q, $path ) = @_; if ( $q->request_method eq 'DELETE' && $q->path_info =~ $path ) { return 1; } else { return 0; } } sub PUT($$) { my ( $q, $path ) = @_; if ( $q->request_method eq 'PUT' && $q->path_info =~ $path ) { return 1; } else { return 0; } } sub ERROR($$$) { ( my $status, my $title, my $message ) = @_; if ($DEBUG_MODE) { $title = "ERROR $status - " . $title ; $status = "200"; } # This is to prevent a loop as the export function may call ERROR! if (!defined($extension) || get_content_type($extension) eq "UNKNOW_TYPE") { if ($JSONenabled) { $extension = "json" ; } elsif ($YAMLenabled) { $extension = "yaml"; } else { $extension = "html"; } } elsif($extension eq "json" && !$JSONenabled) { $extension = "html"; } elsif($extension eq "yaml" && !$YAMLenabled) { $extension = "html"; } elsif($extension eq "xml" && !$XMLenabled) { $extension = "html"; } $status=$status+0; # To convert the status to an integer print $q->header( -status => $status, -type => get_content_type($extension) ); if ($extension eq "html") { print $q->title($title) ."\n"; print $q->h1($title) ."\n"; print $q->p("
\n". $message ."\n
"); } else { my $error = { code => $status, message => $message, title => $title }; print export($error,$extension); } local $^W = 0; next FCGI; } ############################################################################## # Posted resources ############################################################################## # Check the consistency of a posted job and load it into a hashref sub check_job($$) { my $data = shift; my $content_type = shift; my $job; # content_type may be of the form "application/json; charset=UTF-8" ($content_type)=split(/\s*;\s*/,$content_type); # If the data comes in the YAML format if ( $content_type eq 'text/yaml' ) { $job=import_yaml($data); } # If the data comes in the JSON format elsif ( $content_type eq 'application/json') { $job=import_json($data); } # If the data comes from an html form elsif ( $content_type eq 'application/x-www-form-urlencoded' ) { $job=import_html_form($data); } # We expect the data to be in YAML or JSON format else { ERROR 406, 'Job description must be in YAML or JSON', "The correct format for a job request is text/yaml or application/json. " . $content_type; exit 0; } # Job must have a "script" or script_path field unless there's a reservation unless ( $job->{reservation} or $job->{script} or $job->{script_path} or $job->{command}) { ERROR 400, 'Missing Required Field', 'A job must have a script, a command (script_path) or must be a reservation!'; exit 0; } # Clean options with an empty parameter that is normaly required foreach my $option ("resource", "name", "property", "script", "script_path", "type", "reservation", "directory", "project", "stagein", "connect", "resources", "array", "array-param-file", "queue", "checkpoint", "signal", "anterior", "notify", "resubmit", "import-job-key-from-file", "import-job-key-inline", "export-job-key-to-file", "stdout", "stderr", "stagein", "stagein-md5sum", "command", "script" ) { parameter_option($job,$option) } # Manage toggle options (no parameter) toggle_option($job,"use-job-key"); toggle_option($job,"scanscript"); toggle_option($job,"hold"); # Ignore some nonsense (for the API) options foreach my $option ("dumper","xml","yaml","json","help","version") { delete($job->{"$option"}); } # Return an error for some forbidden options if ($job->{"interactive"}) { ERROR 400, 'The API cannot manage interactive jobs', 'The API cannot manage interactive jobs'; exit 0; } return $job; } # Check the consistency of a job update and load it into a hashref sub check_job_update($$) { my $data = shift; my $content_type = shift; my $job; # content_type may be of the form "application/json; charset=UTF-8" ($content_type)=split(/\s*;\s*/,$content_type); # If the data comes in the YAML format if ( $content_type eq 'text/yaml' ) { $job=import_yaml($data); } # If the data comes in the JSON format elsif ( $content_type eq 'application/json' ) { $job=import_json($data); } # If the data comes from an html form elsif ( $content_type eq 'application/x-www-form-urlencoded' ) { $job=import_html_form($data); } # We expect the data to be in YAML or JSON format else { ERROR 406, 'Job description must be in YAML or JSON', "The correct format for a job request is text/yaml or application/json. " . $content_type; exit 0; } # Job must have a "method" field unless ( $job->{method} ) { ERROR 400, 'Missing Required Field', 'A job update must have a "method" field!'; exit 0; } return $job; } # Check the consistency of a posted oar resource and load it into a hashref sub check_resources($$) { my $data = shift; my $content_type = shift; my $resources; # content_type may be of the form "application/json; charset=UTF-8" ($content_type)=split(/\s*;\s*/,$content_type); # If the data comes in the YAML format if ( $content_type eq 'text/yaml' ) { $resources=import_yaml($data); } # If the data comes in the JSON format elsif ( $content_type eq 'application/json' ) { $resources=import_json($data); } # If the data comes from an html form elsif ( $content_type eq 'application/x-www-form-urlencoded' ) { $resources=import_html_form($data); $resources=import_yaml($resources->{"yaml_array"}); } # We expect the data to be in YAML or JSON format else { ERROR 406, 'Resource description must be in YAML or JSON', "The correct format for a resource request is text/yaml or application/json. " . $content_type; exit 0; } my $resources_array; if ( ref($resources) eq "HASH") { $resources_array = [ $resources ] ; } elsif ( ref($resources) eq "ARRAY") { $resources_array = $resources ; } else { ERROR 406, 'Bad type', 'resource must be an array or a hash!'; exit 0; } foreach my $r (@$resources_array) { # Resource must have a "hostname" or "network_address" field unless ( $r->{hostname} or $r->{network_address} ) { ERROR 400, 'Missing Required Field', 'A resource must have a hosname field or a network_address property!'; exit 0; } # Fill network_address with $hostname if provided if ( ! $r->{network_address} && $r->{hostname} ) { $r->{network_address}=$r->{hostname}; delete $r->{hostname}; } # Check for system properties foreach my $property ( keys %{$r} ) { if (OAR::Tools::check_resource_system_property($property) == 1){ ERROR 403, "Forbidden", "The property \"$property\" is a system one and can't be assigned by the admin"; exit 0; } } } return $resources_array; } # Check the consistency of a posted oar resource change state request sub check_resource_state($$) { my $data = shift; my $content_type = shift; my $resource; # content_type may be of the form "application/json; charset=UTF-8" ($content_type)=split(/\s*;\s*/,$content_type); # If the data comes in the YAML format if ( $content_type eq 'text/yaml' ) { $resource=import_yaml($data); } # If the data comes in the JSON format elsif ( $content_type eq 'application/json' ) { $resource=import_json($data); } # If the data comes from an html form elsif ( $content_type eq 'application/x-www-form-urlencoded' ) { $resource=import_html_form($data); } # We expect the data to be in YAML or JSON format else { ERROR 406, 'Job description must be in YAML or JSON', "The correct format for a job request is text/yaml or application/json. " . $content_type; exit 0; } # Resource must have a "state" field unless ( $resource->{state} ) { ERROR 400, 'Missing Required Field', 'A state change request must have a "state" field!'; exit 0; } # State must be "Alive, Absent or Dead" my $r=$resource->{state}; unless ( $r eq "Alive" || $r eq "Absent" || $r eq "Dead") { ERROR 400, 'Bad state', 'State mut be Alive, Absent or Dead!'; exit 0; } return $resource; } # Check the consistency of a posted request resource generation and load it into a hashref sub check_resource_description($$) { my $data = shift; my $content_type = shift; my $description; # content_type may be of the form "application/json; charset=UTF-8" ($content_type)=split(/\s*;\s*/,$content_type); # If the data comes in the YAML format if ( $content_type eq 'text/yaml' ) { $description = import_yaml($data); } # If the data comes in the JSON format elsif ( $content_type eq 'application/json' ) { $description = import_json($data); } # If the data comes from an html form elsif ( $content_type eq 'application/x-www-form-urlencoded' ) { $description = import_html_form($data); } # We expect the data to be in YAML or JSON format else { ERROR 406, 'Resource description must be in YAML or JSON', "The correct format for resource description is text/yaml or application/json. " . $content_type; exit 0; } # Resource description must have a "expression" field unless ( $description->{resources} ) { ERROR 400, 'Missing Required Field', 'Resources generation description must have a resources field'; exit 0; } # "properties" field must be a HASH #if (defined($description->{properties})) { # unless ( ref($description->{properties}) eq "HASH" ) { # ERROR 400, 'Missing Type Field', # 'The field properties must be a HASH type'; # exit 0; # } #} return $description; } # Check the consistency of a posted grid job and load it into a hashref sub check_grid_job($$) { my $data = shift; my $content_type = shift; my $job; # content_type may be of the form "application/json; charset=UTF-8" ($content_type)=split(/\s*;\s*/,$content_type); # If the data comes in the YAML format if ( $content_type eq 'text/yaml' ) { $job=import_yaml($data); } # If the data comes in the JSON format elsif ( $content_type eq 'application/json' ) { $job=import_json($data); } # If the data comes from an html form elsif ( $content_type eq 'application/x-www-form-urlencoded' ) { $job=import_html_form($data); } # We expect the data to be in YAML or JSON format else { ERROR 406, 'Job description must be in YAML or JSON', "The correct format for a job request is text/yaml or application/json. " . $content_type; exit 0; } # Job must have a "resources" or "file" field unless ( $job->{resources} or $job->{file} ) { ERROR 400, 'Missing Required Field', 'A grid job must have a resources or file field!'; exit 0; } # Clean options with an empty parameter that is normaly required parameter_option($job,"walltime"); parameter_option($job,"queue"); parameter_option($job,"identity_file"); parameter_option($job,"timeout"); parameter_option($job,"program"); parameter_option($job,"type"); parameter_option($job,"start_date"); parameter_option($job,"directory"); # Manage toggle options (no parameter) toggle_option($job,"FORCE"); toggle_option($job,"verbose"); return $job; } # Check the consistency of a posted oar admission rule and load it into a hashref sub check_admission_rule($$) { my $data = shift; my $content_type = shift; my $admission_rule; # content_type may be of the form "application/json; charset=UTF-8" ($content_type)=split(/\s*;\s*/,$content_type); # If the data comes in the YAML format if ( $content_type eq 'text/yaml' ) { $admission_rule = import_yaml($data); } # If the data comes in the JSON format elsif ( $content_type eq 'application/json' ) { $admission_rule = import_json($data); } # If the data comes from an html form elsif ( $content_type eq 'application/x-www-form-urlencoded' ) { $admission_rule = import_html_form($data); } # We expect the data to be in YAML or JSON format else { ERROR 406, 'Admission rule description must be in YAML or JSON', "The correct format for a job request is text/yaml or application/json. " . $content_type; exit 0; } # Admission rule must have a "priority" field unless ( $admission_rule->{priority}) { ERROR 400, 'Missing Required Field', 'An admission priority must have a priority field'; exit 0; } # Admission rule must have a "enabled" field unless ( $admission_rule->{enabled}) { ERROR 400, 'Missing Required Field', 'An admission enabled must have a enabled field'; exit 0; } # Admission rule must have a "rule" field unless ( $admission_rule->{rule}) { ERROR 400, 'Missing Required Field', 'An admission rule must have a rule field'; exit 0; } return $admission_rule; } # Check the consistency of a posted oar admission rule for update and load it into a hashref sub check_admission_rule_update($$) { my $data = shift; my $content_type = shift; my $admission_rule; # content_type may be of the form "application/json; charset=UTF-8" ($content_type)=split(/\s*;\s*/,$content_type); # If the data comes in the YAML format if ( $content_type eq 'text/yaml' ) { $admission_rule = import_yaml($data); } # If the data comes in the JSON format elsif ( $content_type eq 'application/json' ) { $admission_rule = import_json($data); } # If the data comes from an html form elsif ( $content_type eq 'application/x-www-form-urlencoded' ) { $admission_rule = import_html_form($data); } # We expect the data to be in YAML or JSON format else { ERROR 406, 'Admission rule description must be in YAML or JSON', "The correct format for a job request is text/yaml or application/json. " . $content_type; exit 0; } # Admission rule must have either a "method" or the "priority" and "enabled" and "rule" fields unless ( $admission_rule->{method} or ( $admission_rule->{priorty} and $admission_rule->{enabled} and $admission_rule->{rule} ) ) { ERROR 400, 'Missing Required Field', 'An admission rule update must have either a "method=delete" or "priority"= and "enabled"= and "rule"= fields!'; exit 0; } return $admission_rule; } # Check the consistency of a posted configuration variable and load it into a hashref sub check_configuration_variable($$) { my $data = shift; my $content_type = shift; my $parameter; # content_type may be of the form "application/json; charset=UTF-8" ($content_type)=split(/\s*;\s*/,$content_type); # If the data comes in the YAML format if ( $content_type eq 'text/yaml' ) { $parameter = import_yaml($data); } # If the data comes in the JSON format elsif ( $content_type eq 'application/json' ) { $parameter = import_json($data); } # If the data comes from an html form elsif ( $content_type eq 'application/x-www-form-urlencoded' ) { $parameter = import_html_form($data); } # We expect the data to be in YAML or JSON format else { ERROR 406, 'Configuration variable description must be in YAML or JSON', "The correct format for a job request is text/yaml or application/json. " . $content_type; exit 0; } # Parameter must have a "value" field unless ( $parameter->{value}) { ERROR 400, 'Missing Required Field', 'Configuration variable must have a value field'; exit 0; } return $parameter; } # Check the consistency of a posted chmod query sub check_chmod($$) { my $data = shift; my $content_type = shift; my $parameter; # content_type may be of the form "application/json; charset=UTF-8" ($content_type)=split(/\s*;\s*/,$content_type); # If the data comes in the YAML format if ( $content_type eq 'text/yaml' ) { $parameter = import_yaml($data); } # If the data comes in the JSON format elsif ( $content_type eq 'application/json' ) { $parameter = import_json($data); } # If the data comes from an html form elsif ( $content_type eq 'application/x-www-form-urlencoded' ) { $parameter = import_html_form($data); } # We expect the data to be in YAML or JSON format else { ERROR 406, 'Configuration variable description must be in YAML or JSON', "The correct format for a job request is text/yaml or application/json. " . $content_type; exit 0; } # Parameter must have a "mode" field unless ( $parameter->{mode}) { ERROR 400, 'Missing Required Field', 'Chmod query must have a mode field'; exit 0; } return $parameter; } ############################################################################## # Other functions ############################################################################## # APILIB Version sub get_version() { return $VERSION; } # Return the cgi handler sub get_cgi_handler() { return $q; } # Check if YAML is enabled or exits with an error sub check_yaml() { unless ($YAMLenabled) { ERROR 400, 'YAML not enabled', 'YAML perl module not loaded!'; exit 0; } } # Check if JSON is enabled or exits with an error sub check_json() { unless ($JSONenabled) { ERROR 400, 'JSON not enabled', 'JSON perl module not loaded!'; exit 0; } } # Clean a hash from a key having an empty value (for options with parameter) sub parameter_option($$) { my $hash = shift; my $key = shift; if ((defined($hash->{"$key"}) && ($hash->{"$key"} eq "")) || not defined($hash->{"$key"})) { delete($hash->{"$key"}) } } # Remove a toggle option if value is 0 sub toggle_option($$) { my $job = shift; my $option = shift; if (defined($job->{$option})) { if ($job->{$option} eq "0" ) { delete($job->{$option}); } else { $job->{$option}="" ; }; } } # Send a command and returns the output or exit with an error sub send_cmd($$) { my $cmd=shift; my $error_name=shift; my $cmdRes = `$cmd 2>&1`; my $err = $?; if ( $err != 0 ) { #$err = $err >> 8; ERROR( 400, "$error_name error", "$error_name command exited with status $err: $cmdRes. (Command was: $cmd)." ); exit 0; } else { return $cmdRes; } } # Get a ssh key file sub get_key($$$) { my $file=shift; my $key_type=shift; my $OARDODO_CMD=shift; if ($key_type ne "private") { $file = $file.".pub"; } my $cmdRes = OAR::API::send_cmd("$OARDODO_CMD cat $file","Cat keyfile"); if ($key_type eq "private" && ! $cmdRes =~ m/.*BEGIN.*KEY/ ) { OAR::API::ERROR( 400, "Error reading file", "The keyfile is unreadable or incorrect" ); } else { return $cmdRes; } } # add_pagination # add pagination to a set of record # parameters : record,total size,uri path_info,uri query_string,extension,max_items,offset,structure # return value : / sub add_pagination($$$$$$$$) { my $record = shift; my $total = shift; my $path = shift; my $params = shift; my $ext = shift; my $limit = shift; my $offset = shift; my $STRUCTURE = shift; my $offset_separation_char = "&"; # remove leading / into path if any $path =~ s/^\///; if(defined($params) && $params ne "") { # replacing all ';' char by '&' in query string $params =~ s/;/&/g; $params =~ s/offset=(.*?)(&|$)//g; $params =~ s/&$//g; # completing path with query string or separating char if ($params ne "") { $path .= "?".$params; } else { $offset_separation_char = "?"; } } else { # no parameters was passed, the separating char # must be '?' $offset_separation_char = "?"; } # current, next and previous uri my $current_uri; my $next_uri; my $previous_uri; if (!defined $record || $total <= 0) { # return an empty structure return { items => [], total => 0, offset => 0, links => [] }; } else { # setting current uri if ($limit != 0) { $current_uri = $path.$offset_separation_char."offset=".$offset; }else{ $current_uri = $path; } # setting next uri if ($limit != 0 && ($offset + $limit < $total)) { # next items list uri $next_uri = $path.$offset_separation_char."offset=".($offset + $limit); } # setting previous uri if ($limit != 0 && ($offset - $limit >= 0)) { # previous items list uri $previous_uri = $path.$offset_separation_char."offset=".($offset - $limit); } # uris are setting into hasmaps my $links; $current_uri = OAR::API::htmlize_uri(OAR::API::make_uri($current_uri,"",0),$ext); $current_uri = { href => $current_uri, rel => "self" }; push (@$links,$current_uri); if (defined($next_uri)) { $next_uri = OAR::API::htmlize_uri(OAR::API::make_uri($next_uri,"",0),$ext); $next_uri = { href => $next_uri, rel => "next" }; push (@$links,$next_uri); } if (defined($previous_uri)) { $previous_uri = OAR::API::htmlize_uri(OAR::API::make_uri($previous_uri,"",0),$ext); $previous_uri = { href => $previous_uri , rel => "previous" }; push (@$links,$previous_uri); } my $result = { items => $record, total => int($total), offset => int($offset), links => $links, api_timestamp => time() }; return $result; } } ######################################################################## # HTML functions ######################################################################## # our $HTML_HEADER; our $apiuri; sub job_html_header($) { my $job=shift; my $jobid=$job->{id}; my $hold="holds"; if ($job->{state} eq "Running") { $hold="rholds";} print $HTML_HEADER; print "\n\n\n"; print "
Job $jobid actions:\n"; print "
\n"; print "
\n"; print "\n"; print "\n"; print "
\n"; print "
\n"; print "\n"; print "\n"; print "
\n"; print "
\n"; print "\n"; print "\n"; print "
\n"; print "
\n"; print "\n"; print "\n"; print "
\n"; print "
\n"; print "\n"; print "\n"; print "
\n"; } sub resources_commit_button($) { my $resources=shift; my $yaml_array=OAR::API::export_yaml($resources); print "
\n"; print "\n"; print "\n"; print "

"; } #### Functions for desktop computing (Thiago Presa) sub message($) { my $msg = shift; warn $msg; } sub jobStageIn($) { my $jobid = shift; my $base = OAR::IO::connect() or die "cannot connect to the data base\n"; my $stagein = OAR::IO::get_job_stagein($base,$jobid); OAR::IO::disconnect($base); if ($stagein->{'method'} eq "FILE") { open F,"< ".$stagein->{'location'} or die "Can't open stagein ".$stagein->{'location'}.": $!"; print $q->header( -status => 200, -type => "application/x-gzip" ); print ; close F; } else { print $q->header( -status => 404, -type => "application/json" ); die "Stagein method ".$stagein->{'method'}." not yet implemented.\n"; } } sub jobStageInHead($) { my $jobid = shift; my $base = OAR::IO::connect() or die "cannot connect to the data base\n"; my $stagein = OAR::IO::get_job_stagein($base,$jobid); OAR::IO::disconnect($base); if ($stagein->{'method'} eq "FILE") { open F,"< ".$stagein->{'location'} or die "Can't open stagein ".$stagein->{'location'}.": $!"; print $q->header( -status => 200, -type => "application/x-gzip" ); close F; } else { print $q->header( -status => 404, -type => "application/json" ); die "Stagein method ".$stagein->{'method'}." not yet implemented.\n"; } } sub terminateJob($) { my $jobid = shift; my $base = OAR::IO::connect() or die "cannot connect to the data base\n"; OAR::IO::lock_table($base,["jobs","job_state_logs","resources","assigned_resources","event_logs","challenges","moldable_job_descriptions","job_types","job_dependencies","job_resource_groups","job_resource_descriptions"]); OAR::IO::set_job_state($base,$jobid,"Terminated"); OAR::IO::set_finish_date($base,$jobid); OAR::IO::set_job_message($base,$jobid,"ALL is GOOD"); OAR::IO::unlock_table($base); OAR::IO::disconnect($base); } sub runJob($) { my $jobid = shift; my $base = OAR::IO::connect() or die "cannot connect to the data base\n"; OAR::IO::lock_table($base,["jobs","job_state_logs","resources","assigned_resources","event_logs","challenges","moldable_job_descriptions","job_types","job_dependencies","job_resource_groups","job_resource_descriptions"]); #OAR::IO::set_running_date($base,$jobid); OAR::IO::set_job_state($base,$jobid,"Running"); OAR::IO::unlock_table($base); OAR::IO::disconnect($base); } sub errorJob($) { my $jobid = shift; my $base = OAR::IO::connect() or die "cannot connect to the data base\n"; OAR::IO::lock_table($base,["jobs","job_state_logs","resources","assigned_resources","event_logs","challenges","moldable_job_descriptions","job_types","job_dependencies","job_resource_groups","job_resource_descriptions"]); OAR::IO::set_running_date($base,$jobid); OAR::IO::set_job_state($base,$jobid,"Error"); OAR::IO::unlock_table($base); OAR::IO::disconnect($base); } sub sign_in($$$$$) { my $hostname = shift; my $remote_host = shift; my $remote_port = shift; my $expiry = shift; my $allow_create_node = shift; my $do_notify; my $base = OAR::IO::connect() or die "cannot connect to the data base\n"; my $is_desktop_computing = OAR::IO::is_node_desktop_computing($base,$hostname); if (defined $is_desktop_computing and $is_desktop_computing eq 'YES'){ OAR::IO::lock_table($base,["resources"]); if (OAR::IO::set_node_nextState_if_necessary($base,$hostname,"Alive") > 0){ $do_notify=1; } OAR::IO::set_node_expiryDate($base,$hostname, iolib::get_date($base) + $expiry); OAR::IO::unlock_table($base); } elsif ($allow_create_node) { my $resource = OAR::IO::add_resource($base, $hostname, "Alive"); OAR::IO::set_resources_property($base,{resources => [$resource]},"desktop_computing","YES"); OAR::IO::set_resource_nextState($base,$resource,"Alive"); OAR::IO::set_node_expiryDate($base,$hostname, iolib::get_date($base) + $expiry); $do_notify=1; } if ($do_notify) { OAR::Tools::notify_tcp_socket($remote_host,$remote_port,"ChState"); } OAR::IO::disconnect($base); } # Stop if the user is not authenticated # Args: # - #1 : the user as identified by the api # - #2 : an informative message # - #3 : "undef" or "oar". If "oar", then, it means that the user must be admin sub authenticate_user($$$) { my $authenticated_user = shift; my $msg = shift; my $user = shift; if ( not $authenticated_user =~ /(\w+)/ ) { OAR::API::ERROR( 401, "Permission denied", "A suitable authentication must be done to $msg" ); return 1; } if (defined($user)) { if ( not $authenticated_user eq "$user" ) { OAR::API::ERROR( 401, "Permission denied", "Only the $user user can $msg" ); $ENV{OARDO_BECOME_USER} = "$user"; return 2; } } return 0; } return 1; oar-2.5.7/sources/api/examples/0000755015014700017500000000000012677211234016000 5ustar neyronneyronoar-2.5.7/sources/api/examples/oarapi_examples.txt0000644015014700017500000000627712677211234021726 0ustar neyronneyron### Examples using ruby restclient ### > gem install rest-client > export PATH=$PATH:/var/lib/gems/1.8/bin > restclient http://kameleon:kameleon@localhost/oarapi-priv # Getting resources infos # in JSON irb(main):004:0> puts get('/resources.json') # in YAML irb(main):005:0> puts get('/resources.yaml') # Same thing irb(main):050:0> puts get('/resources', :accept=>"text/yaml") # Specifying the "oar" data structure irb(main):050:0> puts get('/resources.json?structure=oar') # Specifying the "simple" data structure irb(main):050:0> puts get('/resources.json?structure=simple') # Details about a resource irb(main):008:0> puts get('/resources/1.yaml') # Details and resources of a node irb(main):007:0> puts get('/resources/nodes/liza-1.yaml') # Details of all the resources (expansion) irb(main):007:0> puts get('/resources/all.yaml') # Getting jobs infos irb(main):006:0> puts get('/jobs.yaml') irb(main):009:0> puts get('/jobs/12.yaml') # Submiting a job (using JSON format) irb(main):010:0> require 'json' irb(main):012:0> j={ 'resource' => '/nodes=2/cpu=1', 'command' => '/usr/bin/id' } irb(main):015:0> job=post('/jobs' , j.to_json , :content_type => 'application/json') # Getting details about the previously submited job irb(main):035:0> uri=JSON.parse(job)['links'].find { |l| l["rel"]=="self" }["href"] irb(main):035:0> puts get(uri+"yaml") # Submitting a job using JSON format, but requiring the result in YAML irb(main):037:0> job=post('/jobs.yaml' , j.to_json , :content_type => 'application/json') # Submitting a job with a provided inline script irb(main):024:0> script="#!/bin/bash irb(main):025:0" #OAR --name test irb(main):025:0" echo \"Hello world\" irb(main):026:0" whoami irb(main):027:0" sleep 300 irb(main):028:0" " irb(main):029:0> j={ 'resource' => '/nodes=2/cpu=1', 'script' => script , 'scanscript' ==> 1, 'workdir' => '~kameleon'} irb(main):030:0> job=post('/jobs' , j.to_json , :content_type => 'application/json') # Deleting a job irb(main):111:0> delete("/jobs/#{JSON.parse(job)['id']}.yaml") # Send the checkpoint signal to a job irb(main):102:0> puts post('/jobs/2911/checkpoints/new','',:content_type => "application/json") # Suspending/resuming a job irb(main):102:0> puts post('/jobs/2911/holds/new','',:content_type => "application/json") irb(main):102:0> puts post('/jobs/2911/resumptions/new','',:content_type => "application/json") # Adding new resources (oar user only) irb(main):078:0> r=[{ 'network_address' => 'test1', 'besteffort'=>'NO' , 'cpu' => '10' }, { 'network_address' => 'test2', 'besteffort'=>'NO' , 'cpu' => '11' }] irb(main):078:0> puts post('/resources', r.to_json , :content_type => 'application/json') # Changing the state of a resource irb(main):079:0> puts post('/resources/11/state','{"state":"Dead"}',:content_type => 'application/json') # Deleting a resource by id (oar user only) irb(main):079:0> puts delete('/resources/11.yaml') # Deleting a resource by node/cpuset (oar user only) irb(main):080:0> puts delete('/resources/test2-p/1') ### Example using curl ### curl -i -X POST http://www/oarapi/jobs.json -H'Content-Type: application/json' -d '{"resource":"/nodes=1,walltime=00:10:00", "script_path":"\"sleep 600\"", "type":"inner=986078"}' oar-2.5.7/sources/api/examples/chandler_timesharing.rb0000755015014700017500000000674712677211234022520 0ustar neyronneyron#!/usr/bin/ruby # "Chandler" # Simple example ruby script using the OAR RESTFUL API # It prints a colored textmode status of the cluster # # This is a modified version of the original chandler to # better display information regarding timesharing jobs require 'rubygems' require 'rest_client' require 'json' require 'pp' require 'natural_sort' require 'date' # Custom variables APIURI="http://localhost/oarapi" NODENAME_REGEX="(.*)\.grenoble\.grid5000\.fr" NODENAME_MAX_LENGTH=12 # Function to get objects from the api # We use the JSON format and the 'simple' data structure def get(api,uri) begin return JSON.parse(api[uri+'?structure=simple'].get(:accept => 'application/json')) rescue => e if e.respond_to?('http_code') puts "ERROR #{e.http_code}:\n #{e.response.body}" else puts "Parse error:" puts e.inspect end exit 1 end end # Instanciate an api connection api = RestClient::Resource.new APIURI # Print a waiting message printf ("Please, wait while querying OAR API...\n\033[1A") # Get the resources resources = get(api,'/resources') # Get the running jobs jobs = get(api,'jobs/details') # Erase the waiting message printf ("\033[2K") # Construct a has of used resources used_resources={} resource_jobs={} jobs['items'].select{|job| job['state'] == "Running"}.each do |job| v=1 if job['types'].grep(/^timesharing=\*,name$/).any? v=2 end job['resources'].each do |r| resources['items'].select{|rr| rr['id']==r['id']}.each do |rr| h = rr['network_address'] if resource_jobs[h].nil? resource_jobs[h] = [job] else resource_jobs[h] << job end end used_resources[r['id']]=v if r['status']=="assigned" end end # Print summary puts "#{resources['items'].length} resources, #{used_resources.length} used, by #{jobs['items'].length} job(s)" # For each node col=0 NaturalSort::naturalsort(resources['items'].collect{|r| r['network_address']}.uniq).each do |node| state = "" if node!="" # some resources are not nodes (subnets) n = resources['items'].select{|r| r['network_address']==node} n.each do |resource| if resource['state'] == "Dead" state << "\033[41m\033[30mD\033[0m" elsif resource['state'] == "Absent" if resource['available_upto'].to_i > Time.new().to_i state << "\033[46m \033[0m" else state << "\033[41m\033[30mA\033[0m" end elsif resource['state'] == "Suspected" state << "\033[41m\033[30mS\033[0m" elsif resource['state'] == "Alive" #jobs=get(api,resource['jobs_uri']) #if jobs.nil? if used_resources[resource['id']].nil? state << "\033[42m \033[0m" elsif used_resources[resource['id']] == 2 state << "\033[47m\033[30mT\033[0m" else state << "\033[43m\033[30mJ\033[0m" end end end node=~/#{NODENAME_REGEX}/ puts "#{$1.rjust(NODENAME_MAX_LENGTH)}: #{state}" end end puts "\nNode state: \033[42m \033[0m=Free \033[46m \033[0m=Standby \033[41m\033[30mS\033[0m=Suspected \033[41m\033[30mA\033[0m=Absent \033[41m\033[30mD\033[0m=Dead\n" puts "Job kind: \033[43m\033[30mJ\033[0m=Exclusive job \033[47m\033[30mT\033[0m=Shared job\n\n" NaturalSort::naturalsort(resource_jobs).each do |k,v| print k,"\n" v.uniq.each do |j| d = Time.at(j['start_time'].to_i + j['walltime'].to_i) - Time.now puts " [#{j['id']}] #{j['owner']} (#{j['name']}), ends in #{(d/3600).to_i}h#{(d%3600/60).to_i}m#{(d%60).to_i}s" end print "\n" end oar-2.5.7/sources/api/examples/chandler.rb0000755015014700017500000000452012677211234020111 0ustar neyronneyron#!/usr/bin/ruby # "Chandler" # Simple example ruby script using the OAR RESTFUL API # It prints a colored textmode status of the cluster require 'rest_client' require 'json' require 'pp' # Custom variables APIURI="http://localhost/oarapi" NODENAME_REGEX="(.*)" COLS=2 # Function to get objects from the api # We use the JSON format and the 'simple' data structure def get(api,uri) begin return JSON.parse(api[uri+'?structure=simple'].get(:accept => 'application/json')) rescue => e if e.respond_to?('http_code') puts "ERROR #{e.http_code}:\n #{e.response.body}" else puts "Parse error:" puts e.inspect end exit 1 end end # Instanciate an api connection api = RestClient::Resource.new APIURI # Print a waiting message puts printf ("Please, wait while querying OAR API...\n\033[1A") # Get the resources resources = get(api,'/resources') # Get the running jobs jobs = get(api,'jobs/details') # Erase the waiting message printf ("\033[2K") # Construct a has of used resources used_resources={} jobs['items'].each do |job| job['resources'].each do |r| used_resources[r['id']]=1 if r['status']=="assigned" end end # Print summary puts "#{jobs['items'].length} jobs, #{resources['items'].length} resources, #{used_resources.length} used" # For each node col=0 resources['items'].collect{|r| r['network_address']}.uniq.each do |node| resources['items'].select{|r| r['network_address']==node}.each do |resource| if resource['state'] == "Dead" printf("\033[41m\033[30mD\033[0m") elsif resource['state'] == "Absent" if resource['available_upto'].to_i > Time.new().to_i printf("\033[46m \033[0m") else printf("\033[41m\033[30mA\033[0m") end elsif resource['state'] == "Suspected" printf("\033[41m\033[30mS\033[0m") elsif resource['state'] == "Alive" #jobs=get(api,resource['jobs_uri']) #if jobs.nil? if used_resources[resource['id']].nil? printf("\033[42m \033[0m") else printf("\033[47m\033[30mJ\033[0m") end end end node=~/#{NODENAME_REGEX}/ print $1.ljust(20) col+=1 if col >= COLS col = 0 puts end end printf("\n\n\033[42m \033[0m=Free \033[46m \033[0m=Standby \033[47m\033[30mJ\033[0m=Job \033[41m\033[30mS\033[0m=Suspected \033[41m\033[30mA\033[0m=Absent \033[41m\033[30mD\033[0m=Dead\n\n") oar-2.5.7/sources/api/apache2.conf.in0000644015014700017500000001666412677211234016756 0ustar neyronneyron# Apache2 configuration for the OAR API # WARNING: the OAR API requires Apache fastcgi and a way for the httpd user to # become oar. This can be achieved using Apache suexec. But since the suexec # mechanism is global to a virtual host, enabling it for the OAR API might # break other CGI programs (e.g. monika). As a result, a solution is to setup # several virtual hosts. The configuration proposed below sets a port based # virtual host listening on 6668. # Furthermore the suexec user cannot have a system UID, which is the case of # the oar user by default. One may need to change that uid (e.g. on Centos). #Virtual host to isolate the oar-restful-api (suexec) setup Listen 6668 # Aliases to the API. ScriptAlias /oarapi %%CGIDIR%%/oarapi/oarapi.cgi ScriptAlias /oarapi-public %%CGIDIR%%/oarapi/oarapi.cgi #ScriptAlias /oarapi-debug %%CGIDIR%%/oarapi/oarapi-debug.cgi #ScriptAlias /oarapi-priv %%CGIDIR%%/oarapi/oarapi.cgi #ScriptAlias /oarapi-cigri %%CGIDIR%%/oarapi/oarapi.cgi # FastCGI server FastCgiServer %%CGIDIR%%/oarapi/oarapi.cgi -processes 3 -user oar -group oar # Suexec configuration SuexecUserGroup oar oar # Default options for the oar api Options +ExecCGI -MultiViews +FollowSymLinks SetEnv OARCONFFILE %%ETCDIR%%/oar/oar.conf # FastCGI handler AddHandler fcgid-script .cgi = 2.3> Require local Order Deny,Allow Deny from all Allow from localhost Allow from localhost.localdomain # Set the X_API_PATH_PREFIX variable to value of the header of the same name RewriteEngine On RewriteCond %{HTTP:X_API_PATH_PREFIX} (.*) RewriteRule .* - [E=X_API_PATH_PREFIX:%1] # By URI options # This is where you should pay attention to security! # The OAR API trusts the X_REMOTE_IDENT header variable to be the login name # of the user that makes the query if there is no other authentication mechanism # (ie basic auth). # Such a header variable is set by the http client. So, you should at least # unset this variable (to disable auth) or erase it with something generated or # filtered by the current apache configuration. # Note that you can disable the X_REMOTE_IDENT trusting by setting API_TRUST_IDENT # to 0 into the oar.conf file. # In this first example, we set up a public API that will never satisfy requests # that need authentication (for example /jobs/100 will do a 401) # IMPORTANT: if you have not the headers_module, you are vulnerable to # identity stealing as the X_REMOTE_IDENT may be set by the client! # If you are in this case, please, set API_TRUST_IDENT=0 into oar.conf RequestHeader unset X_REMOTE_IDENT # In this second example, we set up a "pident" authentication if possible and an # an ldap basic auth for the hosts that are not in the "Allow from" directives above. # If the ident module is not setup, we unset the X_REMOTE_IDENT variable to # protect from malicious users that could inject a login name. # THIS IS IMPORTANT!! # You need at least the headers_module or a properly ident setup. # In other words, if you have not the ident_module, nor headers_module, # you are vulnerable to identity stealing! # If you are in this case, please, set API_TRUST_IDENT=0 into oar.conf. RequestHeader unset X_REMOTE_IDENT # Pidentd (or authd) is a daemon that should run on the client host to tell # to the server who is making the query. So, be aware that with this kind of # authentication, you have to trust the client host! # In other words, if you accept connections from a user's laptop for example, # you are vulnerable as long as the user can create a login name of its choice # on his laptop! So, be sure of your "Allow from" directives above! IdentityCheck On # Set the X_REMOTE_IDENT http header and variable to REMOTE_IDENT env value RewriteEngine On RewriteCond %{REMOTE_IDENT} (.*) RewriteRule .* - [E=X_REMOTE_IDENT:%1] RequestHeader add X_REMOTE_IDENT %{X_REMOTE_IDENT}e # Ldap auth for external users (not in the "Allow from" list) # In this example, we suppose that the users have an ldap account # common to the authentication used by the oar server. AuthType basic AuthBasicProvider ldap AuthName "Authorized Users Only" AuthzLDAPAuthoritative off AuthLDAPURL "ldaps://myldaphost.mydomain/dc=mydomain,dc=fr?uid?sub?(objectClass=posixAccount)" Require valid-user Satisfy any # This example sets up a simple basic authentication with user/password # into the /etc/oar/api-users file (use htpasswd command to create the # password entries. # # Options +ExecCGI -MultiViews +FollowSymLinks # AuthType basic # AuthUserfile /etc/oar/api-users # AuthName "OAR API authentication" # Require valid-user # RewriteEngine On # RewriteCond %{REMOTE_USER} (.*) # RewriteRule .* - [E=X_REMOTE_IDENT:%1] # RequestHeader add X_REMOTE_IDENT %{X_REMOTE_IDENT}e # # In this last example, we set up a trusted connection with a client that # has a specific SSL certificate. This client may do queries for whatever login # name that it sends through the X_REMOTE_IDENT header variable. # This is commonly the case for a grid middleware that has already authenticated # users and that may be trusted by OAR. # # # # Require SSL on this location # SSLRequireSSL # # Check the validity of the client SSL certificate # SSLVerifyClient require # SSLVerifyDepth 1 # # In this example, we check that the client is the cigri middleware of the # # Ciment project: the organisational unit presented by the certificatethe # # should be "CIMENT" and the DN should be "CIGRI" # SSLRequire ( %{SSL_CLIENT_S_DN_OU} eq "CIMENT" \ # and %{SSL_CLIENT_S_DN_CN} eq "CIGRI" ) # # We can also do some filtering on the X_REMOTE_IDENT header # ## This example only allows users kameleon and oar to be authenticated to the API # # RewriteEngine On # # RewriteCond %{HTTP:X_REMOTE_IDENT} (.*) # # RewriteRule .* - [E=X_REMOTE_IDENT:%1] # # RewriteCond %{HTTP:X_REMOTE_IDENT} !=kameleon # # RewriteCond %{HTTP:X_REMOTE_IDENT} !=oar # # RewriteRule .* - [E=X_REMOTE_IDENT:] # # RequestHeader set X_REMOTE_IDENT %{X_REMOTE_IDENT}e # # oar-2.5.7/sources/api/features/0000755015014700017500000000000012677211234016000 5ustar neyronneyronoar-2.5.7/sources/api/features/job_submit.feature0000644015014700017500000000041212677211234021507 0ustar neyronneyronFeature: Submit jobs As a user I want to submit a job In order to get computation done Scenario: command job submission successful When I submit a "date" command job Then the job status should be "submitted" And the job list should not be empty oar-2.5.7/sources/api/features/step_definitions/0000755015014700017500000000000012677211234021346 5ustar neyronneyronoar-2.5.7/sources/api/features/step_definitions/oar_steps.rb0000644015014700017500000000076712677211234023704 0ustar neyronneyronrequire 'oarrestapi_lib' When /^I submit a "([^"]*)" command job$/ do |command| APIURI="http://kameleon:kameleon@192.168.56.101/oarapi-priv" @oar_server = OarApi.new(APIURI) job = { 'resource' => "/nodes=1/core=1" , 'script' => command } @oar_server.submit_job(job) end Then /^the job status should be "([^"]*)"$/ do |status| @oar_server.jobstatus['status'].to_s.should == status end Then /^the job list should not be empty$/ do @oar_server.jobarray['items'].should_not be_empty end oar-2.5.7/sources/api/features/oarrestapi_lib.rb0000644015014700017500000003674112677211234021337 0ustar neyronneyronrequire 'rubygems' require 'rest_client' require 'json' require 'pp' ####################################################################### #Coded By Narayanan K - GSOC Testsuites project - RESTful API Library ####################################################################### class OarApi attr_accessor :jobhash, :statushash, :specificjobdetails, :oarv, :oartz, :jobarray, :deletehash, :apiuri, :value attr_reader :deletestatus,:jobstatus,:api,:chkpointstatus,:holdjob,:rholdjob,:signalreturn,:resumejob,:resources,:resourcedetails,:resstatus,:specificres,:noderesources def initialize(apiuri,get_uri="") @apiuri = apiuri @api = RestClient::Resource.new @apiuri @jobarray = [] end ######################################################################## # # GET REST OAR API # # Purpose: Function to get objects from the api # # Result: We use the JSON format # ######################################################################## def get(api,uri) begin return JSON.parse(api[uri].get(:accept => 'application/json')) rescue => e if e.respond_to?('http_code') puts "ERROR #{e.http_code}:\n #{e.response.body}" else puts "Parse error:" puts e.inspect end exit 1 end end ######################################################################## # # POST REST OAR API # # Purpose: Function to create/delete/hold/resume objects through the api # # Result: We use the JSON format. # ######################################################################## def post(api,uri,j) begin j=j.to_json return JSON.parse(api[uri].post( j,:content_type => 'application/json')) rescue => e if e.respond_to?('http_code') puts "ERROR #{e.http_code}:\n #{e.response.body}" else puts "Parse error:" puts e.inspect end exit 1 end end ######################################################################## # # DELETE REST OAR API # # Purpose: Function to Delete objects through the api # # Result: We use the JSON format. # ######################################################################## def delete(api, uri) begin return JSON.parse(api[uri].delete(:content_type => 'application/json')) rescue => e if e.respond_to?('http_code') puts "ERROR #{e.http_code}:\n #{e.response.body}" else puts "Parse error:" puts e.inspect end exit 1 end end ######################################################################## # # GENERIC FUNCTIONS TO GET REST OBJECTS # ######################################################################## def get_hash(uri) @value = get(@api, uri) if !@value.is_a?(Hash) raise "Error: GET #{uri} should return a hash" end end ######################################################################## # # Method: oar_version # # Usecase01: Gives version info & Timezone about OAR and OAR API/Server. # # Input: Nil # # Result: GETs the Version details(hash)and stores in Hash oarv # ######################################################################## def oar_version @oarv = get(@api, '/version') if !@oarv.is_a?(Hash) or @oarv.empty? raise 'Error: In return value of GET /version API' end end ######################################################################## # # Method: oar_timezone # # Usecase02: Gives the timezone of the OAR API server. # # Input: Nil # # Result: GETs the Timezone details(hash)and stores in Hash oart # ######################################################################## def oar_timezone @oartz = get(@api, '/timezone') if !@oartz.is_a?(Hash) or @oartz.empty? raise 'Error: In return value of GET /timezone API' end end ######################################################################## # # Method: full_job_details # # Usecase03: List the current jobs & some details like assigned resources # # Input: Nil # # Result: GETs details of current jobs(array of hashes)& stores in jobhash # ######################################################################## def full_job_details @jobarray = get(@api,'/jobs/details') if !@jobarray.is_a?(Hash) raise 'Error: In return value of GET /jobs/details API' end end ######################################################################## # # Method: run_job_details # # Usecase04: List currently running jobs # # Input: Nil # # Result: GETs details of running jobs(array of hashes)& stores in jobhash # ######################################################################## def run_job_details @jobarray = get(@api,'/jobs') if !@jobarray.is_a?(Hash) raise 'Error: In return value of GET /jobs API' end end ######################################################################## # # Method: specific_job_details(jobid) # # Usecase05: Get Details of a specific job # # Input: jobid # # Result: GETs details of specific job & stores in hash specificjobdetails # ######################################################################## def specific_job_details(jobid) @specificjobdetails = get(@api, "/jobs/#{jobid}") if !@specificjobdetails.is_a?(Hash) or @specificjobdetails.empty? raise 'Error: In return value of GET /jobs/ API' end end ######################################################################## # # Method: dump_job_table # # Usecase06: Dump the jobs table (only current jobs) # # Input: None # # Result: Dumps details of current jobs into array of hash - jobhash # ######################################################################## def dump_job_table @jobarray = get(@api,'/jobs/table') if !@jobarray.is_a?(Hash) raise 'Error: In return value of GET /jobs/table API' end end ######################################################################## # # Method: submit_job(jhash) # # Usecase07: Submits job # # Input: jhash containing details of resources,jobscript in hash form # # Result: Returns the submitted job Details in Hash and stores in jobstatus # ######################################################################## def submit_job(jhash) @jobstatus = post(@api, '/jobs', jhash) if !@jobstatus.is_a?(Hash) or @jobstatus.empty? raise 'Error: In return value of POST /jobs API' end end ######################################################################## # # Method: del_job(jobid) # # Usecase08: Delete job - POST /jobs/id/deletions/new # # Input: jobid # # Result: Returns the deleted job Details in Hash and stores in deletestatus # ######################################################################## def del_job(jobid) @deletestatus = post(@api,"/jobs/#{jobid}/deletions/new", '') if !@deletestatus.is_a?(Hash) or @deletestatus.empty? raise 'Error: In return value of POST /jobs//deletions/new API' end end def del_array_job(jobid) @deletestatus = post(@api,"/jobs/array/#{jobid}/deletions/new", '') if !@deletestatus.is_a?(Hash) or @deletestatus.empty? raise 'Error: In return value of POST /jobs/array//deletions/new API' end end ######################################################################## # # Method: send_checkpoint(jobid) # # Usecase09: Send checkpoint signal to a job # # Input: jobid # # Result: Returns details of checkpointed job in hash - chkpointstatus # ######################################################################## def send_checkpoint(jobid) @chkpointstatus = post(@api,"/jobs/#{jobid}/checkpoints/new", '') if !@chkpointstatus.is_a?(Hash) or @chkpointstatus.empty? raise 'Error: In return value of POST /jobs//checkpoints/new API' end end ######################################################################## # # Method: hold_waiting_job(jobid) # # Usecase10: Hold a Waiting job # # Input: jobid # # Result: Returns details of holded job in hash - holdjob # ######################################################################## def hold_waiting_job(jobid) @holdjob = post(@api,"/jobs/#{jobid}/holds/new", '') if !@holdjob.is_a?(Hash) or @holdjob.empty? raise 'Error: In return value of POST /jobs//holds/new API' end end ######################################################################## # # Method: hold_running_job(jobid) # # Usecase11: Hold a Running job # # Input: jobid # # Result: Returns details of holded job in hash - rholdjob # ######################################################################## def hold_running_job(jobid) @rholdjob = post(@api,"/jobs/#{jobid}/rholds/new", '') if !@rholdjob.is_a?(Hash) or @rholdjob.empty? raise 'Error: In return value of POST /jobs//rholds/new API' end end ######################################################################## # # Method: resume_hold_job(jobid) # # Usecase12: Resume a Holded job # # Input: jobid # # Result: Returns details of resumed job in hash - resumejob # ######################################################################## def resume_hold_job(jobid) @resumejob = post(@api,"/jobs/#{jobid}/resumption/new", '') if !@resumejob.is_a?(Hash) or @resumejob.empty? raise 'Error: In return value of POST /jobs//resumption/new API' end end ######################################################################## # # Method: send_signal_job(jobid, signo) # # Usecase13: Send signal to a job with signalno. # # Input: jobid, signal number # # Result: Returns details of signalled job in hash - signalreturn # ######################################################################## def send_signal_job(jobid, signo) @signalreturn = post(@api,"/jobs/#{jobid}/signal/#{signo}", '') if !@signalreturn.is_a?(Hash) or @signalreturn.empty? raise 'Error: In return value of POST /jobs//signal/ API' end end ######################################################################## # # Method: update_job(jobid, actionhash) # # Usecase14: Update a job # # Input: jobid, actionhash # # Result: Returns details of updated job in hash - updatehash # ######################################################################## def update_job(jobid, actionhash) @updatehash = post(@api, "/jobs/#{jobid}",actionhash) if !@updatehash.is_a?(Hash) or @updatehash.empty? raise 'Error: In return value of POST /jobs// API' end end ######################################################################## # # Method: resource_list_state # # Usecase15: Get list of Resources and state # # Input: None # # Result: Returns details of resources & states in array of hashes - resources # ######################################################################## def resource_list_state @resources = get(@api, '/resources') if !@resources.is_a?(Hash) raise 'Error: In return value of GET /resources API' end end ######################################################################## # # Method: list_resource_details # # Usecase16: Get list of all the resources and all their details # # Input: None # # Result: Returns details of resource list in array of hashes - resourcedetails # ######################################################################## def list_resource_details @resourcedetails = get(@api, '/resources/full') if !@resourcedetails.is_a?(Hash) raise 'Error: In return value of GET /resources/full API' end end ######################################################################## # # Method: specific_resource_details(jobid) # # Usecase17: Get details of resources identified by an ID # # Input: jobid # # Result: Returns details of specific resource in array of hashes - specificres # ######################################################################## def specific_resource_details(jobid) @specificres = get(@api, "/jobs/#{jobid}/resources") if !@specificres.is_a?(Hash) or @specificres.empty? raise 'Error: In return value of GET /jobs//resources API' end end ######################################################################## # # Method: resource_of_nodes(netaddr) # # Usecase18: Get details about the resources belonging to the node identified by network address # # Input: netaddr # # Result: Returns details of resource of nodes - noderesources # ######################################################################## def resource_of_nodes(netaddr) @noderesources = get(@api,"/resources/nodes/#{netaddr}") if !@noderesources.is_a?(Hash) or @noderesources.empty? raise 'Error: In return value of GET /resources/nodes/ API' end end ######################################################################## # # Method: create_resource(rhash) # # Usecase19: Create Resource # # Input: rhash # # Result: Returns details of created resources - resstatus # ######################################################################## def create_resource(rhash) @resstatus = post(@api,'/resources', rhash) if !@resstatus.is_a?(Hash) or @resstatus.empty? raise 'Error: In return value of POST /resources API' end end ######################################################################## # # Method: statechange_resource(jobid, hasharray) # # Usecase20: Change the state of resources of a job # # Input: jobid, hasharray # # Result: Returns details of created resources in hash- statushash # ######################################################################## def statechange_resource(jobid, hasharray) @statushash = post(@api, '/resources/#{jobid}/state', hasharray) if !@statushash.is_a?(Hash) or @statushash.empty? raise 'Error: In return value of POST /resources//state API' end end ######################################################################## # # Method: delete_job(jobid) # # Usecase21: Delete or kill a job. # # Input: jobid # # Result: Returns details of deleted job in hash- deletehash # ######################################################################## def delete_job(jobid) @deletehash = delete(@api,"/jobs/#{jobid}") if !@deletehash.is_a?(Hash) or @deletehash.empty? raise 'Error: In return value of DELETE /jobs/ API' end end ######################################################################## # # Method: delete_resource(resid) # # Usecase22: Delete the resource identified by id # # Input: resid # # Result: Returns details of deleted resources in hash- deletehash # ######################################################################## def delete_resource(resid) @deletehash = delete(@api,"/resources/#{resid}") if !@deletehash.is_a?(Hash) or @deletehash.empty? raise 'Error: In return value of DELETE /resources/ API' end end ######################################################################## # # Method: delete_resource_cpuset(node, cpuid) # # Usecase23: Delete the resource corresponding to cpuset id on node node. # # Input: node, cpuid # # Result: Returns details of deleted resources in hash- deletehash # ######################################################################## def delete_resource_cpuset(node, cpuid) @deletehash = delete(@api,"/resources/#{node}/#{cpuid}") if !@deletehash.is_a?(Hash) or @deletehash.empty? raise 'Error: In return value of DELETE /resources// API' end end ######################################################################## # # Method: oar_whoami # # Usecase24: Gives authenticated user seen by OAR API. # # Input: Nil # # Result: GETs the authenticated user details(hash)and stores in Hash oarv # ######################################################################## def oar_whoami @oarv = get(@api, '/whoami') if !@oarv.is_a?(Hash) or @oarv.empty? raise 'Error: In return value of GET /version API' end end ############################################ def get_link_href(rel) @value['links'].each do |link| if link.is_a?(Hash) && link['rel'] == rel return link['href'] end end raise "#{rel} link not found!" end def get_link_href_from_array(array,rel) array.each do |link| if link.is_a?(Hash) && link['rel'] == rel return link['href'] end end raise "#{rel} link not found!" end end oar-2.5.7/sources/api/api_html_header.pl0000644015014700017500000000106712677211234017630 0ustar neyronneyron$HTML_HEADER = " OAR REST API


RESOURCES    GENERATE RESOURCES    JOBS    JOB SUBMISSION    ADMISSION RULES    RULE SUBMISSION    CONFIGURATION   
" oar-2.5.7/sources/api/livecd_snapshot1.png0000644015014700017500000020516012677211234020142 0ustar neyronneyron‰PNG  IHDRÉŠBX pHYsëëqÍ• IDATxœì½ŒÇyçýÝÃèEÍaô¢çÀ;ìrà•%û²Úuüâu^­ì¦$¢¤&­{S¾ÀG:‡DÒy%^p #gÑÎ Ç XœíuŸ¨ ŽI#¶vKÖ± !^˜´¸i¼¸ P|ÿè™ÞžîêîêŸÓ½ûý`AÎÔTW=UÝÓó|û©!„B!dß³àÚµkó6ƒB!„2Nþ‡ãg¾òÕ†ófÐïÏ×B!„BÈixßœùòé"ê8ýßÎúý ?Ü,¢pB!„B*Îá»6ÖÙ>ýßΞüÇó¶hR²7<Ð~œo}|À…n¸öB!„RqW'þwRg{ëÕ­tÆâxé^ü€eY`CBÂFൔÓDÀ²¦¯mÀM,Ûʵ-„B!„Ô˲`CÚÀÌ‹© mÁr^H/¼t…0˜"'ÿû‹ó7Í0ûïn5ÞÌÁº !„¤ãñGOzß>qê´2ÝýÈMws·Á ÞB!9àx×Á—ÝŠðÝäï¥O NÑS$ä¿uã[o½åý›?ðË_üRz —»vÌ4f"†!„dãÔ—ðèŸ=é¾}üÑ“î[ïGÜ{•·bob0ïÞ„’/®p^üæoþ¦ûÑ[ÿòKËõݽn½Kˆ—þ›¿õ›þ$À+¿xÅS¯[ Zr„E ”á Üø[7¸ñÆßú—·,à7À>øW¶^ Vãÿ%aÄ€B2sê‰Ç<úø“îMõÑÇŸ<õÄc§¾ôØ£Oõ@øýÖÍæ”£È<–woBÉ—YUðÖÿûÖ®³ýÛ7þòõ_*í¢öÒ£ê‚V¸ja`«sKÈ·ÞzëÆopãoß覿ò‹W P6~Cù̉Bò"úÁØýöÄŸs—>¯<ÒKw2¨gDzé.ʈA”qµÃ/ñË™ »Eêã3'BÉ åušè¸û'¾è ì~jÃÿBY2ïÞ„’+Ò–þ;°3á3wfϬƒÝCüt¯îå•­Wâ½ô) a ½/ãB3:Fª°¦“øÌ‰Bò":bpü '•9¥-áäÙ/Ÿvò(# ŒBHïŸSí[†wÚy1%ÆK ÒKwQ%šV£À;ˆÀm¼-RˆXê'R„B²1½ß†E1 „¢ñ9Ý3 ¸ ÑtáQwÐô¨é±~|ƒzt½ô½(„ˆ[Ÿ3+âü€ÛVo{åŸ^ "»pBÉÎÑ?<~îkgÏ~åôÑ?œìyîkgt÷6v¿uÒ½yÂ^G—F!DÑhî¾™z×oýË[“ÙÆiOüêð™Ç“ŒÊA=¿ü—_~à·?àfšLT@X¸@Aär¥Ä]ëmò•­W&Öë>s"„<8úðñs_?ëè7Å{õäI,™BHv¼ƒœÙÆîG3ª`7¤à!ÄKwþuKSN_Ž L¨wS,X^MãXïµ&BˆøgUBIË‘‡9/Îýxn°nº‹ó‘“¼ûÒÃ'„’™™ˆó¯’U¬åãÛÙC„—î¼ð–6ûoL¸Qs ”‰Þ¢½ö¹¯w3X3‡„K!$G>sìü7ž9ÿõgŽ|ÆïÓB©.žeˆT›Ïî‚ì9JYÔì¿É½ô)~a0zg+Df‹–J;B„ëZBHyè€÷XB©ý~ß¿ ‘_ ¸3-Ëã»è¥OYpíÚµA¿ ÓífigNù„B!„ì[Šs¶Sãxég¾|úÌW¾º18óåÓó3‰B!„2NLw¿™Jtæ+_‡1„B!{Šÿõë_ÏÛ„z#â³T‡À¬â)2¢Ê£^ È›¨^žh6År …g“³yz½×|à'>ÿ97£ŽÁµk×T¦%`aa!{!„B!å“‹³°°‹1û– *ˆDU !Q+UàÂß\ðåU¬Jôâó/ª Ôâüóç³B!„R>¹¸1n!$•pñ“sáùxßzgïâWªW#„Ô÷ÞåŠ÷En·5Îú¬-±ª@BJ;  f¡i9y”ÙÜr JÒ“"aMTRmFªh^†a=R}|‘neàÛ÷SçýÔû5þ4ºéweÕÁüa&?Š@ÇÚXÛ‚ock ëÀ`GE§B*‹{£Kww"{™ØüqÁkš§÷Æ¥¶Ñ\…U%Zè.­†×¹,iœ*õ)!{çÇìÞOßëþªÉÂ>Švåƒù½9Ý×NÕæ³ù^G— im ÛÂj Ú¦ìÀ HVG¯‚á{’ó÷7éP"zpå’`w…„ª`뵋äÎûœFçŽÜt¢2ª‚@N^V„ì}\m€äOß}ž®÷möŰR”km^äX&U!$=ÑB‚þݼ ϰõÚŶіcM=°‹“íöÞÆ]8)š E«ðÂ!dߢùÜk.#u*M:j(/8„’}Kpòquå}–©Ìô Sœmža뵋rŒ3_?“º¶Ë?½|ù§—×n_;t×a¥¾”XUž|BH4åÿìEÓ¦hk³ØF©5¾ÙÆî|ƒêjƒÔÄŠ :Jb× ò¼í_Ý>÷õdQ‚0ypäþ£Ý›–#LÒQàªD„씃ï‘ñ+ëWÊöÙŸ£µ•j&!¤ × Ú׸èj$ªàÒO/žy*} @ÉùoŸ»ø£ Ê'k©, ¢%úöãEOÈ^Á« ¼‘c3cvrÊŠø*M}`"k5+ͦìmïáú&BªFpñ:HH¬ ’Î(ÐäòO/èvq ³Ô Z¢dÀµk×ýþ™/Ÿ>ó•¯^»víÅç_LmÓùçÏ_xþBÆB!„BÊ'7Æ)äý¿ÎѰ½À€4n¸ðݧ žûöYÇ}ÏΑûv¶½)#sÔ6ÚÊXĉ?yÂg‰CïÕÞæßž?ñùÏøÂIGìá³D!„BªÁ>˜;¯ /U s°}ú/NÓGæH={!nÕT‡šô4!„BÙŸÔamVõ–SúW·sŸW ä™ÿþŒbýÓU`ÖMªF_B!„’XDÁ¯„mF9ªÀá¹óÏ z¯´U®JD!„Bö2óRÓÄK?½X¬N|ñxègáªÊ®:ÿüùìåR!„BHùÐÙSØkƒHU`A´ Q«+«Gî?ª¨7R ØO Ù­É¥B!„ò¡³‰çS„fð¨‚íŸ^* ‚xN|ñ¸r¦¹§¿3þê›3kô~öj¹@¯¯„B!¥QS÷iŸ’{<Ážy]~¸ÀaueuíöµÝu4T¢{â³pï+¿x+7Kä¶ÞHm@!„BJÅãmGŒØ)‡nwy" ôT"„A}U€W~ñµ!„R鞎¯ýÎÚ±‡OìÕBHÍPzÉ)ÂU°ýóùŒ#rðŽ&ÒQkt­Uµ!„RM^ùÅ[|î`bÒrª\Ùwc6úýÞ¼Ìñ¢©  {@8PB!å°øÝ_Ûá78þžÔ×Ö ¨T€·:NÁêÊê‰/ž˜ÙB!nÏîc@!„ýÂæ÷K8„ì)l¿)^UP9Bö?ö !„’•|㫼qË3xaõƒ7ØÊ<œ!µ‹¿ù½ÅO3ÖNöúo?ªS « V§NˆO-$%ãƒjMU ¬›¤% \Ï;‹_Î,‚y[A!„|âw?á•>=àþ«ÃÖ/ÞZýà>%0GUàBm@”Èu¸è¸¤6¨#™UAIDªdAß« ‚y\UL +6˜?X/!„BæNS4ïü?îüÉ?ýÄyë“=é³g—ÁN¹ %¢¿N!„ì[Ú¢)€¢e8ª`2šèúvRUà \¨4õ,ä\ú ª‚‚FQ¤!  æÎàêÈy¡© %bà›7¬=ðåqÞ§,l³Íà !„R8³Ë’¦.A}ÛãŒqƒ ª%¹8¤¾B¨âQªŽÜôü·ç4ØÚÞR×91:™0ð9ßú…½éÞ%‰4ËWK%@!„T'>QMjmF(ݯùo•ÇÏ¥<%\`~£‰ùÜ#ŠÔ¸å’ò_•ˆB!ûó¿ÿ›ý¿ýë ækg ?ÏX­ñWU¸PR,AUà¼>rÿÑ’-ÙÚÞRLzÖXVµžÒ•B!•1ü<‰Ö•wÜöm`!LX~ÙAƒ3Oõ'©T„åK«üõE!„ ³ö;k|îRuðÚ‚ƒý ,¥*ððèŸ=uêK_,ǘŽóÏ.ÐS¨Ç%F!„ªrìá,¤$"‚ ±{ltΰ*28Œ¹ .ª²ºˆUŽ ^Ž68ùÇ'ãç:‡¨Ïógÿà^ÛÛ[yØV œB!„ìY4''”® òB©.ª¥TOåÿ’bð‰/ªÅç‘ûd4ak{kw«ã0ÂU‚§ú¯¾ùBF›*Åk!„BªOuJ× 8ý©É‹ÈYThÌëu\=wþ™|ë°µ½uÛêm1™"U‚—ƒÑ€óÏŸ?rßÜsß=YšA!„²—øìÌÛ‚|©ù|èÂI¢ œÿö¹óß>÷ÊÖ+«+«y™ ˜W$¨ vú—+½÷Ó÷Þûé{5UÁùçÏßûéªjbR.Êèæ¾,]îì½BÙ×T~™Ô"(v Ò´3£ŸÍß¶zÛÉ?>™½¶­í­¼T”û¼ðô#/|G=VGßJ´ÂqD¶r<¶¤íÊRBºc#òÌ×w/bùj_™¹”_M׿šVBÙ;ì'mPàÆ zªÀáÌSg²Èƒ“|ò¶ÕÛòRÛàL?b¢ >®Í‘saaÁ›Óu•\ï°RÎSt[öΩ‰N,¢CJîde3 !„}Mm·lËŸ$ªÀÅ•[Úkÿlmoüã“ ñS•ö„Ÿõ¸°Ds r$…ãå⼨¾ëVqó¢©~÷îUØí„BjIf ø‚)UAQtæ©3Ž—ï®Ytú/N{3¸M1J¤UêÓ¥1p´÷Q½×ƒqÓuÜšX§3£oä*_iJドÞEìá6 ¤‹¼í «=º¢èÃÕ½äf ž&pA´‘H~:tŠÍë+[¤_¦æUÛóÔ„BHEɦ ¼¸~V $Ϊ"A‡ÉëèøÃs:#ò;9}QÁHÞ×J㕉ÁFž âõü"Ú©¬]¿™ÊÃÃÊ ;qùdô{>Q'ç~Š3¯o’2§óÚwÙB!µ!ËP¢:D€(UðèãOòxâ!ËYy¤/Ρ³·±Æ¹ÈaŽÏk‰öÑfñåÂrŠ=VÓ© k‘Κ9 -§¸ÃK~híj¿¤‡èdKwŠSTL×ÏI!„ì_æ4u!ݤä¨XAUU´ý­ÌgŽëfÅz6¹¸>ÁgºîSXýGÚÊA¾Q¼¯V÷'Á©Ç%­%ÇÒbýXMl¥š9 !„EFmŽH4Ó`×S¯³*@Ž«¥~ÞŸôˆ¡Þé¸6‹/½h.¬öj2wÖç“{å{Šõí,®E„BÑ"¿˜ÃžQÈ}ŽA¢gö:$ÄŸKu:-*âIyŠ)9V¤éîË€ðqðyÙVPQ%Ǟ⢯:¥U„B)¸ˆAâý ê¯ ã—¤žMÄá¾™î[ï÷p¤ò«”µG˜ä~Ók’×~_bÒ®óÕžåáÁD¯U¾œH;¶J³í:‰eF·:Ý)N]fDo„åTö¼f3 !„27ö„*@Žs |%øR¢½É°Oƒï#öäb×ÌüHÿpÍÄèòuÄCÒÃcmP¦+;<ì,”“ÖØ,§8c‹]u‰J „BHz”C‰Ò­ƒ´WTª°óq4ú^ý'B!„’ž\Ö;ª‘*d«ÖÎÇdîdTb{Ož•Ö¢½×u„BH-±“…z½×/üÍ…É›÷&ÿ×Q ¯s$vDPe '±”Öÿ<Ñ„B)‡øÄ¼MÈ<#±ÞXö M´hÒ‚j‘{e¢fí‡W’}kºò„BöÊÁ܉Ç'ó#IÐà׿ö80³áe E•ÇR_²½ydð@_ÊnüAg΃ ½Þë>US¡9帆×ôÖ­_˜®4ï['˜íÕýÃÊÔ¶B!µ&ݦºd¤Øh¹VªÀî¨)yF æûÄ7cí¾"}kw×GrߺŸ¦( ƒeR²IìB!„@+zpáùxßJH U Ê•ÇY”ÞkVh¹E ‚kÌ»‰ÁçëÊÄà …Ù} ¼Ç*ËÔ©ª A°"}ÂÌO·¥®F=Ó ”‹×«žžÜº«TjU¢X¦«ú8ä^x¾&*3ß‘0×fÉ«ØÒ*R.ýD!„Ô¿ŸnOÿUþåYg)̇:ªÿîiåï|æ—¹8O°"ß÷à¢Ca‰Ñµh^hÃë´6ߊ2RÙõš!„X|—@¤ÐÔ¡a¿?‹6`8"†Ø•Iudƒ¥!”K—JiÁ–R²%l)¥%mÙ]ZVÛ® ×ÎǾµb"œ9ï“`ŸÏ›'ì)²~íÑV)ëŠM «]³Ì‚&={ß"Ðí®ÁĈéT”ˆ`ÛcOW!„2_¬¶þu´¨¨m³r"wU`š#96-)›-¶\<°Ø4šš¶+k«Ò¶`KKJiC´aK)¥´¤”Öhl^~ùÒsßÚ\ÿ؆_Dªä1új3£M¯c,MsBsÐÝt_G„,ô››M?s77¢'S$Ftr¢Š2’ýB!ÕDÿ¡½Â×.j–Bvöý<‡DªÀ†%MiÃÜ £%„ËËËÐÀúíë°%ž£¤=‰HÛÙ MZ°… [J@JË’@¸N ͆ ¥¼ôã òÝCË·®)L !ŸˆA^=z„CS*EÒð!„² zŸÕ’ ûUQ©‚‘ivËËËÝ¥nÛhã:w©ÐÉLËžÒhLŽŽ+/N–Ƥ"slYÒ”¶”ïŽLÓ Z q)mq駛˷®…ª‚ÀEUöƒXŠž,[\á5¢:ýPK!„êà}¢«ö¸© ªIH¬`0ì?ö§§©x€4ÓÖ"‘CÖØ”Rš£ÑhlšãlÙYFËÑ€„ÐW¨ZÄ€B!„xQû˜õêBsý=õ9¾ª‚)väÛiˆÀ 4'Ûtƒ€”Rʱì äx4Ø1Í‘92GæØí ÌÓ|×™¦¹3²¤4ÇÒÜ1<¥KOü×ãGî;vñ§›M4€Fø¤‚“^•ˆùB!„äL„Ó¯£´âS'ö“f®LÀ²-96Íñhdš¦9í˜ÃÁ`°c†óAï5ÙSLŽö–ä/³9+'vim÷µh !RaLøUQ`Ä€¾>!„BHq@;rÅ$¥™`“R3„©Å¯µAo¿Ó>ö¥Ç.|]îfœ!ÐäÆ4Ñ–®Th1ùW8ç¨ XÓù a¦** ’KÄ€ëÐB!„”@²õDÞ_­|ðê« ¦o…0BOU£ ç1?,@ £Õì,h9vI)§+EÐð¼hÌ(@ïȢأgH1î-h*åªùÎQ¾%kÂöã"÷„B!aø}É€w˜`0P“ž5WmMº#[%ÔM„*,Õƒ-Ñ6„qÀ-4M4 Xì›?>ßÂXì;æŽíŒÌ±”¶„ ØR†yù= DC áÙ-n/ä1ˆöÅcµAØ^ÂÞ”ˆÊÜE˜B!d_-*DµGš3‘ª@ 3x”h‰ÎA£³„Ѹ×{³gš¦ôȇ+€hô—ºÝ¥ng±3CŽ¥´åÈ™;28Ó@éäæˆ(*ý_)sêG Bªš!lÇâØ£’B!„BJCÚ“¿ ÃÿÊ©>Z8Ÿ”-Ñ]2:Ñ¿º½ýóËÃáPª‚ r<2wâz,¿Ïè.‰ÅèlŒÀ~±»ËvÎj£±B8¶YÎÉ!b1”È!ûS|ÍÁH„B!¤|‚Ú Y0Á9¼øCCŒ$¬Øáû–m3jAÑY4Ú‹ ·ûoôÂæ,.-ÞóÉ{–oYп2èõ¶{oôºKËm£=š³S½Óš…MÑ@oûâúÇÏ”¢ ˃X¯½ègÿŒ-B!„T W*è*„ÚŽJŠU|&Ðn c³×{3T Îοãîw·e£åuز÷f_JS´:ÜÓ%‰0]±t0ìÆf»5Ýô \ è} R¨ÍC¢œc@!„R”¼ñ'.ªöx¤„‚pÞ1¥åÓDk:ĨÙhJ˜®=¢aÀì¿ÙSrË™Ì6š t—ºŸÜ¸ô³íáÕ¾D#dWC8ª ) %`ϬJ¦ PèƒD>º3!všòÂßÂGÁtB!„RA2:æ“Y Á¿êP“w³M7Zí¡Ù7MÕUišæòMˇîXT÷δc@ˆf³%DS xF1ͨ‚@§©…A^ûÄ´3ßëîGäq>õfö¦B!„ÊRÈÔàdÛ®9MY­ `Ù€w¼PÍ–í â͵g¶/-±¾¶.ZP…%œ™ÇM!„ðF¢UÊY•ˆB!„Ê“Yد§ˆ†;C2¥/hà,]6¤JL"Bˆ¦MG?X±ªEÏ1 „B!$wb6X@ºÙÌÙF9yã› Hß®[ !DKøÚb´ ¥©»R¡!š !v74±ÓG«Å4(!…ÎØo“¼›IGg«o·”f¼þ.{•e^vf¬·‚Ý»W¯º vujtÚ¢y‡$„ì'¦›¤ R–¥1 B´ÄÑ‡Ž®ÿκq½š¢ ÀhÝ¥îL6!`K4 ÿáM 4BˆfÃÝYag<#±7âì2» ³¯@¨ödð%z×G*íwHó7?xµ ¯3•èR,ˆº\uú«ŸU¼9Ñæn žtÄÆ8š÷d}œ£ª– !)q=àÄ¡ƒØEåT¡þ·ˆ(_4ÄÍï¿yãã¢%4Mu¾Fæ¨m,ú›æÎ:׉¦€€ ±kLœ8©ÐƒrîΚÛ0;Æø2Ý”`fý2Ó6…d"¯ž¯ˆW{)–`'/æXª|Õi>[É·ReÊõ$4ïɄ⧄íbU wHÏ®*60CÃyäß UÀphö¯ö¨ƒÎ ˆ†€˜ÄÔ 7º*Ñ|Ý£ŒµlÜb”‰ËÔ/ÊG<ѺCg"_*"4™—©%_u5:#JÜ‹*¯{2!dßQîVÊaª )tý‰#Ž.þhSJÒ7ÿXxík@Lv3ˆÙiÁKngï[7Ñw¿K $§%O IDATˆÝB‚Ç*ËÔ©ªŸ`EšDñ5ËLú“æíú…ø ðU×)kÑLŒèí,WÑK‰z^YÑ‚çºM×¢0S#•-J4H/ìiž8eFÑ=UÞtz)Ø"oæ°vùò×iQX/!ï«ÎW]0Ñû6,g°L¥åJ²ŸŽˆ’³\9uE„ŒLUnwû—ŠU`;Ë•z´ŠÑØêX³«ŽZvÌ>ʃÁæÿÜ”c(ŸéŒ!„@SÑÊȃ 20¨)·9JoÛë3üÄÞ÷Ý)Þ•åkÖ[QDžX|%$*3EföËì:eÏë'Q‘~sJ8õ.)Zäõœ4Û®ã•jv;’7çëo%ºBÂZ¤s»–ˆù^uÞZtrF˜"gÆ ÌÍ “B¢ñº½"åÃÿTA©+˜}x/¥ì.-›ï7{olOÒãdÉh<ºðÝÍ­í-g³d¡ÚÊ`7P !¤³»YÀ° *@¡«)oè¥=JZQ??I .ÈWHJ:1“¢ºØCÊñ rìùtñ5{'ëP\á¹£Ó!)ZT~ÛçrÕ•öÕÎR»/s Ú ß{/!¤²('üú•ƒ–*>A¡VÁ ˜¢!;W,\ê.uÛFÛhËï[3ò­‹ñÅçŸ^ØýÀ±­‰Æt²=ÛôpU€Òö1ÈÑßÍ¥œÜÉ=à yˆ/Å÷°0{·lû>Í+v¡óø0½äfHgî΄f'G·(hU¾vÆögѤ»êJ6²FW²LýNV^´•½Q+¡* „8L†yÙAL5Ç |^o˜ ŽÚFóÒ—¤- Ãèv»‡þÝ¡n·Û]ê ¡¨bdŽ.þýÅs}nûŸ·peKø§·p4ΞÒ"U*¸AÁuq…çr¬~™éj/óÇ,z`IÑ¿¬Åš*åhv²þ0¡"¨Bw•sÕe¡FW]šœ{d¸CÙǤR“aBw\Ó4˜Ò¼ü³ËÎVÅ݃]ßzD–´¶_Û¾øòÅÍnö^ë9‡(é,¶g hxþ*ž¼~ŠSa7ý2ƒ¹ÊGª˜u¼‚ãb•‰ÊÒôËŒ.¡²G럾DrNYfE\åeFX‡¤èätÝvYjÚ™ŽÔ&I|+Í•ÏýªËh[tˆ)Ñ9Ú¼ŒãõïÉ„2g”ªÎ&³N¹œ¼•¶ì½Ö GÛ¯n_¼õbç`§»Ô5®7¤-‡oûWú½_õ^ãõáÕ¡”»%˜æÈW³p'mxÒ[¼&LuÉ'b°à™@‰¸õIÜÌ:÷qožk!£±õk¶JYWt¢ëý Ö,³è¨B.øzÞû«œ41ì$&­(;åô§~‡dl{Ä¥¨cRЪ0;£ €Þ×0¶4ÍS\!J;ÃîKÊïlŠ¸ê”Æg¹+†õg°ÌD§Cóæ{x¡'ˆBâˆÛû,~­Ò©<°1ŽVnÙ0ŒÝñ?͆o›¦ s¢%`c°34ßÁ݃«Ýƒ®€”–CŽålÓK=›»‰V¶*P š‘OÄ xSVަݟ e¥Áç£ÁÒ"ŠHÑqÄ5!:O¢2«ö{qvòJŒ½ ô­ÊB¾Yƒê_´I/o%ÊlúW{XºÒN}Š Ë÷7ÇôttÕ¥¸Õ\‹|Ð^DbDz–ëv %d—èåeJØu‹dFzNbÈ|ƒY¼+Aª†É݇÷6C³}`ÑôxìæäS³'9T‡XæØ4dzÀîNj®%Bmø¹>«5ÇàZà){¾Ô:ܬù¼-˜¿¾M&{•ZÉžwH27¨ jˆô,(¤Þá̧ Tˆ–qì3Çr ß›L90ÇÒ’ØÒÕ!»ã…ìÉ4cËëÇÛpƒœÙuAJíÖtr‚m°lHiv;˦ú({ŽA,…Þ£ëþÔþº··²Ô¥cõí,¹E•êÀJAÕâfÕ¬(Õ´ŠRqR«hˆµÛ×vg!«v!TÓ”§µL?ð‡#¤=ž4öáÈ 9¶üá‚ÈXVn;ç‚wtipØôÜÉhRôáE´´R½—…B{¾âÔîª+‚¹Øì:ß=ŠBÒÇ>»dØITÿÿÔÝsúà)Á»ü¨ i[°eÓe{ôƒÞjŠ”6º@³¢yvH±òLÆêP𓳠#å›Îè«ñý‘×YÄüò6ÄV=4ŸBÒTxWŸä¨¤r‘‘'+Jd'ªœ™õŽ,8’À’¶£Cš¡ª  U‰”ìçßÎ"L,ÈŒkiׇÑGé÷#dC®?˜šŠ\u)ð™´ª; „Ô’0g‘‚¡tâTAóâ?^ò¦·&ˆ†  4…¦súœôé©tc3K JH!àYÄ0GcSJ9Ìá@´3§6HX¾´#EÏ$NM &×ö ög"”~¿Û]ÊĹÙZ7Øc©q/¿yB!Ä>¦*(+.VÐ9¸xùg=obÿjïÄÃHÛ’ÒIéL>–i,ß´Üb08㎤œŒ²&Ä”¦´¤”ÖÅ¿Ù|g´¼¼lÙ²mm!DïÍþ•·â:1¼jJ«½ØRY¬RÈ%b1P$£§\‰/zumÌú•køø†©(sF,î3)iÛÃÖT>"Mg|X™)zGÚNŽ(9Ç‹!ËáaÆk¶]™¨|ì½"¥ñÊÖ!ÃU—ÎÎtßÍ ñ±dtEaßbåéÖŽðë*ãUG!ó!v¥T›â!OÔªÀî î]ÿ¢×ïÆh Ñí–F:‹\ „F³ËF³!„h–3@èâß¿ È•/o¿Ö$¦A£ÙEâ CePˆ*@.ƒè_ÍŸbF8^Á<ÊÑ)®=aÅ:¯õ‡²Ôö,ÆÇ˜"gÒN+Y'[i(ÝbͶë÷gÆŠ”–vÕÅÚ{x¬aú‰ä—bE®=B™®ßÇmr'‰*Ð>йôÓ-slBJiKX¶eÙf§Ó¼=pWšh€™w‹í Ðÿñ²hÀ‚è½zÍEÃh #ü‡«”³Ž§¢é…û¼dežˆOÊÕÌ™‚t^ZîÆët] •£/!Ê¡´®Ë(/SPôUç«HÓŒ"Nz¡…G×[‘˘Bò‡ª !ózÃTÑ¢Õm·ü“ÃA·+.ÿì’3Ç@JiÙÓFrv•ÒD¢%Ä•_™‹Ý®ÑéDÙÓˆQÈ%b1°Á!…Ó-XEìQú™‘KÛ‹ð0”ãI4»NéêEø{€à#pß§)®ºèŠ”hvr5¯:Í®‹6^9¦.G;c»N¿ªBH-áê¨E¶ÚO#|‘PÏìa7e46¥´Œ–°¼¼<™r,•…&Q·œDC´Ý¥Îb§`±»,ÜŸTE¬J”=ýq>%PrÛ3¢ÙuÑ¡˜T­"ˆ‚RtCôƒŸÎ«·5»N˜PÔå:$„ìüã?j„¦x``! ;ò-üªÀ2Ͷ!6>µa´Dÿjoûg—º7­‰ëšŽ®0ßµ;ýÁÕáðíÁ`hJg›ä„hvoXì.uGcyåWýþ•‹Æ®›Ý¥. cñ7f¢Š@êD»AîOû¼#”…§¨1—aN©Ê«чët] ó²Øé5Ãë5&*<¯ùa…ÃèŸÖ¤é$¦+*u6r"ÊOÔué:AójÙÛñ.BH5©«*ÐÇóôšì²ëô[¢ÑTl‚<« Vnénܵ!&ƒ|dû@çæ÷¯¦h@BÀ–#sÐ{³·½½%š½þÛCÓYc)¥Ù³/íËN™rå@ûð'×ÐjöW¥ô+4Uêµo@³×•ô%F˜ä},Á{x–$Û®4Ii|Š£ËLÔÉa]§Y»²‡uûµÈ1îIÑo{lb´aÙ¯d%åã¼'+K‹ GÄ4/EýÓl_.BQâ8b{_¤PA—tÏH *pþ Ï0ùlpupá»}l &l Ãè:3 H@tZÝÎb÷ÐïlH[ÂÆh<2MsdÌwÌÁp0ö/]ÞB,ßÚí¥iöÑ0 gï‚„ªEïcñi:4G¹DjÈžK–çña#.bS¢‘‘žåðܲìöÄ&†Ç¤eê“ýª ¾Õl¦NΔÙ]ÉÊt¥úBHv¢¦yî ÙÔËßÓ|ª è‘«æ wäpgÐ{ã‚“02M)GÎGBÓ½–…rlb²$‘Ä{Nº´l ¦Ý]Ó\¢i3Õ%R(gU"M²<¡'û“Í^ {Þ£!9!j¬f—ÍIvH}CUàß,B¥ ‚…´[Z†å‰5ˆi6!ÚÞ¥'O7vM¤€a;Ç )åÿÜÎ÷¾´ JTÁ7ª‚ µ£.¦og™-ªKïBêŽ×¡«±HHŠÒm­¾ZPªOº¦*pðª‚ðUPuòÄ,@¤ä_)Sõ#Z•$¡Ði‚œƒX2¾èÿN Ï>©¼hË¿3°Ï É CŸbQõUÁ”Ð- *¬ &Û¨yP ƒtƒØû©N†Ôätîæ‰æª.,,3û¤(3óõ°õ-Éøxµ:ÍŒ&û•ŸWEµ&cë}µ³TTkÂnAYú$bqªÔe¦«1ò]Ò€\°5 >}.D9ýA‚“º»2T¨TÄ œñâš7}Ç_æ`âµYÒ•™ªU'ÑÙäT²O˜û÷½^_´yݨ HÅ©ÇÈ"[õ—”š¨ P€ÎcþÄá‚l:á¥*@¾s j=^ßû ´ Z]™V‚f™aEÅR¯_÷ÔÔ¥™ûj^‡ å\ Ò}ßK ^ó*Ø„”ÉÞ_éÈÅçÑV\'Ô_ LjApŒ›Á©L zÕÁÕÍÃíè×ÕÓ `EIQÚ¯YfÒ§SÞFEwˆ2›¯cƒ‡+Ë &zˉ=›nK•Í KOÚ̈œaµgGYWðS};u*Ò?Gÿ"da!pyg1I¿—®4;˜s!pQ…UÖÌ°Š”™}ß•wEQmmtEaµ‡õ¼N™Ñv.¤½3$­(ìf¥š©,ÁHµ‰¤$cü¡Pö„*@Ž¥·|^®L Ã÷´Þ—!ð >¶öØŠ"òDàþêøÖM×/3Eæ`Vr0§²Leb°®|IÑ̈+¤8¢e/¥³3ºCô{I¿i±Æ„•œÔ¤D½¤yx˜Ùš9•韸"n8‰NqŠ`tEIo:e&µÓWr¾„T¿ß—§–A†JEöŠ*@¡s ôŸk’èØ¤e4ÌÁç &58¯Túõ&•"IË/”X_¤"væN¢f× %jRi§µÐŠR|߉¿6ô˜WÁÂS[…/!5B©j© *NTA [IûäuSÞñÝBbiFÏ#pƒó52÷VdgÕØ'ͬà÷]Ó¤Øo\º+¾RfíI£{û‹@H¡ÕBͤ‚=ÿèA¯÷ú…¿™l]Œ÷&ÿ×Q R;ÇŒWx.Gé—Yth;— Ø#u±3#sof U—ß´Ø»Š~-º–ìw›’EÂ|k`î_BöµQvàõüäÁƒ|bnuçMÙ;‡Ý¾Ó ºMG°"߈U¯1щѵhž{Ãs$ÞlagJ'Oj;5Oaƒ²XdsI#êÍå\çÒ̰’¡×vå o¥…é̈¾ÀR‘Ó;"Åû:¶œ"ž&¤ cw¥+?cÎ\Ê)î‹ o!¤BDLG.X3üúמÛŬ2¢Êc©·½ydð@_ÊnüAg΃ ½Þë>U“OÄÀûSЏÁÇÞßà°lÞüÊc½è×m•²®èĈA®šefùÑ «]¿“ƒ9•eÆ63¶"}²43ÂN}Â.³X;Ýôà§¾^Jd§f‡”Ùv.ï\LÊÒKÁÃåŒxZ‘¥EA²¸›agGù}W&*o•ÁD³©4 ¢¢"º®¸/!û™Œk•phTly¢Z©»# ¦ä1Þ|Ã~hÃ>‚ÊÕ–QlDŠŽ#ž¨ ±Ùô3güÝ +P¿ØÔ ÍŸ×8«#sïÏì„5<âšLW‹Nb¾•¦(<©I±e&͆Î=AÇ€¤tx¾÷´D‰Ê²\ ï úEÀp!ù⊜eƒf ¬!Fžÿ÷­„ÔPªøÈÍÈÚ°HÔ^º+’üiìYUà%QL Àè­ý—uRúË•Vg­ÒúFuõ-¯o³¢ÕÁC”…äRò#¢•m{Яª¦åSÙS¦Oqd™—MŠI„hù û@9„1·M‚ç%ÕY¨»*@¡ƒÜŸ—=¡üŠ2ÂÉ—ŒÍ¬õ騦ñ×fIzxÆÚ³ÀŠJsš½e¹löɽŽT¥?ZØãm’#uTþÝÓ„A.ÞaëB]NË¥¦´®«ËµTkŠ8›%Ÿ8~— IÉþ‰ä¥¤9Ê™‰]™TBJ;  fÅži9y”Ù}t;+kí÷­9‰›ÃEòÀÊæpÑÍ&aMTRI†«ä²ADèöšö¦3îsØl¾·® yýÞ„Y´ÓÛ|7²ìýÈͬ™SÙ@åá‰ì Ã9c‡([äÍìKQžè`6º.:³2Ñ[KÆþ¬àõ ÕþE´¥\KÙí¬Ú9 3&̤àÙ¬à‰S6MÙå)Fø!˜3XQÆË&û¢ßó„øÙgNÿžAGÄ,`‚\\9ûû«–4°}S§weôW÷w:†0ÇríÖÎåW›?ïØ8hù –¦TÈeŽAºß’ñ9šeÞŽ•¿±ÞptNýŠriB¾'(‘a'Îëù½fË×ïy¥8)ˆ9^Ÿ¾®+®í¹Ù ºæƒÌý‰þvä[W wé`uˆ|âk{¢K—M¯²‰U” %ãøÐ:Ý^Ž*€/asB¦dW={±s ½Ü5–—:hfûzOùÓj_?™¤½ºÜY]î,h>þ ¹±85)Ä’°%‹D %rH}ÓTÞpK» kVäºV:Oý³Û¬¨¾R‰z>cVít̽Ì"*ÚoçHóKW©tq"Ãñ‰ú“ª€Ì“Ô›$ØÔ‘$U\@ €„ª ßè®//vŒ¶ÑB»%„BÀõøÃÍYkGïâЇ»ÒÆÆ‡»ÎýíÖàggL ±¦ì’(b}OÜ7Må£`ó­(Eü„Qlj*bÆ~ ¸ai¤PjÑÛ)î´„ìG\o¯H©-%-ZšŽU xHqTÙZ>v×r÷†¶NmÍëüoìvOÿk±Õl^‡Û»°!¥uüS«Çe¶Í-ÿð¡DË•æ5ލ {tÑc?ô+òzWfÖ75˜ÓM‰®(K‡¸ƒ}u2gïß`÷†F¢ßóÑ&9höç‚2[u®ÏXR·=¢´¼®¥\¯×9*¡C"êÍñÄe¼óGI½$­H¿—J»B)„ý·xÑ<±/(Çñ«TAû}kOþûuMUà2Œ~ðò–óÚ‘ £w­Á;–Ñ@³9Il6Fsô.ÖW5U c°žÜø~<¼íõ¾#~f"rz? «(—&äU ÒNe‹‚¯}åxßú’w¨qptAtÏG›”¥±Õ$Øu¹´]I ×RÆB*H¢ÓöEÈņ¢o×aãB½oƒéßb%ÅÝ* ©õøÐY®4ϨBŠŒÝ¯@¥ šÝ•cŸ¼ÙW’3Ÿ¶%mŒÆ@»%ˆD«éÈ€»7î<ôñCWÞ6ÿþ!£w!%ŒV³9Û B@J˜¦®*@¡;zGvÉ¢Ê+ŠÈ ùQºœÞË,vF›(sŠ ¶ÈûotÎh c«Ó7É÷i.£Ø«y}×ö®%ýÃ5k¯Ô9 û^èØV‘—Ȇ°;@ô!º¢¼z©´+„ùáÖ3Ú sÙ8YSôìîÓŸXÝM|R¢?]þçÞV¯o^€EÃp>5!l||ùß @´ÄÙ¯œ}ô/ïp>m_\ß Fç¾}ñÈ}÷ìÎN¶!.õL'–Äiž2V%Ê‚ò‘0!U`?ÄÄêÏQuˆˆÖþ6‘=‹þ2ÕÆ§ ,UbîhªܱìN½‹K¯õÏw«÷cóÐÇ7>´">‚öéø")GcKŽeÿí¡eÝŒ^Ú|ÉK á;zwþÞ=w¬>óõþÉÿxÒIl6qúüVGnOlˆ›ó€B#y‘îáY T vH¾Ä63öÁd®æ”ZQ]ŒßÏ稲¥åhC^Väú!ddTÁ Ðó %àE_XûPÇy1xÇ:óÍÍo ×>²|âáUq½h  Œ…p<ÿ†h C6äåþ@Ú@óúfsvÁ"sl-ߺ|ö+gOŸ}ÖM<û½×‡¯m†F Z•(¤¶”ú„«@p¦\Æ$TýVB!s&Åâý©³ŒùÖKF ‘H˜­I¸ ÿöè£gÍ«í;ÖºKBJ !GDc@8[+Ã’Òhu¤´L†=³›€n§ùâ¹³Ö_žvÃcÿý’¼r1ZXÒy®J¤³TEl†ÔÞ’ÎÃkIf"*×3 [äDÓ€ˆÃK ´ª#*ÊîGž¥ä\Ð<ʼn.EB!¤6xWéñþíi$¬è6úv1ëv&“.ýsðš¸cmE´02¥[r iô0É‘”–)GRޤ”:h?÷ÃË̱5zWQKóú¦eÁzOþõV U€0a 1ˆêƒ„”ó UÓ!sçœy3+ÝR—©m{íItŠkúL=Ñ(…}uö !„ììÈ¿tGÍ[9d $UÀîæ¦”«·tÈ1Ö×:– 9¶Ì‰<ïÂ|ò]ÈwaŽ!¥Õÿç‘%¥¥ªÎY±TÚÖÅŸ÷Í7bF)UòÌ×Ëñ9´×%u½7eb0¢2ƒE‘Xê¨!„Re¬é_”.ø41¨ 4ÓyÖ %,‹KBŽåÈ„e;A4 ®‡¸¢g¾A»Ñ9óÄ…N ½×.­®¬Þ}×Ý/>ÿâè]lýj40àÒk׿÷\è<ãHU€#¾®3Y–èsøÜ<¾b#ÊÔ©*_rjYöÚ£© P©U‰bq«¸CVò-<õaÃÍõËœãX”°u–|yÜfzí¼6KñƦG§™^¼ êÒFB!UCªT 9ýƒïõ\¤¡ 6Þ—6Ë4'Ú:½·gÿ¢'%¤”ÒÂhÇ`Âç¾ËÉòMBZ“×¢Õ9rßú‰?^ï¿!7>Ùíl–´1úÙ1¯=úªù®J¤C˜gVæ,Ì îsë½Æ¸™Ã½.£o0zl™aö$jKŠOƒ2F§ÿ£=cåáI«@f¬"Ú†à§AýSœœ@!û›ˆ¸AP2P;Ž5û—€ *Pmv&u¶´lôÒzRZ£±l·„iZ–œd“cŒL´4EKø m °¥%±²btoj¯~ØhÀŸ¾d-Ãh–¸º–N ¯ˆ÷‘yºgÏù•Çzkѯ=ºe]±‰ËÌèû3¢‡}øú3Úé÷fV¥£tžÖ°Ú£;$Øù –9› IDAThŸþ »êÜO}vf¼ !„ìª@c€Ç •‡ù·‹ž*¹(¥l6п2îXƒ `4–@SÚÒ;„ÁŽƒM4Äôo·(i ÑíŠþ›ró{ýK?6_Ã`ÙìXhHØbKl"8Õ8lµ"ùÌ1úJ0è+û>]™$ªLŒ¨+軯üÕDM³?—”¤D—ÑIkw3{}n}« 1Á:‘–k¸~'ûìÑ¿6äú #GáD!¤n¨ý{9û ÓþP5Gäj±›¥ 6߸$±â¼î}¯ß7`Ž-ój[° H!aîX‹ÝvGZ£¢!-@´Äò" vd¯g^¾ln|r±Ùš\2– 9 )ÞþŸÉ%«4ˆ› ëp?óvN¨UA0CÀ-CÚ@cúAc"š†¶!ŒMÑÂ"šæÐ›¸ôê ÿ¦œÄbêÛïöÀì‚« U*1 „B!‰ÐöïU{*Ô‹ ëtË— áózU²aâ¾ 骺†ðœ ÑMÑ‚h¡y˜À` ‡CNNïÈ!;dÏ„Ä0U€zíc@!„RìÀ_®ø–/ÝG šÖ¥éÑT^ Ö˜ÎþX¬|+ŸÖÒÂY\í–€ ë=Xïadb2£ÀÛp[hºê¢!f ˜§ Àˆ!„BHá”ø [$ÓO” ×užË(£°XÁõ}4–ј>àoˆþ ƒD8j ±ºÔ1nAïM³m..ßÒDý«æÈ”¢%Ú¤”ý«Ò’€´wϯhRÊ1Ѐ0Ì(“éžCUpŽ!„BHn¤x¼Ö©M1Ø‹²`®D¬JÔ¸ÓD„‘”m!Œ!6î0LSnýÊl_1`£³Ø-,v&§HJHk&`Òn‰‘ ØÂ)PÚΈ¤ëû>Õ5YöÎÇ„B!$†Œº+8Þf?à[†h¶óÝt3¦’ÀÁ´e÷@[ˆVÓh¡óÂh5×>Ô=ö©®ñ!9°ÍÁÐê¿i]þñÈ|Å©ÓïA´`ޤ÷-Ѽé¢×$MU€|w>öí«ŸH!„Bæ‚Ôø«ÒÇùT*ƒh™¢%ÐÎÇâòr»%:F³Óíß0ŒV³cÑ@wÑ8þ©Õ'_ÁMr²òPІèlŠ&D BˆfCÂh é jÑ‚” ¥ÞÒxÝ5I_ ¯ˆÁµY’&B!„ WV·¨»­M«®–Nþ.t:¸†*€îEØ¢{PˆÐëw´ÜµlF»-–4Û-!„èBˆ&èüFóÉÏ­ýBgtÀîX¦);‹B!®B@´Ð9ÑÂÈ„ÂhÁ4!@‡>ÕqkL¤ ÀU‰!„B*Dvw6Ë›ØÉŸ¿ëŸ‘ã JU`+2º¥ `°ƒîMâÈCíѰ#Ú¢!Ú-Ñ1vU³J)€›»í³º¾ñPûus Dzs°)Z× Ñ‹!%º7‰öaJGˆîre¹£PvÀ*œc@!„Rô•CNÏÈ%dð/vü‘'g%) z­ HXbi[4Dÿ º7EœýJÃö¥™£±¯ \}¤sö¿¬/} 1hM!й¡yÏ}¶Ñ`Ù0ÐhÉ£u†;#hª‚@ #„B!ûƒ¢GÔ¨PꊪŒ8rÈ#z £ ¬¯ €Î}¥ß{Õê.µï¸Ë8ýøúæ÷ý¡©T.w¯uÏþéúÚ}hÞdyÈ8tW{ùýf»…¦€hàðÃbý–îVÏT¨‚ öÄ$/ŒB!„2Ù¶Pmà%¹^²ôT“(VÎ 4„è_ ¯H+˾׿ð·[±uݽÖ}â ë=sðØW·¶^‰¦%p@n|Çî[î_àê¦Ò†TªÜÇ€B!„”H6NHCP«^U`ý`÷ÒÒ¶e®,^!°ùC³ß—RbÙèÊ·G'ÿâÅêtÚŠŠÞÛ}}øwn–·£ÿñQïÊÀòÒrÇ8ÿ£Þn¦„ªÜù˜B!d_cÏi‡àê 1ø~ew驇õ ¶Ü‘ï.:C,ß"Ì)Dg¹Õ<óåK‹·4ßw¨ÙfõlÈI9–”è¢ó¡®œ¦oþ¼?zc3XÏÎ0UÎ1 „B!eØ¢k.VD«‘4UÁd] …*pXYÛ2ÇCg±QÑ‚iJã€-,þ†qÇGÖ;¶qòÑOÿõÅÁ;»%H i[°-)­ÉpÒ†%aÙ¸øóþÖÏEÛ­ ÂWxÄ`aa!lƒˆÂòûR¸=!„BH% Î)¨’4ˆVaŸ&WNÊÊÚÖ¥7/áÊë· Ñ€¸š“= –»ÝîHžùÖEÓ–+ËÝå÷wÁBα–[¦-{WÍÍË}\ „©‚@ν0Ç€J€B!¤vˆJ©Ä ò}ª©ÂÇ)IÈÕ›°ež4øèÚÇ:Fí&1„öÑA·{°cšæhl]~¹×7G š¢!ŒÆÒ´GæÐ\´#çøTJDÎyE ô]ù¤B!„’Œ0‡xŸÏ=ðÒÐðøáuú-u*p^¬¶Vpëææ›ƒíŸ_Yi¯®ÃM!„€MÍÎb[Jëæ%ŒÆÒÜÁÖ¶ÜþÙhpÝùå0½2iU€¹D œÁ?^wßäÓNz¬6ðŽ&¢Š „BÉJ’ùµ‰Ë©#IöœÖWnÊê\Ø^ÜüÖ÷VºÝNg†!6ÌLS†è÷G¹î3Ë7¬a{ªÓW˜KÄàÚµk^WÞë÷û& 89c}}ŸÆ 6 „B©ûgÉ#Ÿ*ˆÊº¼éª8„ƒ`0‚¼xå ëŒ¶’è­4Ž7À€u£ WÄ èÐGÕŽO3èE@!„’3¹ìˆ' $¤˜y;¡rsb ª‚qGªÀMq6FXÇ<‰ë¾lE¨ä1 wN!„BfpÜÐpy tÿ© ‚‰¾”4ª@OéU}ƒàj¤I3B!„¹a«þrö T‰5 Žª@ÚþV ƒy­UêóòÝÉÇùÖB!„Bª‡"VP ‘åô †PROÃÈPTP üˆÁ‚ëî»Ë-Lñ IrÞFSòΙDŽB!õ¤n#ˆ¦è„tó'„dÓ (UÊ_•Hé¸{•Ú E™„B!¤Š$@^ÑPU€êÏ1 „B!{xþQì U€yí|L!„Bö#jß3z~, «"'öŠ*À~‹p3!„BÈ^A†ÿÍ©‚@¶}1p¦&»”9S™B!¤(ýß_Ì~.w¹ò ×{ýÂß\˜¼yÏ­´~ªyí|\#¼Ú€B!„ì1JcôàŸ(±¶bÙ;ƒXwßý”Ú€B!…"gÇŠÔ Õï=ÂVúo>ÊÐiÁx‚7%_Ùðë_{\ÊÙ&È@Š*¥îÛ›Gô¥ìÆtæ<ØÐë½îS5¥Î1ðî`àîï݈À—ˆÙ‰ÊœH¾U!„BÊ#dë_2!Ç=¿â(0˜P+U`wÔ”²#ÞGõ¾AÿÁ î§ú9“ÚC!„R6 ø(Q)…L9ÈÊ…ç0[‹ÔPªµ{"îIW"ög8"^ˆ"”TTþr¥µX•È7]Üš€B!5$f×_ß{½áþ£lNl˜P\\¥îªUˆ8ó†•k avæ€/§ï#pš!„Bö»ûF( †}¥ bËXA œ)¥F |Ž»wM¡èÌÑ9c?"„BÙ ø71B2xNHÈåʤgnx|ò*ú4Ù^ø¶f‹9J•˜30)Ù†6Þ<î=0¨ °w>&„B©+)f ìCUÑK µCì"’÷MÄ~Ç{'œw–½›×g¡³Þ…[O~õ¸ïSéÏ<LØ\yæÐö1ØŠ&•î.·?üâlÉêN¨ñB!„ƒÊKžYËhÿŒ2ÒhiÐcŽ q#ˆUpꉓ¦i8òÐÑ•[V'Õù4tUÁlæU(9TÍŽ!„B™Þ©‰¦1ÔŒòW/µ*XùÐÊ÷7_ZZZ:ÿ­s_üOÀ£ KÌëŒ)êíå[»+·.wÛhˆÙi³/cUÁnnOJ@Ò¨…Áþ‰p‘SB!„ì_<îòÞѹ’L)©b€4Mó±?}lõC+—þáÒçþðsmàä kíå[—×îX[^êvÛw|líÐÚjç`Ç9_žÁKbªP#„B!û’}¥ òÛÏaV$x†©ËŸtí#ÿñhˆÇò… /L?µ|¹E«¹|ëò¡­u—ºƒáÐKic¸c !îøØÚÚÚzg±33º)?U€=1`@€B!D­ñ—v½Ôý€WS/|ÒCG:Ú{­wñG·«·¬xüÑGvµ ³ØYÿØZw©kî MÓl6vËwäAÛkw¬­­­,.¶ñ^U0C¸@*;b Ü² øÚý7˜Ó—–ÓW”¦U±möf &êØI!„2OÂÆßÇËßã«é½_ g¶ñƒÇî °¥hÏ~óY§žxÜÍ)ŒöbÇèmov†h¨»VŽaͶÑ>tÇO\ÿôâbÇ=G‘±‚PS}”1pv%s‰ö½™½ætÐÜõL¿¢Øcº’ÚI!„REâ‚ û™ÝpAœ*pxê¿> ·­~àÆß¾q´cúøÆ³ß|VJyêÏïìl¼g}e¹³ØùìÿýÙG>wlk{[Q¥ëèK˜;fÛhúøkkkÆÓ!½*@¥æø|eý Ë2îzÌSÐ^iÜ‚B!U$íöûyX‘„tþ|‰JU@ÚxâÔÓOœzZJyÛúÍ£Á¡o<}öi)å#ôÙÁwG=ôÑÛþím®¼yå‹'yò¿œí ”EM ”0wÌÎbg㮵µµÎc7Â\óT©åê¾*‘r$’—¼œïØŠ!„BHÍ(2èáWÞ<+“>qê)9–·­ß62‡?uä©3Oɱ<÷çç|Ǿü?7üý/ýøÒÄl0ËÁŽÙ9ØÞøø¡õ¯t,zìAı{aU¢k³ÄæOçÖûÆEë r`@€B!ûÕà"éù«Á†KiªÑhvvò?‘cyÛ¿½m0öèãX^N© \y0¸Ú_îv}|½s ãÝ#9L äˆA­QÆ „Bñ!r¨“?:“‚y’K… ·ž–€@sãàÆVÏúâ}Q™Ý4ÍÚÜý{wþàÂKÊœ:ªÀEˆö`gÔ]Ƽ­R6ÖxŽAù(ý~ŠB!„½O˜œðyÓî†eÀáWèìvDûÎîŒ(ÛÜ1ïþÝ;_ú»—Ž=|LJy÷a…6H¤ `CJëÜ_uã®ÃV¯ƒÖ&âTj·*!„B©4Šwã@»Õîv;Çþý±ØC‡ÃáwŽvFÇÿðøñ‡ß}xFH$U滣3ÿíÌæ÷7—nX4wFÐP¨Ý>E£³¼i–Í ”Çr«B!„ìD|–=ŠÇÛ¶ ~Xì,n¿Ú»råŠNëÃ;7îå‰/œ8úÐÑ{ŽÜ=-Í­BOŒgž:uù_vDÚ`Ç ³Ó#Ép·8HçÍsÜ!„²/(`ÿ,RifUóB4šÅöÉÿtR¿˜áÕá¿»>ËÇþä±»ßý{w&UÃAÿ±/=¶ýÏÛŽ>tÔI9ö¬›yYîñ9Åí;FŸB!Qìç5û *° }À™#96ÕG…0¼:¼{ãÐ6/ž>õ¤hà…ŃK€‡Ï~ó£Ý3£÷«Þ™§ž‡“” 1‚ȥ숻O0<ù2ørzS4sz3Ä>Ú;V™qx¬aÇ"Ûð$B!„Tª‚ýCˆ*€ ãzcûÕ^Š"¯\¹rïụ”OþÙ“Gî?²vûÚ¥¸´uië'ÿðÊ#Ç?fÆvoëÔíªàÜ7Ήë !üv-w(uŽ;'v(Ž7gt戜¾½ôMR–©tâõíTântàÛEB!¤–4 ¾NþžfFD«yùòËIË-qôáÏõÞèÝóé{¤”§O~îü‹Î °ÝƒõßYßÞÞòcãòå‹§žxÜ4Ó „h*ª©ÔªDåøÁ‰j‰Ý+-èÄÓ›'„B "±¿BPh6pé§—•³üþå'þìéߺçé³µýÏÛ§¿v³ûB<ñŸŸ8ÿ­sŸø½;{½I,BJkóG›g¾|FŽ•ý-›"0!Ü8?Õc ÿô½ˆA8ó­B!õFsæñÞqdï6jÿ,O$UªÞÕ„thˆÃŸ:rø¾Ã†ÑðÈñÏ®|xåäçOøru;/ýÝKƒÑÝwžøâcÝ–.|ïÂùoŸK0Ù=D Ê;ë?ŒÈ™zò±æQ¾ò)!„’Í=³êÅ´QJÇsï©…0UÒZ¿}}óû›±…,\:þðñ•¬¢±ÛCÏþõ‹a{Hw´ð?~p÷ïÝÝ9ØÙþùvdÙÂ’þùÇJU€9îc ô¡Ãkýµÿ½éš“SÔ®O¢c©+!„ýN#\ØáuÁ†LòW›f†Ìë•R®­­épüó'××ÖwU.6¦t;/^x±ÿf?*SäxºˆT(yŽ3=×Á;L?:ÑM×Ïé~™‰ÊŒ8Üuë•e"| "7?g,B!ûšt‚Z‡öá«ý GråÖ2žùÚéþÛSº_Á™¯<qˆ:»?ø?0 #,Ï‘û˜ï˜¦”®²ŠP(?bà.à–èõ΃™õsº%2)¶LeÁ̱e*{ ÖTB!„Ô‚ý6õ¶ê:èÈ£F;ƒf«-ZñM¹råÊcžì½ºíª‚ïo¾tîëçnþàÍg¾|&˜ß½´:KÝ¿ób˜6Øø¿÷¯ö=GÍ^’šË•rçcB!„ìÈ?5)†ÍìÝpÁLwEŒ°ª³'NŽå`08}ê´Î¡Ãáðñ/ÜþÙî*Fßß|éÉS§Ï|ùÌÈÍ;[c÷¦å¿óbP~,¿Y4Åàê@+Ð_®´œ™Ç|FN!„½òYqšgáJ©P _yÿà9G®Þ¿Ò_¾ueiiI§9–§þüÔË?Út‹ZêvœûÆ9ש÷©‡îMË/|ç>mðÄÿóDïÕž9VIÑåɈ!„BHÅxüê CÄtä*OÕMNü4å¹TÎsú±ìÿªÿôWŸÑ,FJyæ+g.|÷9iOf ó¥3_>óÌ×ÎúüÙVßüþå¾ó‚˜nYpâ '¤%{oöõUª³þÔÛ|'éúÊ7ˆÁùÄ„BÈ~F¨z­p×ukhEæ…*V`såØ0îyê›O|ñ×,íÜ7ÎI)ßwÄÙ´øÙç^xð{GæèäŸ<¬Ñåæ÷¯¾ðîýô½Ý›º+÷wÏ¿zjtûd Òîõ)¢ª»Aiø¢+O!„\PïC;û6Þã·Sµo[é¿<”ªÀ€CÛÇ&§ïU¬|dåé¿|ú‘?zD³Ôóß>oŽÌ#׉‹QñÕ¯}µÙjÿü‰çþæ[VŸýëgüýÏÿçMqýJgš>ú?/úLUR•ˆAAÌ×Ñ§Æ „BH4^?Ow?©»tçîpëQÉäSžRJ\þÙöÊÊʳß|öÁcjôÚüÛÍÑxÔ½¡{þùóÎ!gž:ˆãx<â¨Õ¯?{þ…Ü»üþåîû–à½Y«\æ¾*QpÕÿ°Õý³ätÓ‘j×°ˆr‚&}ÖFçô¦¤0•B!{ž`ä!l±£<—I­ÂÀýXfÕKµTû r,·¶ ˆ—6_ZºiI³ØËÿxùü·Ï{Ë<óÔ©ç¾3caõC«Ïžaûµí~¿?QAlHX¾´RW%ržß»8~°w½÷{Æœ¾m²ã­Ë« "j>Ü—Â!„²ŸÉŹy®©EÄ`v¾õ¼&"[qª`òFÊí×¶·z½gþöÞ>¶ëZô]º`†ÊÃðAȹ04e7åæ ¢ë ¢ë¢¦â¢¦ê‘ì剔8”rQ‹rP‹JÐHJÐX´qkIÅ‹-°-é Žè¢®©¢©©¢nÄ qÄ 1<Æ‹Q7ÂáàD(7~Œ4Íg†ÃO­(ÜÜkï’kíµöÞg&Æ~=fx„^˜º˜ß6ø`öƒÄÇ‹òoËYP–“…/Urꪹz„õü²ïjõ~AAô¢ÛBØ:VAe lÈ$fsÀÜKÅ>ŒSõôßß‹Œ©œ[¬Â@~Û qWÓKÇ^šýÏi"CÁ*€²œ|,º‘E)@¨œJ"™î[@A)ƒ~õ=LµìgŠV¤ãùµÄ*XÏ™aÙ¥±…8e¡/LÏ\™½Òy¼SËÉ<¾g}ýÑkQõlm‡Ú¤r*YP–]‰8ý[}z^ô®ºÆ¯½õJJÌ#t¡ Y‚ ‚ Hè ²W² rhèDúÞìFúš¹—Ya3+ ëgIÚîp²]i¹ìW„]I÷ö÷’U«p,2nÔN¤3¬ëºçG]c¿óô+ÉåÜîI¥b@‰w%jÞJЏvíh ‚ rJ¬ŠŠÎ¿UÆC½*òZ‚tV÷Ÿdã[rØ”…Š}&± DÊý×à¶ýÌÙ3gΞ&·üpÝ*Æ,Ov%BAA6cL‰Í_Jj[ä-SŦÆf­WØ÷â.J–Z9þ¿6«dÞ%„0÷aqÁ»‚έŸmìûñºZžÛ|ÙµYP±q5†â”,’Ge'V~#WQÑ>K&æÔغJC‚ ‚L±¬c°%ªYØkAÁ* ôù ˆä]ÁuÐ`l$I¬ADSÐcPRD¶ÔH.¡æ‹HM—sʶ.Í,[‚ ‚ &Q:«@©LÞE¢ µ`'€D .Ìrû @âÛ3ò¹ÅmH~wVMn ¶9 IDATI:ù^L¹NÕª¸Vsâ+_¡¨¹X\‹ÃßœÔ@µyë7AA-…iú}e®eXc žÈk¢²™¥9µÔiJ¢ºq¢EWÎ[§)r–2AAEò4«¤ÑŠ VŠ»€Pˆp‚ §êjAX§¬÷@dZô0˜Ê¿ßUÏPsÈ<ÎðÏK}Ž‚ ‚ ¢~bÈ­=²ÜƒpÈæH6YX{-9­Í—£Â­µsò1‚ ‚ Hu â0gê]n1®0˜Ç¤ þ"¡OãÏ•<šHÛèU¢Iϵ%<%;¬OFA$Æ´XU["Ë=ˆê#Y#·R£Ñ*Ø”-§ð(¥¶ ´ô]v}óæÄJ÷o·•š ß)H”‚ú‚ ‚¬a`†›ÏŸhœ¥W|…-m’^E¥¶Jž” 4«4š(Ã9%¦dqæ=?AA@QiË®¿E”C>jñ`­d7?Q3̲[ ©×%u˜j¨TºÇ@VÃ6E×GÝAA2" ÷[B6+k¤lƒ ؉µö#*?f»/Jê1=â—ÿÏ%Š2€Dƒ×uš˜R6aÍJ;ôKERÙË_Ú5¥œ‚ ‚l=€V& zÒ¼ÂØºù¥9hÙë¶AMá1jÕÒó‰E™M9´Xx¸˜ÔV‘I)§Rýs"‚ R{dä¶2‚DSã*.›yPVˆ¢-È þ›‰¿8K*bW"½zs ôlÙÃÈ´Ÿ=\,±AÙ:(k±dýQj”öÿ)÷.@& Ú—¬Ü£Xb”Šð1Q«6}ªž· ÔãˆAAL ß®óå+Bj‹Šð襌Çk¡të‰+€’z 8}š#¯2Íe>á+£GJK™¥RIEUÊ©ÞM4A1É4³1×A™ý •@i¦ê«Á*€Ò{ „Z²ºŠ_Èê^]ê¸ì:c•t- ¡1€ ‚ H‰0/†Çø! Z¶×T)«§ ùO73ƒîn4,›_VU¹ÆÀ0º\‚ ‚ •ŽÙ+’‹²h!¯Þ_=ª³*cÙ€.*nW"S(Ù^¢h] ‚ RQHz%SA]õ7m½o@EP¬ I+˜­å1@A©4èÓ¦,J6NEjüˆ•î1ÝpªAAÄ@˜ŠfMÝ/¡J»i©AY€,X²kOÖ ð$T a TÊzÍX d‚i÷p¶P[Õ¹R¡ê q¶R¶¬í­«K%Û–z¢t&UoþœKÇS”"«·Is‚ž«ÆW"[\z9òŽ’‘t!d¥†ÔÇÓ,‘d?² ém])ŠI¥Nr©‘/õ[ÑÜÉÙ‘åQoQv¶ øZC¤üÈú À*Þ’Hœ­LfCNqb¾œË4F•öèâr5m62[c™³Æ@ö'PZ-¯XÈ6*Ò¤EêcÞjUR´(⺺7›öÌ…ÿޫש2ºZ/är¨7¤]$©­%B—•¥4nZ®‘JCê7¹JÚUFLvˆ ¹ \ͼWAûÈCa–s^áMÔ¶E×þ=£$’.ÙÐ]€ ÕƒD鯨ÐyYײ¦ Wâêd±‹²ÂØü*Ë…ü†¹•µÆÀÜ9<)øóYí»C”<®CE†4Tì&ò š•7<ò*¥øj ’5_ëÒ&Tú"µÐJs×áׂT.²î¹ì¦Ø}ñ»e$°[ʣˡ†5:­ùõ9ñ£4+Šâ1%Ú•H;Eý…«±ŸÏëŽFt¹h´¼e® ¦—*„2ZA¦È Ëa:z½%†sÈÖü@êd“Ò/7oȧkV”‡¡V·yªUéÏ‹Úáz•å1@A©Q²Ù‚ÂrJiXÄÍUn(QaÔ¬U à°¥ˆVNWœÇAA¤&Ég¨Må–ú0„Íú"U+ž MQÕgˆî«B6e“ ùëÉAAjRô)ö’®FÙ‘³–ü Õg ¨’“·0µx« À™Ë3êb‚ ‚ ˆ^„3µ:ôéMÛ‰–{²ª¡bw1ª¡=…Í…½˜ˆÂs)µâBA©$ò: t«Î*ÛeU褩@« 69r…?h ‚ ‚˜ŒT3–jl²:œ•ºâÜZºVvS¡ÊÜZ6§’„ ÞGs ÑVßÜöyÚAAƒVA‰w+R…ªH«`B»2gÈó®yÈQ_ªnsÆÃ”pAAjƒâÌO—Û*‰Îªa r%X—C$E,;‡Iáå§Šì/ªLC AA¤àÔbv‚J6 @~?ÓMóß%Œ2’¨Õg”^€ÑÓaËQÀƒ†‚ ‚ HM Ú ¦Ä[šJR*Á*Ø r¬‚õçJZ~Ç ©JDËuAŠâˆgg¹E@¶:âŸê-‚†‚T+D?(°†g}Ï^ ‚ ‚ &bʯó³¾g ”BÃAªc{ŽÎç; ¯AA1å×™¯D/ÿÃp“‚ ‚ ‚Ô h ‚ ‚ bj(Q]]Ò1*o)å¥à‚ ‚ R<*wZ‚ ‚ R2Ì4 ´«òz‚hAýc…;œ"RÃp_€øE‡Ô*Jw¸¹w¾i†'P/áE)+\z^Û@ØC´"Audkd3¨ÿ¾Èþ¾ªdÓþ–ô‡R{»e6 " > UăÌÑŽ{3Í0 *ÔûE_7\μ=Ùh ‚ Jˆ´Ûˆ~•ÔÑXP%[Þi<éob¹áÎ"RðÊ0ÿyWÒ´ó£|t)ÖH¿°tY‚hGéÛ?SH #Õ°¹_Pᯟ§\j´Ë%s^7…¬m£ô\¥¸ú[Š Hm#´ „‰&6Q¹‹A¤Ú©º@‘~¯¤ôR§è-YׇÔߢb ÈÖADc¢¯€£<†–øiGAJƒÆZ]sØÂ²j1DrªLÿ+u_é-¥âÇD%þ èD¡ Må/…a úÄj\|Œ ‚ ¦ Ô&e#s4N?«d“ÕMEê¬.6¯Ìºf ·<äóp˜cHgD^?©q¯þ©VùúCAhÑûµDóú7<¦RªÄÓäy)B@cq¥õÙ¢"J†‚l5D¦²‡¼üSjy°Q"ÈÙ7ºê4EHA¤&‘NäˆîÔ­S©Lùñ2Kæ:êÙ`s\4tvÍXquG„aa¤z‘:ДŒêBÀÅÇRSào$²5Ež€jTºÊ”¿a§JÓÒô¼è’Ù\„#)Ô?”{d!R“L¶¸ôª)U+;²m!Hm#ûáR/B(Íõ£a€ µþ@"[¥û_=ú_Ö6ÐRIÞå³y?*ôʬ½Q-E4Ž€ì[zGÃX_ôJˆ 5€±¯"ø¯sB‰Á¯3AA¤¼Tœa eŠÅt5ºÀ Q­GAA* 펞Š3 ò‚!Ô‚ ‚ b:ÕgTèI@AAª“Ï1¹Ý”@°Á‚ìê»:€!/Rë $‡/ªÈ©½¸0ÅðÞÕ¢…Îç;+¤AAL¤,¿Î&J³4Q”YšS´…™RÆD’Í)«ôËÊ©«8h;Ç A áYß³R ‚ ‚ &R®_çbmWª®I«”ªðSz´ ¢‚7‚ ‚ R «ÓE<Ç ¯LêjM…XRÉ0Ÿ/—[AA*ˆØÂ‚á²Å2 TÎ,ÔH ̆b(‚ ‚ R-TÖ®D†Ï4½!õµÈÉ/>6("‚ ‚ ‚”üƒéËÓ³—g¹çW.]‘f- àæÈµ¯íÿÃoӑt ]"I3ˆ*”îJ¤«8àâcAA¤È€¦8¡<Î*ðöséËÓ²ÙMäukõâ°Y5×R§êÅ¥ÂH+,°¸J¤\ìx|gÍ·ˆƒ\Ç ¼UÊ+R‚ •saî§õ•É)<ä±8«Ú·ëk»THý¨Ž#ˆˆï¼ûOkX†šï ‚ ‚ðd É®Ĺ͞?w.M‹9« ípÌ\žÑQ}ñ)†PzÓÄDDwÿñi1Vét¦z+ü»hæÓÖ~äæŸnX-”0=»JZÚ6si¦4¹¬ä|¢º e1„׈ª§š¿Ó>rhù© dgÜËb¼©ß9‚ Yº•€‡ i—ÛJQ$G¸Ä,!ÉÏ’Ðô”[¦Œ«´ïJÄY‚T¥Q8J¦Ö8·;=ßvÏ^žíxn“ëròât“»ÉVO)Døk”aÙ‰ßNt½Ô3ÿ¾ÌR±š¤[A¤y(Šbî3ÎíΦ§ÜYB€¹Ÿ¢(Š"“_§Uy׈Vè.¨ =¿ÆœºÒ #ªÐÜúUj+ÆîFuLoB¶!õÖeåјSZ§,ºD’•§ê:mú÷=Oîîy¥/+û…bŒô¾6Ðøäî&Ïž‰s“"øÿzã§_z©;rnBÔÐÔù‰îc°¹ƒÒ~y¼û˜; ÷îÌÜÚV ÌÆãݧ¿{Šð2Ä>\ôúZw4îô<³oêò,Èõ:›#½ýM»›v‡ú²ë?;ß9ñÛIÏ3{v<¾³­ýHôj”¯?•N7yödW ^)Mw¿Ü¼“T@)gùvÒãÙ3q~š“vêâ´Ç»oGãN¯¯uéVbfnÖûƒ};w¶þè'ËëcžºŸ¼ÐÓøäî;;:»2,+í¬RÒÁ,ý6W )êÆ›ä2ô¾6`à—AÚÀµË9°osp/­Îm+E¹v¹Li"ÿv¥\ÑÌåS‚ˆøõ»ZÔ, °)6Ús›ØP`s'Qëuuu*9…OdsŠV‡KŸ »©Q$ÐyÓV ‘³‘Ä'Éù÷g>úëMŠ¢†Þ5«æð;£6uóO7n¼?[Œ‹Þå£nôÎà6>árnwF¯m(Ê3Wg]»ÜÎíNa6Ù~y÷zã· •N¼>Ä)^ñ[‹Þ¯¡.æ¡7ØÛ{¼÷îß?¹4•ø8r½Žd¾L݌ݸùûL*5úN„/žH$çߟ¿ûOƒ/vœÞH= <°udX6rz½îhV@E0ˆ-,éì ÿ28ºæº‰}Ÿ™žút飶ƒmG] ±©÷¦>]úÈwÀ7p¢ËÓñB ð|ÇG½ùé_?r9§†¤UjB:˜…`¬×¦‹!BˇqéVüÆïçoþéF†M…ß1íÓŠ HuaµP»\¢¨Z+E9·;E‰†)Û9¥Q³ªË´¨.i· Udp“Ó*óSgçúv»•¢ú_ F¯Ge³io…o(:7:¶Ñ´­Ÿì7Þ Ý/vG.ˆÈ¹‰î—ºEydûåýžgq1³W£EÍ^ÀâbÂû]^D]–^Š¢2éTj%í°ÛG†e뙽::ÑÏRtncºÿd¿¦À³·ÙZoåœÌ=&þa¬ó¨îM x9wÿûžÉó“#§ÕPlêütoèÂä¸w Ÿ8òF˜íÎçÛ !ƒ§6^&>^óNÄ¢óžæf+EYë©`_0þç s‘ï¬RZS;zm–*wŽ–ãÚgЦC'ú£WÍwY Rá0w˜åÛÉ%剉¥K·“¼{Ü0Å:ùXu›ÏЕS"*.Jáæ˜…sâ:¨ž<·!Ù:óöHVZ¥âÒ†TäÔ"€9K‰v‘*Pøò’w>>NïûÁ³Åh%½Âò›$ˆ¦ó Äó´›²@|qÑÓÜÿpÑAÛš$žSÙ~577‡^ÀÌÜÌȯ‘³‡ýK/ ¿¥[Ó]B*J?36úndôt„ª§Â!oK H`WX~pœÛé–ËѰ¡(_ìøúFß=8ÖÍy œY%Ó¿˜z*‚E~;Ñ~Øß¸yÌyµž“Mô’céãÄÐ[£ÉÛIi¬°³²MhLíèµYb¨Ü9Z>ŒÂÏT:-A­C6G”œ˜ ×—ß0éâꪹ4§0°D”_:¿+ÌÆÛ ¢%9•R¯3oµRi•ŠkU—Šl@NÑbç(ñ@îP¹Â*D¤êÂn·ÏÌN9Ìß ÆÞ@3÷ÓœÃÜ+têBD÷‹Ý‘sžææÈ¹‰À‹bw(ôËJQÎmŽèµ¨•²z[ZFOGbלÛôl-4îrMüf b ‹½ý½Kñ›Ò<ôæQ¢7ëÇ<Þý-áwFÂãK[{k¸©lõT÷‹Ý£gϨ  "ØÌôT[{‡­Þ8Ö©«éž—zBý-{½Öz*»Jv6íVÊ)mBË`jÇ@¯‹!†-Æ ñî§í w ‚ 5Œó1'ä ŠVAÓSnÈ™ ×—-”¨,CÛ+™izC¥Ô}…Kx¥±û*ùUêäãþó†÷È6¤W¤£ã¹ŽÐ‰Pê~–ï0=¯ô™U³ï?|*œa٠ˆß’f ê)÷¥%•NÍÌEY6åÝÛ,Í Ô/O‹7<8ä?äÿ!h0äÙ[”Ðójs‡~¨¨×þƒ¾ð©7J¡SCþƒ~¥Úz_îž<7|¹»À¯ûì*‰œ‹¸Û®.€Š`»}æÒÌÔå™ÈÙIiý*B(‹ÕJQ©ûé¾*9¥MȦa ôºbˆÐòaÜøL û)Þ-‚Ô2°Z(æ#Þ¢ Ìý´)VTˆa }ã—jÙ"¦ŒrÖI(±²ðÚ¶F[»vnxY°^‘jŒî;›Üž¶öŽ;{^éñ0¡!3<Þm£­{žÙ·ï­ž§e‚ø»u¶þè'†Ouí~±»ïõu“q€r¿Zö6§WXÿAøúÒi¶Eή0_KKफ़;ÃÃ#c£#k‚mîuðxÐöˆcÏ3ûö<³ÏápËw¬Û·ÛÛÔ7ÖxöÄo%ÆÞS@]0G=3=5379+^ž«ÂȯFBo†w4îlkïp?-·Í¶r²ƒic½6] Z>ŒMO7íûAëžgöÙh›êÝ‚ H-³ôq"›#¢…Ë÷˜ìjfé¶Á}D!žkÁ)†}gdôô¸réJÛá¶¼{M_žž½<ËeÖØ¶lŒz‹Æø¥·TŠ Ct¸A)*á7Zz”·r-ušöSŒ:ó6$¥Q$-W3oNsE*#œ$ÌçËå).zÚú|}å)x‚ Üâc×c.k=Å=ozÊÍ‘äíMœÅº~Þã±<_œUÀÌE‚Ç{9C lk ´¨òj0¦·(R œ¨•Tû˜+I«Ýp*™¯C—H*+L*„Òœöª4ß_<õEÅÃPQ:“¹ã?uy–¹Ï³ ªeÄŠG…œ|¬îÛ"×ASØt¶±…¢ V %æq>dÅ)µa žÅçq…O¤#B…LºUZ\Ižr[)¡eÍ«ŠœJh)®KN-è’ÖGR:ƒ®1Q©B¡¢>Š."h»´4¤+§Ò°kìf‰©±3ËØ¢1L”sÇã;ívûØ™±²KR¥TÈTˆ‚ÔEY-:y93@&­¤†’þ¤4µ¬½é[Òœ*´D+©½,PSTÞtTW…²3ëZeGIËÍ >žo-eUDÊkV”U€Ô¨P"x' "¥ñ±ü‚nS @Ö[P Û•–½³æE òULSL¸Zb‹tA>ï—m IDATAjDÑP`«Pº]Ù@ª—ØÂB¹E@A¤ŠP3Ð0Ø„ö-’´TÅ?7kñ±¹"ÕN…ìE‹ ‚ H•Ç…PRÃ@I1QÍ5°¥©ö zcÊ5.çÕXDº®Ú²ûêHÛÍ»ÀZ¶ªBиRÙØÞA¦©Àå•&‚ ‚ •€¼®˜ËXTžÅÇ¢]äK)ƒÕ>Ó×›–]·{ w:˜lby©@‘*<ÇAA!‚0c% íÔöŠ8ùØDÊ®gW88>†Á¡CA¤¶©”5Òy „Ô £M”ŠËn¤`#Ûº¹Nƒb¬P:÷W{4Ž®¶¸'.œÒµÐ[$]éP ÙDáI qyi¬Ac”êTAADm^!aHYéYÚã|¤ùù—J³Š<Ú[7FÉ‚"DãrádÃÉŒç_J¯²ÒK½ÁlÒ¡+ƽ¤qUv/ü!óÊÏeÓÞ#QY¾-õMxøl* ‰ÂÀdsʶ®„öQï¦ò ¯ †MD>éÙû‘ay´Ðw¶uøØŒ•2>o]l–ï³ÑE&y¤¿Ìds`{Øêh |ß¶·¸V“¤Î®’ÑŸîñŒÇ^ïòþRòhÜiÇ.w­ÄÛwòÏïÞ ê8ìgÒ©ÐàP!¶ÁÝ»ŸR`]{ÁÿDX(žµ]²¹ssr|b6v}Á¬‰LAd)ñQ6Jþ„b[À/}˜u3”gñ±H“}ëcMˆŠóJ•lR L6§éî‚»©R-HÆYvL4&ª4!ʦ½GÂlê×=¯œ²5«‹$ÛººœJùõWÊ&ûRIx•eYf#É¢áÔà œè9Ûš]-zCȹ˜ømÂawvj>Ñ1v²#xÌ×ÒÒÿŒŒ.ßKsªmìãtÇ›]çÙUùÙ¾îé›äÏÑàûIÿ³L3YHÝNÞ#ÏÁvÏÁv–¢{O„‚¯¾ä?ìï>pls†‡ ¨u³U`¡( EY€²X,”à`ÊÅ…0Y$• ‚ ÕC…z tñ@óŽòZêQ©A¯U`ŠTÒÚD/Ë+ ³ÌHðÀÈÐ\W±Û ÏuL ,u {†ÎXë+Éoƒ®á÷®íƒ/{ŸgâŸ6ÁÐõਧ<{›\»œ}çbÁ» òÁ½L&“%D¯ëƒ³ “7g‡Ü/÷/÷¹Šþ·übxáÍ>æÙv¸(Ðo½Ï$sÔ¸Ã'C®'\YÍô÷#g#½¯ ôøŽ_ë°€²P©tjaq1»šç³X(GƒÃív;„ŠäXrò¾Ató50÷pnwÂC弃Äñ\›öüSÍO˜š'óe&þ·xúËt†ÍØêmv‡½é©&‡ÃQ¼kÁ0€R훩«³D*^…Èai%eFƒÇ­–"~•ð„MEÿêôìõ©Ñ1 ‘%žž}é>0+ ^TÂsó¿º;ý»HEÙË÷Ø¥;l÷Q_ü“Tâ3&µÂ²l†²XvÚnw4¹œ©L6ùë´ÓÏùHlõV «$KiÝçg“Uðbì¥.Û±îÅWºšßO ¸&†œÇ‚Qï>ïûó‹oö5÷ .b$iW,g?3ÆI+$Ãf‚ǃ‘s½¯ þrÐÈrðµ^SÙÕŒíÃ,CNü‹±ôqÒû=oçÑöÉóv»Óaw°P ±VúÌmQö¬Ì-KmÙWÕ×+Ãf8{€¬ø*ÄiÀ[ÌŽžOÆn±Y.…~­Éý„Ýó­ê‹'ì}­wä­‘rK±ÆÒ­8»JÚŸ D./%î±pm£»ú“·ñãE² Š»Æ ¢vš¯ =¿Æœ…‰VNJ)|%ŒgU_,½ÄïOÇÒÝFÀlŽÉ€ž…ÒGc÷§µ×»eî¥;†÷Hÿ‡MM^õ?0}môÂÀÒÀÅ#¶üë )Mþ!F“¤Çžjÿ6øwe·S)æ³øÄÅÈgZ!Ì—„ýŠds„dµ71úÓ=ɉÓCîûc¯q¼„; ýb0öj—ûø`b¸×ù|0öÓ¶ÀòrügÎ烉7{›ûÙÿœ`t4²ÁÌÜlÜâœúÍ„ÃîH±â8ÎoÐý|‡k—»ïõ¬±µ%–Í–€Å °ùaYk¨¹Ù›H,Šó#U–R±d2GÚ—€¦éŒä“^^¦®g;^‹6?AîF½Ù[­ÜãÂÞ‘ÉØ>ÿP&cè« €L&“ø$éý®·ëð5;=n§û›v†%½g]O¸™/˜T*UŒ¦·Ö·8?g eþànT3±û“ñ•™À÷Ã`!l.`±ý@63Ã.N^õnk×X¹³¾)ÆLÝýçäïF¥ÿ;#s½á‰kC~qóÈ›{ÛhÚ¬® yŸ]f2{m.;жR@QV€lŽxs°øIzöw1ÿ½„3 rºÒ¼ã‰s£î—ûOöØŽÉídû@ÿôÙˆãÅ`ì•®¦S#±ö¶àòÝèõhG<>ÑØèûýĩޖSc£?Úíù½¾­¢&ÎO'>INMŽsz¹)6|¹;r6ÒwbhøT¿®õ€ €EfòÏawÄÿ‡8·9S+ €EªLr˜²%ôrr¹Õ×Ê0ŒèyÅ"íf¹ÄŠÁË`úû¦ ôÉrÏ«=‹^¤i:<t4VRÕsÿÉd2kŸëdV3®F.ÝFÛ–ï,¯½eŠ¢l6™¿’»•í9í>l <çq<²‘Þºßæùv;EÕj²Ç ûU6ú‡h2™$«,àÜîlnnæÇ§ÆHÜNøø",»¿i÷>å€0+„Igm•µPLv´x—>^ju´šÞtíº¾/ò®3FŠxɈދ,­Fß°©ÜÚ¤C¸mpˆ$þ›²Qε·´­ ]n›º;:ר½Ü8ë ìßô?r­7°?K2÷RtƒƒKåÌ]ÆAìõ®àû-žìqŸ‰¿Úåx¹úl¤ýÅîé³ÇËAÞ*ðí÷6îð¾?Ÿ|»×õÚÈâé!ï/Çuõeät$ÉÜ›úÍ8EQ©•­<ªk~ƒcÝÌýPßIͶEæ9H­dG/&wRà~Ì<êv=F‘UâzÊû0¶–9'©¤$D¯E}|ÒçUD%ˆ]<øš™Ï™}¾}cïŽÍ¿?Ï®°¡×CÚ ƒš‡›æ>ÔV‹Õ‚EA£«¾†l. ,˦¾P›06ñûS–è-96üªÌ*d›MÞ$(D¤ìWÙÑÓ£ž§=Ý/vÛl¶l6ËÜc?\¬Uà •N5»y‰Iú[\ŽzŠä Å6ôÔ‚tŠ¥ëét*]Œ¦Í %’FéðÏE9sЦêE™¥A>| ¦_Œn*U(̬^\˜"Û_õQÒ.¼érŠš3 ’lNc"mfî.¯F;¾×K •Ê1$GH.CH†!)B2l.Ã’Gz5™ZÕ7I><3:×ÓÑÜ;zµ'°?¹Úháÿ÷Z‘kkÿ;ZB‘k½ã}7‡æºR+¬®Vzû‚¾gÅ:ŠïYŸ_5ßwœþ½Nš¶Ùtm«§­Å=lõôÌ"KQ6ç6‡­ž²Ñ”­ž‚¯tî¸éýåøâé!×ká佞·ÇSï QvgtªûïËVÁô ónÈõÚHòÞæ—ûc¯kÞ**¡7GÓéTÛÏ:4jõ·%‰T:508¤cM°8ŽˆJ±Ù®Á¨ÃÎö?O_ö¸KŒØÛÖ‡¬ë TM‚È™ˆãQGÝCuMÄlþ,K_rÏGÞ±=b³Z­Îwiø·øç ×¼û½ÒçÙl6ðBÀú°Õú°5ðB ›]7ú¾†ÞW{mØl6ÛÈÛk±Å ôlµ>l­{¨®õ@kæK™ø iGTZ™¿6ßèj¬{¨Îñ¨câ7²ÝŠ­T’`uuu#o8upµ©e“IYøDÅ¡­MÚYQÍ¡×Cá_†ÛµY­VÇ£Ž‰É<ê#,{oDÎDœNgÝCu®Æø‡ñ‰É ç7\©åOJºÇ¿YPÊjµZ­VxHnEÁCÀ½KQyöE0ñûS–è@éó"RôwQO³Ç»ßËùI¬Vk£«1ðºIù5Ì\ž …N†fæf6¾%ÔÓO„§±…Xïk½Òç¯Í‡O…C'BSÓS¯ÒÀfX« ,K–î³Ë÷Ù{+„°Õ[mõVn®&#Ý,Î L0 êêê„[­× Ž ‚Í;ÊkÏ©½!-»Ñë­ÓÜnj©–ÿÖ“—fÓ%g#oXNaµ¢& OÓ‡®6˜º3ÀEïwÚ˜Õ8³š`IŠ%)v•eÉÆƒ¬²„°,I§Vï%W“+q½ç„.·ö‡C—[;›C—;-#á¹®@ËÈèÕ®ÀþðèÕ®@Ëúÿk]{CCsGÆ^¼1zU·m0öÖpów6æ6Ç=öÖ°®8]4MQõ”•¢D‹‰³9ˆÞJ¥R©©‹Ñ©ó³üÃú0”Ó özWóËýÉ7z]'F’§z=ïn² b 1o‹w´qGó{˜·C\×  „œŸ¾0ÿÞÂnÿæ> ør„rá7c3ï Ú¡h½éÑó ß÷“Íßb˜U?@Êã^hÿazèb\Ρ藈ý1¶ô×¥ý÷¿ü‡ü]/tÁæQ¤/9î.ßýçÿ÷Ït*ÝÛ/ó_CìÏ1ï÷¼âçë ô¤¿Hÿóî?ÿy÷Ÿ à ¼>À¥‡^-}²´¼´|÷îÝôýµé·V_kðÕàýŸÿú×ýkû7·÷ü‡Ì¯Òލ´rägGß|ð¯Kñ¥ø_âò݈­TŠ`‹Y\^ZæjSÉ–g$õ RmÒΊjŽ^¦Ò)‡ÃaµZÛ~Ú–ÉÈ+7yo•µl×cñ?Åÿõßÿj?ھϷ/ú»h<ÿ×ÿËxãºT‡ƒ’7v<•J‘U’w“"³¾?eø²”þïÃ"%“Éæo7+½;ÿ»yö+¶¿¯¿¿¯Ÿý’ÿÃ|Þt’%ýýÁ¾ lð^ìz,ýE:x<þe˜zˆšù`FG'ÍÀn£³¨zŠ%p/M’i’!Y[½•®§èzŠsýÚhã±dÙÍ!&¸{E* ŠŠ™Wû,¤¡+/Ä6 àj¿F*5è-R"mÛ€¤V+MCR« ɱ@@QëºÉBrd-Œ>Y  g•-„ÏD®†‚û/ ̵ö˜é½ØÚðBh®­ÿÀ…ð\GðÀøúÿ¶àþ ¡¹ÖþW"×zû]½Ú>ª'rÆãgÆüìHâvÒ½Ë5~fÜÀ—Vf•9ËJBßئZ¬Ì¿áeY6ÃfدÈÚÌ·…¢¦h‰¡ÂºÇ`$yªÇub,yªÇujxñgGºÿ¾<;7ë?äŸ>qýz,y²ÏóöøzžÞæ·Æ ¬1 øù( å´;óæõòiïÅ:âü”…J$SÞ§m‹I?¡¶G3„v:RÓØAOåãÿ{œ›ð öòæç{wŒÛ/uìÝ1×Ão Äÿw=áâj>発8ÿSœ«dâ̄癵J&ÎOÄcqÇ£à=ËÉ™æ‘_|ã~CcG”Z¡(*ýE:•N©L ÅVªGE°±_ñ[ʪeSI© y‡N©6ÙÎ kfWXæ³¼¼ =ÿÑÓõó®™K2Z—Æ[e|r=Ûñà@ÿÀF©ãA¡ SE8ud¾Ì0 ãtʺ†¡(Š»ió`Æ÷§ Ch–‰]e­oÌÔðsüÜ]—H$º_ìæ2øù#ç"­ZÕÒ?It¿ØÍ­‚ðò½)>2~+Þ}l­ ï‡¾ÑwFáÃîL¯¤=ßt$¾ÈÐSäkpØ8«Ò+Äñ0¤Óiû#vMuIÅ¿÷rƒoÎ="œñUÏY Z¦½!íh©9…çÈ WoÝÄ¡3KNo³Dª~¨Þ§Æ#·{?ŽºŸhaH‚Í¥6ÖÑr6Àúsá¢s×ùÐå¶©¾¥žóÞþSWÛΠ͵õœáì„ËÜÿŸô¼0põ'ƒ¯L. ùÝÝ‘ë½ú¬°ÖSã“ã=¯ö޽=bìÄ4v(«uìdÇÚ@䀈\ŒzŸ ³«d͇POSekÎ0ȰÙCœÛub°¶ÆàÕ#®“cÉS=öWv„[Wàmñn¬78Þ¥ÃóîTòTëä˜5E‘‰·7và ãšühúâ4sgmÌù˜³ÿxÒyF(­6!¹;I¦Ûï¥mÛâ,éØ˜5´ˆŠËÃ+V«U{\“ó›k’s»3– «Í»À Noªde­’ôý´s»XýŠ/Æ{_ëMü-¡²¶[¶#J­ÌÏΜ½¢izìݱփ2ë…b+Õ£"˜pòX%›úHê:¥Úd;+¬™ª§FFG¸ûõ˜¬Ýšo•MÙŒÞ`•†í»Êf2éòbÎÁ¢ý@ƒÂ¿?åyh»½Çf³ ZcOÉe)Êša3­OËLi‰®§³_eyÛ€³xó€]eyÃØöˆ]ÿVTLgY~le×p³,;4\Èùñ…â~Ê5}qºý¹Îä™T†8Y;~>½BR_fº÷;§/N¸ÝF¶+Ý4 (÷QüÑ›¾¬cïBX×ÌêTWôÖI¶žÐÕ„zCêMç­°\9KY\Ë5*°!ᔼ–V4ŠT²‘¯ ¨î]ã·ûâ·£MOø`RdÝOÊÙÀ¬m|AYh½É„ÏŒÌõö˜škë?430×ÖpjíÿÕ6¡µ0xx~raÀÿtpêáÐá1c]²ÑôÔ¤íyµÞEo¥H4EØ´5—q?JB€«…²ÖSÖÜÆOÔĵDz•tì×ñ;ºæ1XܺׯÇ6lƒ¾0o4¿}ÁˆÇÖ £ÜîíÜËDâžs›“¹Ã´m'_‘ÔJ*ñ—E]Óù›ý`XÀírĬ¯9å ‹ñ¤v/ÅnQî'hþÄù‚fÀ|Îp:(s±7ÈL’E¯GÇÞ“>ç±Ûí²•Ø·Ù™{ ¯àr´ùÛÆÞóýÐg}Øšý*ûoÿ÷¿i”S©•¦§›æ¯ÎÀüµù®Î.Ù@¡ØJõhL%›úHê:¥Úd;+¬ÙýTA§}o( %kÒÛêmdUß×uÁߟòø÷»&/2‘óñÞ6ÔS&•í:1›Z!d:Ò­OËl@$—˵ø·Eo‹Wö]ºžæí¨Ì—ºžÖ‘.ÌFÓtðå ÐGQb¬Û𛛣ŒööE?N'˜Lú+B[ÀaƒîýÎèµÙÔ ÿm„ª§šÜM*õds›Ëi‰ _cPWW7{y6ïƒÏÌT Õ(d®]´ÞT¶!áª5­Èjú ì»Æ†tµ"™Â¯‘JC|ºœºD2å^ªy»†–¦xbÖfqÙ,NB!¤©Á×Ôà÷4ø< >îySƒ¿Éîo¤½É•ä@ã–DžëèØœZ~þÆÔ‡£ÃGçùÿcGcS‹£ý¦æÚúÍD®øÝÁÙ[‘ÞC&Ŷ…ÿB$„8µ3_Bò –ä{4YÖS ÉX‚Ùn§²zŽ„ãÖ$Nv9_Yôÿ$ð×%Þ*h~ïBêÍÐÆZäÛIÛË¡Äk]N½k 6ÃÏ“ÏïqO¸uä+’ºÏ¬½m@M—+BÕÌ›L¦’Ÿ7ÑŸ{»åM|– óm*˜S«D š¦™Ï¥—ÐójOæËLæËLÏ«=G7V]sŸèL&“ü,éùŽGô\HÇs=¯¬WòJOÇsk•Ž/R_¤2™Lï«k³„Š¢¬”•a˜##Ú;¢ÔJG{Çrr™[¿È¯çvS$¶R=Sɦ4’†N©6igE5žô{3™L&“éùÿA?_aÞ¯hé½Q«B6m÷É/~}Ô7).¡çh ÔÀYfbn#tÍé°.Ïu,¿ «§ÝÌ£-½ß÷Æ?ŒÇ®ÇÖôø¯Ax'¸ÝîÙ¹ÙìWÙìWÙÙ«³n·;ozôj4›Íf³ÙÙ¹YisžfÏôåi®­T*55=eb_4Òø­&×vçôÅɦm<è<ì t6o§&.N$>K:·;}ß÷Žžå7?PBi-ò†Á•KWü‡ýZþúVÇ#Ôù·ø5CœÂUr ÃÐUm)ëä%äŸî¦Þ9lÙâyD½GÚ…/PNî ŸÈg.Íxjº­@ǃM6_<¥-Nå&H¢‰Éè­éhb:&xD?™dRIß7ulU1rl>t¾­íé`×;{ÚÜÝÂÿÃMÝC—ÛÏL\hswÇ’Ýú‹×Óü¬VVвQY…T|<“ÎL\gŸ¥R+$µB–î°3 LÇ› ³LÛ±9iJ×QÑÞ¡ñ…Ážæ·.$Oõ4_º2åiò4{Fw4O^¸÷F_Ó»k¶ÁàµË•¹ÞcÎŽºcƒ†–HZ`mB1·ÑGç6'°+)à½$F# t$YÀi§¯¼Ý‘ZqOÎÅ'/ÇqÍÿ:à´Û¬ëGˆ‹h&Ølljä¿1D/ eoËŽÆßøŸß môà/EÅcŒy¿ëåöo>284hwØ¿±ãߨñ »Ã>8´VIø—a—ËÕødãŽ;ìÛÖæ¼Ç'Ç{^é©û¿ê<Ïx¼ß•Ÿ¡”E©ß³¾ÖµÖý[]ß«}3Ó3ÒnŠÄVªG£`*ÙTFRïÐ)Õ&í¬¨æ@gÀ±Í±ãñßøÆ7!cŽDé½Q›|½ñ±Íd2ËÉåå;ËÛî U.Xo¼ç€žSÉÈåTV°oOŠ“ ›ÍÖýrw†ÍDNGz_ë †bƺusï¶þ°•~˜¢¦[Øš7,0484:<êt:)‰gÕÛâu:‘³‘ЉÐÔÅ)÷·ÊãæjüVSûsí©û©Ø¢“ç'gM¯¤=O{2éT†Íœm°üIÛ@k*ZŠaFß=}®\ºÒvXÞû#.\W§=3b"«ãÖI¢Å*S΀[æó<ûñÅîOƾ˜p=ê%¹Œ£Þýdr¬åÓ¢ ÆÜKÏÜ Œ\ííh-¥¢mÍEm1¿H÷ÙÞs‰à1_ŠÍ‚Ø 0+,]OÙ,¼Ã¤VXöË <e¥(Š¢íV‹•¹³4øœÓ¹Ía«§5*Ö©Û & ìN4÷,¾zdûkË?ýIó¥+÷ÞêsKžìq[z¥Ãv<œ5™bΆÝ}#ûºß»a öwæZ´ãpGü…&×Ã@RéÔ=Šm ²k &.Nµí÷iéEla¡ëç=ÿ¼{,Š 5ñÛHïk¡ EÄVÞ5-P"GÞ <€ç¦ ƒèõhà…n½ý’’÷k$ðB iWS÷+Ý¢çUDiÄVI‘ &~{WéE)#Ùl6N;·9™{ UO9ðÐÚNDÎíÎT:EÓ4åÂ|¾ìüf#÷¤ÀF¹ÿÝÈÿ@ßõæ½µð•ÌWýÃrt!=»ô6°ÕSÝþnÇ£¶¥G¬¶¸‘PÉØÂ‚)_ yÉ|™‰œ‹„N„JЖY,%–"§G]»Ü6Úˆÿ%>qf‚»¸;»^0Õ4øékÁ㽜! ø[1s9ÏÞLz! [QPZeÇ»­“²Ð³Ÿºné¶<Å <×1öâ¡Ë]½a†—Ý*àa¾ÈLÏÅà!ðÿÐë ©Ô aè'Ýð!d-ò¹“ôí²Ú( ,:;v¹áv‚ùq`q¸·ùí ‹¯ñ¾?Ÿ<ÕÃ[É“=MïN%_ np‹C( „XOS,CœÛœý}2Ι,«ÞýCr,±ÖÛ„kþdÉf³V‹u}ÕJ©ãb×cÁãAéó*¢Äʰ”X²Ûµmx¢³fD Ü1©tʾÍÎ9Žl6›J§ÀeŒ}a{:5vj€Ó¿»Ò IDATì×`•¼P©Ì_÷~ß 9˜½:[.‡€ašÜMÝ/9Ûr¤}K¥ÔÎÉÇ[ŠJV¸+Y¶­‰Çî§,¶éd¯ÓVŠï¾Ð¡©óGº÷¤HÒû”?`ÌWÙÙbþ§!µ³WcÍ{=t=Å®–’È‘,ä€ä²ìý{´%ë~ÌAÕ[õîÒ-µ „VÁÚÿ·&L° ÀÌ CXvMáϲÀŸ] €²è;¦m€HŽP@µìmž¾8™aÕNÒ±Ò¶–æfÈ­Зv7á6ä²[’W>• ¶P†Ýÿ¾{øW¦- ª„ÞU²ûY­Vë£å7 ϵy®iÍlpljâc£m£Ã£„×.bTE4¹›‚ǃ£g#6ÚÖÜÌ`]­¿{Ó—§Û·›Ø0‚ %£©¡Åö­±È'2ç4™Nx®#th*Œç‰–4§Š¢6kàûvûÃÎmìôBœ~ÄæØf‹•Šä€¬fX–ÍfRM‚ïÛÇ#4]O[õoôéx¹µ?,÷¶œ¹²xzHúŸ³ ¿™'@¬9N q[´# kJ¼p 9³@k;•®Û¶‡ÿ _PœÚœw½~Ød˜è5À¹³Ð±½Û×8æˆ"SÍëÈÏŸ¥,xöz<{l÷Y94~«iâŒü¹(… õ·böòlY i˜#¿tµô Hõ⤛»Ý"‰¢:4•µdš¶)QYz45Þ×Lá”]‡Ýáþf&zë^â^’ý ²9@9W=q·Ø\vÚöM7Ø XƒÌ*ëü–;±£Ÿ Œþh·÷—ãÒÿ‘ö=ß̳«;åÈ¢Ói@R+‹)6Nêc×úàENÆFæþ™õtâÞ‚£¡ÅI{µí^šÎͰfrp!hÔÚŸDç_{-ö”q$‚ ¢M†·œ@¯Ó H O·ÀáµRœõ® ûB±[¡ê³ÎW±[Ñ‹uóÆEu4XÛV³ÙUB²à! ,”µž¢êmt=eÕ³º` ØhràiñeVY÷ìÍôJªûÒ æs&0}#“Nu_ºAVIpö&Ƀ²òPކGCKÓcEÛè)6Å[' ¦úATð¶´¾¢1€¦ß%îȽNNƒ/ïQ_‚qÔ+„š˜ØDCÑ›0ˆàÛÎZOY){¶ž¬cÀM[(ÊMIC6šg½lO»ÀÑ@Ð`(î¿ÚÀßu)±……b7úXMBI}E„?Iù…»É: ¤ó÷¢=õÕo&~ç{QYÀ¨!AЇ¬J÷^=µ~ß"HÕQ‚0 ´ókÎ$¦ç7 øŽAÁi þC¢Ý6>Ǩ!A’¿ýR(>€ "ØU’Éæ‰ •?ù˜GzXã òê÷8G… ‚ ‚ Å€]%Ì—l^«òBwRJiTýAA¤d0_²ÜC‹IÀ¡f(9Dé$ßE«AAA*µ5í‡Û <»­)*%؉AA-‚¼aPWWwåÒõ’Ò˜"i%…X|H’po"ÙDÙšàÒ|AALDÞ0ðöÃúæ¤Jÿý‡ýêþZ»(›pK"Ãu"ÈV?‚ ‚H1[év‚„ßjú÷=M»'~;)_§,êg_WXüËbÿ/‚Žmv°Ñ´ï€ofú‚Öž›u¥d«‘'ÈZÔká¡È6ª+•bDNÙU¼Ò†´´®E—•GK¢Jt“ÆâRa¤ ,TŠÍv Fv¶ÿy2ø²ÇõXêÈ`ÀæØî´>d^ÿ€ø_âþC>aŠÿ/ö—8ÿrêâTçóíÐy´}ê¢Ìsv•DÎE\rëã‰ûú¤éZè ööï½û÷Og.M%>NÀzdŽpÊ0r6’ø$9ÿþÌG½IQÔЛ:M"‘œ^o0ï€/æ–>N@üV"Ãf|ZøwG‡#™/S7c7nþþ“J¾áßZ\LÌÌN}ºô‘oK߉ÙÊc G:»Â¿ ޶@Ç Àóýõæ§ýÈåtœÒ!¨Î«[ˆù+^I¤ý]éE¢~ÈšŠ0ü5UoTƒn~ Ô› ¿3šaS7ÿtãÆûó±ÅO–Òí4rz4ù93ÿþÌGº™J§Š×Á¢~öu倿o»ûN ,}œàÍ{]˜r¥dk!± @É0¸réÊôåiPùåÒ³â‹xŠPTÕÓóu›)·8HcÑó ß÷“Íßb˜U?@Êã^hÿazèb\öW‘]aEë vvemš6u?ø8é;èßA_âãdJiÀMÙîlÚ=q~z\â à*·Ý$‘¢¨L:•ZI;ìö‘¡AÙÖ)Ô–xü}áS¡‘·F tjÈPG8¥ÃnŸ¹4ÓÑÞArÀ)è„ÊbµRTê~zè­Ñ¼5lBïU~µ»Õß–Íe;µ9¶Ù³„$n%øwõJ"º ¢—›ÚÕpˆÐ(ŒJ£Šè4í7^|‡üáSá‘·Â~ccÉ„Òíä?äy#L×Ó£§GuDUÒg_ož¶ö#£íÍO{l t*Žœ›p?åÖÒi¯‚lA€pë=­»!R-P@õó&“©äçM´ÅçÞFÇnyŸeÂÇä×€:·;/¼7½ÝíÙ³Û³'z=zá½qNßš­+áð-kÐðZß ¨™Ÿßÿ‹aBÈÿ÷ý5/DR!÷ïAŸäO%€ÆàhµŸùu/›Ë®—½†¿ûFoYƒ†ÿÐþ@‹"QAü#Ð8Ø œx]do/õ¤^QÙuT>ÊÔÁ·¬AÃh ‚P•µQA‰…ð4ŽŽŽö³ïœÓ©û°¸ŽÊòƒG{´Íà\uÀ·´òÝ,Ü f„oYƒ†ÿÐþ@#u3ˆrÖ›ªz’è¦|ÂFË…Ô¦ŠK)Ÿ•±é«µ­Û4}òº4­ÒÂHMbxhTeŸ¦‰©DÆ10*0ôk§?* ¿é:F-`NªK rð¨+SDuMÐ#Xu‘2+G•Ÿ;B¨”št1zPuGá$"šPŠÌÏëph\*£‚À ÞT}Þ(-¨³çõ‹}@iê£bô¸ Õr‘q¨‹ Ì6ƒˆ(}†Ùl¶ê®€ Ž«ßÙwÐÏÜÆ £‚À ®PZ GSÌ€¥øûÕìÆ0Œï ª= Ñ4:klV ¨Ë´Ž5ˆÀŸÅKï />¬4]@°\iÐ4¶:c£¤ €V3R¢â±rZ˜°uDPÈÔ^m&AÅ¢à€"f2áóa1£aÆPQ jÌÀÒ‚uH”‚¨Ìê& Ÿ$¾H†ç#6ýÖ§D`PK4ƒë‰Æ¨ÇÐ(ÂóóÉkIBHò‹døb„¬Ó'6°êеŒÍ‡þ¨À­W¸¸·»«x7#t*ä¸×Qv·ÈÅ…Ä•Dî×ÅOí·Û;¿Û^}Ô†±‹“Ò†¦q¹f…N…ª>Pʽµ«w/{;'ß(^O%“B•GF``ˆZŽM)L@}©¹Ùæ•L ¤ê0 ½ÕìÅ$¢Šá‘ª¡ø¸þPZ`ˆ Àl,;p« «–Pà‘Ðp"óó5=>ýà›¤¢¨†aj݆“:¡iáz¢.WPÐ:Y ›ÍªÙ­šø¬š+ ?* ¿iD- Râ³x骜k„âc“Cd'gli€™a\YÚä –!Ò ŽÔCÆ€Fˆ ´@i@hºÁk:– *(Ù:r•B`P;ùÈe4E@a˜”üW›´ßgz–ÜWt¹l–Ëý çyiÓÇr?ϾÜÏB"5{"»x%sM´µ°[7÷>ëâïåßH±ÙØö­­C/{8~Í¿ ‘7cá·… „~3ßÑÍ»vu8XóÁjSâȹ¾ÉϨp»šSöqÜÇæ»xzná½ÅÂcæš.ý Tz*¿{ ;ùç},—"…Ÿ €©a*‘&ëÊFkyG˜Ât rõK”¿ ”Õ¡Ò8›å²Y.û5wù2ç=ÈúGÄ©“Eö‘ýO~ÿ‹b䂸ö9Vü’[^æÎœf#É÷:o¼çΓžGDÏOØXŒÍ®p±ëùÛóˆ8ó®BCÅ:©¾Ï„È2°WìÝÅ^޳Ùîrœ|’z=óí癩£õ¼4›|ÒHQ>^ŒÍ'‚ûf;¶:Ü7}Ùøã¾Ž­Žñ}³±ó ùsoŸ|H¿Íf›ò†×ü•hìO ï)Ïô§¾é¸oè˜{qAðý4¤C·K¹ðŒ·«:ÁG±o´GßUXX#ñ‘ÒŠÇTÕÏ ÏBý÷âÞÝqöW‘çÐP“ˆ¬À€Èj=áy2°—Ì̲bEoz-sæ,ël'd=aYâê"3çn]§ÂçäÐóâföž¿ÕP,Êú‹‰D‰kì³ð9ñß³=;{;!ë ¿‰ >Mæf+»e^ú¼ô•Äs/FÆfû]»ÜF–¬'ÜFÖµÛ˜í½I}®üðnèe÷âš1üÆ¥¡ßxø{9²ž–8ä‡Nytéd-ެx ’C®éc äFþöé±hÿ·æ~Vt}/‡\ñ“ñA͉˜ƒÊ¡´@ÎØç ´ ®ï“+_dÊî&¿¹žùŠpk‡ÜŽ{oí0~\z–å6æÛH|ÏV„(Êësð„8ô,ËÞ^°ÛV…ŒDõ祯Ù×H¥ç¥¯Ø|¢½Û¡øRg·cq^9±"$RS/D\;Ûå;¶·O¿¯ëqå©Å‘O!gà{æÄš¤Á¹£‘_ºªégEgQé÷âìv8hy5ªæà&…À Æ>áØ8†hó!*¨ é7Ißc¢ÿ—ù—ärÿ+|ãÛo²âW¤íîTÏqê>_ójò‹Œc³r‹­w‘Ä•òÙ‰Jûœ¸’qÜ¥êíÕœ—¾Ò_¤ø»”sü]œðÅšîõñéîP⣤û‰5ÕÐC¿éÉd2û;ώK ºãu«AÛy·æß€\åîÛŸú†Ž¹§ž Ge…°,KºÏĆܻÛÿ&øÜgOω×õè„~G.} r¿t;º@DB™=øe©ê5ýÔõóQø·™åØ#Ý¡‘HáK”BãˆK£ª–¯|ÉMNq¾çË›dÏÞNúÉô›ìÒGná¡Õ±­wÙW”•ü‚86Ë.ŸuDarö …ϳtŸ[ï²%¾(u Š*=/}Ù‹Ü~&„_¤øÍÊdìíĹÕá=å™>š? eo'®Î¡“=¡Ø!äì szuµÄ‘mE¾A[ñ¿ˆ§ áïå:»6Ͻ‹œ‹·¶·:ÚÕÖx”þT~>Ú¾÷n'‰â’J ª'­xÍš¡´@J *DCp%€Ÿ$þ_U5öeY2yŠ}wuŽg )$Ÿ'ž·~µÛô‰/HkKÑG±Ïž$¢GéB~[kÏK_% bó‰Ž"ÓÜ%ü=\úJñDK'ÜÑ Wªë ª#Ûìl*™ñ¤’¢­¥Ì?c¥O¡÷köµ…™ ‡ÊT¨ì§úW5/ƒ¯¸§.è’¨  (Іíˆ ª3ô ;ûn¦ì„ù¤|†I kWh´­#vûêiù±S¯Š©«ùGH]%S¯‰ÞC·†Œ®’ð{ù»Í¼K:¿_YŸý‡Øà« s~æÞ#–‰yÔŸ—¾zŸé ¿qILåwO¼*οqÉóTW‰÷&þ²·®yØVêêšãØÖÛ:YöÈí­Ñ ‹y_l µô‘óN!ïà:··;»ZåÏÓÜÏŠ>Íß ïàÜO´ŸÄ"h7×ü†À ”ÈÑ”¾°tT ©?ÜFÒ»Ëz£²¤Á@¿»DÈ BnøGdÏ^qè™Õ—øMäø+ìC?§ß$©«„Ü ©«dúMòÐÄÉ“,/«#9ÌúFR¡ÓDŠ"RWIè4ýUÊû|™?…¼>ó›Èñ£ì6·8÷‘ƒD‚މûŸÏœ®¬Œ¿Äyé‹ãÙþ—Ü£½ç¢ïÆÅ«"¹AÄ«bô·ñÑÇÎí;êÎ{°qŽxÄ/ SfóŠw§†Â‰RR·…ÅTð¿Âž"Õ½•*}dÏ3®sÿ½9¯Š„ñªy3~îø‚ç™¢wú‹Bž¡ ÷ÐË=zõSýç£í{‘ô=ãZü°šçtÐáfþ†’Íf…D"x"0³®Ó€>ÑÌØeˆ”lÝâÁü f³Ùb¯$—ݺ IDATçîŽçM¯.‡\)BÈò¸æ;‹ærïŠ.Ðbdž\¹’±­#í÷ÙŸd‡ž[³sâ3â#HòZ¦µÅæÞNF~É: Ö¨ŒÌ“ñ£â¥¿eÒib·“ŽïÛü‡Y·lµS5}–ž™_$cbøB&}´¶ÚÜÛÉø(ë¸7ÿ8Už—v7ÈÀ·¦¦CòmB"5{"»x%sM´µ°[7÷>ë’ß&ïãòýmXÇ=v÷ãî½ÎÜÆÄ%!òÎbìb"ýEЬ#ü=|÷ãí=ûtøw[Í‘ã…Ù×¢‰KÉôW¢}ëx µ÷ÙNçÖ[SnÔœBnŸbÈÛ!ï×Òý,ýªbÓê¿—¼'>|LãÉÇP7cã¾ÃþÄgejœ"óóû1œý:ËÜÆì ½_æ 7 !„û׌÷ /x"|õƒâ¬bO-0d&·ŽR&0€:ëãoꓞ¼&|– >ÌÝ)húߤ äMSC¨bÕ¨€þ\ýQAm©èR‰[æP–æçÏžˆÌ¾Ëýšwû¼Öª¹u]ç®6ä Àd fåP8ð¡Mã`«3á§axiæ¡-hæ=Ý7ûJĶި[8×ãí‡5­±cŒk@bÂajYplúsÄ éª–!‚ºqít¸vÝ €rЧ V%R`ì$"(ÎêQ¢x¨Fɨ€`¬‘ÏØÅIC]º¹‚<øK€j”‹ 2kXuìEÿì—ºF²ê• õ„Ç7° ‘e¥ô·nxÁ1@Q*ÒƒŽUV ”Ñ4.Ç "€ª¨‹ ¦©Ó°Qut0–çUR =¨º;^gÔM"BÁ±œåÿ4 Z•D° ‘ÐÔeG‚„£K ŒC]T€\Ažê¾ ÷v·Ný€ú 9îuèv¸ ÓÄÒ Ž4`T@ éѰ«ŽO­ZZ@]®  u<² zzÞl˰dª±Wc–À´¥ pm€q0QÔ˜Qué”PÃzA™3nغꢂ–Ž hú"Àš,6•ȪÃ/£”*³öW+” \†¹‚’­[:W@Œþ.!–Ë”‚GÔ ÆÁrø4À™‚-Ö•à‘ô0°à¹BˆRT@1¨9L"* ¥u¦º‰µ`áGP`qÒ<þÇ*d PZÅ *Kièá‰UK hœƒeˆäúÏèT"W iÜ ¢9š–!²z]ßý9+ J‘¨@”ÿÒ S‰h[ ¿ <á,Èšã”ÆÌÅ£l\néID:}H@EÔ¤ Hcf ¬ìPXZ€¨ 4DŒL¥o©´­ÐéPçƒ,Ëj>BEŠ5áêr¹º\5mÀ,TF¤K Ö¡´ KG:]ÚrÙl6ïõo©ÈàÓƒ¾_àh@üR¼|ùrÇ÷;4t¤>* t«W›³¡æQ Ž-&29ûúÙ3¡3îínBˆÃáxûìÛßþη éLt!jH»f †Ê¨ÊT<<¥¿´€þ¨ ÞMWÞº–+C=rú¨ÂçÂà¾Ažç™õ Ïóƒû…Ï…ÂÝBgCŽ{Ìz†ã¸¾ÇúŸ%Š0ôFˆâÙîÉmq>à,›y˜{oεÕŲ,˲¡³¡¼‰ÄÀÞ\?ú¢Wý¹IDyÓ–g1•>ßÜ[æÞ›ëìèdY–½íÛÕ—ºšÊí#^}‡}Îv§|¢T­çJT£ìú¤y%0Àâ¤r4E6b«_º€¶DÄèï¢ásÁÙé¼ôÑ¥÷#ïgW²Ñ?GÎÂØ`굩¹ßÏeW²D?H$?èL$”cé&ýôo§íNf=ÃÞÎöìè){çþçü|àñååååÿ,wmíÚ?¸úÍéÜ«R‹—.]zÿïgW²ÑhT„‡~ôôª|Š”$o»úóͽ%x28÷û9ñKqltlöÿ›Ý?´?wGû =;´üŸåì×Ùÿùq×Ã]¹WýGüìí¬ÿEé󨥨@,‘. Ô&*Яu°*Z—!òøÒ×Ò“¯L:Ûd=qÜë ¤¯¥ý¿Êמ9uFÚÇÙîœ|e2VØG’ü"I ¿–‰x,žú*õÐÊÝàW”Íf‡ IwèBHðD0÷ªÿWþôµôäÉIçN²ž8ŽÂ”‚¾ç;ùÊ$¿‰'ëÉÐ3C„È…Hî¥Èÿ‰B<Û=ìí,YOœ8gÎÍä^ žf¾ÊÈ;`:æ j6.W[pl¢³_hšÆcé‚cÔ¢ÄEïv|÷Vq°ôsø|8oÏÎïvæí#+Ëe2BÈäÉIǽið=yr’Ü$¾#¾bÝH]M­Nïa†ašîh"„,~²˜×Ï®ïߺ1ïp84F«?_ç}Néöv–’N§s/µ¶¶Bœßqöììñö…Άl6[®3Þƒ^›Íæ}Ö[ißê¥T®@bþÀ ¼ZN"¢ Mé «G?á8y-I¾û®6t;›Û¾ÆzR~B!v»ÈÖ„Îû; !—þv©X7öí?ûÆYÏNÏÒÒRn.`ë§6ÚÎ7ÏäÉI»ÝžÉdÂ÷îo»»mæ·«Iƒñ£ã¢(ޝ²«2y`€Ò9ä *aÙ¨€ÒÚÒJ¯ßºs ý,m_ã)¿!„öûÛ+íFd>B LxžWÜA 6äýÔ¦‚ó-®ggÏÒÒÒßÿçï¿û_¿óô¶¶¶f2™á熫ì@í•)-È1s`€ÒZÑÔ…]ZKZQôÒ?nÝË—~öìðäíûG,oé½…vBâŸÄo½÷_1BH×»÷'ßLÔáì\±¤5ŽþºÛ’ø,áp8Ší_Œúó-a˜äÉÎ;ûv÷^ Äþ'Fd9‡Õâã#(>3m`P³\)K }¶ýãàB”/NJj<™-0°·Ø‡ŸŽ/ÆÉ ’ø,á;ì³·ØÇ?fÿýkö±+ì#zf¨ã»ÃÏ KKš&>K ?7LÖ‘ñ—ŠÎ®i¿¯x5 ŠbêjªpT=þëqÛÛðsñK1rƒÄã{†žÊí`o±B¤WçÎÏË<¨?ßÒúë‹}#7ˆ(ŠR}‚çg«¡Åjññ«(>ª¨ÍHLÈ„ãà*ø4èOX³àXŽßÄÇcñööömîmLãú‘«½½=‹ó›VÖ¹åù‡žêy¤‡ib:ÐÉoâcÿ+zÃ~=ùàÏt>Øéþ©›YÏ8;6›íƒÈ®­®bÝøÝ¹ßu=Üuè…CÍÍÍÛ<Û:::òZwÜëˆÇâÛ~º¹ÙöÓm½»z}Ïߪf>sêÌæ{6ïßcš˜áç†'OM’µÏ7¨ô|Kü@¹ôKßûÁ÷˜Û˜æææà‰ ÷÷wç~'½„âchæäÖ ]@])–+0¢9ZsÒSº¤›ë9ü&^þÄ€<ò•÷ ªlˆ½  ŽTîï|À™·˜iáŠCŽ{ÓçŠö³ow_ßî¾¼ŠË©?_õ[äÆŽ£ò(Sq‘žÙ2ªæÌÔlìG[T`,Dr”E ÃLŸ›EQ¼.Nü÷!dð µã{°&³åÕl" £šò=–Ž t¢c®à¿ÿÃÔkSMw45ßÙ¾› ¼¬öF>XMC˲Œ]œÔ84FXœT޾ÅI{vöôììÑõÐàÌ“1°ê# ”ÑX> h&ÔXø‘ÔM€10WPкJÖ)-ÐÌ<ƒ@iÉ *¨3Œ1QZ GӃ̬^Z סþp€v7×üF}Æ¥r4õÇêQMß…EÈŸ5f:¦î¼V;ßZÀgõG÷èÆªQu¹‚‚Öé jËÀID6ø,®¡ Eæç 7šåìLÝy ¬v¾µ øèé¦Â6 Ç\ß00*@]=­7h®3ˆ€6ÔO%²SDõ^‰t¤”. F9‹°ê "™­à˜þ\Aº T$* ÈäÃ$¢’( LQ¦xT@¨n¨êJ êÅlÇ ûÈÊþLÀ”JFÄ„#DõbºKƒzºFºA[¾õíÕ#n°9îrtoí|j³Ûó^͹üéÇÒvéÅCÉw.ÜXl{á«W¬Ÿ¹‰'ÆN,üí!¤ëûÞ##Î{¥ß+ý øqéÞùÕ¶l¶ŽïvŒ¿8â¸ÇAŠ)âW™à‰`øB$™LÚ6غ~Ø5øÄ€«««Ä¹ä¾ÍÍ÷lŽ„ç䯺Úsåʕ܊-ê.q%1~,xé¯ éL¦ý¾ö¡§†<;ºÕô¿X÷Ô0þïÄž½{†ž|rŸüûu?Ü5öÒxîËUs©lùÖ·»îš>{¦°ŸÅþ4}NµBÓèϪ2SFST`é\1ú»¨½Õae&“¸’˜ýíì6OÏÜì ßÚ*µ¢C)n)Û>*J|‘ìëßã=è<9I™}/¼§ÏÌìŒã®Öï*ýqé+7â?ûVhøùCs¿ÿ|{žýÏ ;69fÎMówµ¦Òé……hðÕ))0(‹µ±‘ùyww·ôkäÂ<»aÍ¿uø²W}ý{¼ÏŽŽsì±OÏžš’Æñe)vOÍcÿ¸´ÿÀðø/G<;=òC¥Ò鉗&|Gü¡S“¤’K…³sÓox¢¿Xƒ€z(—. ÕXµàئxb– (¤Óâ¤Y Ðºò%S=ÖfsÞ×îéßÝ<¬E´ ¾|jpàñ^vƒÝ`x¼wð©Á©WT{=?.vƒmè©¡Å/–Þmᯠ#¿ôòwµB8»Ý³Ã3sîm•M =µoêµPîשק†žÒÜam‚'O =54ðx?g·“u¤óþöÉS“5=`taaÿáÉ` äpvûÈK# YX=”êKåøKc¡·¦WÕô@g7UE„–À€¦q°ÕЖ.°äµ1ðx_ä¯Q£{QÑ¿F{w­öîòTzîuø¸Ä¯2S¯Oµß×^z·®ïw:2ûÇ%1“©´ ÏO*-Äþq‰ýðR*Ry«^GÑ¿F{ èµ;`øÂ¼ïÿÛgÏOªÜú§Eý¥Ân°OŒ?H僨b–OÅc?Sä X9FjШ€ÎÒ‚ø–Öt:û5ontéYµÛY3Źݒôµ4ß²f*ßÒš¾–.¶¿¢¼K_¹ÎÛ[ìs³3…Û%ÒGwæÔ™©×¦|GüW®\imiõlwôrÔ^3ƒOM …NON½65X.¨Ã—•¾–æZŠVk”ø _•ºWú€ÃCÓS“Î"áV*ž8ìz¸+×7õ—ŠëÁŽ®®®À«AßAo‰>ÔI%÷)( j3‰*f¶G\µ!\KÚeÕ´UÖèµ³f% ˆív»p-)ð ×’öâCIEy—¾¤Î _$‡û.}´XºðƒÝ`óòúy !‰+‰©×Ïž~óLដv÷_ †ß /~²8}:ÿ]uø²ì-öTñ¡|ébwÅî•>àñ‰1ÿ ¾Vû™Î; kÛ`sÿ°+ðÒøê¡*¼Tü½==ê~øRÞÁê­Âì¥ÑS‰ ,-PžÀ]'4¦ Ö²zT`™Ò‚BÓï̸vÕ§-c¹v;–o™}7ìúaeç^‡‹¿«uò•€ÿW~õs„›c£# ["ßÚÚÿdM‰Bü“ÅÖ¼‚éudðÉÁaï¡Á' ù·ÈõC×ìùpùýt:`ßîÞ@0°çû#óóòí—?ýøò§ÇcŸ<5™ **¾TÖ‘ÉcÇ}#|eú«|N£¡Mãàz¢1*@Á±œ%¯L1“‰²8>6qî·ç¼Ï[b „÷¹¡×CÓïÌŠ_eį2Óï̆^yŸ; æ½uþ¸øÖV×÷;òƦyúú÷„χS×Ò„!™œ8ìøîêíê'¤ò©þ,öK‡>1w„¡§ö]þôã¡§öÕè,Jó>w`굩éwfS_¥ÉMû×âðášÐÝÝýöÿsÆ÷‚æÝÙ²‡ªôRqÜãxb`ôʼnjN ÎŒYx"4Eô·nŠ\~­×>P¸¤f uø²›3çÞ?œ8>‘ùæ±ÕtOÍ;ìxûÍ3{öíO_KˆÊ^*ŠŸèØ·_å)Ѐ!„d³Y!‘ž̬ë¬_ËÆN"2uJ òTRpöþ<›Í–=d⳸¶¾Ð&2?¿ÿÃy§l–³3uç5°ÚùÖ‚âgV86î;ì/ûoéê¿_g™Û˜þ©?¨92ÿIØ{Ð<¾zʈiͪTÏÒQU—! ŒIkÖ ¢‚Š!W ‡¨¬ÍèU‰`‘1,èQ˜W}G¦Æ‡º¨¹‚<ÔÕÔ[G%V]†ˆ~ˆ è£Ûç­ÑÞ`L}v¦î¼V;_3ª×˜¨6íÐP—+(h,Гˆ†ÑëP2õÙ™ºóXí|LŠž›¥5žÒsŠ4 )&Q‰þÀ…Ψ€ÒØkšúìLÝy ¬v¾&U—q"YCÙ¸“ˆªGmTP‘Ú¯J„‚cZ!*€œŽ+£)]€Ò‚ê!W¤–cUä ä,4h®@×ëQÏÀœYiqR𢫣î»@TT¨Í(©6¹ýZ¯!êFyfËš~†4.N @3CiX,* .˪Á Çrv ‹“Ö¢hTzg Pp,gÙ\…Quߢ ‹®Ã%c£ãF~4Ff+-0ET€Òh`úY0ƒHβQ&ôG˜A'³öW3SˆÆ!M1 Ð)S°EqœUg)£l\néID4Î ¢1–«)Œ ˆÑÃØªQ8‰È@ˆ jQP"2?_ÓãW=²FiMq–¥£ä  ±0 £Ëqs’êPXœT޲IDP%D #†a²Ù¬æ·ðç÷u쌢*†“(-£)*°t®€ý]QelP¥¹ ]«™"* îÞ/ÆÁr˜DÓkFP-hF©zSÍCFv Çrˆ €z†ä ʦ H͆´ XpL]H Ôº¥£ *€Z«sl &* Z¦Yµà˜:ˆ òP7¥ QU·9E*£Rñ` ‹“ÊÑ4ETP=ä  žŒ­E.TIÆ€¦qp=Ñ8Ä3p" Yõʳ«uÞ@}º€T0¤²êâ¤4æ LØ:åÇÈ@Õ!WPQT@h[®ÊCi€iÕmîP¥QQ;Ð+³Wcæ …éDrXœLEŠ ²Ù,Ã0´U«Nà¦.*(@T@?“F¶ý:ma@¡rã ,C$GÓä~ú£,CT#ˆ ̎ΤAÉ!†UY@]T€Dy,<2FT5R|”aÕeˆ`Æ Lš.€Æ@U®@RdEÓœ™z¢.WPÐ:Y  “FH@í(«|4fi¬A[ºQ€Žn®ùMÛX£1£êÒ(-¨D„äGD!c€‚c9šFcV hú.Ϻ¿)iÌ‚c£”ÈaqR¤ H….Ì ª<²@Q€^”B‰Š'¯Â ¢zÁXPŸ@]¨v5æ "XpÜ ¹‚t€¤xº€?*Ç$¢’¬^Z ËF ÃH?ÈŸŸ¢~#4š’QQ7 FiA]`qÒ<(-¨Žâ(_ýFh(墢¢Æ¥€¨ <¤n Á•5fiQ–!’£é»¨?”€ÎT¤ HÉŒA-Ç~ú@1(8Бº¨€è>BGiAÅPZ ‡¨@Gª£Rd(Ô˜3ˆˆâ‰Q6kQAõô‹ êZW€¨tVIT@*yÀ™éQW=Ѝ tÍÔ¢0\áx‹“ÃÒQu¹‚D`n¦ HAÆ‹“֋˜уrã‚ÜÓͨ:Ô_µS‰è/- ?*¨wÓ•·n£>]Àê Öötë‰ù†¾GÓñ˜„È|ÄÕåbY–çùÐé^‡€JÕ¥ÆÀè{¢ù(‹ .0ŒÑWf­ÓÙlVǧ玦ãa£ Ñþ‘##ËË˱X,ú·¨.‡ ª ÌZZ` ËiJ_BiJ‚ ¸º\ÌzÆÕå!·ÝÄϲlçƒò“eYÿ¿†.M˜<9Ù³³Ãi Ì}“XŽþ\íýCTP Ÿ×çÚêZùrÅÕåòy}¹í™›™ååew·[¾±¢c.//g2™¼—ÔL7Šþ%š’<ϳ,Û³³'u5Ui@/ka`Á±ÖÒ‚20W Œþ ¨Zá aïA/˲ÞCÞð…pnûêÆƒk6j8¦†.¥Óéø'ñx<¾üŸåÍŽÍûŸÞ¯á   -£3W 3ˆò`‘Ò×Ò<ÏBxžO_Kç¶+nÔp̼—ÔÔ!Ø6ØÆ'Æ9Ž#„&Íw6WÚÐKÍŠiš±Cú£‚Ú¢°KKE›mõz³ÛíÒ\Aì-öÜ>ÒÆÔÕ”|£Jö–[ÇÔнö{Ú5¼ j¡²À@í¢†æ Ý:¹jdÂqpc.Nª|ÔoqRÛºú¥ ö$>Käìg;¾Û!mtowOŸE1x"èîvçvÎmôìðTÚg»'x"(½=ï%55ý÷û¼¾T*%^}#>ÏÏ*î襎ƒk“ˆÀžŸxÜ7ÓÄ„^Mžš”6N'££Mw4E/F'ƒ“òý›››#ó‘ÀËÇÌ=¾@þƒ@0¾nnn¶­Óráøúll[¶li¾³ùJâÊ™Óg4t¡väH]AiA¹ÖÕ öaLúyüèxÙýó­'S'§¦NN•ßj¬.8« ꢂôGP#¨¤jÀBy]¡3* )S¡–!ªÓEе:>AèT~Ì‚Ghaì# *GT +”Q”‚ÀšÊL%2Eiš¢ú™"*Ð5]P?¦K€eé1l¡íAfÆ20WPкñhŒ 0‰¨N†)–|(ñ¥TÆ€þÒev©>h›D„¨ÀÚtúGæ#®.˲<χN‡ô=8 PZP±‚çgY½´@ˆ @]ˆôŒY^^ŽÅbѿ寻 UR PZP=«G4}”H$ÜÛÝÌzÆÝíN$¹í ÃŽøM<˲¹gnT|»Ãáˆ/Æ !‚ pGnmù†|£ Òý~ÿ¿†3š8:1yr²gg25¢Ðص4ÓÔ–“ˆ ò6ߨÓ7b[GEºÀívûø³+Ù¾]}ƒûå/Í_œEcKKKáóábßîîvÏÏÏBfßíÝÕKÖm=›ÍÎ#òy}®­®åååL&“÷’â©y¢‰&…$Ïó,ËöììI]M•} TDëÎ(úPÄ„ŸFÖ(£ΔΉ„»ÛMÖ“}Oí[øë‚ü¥3§Ïð›xŽã"ó‘bßîþ±;r!B™~gºwwo¥] _{zY–õòj8£t:ÿ$Ç—ÿ³¼Ù±yÿÓû5JX°ÔÍÐô41úÓô“QZP¥¹ósÎv'Ã0MMMywèyž/Ü?o£âÛÝÛÝ‘?EAXüd±ç'=•v)}--µRØ5eʶ ¶ñ‰qŽãØÛÙÀD ü¿Ãeß©ƒ_q6áÆboÏÜȸâfÙ2ßUv-i#Ïó±c¢(ŽÏkQÕ£ÐÖ“©“S©TJŹ÷æ¸\ù·@%´®Jd8š¢±Y½´ÀÂ(LÔÊ 2õÚTÿî~£û5¡.0 0]”0vqR£ÓŠ anclëlÜÚ¢ÄÀ@5TŒk(Œ ¨Yœ´ÞÕÆ–èQAÅŒhºpª)@`å2ˆ èA[T D4 ·Æ€º¨ `r¿¥—!"F†28*0úôUªtZ¦!«ø¹‚’T¹-hú+(ª‰F¹¨ƒª^P…ÆŒQ±¥´1ÏØ´Ñà“×J¾p*(*7þ ?* ¿uú'eõLÔötó3ɪD"áÞîfÖ3înw"‘Èmg&p,ÀoâY–  Û¨øv‡Ã_ŒBAà8ŽÜ(Úºâ E ÄN‡8Žã6rsïÍIApu¹X–õñçö¯‹}»úX–í|°Sø\6öìì BB§C=;{*ø,@¥Àw%å > ú'5,£? »Ýnÿv%Û·«opß ü¥ù‹ó±hlii)|>\l£âÛÝÝîùùyBÈ컳½»zÉú¢­»=Ÿ¸’XZZ ¼8tø´Åçõ¹¶º–——3™Ln7ß >ûFûòòrï®Þaï°´qòädðDPÅñãã“''å‡Eq€.BH6›‰à‰@ØæBiAéÖé (Ï”hSÐúìÐÏÕÌE±¹¹YEéW†a–––xž—±ðíÓoNϾ;;óîŒk«käÈHÏŽ2·í†‘÷a˜ååe)ÕÀܶú·‘‹ÿ3Îó¼ mmmÒFžçc±Ïóâu±íî¶T*%Áÿ¢?z1êÚêi¼DCê»`cã®.—Ê]?t3·1½¿ùCÙ=37Iû•°÷ /x"|õÔÚŒ¢‚’­[½´@ˆ ´¨¼õ¹ósÎv'Ã0MMMò›ñ„Å o£âÛÝÛÝ‘?EAXüd±ç'Z&ópG‘§Ò×ÒRÓò$“ɶ¶6†ašîhJ§Ó¹íƒO Îÿi~ð‰5 ‚zbÐR|Œ¨ ¿é--ЯiËiš>ù={÷ŒË~]ùrE¯·óöHc—b—>¼4š¾ôá¥øGqùAPc  *ÊÑÔ…]²ˆ*>ùÉßLö<ÒÓvw›ã.‡Žoww»m6›û'îÒoÏ-IT¸6Qž@0¾nnn¶­»õW˜ׄæ;›;]å;ìóò’õÄ{È;üüp¥g¤¾K ¯0W Y[|¼AmMƒ^¨Ë´^ïºÚÒ.8¦¼®@eñ±¾¦ÏMŸ{ç\n±Q¨‹ó¢‚âÅÇ@÷XPýsíÍ€‚d굩þÝýF÷4*–+( ñ4ÝêÆ„,@iAPž.0sc[gx|àÖ%öJ( ÔÝøET‡Ê±©%ÐúÉÎ\Â:¡Ä˜1¥kÑÿÈú£ä ´ é¯FÙt1d*#nŒ”] µ›DóŒ#û¦x(šÏ•š¨€Ð2¡l\néID^†ˆž. ŒYf 1 c–®ԟʨ€ÔHN]ºÀl2#ˆ jÆŒ2(A}T@ê<•ˆþÒú!*¨‘Ë$ ÷v7³žqw»‰„´1r!â|ÀɬgøM|èl¨ÄFÅ%†Apu¹X–õ¿èϽÄ0Lètˆã8n#—{¾x]ìÛÕDzlçƒÂçBþÛøKw^ý1 [æ¸×_”=ùá6r©«)©uf=ãêr ‚ o+p,ÀoâY–  È»1~t¼³£S¼.Vô!+žf±s/l]ñ4ÕqrE¤žuQAÁÒ¨ô§ ¨Ë·@TP±Ú,Ñëv»ýGüÙ•lß®¾Á}ƒÒƾþ¾ãGgW²Ñ?G#Š”Ø˜Íf 'çø^ð¹º\ËËË™LF¾=q%±´´x9pèð¡ÜžööåååÞ]½ÃÞÕ§û¼>×V…·+RyÌ\?s?ôíì›}w6wœ™?ÌtÜßÁmä¤ÖW¾\qu¹|^Ÿ¼­ù‹ó±hlii)|>œÛ::÷Ö¹÷ÿø>{{Ñ‹ZñCV<Íçž×ºâiªÿâ$(cRyT@êùäcå§Qu邺A¦›Dd#䜺'‹¢ØÜÜ,Š"!„ßÄ{Ÿõzvzœ÷8ÉúÕ7Jòæîs¹ø?ã<Ï ‚ÐÖÖ&½Ä0Ìòò2Çqäan[ÝŸçùX,Æó¼x]l»»-•J{»"õÇ,ìgôbtøùá÷ÿø~ssóòòòþ}ûÝÛÝC†ä­;¿ãL]MåÞ»´´Äó¼ühøý†ŸŽþ9Êo≠òYñ4‹{a늧Yå @Ó=Aå'ç©÷“mˆ Š7Mꢂú±­3eTPÖÜù9g»“a˜¦¦¦Ü]ê¹Ù¹………m?ÝÆÞÁ†N‡JlT”¾––†°ò,!„ã8Bˆ|lšL&ÛÚÚ†iº£)N—~»"•Ç,äú¡+ñïĹwΑu$ü^8ü¿ÃÒ£šå­§¯­y{aöìÝÓ·»¯lT ø!+žf‰sÏÛ¢xš•~qˆ @#Ÿ|l ‡æå ´$*?š={÷ŒË~]ùr%·±óÁΙwg„Ï…¹ßÏù^ð•Ø¨ÈÞb—fçËçè+jmm]YYÉ~#÷vé>}Ù·«?¦‚õijÃ3>6îù™Ç÷‚¯ëá.n#G±Ûoµno±—n+‹Eæ#Ñ…héÝ?dÅÓTYå Rmƒ¢¹šîÑÒŸ. ˜lÒ¨Àt¥ê?šL&÷ðbFÍmì{¬/þQœÜ ©tÊf³•بȳÃ<EqêÕ©Ò­÷îÂçÂÀÞÕ·o÷OEQ žª>2Ç”Øíö؇±[ýü¹'™L8p ™Lì^ÝÓ½Ý=q|BjÝÝí.Ý–Ãá˜ù_3ÆKT“"²âiª?wÅÓ¬ô‹ChcÉŒŒÕ£Ÿp¬Œþ È&3ÙóHOÛÝmŽ»¹ý»û}ìQ¦‰}itúÜt‰…«ýB/¢ ÑæææÒñ!$0® Íw6wº:Ý?^…‚ð…pss³m–oYñ˜ï!ïC?z(×OϽÅÞ³£Çn·÷îî]ý@‚“ыѦ;𢣓ÁɲÍ9ޱ—Æöí/±â‡¬xšêÏ]ñ4ÕqÕ¨añ1Ë­…¨ zÈh¡ÇÅ ²ø¸R©Ô–-[äå¿PSæ.>¦.*(`é¨@§Ù\ˆ ´ íb¨„ï°O¼.†^åݳ€P“!QM1Ic@T …™£BHkKks[sû=í3³3ÕMq*<…+꘥ŸUªWM£1±Õ/] µÆ”þeˆ b& È7ƒØ¥˜Ãá(¿w9Y%ÕVwfé'@•ô ¨Ç‚qðZÖ^œÔàtÅt(Q7‰Çrˆ ŒBÛ•PGx /€Yè™1 .*0VƒŽ€ŽæÞ›su¹˜õ Çq{¤§€€!t ¨‹ &÷×»´ rô/Nª+úƒ Px1P#x28òâÈÊòÊåË—ùV¾ï±>£{`]úÔE,=ƒˆè¶8©–trùu]s˜D¤ †aB§CÇq¹¹÷椂 H·ü]].AäY–õñçÞ.^ûvõ±,Ûù`§ðùêž‘ ‘ž=ìí,Çqc¿›ÿË|O rt hÄä êhŠÐ¬¥¢IâJbii)ðràÐáCÒŸ×çÚêZùrÅÕåòy}òËËË™L&÷^ß >ûFûòòrï®ÞaïpáÁ#Š´ßÓ^‡³EÕŽi̘°uÊ ŽQW mW‚¼‡¼,Ë>1¸p¿´%|!ÿgœeYï!¯ó;ÎÂÁAiã컳±XŒeYï³Þ¶»ÛòŽ_ŒïÙ»çí7߮۹@ž†»™Œeˆ*”{€WÙåƒ8Ž#„õ·¶¤¯¥yž'„ð<Ÿ¾–.ܘÛ3™L¶µåÇ’؇±žGz/zvôh= ¨VUS‰¨K *ÓôlµBHhAÛÅPR5í²ÛíÒRB‚ Ø[ì«mÌíÙÚÚº²²RØÖÜ{sÛ<ÛΜ=3¸o°ªÓ€êh ¨‹ X½´@ˆ ´0UTP%÷v÷Äñ Qƒ'‚în·´Ñ³Ý<”6æöìÝÝ;:2*^…Ï…½ÒÆ©“SûŸÞÿþßG®Àp£ Ž5Ý›·¡´ 6ÔÓdp2z1ÚtGSôbt28)m á áææfÛº[g˜ׄæ;›;]Ãÿ5œL&¿×ù=æ©e` -£ú£«Ã§a”†þäåór?ó›øèB4oOžçcƤŸÇŽK?°·³ÓoN“7‹ŒÕK (¼=¬ÓWŠtAÅ(¼T«l,C®Àêuˆ Œ‚¨LNŸ'†¦˜D%Êë ¢Kª 0 .]€ÅIkQ z1€¥¨ èÄX=*Àýr£Px1è$÷à34S5¨¡.WPÐ:J ª‡\,`1æ¬1ÀXP¹£Ðv%T¡L` ü.MÏóÒ J äPp J‰„{»›Yϸ»Ý‰DBÚ¹q>àdÖ3ü&>t6Tbcîqcòc ‚àêr±,ëÑŸ{‰a˜ÐéÇqÜFnî½9i£x]ìÛÕDzlçƒÂçBþÛøËöŸa˜À±¿‰gY6p,P옊—bÖ3®.— ¹Ê^¢!rƒøž÷q9Žã¯Jœ‘b릒‘ÿb¶Œ¢‚Ð5*¨L"*Áívûø³+Ù¾]}ƒû¥}ý}ÇÏ®d£ŽFþ)±1›ÍÎ#ò½àsu¹–——3™5ÿˆ$®$–––/>”ÛӾѾ¼¼Ü»«wØ;¼ºÑësmUx{1óçcÑØÒÒRø|¸Ø1;/5´ò劫Ëåóú*mÈÿ+ÿââbüŸñ¥ÿ»”L&Kœ‘bëQ€1„l6+$Áð—ü5””hZ%ä jQÁ¹¡Ÿ«©E±¹¹YEB¿‰÷>ëõìô8ïq’õ«;(n”0 #o‚ÛÈÅÿçy^„¶¶6é%†a–——9Ž#7sÛêþ<ÏÇb1žçÅëbÛÝm©TªØÛ‹afii‰çùÜÅc*v^Þó;ÎÔÕTÞ¹äýœßÐ&>‰:îuÈû£¾uÅ Jcã®.Wùý!„¸~èfnc<Á?”Ükõ>]û•ˆ÷ /x"|õTÑŒuQAÁü%KG:AT Eå­+OÉ«¥¹ósÎv'Ã0MMM¹;ôs³s Û~º½ƒ •ب(}--  åÃhBÇq„ùÈ8™L¶µµ1 ÓtGS:.ýöbòvS<¦bçå ¥¯¥+nè‹d^TPQëD@7åì½r`@]T`, £—!RF¤“üìÙ»gìèXöëìÊ—+¹vμ;#|.Ìý~Î÷‚¯ÄFEö»4e?7q¿˜ÖÖÖ•••ì7ro—nÞ—}»úc*vÞn¿Õ½Å~ë7!Dz©tC¹ª ­˜—B`@cTP+¨_º A£³¶nlº€Â‹¡ˆL&÷ðbFÍmì{¬/þQœÜ ©tÊf³•بȳÃ<EqêÕ©Ò­÷îÂçÂÀÞÕ·o÷OEQ žj8#Åc*vÞ½Ý=q|BjÈÝí–6¶ß×z+¤¦õÁ'‡ ‚ ^suÒê[— Æ(V´ØÏlÅÇ€ÒPaò7“=ô´ÝÝæ¸ëÖ¬˜þÝý>ö(ÓÄŒ¾4:}nºÄÆÜ’Dòµ‰/¢ ÑæææÒñ!$0® Íw6wº:Ý?^š‚ð…pss³m– Fñ˜ŠŸ NF/F›îhŠ^ŒN'¥Ç÷½àkkkslΟ&”gü×ã›ïÝìt:›Ûšív{¥­ЭÔ kŠ#ŠÔ4ÐtÖÒ¥ˆ ŒBÛ• ºø¸R©Ô–-[¤\¨Š ¢‚›¤ý ÅÇ·ÐtÖÒQNPZÐ ú«ôö‰×ÅÐë¡Ü]s0«›ùÊ/hºGkõ¨ÀÀ‚c+ç }ƒqŸFkKks[sû=í3³3ÕMq">Öó¨µé‚‚¨€”©1@® µ"*0 …ƒq¤ŒAìRÌá(3S_¬’ê keÔD¤T``ÂÑèÏè/Q€žŠD¤èÀ‡²Ñ'­ž~¥–÷6îÅ–¡*W QhX6*h\ºN"ª,Nº†ÑŸF^I¦ýP¯‚¨€?Öȃ‚c9,Nj Ê[·B®Á€y”zd¢‚:ÆKG:AT M:(—. ùM£1«G.C¤Œþ H'´] :­I¥ n#ǬgÇøKãä†Ñ½•TD¤Ìr¥õDÍЇ 4Ehõ‡Ò:e³ÙÔÕTöFvî÷s‘‹‘!ïÑ=ÔE„–À  WP×eˆ(¼C¬L"ª˜¦‹Áf†‹¡4æ*÷w>àœ97sö³5íÔ÷f)èB¥("$Ђ¶øÔïOCKI± ÿl,Gu®@btÆË (æÒ×¥¾Çúb—bä>öÿbÿãýF÷ôdh`€¨@N§S¤ ê†òÄ‘îŽ^MäŽ&ý ã1ªçÚêV³Ã0Ù¯5þ'L§©D¥õ®.  J ŒBaT€Ò‚êDæ#®­®ÒûT:‚/}Ìl6[Ÿ r!âÞîfÖ3Ç ìH]MIÛ}Ïû8Žã8Î÷¼/·³âF°šÄgñÒÿ ¾µx`¥é¢O``ì@°òÖm4ÎYCû³¬Z¯íéæ7†¨@N¨ ®ß}ü/úÇ_§ÿ˜_ úûW¾\¹|ù²c³£ï±>BÈÔÉ©èB4ÇãñèBtêÔT±º«:00¶´äŒž†‚ã5ŒÍÜ ¾ç}ÜFŽã¸À+i› ®.³žqu¹A62 Ãmä|‡}®.—ÿE‰‰DBºÃíîv'‰Üž¡Ó!Žã¸ÜÜ{sò†X–õñWs‘ù!Äݽš9õñ³,Ûù`§¼óù»»¤xÌÈ…ˆó'³žá7ñ¡³¡=¯‹}»úV[ÿ\(±‘a©ŸòYÑÜù9÷v7˲Çürdþ/ó„Ð[¡À±Ïó<ÏŸ~kºØFÝé¼*‘¥ Ž5¥/ a‘^ Zè–+ðÿÊ¿¸¸ÿg|éÿ.%“Ii£Ïësmu­|¹âêrù¼·f¤&ÁãÁÁ'å#ÎÂn·ÛÄŸ]ÉöíêÜ7˜Û3q%±´´x9pèð!yCËËË™L&¯cyƒø2g±öÖ~æffyyÙÝíÎu¾Ø´ŸÂ.)³¯¿ïøÑãÙ•lôÏÑÈŸ"%zâ{Ágßh_^^îÝÕ;ì.±1×O×V—ïUÓ~Äëbðx°ûánBÈâ'‹ßí¶w}¿ëÒ¿.Û ;†’Íf…D"x"±—™Ë›O-CT`Ú®¢[`PÂÙ_l+1žßÄG#QǽùFn#ÿgœçyAœßqJ“Ú†YYYijjZYYiº£){#[lcŽ(ŠÍÍÍ¢(J{.//sGnæ¶Õ"`yCmmmò~ª/ŽÌGü/ú££¹7.--åu^ñ˜Š]R<&¿‰÷>ëõìô8ïq’õkZÏ;&Ïó±XŒçyñºØvw[*•*¶±D?I‘Rkkk4u8¹v][]Ñ‹QéWÅj>Chcã¾ÃþÄgqBˆÿWçÞ9'µÿñþñ_B"óóû1œý:ËÜÆt¿ü;5Gîü"â=è ž_=UEÆÀÀ¨ qK ôkÚ2ºh‹ 4&ŽòëJªìaò‹d^T@I_Kó}-}«m–]ýÿ›¤ÄƹósÎv'Ã0MMMòTÇq„ùÀZÞP^Ôh +;¯¨°KŠÇœ›[XXØöÓmìlèt©©DÉd²­­a˜¦;šÒét‰õ“’Íf———Ÿ>0L±m°‰×EBHôbT¼.Ú6ØŠmËÿõH÷»s¿vÿ¸[Š ª§50Àlr9ê>ºŽPZ@¡ÖÖÖ\@ŽÝn—n` ‚`o±WzÌ={÷ŒË~]ùr¥ôžö–[ UÚŠ$¯º@"3u5¥¡óŠÇì|°sæÝásaî÷s¥§ý´¶¶®¬¬d¿Qb£†~J5Ò\¦öûÚ/ýcu¦ÐÂß:îï(¶¬lòd ãþvBHÇýí“'zVS``àâ¤ZçñSž+ :§ êÇàeˆ$q¤ÿ2DƒOA¼.æ*€ÝÛÝÇ'DQ žæ¹ÕÈd2| /fÄѱÑÒ{z¶{‚'‚RCy/©¬1P\8(×yÏún—8fßc}ñâäI¥S6ÛšO}óæÍ¹G„Þݽ£#£âuQø\Ø;Pbãš~n/ÕϾ]}±cäI]Mþj´ýþvBÈàƒ¾#>AAðñ<1Pl#Xk³9{¦ëá®3gϰ6݆6:Ó‰¾`>“N"B®` šY0þëñÍ÷nv:ÍmÍvûê}ëÉàdôb´éަèÅèdp²ÒcNþf²ç‘ž¶»ÛwåORÊÂÂÍÍͶuZ®FÅt¤¹¹92 ¼¼zk$·$QáÚDjŽÙ¿»ÿÑÇeš˜Ñ—F§Ï­Yêg|b|›g[€pMh¾³¹ÓÕéþ±»ÄÆ\?ÃÂ`©[8ý{û÷ØÏ41[¾µ%q%17;GznÈõ kË·¶lùÖW—kèÀP±`qœÝ>}ö g×’E/¦Ââcc'¥-W@,]Z€G¬¡ST ¾“¥‹M͵Õ5þÒ¸†œF©•ÁP òâãª,>®d8ƒ¨ ¢Ô=*hlò9<4 Á¨Ñ *ȃ‘±Q(¼ô@ÀX‘ùùš_ãð–þÇÓ W …QAíY&‚yDP#=$TuÅÇ& BjШ 4ßAöë¬ÊÿinEŸ“ˆä° ä˜+XG!cù z@ãñô'®”);ÖèæšßÊ mÔ¢-h»舑|‡ýjvÃR9ê1 óÁŸß¯u+®­ªÖÊcÆwPÕî«WÙèÆÒQrj‹A§eˆÖ¶®få2•{@­ |åÔÿG¼&næo(>ÀXi ÂIDATA® TLkÓ‰ ´(ˆ ˆú'[=* n4Fd$ú>ºFÑ…m‡£ŒMÔ¯1¥¨€ ÖŽ?è j‹ÆIDub[g¾tý!b £‚›$|aþÒ¿[[xm€!ξunðÀ°˜ÉÔ¼¥"QQ (š—Cß¼‘|&Dd:TFuZœTÌdfÞ '®$!,ÇÕ§QÐËüÿ™ß³wO*6ªJ jÀ¤QÁ¹‚Ê[7ETP»tÁü|$y-©íð@ƒKÿX~ÞW«£ß,•. ù¢‚<>áXýAPƒ¢>* „tw»w9´µ4èønûä+£Z/U|Œ¨ zÚs ­×5W€ÒÝÕz"ÖfëÝá鸯][;`¬îŸt¿ýæÛœÝ^“£—ÌHŠ:êPÈ„… ‚¨ÀÀ'W(CDWw—«Í?(P3ûžè÷ŽÛ:Æ¿´Í(°F]¡ïJ †FÚš¾I:ïoS)mm€!j¨ÈH'¬`¶‹Á uÅ$¯ U½ƒê¨€`œÏÚ‹“œ.MÔ?,½žÏx€²hûOóš‘`½ë äq>D£íJ ¦I0 £ûžPõøOs%ébdÆ€¶± ¢¨V½£ßA¿ï _[#`¬ì×ÙÚ6PaT@ h‹ hd™¨€¶‹Á$¹BHè)m2bHHÛ@Й.€¢èëVp¼ÿÃÚšÊe³ÙÐé) ÿ­Ïf³ÚF“ÒX#]Ð8!¢®·®ÐåO?6°u¨µºý·¾Ô“k‚¶± ¢È1Ï$"ÝÕ70 -*Ð ¢-h»€µÕq<Ò Á|ˆ ´h‹Á¸Çè­îS‰ ¢-h‹  N·+)êqÞˆ ´ íbhÐD[¾õméÛ›ã.G÷Ö®Á§9»½Ví€ùY2c€ÉFÁ'_G—?ýøò§ÿ=úÁñcc™Lf›§GH&îÔã^g5o¯q`°NËXÐFãâ|HTLk®€¾‹!¿´@K5ýihÀÚlÎûÚý£#ý»ûƒÇ‚ÒFñfÆ72êìüž³ó{þ‘QñfFÚ¾å[ßž~çœëGÛ¶8¿ÝóÈ£ñOsÇ vþà!çw¾7üÜ!1“©G× Ž{¡ÓU=üÔ’ƒª!*Óx¼/òרôsðøTêªðAäýþø~B‚'ný#²°pifvúãØß=Û»•6N½6ué£Å¹ßÏüý>°Ùlÿ4à ¸ê£RÛÀ€ÂÙä(-0Jƒ\ ¬yW"â[ZÓé´ôóì{³þ##œÝεØÇ_ ¿;›ÛmìèßÒÊÚlûž\ü×jÆ`úÙñ—FøÖVÖf9ì _pPD.*pwwWsºî!Ó¿òŒ®O¸¥ÿtuB×U¦E„áZÒþMñqúZÚ±Ù!ýìØìH^Kçvã6¬îÃÚn_2™Üöӟ׫§P½¢R«A m·‡‰ÑcS£GÆf,-¨í…Ys’éwfÜ»¤Ÿí-öÄIÇ]­„Ä•„½¥ÌjE­­­3³Ó|KkÍ{ •È‹ ÷:ŸÅ5Í5:Í Ò’.Pž²RÛ’Ú5-­CT  ³Fb&ÿdq|lâÜoÏyŸ÷J{wzÆ_ò§ÒéT:íi¢wgoéƒ <>à?â¾HBâÿN ?w¨æý€r £‚*Ë j0T¡m,hôÝzë¢íJ º=µÀ¤GØl6ÇæÖ®­î÷Ãs¹çxzGÇ&úÑ6Bˆg§Ç{p¨ô¡†žÙ7õéëH^KnÞ¼Ù÷l™ý Öt ˆþ£fÚÆ‚Ô-NZ×»áX†h ŸeV÷/âò§—x•µÙc‰±Òï’ÿ:ô̾¡göéØCЬXTPe™®S‰h‹ t¢ë2DõƒeˆÖÐéÓ ÿr€ÆV£¨€èP8Äâ¤F¡íbÐÈÄ‹“@C*Ðýäc0¢‚|š€ù• *-3ȬýUSƒµœ]Z`¤Æ¹+ŠèªzäÒ8Á†h,ȃ¨ÌOeTðÿ·w÷¸mÃ`Çi z”ž¡çzˆ(P4ê’!ÖL‰Ñ¥C/ÐÝbÀ\4‘MK$ý’ïCëÿ›ÒÀ‘(J.ßGÔGúmϱ_^\ñ"÷¢° [ Ô8¦;¿ý|[ôOÿ³Øy…¤ÚbRµ#!x¿² Õ¾ØívÖ<Ôë£Óá¬úE°´`ú.+ýͽPޝ,(_{¶‡ÇõÃãºÑÊ€ó±þT*å%Œ`*àá¤^ÔßW4ÜÃÝÐne «Õ*úû‰T «Á Ù›´j© \7÷öÁàöþv¸j,h<ìN§‚в?ClýzãF¥/s‡o-h¸/$“Ð5› BÉ ÎkA9ËØ\ÁYß[ z–YI©¥CÔ½ƒ¡³Ž¹dJ™.yå ©`~í‹Iùk׿‚¨¼…¤ *1„ŒK‰ÔRRA‰g**"Ué© ¤5‚©Àñ†ã¸ÅÔlj¯ ºþt]cE§pÌUv³RAèõÜï²Ï—÷xk¸SÁçOíVŸhÜ!'‚wø®äš¦y÷Di€ÉâcƒÎ6¡Ÿi"w°Œ0Úƒ–ì½D–·9øŒw·G7)úe)j¹Yß–±éíÙVüoÏUxŸvjôùèšYòy"[juÄ-§°W·%—Ô‰2ß͹Áª´ôÑ;C|ˆ‹ˆ²¹W6Ç|o-p¤ÚC*qÿî´L³ÍðÿlÊ,µT[XZMç*V®EÍîRÙá±1û`;þÙp!Lrü–mfþãJ *a®`Äñ•åk/ÑetѦŸ *«ÙÞu?ö"åˆü®‰×1Ý¥#û³õ•rlÊT@Ë>ì`]USÒwsrÈr?ËU© ÛåLõk`•ÙÛD]¨9]`µìÌ‹ˆ?P“ý%ç±,†^æ> Tyü3nÒ…¤»¹›…Mš›4HíC‹í­»¿löH© ¸WGÇÅÇ?ëó›âôÏ&ê·âLŸ®Ñ‚aƒ»Ûv@Çk0øþíÆ±]…n¾~ñnpôáé/¦pD1#–…IEND®B`‚oar-2.5.7/sources/api/api_html_postform_resources.pl0000644015014700017500000000071012677211234022335 0ustar neyronneyron$POSTFORM="
Resources generation
Resources
Properties (commas separated)
" oar-2.5.7/sources/api/oarapi.pl0000755015014700017500000027123012677211234016002 0ustar neyronneyron#!/usr/bin/perl -w # vim: set foldmethod=marker:syntax: # # # This is the main cgi script for the OAR REST API # This script is part of the OAR project. # # Please, make a good usage of folding markers: {{{ and }}} # into comments. Under vim, use "za" to fold and "zo" to # unfold (or just go inside the title to automatically unfold) # You have to ":set modeline" into vim for the above modeline # to be interpreted by vim or just type the :set command given # by this modeline. # # Copyright (C) 2009-2016 Laboratoire d'Informatique de Grenoble # # 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 # use strict; use DBI(); use OAR::API; use OAR::Conf qw(init_conf dump_conf get_conf_list get_conf is_conf set_value); use OAR::IO; use OAR::Stat; use OAR::Nodes; use OAR::Tools; use OAR::Version; use POSIX; use JSON; use IO::Handle; use File::Temp qw/ tempfile /; use File::Basename; use CGI::Fast qw/ standard /; use File::Listing qw(parse_dir); #use Data::Dumper; my $VERSION="1.0.2"; ############################################################################## # CONFIGURATION AND INITIALIZATION STUFF ############################################################################## # Load config my $oardir; my $config_file; if (defined($ENV{OARDIR})){ $oardir = $ENV{OARDIR}."/"; }else{ die("ERROR: OARDIR env variable must be defined.\n"); } if (defined($ENV{OARCONFFILE})){ init_conf($ENV{OARCONFFILE}); $config_file=$ENV{OARCONFFILE}; }else{ init_conf("/etc/oar/oar.conf"); $config_file="/etc/oar/oar.conf"; } # Oar commands my $OARSUB_CMD = "oarsub"; my $OARDEL_CMD = "oardel"; my $OARHOLD_CMD = "oarhold"; my $OARRESUME_CMD = "oarresume"; my $OARNODES_CMD = "oarnodes"; my $OARDODO_CMD = "$ENV{OARDIR}/oardodo/oardodo"; # Oar admin command (for new list of resources generation) my $API_RESOURCES_LIST_GENERATION_CMD = ""; if (is_conf("API_RESOURCES_LIST_GENERATION_CMD")){ $API_RESOURCES_LIST_GENERATION_CMD = get_conf("API_RESOURCES_LIST_GENERATION_CMD"); } # OAR server my $remote_host = get_conf("SERVER_HOSTNAME"); my $remote_port = get_conf("SERVER_PORT"); my $stageout_dir = get_conf("STAGEOUT_DIR"); my $stagein_dir = get_conf("STAGEIN_DIR"); my $allow_create_node = get_conf("DESKTOP_COMPUTING_ALLOW_CREATE_NODE"); my $expiry = get_conf("DESKTOP_COMPUTING_EXPIRY"); # Enable this if you are ok with a simple pidentd "authentication" # Not very secure, but useful for testing (no need for login/password) # or in the case you fully trust the client hosts (with an apropriate # ip-based access control into apache for example) my $TRUST_IDENT = 1; if (is_conf("API_TRUST_IDENT")){ $TRUST_IDENT = get_conf("API_TRUST_IDENT"); } # Default data structure variant my $STRUCTURE="simple"; if (is_conf("API_DEFAULT_DATA_STRUCTURE")){ $STRUCTURE = get_conf("API_DEFAULT_DATA_STRUCTURE"); } my $DEFAULT_STRUCTURE=$STRUCTURE; # Get the default maximum number of items my $MAX_ITEMS=500; if (is_conf("API_DEFAULT_MAX_ITEMS_NUMBER")){ $MAX_ITEMS = get_conf("API_DEFAULT_MAX_ITEMS_NUMBER"); } # Relative/absolute uris config variable $OAR::API::ABSOLUTE_URIS=1; if (is_conf("API_ABSOLUTE_URIS")){ $OAR::API::ABSOLUTE_URIS=get_conf("API_ABSOLUTE_URIS"); } # TMP directory my $TMPDIR="/tmp"; if (defined($ENV{TMPDIR})) { $TMPDIR=$ENV{TMPDIR}; } # Load the html header file my $file; if (is_conf("API_HTML_HEADER")){ $file=get_conf("API_HTML_HEADER"); } else { $file="/etc/oar/api_html_header.pl"; } open(FILE,$file); my(@html_header_lines) = ; close(FILE); ############################################################################## # FastCGI loop starting ############################################################################## my $q; my $fcgi_cycle_count=0; FCGI: while ($q = new CGI::Fast) { $fcgi_cycle_count++; # Sets the cgi handler of the OAR::API (global variable) $OAR::API::q=$q; # Activate debug mode when the script name contains "debug" or when a # debug parameter is found. my $DEBUG_MODE=0; if ( $q->url(-relative=>1) =~ /.*debug.*/ ) { $DEBUG_MODE = 1; }; if ( defined( $q->param('debug') ) && $q->param('debug') eq "1" ) { $DEBUG_MODE = 1; } $OAR::API::DEBUG_MODE=$DEBUG_MODE; # Check a possible extension my $extension; if ( $q->path_info =~ /^$/ ) { $extension = "html"; } elsif ( $q->path_info =~ /.*\.(yaml|json|html|tgz|tar\.gz)$/ ) { $extension = $1; }; $extension=OAR::API::set_ext($q,$extension); $OAR::API::extension=$extension; # Base uri of the api my $apiuri=OAR::API::get_api_uri_relative_base(); $apiuri =~ s/\/$//; $OAR::API::apiuri=$apiuri; # Header for html version my $HTML_HEADER=""; eval join("\n",@html_header_lines); $OAR::API::HTML_HEADER=$HTML_HEADER; ############################################################################## # Authentication ############################################################################## my $authenticated_user = ""; if ( defined( $ENV{AUTHENTICATE_UID} ) && $ENV{AUTHENTICATE_UID} ne "" ) { $authenticated_user = $ENV{AUTHENTICATE_UID}; } else { # Get ident id from headers or from environement if not in the headers my $remote_ident=""; if (defined($q->http('X_REMOTE_IDENT'))) { $remote_ident=$q->http('X_REMOTE_IDENT'); }elsif (defined($ENV{X_REMOTE_IDENT})) { $remote_ident=$ENV{X_REMOTE_IDENT}; } if ( $TRUST_IDENT && $remote_ident ne "" && $remote_ident ne "unknown" && $remote_ident ne "(null)" ) { $authenticated_user = $remote_ident; } } ############################################################################## # URI prefix header variable ############################################################################## if (defined( $q->http('HTTP_X_API_PATH_PREFIX') ) ) { $OAR::API::HTTP_X_API_PATH_PREFIX=$q->http('HTTP_X_API_PATH_PREFIX'); }elsif (defined($ENV{X_API_PATH_PREFIX})) { $OAR::API::HTTP_X_API_PATH_PREFIX=$ENV{X_API_PATH_PREFIX}; }else{ $OAR::API::HTTP_X_API_PATH_PREFIX=""; } ############################################################################## # Data structure variants ############################################################################## $STRUCTURE=$DEFAULT_STRUCTURE; if (defined $q->param('structure')) { $STRUCTURE=$q->param('structure'); } if ($STRUCTURE ne "oar" && $STRUCTURE ne "simple") { OAR::API::ERROR 406, "Unknown $STRUCTURE format", "Unknown $STRUCTURE format for data structure"; last FCGI; } ############################################################################## # URI management ############################################################################## SWITCH: for ($q) { my $URI; ########################################### # API informations ########################################### # #{{{ GET /: Root links # $URI = qr{^\/*\.*(yaml|json|html)*$}; OAR::API::GET( $_, $URI ) && do { $_->path_info =~ m/$URI/; my $ext = OAR::API::set_ext($q,$1); (my $header, my $type)=OAR::API::set_output_format($ext); my $root={ "oar_version" => OAR::Version::get_version(), "api_version" => $VERSION, "apilib_version" => OAR::API::get_version(), "api_timestamp" => time(), "api_timezone" => strftime("%Z", localtime()), "links" => [ { 'rel' => 'self' , 'href' => OAR::API::htmlize_uri(OAR::API::make_uri("./",$ext,0),$ext) }, { 'rel' => 'collection', 'href' => OAR::API::htmlize_uri(OAR::API::make_uri("resources",$ext,0),$ext), 'title' => 'resources' } , { 'rel' => 'collection', 'href' => OAR::API::htmlize_uri(OAR::API::make_uri("resources/details",$ext,0),$ext), 'title' => 'full_resources' } , { 'rel' => 'collection', 'href' => OAR::API::htmlize_uri(OAR::API::make_uri("jobs",$ext,0),$ext), 'title' => 'jobs' } , { 'rel' => 'collection', 'href' => OAR::API::htmlize_uri(OAR::API::make_uri("jobs/details",$ext,0),$ext), 'title' => 'detailed_jobs' } , { 'rel' => 'collection', 'href' => OAR::API::htmlize_uri(OAR::API::make_uri("jobs/table",$ext,0),$ext), 'title' => 'jobs_table' } , { 'rel' => 'collection', 'href' => OAR::API::htmlize_uri(OAR::API::make_uri("config",$ext,0),$ext), 'title' => 'config' } , { 'rel' => 'collection', 'href' => OAR::API::htmlize_uri(OAR::API::make_uri("admission_rules",$ext,0),$ext), 'title' => 'admission_rules' } ] }; print $header; print $HTML_HEADER if ($ext eq "html"); print OAR::API::export($root,$ext); last; }; #}}} # #{{{ GET /version : Version informations # $URI = qr{^/version\.*(yaml|json|html)*$}; OAR::API::GET( $_, $URI ) && do { $_->path_info =~ m/$URI/; my $ext = OAR::API::set_ext($q,$1); (my $header, my $type)=OAR::API::set_output_format($ext); my $version={ "oar_version" => OAR::Version::get_version(), "apilib_version" => OAR::API::get_version(), "api_timestamp" => time(), "api_timezone" => strftime("%Z", localtime()), "api_version" => $VERSION }; print $header; print $HTML_HEADER if ($ext eq "html"); print OAR::API::export($version,$ext); last; }; #}}} # #{{{ GET /whoami : Authenticated User informations # $URI = qr{^/whoami\.*(yaml|json|html)*$}; OAR::API::GET( $_, $URI ) && do { $_->path_info =~ m/$URI/; my $ext = OAR::API::set_ext($q,$1); (my $header, my $type)=OAR::API::set_output_format($ext); my $version={ "api_timestamp" => time(), "authenticated_user" => $authenticated_user }; print $header; print $HTML_HEADER if ($ext eq "html"); print OAR::API::export($version,$ext); last; }; #}}} # #{{{ GET /timezone: Timezone information # $URI = qr{^/timezone\.*(yaml|json|html)*$}; OAR::API::GET( $_, $URI ) && do { $_->path_info =~ m/$URI/; my $ext = OAR::API::set_ext($q,$1); (my $header, my $type)=OAR::API::set_output_format($ext); my $version={ "api_timestamp" => time(), "timezone" => strftime("%Z", localtime()) }; print $header; print $HTML_HEADER if ($ext eq "html"); print OAR::API::export($version,$ext); last; }; #}}} ########################################### # Jobs ########################################### # #{{{ GET /jobs[/details|table]?state=,from=,to=,ids= : List of jobs # $URI = qr{^/jobs(/details|/table)*\.*(yaml|json|html)*$}; OAR::API::GET( $_, $URI ) && do { $_->path_info =~ m/$URI/; my $ext=OAR::API::set_ext($q,$2); my $header ; my $type; my $more_infos=$1; if (!defined($more_infos)) { ($header,$type)=OAR::API::set_output_format($ext,"GET, POST"); }else{ ($header,$type)=OAR::API::set_output_format($ext); } # Get the id of the user as more details may be obtained for her jobs if ( $authenticated_user =~ /(\w+)/ ) { $authenticated_user = $1; $ENV{OARDO_USER} = $authenticated_user; } OAR::Stat::open_db_connection or OAR::API::ERROR(500, "Cannot connect to the database", "Cannot connect to the database" ); # default parameters for the parameters my $JOBS_URI_DEFAULT_PARAMS = "state=Finishing,Running,Resuming,Suspended,Launching,toLaunch,Waiting,toAckReservation,Hold"; if (is_conf("API_JOBS_URI_DEFAULT_PARAMS")){ $JOBS_URI_DEFAULT_PARAMS = get_conf("API_JOBS_URI_DEFAULT_PARAMS"); } # query string parameters my $from = $q->param('from'); my $to = $q->param('to'); my $state = $q->param('state'); my $user = $q->param('user'); my $array = $q->param('array'); my $max_items = $MAX_ITEMS; my @ids; if (!defined($q->param('from')) && !defined($q->param('to')) && !defined($q->param('state')) && !defined($q->param('array')) && !defined($q->param('ids'))) { my $param = qr{.*from=(.*?)(&|$)}; if ($JOBS_URI_DEFAULT_PARAMS =~ m/$param/) { $from = $1; } $param = qr{.*to=(.*?)(&|$)}; if ($JOBS_URI_DEFAULT_PARAMS =~ m/$param/) { $to = $1; } $param = qr{.*state=(.*?)(&|$)}; if ($JOBS_URI_DEFAULT_PARAMS =~ m/$param/) { $state = $1; } } if (!defined($array)) { $array=""; }; # GET max items from configuration parameter if (!defined($q->param('from')) && !defined($q->param('to')) && !defined($q->param('state')) && !defined($q->param('limit'))) { # get limit from defaut url my $param = qr{.*limit=(.*?)(&|$)}; if ($JOBS_URI_DEFAULT_PARAMS =~ m/$param/) { $max_items = $1; } } # GET max items from uri parameter if (defined($q->param('limit'))) { $max_items = $q->param('limit'); } # set offset / GET offset from uri parameter my $offset = 0; if (defined($q->param('offset'))) { $offset = $q->param('offset'); } # Construct ids array if any if (defined($q->param('ids'))) { @ids=split(':',$q->param('ids')); } # Get the requested user jobs my $jobs = OAR::Stat::get_jobs_for_user_query($user,$from,$to,$state,$max_items,$offset,$array,\@ids); my $total_jobs = OAR::Stat::count_jobs_for_user_query($user,$from,$to,$state,$array,\@ids); if ( !defined $jobs || keys %$jobs == 0 ) { $jobs = OAR::API::struct_empty($STRUCTURE); } else { $jobs = OAR::API::struct_job_list_hash_to_array($jobs); OAR::API::add_joblist_uris($jobs,$ext); if (defined($more_infos)) { if ($more_infos eq "/details") { # will be useful for cigri and behaves as a oarstat -D # Warning: it's a kind of all in one query and may result in a lot of # SQL queries. Maybe to optimize... my $detailed_jobs; foreach my $j (@$jobs) { my $job_resources = OAR::Stat::get_job_resources($j); $j = OAR::Stat::get_job_data($j,1); my $resources = OAR::API::struct_job_resources($job_resources,$STRUCTURE); my $nodes= OAR::API::struct_job_nodes($job_resources,$STRUCTURE); OAR::API::add_resources_uris($resources,$ext,''); $j->{'resources'}=$resources; OAR::API::add_nodes_uris($nodes,$ext,''); $j->{'nodes'}=$nodes; $j = OAR::API::struct_job($j,$STRUCTURE); OAR::API::add_job_uris($j,$ext); push(@$detailed_jobs,$j); } $jobs = $detailed_jobs; } } else { $jobs = OAR::API::struct_job_list($jobs,$STRUCTURE); } } OAR::Stat::close_db_connection(); # add pagination informations $jobs = OAR::API::add_pagination($jobs,$total_jobs,$q->path_info,$q->query_string,$ext,$max_items,$offset,$STRUCTURE); print $header; print $HTML_HEADER if ($ext eq "html"); print OAR::API::export($jobs,$ext); last; }; #}}} # #{{{ GET /jobs/[/details] : Infos of a job. Adding /details results in a "oarstat -f" equivalent # $URI = qr{^/jobs/(\d+)(/details)*(\.yaml|\.json|\.html)*$}; OAR::API::GET( $_, $URI ) && do { $_->path_info =~ m/$URI/; my $jobid = $1; my $details = $2; my $ext=OAR::API::set_ext($q,$3); (my $header, my $type)=OAR::API::set_output_format($ext,"GET, POST, DELETE"); # Must be authenticated if ( not $authenticated_user =~ /(\w+)/ ) { OAR::API::ERROR( 401, "Permission denied", "A suitable authentication must be done before looking at jobs" ); last; } $authenticated_user = $1; $ENV{OARDO_USER} = $authenticated_user; OAR::Stat::open_db_connection or OAR::API::ERROR(500, "Cannot connect to the database", "Cannot connect to the database" ); my $job = OAR::Stat::get_specific_jobs([$jobid]); if (@$job == 0 ) { OAR::Stat::close_db_connection; OAR::API::ERROR( 404, "Job not found", "Job not found" ); last; } my $j=OAR::Stat::get_job_data(@$job[0],1); if (defined($details) and $details eq "/details") { my $job_resources = OAR::Stat::get_job_resources(@$job[0]); my $resources = OAR::API::struct_job_resources($job_resources,$STRUCTURE); my $nodes= OAR::API::struct_job_nodes($job_resources,$STRUCTURE); OAR::API::add_resources_uris($resources,$ext,''); $j->{'resources'}=$resources; OAR::API::add_nodes_uris($nodes,$ext,''); $j->{'nodes'}=$nodes; } my $result = OAR::API::struct_job($j,$STRUCTURE); OAR::API::add_job_uris($result,$ext); OAR::Stat::close_db_connection; print $header; if ($ext eq "html") { OAR::API::job_html_header($j); }; print OAR::API::export($result,$ext); last; }; #}}} # #{{{ GET /jobs//[resources|nodes] : Resources or nodes assigned or scheduled to a job # $URI = qr{^/jobs/(\d+)/(resources|nodes)(\.yaml|\.json|\.html)*$}; OAR::API::GET( $_, $URI ) && do { $_->path_info =~ m/$URI/; my $jobid = $1; my $item = $2; my $ext=OAR::API::set_ext($q,$3); (my $header, my $type)=OAR::API::set_output_format($ext); OAR::Stat::open_db_connection or OAR::API::ERROR(500, "Cannot connect to the database", "Cannot connect to the database" ); my $job = OAR::Stat::get_specific_jobs([$jobid]); my $resources=OAR::Stat::get_job_resources(@$job[0]); if ($item eq "resources") { $resources = OAR::API::struct_job_resources($resources,$STRUCTURE); OAR::API::add_resources_uris($resources,$ext,''); }else{ $resources = OAR::API::struct_job_nodes($resources,$STRUCTURE); OAR::API::add_nodes_uris($resources,$ext,''); } $resources = OAR::API::add_pagination($resources,@$resources,$q->path_info,undef,$ext,0,0,$STRUCTURE); print $header; print $HTML_HEADER if ($ext eq "html"); print OAR::API::export($resources,$ext); OAR::Stat::close_db_connection; last; }; #}}} # #{{{ POST /jobs/[array/]/checkpoints|deletions|holds|rholds|resumptions|resubmissions/new : Actions on a job (checkpoint, hold, resume,...) # $URI = qr{^/jobs/(array/|)(\d+)/(checkpoints|deletions|holds|rholds|resumptions|resubmissions)+/new(\.yaml|\.json|\.html)*$}; OAR::API::POST( $_, $URI ) && do { $_->path_info =~ m/$URI/; my $array = $1; my $jobid = $2; my $action = $3; my $ext=OAR::API::set_ext($q,$4); (my $header, my $type)=OAR::API::set_output_format($ext,"GET, POST"); # Must be authenticated if ( not $authenticated_user =~ /(\w+)/ ) { OAR::API::ERROR( 401, "Permission denied", "A suitable authentication must be done before modifying jobs" ); last; } $authenticated_user = $1; $ENV{OARDO_BECOME_USER} = $authenticated_user; if ($array eq "array/") { $array="--array"; } # Delete (alternative way to DELETE request, for html forms) my $cmd; my $status; if ($action eq "deletions" ) { $cmd = "$OARDODO_CMD $OARDEL_CMD $array $jobid"; $status = "Delete request registered"; } # Checkpoint elsif ( $action eq "checkpoints" ) { $cmd = "$OARDODO_CMD $OARDEL_CMD $array -c $jobid"; $status = "Checkpoint request registered"; } # Hold elsif ( $action eq "holds" ) { $cmd = "$OARDODO_CMD $OARHOLD_CMD $array $jobid"; $status = "Hold request registered"; } # Hold a running job elsif ( $action eq "rholds" ) { $cmd = "$OARDODO_CMD $OARHOLD_CMD $array -r $jobid"; $status = "Hold request registered"; } # Resume elsif ( $action eq "resumptions" ) { $cmd = "$OARDODO_CMD $OARRESUME_CMD $array $jobid"; $status = "Resume request registered"; } # Resubmit elsif ( $action eq "resubmissions" ) { $cmd = "$OARDODO_CMD $OARSUB_CMD $array --resubmit $jobid"; $status = "Resubmit request registered"; } # Impossible to get here! else { OAR::API::ERROR(400,"Bad query","Could not understand ". $action ." method"); last; } my $cmdRes = OAR::API::send_cmd($cmd,"Oar"); # Resubmit case (it is a oarsub and we have to catch the new job_id) if ($action eq "resubmissions" ) { if ( $? != 0 ) { my $err = $? >> 8; OAR::API::ERROR( 500, "Oar server error", "Oarsub command exited with status $err: $cmdRes\nCmd:\n$cmd" ); } elsif ( $cmdRes =~ m/.*JOB_ID\s*=\s*(\d+).*/m ) { print $q->header( -status => 201, -type => "$type" ); print $HTML_HEADER if ($ext eq "html"); print OAR::API::export( { 'id' => int($1), 'links' => [ { 'rel' => 'self' , 'href' => OAR::API::htmlize_uri(OAR::API::make_uri("jobs/$1",$ext,0),$ext) }, { 'rel' => 'parent', 'href' => OAR::API::htmlize_uri(OAR::API::make_uri("jobs/$jobid",$ext,0),$ext) } ], 'status' => "submitted", 'cmd_output' => "$cmdRes", 'api_timestamp' => time() } , $ext ); }else { OAR::API::ERROR( 500, "Parse error", "Job submitted but the id could not be parsed.\nCmd:\n$cmd" ); } # Other cases }else{ print $q->header( -status => 202, -type => "$type" ); print $HTML_HEADER if ($ext eq "html"); print OAR::API::export( { 'id' => "$jobid", 'status' => "$status", 'cmd_output' => "$cmdRes", 'api_timestamp' => time(), 'links' => [ { 'rel' => 'self' , 'href' => OAR::API::htmlize_uri(OAR::API::make_uri("jobs/$jobid",$ext,0),$ext) } ] } , $ext ); } last; }; #}}} # #{{{ POST /jobs/ : Update of a job (delete, checkpoint, ...) # Should not be used unless for delete from an http browser # (better to use the URI above) # $URI = qr{^/jobs/(\d+)(\.yaml|\.json|\.html)*$}; OAR::API::POST( $_, $URI ) && do { $_->path_info =~ m/$URI/; my $jobid = $1; my $ext=OAR::API::set_ext($q,$2); (my $header, my $type)=OAR::API::set_output_format($ext,"GET, POST"); # Must be authenticated if ( not $authenticated_user =~ /(\w+)/ ) { OAR::API::ERROR( 401, "Permission denied", "A suitable authentication must be done before modifying jobs" ); last; } $authenticated_user = $1; $ENV{OARDO_BECOME_USER} = $authenticated_user; # Check and get the submitted data # From encoded data my $job; if ($q->param('POSTDATA')) { $job = OAR::API::check_job_update( $q->param('POSTDATA'), $q->content_type ); } # From html form else { $job = OAR::API::check_job_update( $q->Vars, $q->content_type ); } # Delete (alternative way to DELETE request, for html forms) my $cmd; my $status; if ( $job->{method} eq "delete" ) { $cmd = "$OARDODO_CMD $OARDEL_CMD $jobid"; $status = "Delete request registered"; } # Checkpoint elsif ( $job->{method} eq "checkpoint" ) { $cmd = "$OARDODO_CMD $OARDEL_CMD -c $jobid"; $status = "Checkpoint request registered"; } # Hold elsif ( $job->{method} eq "hold" ) { $cmd = "$OARDODO_CMD $OARHOLD_CMD $jobid"; $status = "Hold request registered"; } # Resume elsif ( $job->{method} eq "resume" ) { $cmd = "$OARDODO_CMD $OARRESUME_CMD $jobid"; $status = "Resume request registered"; } else { OAR::API::ERROR(400,"Bad query","Could not understand ". $job->{method} ." method"); last; } my $cmdRes = OAR::API::send_cmd($cmd,"Oar"); print $q->header( -status => 202, -type => "$type" ); print $HTML_HEADER if ($ext eq "html"); print OAR::API::export( { 'id' => "$jobid", 'status' => "$status", 'cmd_output' => "$cmdRes", 'api_timestamp' => time(), 'links' => [ { 'rel' => 'self' , 'href' => OAR::API::htmlize_uri(OAR::API::make_uri("jobs/$jobid",$ext,0),$ext) } ] } , $ext ); last; }; #}}} # #{{{ POST /jobs//signals/ : Signal sending # $URI = qr{^/jobs/(\d+)/signals/(\d+)(\.yaml|\.json|\.html)*$}; OAR::API::POST( $_, $URI ) && do { $_->path_info =~ m/$URI/; my $jobid = $1; my $signal = $2; my $ext=OAR::API::set_ext($q,$3); (my $header, my $type)=OAR::API::set_output_format($ext,"GET, POST"); # Must be authenticated if ( not $authenticated_user =~ /(\w+)/ ) { OAR::API::ERROR( 401, "Permission denied", "A suitable authentication must be done before modifying jobs" ); last; } $authenticated_user = $1; $ENV{OARDO_BECOME_USER} = $authenticated_user; my $cmd = "$OARDODO_CMD $OARDEL_CMD -s $signal $jobid"; my $status = "Signal sending request registered"; my $cmdRes = OAR::API::send_cmd($cmd,"Oar"); print $q->header( -status => 202, -type => "$type" ); print $HTML_HEADER if ($ext eq "html"); print OAR::API::export( { 'id' => "$jobid", 'status' => "$status", 'cmd_output' => "$cmdRes", 'api_timestamp' => time() } , $ext ); last; }; #}}} # #{{{ POST /jobs : A new job (oarsub wrapper) # $URI = qr{^/jobs\.*(yaml|json|html)*$}; OAR::API::POST( $_, $URI ) && do { $_->path_info =~ m/$URI/; my $ext=OAR::API::set_ext($q,$1); (my $header, my $type)=OAR::API::set_output_format($ext,"GET, POST"); # Must be authenticated if ( not $authenticated_user =~ /(\w+)/ ) { OAR::API::ERROR( 401, "Permission denied", "A suitable authentication must be done before posting jobs" ); last; } $authenticated_user = $1; $ENV{OARDO_BECOME_USER} = $authenticated_user; # Check and get the submitted job # From encoded data my $job; if ($q->param('POSTDATA')) { $job = OAR::API::check_job( $q->param('POSTDATA'), $q->content_type ); } # From html form else { $job = OAR::API::check_job( $q->Vars, $q->content_type ); } # Make the query (the hash is converted into a list of long options) my $oarcmd = "$OARSUB_CMD "; my $workdir = "~$authenticated_user"; my $command = ""; my $script = ""; my $param_file = ""; my $tmpfilename = ""; my $tmpparamfilename = ""; my @user_infos; # Alias resources=resource if (defined($job->{resources})) { $job->{resource} = $job->{resources} ; delete($job->{resources}); } # Options parsing foreach my $option ( keys( %{$job} ) ) { if ($option eq "script_path") { $job->{script_path} =~ s/(\\*)"/$1$1\\"/g; $command = " \"$job->{script_path}\""; # Expand ~ to home directory @user_infos=getpwnam($authenticated_user); $command =~ s|/~/|$user_infos[7]/|; } elsif ($option eq "command") { # Escapes double quotes $job->{command} =~ s/(\\*)"/$1$1\\"/g; $command = " \"$job->{command}\""; # Expand ~ to home directory @user_infos=getpwnam($authenticated_user); $command =~ s|/~/|$user_infos[7]/|; } elsif ($option eq "script") { $script = $job->{script}; # Expand ~ to home directory @user_infos=getpwnam($authenticated_user); $script =~ s|/~/|$user_infos[7]/|; } elsif ($option eq "param_file") { $param_file = $job->{param_file}; } elsif ($option eq "workdir") { $workdir = $job->{workdir}; # Expand ~ to home directory @user_infos=getpwnam($authenticated_user); $workdir =~ s|/~/|$user_infos[7]/|; } elsif (ref($job->{$option}) eq "ARRAY") { foreach my $elem (@{$job->{$option}}) { $oarcmd .= " --$option"; # Escapes double quotes $elem =~ s/(\\*)"/$1$1\\"/g; $oarcmd .= "=\"$elem\"" if $elem ne ""; } } else { $oarcmd .= " --$option"; # Escapes double quotes $job->{$option}=~ s/(\\*)"/$1$1\\"/g; $oarcmd .= "=\"$job->{$option}\"" if $job->{$option} ne ""; } } $oarcmd .= $command; # Escapes double quotes (one more time, for oardodo) $oarcmd =~ s/(\\*)"/$1$1\\"/g; my $cmd; # If a parameters file is provided, we create a temporary file # and write the parameters inside. if ($param_file ne "") { my $TMP; ($TMP, $tmpparamfilename) = tempfile( "oarapi.paramfile.XXXXX", DIR => $TMPDIR, UNLINK => 1 ); print $TMP $param_file; $oarcmd .= " --array-param-file=$tmpparamfilename"; } # If a script is provided, we create a file into the workdir and write # the script inside. if ($script ne "") { my $TMP; ($TMP, $tmpfilename) = tempfile( "oarapi.subscript.XXXXX", DIR => $TMPDIR, UNLINK => 1 ); print $TMP $script; # This is probably the most annoying thing about this trick: # the tmp file (owned by oar at this stage) has to be readable by the user. # So, the user should be warned that his script may be public. # We could make it owned by the user, with a OARDODO call, but it has a # performance cost. chmod 0755, $tmpfilename; $oarcmd .= " ./". basename($tmpfilename); $cmd = "$OARDODO_CMD bash --noprofile --norc -c \"cp $tmpfilename $workdir/ && cd $workdir && $oarcmd\""; }else{ $cmd = "$OARDODO_CMD bash --noprofile --norc -c \"cd $workdir && $oarcmd\""; } # Escapes some special characters (especially security fix with backquote) $cmd =~ s/(\\*)(`|\$)/$1$1\\$2/g; my $cmdRes = `$cmd 2>&1`; unlink $tmpfilename; unlink $tmpparamfilename; if ( $? != 0 ) { my $err = $? >> 8; # Error codes corresponding to an error into the user's request if ( $err == 6 || $err == 4 || $err == 5 || $err == 7 || $err == 17 || $err == 16 || $err == 6 || $err == 8 || $err == 10 ) { OAR::API::ERROR( 400, "Bad query", "Oarsub command exited with status $err: $cmdRes\nCmd:\n$oarcmd" ); }elsif( $err == 52) { OAR::API::ERROR( 401, "Permission denied", "Oardodo error: $err: $cmdRes\n" ); }else{ OAR::API::ERROR( 500, "Oar server error", "Oarsub command exited with status $err: $cmdRes\nCmd:\n$oarcmd" ); } } elsif ( $cmdRes =~ m/.*JOB_ID\s*=\s*(\d+).*/m ) { my $uri=OAR::API::htmlize_uri(OAR::API::make_uri("jobs/$1",$ext,0),$ext); my $abs_uri=OAR::API::make_uri("jobs/$1",$ext,1); print $q->header( -status => 201, -type => "$type" , -location => $abs_uri ); print $HTML_HEADER if ($ext eq "html"); print OAR::API::export( { 'id' => int($1), 'links' => [ { 'href' => $uri, 'rel' => "self"} ], 'api_timestamp' => time(), 'cmd_output' => "$cmdRes", } , $ext ); } else { OAR::API::ERROR( 500, "Parse error", "Job submitted but the id could not be parsed.\nCmd:\n$oarcmd" ); } last; }; #}}} # #{{{ DELETE /jobs/ : Delete a job (oardel wrapper) # $URI = qr{^/jobs/(\d+)(\.yaml|\.json|\.html)*$}; OAR::API::DELETE( $_, $URI ) && do { $_->path_info =~ m/$URI/; my $jobid = $1; my $ext=OAR::API::set_ext($q,$2); (my $header, my $type)=OAR::API::set_output_format($ext); # Must be authenticated if ( not $authenticated_user =~ /(\w+)/ ) { OAR::API::ERROR( 401, "Permission denied", "A suitable authentication must be done before deleting jobs" ); last; } $authenticated_user = $1; $ENV{OARDO_BECOME_USER} = $authenticated_user; my $cmd = "$OARDODO_CMD $OARDEL_CMD $jobid"; my $cmdRes = OAR::API::send_cmd($cmd,"Oardel"); print $q->header( -status => 202, -type => "$type" ); print $HTML_HEADER if ($ext eq "html"); print OAR::API::export( { 'id' => "$jobid", 'status' => "Delete request registered", 'oardel_output' => "$cmdRes", 'api_timestamp' => time() } , $ext ); last; }; #}}} # #{{{ /jobs/stagein and stageout (desktop computing) # $URI = qr{^/jobs/(\d+)/stagein(.tar\.gz|.tgz)$}; OAR::API::GET( $_, $URI ) && do { $_->path_info =~ m/$URI/; my $ext = OAR::API::set_ext($q,$2); (my $header, my $type)=OAR::API::set_output_format($ext); OAR::API::jobStageIn($1); last; }; $URI = qr{^/jobs/(\d+)/stagein(.tar\.gz|.tgz)$}; OAR::API::HEAD( $_, $URI ) && do { $_->path_info =~ m/$URI/; my $ext = OAR::API::set_ext($q,$2); (my $header, my $type)=OAR::API::set_output_format($ext); OAR::API::jobStageInHead($1); last; }; $URI = qr{^/jobs/(\d+)/stageout(.tar\.gz|.tgz)$}; OAR::API::POST( $_, $URI ) && do { $_->path_info =~ m/$URI/; my $ext = OAR::API::set_ext($q,$2); (my $header, my $type)=OAR::API::set_output_format($ext,"GET, POST"); my $fh = $q->upload('myfile'); if (defined $fh) { my $io_handle = $fh->handle; my $buffer; open (OUTFILE, '>>', "$stageout_dir/$1.tgz"); while (my $bytesread = $io_handle->read($buffer, 1024)) { print OUTFILE $buffer; } } print $q->header( -status => 200, -type => "application/x-tar" ); last; }; #}}} # #{{{ POST /jobs//state : changes the state of a job # $URI = qr{^/jobs/(\d+)/state(.*)$}; OAR::API::POST( $_, $URI ) && do { $_->path_info =~ m/$URI/; my $ext = OAR::API::set_ext($q,$2); (my $header, my $type)=OAR::API::set_output_format($ext,"GET, POST"); print $q->header( -status => 200, -type => $type ); my $json = decode_json $q->param('POSTDATA'); my $state = $json->{'state'}; if ($state eq 'running'){ OAR::API::runJob($1); } elsif($state eq 'terminated'){ OAR::API::terminateJob($1); } elsif($state eq 'error'){ OAR::API::errorJob($1); } else { die "unknown state" } last; }; #}}} ########################################### # Resources ########################################### # #{{{ GET /resources/(details|) : List of resources or details of a resource # $URI = qr{^/resources(/full|/details|/[0-9]+)*\.*(yaml|json|html)*$}; OAR::API::GET( $_, $URI ) && do { $_->path_info =~ m/$URI/; my $ext=OAR::API::set_ext($q,$2); my $header, my $type; if(defined($1)) { # "/full" is kept for backward compatibility if ($1 ne "/full" && $1 ne "/details") { ($header, $type)=OAR::API::set_output_format($ext,"GET, DELETE"); }else{ ($header, $type)=OAR::API::set_output_format($ext,"GET"); } }else{ ($header, $type)=OAR::API::set_output_format($ext,"GET, POST"); } # will the resources need be paged or not # by default resources results are paged my $paged = 1; my $compact = 0; my $max_items = $MAX_ITEMS; # GET limit from uri parameter if (defined($q->param('limit'))) { $max_items = $q->param('limit'); } # set offset / GET offset from uri parameter my $offset = 0; if (defined($q->param('offset'))) { $offset = $q->param('offset'); } my $resources; OAR::Nodes::open_db_connection or OAR::API::ERROR(500, "Cannot connect to the database", "Cannot connect to the database" ); if (defined($1)) { if ($1 eq "/full" || $1 eq "/details") { # get specified intervals of resources $resources = OAR::Nodes::get_requested_resources($max_items,$offset); } elsif ($1 =~ /\/([0-9]+)/) { # get the resources infos my $resource = OAR::Nodes::get_resource_infos($1); if (defined($resource)) { $resources = [OAR::Nodes::get_resource_infos($1)]; } else { # resource does not exist #$resources = OAR::API::struct_empty($STRUCTURE); OAR::Nodes::close_db_connection; OAR::API::ERROR( 404, "Resource not found", "Resource not found" ); } # do not need to paging resource detail $paged = 0; $compact = 1; } else { OAR::Nodes::close_db_connection; OAR::API::ERROR(500,"Error 666!","Error 666"); } } else { # get specified intervals of resources $resources = OAR::Nodes::get_requested_resources($max_items,$offset); $resources = OAR::API::filter_resource_list($resources); } OAR::API::fix_resource_ids($resources); OAR::API::add_resources_uris($resources,$ext,''); $resources = OAR::API::struct_resource_list($resources,$STRUCTURE,$compact); # test if resources need to be paged if ($paged == 1) { # get the total number of resources my $total_resources = OAR::Nodes::count_all_resources(); # add pagination informations $resources = OAR::API::add_pagination($resources,$total_resources,$q->path_info,$q->query_string,$ext,$max_items,$offset,$STRUCTURE); } OAR::Nodes::close_db_connection; print $header; print $HTML_HEADER if ($ext eq "html"); print OAR::API::export($resources,$ext); last; }; #}}} # #{{{ GET /resources/nodes/ : List the resources of a node # $URI = qr{^/resources/nodes/([\w\.-]+?)(\.yaml|\.json|\.html)*$}; OAR::API::GET( $_, $URI ) && do { $_->path_info =~ m/$URI/; my $ext=OAR::API::set_ext($q,$2); (my $header, my $type)=OAR::API::set_output_format($ext); OAR::Nodes::open_db_connection or OAR::API::ERROR(500, "Cannot connect to the database", "Cannot connect to the database" ); my $resources = OAR::Nodes::get_resources_for_host($1); $resources = OAR::API::filter_resource_list($resources); OAR::Nodes::close_db_connection; OAR::API::add_resources_uris($resources,$ext,''); $resources = OAR::API::struct_resource_list($resources,$STRUCTURE,0); $resources = OAR::API::add_pagination($resources,@$resources,$q->path_info,undef,$ext,0,0,$STRUCTURE); print $header; print $HTML_HEADER if ($ext eq "html"); print OAR::API::export($resources,$ext); last; }; #}}} # #{{{ GET /resources/()/jobs : Jobs running on a resource # $URI = qr{^/resources(/[0-9]+)+/jobs(\.yaml|\.json|\.html)*$}; OAR::API::GET( $_, $URI ) && do { $_->path_info =~ m/$URI/; my $ext=OAR::API::set_ext($q,$2); (my $header, my $type)=OAR::API::set_output_format($ext); OAR::Nodes::open_db_connection or OAR::API::ERROR(500, "Cannot connect to the database", "Cannot connect to the database" ); my $jobs; if ($1 =~ /\/([0-9]+)/) { my $job_array=OAR::Nodes::get_jobs_running_on_resource($1); foreach my $job_id (@$job_array) { push(@$jobs,{id =>int($job_id)}); } OAR::API::add_jobs_on_resource_uris($jobs,$ext); } OAR::Nodes::close_db_connection; $jobs = OAR::API::add_pagination($jobs,@$jobs,$q->path_info,undef,$ext,0,0,$STRUCTURE); print $header; print $HTML_HEADER if ($ext eq "html"); print OAR::API::export($jobs,$ext); last; }; #}}} # #{{{ GET /resources/nodes//jobs : Jobs running on a node # $URI = qr{^/resources/nodes/([-\.\w]+)/jobs(.*)$}; OAR::API::GET( $_, $URI ) && do { $_->path_info =~ m/$URI/; my $ext = OAR::API::set_ext($q,$2); (my $header, my $type)=OAR::API::set_output_format($ext); OAR::Nodes::open_db_connection or OAR::API::ERROR(500, "Cannot connect to the database", "Cannot connect to the database" ); my $jobs; my $job_array; #OAR::Nodes::heartbeat($1); <-- what the hell is that???? # a "?state=" filter is possible, but prevent Terminated and Error state # because this result is not paginated and output may be too big if (defined($q->param('state')) && $q->param('state') eq "toKill"){ # This "toKill" state is virtual and implemented for the desktop # computing agent purpose. $job_array=OAR::Nodes::get_jobs_running_on_node($1); foreach my $job_id (@$job_array) { push(@$jobs,{id =>int($job_id)}) if OAR::Nodes::is_job_tokill($job_id); } } elsif (defined($q->param('state')) && $q->param('state') ne "Terminated" && $q->param('state') ne "Error" ) { $job_array=OAR::Nodes::get_jobs_on_node($1,$q->param('state')); foreach my $job_id (@$job_array) { push(@$jobs,{id =>int($job_id)}); } }else{ $job_array=OAR::Nodes::get_jobs_running_on_node($1); foreach my $job_id (@$job_array) { push(@$jobs,{id =>int($job_id)}); } } OAR::API::add_jobs_on_resource_uris($jobs,$ext); OAR::Nodes::close_db_connection; $jobs = OAR::API::add_pagination($jobs,@$jobs,$q->path_info,undef,$ext,0,0,$STRUCTURE); print $header; print $HTML_HEADER if ($ext eq "html"); print OAR::API::export($jobs,$ext); last; }; #}}} # #{{{ GET /resources//jobs : List jobs running on resources, by property # $URI = qr{^/resources/([A-za-z0-9]+)*/jobs\.*(yaml|json|html)*$}; OAR::API::GET( $_, $URI ) && do { $_->path_info =~ m/$URI/; my $ext=OAR::API::set_ext($q,$2); my $header, my $type; my $property=$1; ($header, $type)=OAR::API::set_output_format($ext,"GET"); my $dbh = OAR::IO::connect() or OAR::API::ERROR(500, "Cannot connect to the database", "Cannot connect to the database" ); my $jobs=OAR::IO::get_resources_jobs($dbh) or OAR::IO::disconnect($dbh), OAR::API::ERROR(500, "Could not get resources jobs", "Could not get resources jobs" ); my $resources=OAR::IO::get_resources_by_property($dbh,$property) or OAR::IO::disconnect($dbh), OAR::API::ERROR(500, "Could not get resources by property $property", "Could not get resources by property $property" ); my %resources_by_property_jobs; foreach my $property (keys %$resources) { if (!defined($resources_by_property_jobs{$property})) { @{$resources_by_property_jobs{$property}}=();} foreach my $resource_id (@{$resources->{$property}}) { foreach my $job_id (@{$jobs->{$resource_id}}) { push(@{$resources_by_property_jobs{$property}}, $job_id); } } } # Formatting pass my @items; foreach my $r (keys %resources_by_property_jobs) { push(@items,{ $property => $r, jobs => $resources_by_property_jobs{$r} }); } my $output={ 'items' => \@items, 'links' => [ { 'rel' => "self", 'href' => OAR::API::htmlize_uri(OAR::API::make_uri("/resources/$property/jobs",$ext,0),$ext) } ], 'api_timestamp' => time() }; OAR::IO::disconnect($dbh); print $header; print $HTML_HEADER if ($ext eq "html"); print OAR::API::export($output,$ext); last; }; #}}} # #{{{ POST /resources : Create new resources # $URI = qr{^/resources(\.yaml|\.json|\.html)*$}; OAR::API::POST( $_, $URI ) && do { $_->path_info =~ m/$URI/; my $ext=OAR::API::set_ext($q,$1); (my $header)=OAR::API::set_output_format($ext,"GET, POST"); # Must be administrator (oar user) if ( not $authenticated_user =~ /(\w+)/ ) { OAR::API::ERROR( 401, "Permission denied", "A suitable authentication must be done before creating new resources" ); last; } if ( not $authenticated_user eq "oar" ) { OAR::API::ERROR( 401, "Permission denied", "Only the oar user can create new resources" ); last; } $ENV{OARDO_BECOME_USER} = "oar"; # Check and get the submited resource # From encoded data my $resources; if ($q->param('POSTDATA')) { $resources = OAR::API::check_resources( $q->param('POSTDATA'), $q->content_type ); } # From html form else { $resources = OAR::API::check_resources( $q->Vars, $q->content_type ); } my $dbh = OAR::IO::connect() or OAR::API::ERROR(500, "Cannot connect to the database", "Cannot connect to the database" ); my @ids=OAR::IO::add_resources($dbh,$resources) or OAR::IO::disconnect($dbh), OAR::API::ERROR(500, "Could not create asked resources", "Could not create asked resources" ); my $result=[]; foreach my $id (@ids) { if (not $id =~ /^\d+$/) { OAR::IO::disconnect($dbh); OAR::API::ERROR(500,"SQL query failed into resources creation",$id); } push(@$result,{ id => $id, links => [ { rel => "self", href => "resources/$id" } ] }); } $result = OAR::API::add_pagination($result,@ids,$q->path_info,$q->query_string,$ext,0,0,$STRUCTURE); print $header; print $HTML_HEADER if ($ext eq "html"); print OAR::API::export( $result , $ext ); OAR::Tools::notify_tcp_socket($remote_host,$remote_port,"ChState"); OAR::Tools::notify_tcp_socket($remote_host,$remote_port,"Term"); OAR::IO::disconnect($dbh); last; }; #}}} # #{{{ POST /resources//state : Change the state of a resource # $URI = qr{^/resources/(\d+)/state(\.yaml|\.json|\.html)*$}; OAR::API::POST( $_, $URI ) && do { $_->path_info =~ m/$URI/; my $id=$1; my $ext=OAR::API::set_ext($q,$2); (my $header)=OAR::API::set_output_format($ext,"GET, POST"); # Must be administrator (oar user) if ( not $authenticated_user =~ /(\w+)/ ) { OAR::API::ERROR( 401, "Permission denied", "A suitable authentication must be done before creating new resources" ); last; } if ( not $authenticated_user eq "oar" ) { OAR::API::ERROR( 401, "Permission denied", "Only the oar user can create new resources" ); last; } $ENV{OARDO_BECOME_USER} = "oar"; # Check and get the submited resource # From encoded data my $resource; if ($q->param('POSTDATA')) { $resource = OAR::API::check_resource_state( $q->param('POSTDATA'), $q->content_type ); } # From html form else { $resource = OAR::API::check_resource_state( $q->Vars, $q->content_type ); } my $dbh = OAR::IO::connect() or OAR::API::ERROR(500, "Cannot connect to the database", "Cannot connect to the database" ); OAR::IO::set_resource_state($dbh,$id,$resource->{state},"NO"); print $header; print $HTML_HEADER if ($ext eq "html"); print OAR::API::export( { 'status' => "Change state request registered", 'id' => "$id", 'api_timestamp' => time(), 'uri' => OAR::API::htmlize_uri(OAR::API::make_uri("resources/$id",$ext,0),$ext) } , $ext ); OAR::Tools::notify_tcp_socket($remote_host,$remote_port,"ChState"); OAR::Tools::notify_tcp_socket($remote_host,$remote_port,"Term"); OAR::IO::disconnect($dbh); last; }; #}}} # #{{{ DELETE /resources/(|/path_info =~ m/$URI/; my $id; my $node; my $cpuset; if ($2) { $node=$1; $id=0; $cpuset=$2; $cpuset =~ s,^/,, ;} else { $node=""; $id=$1; $cpuset=""; } ; my $ext=OAR::API::set_ext($q,$3); (my $header)=OAR::API::set_output_format($ext); # Must be administrator (oar user) if ( not $authenticated_user =~ /(\w+)/ ) { OAR::API::ERROR( 401, "Permission denied", "A suitable authentication must be done before deleting new resources" ); last; } if ( not $authenticated_user eq "oar" ) { OAR::API::ERROR( 401, "Permission denied", "Only the oar user can delete resources" ); last; } $ENV{OARDO_BECOME_USER} = "oar"; my $base = OAR::IO::connect() or OAR::API::ERROR(500, "Cannot connect to the database", "Cannot connect to the database" ); # Check if the resource exists my $query; my $Resource; if ($id == 0) { $query="WHERE network_address = \"$node\" AND cpuset = $cpuset"; } else { $query="WHERE resource_id=$id"; } my $sth = $base->prepare("SELECT resource_id FROM resources $query"); $sth->execute(); my @res = $sth->fetchrow_array(); if ($res[0]) { $Resource=$res[0];} else { OAR::IO::disconnect($base); OAR::API::ERROR(404,"Not found","Corresponding resource could not be found ($id,$node,$cpuset)"); last; } # Resource deletion # !!! This is a dirty cut/paste of oarremoveresource code !!! my $resource_ref = OAR::IO::get_resource_info($base,$Resource); if (defined($resource_ref->{state}) && ($resource_ref->{state} eq "Dead")){ my $sth = $base->prepare(" SELECT jobs.job_id, jobs.assigned_moldable_job FROM assigned_resources, jobs WHERE assigned_resources.resource_id = $Resource AND assigned_resources.moldable_job_id = jobs.assigned_moldable_job "); $sth->execute(); my @jobList; while (my @ref = $sth->fetchrow_array()) { push(@jobList, [$ref[0], $ref[1]]); } $sth->finish(); foreach my $i (@jobList){ $base->do("DELETE from event_logs WHERE job_id = $i->[0]"); $base->do("DELETE from frag_jobs WHERE frag_id_job = $i->[0]"); $base->do("DELETE from jobs WHERE job_id = $i->[0]"); $base->do("DELETE from assigned_resources WHERE moldable_job_id = $i->[1]"); } $base->do("DELETE from assigned_resources WHERE resource_id = $Resource"); $base->do("DELETE from resource_logs WHERE resource_id = $Resource"); $base->do("DELETE from resources WHERE resource_id = $Resource"); #print("Resource $Resource removed.\n"); print $header; print $HTML_HEADER if ($ext eq "html"); print OAR::API::export( { 'status' => "deleted",'api_timestamp' => time() } , $ext ); }else{ OAR::IO::disconnect($base); OAR::API::ERROR(403,"Forbidden","The resource $Resource must be in the Dead status"); last; } OAR::IO::disconnect($base); last; }; #}}} # #{{{ POST /resources/generate : Generate resources (needs an external command like oar_resources_add) # $URI = qr{^/resources/generate(\.yaml|\.json|\.html)*$}; OAR::API::POST( $_, $URI ) && do { $_->path_info =~ m/$URI/; my $ext = OAR::API::set_ext($q,$1); (my $header) = OAR::API::set_output_format($ext,"GET, POST"); # Must be administrator (oar user) if ( not $authenticated_user =~ /(\w+)/ ) { OAR::API::ERROR( 401, "Permission denied", "A suitable authentication must be done before generating resources" ); last; } if ( not $authenticated_user eq "oar" ) { OAR::API::ERROR( 401, "Permission denied", "Only the oar user can generate resources" ); last; } $ENV{OARDO_BECOME_USER} = "oar"; # Check feature activation if ($API_RESOURCES_LIST_GENERATION_CMD eq "" ) { OAR::API::ERROR( 500, "Disabled feature", "To enable this feature, please provide a command into the API_RESOURCES_LIST_GENERATION_CMD configuration variable" ); last; } # Check and get the submited resource description # From encoded data my $description; # command generation my $cmd; # ressources properties my $cmd_properties=""; if ($q->param('POSTDATA')) { $description = OAR::API::check_resource_description( $q->param('POSTDATA'), $q->content_type ); # getting properties if (defined($description->{properties})) { foreach my $property ( keys %{$description->{properties}} ) { $cmd_properties .= " -p ".$property."=".$description->{properties}->{$property} } } } # From html form else { $description = OAR::API::check_resource_description( $q->Vars, $q->content_type ); # getting properties if (defined($description->{properties})) { my @properties = split(/,/,$description->{properties}); foreach my $property (@properties) { $cmd_properties .= " -p $property"; } } } my $auto_offset=""; if (defined($description->{auto_offset}) && "$description->{auto_offset}" eq "1") { $auto_offset="--auto-offset "; } # command with arguments $cmd = "$API_RESOURCES_LIST_GENERATION_CMD $auto_offset".$description->{resources}.$cmd_properties; # execute the command my $cmdRes = OAR::API::send_cmd($cmd,"Oar"); my $data = OAR::API::import_data($cmdRes,"yaml"); OAR::API::struct_resource_list_fix_ints($data); $data = OAR::API::add_pagination($data,@$data,$q->path_info,undef,$ext,0,0,$STRUCTURE); print $header; if ($ext eq "html") { print $HTML_HEADER; api_uri::resources_commit_button($data->{"items"}); } print OAR::API::export($data,$ext); last; }; #}}} ########################################### # Accounting ########################################### # #{{{ GET /accounting[]?from=,to= : Show accounting informations between 2 unix timestamps # $URI = qr{^/accounting(/[^\..]+)*\.*(yaml|json|html)*$}; OAR::API::GET( $_, $URI ) && do { $_->path_info =~ m/$URI/; my $ext=OAR::API::set_ext($q,$2); my $header ; my $type; my $user=$1; ($header,$type)=OAR::API::set_output_format($ext,"GET"); if (defined($user)) { $user=~s/^\///; } my $JOBS_URI_DEFAULT_PARAMS = "from=0&to=2147483647"; if (is_conf("API_JOBS_URI_DEFAULT_PARAMS")){ $JOBS_URI_DEFAULT_PARAMS = get_conf("API_JOBS_URI_DEFAULT_PARAMS"); } my $from; if (!defined($q->param('from'))) { my $param = qr{.*from=(.*?)(&|$)}; if ($JOBS_URI_DEFAULT_PARAMS =~ m/$param/) { $from = $1; }else { $from = 0; } }else{ $from = $q->param('from'); } my $to; if (!defined($q->param('to'))) { my $param = qr{.*to=(.*?)(&|$)}; if ($JOBS_URI_DEFAULT_PARAMS =~ m/$param/) { $to = $1; }else{ $to = 2147483647; } }else{ $to = $q->param('to'); } # get accounting infos my $dbh = OAR::IO::connect() or OAR::API::ERROR(500, "Cannot connect to the database", "Cannot connect to the database" ); my $accounting = OAR::API::struct_accounting(OAR::IO::get_accounting_summary_byproject($dbh,$from,$to,$user,undef,undef)); my $total; if (defined($accounting)) { $total = @$accounting; }else{ $accounting=OAR::API::struct_empty($STRUCTURE); $total=0; } OAR::IO::disconnect($dbh); # add pagination informations and export $accounting = OAR::API::add_pagination($accounting,$total,$q->path_info,$q->query_string,$ext,0,0,$STRUCTURE); print $header; print $HTML_HEADER if ($ext eq "html"); print OAR::API::export($accounting,$ext); last; }; #}}} ########################################### # Admission rules ########################################### # #{{{ GET /admission_rules : List of all admissions rules # $URI = qr{^/admission_rules\.*(yaml|json|html)*$}; OAR::API::GET( $_, $URI ) && do { $_->path_info =~ m/$URI/; my $ext = OAR::API::set_ext($q,$1); (my $header, my $type) = OAR::API::set_output_format($ext); # Must be administrator (oar user) OAR::API::authenticate_user($authenticated_user,"get admission rules","oar"); # GET limit from uri parameter my $max_items=$MAX_ITEMS; if (defined($q->param('limit'))) { $max_items = $q->param('limit'); } # set offset / GET offset from uri parameter my $offset = 0; if (defined($q->param('offset'))) { $offset = $q->param('offset'); } OAR::Stat::open_db_connection or OAR::API::ERROR(500, "Cannot connect to the database", "Cannot connect to the database" ); # get specified intervals of admission rules my $admissions_rules = OAR::Stat::get_requested_admission_rules($max_items,$offset); OAR::API::add_admission_rules_uris($admissions_rules,$ext); $admissions_rules = OAR::API::struct_admission_rule_list($admissions_rules,$STRUCTURE); # get the total number of admissions rules my $total_rules = OAR::Stat::count_all_admission_rules(); OAR::Stat::close_db_connection(); # add pagination informations $admissions_rules = OAR::API::add_pagination($admissions_rules,$total_rules,$q->path_info,$q->query_string,$ext,$max_items,$offset,$STRUCTURE); print $header; print $HTML_HEADER if ($ext eq "html"); print OAR::API::export($admissions_rules,$ext); last; }; #}}} # #{{{ GET /admission_rules/ : Details of an admission rule # $URI = qr{^/admission_rules/(\d+)(\.yaml|\.json|\.html)*$}; OAR::API::GET( $_, $URI ) && do { $_->path_info =~ m/$URI/; my $rule_id = $1; my $ext = OAR::API::set_ext($q,$2); (my $header, my $type)=OAR::API::set_output_format($ext); # Must be administrator (oar user) OAR::API::authenticate_user($authenticated_user,"get admission rules","oar"); OAR::Stat::open_db_connection or OAR::API::ERROR(500, "Cannot connect to the database", "Cannot connect to the database" ); my $admission_rule = OAR::Stat::get_specific_admission_rule($rule_id); if (defined($admission_rule->{id})) { OAR::API::add_admission_rule_uris($admission_rule,$ext); $admission_rule = OAR::API::struct_admission_rule($admission_rule,$STRUCTURE); OAR::Stat::close_db_connection; print $header; print $HTML_HEADER if ($ext eq "html"); print OAR::API::export($admission_rule,$ext); }else{ OAR::Stat::close_db_connection; OAR::API::ERROR(404,"Admission rule not found","No admission rule corresponding to id=$rule_id"); } last; }; #}}} # #{{{ POST /admission_rules : Create a new admission rule # $URI = qr{^/admission_rules(\.yaml|\.json|\.html)*$}; (OAR::API::POST( $_, $URI ) || OAR::API::PUT( $_, $URI )) && do { $_->path_info =~ m/$URI/; my $ext = OAR::API::set_ext($q,$1); (my $header) = OAR::API::set_output_format($ext,"GET, POST"); # Must be administrator (oar user) OAR::API::authenticate_user($authenticated_user,"create admission rules","oar"); # Check and get the submited admission rule # From encoded data my $admission_rule; if ($q->param('POSTDATA')) { $admission_rule = OAR::API::check_admission_rule( $q->param('POSTDATA'), $q->content_type ); } elsif ($q->param('PUTDATA')) { $admission_rule = OAR::API::check_admission_rule( $q->param('PUTDATA'), $q->content_type ); } # From html form else { $admission_rule = OAR::API::check_admission_rule( $q->Vars, $q->content_type ); } my $dbh = OAR::IO::connect() or OAR::API::ERROR(500, "Cannot connect to the database", "Cannot connect to the database" ); my $id = OAR::IO::add_admission_rule($dbh,$admission_rule->{priority},$admission_rule->{enabled},$admission_rule->{rule}); if ( $id && $id > 0) { print $q->header( -status => 201, -type => OAR::API::get_content_type($ext) , -location => OAR::API::htmlize_uri(OAR::API::make_uri("admission_rules/$id",$ext,0),$ext) ); print $header; print $HTML_HEADER if ($ext eq "html"); print OAR::API::export( { 'id' => "$id", 'priority' => "$admission_rule->{priority}", 'enalbed' => "$admission_rule->{enabled}", 'rule' => OAR::API::nl2br($admission_rule->{rule}), 'api_timestamp' => time(), 'uri' => OAR::API::htmlize_uri(OAR::API::make_uri("admission_rules/$id",$ext,0),$ext) } , $ext ); OAR::IO::disconnect($dbh); } else { OAR::IO::disconnect($dbh); OAR::API::ERROR( 500, "Admission rule not created", "Could not create the new admission rule" ); } last; }; #}}} # #{{{ DELETE /admission_rules/ : Delete an admission rule # $URI = qr{^/admission_rules/(\d+)(\.yaml|\.json|\.html)*$}; OAR::API::DELETE( $_, $URI ) && do { $_->path_info =~ m/$URI/; my $rule_id = $1; my $ext = OAR::API::set_ext($q,$2); (my $header, my $type)=OAR::API::set_output_format($ext); # Must be administrator (oar user) OAR::API::authenticate_user($authenticated_user,"delete admission rules","oar"); OAR::Stat::open_db_connection or OAR::API::ERROR(500, "Cannot connect to the database", "Cannot connect to the database" ); my $admission_rule = OAR::Stat::get_specific_admission_rule($rule_id); print $header; if (defined($admission_rule)) { OAR::Stat::delete_specific_admission_rule($rule_id); print $HTML_HEADER if ($ext eq "html"); print OAR::API::export( { 'id' => "$admission_rule->{id}", 'priority' => "$admission_rule->{priority}", 'enalbed' => "$admission_rule->{enabled}", 'rule' => "$admission_rule->{rule}", 'status' => "deleted", 'api_timestamp' => time() } , $ext ); OAR::Stat::close_db_connection; } else { OAR::Stat::close_db_connection; OAR::API::ERROR(404,"Not found","Corresponding admission rule could not be found"); } last; }; #}}} # #{{{ POST /admission_rules/[?method=delete]: Erase or Delete an admission rule # $URI = qr{^/admission_rules/(\d+)(\.yaml|\.json|\.html)*$}; OAR::API::POST( $_, $URI ) && do { $_->path_info =~ m/$URI/; my $rule_id = $1; my $ext = OAR::API::set_ext($q,$2); (my $header, my $type) = OAR::API::set_output_format($ext,"GET, POST"); # Must be administrator (oar user) OAR::API::authenticate_user($authenticated_user,"edit admission rules","oar"); my $dbh = OAR::IO::connect() or OAR::API::ERROR(500, "Cannot connect to the database", "Cannot connect to the database" ); # Check and get the submitted data # From encoded data my $admission_rule; if ($q->param('POSTDATA')) { $admission_rule = OAR::API::check_admission_rule_update( $q->param('POSTDATA'), $q->content_type ); } # From html form else { $admission_rule = OAR::API::check_admission_rule_update( $q->Vars, $q->content_type ); } # Delete (alternative way to DELETE request, for html forms) if (defined($admission_rule->{method}) && $admission_rule->{method} eq "delete" ) { print $q->header( -status => 202, -type => OAR::API::get_content_type($ext) ); my $id=OAR::IO::delete_admission_rule($dbh,$rule_id); OAR::IO::disconnect($dbh); if ( $id && $id > 0) { print $HTML_HEADER if ($ext eq "html"); print OAR::API::export( { 'id' => "$rule_id", 'status' => "deleted", 'api_timestamp' => time() } , $ext ); }else{ OAR::API::ERROR( 404, "Admission rule not found", "Could not find admission rule to delete: id=$rule_id" ); } }elsif (defined($admission_rule->{priority}) and defined($admission_rule->{enabled}) and defined($admission_rule->{rule})) { my $id = OAR::IO::update_admission_rule($dbh,$rule_id,$admission_rule->{priority},$admission_rule->{enabled},$admission_rule->{rule}); OAR::IO::disconnect($dbh); if ( $id && $id > 0) { print $q->header( -status => 201, -type => OAR::API::get_content_type($ext) , -location => OAR::API::htmlize_uri(OAR::API::make_uri("admission_rules/$id",$ext,0),$ext) ); print $HTML_HEADER if ($ext eq "html"); print OAR::API::export( { 'id' => "$id", 'priority' => "$admission_rule->{priority}", 'enalbed' => "$admission_rule->{enabled}", 'rule' => OAR::API::nl2br($admission_rule->{rule}), 'api_timestamp' => time(), 'uri' => OAR::API::htmlize_uri(OAR::API::make_uri("admission_rules/$id",$ext,0),$ext) } , $ext ); } else { OAR::API::ERROR( 404, "Admission rule not found", "Could not find admission rule to update: id=$rule_id" ); } }else { OAR::API::ERROR(400,"Bad query","Could not understand ". $admission_rule->{method} ." method"); } last; }; #}}} ########################################### # Config file edition ########################################### # #{{{ GET /config : List of all the configured variables # $URI = qr{^/config\.*(yaml|json|html)*$}; OAR::API::GET( $_, $URI ) && do { $_->path_info =~ m/$URI/; my $ext = OAR::API::set_ext($q,$1); (my $header, my $type) = OAR::API::set_output_format($ext); # Must be administrator (oar user) OAR::API::authenticate_user($authenticated_user,"get configuration variables","oar"); # get all configured parameters my $list_params = get_conf_list(); # parameters hash result my $parameters; if ( !defined $list_params || keys %$list_params == 0 ) { $parameters = OAR::API::struct_empty($STRUCTURE); } else { foreach my $param (keys %$list_params) { $parameters->{$param}->{value} = $list_params->{$param}; } OAR::API::add_config_parameters_uris($parameters,$ext); $parameters = OAR::API::struct_config_parameters_list($parameters,$STRUCTURE); } print $header; print $HTML_HEADER if ($ext eq "html"); print OAR::API::export($parameters,$ext); last; }; #}}} # #{{{ GET /config/file : Get the raw configuration file # $URI = qr{^/config/file\.*(yaml|json|html)*$}; OAR::API::GET( $_, $URI ) && do { $_->path_info =~ m/$URI/; my $ext = OAR::API::set_ext($q,$1); (my $header, my $type) = OAR::API::set_output_format($ext); # Must be administrator (oar user) OAR::API::authenticate_user($authenticated_user,"get configuration variables","oar"); my $cmd="$OARDODO_CMD cat $config_file"; my $cmdRes = OAR::API::send_cmd($cmd,"cat $config_file"); my $file= { 'path' => $config_file, 'file' => $cmdRes }; print $header; print $HTML_HEADER if ($ext eq "html"); print OAR::API::export($file,$ext); last; }; #}}} # #{{{ GET /config/ : Get a configuration variable value # $URI = qr{^/config/(\w+)\.*(yaml|json|html)*$}; OAR::API::GET( $_, $URI ) && do { $_->path_info =~ m/$URI/; my $variable = $1; my $ext = OAR::API::set_ext($q,$2); (my $header, my $type) = OAR::API::set_output_format($ext); # Must be administrator (oar user) if ( not $authenticated_user =~ /(\w+)/ ) { OAR::API::ERROR( 401, "Permission denied", "A suitable authentication must be done before getting configuration parameters" ); last; } if ( not $authenticated_user eq "oar" ) { OAR::API::ERROR( 401, "Permission denied", "Only the oar user can get configuration parameters" ); last; } $ENV{OARDO_BECOME_USER} = "oar"; # result parameter my $parameter; if (is_conf($variable)) { $parameter->{id} = $variable; $parameter->{value} = get_conf($variable); OAR::API::add_config_parameter_uris($parameter,$ext); $parameter = OAR::API::struct_config_parameter($parameter,$STRUCTURE); } else { $parameter->{id} = OAR::API::struct_empty($STRUCTURE); } print $header; print $HTML_HEADER if ($ext eq "html"); print OAR::API::export($parameter,$ext); last; }; #}}} # #{{{ POST /config/ : Change the value of a configuration parameter # $URI = qr{^/config/(\w+)\.*(yaml|json|html)*$}; OAR::API::POST( $_, $URI ) && do { $_->path_info =~ m/$URI/; my $variable = $1; my $ext = OAR::API::set_ext($q,$2); (my $header, my $type) = OAR::API::set_output_format($ext,"GET, POST"); print $header; print $HTML_HEADER if ($ext eq "html"); # Must be administrator (oar user) if ( not $authenticated_user =~ /(\w+)/ ) { OAR::API::ERROR( 401, "Permission denied", "A suitable authentication must be done before changing configuration parameters" ); last; } if ( not $authenticated_user eq "oar" ) { OAR::API::ERROR( 401, "Permission denied", "Only the oar user can make changes on configuration parameters" ); last; } $ENV{OARDO_BECOME_USER} = "oar"; # configuration parameter my $parameter; if ($q->param('POSTDATA')) { $parameter = OAR::API::check_configuration_variable( $q->param('POSTDATA'), $q->content_type ); } # From html form else { $parameter = OAR::API::check_configuration_variable( $q->Vars, $q->content_type ); } my $result; set_value($variable, $parameter->{value}); if (is_conf($variable)) { print $q->header( -status => 202, -type => $type , -location => "/config/$variable" ); $result={"status" => "accepted"}; } else { print $q->header( -status => 201, -type => $type , -location => "/config/$variable" ); $result={"status" => "created"}; } print OAR::API::export($result,$ext); last; }; #}}} ########################################### # Desktop computing specific ########################################### # #{{{ GET /desktop/agents : Desktop computing agent sign in # $URI = qr{^/desktop/agents(.*)$}; OAR::API::GET( $_, $URI ) && do { my $db = OAR::IO::connect() or die "cannot connect to the data base\n"; OAR::IO::lock_table($db,["event_logs"]); my $result = OAR::IO::get_last_event_from_type($db, "NEW_VIRTUAL_HOSTNAME"); if ($result) { $result = $result->{'description'}; $result++; OAR::API::sign_in($result,$remote_host,$remote_port,$expiry,$allow_create_node); OAR::IO::add_new_event($db,"NEW_VIRTUAL_HOSTNAME",0,$result); $result = {'hostname' => $result}; } else { OAR::API::sign_in('vnode1',$remote_host,$remote_port,$expiry,$allow_create_node); OAR::IO::add_new_event($db,"NEW_VIRTUAL_HOSTNAME",0,'vnode1'); $result = {'hostname' => 'vnode1'}; } OAR::IO::unlock_table($db); # TODO: reject if DESKTOP_COMPUTING_ALLOW_CREATE_NODE="0" print $q->header( -status => 200, -type => "application/json" ); print OAR::API::export($result,'json'); last; }; #}}} ########################################### # Media (files) download/upload ########################################### # #{{{ GET /media/ls/ : List files # $URI = qr{^/media/ls/(.*)$}; OAR::API::GET( $_, $URI ) && do { $_->path_info =~ m/$URI/; my $path=$1; my $ext = OAR::API::set_ext($q,undef); (my $header, my $type) = OAR::API::set_output_format($ext); # Must be authenticated if ( not $authenticated_user =~ /(\w+)/ ) { OAR::API::ERROR( 401, "Permission denied", "A suitable authentication must be done before getting files" ); last; } $authenticated_user = $1; $ENV{OARDO_BECOME_USER} = $authenticated_user; # Security escaping $path =~ s/(\\*)(`|\$)/$1$1\\$2/g; # Get the path and replace "~" by the home directory $path="/".$path; my @user_infos=getpwnam($authenticated_user); $path =~ s|/~/|$user_infos[7]/|; # Check file existency if (system("$OARDODO_CMD","test","-d","$path") != 0) { OAR::API::ERROR(404, "Not found", "Path not found: $path"); last; } # Check file readability if (system("$OARDODO_CMD","test","-r","$path") != 0) { OAR::API::ERROR(403, "Forbidden","File could not be read: $path" ); last; } # Get the listing my $cmd="$OARDODO_CMD ls -l $path"; my $cmdRes = OAR::API::send_cmd($cmd,"ls"); my $listing=[]; my ($l_name, $l_type, $l_size, $l_mtime, $l_mode); for (parse_dir($cmdRes)) { ($l_name, $l_type, $l_size, $l_mtime, $l_mode) = @$_; push(@$listing,{'name' => $l_name, 'type' => $l_type, 'size' => $l_size, 'mtime' => $l_mtime, 'mode' => $l_mode }); } print $header; print $HTML_HEADER if ($ext eq "html"); $listing = OAR::API::add_pagination($listing,@$listing,$q->path_info,undef,$ext,0,0,$STRUCTURE); print OAR::API::export($listing,$ext); last; }; #}}} # #{{{ GET /media/?tail= : Get a file (tail it to lines if specified) # $URI = qr{^/media/(.*)$}; OAR::API::GET( $_, $URI ) && do { $_->path_info =~ m/$URI/; my $filename=$1; # Must be authenticated if ( not $authenticated_user =~ /(\w+)/ ) { OAR::API::ERROR( 401, "Permission denied", "A suitable authentication must be done before getting files" ); last; } $authenticated_user = $1; $ENV{OARDO_BECOME_USER} = $authenticated_user; # Security escaping $filename =~ s/(\\*)(`|\$)/$1$1\\$2/g; # Tail parameter my $tail=0; if (defined($q->param('tail')) && $q->param('tail') =~ /^\d+$/) { $tail=$q->param('tail'); } # Get the filename and replace "~" by the home directory my $file="/".$filename; my @user_infos=getpwnam($authenticated_user); $file =~ s|/~/|$user_infos[7]/|; # Check file existency if (system("$OARDODO_CMD","test","-f","$file") != 0) { OAR::API::ERROR(404, "Not found", "File not found: $file"); last; } # Check file readability if (system("$OARDODO_CMD","test","-r","$file") != 0) { OAR::API::ERROR(403, "Forbidden","File could not be read: $file" ); last; } # Output the file print $q->header( -status => 200, -type => "application/octet-stream" ); if ($tail != 0) { print `$OARDODO_CMD tail -n $tail $file`; }else{ print `$OARDODO_CMD cat $file`; } last; }; #}}} # #{{{ POST /media/chmod/?mode= : Change the unix mode of a file # $URI = qr{^/media/chmod/(.*)$}; OAR::API::POST( $_, $URI ) && do { $_->path_info =~ m/$URI/; my $filename = $1; # Must be authenticated if ( not $authenticated_user =~ /(\w+)/ ) { OAR::API::ERROR( 401, "Permission denied", "A suitable authentication must be done before deleting an admission rule" ); last; } $authenticated_user = $1; $ENV{OARDO_BECOME_USER} = $authenticated_user; # Security escaping $filename =~ s/(\\*)(`|\$)/$1$1\\$2/g; # Get the filename and replace "~" by the home directory my $file="/".$filename; my @user_infos=getpwnam($authenticated_user); $file =~ s|/~/|$user_infos[7]/|; # Check and get the submitted data # From encoded data my $chmod; if ($q->param('POSTDATA')) { $chmod = OAR::API::check_chmod( $q->param('POSTDATA'), $q->content_type ); } # From html form else { $chmod = OAR::API::check_chmod( $q->Vars, $q->content_type ); } # Security checking if ( not $chmod->{mode} =~ /^[a-z0-9+]+$/ ) { OAR::API::ERROR( 401, "Permission denied", "Bad mode value: ". $chmod->{mode} ); last; } # Do the chmod my $cmd="$OARDODO_CMD chmod ". $chmod->{mode} ." $file"; my $cmdRes = OAR::API::send_cmd($cmd,"chmod"); if ($? != 0) { OAR::API::ERROR(500, "Chmod error", "Could not set mode $chmod->{mode} on file $file: $cmdRes"); } print $q->header( -status => 202, -type => "application/octet-stream" , -location => "/media/$file" ); last; }; #}}} # #{{{ POST /media/ : Upload a file and create underlying directories # $URI = qr{^/media/(.*)$}; OAR::API::POST( $_, $URI ) && do { $_->path_info =~ m/$URI/; my $filename=$1; my $ext = OAR::API::set_ext($q,undef); (my $header, my $type) = OAR::API::set_output_format($ext); #Must be authenticated if ( not $authenticated_user =~ /(\w+)/ ) { OAR::API::ERROR( 401, "Permission denied", "A suitable authentication must be done before getting files" ); last; } $authenticated_user = $1; $ENV{OARDO_BECOME_USER} = $authenticated_user; # For frameworks that can't set the Accept header field: if (defined($q->param('Accept'))) { $type=$q->param('Accept'); $ext=OAR::API::get_ext($type); $OAR::API::extension=$ext; } # Security escaping $filename =~ s/(\\*)(`|\$)/$1$1\\$2/g; # Get the filename and replace "~" by the home directory my $file="/".$filename; my @user_infos=getpwnam($authenticated_user); $file =~ s|/~/|$user_infos[7]/|; # Check if the file already exists if (system("$OARDODO_CMD","test","-f","$file") == 0) { OAR::API::ERROR(403, "File already exists", "The file already exists"); last; } # Create the directories if necessary my $path=dirname($file); if (system("$OARDODO_CMD","mkdir","-p",$path) != 0) { OAR::API::ERROR(500, "mkpath error", "Problem while creating path: $path"); last; } # Touch the file if (system("$OARDODO_CMD","touch",$file) != 0) { OAR::API::ERROR(500, "write error", "Error creating file: $file"); last; } # Upload file from an html form if ($q->content_type =~ /^multipart\/form-data.*/) { my $fh = $q->upload('file'); if (defined $fh) { my $io_handle = $fh->handle; my $buffer; open (OUTFILE, "|$OARDODO_CMD bash --noprofile --norc -c \"cat > $file\""); while (my $bytesread = $io_handle->read($buffer, 1024)) { print OUTFILE $buffer; } close(OUTFILE); } # Upload file from a direct octet-streaam }elsif ($q->content_type eq "application/octet-stream") { if ($q->param('POSTDATA')) { if (system("$OARDODO_CMD","touch",$file) != 0) { OAR::API::ERROR(500, "write error", "Error creating file: $file"); last; } open (OUTFILE, "|$OARDODO_CMD bash --noprofile --norc -c \"cat > $file\""); print OUTFILE $q->param('POSTDATA'); close(OUTFILE); } }else{ OAR::API::ERROR(406, "Bad content type", $q->content_type ." not allowed for file upload"); last; } print $q->header( -status => 201, -location => "media/$file" ); # Warning: we should do this: #print $q->header( -status => 201, -type => $type, -location => "media/$file" ); # But ajax queries form popular browsers add
 tags
    # (http://dotclear.placeoweb.com/post/json-error-pre-tag-added-undesirable)
    print $HTML_HEADER if ($ext eq "html");
    # Warning: for extjs, we need to send a "success => 'true'"
    print OAR::API::export( {
                        'status' => "created",
                        'success' => "true",
                        'links' => [ { "rel" => "self", 
                                       "href" => OAR::API::htmlize_uri(OAR::API::make_uri("media/$file",undef,0),$ext) 
                                   } ]
                     } , $ext );
    last;
  };
  #}}}
  #
  #{{{ DELETE /media/ : Delete a file or a directory recursively
  #
  $URI = qr{^/media/(.*)$};
  OAR::API::DELETE( $_, $URI ) && do {
    $_->path_info =~ m/$URI/;
    my $filename=$1;

    # Must be authenticated
    if ( not $authenticated_user =~ /(\w+)/ ) {
      OAR::API::ERROR( 401, "Permission denied",
        "A suitable authentication must be done before getting files" );
      last;
    }
    $authenticated_user = $1;
    $ENV{OARDO_BECOME_USER} = $authenticated_user;

    # Security escaping 
    $filename =~ s/(\\*)(`|\$)/$1$1\\$2/g;

    # Get the filename and replace "~" by the home directory
    my $file="/".$filename;
    my @user_infos=getpwnam($authenticated_user);
    $file =~ s|/~/|$user_infos[7]/|;  
 
    # Check file existency
    if (system("$OARDODO_CMD","test","-e","$file") != 0) {
      OAR::API::ERROR(404, "Not found", "File not found: $file");
      last;  
    }
    
    # Check file readability
    if (system("$OARDODO_CMD","test","-w","$file") != 0) {
      OAR::API::ERROR(403, "Forbidden","File or directory is not writeable: $file" );
      last;  
    }

    # Delete the file
    print $q->header( -status => 204, -type => "application/octet-stream" );
    print `$OARDODO_CMD rm -rf $file`;
    last;
  };
  #}}}
  
  ###########################################
  # SQL queries
  ###########################################
  # 
  #{{{ GET /select_all?query=) : Allows select SQL queries into the OAR database (ro) 
  #
  $URI = qr{^/select_all\.*(yaml|json|html)*$};
  OAR::API::GET( $_, $URI ) && do {
    $_->path_info =~ m/$URI/;
    my $ext=OAR::API::set_ext($q,$1);
    my $header, my $type;
    ($header, $type)=OAR::API::set_output_format($ext,"GET");

    # Must be authenticated
    if ( not $authenticated_user =~ /(\w+)/ ) {
      OAR::API::ERROR( 401, "Permission denied",
        "A suitable authentication must be done before looking at jobs" );
      last;                                     
    }                                     
    $authenticated_user = $1;
    $ENV{OARDO_USER} = $authenticated_user;

    my $query;
    # GET the query parameter from the uri
    if (defined($q->param('query'))) {
        $query = $q->param('query');
    }else{
      OAR::API::ERROR(400,"Bad query","The 'query' parameter is mandatory");
    }

    # GET limit from uri parameter
    my $limit;
    if (defined($q->param('limit'))) {
        $limit = $q->param('limit');
    }else{
        $limit=$MAX_ITEMS;
    }

    # set offset / GET offset from uri parameter
    my $offset = 0;
    if (defined($q->param('offset'))) {
        $offset = $q->param('offset');
    }
   
    # Do the query
    # The query should not contain the "SELECT  part". Example:
    #  query="FROM events,jobs WHERE ..." 
    my $dbh = OAR::IO::connect_ro() or OAR::API::ERROR(500,
                                                "Cannot connect to the database",
                                                "Cannot connect to the database"
                                                 );
    my $count = OAR::IO::sql_count($dbh,$query) or OAR::IO::disconnect($dbh), OAR::API::ERROR(500,
                                                "SQL error",
                                                "SQL error" # <- add here the sql error output
                                                 ); 
    my $result = OAR::IO::sql_select($dbh,$query,$limit,$offset) or OAR::IO::disconnect($dbh), OAR::API::ERROR(500,
                                                "SQL error",
                                                "SQL error" # <- add here the sql error output
                                                 );

    #$result = OAR::API::format_select_result($result);
    $result = OAR::API::add_pagination($result,$count,$q->path_info,$q->query_string,$ext,$limit,$offset,$STRUCTURE);

    print $header;
    print $HTML_HEADER if ($ext eq "html");
    print OAR::API::export(\$result,$ext);
    OAR::IO::disconnect($dbh);
    last;
  };
  #}}}

  ###########################################
  # Colmet
  ############################################
  #
  #{{{ GET /colmet/job/?[from=timestamp]&[to=timestamp]&[metrics=m1,m2...] : Extract colmet data for the given job
  #
  $URI = qr{^/colmet/job/(\d+)$};
  OAR::API::GET( $_, $URI ) && do {
    $_->path_info =~ m/$URI/;
    my $jobid = $1;
    my $ext=OAR::API::set_ext($q,undef);
    
    if ( not $ext eq "tgz" ) {
      OAR::API::ERROR( 400, "Bad format",
        "Colmet data is only available in compressed JSON , as application/x-gzip" );
    }    

    (my $header, my $type)=OAR::API::set_output_format($ext,"GET");
    
    # Must be authenticated
    if ( not $authenticated_user =~ /(\w+)/ ) {
      OAR::API::ERROR( 401, "Permission denied",
        "A suitable authentication must be done before looking at jobs" );
      last;
    }
    $authenticated_user = $1;
    $ENV{OARDO_USER} = $authenticated_user;

    OAR::Stat::open_db_connection or OAR::API::ERROR(500, 
                                                "Cannot connect to the database",
                                                "Cannot connect to the database"
                                                 );
    my $job = OAR::Stat::get_specific_jobs([$jobid]);
    if (@$job == 0 ) {
      OAR::Stat::close_db_connection; 
      OAR::API::ERROR( 404, "Job not found",
        "Job not found" );
      last;
    }

    OAR::Stat::close_db_connection; 

    my $COLMET_EXTRACT_PATH="/usr/lib/oar/colmet_extract.py";
    if (is_conf("API_COLMET_EXTRACT_PATH")){ $COLMET_EXTRACT_PATH = get_conf("API_COLMET_EXTRACT_PATH"); }
    my $COLMET_HDF5_PATH_PREFIX="/var/lib/colmet/hdf5/data";
    if (is_conf("API_COLMET_HDF5_PATH_PREFIX")){ $COLMET_HDF5_PATH_PREFIX = get_conf("API_COLMET_HDF5_PATH_PREFIX"); }

    if (not -X $COLMET_EXTRACT_PATH) {
       OAR::API::ERROR( 400, "Missing extractor script",
        "You have to install the colmet extraction script ($COLMET_EXTRACT_PATH), python and the h5py module.\nPlease, check https://github.com/oar-team/colmet/oar/api." );
    }

    my $stop_time=@$job[0]->{'stop_time'};
    if ($stop_time==0) { 
        my $dbh = OAR::IO::connect() or OAR::API::ERROR(500,
                                                "Cannot connect to the database",
                                                "Cannot connect to the database"
                                                 );
        $stop_time=OAR::IO::get_date($dbh);
        OAR::IO::disconnect($dbh);
    }
    if (defined($q->param('to'))) {
      my $to = $q->param('to');
      if ($to < $stop_time) {
        $stop_time=$to;
      }
    }
    my $start_time=@$job[0]->{'start_time'};
    if (defined($q->param('from'))) {
      my $from = $q->param('from');
      if ($from > $start_time) {
        $start_time=$from;
      }
    }
    my $metrics="ac_etime,cpu_run_real_total,coremem,read_bytes,write_bytes";
    if (defined($q->param('metrics'))) {
      $metrics=$q->param('metrics'); 
    }
    my $cmd="$COLMET_EXTRACT_PATH $COLMET_HDF5_PATH_PREFIX $jobid $start_time $stop_time $metrics";
    my $cmdRes = OAR::API::send_cmd($cmd,"Oar");    

    print $header;
    print $cmdRes;
    last;
  };
  #}}}

  ###########################################
  # Html stuff
  ###########################################
  #
  #{{{ GET /index : Welcome page (html only)
  #
  $URI = qr{^/index\.html$};
  OAR::API::GET( $_, $URI ) && do {
    print $q->header( -status => 200, -type => "text/html" );
    print $HTML_HEADER;
    print "Welcome on the oar API\n";
    last;
  };
  #}}}
  #
  #{{{ GET /jobs/form : Html form for job posting
  #
  $URI = qr{^/jobs/form.html$};
  OAR::API::GET( $_, $URI ) && do {
    (my $header, my $type)=OAR::API::set_output_format("html");
    print $header;
    print $HTML_HEADER;
    my $POSTFORM="";
    my $file;
    if (is_conf("API_HTML_POSTFORM")){ $file=get_conf("API_HTML_POSTFORM"); }
    else { $file="/etc/oar/api_html_postform.pl"; }
    open(FILE,$file);
    my(@lines) = ;
    eval join("\n",@lines);
    close(FILE);
    print $POSTFORM;
    last;
  };
  #}}}
  #
  #{{{ GET /admission_rules/form : Html form for admission rules submission
  #
  $URI = qr{^/admission_rules/form.html$};
  OAR::API::GET( $_, $URI ) && do {
    (my $header, my $type)=OAR::API::set_output_format("html");
    print $header;
    print $HTML_HEADER;
    my $POSTFORM="";
    my $file = "/etc/oar/api_html_postform_rule.pl";
    open(FILE,$file);
    my(@lines) = ;
    eval join("\n",@lines);
    close(FILE);
    print $POSTFORM;
    last;
  };
  #}}}
  #
  #{{{ GET /resources/form : Html form for resources generation
  #
  $URI = qr{^/resources/form.html$};
  OAR::API::GET( $_, $URI ) && do {
    (my $header, my $type)=OAR::API::set_output_format("html");
    print $header;
    print $HTML_HEADER;
    my $POSTFORM="";
    my $file = "/etc/oar/api_html_postform_resources.pl";
    open(FILE,$file);
    my(@lines) = ;
    eval join("\n",@lines);
    close(FILE);
    print $POSTFORM;
    last;
  };
  #}}}
  #
  
  ###########################################
  # Misc
  ###########################################
  #
  #{{{ GET /stress_factor/ : return the stress factor of the given cluster
  #
  $URI = qr{^/stress_factor\.*(yaml|json|html)*$};
  OAR::API::GET( $_, $URI ) && do {
        $_->path_info =~ m/$URI/;
    my $ext = OAR::API::set_ext($q,$1);
    (my $header, my $type) = OAR::API::set_output_format($ext);

    my $stress_factor_script="/etc/oar/stress_factor.sh";
    if (is_conf("API_STRESS_FACTOR_SCRIPT")){ $stress_factor_script=get_conf("API_STRESS_FACTOR_SCRIPT"); }

    my $cmd = "$OARDODO_CMD bash --noprofile --norc -c \"$stress_factor_script\"";
    my $cmdRes = `$cmd 2>&1`;

    my %output=(  "api_timestamp" => time(),
                  "links" => [
                      { 'rel' => 'self' ,
                        'href' => OAR::API::htmlize_uri(OAR::API::make_uri("stress_factor",$ext,0),$ext)
                      } ]
               );

    my @lines=split("\n",$cmdRes);

    foreach my $line (@lines) {
      if ($line =~ qr{^\s*(.+)\s*=\s*(.+)\s*}) {
        my ($key,$val) = ($1,$2);
        $output{$key}=$val;
      }
    }

    print $header;
    print $HTML_HEADER if ($ext eq "html");
    print OAR::API::export(\%output,$ext);
    last;
  };
  #}}}

  ###########################################
  # Anything else -> 404
  ###########################################
  #
  OAR::API::ERROR( 404, "Not found", "No way to handle your request " . $q->path_info );
}

if ($fcgi_cycle_count > 50) {
  exit 0;
}

} # End of fastcgi loop

oar-2.5.7/sources/api/stress_factor.sh0000755015014700017500000000225112677211234017402 0ustar  neyronneyron#!/bin/bash
# Sample script for stress_factor
# This script should return at least a real value between 0 and 1 that is given by 
# the OAR api for the "GET /stress_factor" URI.
# Warning: this script is run by root and the output is parsed as a list of
# variables as is!
# - A stress_factor of 0 means that everything is fine
# - A stress_factor of 1 (or more) means that the resources manager is under
# stress. That generally means that it doesn't want to manage anymore jobs!
# - Any value between 0 and 1 is allowed to define the level of stress.
# It allows the administrator to define custom criterias to tell other systems
# (those using the API) that they maybe should reduce or stop to query this
# OAR system for a while. So, this script is meant to be polled regularly.
# The script should return at least the variable "GLOBAL_STRESS=" but it
# may also provide other custom defined values.

# Load the OAR configuration 
. /etc/oar/oar.conf

# By default, returns the load of the OAR server or 1 if could not get it
global_stress=`(su - oar -c "$OPENSSH_CMD $SERVER_HOSTNAME cat /proc/loadavg" 2>/dev/null|| echo 1)| cut -f 1 -d" "`
echo -n "GLOBAL_STRESS="
echo $global_stress

oar-2.5.7/sources/api/INSTALL0000644015014700017500000000327012677211234015215 0ustar  neyronneyronInstallation of the OAR RESTful user API
========================================

Configuring OAR
---------------
For the moment, the API needs the user tools to be installed on the same host ('make user-install' or oar-user package). A suitable /etc/oar/oar.conf should be present. For the API to work, you should have the oarstat/oarnodes/oarsub commands to work (on the same host you installed the API)

Installing the API files
------------------------
 - From sources: Download OAR and do "make api-install" as the root user.
 - From Debian packages: apt-get install oar-api
 - From RPM packages: yum install oar-api

Configuring apache
------------------
The api provides a default configuration file (/etc/oar/apache-api.conf) that
is using a identd user identification enabled only from localhost.
Edit the /etc/oar/apache-api.conf file and customize it to reflect the authentication mechanism you want to use. For ident, you may have to install a "identd" daemon on your distrib. The steps may be:
 - Install and run a identd daemon on your server
 - Activate the ident auth mechanism into apache (a2enmod ident)
 - Activate the headers apache module (a2enmod headers)
 - Customize apache-api.conf to allow the hosts you trust for ident

YAML, JSON, XML
---------------
You need at least one of the YAML or JSON perl module to be installed on the host running the API.

Test
----
You may test the API with a simple wget:

 wget -O - http://localhost:/oarapi/resources.html

It should give you the list of resources in the yaml format but enclosed in an html page.
To test if the authentication works, you need to post a new job. See the example.txt file that gives you example queries with a ruby rest client.
oar-2.5.7/sources/visualization_interfaces/0000755015014700017500000000000012677211234020515 5ustar  neyronneyronoar-2.5.7/sources/visualization_interfaces/Monika/0000755015014700017500000000000012677211234021733 5ustar  neyronneyronoar-2.5.7/sources/visualization_interfaces/Monika/VERSION0000755015014700017500000000000612677211234023002 0ustar  neyronneyron0.6.2
oar-2.5.7/sources/visualization_interfaces/Monika/lib/0000755015014700017500000000000012677211234022501 5ustar  neyronneyronoar-2.5.7/sources/visualization_interfaces/Monika/lib/OAR/0000755015014700017500000000000012677211234023122 5ustar  neyronneyronoar-2.5.7/sources/visualization_interfaces/Monika/lib/OAR/Monika/0000755015014700017500000000000012677211234024340 5ustar  neyronneyronoar-2.5.7/sources/visualization_interfaces/Monika/lib/OAR/Monika/OAR.pm0000755015014700017500000004175312677211234025334 0ustar  neyronneyron## Modified on November 2007 by Joseph.Emeras@imag.fr
## added: OAR2 compatibility
##        added methods used for managing OAR2 nodes and display

## This package handles OAR stuff...
## It uses OARNode.pm and OARJob.pm to store nodes and Jobs descriptions

package OAR::Monika::OAR;

use strict;
use warnings;
use Data::Dumper;
use OAR::Monika::Conf;
use OAR::Monika::db_io;
use OAR::Monika::OARNode;
use OAR::Monika::OARJob;
use Tie::IxHash;

## Class constructor
sub new {
  my $proto = shift;
  my $class = ref($proto) || $proto;
  my $self = {};
  $self->{ALLNODES} = {};
  $self->{PROPERTIES} = {};
  $self->{ALLJOBS} = {};
  bless ($self,$class);
  return $self;
}

## return all nodes
sub allnodes {
  my $self = shift;
  return $self->{ALLNODES};
}

sub properties {
  my $self = shift;
  return $self->{PROPERTIES};
}

## acces DataBase and get information about nodes
sub oarnodes {

  my $self = shift;
  my $hostname= OAR::Monika::Conf::myself->hostname;
  my $port = OAR::Monika::Conf::myself->dbport;
  my $dbtype= OAR::Monika::Conf::myself->dbtype;
  my $dbname= OAR::Monika::Conf::myself->dbname;
  my $username= OAR::Monika::Conf::myself->username;
  my $pwd= OAR::Monika::Conf::myself->password;

  my $dbh = OAR::Monika::db_io::dbConnection($hostname, $port, $dbtype, $dbname, $username, $pwd);
  my @nodeNames= OAR::Monika::db_io::list_nodes($dbh);
  foreach my $currentNode (@nodeNames){
	next unless $currentNode;
    my @currentNodeRessources= OAR::Monika::db_io::get_all_resources_on_node($dbh, $currentNode);
    my %hashInfoCurrentNodeRessources;
    foreach my $currentRessource (@currentNodeRessources){
      my %hashInfosJobs;
      $hashInfosJobs{infos}= OAR::Monika::db_io::get_resource_info($dbh, $currentRessource);## get_resource_info returns a hash ref
      my @jobs= OAR::Monika::db_io::get_resource_job($dbh, $currentRessource);## get_resource_job returns an array
      $hashInfosJobs{jobs}= \@jobs;
      $hashInfoCurrentNodeRessources{$currentRessource}= \%hashInfosJobs;
    }
    if ( $currentNode =~ OAR::Monika::Conf::myself()->nodenameRegex() ) {
      my $node= new OAR::Monika::OARNode($currentNode, \%hashInfoCurrentNodeRessources);
      $self->allnodes()->{$node->displayname} = $node;
    }
  }
  OAR::Monika::db_io::dbDisconnect($dbh);
}

## retrieve a OAR job description.
sub getJobProperties {
  my $myself = shift;
  my $currentJobId = shift;
  my $cgi = shift;
  my $hostname= OAR::Monika::Conf::myself->hostname;
  my $port = OAR::Monika::Conf::myself->dbport;
  my $dbtype= OAR::Monika::Conf::myself->dbtype;
  my $dbname= OAR::Monika::Conf::myself->dbname;
  my $username= OAR::Monika::Conf::myself->username;
  my $pwd= OAR::Monika::Conf::myself->password;

  my $dbh = OAR::Monika::db_io::dbConnection($hostname, $port, $dbtype, $dbname, $username, $pwd);
  
  my $jobInfos= OAR::Monika::db_io::get_job_stat_infos($dbh, $currentJobId);
  my $job = OAR::Monika::OARJob->new($currentJobId);
  foreach my $key (keys %{$jobInfos}){
    my $value= $jobInfos->{$key};
    $job->set($key,$value,$cgi);
  }

  ## let's count the nodes and cpu used.

  my $structure= OAR::Monika::db_io::get_resources_data_structure_current_job($dbh, $currentJobId);
  my $parrayRessources= $structure->[0]->[0]->[0]->{'resources'};
  my $property= $structure->[0]->[0]->[0]->{'property'};
  my $walltime= $structure->[0]->[1];
  my $string= "-l \"{$property}";
  foreach my $ressourceGroup (@$parrayRessources){
    $string.= "/".$ressourceGroup->{resource}."=".$ressourceGroup->{value};
  }

  my $sec=$walltime%60;
  $walltime/=60;
  my $min=$walltime%60;
  $walltime = int($walltime / 60);
  my $hour=$walltime;
  my $hWallTime= "$hour:$min:$sec";
  $job->set("walltime",$hWallTime,$cgi);
  $string.=",walltime=$hWallTime\"";
  $job->set("wanted_resources",$string,$cgi);

  ## dates formatting
  my $submission_time= $job->get("submission_time");
  #my ($year,$mon,$mday,$hour,$min,$sec)= OAR::Monika::db_io::local_to_ymdhms($submission_time);
  #$submission_time= "$year-$mon-$mday $hour:$min:$sec";
  $job->set("submission_time",OAR::Monika::db_io::local_to_sql($submission_time),$cgi);

  my $start_time= $job->get("start_time");
  $job->set("start_time",OAR::Monika::db_io::local_to_sql($start_time),$cgi);

  my $stop_time= $job->get("stop_time");
  $job->set("stop_time",OAR::Monika::db_io::local_to_sql($stop_time),$cgi);
  OAR::Monika::db_io::dbDisconnect($dbh);
  return $job;
}

## retrieve OAR jobs description and store them in the ALLJOBS hash.
sub qstat {
  my $self = shift;
  my $cgi = shift;
  my $hostname= OAR::Monika::Conf::myself->hostname;
  my $port = OAR::Monika::Conf::myself->dbport;
  my $dbtype= OAR::Monika::Conf::myself->dbtype;
  my $dbname= OAR::Monika::Conf::myself->dbname;
  my $username= OAR::Monika::Conf::myself->username;
  my $pwd= OAR::Monika::Conf::myself->password;

  my $dbh = OAR::Monika::db_io::dbConnection($hostname, $port, $dbtype, $dbname, $username, $pwd);
  my @jobIds= OAR::Monika::db_io::get_queued_jobs($dbh);
  foreach my $currentJobId (@jobIds){
    my $jobInfos= OAR::Monika::db_io::get_job_stat_infos($dbh, $currentJobId);
    my $job = OAR::Monika::OARJob->new($currentJobId);
    foreach my $key (keys %{$jobInfos}){
      my $value= $jobInfos->{$key};
      $job->set($key,$value,$cgi);
    }

    ## let's count the nodes and cpu used.

    my $structure= OAR::Monika::db_io::get_resources_data_structure_current_job($dbh, $currentJobId);
    my $parrayRessources= $structure->[0]->[0]->[0]->{'resources'};
    my $property= $structure->[0]->[0]->[0]->{'property'};
    my $walltime= $structure->[0]->[1];
    my $string= "-l \"{$property}";
    foreach my $ressourceGroup (@$parrayRessources){
      $string.= "/".$ressourceGroup->{resource}."=".$ressourceGroup->{value};
    }

    my $sec=$walltime%60;
    $walltime/=60;
    my $min=$walltime%60;
    $walltime = int($walltime / 60);
    my $hour=$walltime;
    my $hWallTime= "$hour:$min:$sec";
    $job->set("walltime",$hWallTime,$cgi);
    $string.=",walltime=$hWallTime\"";
    $job->set("wanted_resources",$string,$cgi);

    ## dates formatting
    my $submission_time= $job->get("submission_time");
    #my ($year,$mon,$mday,$hour,$min,$sec)= OAR::Monika::db_io::local_to_ymdhms($submission_time);
    #$submission_time= "$year-$mon-$mday $hour:$min:$sec";
    $job->set("submission_time",OAR::Monika::db_io::local_to_sql($submission_time),$cgi);

    my $start_time= $job->get("start_time");
    if($start_time ne '0'){
      $job->set("start_time",OAR::Monika::db_io::local_to_sql($start_time),$cgi);
    }
    else{
      $job->set("start_time", "n/a", $cgi);
    }
    my @scheduled_start_array= OAR::Monika::db_io::get_gantt_job_start_time($dbh, $currentJobId);
    my $scheduled_start= $scheduled_start_array[0];
    if(defined $scheduled_start && $scheduled_start ne '0'){
      $job->set("scheduled_start",OAR::Monika::db_io::local_to_sql($scheduled_start),$cgi);
    }
    else{
      $job->set("scheduled_start", "no prediction", $cgi);
    }

    $self->alljobs()->{$currentJobId} = $job;
  }
  OAR::Monika::db_io::dbDisconnect($dbh);
}


## return nodes verifying a property
sub nodelistByProperty {
  my $self = shift;
  my $property = shift;
  my @nodes = values %{$self->allnodes};
  my %alreadyCounted;
  my @nodesSelected;
  foreach my $node(@nodes){
    my %hashRessProp= $node->properties();
    foreach my $ress (keys %hashRessProp){
          my %hashProp= %{$hashRessProp{$ress}};
          foreach my $p (keys %hashProp) {
                  my $hidden = undef;
                  my $prop= $p."=".(defined($hashProp{$p})?$hashProp{$p}:"?");
                  if($prop eq $property){
                    unless (defined($alreadyCounted{$node})){
                      $alreadyCounted{$node}= 1;
                      push @nodesSelected, $node->name;
                      #push @nodesSelected, $node->displayHTMLname;
                    }
                  }
          }
    }
  }
  #print STDOUT Dumper(@nodesSelected);
  return \@nodesSelected;
}

## return all jobs
sub alljobs {
  my $self = shift;
  return $self->{ALLJOBS};
}

## print a HTML summary table of the current usage of the nodes.
sub htmlSummaryTable {
  my $self = shift;
  my $cgi = shift;
  my $output = "";
  my $summary_display = OAR::Monika::Conf::myself->summary_display;
  my $nodes_synonym = OAR::Monika::Conf::myself->nodes_synonym;
  $summary_display = $summary_display.";";  ## add a ., to the end for parsing the string
  my %hash_display;
  tie %hash_display, "Tie::IxHash"; ## for hash insertion order
  while($summary_display ne ""){
    $summary_display =~ s/(.*?);//;
    my $tmp=$1;
    my $key;
    if($tmp =~ m/(.*?):/){
      $tmp = $tmp.",";
      $tmp =~ s/(.*?)://;
      $key = ($1);
      my @array_values;
      while($tmp ne ""){
        $tmp =~ s/(.*?),//;
        my $value = $1;
        if($value eq 'nodes_synonym'){
          $value = $nodes_synonym;
        }        
        push @array_values, $value;
      }
      $hash_display{$key} = \@array_values;
    }
    else{
      $key = $tmp;
      my @array_values;
      push @array_values, "resource_id";
      $hash_display{"$key"} = \@array_values;
    }
  }
  $output .= $cgi->start_table({-border=>"1",
		     -align =>"center"
		    });
	$output .= $cgi->start_Tr({-align => "center"});
  my $pt_resources = $self->getResources();
  foreach my $type_res (keys %hash_display){
  	$output .= $cgi->td();
    $output .= $cgi->start_table({-border=>"1",-align =>"center"});
		$output .= $cgi->start_Tr({-align => "center"});
	  $output .= $cgi->td($cgi->i($cgi->u($type_res." summary")));
	  $output .= $cgi->end_Tr();
    $output .= $cgi->start_Tr({-align=>"center"});
    $output .= $cgi->td($cgi->i(""));
    $output .= $cgi->td($cgi->b("Free"));
    $output .= $cgi->td($cgi->b("Busy"));
    $output .= $cgi->td($cgi->b("Total"));
    $output .= $cgi->end_Tr();
    if($type_res eq 'default'){
      foreach my $val (@{$hash_display{$type_res}}){
        $output .= $cgi->td($cgi->b($val));
        my ($free, $busy, $total) = $self->resourceCount($type_res, $val, $pt_resources);
        $output .= $cgi->td([$free, $busy, $total]);
        $output .= $cgi->end_Tr();
      }
    }
    else{
      foreach my $val (@{$hash_display{$type_res}}){
        my ($free, $busy, $total) = $self->resourceCount($type_res, $val, $pt_resources);
        $output .= $cgi->td($cgi->b($val));
        $output .= $cgi->td([$free, $busy, $total]);
        $output .= $cgi->end_Tr();
      }
    }  
    $output .= $cgi->end_table();
  }
  $output .= $cgi->end_Tr();
  $output .= $cgi->end_table();
  return $output;
}
sub getResources{
  my $self = shift;
  my %resources;
  foreach my $resource_name (keys %{$self->{'ALLNODES'}}){
    foreach my $resource_id (keys %{$self->{'ALLNODES'}->{$resource_name}->{'Ressources'}}){
      $resources{$resource_id} = $self->{'ALLNODES'}->{$resource_name}->{'Ressources'}->{$resource_id};
    }
  }
  return \%resources;
}

## compute a summary of the usage of OAR nodes
sub resourceCount($$$$) {
  my $self = shift;
  my $type_resource = shift;
  my $att_name = shift;
  my $all_resources = shift;
  my ($free, $busy, $total) = (0,0,0);
  my %hashtotal;
  my %hashfree;
  my %alreadyCounted;
  my @associated_resources;
  foreach my $resource_id (keys %{$all_resources}){
    foreach my $att (keys %{$all_resources->{$resource_id}->{'infos'}}){   
      my $value= $all_resources->{$resource_id}->{'infos'}->{$att};
      if($att eq $att_name && $type_resource eq $all_resources->{$resource_id}->{'infos'}->{'type'}){
        push @associated_resources, $resource_id;
        unless(exists $alreadyCounted{$value}){
          $total++;
          if(!(@{$all_resources->{$resource_id}->{'jobs'}} > 0)){
            if($all_resources->{$resource_id}->{'infos'}->{'state'} eq 'Alive'){
              $hashfree{"$value:$att:$type_resource"}++;
            }
          }
          $alreadyCounted{$value} = "$att:$type_resource";
          $hashtotal{"$value:$att:$type_resource"} = 1;
        }
        else{
          $hashtotal{"$value:$att:$type_resource"}++;
          unless(@{$all_resources->{$resource_id}->{'jobs'}} > 0){
            $hashfree{"$value:$att:$type_resource"}++;
          }
        }
      }
    }
  }
  my %cpt_att;
  foreach (@associated_resources){
    if(@{$all_resources->{$_}->{'jobs'}} > 0){
      my $value= $all_resources->{$_}->{'infos'}->{$att_name};
      $cpt_att{$value} = '';
    }  
  }
  foreach (keys %cpt_att){
    $busy++;
  }
  foreach (keys %hashfree){
    if($hashfree{$_} eq $hashtotal{$_}){
      $free++;
    }
  }
  return ($free, $busy, $total);
}

## print a HTML tables describing current OAR jobs.
sub htmlJobTable {
  my $self = shift;
  my $cgi = shift;
  my $output = "";
#  $output .= $cgi->start_form();
  $output .= $cgi->start_table({-border=>"1", -align => "center"});
  my $alljobs = $self->alljobs();
  my @keys = keys %$alljobs;
  if ($#keys < 0) {
    $output .= $cgi->Tr($cgi->td("No job currently in queues"));
  } else {

        $output .= $cgi->start_Tr();
        $output .= $cgi->td({-align => "center"},"Id");
        $output .= $cgi->td({-align => "center"},"User");
        $output .= $cgi->td({-align => "center"},"State");
        $output .= $cgi->td({-align => "center"},"Queue");
        $output .= $cgi->td({-align => "center"},"Name");
        #$output .= $cgi->td({-align => "center"},"NbNodes");
        #$output .= $cgi->td({-align => "center"},"NbCores");
        $output .= $cgi->td({-align => "center"},"wanted_resources");
        $output .= $cgi->td({-align => "center"},"Type");
        $output .= $cgi->td({-align => "center"},"Properties");
        $output .= $cgi->td({-align => "center"},"Reservation");
        $output .= $cgi->td({-align => "center"},"Walltime");
        $output .= $cgi->td({-align => "center"},"Submission Time");
        $output .= $cgi->td({-align => "center"},"Start Time");
#        $output .= $cgi->td({-align => "center"},"Comment");
        $output .= $cgi->td({-align => "center"},"Scheduled Start");
        $output .= $cgi->end_Tr();

    @keys = sort {$a <=> $b} @keys;
    foreach my $key (@keys) {
      $output .= $alljobs->{$key}->htmlTableRow($cgi);
    }
  }
  $output .= $cgi->end_table();
  return $output;
}

sub htmlPropertyChooser {
  my $self = shift;
  my $cgi = shift;
  my $output = "";
	# do not show hidden properties...
	my @checkboxes = ();
  my @hiddenProperties = OAR::Monika::Conf::myself()->hiddenProperties();
  my @nodes = values %{$self->allnodes};
  #my %alreadyCounted;  
  my %hiddenHash;
  foreach(@hiddenProperties){
    $hiddenHash{$_} = '';
  }
  my $hostname= OAR::Monika::Conf::myself->hostname;
  my $port = OAR::Monika::Conf::myself->dbport;
  my $dbtype= OAR::Monika::Conf::myself->dbtype;
  my $dbname= OAR::Monika::Conf::myself->dbname;
  my $username= OAR::Monika::Conf::myself->username;
  my $pwd= OAR::Monika::Conf::myself->password;
  my $dbh = OAR::Monika::db_io::dbConnection($hostname, $port, $dbtype, $dbname, $username, $pwd);
  my $result = OAR::Monika::db_io::get_properties_values($dbh, \%hiddenHash);
  OAR::Monika::db_io::dbDisconnect($dbh);
  my %hashcheckboxes;
  foreach(keys %{$result}){
    foreach my $prop (keys %{$result->{$_}}){
      if(defined($result->{$_}->{$prop})){
        my $str = $prop."=".$result->{$_}->{$prop};
        $hashcheckboxes{$str} = '';
      }
    }
  }
  foreach(keys %hashcheckboxes){
    push @checkboxes, $_;
  }
  # old one, very slow...
  #foreach my $node(@nodes){
  #  my %hashRessProp= $node->properties();
  #  foreach my $ress (keys %hashRessProp){
  #        my %hashProp= %{$hashRessProp{$ress}};
  #        foreach my $p (keys %hashProp) {
  #                my $hidden = undef;
  #                my $prop= $p."=".$hashProp{$p};
  #                foreach my $h (@hiddenProperties) {
  #                        $prop =~ /^$h=/ and $hidden = 1;
  #                }
  #                unless (defined($alreadyCounted{$prop})){
  #                  defined $hidden or push @checkboxes, $prop;
  #                  $alreadyCounted{$prop}= 1;
  #                }
  #        }
  #  }
  #}
  if ($#checkboxes >= 0) {
    my @sortedCheckboxes= sort { $a cmp $b } @checkboxes;
    $output .= $cgi->start_div({ -align => "center" });
    $output .= $cgi->start_form({ -method => "get" });
    $output .= $cgi->b("OAR properties:");
    $output .= $cgi->checkbox_group({
				    -name=> 'props',
				    -values=> \@sortedCheckboxes,
				    -columns => 5,
				     -title => "click to select property"
				    });
    $output .= $cgi->submit("Action","Display nodes for these properties");
    $output .= $cgi->end_div();
    $output .= $cgi->end_form();
  }
  return $output;
}

sub htmlNodeByProperty {
  my $self = shift;
  my $cgi = shift;
  my $output = "";
  my @selected = sort $cgi->param('props');
  #my @nodesList;
  foreach my $prop (@selected) {
    if (defined($self->nodelistByProperty($prop))){
        $output .= $cgi->h3({-align => "center"}, "Reservations for property $prop:");
        #push @nodesList, @{$self->nodelistByProperty($prop)};
        $output .= $cgi->nodeReservationTable($self->allnodes(),$self->nodelistByProperty($prop));
    }
  }
  #$output .= $cgi->nodeReservationTable($self->allnodes(),\@nodesList);
  return $output;
}

## that's all.
return 1;

oar-2.5.7/sources/visualization_interfaces/Monika/lib/OAR/Monika/Conf.pm0000755015014700017500000001601212677211234025566 0ustar  neyronneyron## Modified on November 2007 by Joseph.Emeras@imag.fr
## added: OAR2 compatibility
## This package handles monika.conf file.
## it uses ConfNode.pm to store nodes description got from the configuration file.
package OAR::Monika::Conf;

use strict;
use warnings;
use AppConfig qw(:expand :argcount);
use OAR::Monika::ConfNode;

## class constructor
my $myself;

sub new {
  my $proto = shift;
  my $class = ref($proto) || $proto;
  my $self = {};
  $self->{ALLNODES} = {};
  bless ($self, $class);
  $myself = $self;
  return $self;
}

sub myself () {
  defined $myself or die "do first a new and parse please...";
  return $myself;
}

## parse config file
sub parse {
  my $self = shift;
  if (@_) {
    $self->{FILE} = shift;
  } else {
    $self->{FILE} = "/etc/oar/monika.conf";
  }
  my $config = AppConfig->new({
				  GLOBAL => {
					     DEFAULT  => "",
					     ARGCOUNT => ARGCOUNT_ONE,
					    }
				 });
  $config->define("clustername",
		  {
		   DEFAULT => "Cluster"
		  });
  $config->define("max_cores_per_line",
		  {
		   DEFAULT => "16"
		  });
	$config->define("css_path",
		  {
		   DEFAULT => "/monika.css"
		  });
  $config->define("gridname",
		  {
		   DEFAULT => "Grid"
		  });
  $config->define("summary_display",
		  {
		   DEFAULT => "default"
		  });
  $config->define("hostname",
		  {
		   DEFAULT => ""
		  });
	$config->define("dbport",
		  {
		   DEFAULT => ""
		  });
  $config->define("nodes_synonym",
		  {
		   DEFAULT => "resource_id"
		  });
  $config->define("dbtype",
		  {
		   DEFAULT => ""
		  });
  $config->define("dbname",
		  {
		   DEFAULT => ""
		  });
  $config->define("username",
		  {
		   DEFAULT => ""
		  });
  $config->define("password",
		  {
		   DEFAULT => ""
		  });
  $config->define("nodes_per_line",
		  {
		   DEFAULT => 10
		  });
  $config->define("nodename_regex",
		  {
		   DEFAULT => '(.*)'
		  });
  $config->define("nodename_regex_display",
		  {
		   DEFAULT => '(.*)'
		  });
  $config->define("loadimgpath",
      {
       DEFAULT => "/tmp/"
      });
  $config->define("oargridstat",
		  {
		   DEFAULT => "oargridstat --monitor"
		  });
  $config->define("server_do_mail",
		  {
		   DEFAULT => "no",
		  });
  $config->define("user_infos",
                  {
                   DEFAULT => "",
                  });
  $config->define("node_group",
		  {
		   ARGCOUNT => ARGCOUNT_HASH
		  });
  $config->define("default_state",
		  {
		   ARGCOUNT => ARGCOUNT_HASH
		  });
  $config->define("set_color",
		  {
		   ARGCOUNT => ARGCOUNT_HASH
		  });
  $config->define("color_pool",
		  {
		   ARGCOUNT => ARGCOUNT_LIST
		  });
  $config->define("hidden_property",
		  {
		   ARGCOUNT => ARGCOUNT_LIST
		  });
  $config->file($self->{FILE});

  $self->{CLUSTERNAME} = $config->clustername();
  $self->{MAXCORESPERLINE} = $config->max_cores_per_line();
  $self->{CSS_PATH} = $config->css_path();
  $self->{GRIDNAME} = $config->gridname();
  $self->{SUMMARY_DISPLAY} = $config->summary_display();
  $self->{HOSTNAME} = $config->hostname();
  $self->{DBPORT} = $config->dbport();
  $self->{NODES_SYNONYM} = $config->nodes_synonym();
  $self->{DBTYPE} = $config->dbtype();
  $self->{DBNAME} = $config->dbname();
  $self->{USERNAME} = $config->username();
  $self->{PASSWORD} = $config->password();
  $self->{NODESPERLINE} = $config->nodes_per_line();
  my $regex = $config->nodename_regex();
  $self->{NODENAMEREGEX} = qr/$regex/;
  my $regex_display = $config->nodename_regex_display();
  $self->{NODENAMEREGEXDISPLAY} = qr/$regex_display/;
  $self->{LOADIMGPATH} = $config->loadimgpath();
  $self->{OARGRIDSTATCMD} = $config->oargridstat();
  $self->{SERVER_DO_MAIL} = $config->server_do_mail();
  $self->{NODE_GROUP} = $config->node_group();
  $self->{DEFAULT_STATE} = $config->default_state();
  $self->{SET_COLOR} = $config->set_color();
  $self->{COLOR_POOL} = $config->color_pool();
  $self->{HIDDEN_PROPERTIES} = $config->hidden_property();
  $self->{USER_INFOS} = $config->user_infos();

  my $allnodes = $self->{ALLNODES};

  foreach my $nodeType (keys %{$self->{NODE_GROUP}}) {
    my $state;
    if ($self->{DEFAULT_STATE}->{$nodeType}) {
      $state = $self->{DEFAULT_STATE}->{$nodeType};
    } else {
      $state = $nodeType;
    }
    my @nodes = split /\s+/,$self->{NODE_GROUP}->{$nodeType};
    foreach (@nodes) {
      if (/^(\d+)-(\d+)$/) {
	foreach ($1..$2) {
	  $allnodes->{$_} = OAR::Monika::ConfNode->new($_,$state);
	}
      } else {
	$allnodes->{$_} = OAR::Monika::ConfNode->new($_,$state);
      }
    }
  }
  return 1;
}

## return cluster name
sub clustername {
  my $self = shift;
  return $self->{CLUSTERNAME};
}

## return max cores to display per line
sub max_cores_per_line {
  my $self = shift;
  return $self->{MAXCORESPERLINE};
}
## return css path
sub css_path {
  my $self = shift;
  return $self->{CSS_PATH};
}

## return grid name
sub gridname {
  my $self = shift;
  return $self->{GRIDNAME};
}

## return summary_display properties
sub summary_display {
  my $self = shift;
  return $self->{SUMMARY_DISPLAY};
}

## return the hostname
sub hostname {
  my $self = shift;
  return $self->{HOSTNAME};
}

## return the db port
sub dbport {
  my $self = shift;
  return $self->{DBPORT};
}

## return the nodes_synonym
sub nodes_synonym {
  my $self = shift;
  return $self->{NODES_SYNONYM};
}

## return the dbtype
sub dbtype {
  my $self = shift;
  return $self->{DBTYPE};
}

## return the dbname
sub dbname {
  my $self = shift;
  return $self->{DBNAME};
}

## return the username
sub username {
  my $self = shift;
  return $self->{USERNAME};
}

## return the password
sub password {
  my $self = shift;
  return $self->{PASSWORD};
}

## return the number of node to be diplayed per line in the reservation table
sub nodes_per_line {
  my $self = shift;
  return $self->{NODESPERLINE};
}

## return the regex to extract a node display name from its real name
sub nodenameRegex {
  my $self = shift;
  return $self->{NODENAMEREGEX};
}

## return the regex to extract a the name displayed on the www page
sub nodenameRegexDisplay {
  my $self = shift;
  return $self->{NODENAMEREGEXDISPLAY};
}

## return oargridstat command (with arg) line as set in config file
sub oargridstatCmd {
  my $self = shift;
  return $self->{OARGRIDSTATCMD};
}

## return loadimgPath path
sub loadimgPath {
  my $self = shift;
  return $self->{LOADIMGPATH};
}



## return true if config file says server also is a mail server
sub server_do_mail {
  my $self = shift;
  $_ = $self->{SERVER_DO_MAIL};
  return (/^\s*yes\s*$/i or /^\s*true\s*$/i);
}

## return a hash containing (state,color) couples
sub colorHash {
  my $self = shift;
  return $self->{SET_COLOR};
}

sub colorPool {
  my $self = shift;
  return $self->{COLOR_POOL};
}

## return the list of properties not to be shown in the property chooser
sub hiddenProperties {
	my $self = shift;
	return @{$self->{HIDDEN_PROPERTIES}};
}

## return a hash containing all node descriptions got from the config file
sub allnodes {
  my $self = shift;
  return $self->{ALLNODES};
}

## retrun the string for property USER_INFOS
sub user_infos {
  my $self = shift;
  return $self->{USER_INFOS};
}

## that's all.
return 1;
oar-2.5.7/sources/visualization_interfaces/Monika/lib/OAR/Monika/OARJob.pm0000755015014700017500000001152612677211234025762 0ustar  neyronneyron## Created on November 2007 by Joseph.Emeras@imag.fr

## this package handles a OAR job description

package OAR::Monika::OARJob;

use strict;
#use warnings;
use OAR::Monika::monikaCGI;
use File::Basename;
use Data::Dumper;

my $bestEffortColor = "#dddddd";

## class constructor
sub new {
  my $proto = shift;
  my $class = ref($proto) || $proto;
  my $self = {};
  my $jobId = shift;
  defined $jobId or die "missing jobId !";
  $self->{job_id} = $jobId;
  bless ($self,$class);
  return $self;
}

sub jobId {
  my $self = shift;
  return $self->{job_id};
}

sub owner {
  my $self = shift;
  my $owner = $self->get("job_user");
  $owner =~ s/@.+//;
  return $owner;
}

sub set {
  my $self = shift;
  my $key = shift;
  defined $key or die "which key ?";
  my $value = shift;
  # for best effort jobs
  my $cgi = shift;
  # for best effort jobs
  #defined $value or die "which value for $key ?";
  #unless (exists $self->{$key}) {
    #$self->{$key} = [];
    $self->{$key} = $value;
  #}
  #push @{$self->{$key}},$value;

  # for best effort jobs
  if ($self->get("queue_name") eq "besteffort"){
    $cgi->setColor($self->jobId(),$bestEffortColor);
  }
  # for best effort jobs

  return 1;
}

sub get {
  my $self = shift;
  my $key = shift;
  defined $key or die "which key ?";
  if (exists $self->{$key}) {
    #return $self->{$key}->[0];
    return $self->{$key};
  } else {
    return undef;
  }
}

sub getList {
  my $self = shift;
  my $key = shift;
  defined $key or die "which key ?";
  exists $self->{$key} or die "Unknown key: ".$key;
  return $self->{$key};
}

sub htmlTableRow {
  my $self = shift;
  my $cgi = shift;

  my $output = "";
  $output .= $cgi->start_Tr();
  my $cgiName = File::Basename::basename($cgi->self_url(-query=>0));
  $output .= $cgi->colorTd($self->jobId(),undef,$cgiName."?job=".$self->jobId(), "click to see job details");
  if (OAR::Monika::Conf::myself()->server_do_mail()) {
    $output .= $cgi->td({-align => "center"},
			$cgi->a({
				 -href => "mailto:".$self->get("job_user"),
				 -title => "click to send mail"
				}, $self->owner()));
  } elsif (OAR::Monika::Conf::myself()->user_infos() ne "") {
    $output .= $cgi->td({-align => "center"},
                        $cgi->a({
                                 -href => OAR::Monika::Conf::myself()->user_infos().$self->get("job_user"),
                                 -title => "click for more informations"
                                }, $self->owner()));
  } else {
    $output .= $cgi->td({-align => "center"},$self->owner());
  }
  #Until now, we've displayed jobId and User...

  my $wanted_resources=$self->get("wanted_resources");
  my $walltime=$self->get("walltime");
  my $state= $self->get("state");
  my $queue= $self->get("queue_name");
  my $name= $self->get("job_name");
  my $type= $self->get("job_type");
  my $properties= $self->get("properties");
  my $reservation= $self->get("reservation");
  my $submission_time = $self->get("submission_time");
  my $start_time = $self->get("start_time");
  my $scheduled_start = $self->get("scheduled_start");
  my $initial_request = $self->get("initial_request");
  
  if($initial_request =~ / -t container/){
  	$type.=" - container";
  }
  elsif($initial_request =~ / -t inner=(\d+)/){
  	$type.=" - inner job (container=$1)";
  }
  elsif($initial_request =~ / -t timesharing/){
  	$type.=" - timesharing";
  }

  $output .= $cgi->td({-align => "center"},$state);
  $output .= $cgi->td({-align => "center"},$queue);
  $output .= $cgi->td({-align => "center"},$name);
  $output .= $cgi->td({-align => "center"},$wanted_resources);
  $output .= $cgi->td({-align => "center"},$type);
  $output .= $cgi->td({-align => "center"},$properties);
  $output .= $cgi->td({-align => "center"},$reservation);
  $output .= $cgi->td({-align => "center"},$walltime);
  $output .= $cgi->td({-align => "center"},$submission_time);
  $output .= $cgi->td({-align => "center"},$start_time);
  $output .= $cgi->td({-align => "center"},$scheduled_start);
  $output .= $cgi->end_Tr();
  return $output;
}

sub htmlStatusTable {
  my $self = shift;
  my $cgi = shift;
  my $output = "";
  $output .= $cgi->start_table({-border=>"1",
				 -align => "center"
				});
  $output .= $cgi->start_Tr();
  $output .= $cgi->th({-align => "left", bgcolor => "#c0c0c0"}, $cgi->i("Job Id"));
  $output .= $cgi->th({-align => "left"}, $self->jobId());
  $output .= $cgi->end_Tr();
  my @keylist = keys %{$self};
  foreach my $key (sort @keylist) {
    if(($key eq "job_id")){
    #if(($key eq "job_id") or ($key eq "initial_request")){
      next;
    }
    $output .= $cgi->start_Tr();
    $output .= $cgi->td({-valign => "top", bgcolor=> "#c0c0c0"}, $cgi->i($key));
    my $list = $self->getList($key);
    my $val = join $cgi->br(),$list;
    #$val =~ s/([+,]\s*)/\1
/g; $output .= $cgi->td($val); $output .= $cgi->end_Tr(); } $output .= $cgi->end_table(); return $output; } ## that's all. return 1; oar-2.5.7/sources/visualization_interfaces/Monika/lib/OAR/Monika/db_io.pm0000755015014700017500000003774212677211234025772 0ustar neyronneyron## Created on November 2007 by Joseph.Emeras@imag.fr package OAR::Monika::db_io; use DBI; use strict; use Data::Dumper; use warnings; use Time::Local; use POSIX qw(strftime); my $Db_type; sub get_database_type(){ return($Db_type); } my $nodes_synonym; ########################################################################################### ## Methods for Monika exclusively: # ########################################################################################### # Creates a connection to the DB and returns it sub dbConnection($$$$$$){ my $host = shift; my $port = shift; my $dbtype = shift; my $dbname = shift; my $user = shift; my $pwd = shift; if($dbtype eq "psql"){ $dbtype = "Pg"; } $Db_type = $dbtype; $nodes_synonym = OAR::Monika::Conf::myself->nodes_synonym; my $connection_string; if($port eq "" || !($port>1 && $port<65535)){ $connection_string = "DBI:$dbtype:database=$dbname;host=$host"; } else{ $connection_string = "DBI:$dbtype:database=$dbname;host=$host;port=$port"; } my $dbh= DBI->connect($connection_string, $user, $pwd, {AutoCommit => 1, RaiseError => 1}); return $dbh; } sub dbDisconnect($) { my $dbh = shift; # Disconnect from the database. $dbh->disconnect(); } # get_properties_values # returns the list of the fields of the job table and their values # usefull for the 'properties' section in Monika # parameters : base, list of excluded fields # return value : list of fields end values # side effects : / sub get_properties_values($$) { my $dbh = shift; my $excluded = shift; my @result; my $sth; if ($Db_type eq "Pg"){ #$sth = $dbh->prepare("SELECT a.attname # FROM pg_class AS c, pg_attribute AS a # WHERE relname = 'resources' AND c.oid = a.attrelid AND a.attnum > 0;"); $sth = $dbh->prepare("SELECT column_name FROM information_schema.columns WHERE table_name = \'resources\'"); } else{ $sth = $dbh->prepare("DESC resources"); } $sth->execute(); while (my $ref = $sth->fetchrow_hashref()){ my $current_value; if ($Db_type eq "Pg" || $Db_type eq "psql"){ $current_value = $ref->{'column_name'}; } else{ $current_value = $ref->{'Field'}; } unless (defined($excluded->{$current_value})){ push(@result, $current_value); } } $sth->finish(); my $str = "SELECT DISTINCT "; foreach(@result){ $str = $str.$_.", "; } $str = substr $str, 0, length($str) - 2; $str = $str." FROM resources;"; my $sth2 = $dbh->prepare($str); $sth2->execute(); my $ref; my $i = 0; while (my $current = $sth2->fetchrow_hashref()){ $i++; $ref->{$i} = $current; } $sth2->finish(); return $ref; } # get_all_resources_on_node # returns the current resources on node whose hostname is passed in parameter # parameters : base, hostname # return value : weight # side effects : / my %Resources_on_nodes; sub get_all_resources_on_node($$) { my $dbh = shift; my $hostname = shift; if (defined($Resources_on_nodes{$hostname})){ return(@{$Resources_on_nodes{$hostname}}); }else{ my $sth = $dbh->prepare(" SELECT resources.resource_id as resource, resources.$nodes_synonym as node FROM resources "); $sth->execute(); my @result; while (my $ref = $sth->fetchrow_hashref()){ push(@{$Resources_on_nodes{$ref->{node}}}, $ref->{resource}); } $sth->finish(); return(@{$Resources_on_nodes{$hostname}}); } } # get_queued_jobs # returns the list of queued jobs: running, waiting... # parameters : base # return value : list of jobid # side effects : / sub get_queued_jobs($) { my $dbh = shift; my $sth = $dbh->prepare(" SELECT jobs.job_id FROM (jobs INNER JOIN moldable_job_descriptions ON jobs.job_id = moldable_job_descriptions.moldable_job_id) LEFT JOIN assigned_resources ON assigned_resources.moldable_job_id = moldable_job_descriptions.moldable_job_id WHERE jobs.state IN (\'Waiting\',\'Hold\',\'toLaunch\',\'toError\',\'toAckReservation\',\'Launching\',\'Running\',\'Suspended\',\'Resuming\') "); $sth->execute(); my @res = (); while (my $ref = $sth->fetchrow_hashref()) { push(@res, $ref->{'job_id'}); } return @res; } # get_job_stat_infos # returns the information about the given job # parameters : base, job_id # return value : list of information # side effects : / my %Job_stat_infos; sub get_job_stat_infos($$) { my $dbh = shift; my $job= shift; if (defined($Job_stat_infos{$job})){ return($Job_stat_infos{$job}); }else{ my $sth = $dbh->prepare(" SELECT * FROM jobs WHERE jobs.job_id = $job "); $sth->execute(); my $ref = $sth->fetchrow_hashref(); $sth->finish(); $Job_stat_infos{$job} = $ref; return $ref; } } # get_job_cores # returns the list of cores used by the given job # parameters : base, job # return value : list of cores ressources # side effects : / #sub get_job_cores($$) { # my $dbh = shift; # my $job = shift; # my $sth = $dbh->prepare(" SELECT resources.resource_id # FROM ((jobs INNER JOIN moldable_job_descriptions ON moldable_job_descriptions.moldable_job_id = jobs.job_id) LEFT JOIN assigned_resources ON assigned_resources.moldable_job_id = moldable_job_descriptions.moldable_id) INNER JOIN resources ON assigned_resources.resource_id = resources.resource_id # WHERE # assigned_resources.assigned_resource_index = \'CURRENT\' # AND moldable_job_descriptions.moldable_index = \'CURRENT\' # AND jobs.job_id = $job # AND jobs.state != \'Terminated\' # AND jobs.state != \'Error\' # "); # $sth->execute(); # my @res = (); # while (my $ref = $sth->fetchrow_hashref()) { # push(@res, $ref->{'resource_id'}); # } # return @res; #} ########################################################################################### ## Methods from the OAR IOLIB: # ########################################################################################### # get_resource_job # returns the list of jobs associated to the resource passed in parameter # parameters : base, resource # return value : list of jobid # side effects : / my %Resource_job; my $Resource_job_init = 0; sub get_resource_job($$) { my $dbh = shift; my $resource = shift; if ($Resource_job_init > 0){ if (defined($Resource_job{$resource})){ return(@{$Resource_job{$resource}}); }else{ return(()); } }else{ my $sth = $dbh->prepare(" SELECT assigned_resources.resource_id, jobs.job_id FROM assigned_resources, moldable_job_descriptions, jobs WHERE assigned_resources.assigned_resource_index = \'CURRENT\' AND moldable_job_descriptions.moldable_index = \'CURRENT\' AND assigned_resources.moldable_job_id = moldable_job_descriptions.moldable_id AND moldable_job_descriptions.moldable_job_id = jobs.job_id AND jobs.state != \'Terminated\' AND jobs.state != \'Error\' "); $sth->execute(); my @res = (); $Resource_job_init++; while (my $ref = $sth->fetchrow_hashref()) { push(@{$Resource_job{$ref->{'resource_id'}}}, $ref->{'job_id'}); } if (defined($Resource_job{$resource})){ return(@{$Resource_job{$resource}}); }else{ return(()); } } } # list_nodes # gets the list of all nodes. # parameters : base # return value : list of hostnames # side effects : / sub list_nodes($) { my $dbh = shift; my $sth = $dbh->prepare(" SELECT distinct($nodes_synonym) FROM resources ORDER BY $nodes_synonym ASC "); $sth->execute(); my @res = (); while (my $ref = $sth->fetchrow_hashref()) { push(@res, $ref->{$nodes_synonym}); } $sth->finish(); return(@res); } # get_resource_info # returns a ref to some hash containing data for the nodes of the resource passed in parameter # parameters : base, resource id # return value : ref # side effects : / my %Resource_info; sub get_resource_info($$) { my $dbh = shift; my $resource = shift; if (defined($Resource_info{$resource})){ return($Resource_info{$resource}); }else{ my $sth = $dbh->prepare(" SELECT * FROM resources "); $sth->execute(); while (my $ref = $sth->fetchrow_hashref()) { $Resource_info{$ref->{resource_id}} = $ref; } $sth->finish(); return($Resource_info{$resource}); } } # Get start_time for a given job # args : base, job id my %Gantt_job_start_time; my $Gantt_job_start_time_init = 0; sub get_gantt_job_start_time($$){ my $dbh = shift; my $job = shift; if ($Gantt_job_start_time_init > 0){ if (defined($Gantt_job_start_time{$job})){ return($Gantt_job_start_time{$job},$job); }else{ return(undef); } }else{ $Gantt_job_start_time_init = 1; my $sth = $dbh->prepare("SELECT gantt_jobs_predictions_visu.start_time, moldable_job_descriptions.moldable_job_id FROM gantt_jobs_predictions_visu,moldable_job_descriptions WHERE moldable_job_descriptions.moldable_index = \'CURRENT\' AND moldable_job_descriptions.moldable_id = gantt_jobs_predictions_visu.moldable_job_id GROUP BY gantt_jobs_predictions_visu.start_time, moldable_job_descriptions.moldable_job_id "); $sth->execute(); while (my @res = $sth->fetchrow_array()){ $Gantt_job_start_time{$res[1]} = $res[0]; } $sth->finish(); if (defined($Gantt_job_start_time{$job})){ return($Gantt_job_start_time{$job},$job); }else{ return(undef); } } } # local_to_sql # converts a date specified in an integer local time format to the format used # by the sql database # parameters : date integer # return value : date string # side effects : / sub local_to_sql($) { my $local=shift; #my ($year,$mon,$mday,$hour,$min,$sec)=local_to_ymdhms($local); #return ymdhms_to_sql($year,$mon,$mday,$hour,$min,$sec); #return $year."-".$mon."-".$mday." $hour:$min:$sec"; return(strftime("%F %T",localtime($local))); } # Return a data structure with the resource description of the given job # arg : database ref, job id # return a data structure (an array of moldable jobs): # example for the first moldable job of the list: # $result = [ # [ # { # property => SQL property # resources => [ # { # resource => resource name # value => number of this wanted resource # } # ] # } # ], # walltime, # moldable_id # ] my %Resources_data_structure_current_job; sub get_resources_data_structure_current_job($$){ my $dbh = shift; my $job_id = shift; # my $sth = $dbh->prepare(" SELECT moldable_job_descriptions.moldable_id, job_resource_groups.res_group_id, moldable_job_descriptions.moldable_walltime, job_resource_groups.res_group_property, job_resource_descriptions.res_job_resource_type, job_resource_descriptions.res_job_value # FROM moldable_job_descriptions, job_resource_groups, job_resource_descriptions, jobs # WHERE # moldable_job_descriptions.moldable_index = \'CURRENT\' # AND job_resource_groups.res_group_index = \'CURRENT\' # AND job_resource_descriptions.res_job_index = \'CURRENT\' # AND jobs.job_id = $job_id # AND jobs.job_id = moldable_job_descriptions.moldable_job_id # AND job_resource_groups.res_group_moldable_id = moldable_job_descriptions.moldable_id # AND job_resource_descriptions.res_job_group_id = job_resource_groups.res_group_id # ORDER BY moldable_job_descriptions.moldable_id, job_resource_groups.res_group_id, job_resource_descriptions.res_job_order ASC # "); if (defined($Resources_data_structure_current_job{$job_id})){ return($Resources_data_structure_current_job{$job_id}); }else{ my $sth = $dbh->prepare(" SELECT moldable_job_descriptions.moldable_id, job_resource_groups.res_group_id, moldable_job_descriptions.moldable_walltime, job_resource_groups.res_group_property, job_resource_descriptions.res_job_resource_type, job_resource_descriptions.res_job_value FROM moldable_job_descriptions, job_resource_groups, job_resource_descriptions, jobs WHERE jobs.job_id = $job_id AND jobs.job_id = moldable_job_descriptions.moldable_job_id AND job_resource_groups.res_group_moldable_id = moldable_job_descriptions.moldable_id AND job_resource_descriptions.res_job_group_id = job_resource_groups.res_group_id ORDER BY moldable_job_descriptions.moldable_id, job_resource_groups.res_group_id, job_resource_descriptions.res_job_order ASC "); $sth->execute(); my $result; my $group_index = -1; my $moldable_index = -1; my $previous_group = 0; my $previous_moldable = 0; while (my @ref = $sth->fetchrow_array()){ if ($previous_moldable != $ref[0]){ $moldable_index++; $previous_moldable = $ref[0]; $group_index = 0; $previous_group = $ref[1]; }elsif ($previous_group != $ref[1]){ $group_index++; $previous_group = $ref[1]; } # Store walltime $result->[$moldable_index]->[1] = $ref[2]; $result->[$moldable_index]->[2] = $ref[0]; #Store properties group $result->[$moldable_index]->[0]->[$group_index]->{property} = $ref[3]; my %tmp_hash = ( resource => $ref[4], value => $ref[5] ); push(@{$result->[$moldable_index]->[0]->[$group_index]->{resources}}, \%tmp_hash); } $sth->finish(); $Resources_data_structure_current_job{$job_id} = $result; return($result); } } return 1; oar-2.5.7/sources/visualization_interfaces/Monika/lib/OAR/Monika/monikaCGI.pm0000755015014700017500000001347412677211234026513 0ustar neyronneyron## This package inherits CGI.pm and adds support for color management package OAR::Monika::monikaCGI; use strict; use File::Basename; use Sort::Naturally; #use warnings; use base qw(CGI); use Data::Dumper; ## class constructor sub new { my $proto = shift; my $class = ref($proto) || $proto; my $self = $class->SUPER::new(); $self->{USED_COLORS} = {}; $self->{COLOR_POOL} = []; bless ($self, $class); return $self; } ## get the color for a key sub getColor { my $self = shift; my $key = shift; if (not $self->{USED_COLORS}->{$key}) { $self->{USED_COLORS}->{$key} = $self->getColorFromPool($key); } return $self->{USED_COLORS}->{$key}; } ## set a color for a key sub setColor { my $self = shift; my $key = shift; my $color = shift; $self->{USED_COLORS}->{$key} = $color; return 1; } ## set color pool sub setColorPool { my $self = shift; $self->{COLOR_POOL} = shift; return 1; } ## get a color from color pool, and rotate the pool by one. sub getColorFromPool { my $self = shift; my $key = shift; my $color_pool = $self->{COLOR_POOL}; my $color = $color_pool->[$key % ($#{$color_pool}+1)]; #my $color = shift @$color_pool; #push @$color_pool,$color; return $color; } ## print a HTML with a background color corresponding to the text ## given as parameter sub colorTd { my $self = shift; my $txt = shift; my $width; my $href; my $title; if (@_) { $width = shift; } else { $width = undef; } if (@_) { $href = shift; } else { $href = undef; } if (@_) { $title = shift; } else { $title = undef; } my $txt2; if ($href) { $txt2 = $self->a({-href => $href, -title => $title }, $self->b($txt) ); } else { $txt2 = $self->b($txt); } return $self->td({ -bgcolor => $self->getColor($txt), -width => $width, -align => "center" }, $txt2); } # print a HTML with a background color corresponding to the text ## given as parameter sub colorjavascriptTd { my $self = shift; my $txt = shift; my $width; my $href; my $title; my $javascript; if (@_) { $width = shift; } else { $width = undef; } if (@_) { $javascript = shift; } else { $javascript = undef; } if (@_) { $href = shift; } else { $href = undef; } if (@_) { $title = shift; } else { $title = undef; } my $txt2; if ($href) { $txt2 = $self->a({-href => $href, -title => $title, }, $self->b($txt) ); } else { $txt2 = $self->b($txt); } if ($javascript) { return $self->td({-class => "fixed_td", -bgcolor => $self->getColor($txt), -width => $width, -align => "center", -onmouseout => "return nd()", -onmouseover => "return overlib('$javascript')" }, $txt2); } else { return $self->td({ -bgcolor => $self->getColor($txt), -width => $width, -align => "center" }, $txt2); } } ## debug function: show color settings sub colorTable { my $self = shift; my $output = ""; $output .= $self->start_table({-border => "1", -align => "center"}); foreach my $key (keys %{$self->{USED_COLORS}}) { $output .= $self->start_Tr(); $output .= $self->td({-bgcolor => $self->{USED_COLORS}->{$key}, -width => "20"},""); $output .= $self->td({-align => "center"},$key); $output .= $self->end_Tr(); } my $i=0; foreach my $color (@{$self->{COLOR_POOL}}) { $output .= $self->start_Tr(); $output .= $self->td({-bgcolor => $color, -width => "20"},""); $output .= $self->td({-align => "center"},"Pool ".$i++); $output .= $self->end_Tr(); } $output .= $self->end_table(); } sub nodeReservationTable { my $self = shift; my $nodes = shift; my $nodelist = shift; my $output = ""; my @names; if (defined $nodelist) { @names = @$nodelist; } else { @names = keys %$nodes; } my $is_sorted = 1; #@names = sort {$a <=> $b or $a cmp $b} @names or $is_sorted = 0; @names = sort {$a <=> $b or Sort::Naturally::ncmp($a,$b)} @names or $is_sorted = 0; $output .= $self->start_table({-border=>"1", -align => "center" }); $output .= $self->start_Tr(); my $i=1; ## each nodes get printed in the right order foreach my $name (@names) { # $output .= $self->start_td({-align => "center",}); # $output .= $self->start_form({ action => "input_button.htm"}); # $output .= $self->start_form(); # $output .= $self->input({ # type => "button", # name => "lien", # value => "$name", # onclick => "self.location.href = '".$self->self_url(-query=>0)."?node=".$name."'" # }); # $output .= $self->end_form(); # $output .= $self->end_td({-align => "center",}); $output .= $self->start_td({-align => "center", }); #$output .= $self->b($self->small($self->small($self->a({ -href => $self->self_url(-query=>0)."?node=".$name, my $cgiName = File::Basename::basename($self->self_url(-query=>0)); $output .= $self->b($self->small($self->small($self->a({ -href => $cgiName."?node=".$name, -title => "click to see node details" },$$nodes{$name}->displayHTMLname())))); $output .= $self->end_td(); $output .= $self->start_td(); ## print this node status sub table $output .= $$nodes{$name}->htmlTable($self); $output .= $self->end_td(); ## 10 nodes per line if ($i++ % OAR::Monika::Conf::myself()->nodes_per_line() == 0) { $output .= $self->end_Tr(); $output .= $self->start_Tr(); } } $output .= $self->end_Tr(); $output .= $self->end_table(); return $output; } ## print page head sub page_head { my $self = shift; my $title = shift; my $output = ""; $output .= $self->header(); $output .= $self->start_html(-title => $title, -link => "black", -vlink => "black", -alink => "darkblue" ); } ## that's all return 1; oar-2.5.7/sources/visualization_interfaces/Monika/lib/OAR/Monika/OARNode.pm0000755015014700017500000002116512677211234026135 0ustar neyronneyron## Created on November 2007 by Joseph.Emeras@imag.fr ## this package handles a OAR node description package OAR::Monika::OARNode; use strict; use warnings; use OAR::Monika::monikaCGI; use OAR::Monika::Conf; use Data::Dumper; use Time::Local; use POSIX qw(strftime); ## class constructor sub new { my $proto = shift; my $class = ref($proto) || $proto; my $self = {}; $self->{Nodename} = shift or die "missing a node name !"; $self->{Ressources} = shift or die "missing node ressources !"; bless ($self, $class); return $self; } ## return node full name sub name { my $self = shift; return $self->{Nodename}; } ## return node's ressource state # parameters : node, resource id # return value : state of the given ressource sub ressourceState($$){ my $self = shift; my $ressource= shift; return $self->{Ressources}->{$ressource}->{infos}->{state}; } ## return node's state # parameters : node # return value : hash table containing (ressource, state) couples sub state($){ my $self = shift; my %hashResult; foreach my $key (keys %{$self->{Ressources}}){ #$hashResult{$key}= $self->{Ressources}->{$key}->{infos}->{state}; $hashResult{$key}= $self->ressourceState($key); } return %hashResult; } ## return this node's ressource cores count # parameters : node, resource id # return value : number of cores of the given ressource #sub ressourceCores($$) { # my $self = shift; # my $ressource= shift; # return $self->{Ressources}->{$ressource}->{infos}->{cpucore}; #} ## return this node cpu/cores resource count: if a cpu is composed of two cores, the return value will be 2... sub nodeResources { my $node = shift; my $cpt=0; #my %alreadyCounted; foreach (keys %{$node->{Ressources}}){ #unless (defined($alreadyCounted{$node->{Ressources}->{$_}->{infos}->{cpu}})){ #$cpt+=$node->{Ressources}->{$_}->{infos}->{cpucore}; #$alreadyCounted{$node->{Ressources}->{$_}->{infos}->{cpu}}= 1; #} $cpt++; } return $cpt; } ## alias cpus --> core sub cpus { my $node = shift; my $result= $node->nodeResources; return $result; } ## extract the name to display using a regex from the node real name sub displayname { my $self = shift; $self->name() =~ OAR::Monika::Conf::myself()->nodenameRegex(); my $shortname = $1 or die "Fail to extract node' shortname"; return $shortname;; } ## extract the name to display on the page sub displayHTMLname { my $self = shift; $self->name() =~ OAR::Monika::Conf::myself()->nodenameRegexDisplay(); my $shortname = $1 or die "Fail to extract node' shortname"; return $shortname; } ## return a hash containing (ressource,\@jobs) couple. sub jobs { my $self = shift; my %hashResult; foreach my $key (keys %{$self->{Ressources}}){ $hashResult{$key}= $self->{Ressources}->{$key}->{jobs}; } return %hashResult; } ## return an array containing ressource's jobs. sub ressourceJobs { my $self = shift; my $ressource= shift; my $ptResult= $self->{Ressources}->{$ressource}->{jobs}; return @$ptResult; } sub isRessourceWorking{ my $self = shift; my $ressource= shift; if (@{$self->{Ressources}->{$ressource}->{jobs}}){ return 1; }else{ return 0; } } ## return the hash table of properties of this node's ressource sub ressourceProperties($$) { my $self = shift; my $ressource= shift; return %{$self->{Ressources}->{$ressource}->{infos}}; } ## return the (ressource, \%properties) couple for this node sub properties { my $self = shift; my %hashResult; foreach my $key (keys %{$self->{Ressources}}){ #$hashResult{$key}= $self->{Ressources}->{$key}->{infos}; my %hashtemp= $self->ressourceProperties($key); $hashResult{$key}= \%hashtemp; } return %hashResult; } ## print this node status HTML table sub htmlTable { my $self = shift; my $cgi = shift; my $output = ""; $output .= $cgi->start_table({-border => "1", -cellspacing => "0", -cellpadding => "0", -width => "100%" }); $output .= $cgi->start_Tr({-align => "center"}); my $cgiName = File::Basename::basename($cgi->self_url(-query=>0)); my $max_cores_per_line = OAR::Monika::Conf::myself()->max_cores_per_line(); my $nb_cells = 0; foreach my $currentRessource (sort keys %{$self->{Ressources}}){ if (($nb_cells++ % $max_cores_per_line) == 0){ $output .= $cgi->end_Tr(); $output .= $cgi->start_Tr({-align => "center"}); } #my $ressourceState= $self->{Ressources}->{$currentRessource}->{infos}->{state}; my $ressourceState= $self->ressourceState($currentRessource); if ($ressourceState eq "Alive" && $self->isRessourceWorking($currentRessource) eq '1') { my @jobs = @{$self->{Ressources}->{$currentRessource}->{jobs}}; $output .= $cgi->start_td(); $output .= $cgi->start_table({-border => "1", -cellspacing => "0", -cellpadding => "0", -width => "100%"}); foreach my $curr_job (@jobs){ $output .= $cgi->start_Tr({-align => "center"}); $output .= $cgi->colorTd($curr_job, 100/$self->cpus."%",$cgiName."?job=$curr_job"); $output .= $cgi->end_Tr(); } $output .= $cgi->end_table(); $output .= $cgi->end_td(); } elsif ($ressourceState eq "Alive" && $self->isRessourceWorking($currentRessource) eq '0'){ my $drain = $self->{Ressources}->{$currentRessource}->{infos}->{drain}; if (!defined($drain) or ($drain ne "YES")) { $output .= $cgi->colorTd("Free",100/$self->cpus."%"); } else { $output .= $cgi->colorTd("Drain",100/$self->cpus."%"); } } elsif ($ressourceState eq "Down") { $output .= $cgi->colorTd("Down",100/$self->cpus."%"); } elsif ($ressourceState eq "Absent") { my $available_upto = $self->{Ressources}->{$currentRessource}->{infos}->{available_upto}; if(defined($available_upto) && $available_upto ne '0'){ #my $now= `date +%s`; my $now= time(); if($now < $available_upto && $available_upto ne '2147483647'){ $output .= $cgi->colorTd("StandBy",100/$self->cpus."%"); }else{ $output .= $cgi->colorTd("Absent",100/$self->cpus."%"); } } else{ $output .= $cgi->colorTd("Absent",100/$self->cpus."%"); } } elsif ($ressourceState eq "Suspected") { # if the resource is suspected and running a job, we must display it # differently if($self->isRessourceWorking($currentRessource) eq '1'){ my @jobs = @{$self->{Ressources}->{$currentRessource}->{jobs}}; $output .= $cgi->colorTd($jobs[0].'*',100/$self->cpus."%"); #$output .= $cgi->colorTd($cgi->i("Suspected"),100/$self->cpus."%"); } else{ $output .= $cgi->colorTd("Suspected",100/$self->cpus."%"); } } else { $output .= $cgi->colorTd("Down",100/$self->cpus."%"); } } $output .= $cgi->end_Tr(); $output .= $cgi->end_table(); return $output; } sub getRessourceInfos { my $self = shift; my $ressource = shift; defined $ressource or die "which ressource ?"; exists $self->{Ressources}->{$ressource}->{infos} or die "Unknown ressource: ".$ressource; my %return = %{$self->{Ressources}->{$ressource}->{infos}}; return %return; } sub htmlStatusTable { my $self = shift; my $cgi = shift; my $output = ""; my $nodes_synonym = OAR::Monika::Conf::myself->nodes_synonym; $output .= $cgi->start_table({-border=>"1", -align => "center"}); $output .= $cgi->start_Tr(); $output .= $cgi->th({-align => "left", bgcolor => "^c0c0c0"}, $cgi->i("Nodename")); $output .= $cgi->th({-align => "left"}, $self->name()); $output .= $cgi->end_Tr(); $output .= $cgi->end_table(); $output .= $cgi->br(); $output .= $cgi->start_table({-border=>"1", -align => "center"}); my @keylist = keys %{$self->{Ressources}}; my @properties= keys %{$self->{Ressources}->{$keylist[0]}->{infos}}; $output .= $cgi->start_Tr(); $output .= $cgi->th({-align => "left", bgcolor => "^c0c0c0"}, $cgi->i("Ressource no.")); foreach my $key (sort @keylist) { $output .= $cgi->th({-align => "left", bgcolor => "^c0c0c0"}, $cgi->i($key)); } $output .= $cgi->end_Tr(); foreach my $prop (@properties) { $output .= $cgi->start_Tr(); $output .= $cgi->th({-align => "left", bgcolor => "^c0c0c0"}, $cgi->i($prop)); foreach my $key (sort @keylist) { my $value= $self->{Ressources}->{$key}->{infos}->{$prop}; if($prop eq $nodes_synonym){ $value= $self->displayHTMLname(); } if($prop eq 'available_upto'){ $value= strftime("%F %T",localtime($value)); } $output .= $cgi->td({-valign => "top", bgcolor => "^c0c0c0"}, $cgi->i($value)); } $output .= $cgi->end_Tr(); } $output .= $cgi->end_table(); return $output; } ## that's all. return 1; oar-2.5.7/sources/visualization_interfaces/Monika/lib/OAR/Monika/ConfNode.pm0000755015014700017500000000351712677211234026402 0ustar neyronneyron## this package handles a node description got from the configuration file package OAR::Monika::ConfNode; use strict; use warnings; use OAR::Monika::monikaCGI; ## class constructor sub new { my $proto = shift; my $class = ref($proto) || $proto; my $self = {}; $self->{NAME} = shift; $self->{STATE} = shift; bless ($self, $class); return $self; } ## return node number sub name { my $self = shift; return $self->{NAME}; } ## extract the name to display on the page sub displayHTMLname { my $self = shift; $self->name() =~ OAR::Monika::Conf::myself()->nodenameRegexDisplay(); my $shortname = $1 or die "Fail to extract node' shortname"; return $shortname; } ## return node state as define in the configuration file. sub state { my $self = shift; return $self->{STATE}; } ## print this node status HTML table sub htmlTable { my $self = shift; my $cgi = shift; my $output = ""; $output .= $cgi->start_table({-border => "1", -cellspacing => "0", -cellpadding => "0", -width => "100%" }); $output .= $cgi->start_Tr({-align => "center"}); $output .= $cgi->colorTd($self->state()); $output .= $cgi->end_Tr(); $output .= $cgi->end_table(); return $output; } sub htmlStatusTable { my $self = shift; my $cgi = shift; my $output = ""; $output .= $cgi->start_table({-border=>"1", -align => "center" }); $output .= $cgi->start_Tr(); $output .= $cgi->th({-align => "left", bgcolor => "#c0c0c0"}, $cgi->i("Nodename")); $output .= $cgi->th({-align => "left"}, $self->name()); $output .= $cgi->end_Tr(); $output .= $cgi->start_Tr(); $output .= $cgi->td({-align => "left", bgcolor => "#c0c0c0"}, $cgi->i("State")); $output .= $cgi->td({-align => "left"}, $self->state()); $output .= $cgi->end_Tr(); $output .= $cgi->end_table(); return $output; } ## that's all return 1; oar-2.5.7/sources/visualization_interfaces/Monika/monika.cgi.in0000755015014700017500000001113612677211234024307 0ustar neyronneyron#!/usr/bin/perl ############################################################################## ## Monika is a small web interface to monitor OAR node reservations. ## It tries to display a very synthetic view of the cluster usage. ## Monika should work also with PBSPro or OpenPBS. ## Author: pierre.neyron@imag.fr ## Modified by: joseph.emeras@imag.fr ############################################################################## use strict; #use warnings; use OAR::Monika::monikaCGI; use OAR::Monika::Conf; use OAR::Monika::OAR; use Data::Dumper; ## begin CGI stuff my ($basename) = $0 =~ /([^\/]+)\.cgi$/; my $cgi = OAR::Monika::monikaCGI->new; my $file = $cgi->param("conf"); ## first get nodes description from the configuration file my $Oardir = "%%OARCONFDIR%%"; my $conf = OAR::Monika::Conf->new; if ( defined $file and -r $file) { $conf->parse($file); } elsif (-r "$Oardir/$basename.conf") { $conf->parse("$Oardir/$basename.conf"); } elsif (-r "./$basename.conf") { $conf->parse("./$basename.conf"); } elsif (-r "/etc/$basename.conf") { $conf->parse("/etc/$basename.conf"); } else { die "Neither $Oardir/$basename.conf nor /etc/$basename.conf nor ./$basename.conf are readable. I need a configuration file !"; } ## then get nodes description my $oar = OAR::Monika::OAR->new; $oar->oarnodes; $oar->qstat($cgi); ## my global node container... my %nodes; ## ... filled in with previousely got nodes: ## first with node descriptions from the configuration file foreach my $key ( keys %{$conf->allnodes()}) { $nodes{$key}=$conf->allnodes->{$key}; } ## then with node descriptions (which may overwrite descriptions ## from the configuration file, which is what we want for instance if the ## configuration file define a default state (say "missing") for nodes ## that may actually not be described) foreach my $key ( keys %{$oar->allnodes()}) { $nodes{$key}=$oar->allnodes->{$key}; } ## set color scheme up my $colorHash = $conf->colorHash; while (my ($state,$color) = each %{$colorHash}) { $cgi->setColor($state,$color); } $cgi->setColorPool($conf->colorPool()); ## begin html printing print $cgi->page_head($conf->clustername." - Monika"); my $css_path = OAR::Monika::Conf::myself->css_path; print ""; print $cgi->h1({-align => "center"}, $conf->clustername()." "." nodes"); ## if node param is present, show detailed view of the pointed node if (defined $cgi->param('node') and defined $nodes{$cgi->param('node')}) { my $node = $cgi->param('node'); print $cgi->h2({-align => "center"}, "Node ".$node." detailed status:"); print $nodes{$node}->htmlStatusTable($cgi); print $cgi->h3({ -align => "center" }, $cgi->a({ -href => $cgi->url(-absolute=>1,-query=>0)}, "back to main page" )); ## if job param is present, show detailed view of the pointed job } elsif (defined $cgi->param('job')) { # and defined $oar->alljobs()->{$cgi->param('job')} my $job = $cgi->param('job'); print $cgi->h2({-align => "center"}, "Job ".$job." detailed status:"); if(exists($oar->alljobs()->{$job})){ print $oar->alljobs()->{$job}->htmlStatusTable($cgi); } else{ my $jobInfos = $oar->getJobProperties($job, $cgi); print $jobInfos->htmlStatusTable($cgi); } print $cgi->h3({ -align => "center" }, $cgi->a({ -href => $cgi->url(-absolute=>1,-query=>0)}, "back to main page" )); ## else show the main page } else { ## print oar status summary print $oar->htmlSummaryTable($cgi); print $cgi->br(); ## print nodes reservations table print $cgi->h2({-align => "center"}, "Reservations:"); ## print resources for each of the properties if asked in the CGI request, or all resources. if (defined $cgi->param('props')) { ## print resources property, for the properties selected in the CGI request print $oar->htmlNodeByProperty($cgi); } else { ## print all resources print $cgi->nodeReservationTable(\%nodes); } print $cgi->h5({-align => "center"}, "*: Running job but suspected resources."); ## print oar node property chooser print $cgi->br(); print $oar->htmlPropertyChooser($cgi); ## print oar job status print $cgi->br(); print $cgi->h2({-align => "center"}, "Job details:"); print $oar->htmlJobTable($cgi); } #open VERSION, "<./monika/VERSION"; #my $version=""; #while () { # $version.=$_; #} #close VERSION; ## print © stuff print $cgi->h6({ -align => "center", onmouseover => "popup('Link description here','yellow')", onmouseout => "kill()" }, "- ". $cgi->a({ -href => 'http://oar.imag.fr'}, "Monika - OAR"). " -" ); print $cgi->end_html(); oar-2.5.7/sources/visualization_interfaces/Monika/monika.css0000644015014700017500000000216412677211234023726 0ustar neyronneyron oar-2.5.7/sources/visualization_interfaces/Monika/monika.conf.in0000755015014700017500000002066412677211234024500 0ustar neyronneyron## Created on November 2007 by Joseph.Emeras@imag.fr ################# ## monika.conf ## ################# ############################################################################## ## WARNING: About the location of this file: ## monika.cgi is looking first for its configuration file in its own ## directory then in /etc/oar/ ############################################################################## ############################################################################## ## CSS path for the HTML diplay ## - default is "/monika.css" ############################################################################## css_path = %%WWWROOTDIR%%/monika.css ############################################################################## ## clustername: set the name of the cluster ## - default is "Cluster" ## - ex: clustername = "MyCluster" ############################################################################## clustername = OAR Cluster ############################################################################## ## DataBase : set the connection parameters for accessing the OAR DataBase ############################################################################## hostname = 127.0.0.1 dbport = 5432 # dbtype can be mysql or psql for postgresql dbtype = psql dbname = oar username = oar_ro password = oar_ro ############################################################################## ## nodes_synonym: which real resource must be used when using the "nodes" ## keyword ? ## - ex: nodes_synonym = resource_id ## nodes_synonym = host ## - default is resource_id ############################################################################## nodes_synonym = network_address ############################################################################## ## Summary Display: specify how to display the summary status. For each type ## of resource, a resource hierarchy can be specified. Syntax is: ## [:[,]...][;...] ## -ex: summary_display = default:nodes_synonym;licence:resource_id; ## memory:resource_id;userid:resource_id ## -ex: summary_display = default:host,cpu,core;licence;memory;userid ## -ex: summary_display = default:network_address ## -ex: summary_display = default:nodes_synonym ############################################################################## summary_display = default:nodes_synonym,resource_id ############################################################################## ## nodes_per_line: set the number of node to be displayed per line in the ## reservation table ## - default is 10 ## - ex: nodes_per_line = 5 ############################################################################## nodes_per_line = 2 ############################################################################## ## max_cores_per_line: set the number of cores to be displayed per line in the ## reservation table ## - default is 16 ## - ex: max_cores_per_line = 32 ############################################################################## max_cores_per_line = 16 ############################################################################## ## nodename_regex: set the regular expression to extract nodes' short ## names (ex: node22 => 22). Use Perl regular expression syntax. ## - default is "(\d+)" ie extract the first number from the left in nodenames ## - ex: nodename_regex = cluster5node(\d+) ie basename contains a number... ## - ex: nodename_regex = ([^.]+) ie to extract the short hostname. ## - ex: nodename_regex = (.+) ie to keep the whole word if really needed. ## Rq: this regex is used to sort nodes ############################################################################## nodename_regex = (.+) ############################################################################## ## nodename_regex_display: set the regex display on the page node names ## it is just for final display ## Rq: monika looks better with numerical only short nodenames... ############################################################################## nodename_regex_display = (.*) ############################################################################## ## server_do_mail: set the capability of the server to handle mail. If ## true, then monika use the job owner attribut as a valid email address ## unless -M is specified in qsub and then used instead ## - default is "False" ## - ex: server_do_mail = "True" ############################################################################## #server_do_mail = "False" ############################################################################## ## user_infos : if server_do_mail is not set then you can specify a cgi page ## wich can display informations about a user. It is a link on the user name. ## The link pints on the content of user_infos+user_name ############################################################################## #user_infos = "userInfos.cgi?" ############################################################################## ## node_group: define a group of nodes ## - ex: node_group group1 = 5-10 25 32 40-50 ## - ex: node_group group2 = master nodeone nodetwo ## * Rq: monika looks better with numerical only node names. ## * Rq: nodes you define this way may be either extra nodes (ex: login nodes) ## or the nodes in order to give them a "rescue" state (ex: Missing) ############################################################################## #node_group login = 1-4 #node_group batch = 5-225 ############################################################################## ## default_state: define the default state for a node group defined above ## - ex: default_state group1 = "StateGroup1" ############################################################################## #default_state login = Login #default_state batch = Missing ############################################################################## ## set_color: associate a HTML color to a node state ## - ex: set_color Down = "red" ## - ex: set_color Free = "#33ff33" ############################################################################## set_color Down = "red" set_color Free = "#ffffff" set_color Absent = "#c22200" set_color StandBy = "cyan" set_color Suspected = "#ff7b7b" #set_color Missing = "grey" #set_color Login = "cyan" ############################################################################## ## color_pool: add an HTML color to dynamically use in HTML table generation ## - ex: color_pool = "#9999ff" ## color_pool = "#ff6600" ## color_pool = "#00cccc" ############################################################################## color_pool = "#9999ff" color_pool = "#00cccc" color_pool = "pink" color_pool = "yellow" color_pool = "orange" color_pool = "#ff22ff" color_pool = "#33cc00" color_pool = "#cc66cc" color_pool = "#99ff99" color_pool = "#995522" color_pool = "orange" color_pool = "#999999" ############################################################################## ## hidden_property: define properties not to be shown in the main page ## - ex: hidden_property = hostname ## hidden_property = besteffort ## hidden_property = expiryDate ############################################################################## #hidden_property = network_address #hidden_property = besteffort #hidden_property = expiry_date #hidden_property = desktop_computing #hidden_property = cpu #hidden_property = cpuset #hidden_property = available_upto #hidden_property = core #hidden_property = finaud_decision #hidden_property = last_job_date #hidden_property = resource_id #hidden_property = state #hidden_property = state_num #hidden_property = type #hidden_property = mem #hidden_property = suspended_jobs #hidden_property = next_state #hidden_property = next_finaud_decision #hidden_property = deploy #hidden_property = host hidden_property = network_address hidden_property = host hidden_property = cpu hidden_property = core hidden_property = thread hidden_property = cpuset hidden_property = ip hidden_property = hostname #hidden_property = besteffort hidden_property = expiry_date hidden_property = desktop_computing hidden_property = available_upto hidden_property = last_available_upto hidden_property = finaud_decision hidden_property = last_job_date hidden_property = resource_id #hidden_property = state hidden_property = state_num #hidden_property = type #hidden_property = mem hidden_property = suspended_jobs hidden_property = next_state hidden_property = next_finaud_decision hidden_property = deploy hidden_property = scheduler_priority #hidden_property = switch oar-2.5.7/sources/visualization_interfaces/Monika/userInfos.cgi0000755015014700017500000000036012677211234024376 0ustar neyronneyron#!/bin/bash echo Content-type: text/plain echo echo "# id $QUERY_STRING" id "$QUERY_STRING" #echo #echo "# oarstat -u $QUERY_STRING --accounting '2006-03-30, 2008-04-30'" #oarstat -u "$QUERY_STRING" --accounting '2000-01-01, 2010-12-31' oar-2.5.7/sources/visualization_interfaces/DrawGantt-SVG/0000755015014700017500000000000012677211234023045 5ustar neyronneyronoar-2.5.7/sources/visualization_interfaces/DrawGantt-SVG/drawgantt-svg.php.in0000644015014700017500000017614112677211234026765 0ustar neyronneyron * */ //////////////////////////////////////////////////////////////////////////////////////////////////// // Configuration: DO NOT EDIT HERE. Customization must go in /etc/oar/drawgantt-config.inc.php //////////////////////////////////////////////////////////////////////////////////////////////////// $CONF=array(); // Database access configuration $CONF['db_type']="pg"; // choices: mysql for Mysql or pg for PostgreSQL $CONF['db_server']="127.0.0.1"; $CONF['db_port']="5432"; // usually 3306 for Mysql or 5432 for PostgreSQL $CONF['db_name']="oar"; // OAR read only user account $CONF['db_user']="oar_ro"; $CONF['db_passwd']="oar_ro"; $CONF['db_max_job_rows']=20000; // max number of job rows retrieved from database, which can be handled. // Data display configuration $CONF['timezone'] = "UTC"; $CONF['site'] = "My OAR resources"; // name for your infrastructure or site $CONF['resource_labels'] = array('network_address','cpuset'); // properties to describe resources (labels on the left). Must also be part of resource_hierarchy below $CONF['cpuset_label_display_string'] = "%02d"; $CONF['label_display_regex'] = array( // shortening regex for labels (e.g. to shorten node-1.mycluster to node-1 'network_address' => '/^([^.]+)\..*$/', ); $CONF['label_cmp_regex'] = array( // substring selection regex for comparing and sorting labels (resources) 'network_address' => '/^([^-]+)-(\d+)\..*$/', ); $CONF['resource_properties'] = array( // properties to display in the pop-up on top of the resources labels (on the left) 'deploy', 'cpuset', 'besteffort', 'network_address', 'type', 'drain'); $CONF['resource_hierarchy'] = array( // properties to use to build the resource hierarchy drawing 'network_address','cpuset', ); $CONF['resource_base'] = "cpuset"; // base resource of the hierarchy/grid $CONF['resource_group_level'] = "network_address"; // level of resources to separate with blue lines in the grid $CONF['resource_drain_property'] = "drain"; // if set, must also be one of the resource_properties above to activate the functionnality $CONF['state_colors'] = array( // colors for the states of the resources in the gantt 'Absent' => 'url(#absentPattern)', 'Suspected' => 'url(#suspectedPattern)', 'Dead' => 'url(#deadPattern)', 'Standby' => 'url(#standbyPattern)', 'Drain' => 'url(#drainPattern)'); $CONF['job_colors'] = array( // colors for the types of the jobs in the gantt 'besteffort' => 'url(#besteffortPattern)', 'deploy(=\w)?' => 'url(#deployPattern)', 'container(=\w+)?' => 'url(#containerPattern)', 'timesharing=(\*|user),(\*|name)' => 'url(#timesharingPattern)', 'placeholder=\w+' => 'url(#placeholderPattern)', ); $CONF['job_click_url'] = ''; // set a URL to open when a job is double-clicked, %%JOBID%% is to be replaced by the jobid in the URL $CONF['resource_click_url'] = ''; // set a URL to open when a resource is double-clicked, %%TYPE%% is to be replaced by the resource type and %%ID%% by the resource id in the URL // Geometry customization $CONF['hierarchy_resource_width'] = 10; // default: 10 $CONF['scale'] = 10; // default: 10 $CONF['text_scale'] = 10; // default: 10 $CONF['time_ruler_scale'] = 6; // default: 6 $CONF['time_ruler_steps'] = array(60,120,180,300,600,1200,1800,3600,7200,10800,21600,28800,43200,86400,172800,259200,604800); $CONF['gantt_top'] = 50; // default: 50 $CONF['bottom_margin'] = 45; // default: 45 $CONF['right_margin'] = 30; // default 30 $CONF['label_right_align'] = 105; // default: 105 $CONF['hierarchy_left_align'] = 110; // default: 110 $CONF['gantt_left_align'] = 160; // default: 160 $CONF['gantt_min_width'] = 900; // default: 900 $CONF['gantt_min_height'] = 100; // default: 100 $CONF['gantt_min_job_width_for_label'] = 40; // default: 40 $CONF['min_state_duration'] = 2; // default: 2 // Colors and fill patterns for jobs and states $CONF['job_color_saturation_lightness'] = "75%,75%"; // default: "75%,75%" $CONF['job_color_saturation_lightness_highlight'] = "50%,50%"; // default: "50%,50%" $CONF['static_patterns'] = << C B P D T EOT; // Standby state display options for the part shown in the future $CONF['standby_truncate_state_to_now'] = 1; // default: 1 // Besteffort job display options for the part shown in the future $CONF['besteffort_truncate_job_to_now'] = 1; // default: 1 $CONF['besteffort_pattern'] = << ' EOT; // Advanced customization for the computation of the colors of the jobs // Uncomment and adapt the following to override the default function //class MyShuffle extends Shuffle { // // Default function: get the color's hue value as a function of the job_id // function job2int($job) { // // compute a suffled number for job_id, so that colors are not too close // $magic_number = (1+sqrt(5))/2; // return (int)(360 * fmod($job->job_id * $magic_number, 1)); // } // // Other example: get the color's hue value as a function of the job_user value // protected $cache = array(); // function job2int($job) { // // shuffled number based on the job_user: // if (! array_key_exists($job->job_user, $this->cache)) { // $n = (int) base_convert(substr(md5($job->job_user) ,0, 5), 16, 10); // $magic_number = (1+sqrt(5))/2; // $this->cache[$job->job_user] = (int)(360 * fmod($n * $magic_number, 1)); // } // return $this->cache[$job->job_user]; // } //} //Shuffle::init(new MyShuffle()); // this line must be uncommented for the overiding to take effect // Minimum timespan the gantt can handle $CONF['min_timespan']= 480; // gantt does not show if (stop date - start date) < 8 minutes // Debugging $CONF['debug'] = 0; // Set to > 0 to enable debug prints in the web server error logs //////////////////////////////////////////////////////////////////////////////// // End of the embedded configuration settings //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// // // This php script take the following parameter as argument in URL (GET): // - display: all | no_ruler | no_mobile_ruler | ruler_only, as option the the rulers display // - config: , to add a suffix to config file (drawgantt-config.inc.php.[suffix]) and allow multiple configuration for a same installation // - timezome: UTC | ..., as the timezone to use // - start: , start date for the gantt // - stop: , stop date for the gantt // - relative_start: , start date relative to now for the gantt // - relative_stop: , stop date relative to now for the gantt // - filter: , SQL where clause for the OAR resource selection // - resource_base: , base resource to use in hierarchy // - width: : gantt width in pixel // - scale: : scale for the gantt in pixel // // The generated SVG page can be used as a widget in a parent html document. API for that widget is the following: // - use an HTML element and set both the data and innerHTML attributes to the drawgantt-svg.php URL. // - the caller page can provide the following for interaction with the SVG document: // - inboxbox element and infoboxDisplay(array of lines), infoboxHide(), infoboxMove(x,y) callback function to use an infobox in the parent document // - setZoomWindow(now, zoom1, zoom2) callback function to use the mouse selection zone (zoom) // - highlightOthers(object_ref, element class, boolean) callback function to propagate highlight to other gantts in the parent document // - also, the parent document must set a reference to the object element that contains the SVG document: // - the parent script: ganttObjectElement.contentDocument.object_ref = ganttObjectElement // //////////////////////////////////////////////////////////////////////////////// // Look for a config file suffix in URL $config_file_suffix = array_key_exists('config',$_GET)?'.'.$_GET['config']:''; if (! preg_match('/^\.\w+$/', $config_file_suffix)) { debug(1, "invalid config file suffix: $config_file_suffix, falling back to the default config"); $config_file_suffix = ''; } // Overwrite configuration with values from config_file define('CONFIG_DIR', '%%OARCONFDIR%%'); define('CONFIG_FILE', CONFIG_DIR . '/drawgantt-config.inc.php' . $config_file_suffix); if (is_readable(CONFIG_FILE)) { require CONFIG_FILE; } else { debug(1, "config_file not readable: $config_file"); } //////////////////////////////////////////////////////////////////////////////// // Script parameters (GET) //////////////////////////////////////////////////////////////////////////////// date_default_timezone_set(array_key_exists('timezone',$_GET)?$_GET['timezone']:$CONF['timezone']); $display = array_key_exists('display',$_GET)?$_GET['display']:'all'; $gantt_start_date = array_key_exists('start',$_GET)?round($_GET['start']):0; $gantt_stop_date = array_key_exists('stop',$_GET)?round($_GET['stop']):0; $gantt_relative_start_date = array_key_exists('relative_start',$_GET)?round($_GET['relative_start']):-86400; $gantt_relative_stop_date = array_key_exists('relative_stop',$_GET)?round($_GET['relative_stop']):86400; $resource_filter = array_key_exists('filter', $_GET)?$_GET['filter']:""; $resource_base = array_key_exists('resource_base', $_GET)?$_GET['resource_base']:$CONF['resource_base']; if (! in_array($resource_base, $CONF['resource_hierarchy'])) { debug(1, "resource_base: $resource_base does not belong to CONF['resource_hierarchy']=".join(",",$CONF['resource_hierarchy'])); $resource_base = end($CONF['resource_hierarchy']); debug(1, "set resource_base to $resource_base"); } $gantt_left_align = $CONF['hierarchy_left_align'] + (3 + array_search($resource_base,$CONF['resource_hierarchy'])) * $CONF['hierarchy_resource_width']; $gantt_width = $CONF['gantt_min_width']; if (array_key_exists('width', $_GET) and $_GET['width'] > ($gantt_left_align + $CONF['gantt_min_width'] + $CONF['right_margin'])) { $gantt_width = $_GET['width'] - $gantt_left_align - $CONF['right_margin']; } $scale = array_key_exists('scale', $_GET)?$_GET['scale']:$CONF['scale']; $patterns = array(); //////////////////////////////////////////////////////////////////////////////// // Utility functions and database wrapper class //////////////////////////////////////////////////////////////////////////////// // print debug info to the web server error logs function debug($d, $str) { global $CONF, $display; if ($display != "mobule_ruler_only" and array_key_exists('debug', $CONF) and $CONF['debug'] >= $d) { error_log($str); } } // conversion function from date to pixel coordinates in the gantt function date2px($date) { global $CONF, $gantt_width, $gantt_left_align, $gantt_start_date, $gantt_stop_date, $gantt_now; if ($date < $gantt_start_date) { return $gantt_left_align; } if ($date > $gantt_stop_date) { return $gantt_left_align + $gantt_width; } return round($gantt_left_align + ($gantt_width * ($date - $gantt_start_date)) / ($gantt_stop_date - $gantt_start_date)); } // class to compute colors for jobs class Shuffle { protected static $singleton; function init($shuffle_instance) { self::$singleton = $shuffle_instance; } function get_int($job) { if (self::$singleton === null) { self::init(new Shuffle()); } return self::$singleton->job2int($job); } function job2int($job) { // compute a suffled number for job_id, so that colors are not too close $magic_number = (1+sqrt(5))/2; return (int)(360 * fmod($job->job_id * $magic_number, 1)); } } // database functions class Db { function __construct($backend, $server, $port, $dbname, $user, $password) { $this->backend = $backend; if ($this->backend == "mysql") { $this->handler = mysql_connect("$server:$port", $user, $password) or die('Cound not connect Mysql server: ' . mysql_error()); mysql_select_db($dbname) or die('Could not select database'); } elseif ($this->backend == "pg") { $this->handler = pg_connect("host=$server port=$port dbname=$dbname user=$user password=$password") or die('Cound not connect PostgreSQL server'); } else { die ("Unknown database backend: $backend (must be 'mysql' or 'pg'"); } } function query($query) { debug(3, $this->backend . " query: " . $query); $t0 = microtime(true); if ($this->backend == "mysql") { $this->result = mysql_query($query, $this->handler) or die('Query failed: ' . mysql_error()); $this->num_rows = mysql_num_rows($this->result); } elseif ($this->backend == "pg") { $this->result = pg_query($this->handler, $query) or die('Query failed'); $this->num_rows = pg_num_rows($this->result); } else { die ("Unknown database backend: " . $this-> backend . " (must be 'mysql' or 'pg'"); } debug(2, "-> " . $this->num_rows . " rows (" . (microtime(true) - $t0) . "s)"); } function fetch_array() { if ($this->backend == "mysql") { return mysql_fetch_array($this->result, MYSQL_ASSOC); } elseif ($this->backend == "pg") { return pg_fetch_array($this->result, NULL, PGSQL_ASSOC); } else { die ("Unknown database backend: " . $this->backend . " (must be 'mysql' or 'pg'"); } } function free() { if ($this->backend == "mysql") { return mysql_free_result($this->result); } elseif ($this->backend == "pg") { return pg_free_result($this->result); } else { die ("Unknown database backend: " . $this->backend . " (must be 'mysql' or 'pg'"); } } function close() { if ($this->backend == "mysql") { return mysql_close($this->handler); } elseif ($this->backend == "pg") { return pg_close($this->handler); } else { die ("Unknown database backend: " . $this->backend . " (must be 'mysql' or 'pg'"); } } function get_timestamp() { if ($this->backend == "mysql") { $this->query('SELECT UNIX_TIMESTAMP()'); $array = mysql_fetch_array($this->result, MYSQL_NUM); } elseif ($this->backend == "pg") { $this->query('SELECT EXTRACT(EPOCH FROM current_timestamp)'); $array = pg_fetch_array($this->result, NULL, PGSQL_NUM); } else { die ("Unknown database backend: " . $this->backend . " (must be 'mysql' or 'pg'"); } $this->free(); return (int)$array[0]; } function cast($var,$type) { if ($this->backend == "mysql") { return $var; } elseif ($this->backend == "pg") { return $var."::".$type; } else { die ("Unknown database backend: " . $this->backend . " (must be 'mysql' or 'pg'"); } } } //////////////////////////////////////////////////////////////////////////////// // Some classes to handle data //////////////////////////////////////////////////////////////////////////////// // Storage class for State class State { public $value, $start, $stop, $real_start, $real_stop; function __construct($value, $start, $stop) { global $gantt_start_date, $gantt_stop_date; $this->value = $value; $this->set_start($start); $this->set_stop($stop); } function set_start($start) { global $gantt_start_date; $this->real_start = $start; $this->start = ($start < $gantt_start_date)?$gantt_start_date:$start; } function set_stop($stop) { global $gantt_stop_date; $this->real_stop = $stop; $this->stop = (($stop == 0) or ($stop > $gantt_stop_date))?$gantt_stop_date:$stop; } } // Storage class for jobs class Job { public $job_id,$job_name,$project,$job_type,$state,$job_user,$command,$queue_name,$moldable_walltime,$properties,$launching_directory,$submission_time,$start_time,$stop_time,$resource_ids,$network_addresses,$types; protected $color, $colorHL; function __construct($job_id,$job_name,$project,$job_type,$state,$job_user,$command,$queue_name,$moldable_walltime,$properties,$launching_directory,$submission_time,$start_time,$stop_time) { $this->job_id = $job_id; $this->job_name = $job_name; $this->project = $project; $this->job_type = $job_type; $this->state = $state; $this->job_user = $job_user; $this->command = $command; $this->queue_name = $queue_name; $this->moldable_walltime = $moldable_walltime; $this->properties = $properties; $this->launching_directory = $launching_directory; $this->submission_time = $submission_time; $this->start_time = $start_time; $this->stop_time = $stop_time; $this->resource_ids = array(); $this->network_addresses = array(); $this->types = array(); $this->color = NULL; $this->colorHL = NULL; } function add_resource_id($resource_id) { $this->resource_ids[$resource_id->id] = $resource_id; } function add_type($type) { if (! in_array($type, $this->types)) { array_push($this->types, $type); } } function add_network_address($network_address) { if ($network_address != '' and ! in_array($network_address, $this->network_addresses)) { array_push($this->network_addresses, $network_address); } } // build groups of continuous resource ids function group_resources($resources) { $grp = NULL; foreach ($resources as $r) { $weight=0; foreach($r->resource_ids as $rid) { if (array_key_exists($rid->id, $this->resource_ids)) { $weight++; } } if ($weight > 0) { $r->add_job_occupation($this, $weight < count($r->resource_ids)); if ($grp == NULL) { debug(3, "new job2resource group for ".$r->id); $grp = new Job2ResourceGroup($this, $r); $r->add_job2resource_group($grp); } else { debug(4, "add to group ".$r->id); $grp->add_resource($r); } } else { $grp = NULL; } } } function svg_text() { $output = "Jobid: {$this->job_id}"; $output .= "|User: ".htmlspecialchars($this->job_user); $output .= "|Kind: {$this->job_type}"; $output .= "|Queue: ".htmlspecialchars($this->queue_name); $output .= "|Types: ".join(", ", array_map("htmlspecialchars", $this->types)); $output .= "|Name: ".htmlspecialchars($this->job_name); $output .= "|Project: ".htmlspecialchars($this->project); $output .= "|Walltime: " . $this->moldable_walltime/3600 . "hr"; $output .= "|Resources: ".count($this->resource_ids); $output .= "|Machines: ".count($this->network_addresses); $output .= "|Submission: ".date("r", $this->submission_time); $output .= "|Start: ".date("r", $this->start_time); $output .= "|Stop: ".(($this->stop_time > 0)?(date("r", $this->stop_time)):(date("r", $this->start_time + $this->moldable_walltime))); $output .= "|State: {$this->state}"; //$output .= "|Properties: ".htmlspecialchars($this->properties); return $output; } function color($hl) { global $CONF; if ($this->color == NULL or $this->colorHL == NULL) { $hue = Shuffle::get_int($this); $this->color = "hsl(".$hue.",{$CONF['job_color_saturation_lightness']})"; $this->colorHL = "hsl(".$hue.",{$CONF['job_color_saturation_lightness_highlight']})"; } return (($hl)?$this->colorHL:$this->color); } } // Container class for job to resource groupping: since a job may not have continuous resources, it display can be split in serveral groups (rectangles) class Job2ResourceGroup { public $job, $resources; function __construct($job, $r) { $this->job = $job; $this->resources = array($r); } function add_resource($r) { array_push($this->resources, $r); } function size() { return count($this->resources); } } // Storage class for the resource_ids class ResourceId { public $id, $cpuset, $states, $resources, $properties; function __construct($id, $cpuset) { $this->id = $id; $this->cpuset = $cpuset; $this->states = array(); $this->resources = array(); $this->properties = array(); } function add_state($value, $start, $stop) { array_push($this->states, new State($value, $start, $stop)); } function add_resource($resource) { $this->resources[$resource->type] = $resource; } function add_property($key, $value) { $this->properties[$key] = $value; ksort($this->properties); } } // Storage for the abstract resources, e.g. host, cpu, core, a.s.o, i.e. not resource_id class Resource { public $id, $type, $parent, $children, $resource_ids; function __construct($id, $type, $parent) { $this->id = $id; $this->type = $type; $this->parent = $parent; $this->children = array(); $this->resource_ids = array(); $this->jobs = array(); $this->job2resource_groups = array(); } function add_child($id, $type) { if (! array_key_exists($id,$this->children)) { $this->children[$id] = new Resource($id, $type, $this); } return $this->children[$id]; } function add_resource_id($rid) { $this->resource_ids[$rid->id] = $rid; $rid->add_resource($this); } function add_job_occupation($job, $partial) { $this->jobs[$job->job_id] = array($job, $partial); } function add_job2resource_group($g) { array_push($this->job2resource_groups, $g); } function get_hierarchy_info() { if ($this->parent == NULL) { return $this->type.": ".$this->id; } else { return $this->parent->get_hierarchy_info()."|".$this->type.": ".$this->id; } } function cpusets() { $cpusets = array(); foreach ($this->resource_ids as $rid) { array_push($cpusets, $rid->cpuset); } return $cpusets; } function properties() { $properties = array(); foreach ($this->resource_ids as $rid) { foreach ($rid->properties as $key => $value) { if (array_key_exists($key, $properties)) { array_push($properties[$key], $value); } else { $properties[$key] = array($value); } } } return $properties; } function svg_hierarchy($x, $y, $labels=NULL) { global $CONF, $output, $scale, $gantt_width, $gantt_left_align, $resource_base, $first_resource_base, $sorted_resources, $has_aggregated_resources; $h = 0; debug(3,"hierarchy: ". $this->id . "(" . $this->type . ")"); if (in_array($this->type, $CONF['resource_labels'])) { if ($labels == NULL) { $labels = array($this->label()); } else { array_push($labels, $this->label()); } } if (($this->type != $resource_base) and (count($this->resource_ids) >= 1)) { if ($this->type == $CONF['resource_group_level']) { $first_resource_base = true; } usort($this->children, create_function('$a,$b','return $b->cmp($a);')); foreach ($this->children as $child) { $h += $child->svg_hierarchy($x+$CONF['hierarchy_resource_width'], $y+$h, $labels); } $output .= ''; } else { if (count($this->resource_ids) > 1) { $has_aggregated_resources = true; } if ($this->type == $CONF['resource_group_level']) { $first_resource_base = true; } $popup = array(); foreach ($this->properties() as $key => $value) { sort($value); array_push($popup, $key.": ".join(", ", array_unique($value))); } if(in_array("cpuset", $CONF['resource_labels']) and ! in_array("cpuset", $CONF['resource_hierarchy']) and ! $has_aggregated_resources) { array_push($labels, sprintf($CONF['cpuset_label_display_string'],reset($this->cpusets()))); } $output .= ''; $output .= join("/", $labels); $output .= ''; $output .= ''; if ($first_resource_base == true) { $first_resource_base = false; $output .= ''; } else { $output .= ''; } array_push($sorted_resources, $this); $h = $scale; } return $h; } function svg_states($y) { global $CONF, $output, $scale, $resource_base; $states=array(); foreach (array_values($this->resource_ids) as $rid) { foreach ($rid->states as $s) { if (!array_key_exists($s->value, $states)) { $states[$s->value] = array(); } array_push($states[$s->value], array($s->start, 1,$s->real_start), array($s->stop, -1, $s->real_stop)); } } foreach ($states as $value => $date_weight_array) { usort($date_weight_array, create_function('$a,$b','list($d1,$w1)=$a; list($d2,$w2)=$b; return ($d1 != $d2)?(($d1 < $d2)?-1:1):(($w1 != $w2)?(($w1 < $w2)?1:-1):0);')); $weight = 0; foreach ($date_weight_array as $dwr) { list ($d,$w,$r) = $dwr; debug(4, "$value -> $d:$w"); if ($w == -1 and $weight == count($this->resource_ids) and ($d - $start) > $CONF['min_state_duration']) { debug(3, "new full state $start -> $d"); # new state $start,$w,full $info = ucfirst($resource_base)." $value|Since: ".date("r", $real_start)."|Until: ".(($r)?date("r", $r):"indefinite"); $height = $scale; $output .= ''; $start = $d; } $weight += $w; debug(4, "weight: $weight"); if ($w == 1 and $weight == 1) { $start = $d; $real_start = $r; } elseif ($weight == 0 and count($this->resource_ids) > 1 and ($d - $start) > $CONF['min_state_duration']) { debug(3, "new partial state: $start -> $d"); # new state $start,$d,partial $info = ucfirst($resource_base)." partially $value|Since: ".date("r", $real_start)."|Until: ".(($r)?date("r", $r):"indefinite"); $height = $scale/2; $output .= ''; } if ($w == 1 and $weight == count($this->resource_ids) and ($d - $start) > $CONF['min_state_duration']) { debug(3, "new partial state before a full state: $start -> $d"); # new state $start,$d,partial $info = ucfirst($resource_base)." partially $value|Since: ".date("r", $real_start)."|Until: ".(($r)?date("r", $r):"indefinite"); $height = $scale/2; $output .= ''; $start = $d; } } } } function svg_drain($y) { global $CONF, $output, $scale, $gantt_now, $gantt_width, $resource_base; $drain = 0; foreach (array_values($this->resource_ids) as $rid) { if (array_key_exists($CONF['resource_drain_property'], $rid->properties) and ($rid->properties[$CONF['resource_drain_property']] == "YES")) { $drain++; } } if ($drain > 0) { if ($drain < count($this->resource_ids)) { $info = ucfirst($resource_base)." partial draining: no new job accepted"; $height = $scale/2; debug(4, $info); } else { $info = ucfirst($resource_base).((count($this->resource_ids) > 1)?" full":"")." draining: no new job accepted"; $height = $scale; debug(4, $info); } $output .= ''; } } function svg_jobs($y) { global $CONF, $output, $scale, $gantt_now, $output_labels, $patterns, $has_aggregated_resources; if ($has_aggregated_resources) { // we need to display the job on partial resources => we cannot use job groups for that. foreach ($this->jobs as $job_id => $jp) { list($job, $partial) = $jp; if($job->stop_time > 0) { // we know the job's stop time because the the job is in the past $w = date2px($job->stop_time) - date2px($job->start_time); } elseif (in_array('besteffort', $job->types) and ($job->state == "Running")) { $w = date2px($gantt_now) - date2px($job->start_time); } else { $w = date2px($job->start_time + $job->moldable_walltime) - date2px($job->start_time); } if ($partial) { $h = $scale/2; $yy = $y + $scale/2; } else { $h = $scale; $yy = $y; } foreach ($CONF['job_colors'] as $type => $color) { if (preg_grep("/^{$type}$/", $job->types)) { $output .= ''; } } $output .= ''; if (in_array('besteffort', $job->types) and ($job->state == "Running") and ! $CONF['besteffort_truncate_job_to_now']) { foreach ($CONF['job_colors'] as $type => $color) { if (preg_grep("/^{$type}$/", $job->types)) { $output .= ''; } } if (! array_key_exists($job->job_id, $patterns)) { $p = preg_replace("/%%PATTERN_ID%%/", "besteffort{$job->job_id}Pattern", $CONF['besteffort_pattern']); $p = preg_replace("/%%PATTERN_COLOR%%/", $job->color(false), $p); $patterns[$job->job_id] = $p; $p = preg_replace("/%%PATTERN_ID%%/", "besteffortHL{$job->job_id}Pattern", $CONF['besteffort_pattern']); $p = preg_replace("/%%PATTERN_COLOR%%/", $job->color(true), $p); $patterns[$job->job_id] .= $p; } $output .= 'job_id}Pattern)".'" stroke-width="0" style="opacity: 0.3" onmouseover="mouseOver(evt,\''.$job->svg_text().'\', \'job'.$job->job_id.'\')" onmouseout="mouseOut(evt, \'job'.$job->job_id.'\')" onclick="jobclick(evt, \''.$job->job_id.'\')" onmousemove="mouseMove(evt)" />'; } } } foreach ($this->job2resource_groups as $grp) { if($grp->job->stop_time > 0) { // we know the job's stop time because the the job is in the past $w = date2px($grp->job->stop_time) - date2px($grp->job->start_time); } elseif (in_array('besteffort', $grp->job->types) and ($grp->job->state == "Running") and $CONF['besteffort_truncate_job_to_now']) { $w = date2px($gantt_now) - date2px($grp->job->start_time); } else { $w = date2px($grp->job->start_time + $grp->job->moldable_walltime) - date2px($grp->job->start_time); } if ($has_aggregated_resources) { // we only have to display the base rectangle using the job group $output .= ''; } else { // we do everything using the job group foreach ($CONF['job_colors'] as $type => $color) { if (preg_grep("/^{$type}$/", $grp->job->types)) { $output .= ''; } } if (in_array('besteffort', $grp->job->types) and ($grp->job->state == "Running") and ! $CONF['besteffort_truncate_job_to_now']) { if (! array_key_exists($grp->job->job_id, $patterns)) { $p = preg_replace("/%%PATTERN_ID%%/", "besteffort{$grp->job->job_id}Pattern", $CONF['besteffort_pattern']); $p = preg_replace("/%%PATTERN_COLOR%%/", $grp->job->color(false), $p); $patterns[$grp->job->job_id] = $p; $p = preg_replace("/%%PATTERN_ID%%/", "besteffortHL{$grp->job->job_id}Pattern", $CONF['besteffort_pattern']); $p = preg_replace("/%%PATTERN_COLOR%%/", $grp->job->color(true), $p); $patterns[$grp->job->job_id] .= $p; } $output .= 'job->job_id}Pattern)".'" stroke-width="0" style="opacity: 0.3" onmouseover="mouseOver(evt,\''.$grp->job->svg_text().'\', \'job'.$grp->job->job_id.'\')" onmouseout="mouseOut(evt, \'job'.$grp->job->job_id.'\')" onclick="jobclick(evt, \''.$grp->job->job_id.'\')" onmousemove="mouseMove(evt)" />'; $ww = date2px($gantt_now) - date2px($grp->job->start_time); } else { $ww = $w; } $output .= ''; $output .= ''; } if ($w > $CONF['gantt_min_job_width_for_label']) { $output_labels .= ''; $output_labels .= $grp->job->job_id; $output_labels .= ''; } } } function label() { global $CONF; if ($this->type == 'cpuset') { return sprintf($CONF['cpuset_label_display_string'],$this->id); } else { if (array_key_exists($this->type, $CONF['label_display_regex'])) { return preg_replace($CONF['label_display_regex'][$this->type],'$1',$this->id); } } return $this->id; } function cmp($r) { global $CONF; debug(4, "cmp: " . $this->id." ??? ".$r->id . " (" . $this->type . ")"); if (array_key_exists($this->type, $CONF['label_cmp_regex'])) { $r1 = preg_match($CONF['label_cmp_regex'][$this->type],$this->id, $v1); $r2 = preg_match($CONF['label_cmp_regex'][$this->type],$r->id, $v2); if (!$r1 or !$r2) { debug(5, "cmp: regex match failed"); $v1 = array($this->id); $v2 = array($r->id); } else { debug(5, "cmp: regex matches"); array_shift($v1); array_shift($v2); } } else { debug(5, "cmp: no regex to match"); $v1 = array($this->id); $v2 = array($r->id); } debug(4, "cmp: " . join(",",$v1) . " ? " . join(",",$v2)); while (($e1 = array_shift($v1)) != NULL) { $e2 = array_shift($v2); if ($e1 < $e2) { debug(4, "cmp: $e1 < $e2"); return 1; } elseif ($e2 < $e1) { debug(4, "cmp: $e1 > $e2"); return -1; } debug(4, "cmp: $e1 = $e2"); } return 0; } } /////////////////////////////////////////////////////////////////////////////// // Main program /////////////////////////////////////////////////////////////////////////////// debug(1, "starting drawgantt-svg"); $script_start_time = microtime(true); // Connecting database $db = new Db($CONF['db_type'], $CONF['db_server'], $CONF['db_port'], $CONF['db_name'], $CONF['db_user'], $CONF['db_passwd']); // Retrieve the "now" date debug(2,"retrieve time from DB"); $gantt_now = $db->get_timestamp(); // Compute gantt start and stop dates if ($gantt_start_date == 0) { $gantt_start_date = $gantt_now + $gantt_relative_start_date; } if ($gantt_stop_date == 0) { $gantt_stop_date = $gantt_now + $gantt_relative_stop_date; } $timespan = $gantt_stop_date - $gantt_start_date; if ($timespan < $CONF['min_timespan']) { debug(2, "Timespan $timespan too small, using ".$CONF['min_timespan']); $timespan = $CONF['min_timespan']; $gantt_start_date = ($gantt_stop_date + $gantt_start_date)/2 - $timespan / 2; $gantt_stop_date = $gantt_start_date + $timespan; } // Retrieve the resource hierarchy $resource_root = new Resource($CONF['site'], 'site', NULL); $resource_ids = array(); /////////////////////////////////////////////////////////////////////////////// // Retrieve OAR data from database /////////////////////////////////////////////////////////////////////////////// $aborted = false; // common function used both for past and current jobs and predicted jobs function parse_jobs_from_db($query) { global $CONF, $db, $jobs, $resource_ids, $aborted; $t0 = microtime(true); $l = 0; $j = 0; if ($aborted) { debug (1, "already aborted"); return; } debug(2,"start parsing jobs from " . $db->num_rows . " rows of data"); $db->query($query); if ($db->num_rows > $CONF['db_max_job_rows']) { debug (1, "too many data ( > " . $CONF['db_max_job_rows'] . " rows), aborting"); $aborted = true; return; } while ($line = $db->fetch_array()) { if (! array_key_exists($line['job_id'], $jobs)) { debug(3, "got new job: ".$line['job_id']); $jobs[$line['job_id']] = new Job($line['job_id'], $line['job_name'], $line['project'], $line['job_type'], $line['state'], $line['job_user'], $line['command'], $line['queue_name'], $line['moldable_walltime'], $line['properties'], $line['launching_directory'], $line['submission_time'], $line['start_time'], $line['stop_time']); $j++; } else { debug(4, "got an additional line for job: ".$line['job_id']); } if (array_key_exists($line['resource_id'], $resource_ids)) { $jobs[$line['job_id']]->add_resource_id($resource_ids[$line['resource_id']]); } else { // create new resource_id so than the job gets the right resource_id count, even if that resource_id is not displayed in the grid... (filter) debug(2, "create a phantom resource: " . $line['resource_id'] . " ,for job:" . $line['job_id']); $jobs[$line['job_id']]->add_resource_id(new ResourceId($line['resource_id'], -1)); } $jobs[$line['job_id']]->add_network_address($line['network_address']); $jobs[$line['job_id']]->add_type($line['type']); $l++; if (($l % 1000) == 0) { debug(2, "$l rows parsed, got $j jobs, in " . (microtime(true) - $t0) . "s"); } } $db->free(); debug(2,"parsing done, got $j jobs, in " . (microtime(true) - $t0) . "s"); } if ($display != "mobile_ruler_only") { $query = 'SELECT ' . join(',',array_unique(array_merge($CONF['resource_properties'], $CONF['resource_hierarchy'], array('cpuset', 'resource_id')))) . ' FROM resources' . ($resource_filter?' WHERE ('.stripslashes($resource_filter).')':''); debug(2,"retrieve resources from DB"); $db->query($query); while ($line = $db->fetch_array()) { $rid = new ResourceId($line['resource_id'], $line['cpuset']); foreach ($CONF['resource_properties'] as $rp) { $rid->add_property($rp, $line[$rp]); } $resource_ids[$line['resource_id']] = $rid; $resource_root->add_resource_id($rid); $r = $resource_root; foreach ($CONF['resource_hierarchy'] as $rh) { debug(4, "add resource $rh: " . $line[$rh] . " to " . $r->type . ": " . $r->id); $r = $r->add_child($line[$rh],$rh); $r->add_resource_id($rid); } } $db->free(); // Retrieve the states of resources $value_int = $db->cast("value","int"); $query = <<= {$gantt_start_date} ) AND ( ( attribute = 'state' AND ( value = 'Absent' OR value = 'Dead' OR value = 'Suspected' ) ) OR ( attribute = 'available_upto' AND {$value_int} > {$gantt_now} AND date_stop = 0 ) ) EOT; $available_upto_lines = array(); debug(2,"retrieve states from DB"); $db->query($query); while ($line = $db->fetch_array()) { if ($line['attribute'] == 'state') { if (array_key_exists($line['resource_id'], $resource_ids)) { $resource_ids[$line['resource_id']]->add_state($line['value'], $line['date_start'], $line['date_stop']); } } else { array_push($available_upto_lines, $line); } } $db->free(); if ($gantt_now < $gantt_stop_date) { foreach ($available_upto_lines as $line) { if (array_key_exists($line['resource_id'], $resource_ids)) { $resource_id = $resource_ids[$line['resource_id']]; for ($i=0; $i < count($resource_id->states); $i++) { $state = $resource_id->states[$i]; if ($state->value == 'Absent') { if ($gantt_now < $gantt_start_date) { unset($resource_id->states[$i]); } elseif ($state->real_stop == 0) { if ($CONF['standby_truncate_state_to_now']) { $state->set_stop($gantt_now); } $state->value = 'Standby'; } } } } } } // Array to store jobs $jobs = array(); // Retrieve past and current jobs $aborted = false; $query = <<= {$gantt_start_date} OR ( jobs.stop_time = '0' AND ( jobs.state = 'Running' OR jobs.state = 'Suspended' OR jobs.state = 'Resuming' ) ) ) AND jobs.start_time < {$gantt_stop_date} AND jobs.assigned_moldable_job = assigned_resources.moldable_job_id AND moldable_job_descriptions.moldable_job_id = jobs.job_id AND resources.resource_id = assigned_resources.resource_id ORDER BY jobs.job_id EOT; debug(2,"retrieve past and current jobs from DB"); parse_jobs_from_db($query); // Retrieve predicted jobs (future) $query = <<= {$gantt_start_date} AND jobs.job_id NOT IN ( SELECT job_id FROM job_types WHERE type = 'besteffort' AND types_index = 'CURRENT' ) ORDER BY jobs.job_id EOT; debug(2,"retrieve predicted jobs from DB"); parse_jobs_from_db($query); } // Closing connection to the database $db->close(); /////////////////////////////////////////////////////////////////////////////// // SVG document generation /////////////////////////////////////////////////////////////////////////////// $output = ""; $gantt_height = 0; if ($display != "no_ruler") { $gantt_top = $CONF['gantt_top']; $gantt_min_height = $CONF['gantt_min_height']; $bottom_margin = $CONF['bottom_margin']; } else { $gantt_top = 1; $gantt_min_height = 0; $bottom_margin = 0; } if ($display != "mobile_ruler_only") { $sorted_resources = array(); $has_aggregated_resources = false; $gantt_height = $resource_root->svg_hierarchy($CONF['hierarchy_left_align'], $gantt_top); debug(2, "has aggreagated resources: ".($has_aggregated_resources?"yes":"no")); // Split resources of jobs in continuous groups if (!$aborted) { $t0=microtime(true); debug(2, "start grouping resources of jobs"); foreach ($jobs as $job) { $job->group_resources($sorted_resources); } debug(2, "grouping done in " . (microtime(true) - $t0) . "s"); } $y = $gantt_top; foreach ($sorted_resources as $r) { $r->svg_states($y); $y += $scale; } $y = $gantt_top; foreach ($sorted_resources as $r) { $r->svg_drain($y); $y += $scale; } $y = $gantt_top; foreach ($sorted_resources as $r) { $r->svg_jobs($y); $y += $scale; } $output .= $output_labels; // compute sizes $page_height = max($gantt_min_height, $gantt_top + $gantt_height + $bottom_margin); } else { $page_height = 30; } $page_width = $gantt_left_align + $gantt_width + $CONF['right_margin']; // labers will be printed at the end of the doc to be on top of the job boxes. $output_labels = ""; // SVG headers + script + defs $output_headers = << EOT; if ($display != 'mobile_ruler_only') { // diagram drawing $output = ''.$output; } else { $output = ""; } // compute the steps of the time rulers $ruler_step= ($gantt_stop_date - $gantt_start_date) / ($CONF['time_ruler_scale']); while (($r = array_pop($CONF['time_ruler_steps'])) >= $ruler_step) {} $ruler_step = $r; if ($display != 'mobile_ruler_only' and $display != 'no_ruler') { // print top time ruler $d = $gantt_start_date - $gantt_start_date % $ruler_step; while(($d += $ruler_step) < $gantt_stop_date) { $output .= ''.date("Y-m-d",$d).''; $output .= ''.date("H:i:s",$d).''; } // print bottom time ruler $d = $gantt_start_date - $gantt_start_date % $ruler_step; while(($d += $ruler_step) < $gantt_stop_date) { $output .= ''.date("Y-m-d",$d).''; $output .= ''.date("H:i:s",$d).''; } } if ($display != 'mobile_ruler_only') { // print time grid lines $d = $gantt_start_date - $gantt_start_date % $ruler_step; while(($d += $ruler_step) < $gantt_stop_date) { $output .= ''; } // print now line if ($gantt_now < $gantt_start_date or $gantt_now > $gantt_stop_date) { $output .= ''; } else { $output .= ''; } } if ($display != 'no_mobile_ruler' and $display != "no_ruler") { // print mobile time ruler $output .= ''; $output .= ''; $d = $gantt_start_date - $gantt_start_date % $ruler_step; while(($d += $ruler_step) < $gantt_stop_date) { $output .= ''.date("Y-m-d",$d).''; $output .= ''.date("H:i:s",$d).''; } $output .= ''; } // print volatile stuff: infobox + zoom $output .= << EOT; $script_exec_time = microtime(true) - $script_start_time; if ($display != 'mobile_ruler_only' and $display != 'no_ruler') { $output .= 'OAR drawgantt-svg for '.$CONF['site'].' - ref date: '.date("Y-m-d H:i:s",($gantt_start_date + $gantt_stop_date) / 2).' timespan: '.(($timespan >= 3600*24)?(floor($timespan/3600/24)."d"):"").gmdate("H\hi\ms\s",$timespan).' - generated in '.sprintf("%.3f",$script_exec_time).'s'; } // end SVG doc $output .= << EOT; $output_defs = "".$CONF['static_patterns'].join("",array_values($patterns)).""; // generate doc header("Content-Type: image/svg+xml"); header('Content-Encoding: gzip'); print gzencode($output_headers . $output_defs . $output); debug(1, "=> total execution time: " . $script_exec_time . "s"); ?> �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������oar-2.5.7/sources/visualization_interfaces/DrawGantt-SVG/multisite.html�����������������������������0000644�0150147�0001750�00000011140�12677211234�025747� 0����������������������������������������������������������������������������������������������������ustar �neyron��������������������������neyron����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� Drawgantt Multisite NG
oar-2.5.7/sources/visualization_interfaces/DrawGantt-SVG/test.html0000644015014700017500000000162612677211234024717 0ustar neyronneyron Drawgantt

oar-2.5.7/sources/visualization_interfaces/DrawGantt-SVG/drawgantt.php.in0000644015014700017500000004031212677211234026156 0ustar neyronneyron * */ //////////////////////////////////////////////////////////////////////////////////////////////////// // Configuration: DO NOT EDIT HERE. Customization must go in /etc/oar/drawgantt-config.inc.php //////////////////////////////////////////////////////////////////////////////////////////////////// $CONF=array(); // Default settings for the default view $CONF['default_start'] = ""; // default start and stop times (ctime values) ; unless you want to always show a $CONF['default_stop'] = ""; // same time frame, keep those values to "" $CONF['default_relative_start'] = ""; // default relative start and stop times ([+-]), mind setting it $CONF['default_relative_stop'] = ""; // accordingly to the nav_forecast values below, eg -24*3600*0.1 and 24*3600*0.9 $CONF['default_timespan'] = 6*3600; // default timespan, should be one of the nav_timespans below $CONF['default_resource_base'] = 'cpuset'; // default base resource, should be one of the nav_resource_bases below $CONF['default_scale'] = 10; // default vertical scale of the grid, should be one of the nav_scales bellow // Navigation bar configuration $CONF['nav_timespans'] = array( // proposed timespan in the "set" bar '1 hour' => 3600, '3 hours' => 3*3600, '6 hours' => 6*3600, '12 hours' => 12*3600, '1 day' => 24*3600, '3 day' => 3*24*3600, '1 week' => 7*24*3600, ); $CONF['nav_forecast'] = array( // forecast display '1 day' => 24*3600, '3 days' => 3*24*3600, '1 week' => 7*24*3600, '2 weeks' => 2*7*24*3600, '3 weeks' => 3*7*24*3600, ); $CONF['nav_forecast_past_part'] = 0.1; // past part to show (percentage if < 1, otherwise: number of seconds) $CONF['nav_scales'] = array( // proposed scales for resources 'small' => 10, 'big' => 20, 'huge' => 40, ); $CONF['nav_timeshifts'] = array( // proposed time-shifting buttons '1h' => 3600, '6h' => 6*3600, '1d' => 24*3600, '1w' => 7*24*3600, ); $CONF['nav_filters'] = array( // proposed filters in the "misc" bar 'all clusters' => 'resources.type = \'default\'', 'cluster1 only' => 'resources.cluster=\'cluster1\'', 'cluster2 only' => 'resources.cluster=\'cluster2\'', 'cluster3 only' => 'resources.cluster=\'cluster3\'', ); $CONF['nav_resource_bases'] = array( // proposed base resources 'network_address', 'cpuset', ); $CONF['nav_timezones'] = array( // proposed timezones in the "misc" bar (the first one will be selected by default) 'UTC', 'Europe/Paris', ); $CONF['nav_custom_buttons'] = array( // custom buttons, click opens the url in a new window 'my label' => 'http://my.url' // remove all lines to disable (empty array) ); // Overwrite configuration with values from drawgantt-config.inc.php define('CONFIG_DIR', '%%OARCONFDIR%%'); define('CONFIG_FILE', CONFIG_DIR . '/drawgantt-config.inc.php'); if (is_readable(CONFIG_FILE)) { require CONFIG_FILE; } $resource_base = array_key_exists('resource_base',$_GET)?$_GET['resource_base']:$CONF['default_resource_base']; $filter = array_key_exists('filter',$_GET)?$_GET['filter']:reset($CONF['nav_filters']); $timezone = array_key_exists('timezone',$_GET)?$_GET['timezone']:reset($CONF['nav_timezones']); $relative_start = array_key_exists('relative_start',$_GET)?$_GET['relative_start']:$CONF['default_relative_start']; $relative_stop = array_key_exists('relative_stop',$_GET)?$_GET['relative_stop']:$CONF['default_relative_stop']; $start = array_key_exists('start',$_GET)?$_GET['start']:$CONF['default_start']; $stop = array_key_exists('stop',$_GET)?$_GET['stop']:$CONF['default_stop']; $timespan = array_key_exists('timespan',$_GET)?$_GET['timespan']:$CONF['default_timespan']; $scale = array_key_exists('scale',$_GET)?$_GET['scale']:$CONF['default_scale']; $output = << OAR Drawgantt SVG
EOT; $output_before = ""; $output_after = ""; foreach ($CONF['nav_timeshifts'] as $key => $value) { $output_before = "" . $output_before; $output_after .= ""; } $output .= $output_before; $output .= ""; $output .= ""; $output .= ""; $output .= ""; $output .= ""; $output .= $output_after; $output .= ""; $output .= ""; if (count($CONF['nav_forecast']) > 0) { $output .= ""; } $output .= "\n"; $output .= ""; $output .= ""; $output .= "\n"; $output .= ""; $output .= "\n"; foreach ($CONF['nav_custom_buttons'] as $key => $value) { $output .= ""; } $output .= <<
PROCESSING DATA, PLEASE WAIT...
ref date: timespan: