pax_global_header00006660000000000000000000000064144371611340014516gustar00rootroot0000000000000052 comment=c995761c2e1b58ef5b0b67d5fc96e4b2d46857fe vdradmin-am-3.6.13/000077500000000000000000000000001443716113400140075ustar00rootroot00000000000000vdradmin-am-3.6.13/.dir-locals.el000066400000000000000000000003611443716113400164400ustar00rootroot00000000000000((css-mode . ((indent-tabs-mode . t) (css-indent-offset . 8))) (html-mode . ((indent-tabs-mode . t) (sgml-basic-offset . 8))) (js-mode . ((indent-tabs-mode . t) (js-indent-level . 8)))) vdradmin-am-3.6.13/.gitignore000066400000000000000000000002041443716113400157730ustar00rootroot00000000000000/cache/ /locale/ /po/*.mo /ChangeLog* /vdradmind.at /vdradmind.conf /vdradmind.done /vdradmind.log /vdradmind.pid /*.bz2 tags *.swp vdradmin-am-3.6.13/COPYING000066400000000000000000000431031443716113400150430ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. vdradmin-am-3.6.13/CREDITS000066400000000000000000000015421443716113400150310ustar00rootroot00000000000000Current authors (-AM branch): - Andreas Mair, amair.sob@googlemail.com - Ville Skyttä, ville.skytta@iki.fi Contributors (-AM branch): - pbiering https://github.com/pbiering - MegaV0lt https://github.com/MegaV0lt Original author: Thomas Koch, tom@linvdr.org The translation team: - Czech: Karel Borkovec - Dutch: Roel Koelewijn - English: Andreas Mair - Finnish: Rolf Ahrenberg, Ville Skyttä - French: Trois Six, map, lobotomise, bads, Mickaël Nival - German: Andreas Mair - Hungarian: István Füley - Italian: Diego Pierotto - Spanish: Rüdiger Jung, Manuel Gomez - Russian: Oleg Roitburd and Allrussian-forum translation team This package includes/uses: - KDE Crystal theme icons; Copyright (C) 2002 and following years KDE Artists - Bubblehelp infoboxes; (C) 2007 Klaus Knopper - Some Perl modules; see "lib" folder vdradmin-am-3.6.13/FAQ000066400000000000000000000021571443716113400143460ustar00rootroot00000000000000Q: Setting the language for VDRAdmin-AM does not work. What can I do? A: There are some things to check: - Check if "perl -V:d_setlocale" prints "d_setlocale='define';". If it doesn't contact your Linux distributor. - Run: echo -e "LANGUAGE=$LANGUAGE\nLANG=$LANG\nLC_ALL=$LC_ALL" LANGUAGE *must* be empty so that you can set the language in VDRAdmin-AM's configuration menu. If it's not empty VDRAdmin-AM will *always* use that language if it supports it or English if it doesn't support it. LANG and/or LC_ALL are used if you set the language to "System default" in VDRAdmin-AM. Q: I don't get a picture in "Watch TV"! A: This feature uses VDR's "GRAB" SVDRP command that requires a Full-Featured DVB card or an output plugin that implements the GRAB command. In VDRAdmin-AM you can use the "Commands" menu to check if grabbing works in VDR. Execute "grab -". If it returns "Grab image failed" your VDR can't grab and you can't watch TV in VDRAdmin-AM. Q: Can I run VDRAdmin-AM on Windows? A: Yes, have a look at http://www.open7x0.org/wiki/VDRAdmin-AM_unter_Windows (German language only). vdradmin-am-3.6.13/HISTORY000066400000000000000000001246771443716113400151140ustar00rootroot000000000000002023-06-02: 3.6.13 - Improvement: increase height of EPG images 2023-06-01: - Fixed: search text with umlauts (https://github.com/vdr-projects/vdradmin-am/issues/18) - Improvement: display EPG images with filename including channel ID (https://github.com/vdr-projects/vdradmin-am/issues/19) 2023-03-12: 3.6.12 - Fixed: log levels (https://github.com/vdr-projects/vdradmin-am/pull/16) - Adjust: config/channelselection: remove selected channels from available list (https://github.com/vdr-projects/vdradmin-am/pull/17) - Improvement: insert date/time/length to delete confirmation (https://github.com/vdr-projects/vdradmin-am/pull/15) - Improvement: major speed-up display of recording list (https://github.com/vdr-projects/vdradmin-am/pull/14) 2023-02-26: 3.6.11 - Fixed: restart issues related to PID file cleanup and socket ressage (https://github.com/vdr-projects/vdradmin-am/pull/5) - Fixed: 'ST_DIRECT_LINKS_ON = 1' resulting in problem providing the URL (https://github.com/vdr-projects/vdradmin-am/pull/4) - Fixed: outdated/broken IMDb URL (https://github.com/vdr-projects/vdradmin-am/pull/3) - Adjust: adapt values to FullHD (Affects webif tv preview) (https://github.com/vdr-projects/vdradmin-am/pull/8) - Fixed: do not sort channellist because same channels appear side by side (https://github.com/vdr-projects/vdradmin-am/pull/8) - Added: systemd/sysconfig and RPM spec file 2023-02-10: 3.6.10-glenvt18 - Adjust: templates - Adjust: change from IO::Socket to HTTP::Daemon - Adjust: change preview aspect ratio to 16:9 - Improved: EPG parser - Adjust: disable recordings caching by default - Fixed: deleting multiple recordings with >= VDR-2.3.2 - Fixed: truncation of channel names in the timer table - Fixed: sorting of timers and recordings - Fixed: don't check $LOGDIR permissions when logging to syslog or stderr - Fixed: CSS issues with firefox - Added: add an option to stream recordings with streamdev - Fixed: some CGI::param vulnerability warnings - Added: config option to restrict access to local nets only - Fixed: recording files search - Added: option to use direct links to live streams - Adjust: use channel groups from VDR - Adjust: sort channel lists by channel name - Adjust: renamed DESTDIR environment variable to PREFIX 2014-08-05: 3.6.10 - Improved: Optimized images to reduze their size. (Submitted by Ville Skyttä) - Improved: Sort recordings secondarily by date when sorting by name. Makes the ordering stabler for multiple recordings with the same name. (Submitted by Olli Lammi) - Added: streaming of recordings folders (Submitted by Daniel Matzke). - Added: Hungarian translation (Submitted by István Füley). - Fixed LSTR when executing recording commands on VDR >= 1.7.21 (Submitted by David Rütti) - Updated: Italian translation (thanks to Diego Pierotto). - Updated: Finnish translation. 2011-11-20: 3.6.9 - Added: Support changed SVDRP LSTR output of VDR >= 1.7.21. - Fixed: --log 0 command line argument. - Improved: Startup error messages on module load failures. - Added: -L/--logfile command line arg for overriding config. - Changed: Honor config logging options with --nofork. - Changed: Specifying -L or -l turns logging on. - Improved: Do not require pid dir when not running as daemon. - Improved: Autodetect default for number of DVB cards. - Fixed: Non-localhost streamdev URL (Bug report #653). - Added: Live TV streaming with Xineliboutput plugin. - Improved: Adapt rename recording to Liemikuutio 1.32. - Added: Show recording length in list and details with VDR >= 1.7.21 (Bug report #813). - Added: Show available subtitles in EPG/recording details. - Updated: German translation. 2011-06-03: 3.6.8 - Updated: Dutch translation (Submitted by Roel Koelewijn). - Updated: Finnish translation. - Improved: Access logging. - Improved: SVDRP connection error handling/logging/messages. - Improved: Default SVDRP port is 6419 in initial config if locally installed VDR is >= 1.7.15. - Improved: Use default streamdev host from browser URL when VDR host is localhost. - Improved: Allow specifying multiple local subnets (Feature #560). 2010-04-10: 3.6.7 - Updated: Italian translation (Submitted by Diego Pierotto). - Fixed: creating/editing of searches using EPGsearch v0.9.24 (Bug report #567). - Minor bugfixes and improvements. 2010-03-13: 3.6.6 - Added: Support new epgsearch v0.9.25-git settings "unmute" and "min. description match". - Changed: Log to syslog by default (if logging is enabled). - Changed: Fall back to stderr if setting up syslog fails. - Changed: Get character encoding from configured locale or environment variables (Submitted by Tobias Grimm). - Fixed: Encode SVDRP commands sent to VDR if needed (Submitted by Tobias Grimm). - Updated: Italian translation (Submitted by Diego Pierotto). - Updated: Dutch translation (Submitted by Roel Koelewijn). - Updated: Spanish translation (Submitted by Manuel Gomez). - Improved: Default mail settings. - Fixed: Check if "GUI_POPUP_WIDTH" and "GUI_POPUP_HEIGHT" are numeric and set them to the defaults if they are not (Reported by Jan). - Added: Support VDR 1.7.12+ commands.conf and reccmds.conf (means: skip lines ending in "{" and lines with only "}" in them). - Added: check file and directory permissions on startup abort on error. - Changed: Default directory for PID file to /var/run/vdradmin. - Changed: Default directory for log file to /var/log/vdradmin. - Changed: Use "cache" directory in the current directory if $SEARCH_FILES_IN_SYSTEM is not set. - Changed: Hide "record" button in EPG lists there's already a timer for that broadcast (Based on patch by Dave Pickles). - Added: New options to show or hide a broadcast's subtitle and/or summary in EPG lists (Based on patch by Dave Pickles). - Added: New option to set a day's "start time" in "Playing today?" (Based on patch by Dave Pickles). - Changed: Minimum required epgsearch version now is 0.9.24. - Added: Support for new epgsearch search timer actions (Bug #557). - Changed: "--ipv6" only enables IPv6 for connections to VDRAdmin-AM, to also use IPv6 for SVDRP connection one can use "--ipv6-all" (if he really knows what he's doing!). - Fixed: Check encoding for every SVDRP connection (Submitted by Tobias Grimm). - Changed: Warn about missing key or certificate if --ssl is used. - Changed: Certificates for --ssl option must be located in $ETCDIR/certs. - Fixed: Resizing browser window in "Timeline" showed "file not found" (Reported by tag @vdr-portal.de). - Updated: Links to EPGSearch and Streamdev home pages. - Updated: Finnish translation. 2009-12-30: 3.6.5 - Changed: use HTTP::Date for HTTP date/time formatting. - Improved: Create fewer SVDRP connections. - Fixed: some jslint warnings in javascript files. - Improved: Config file read/write error handling. - Improved: Send Last-Modified header for static resources. - Added: "-l" and "--log" parameter. - Changed: "-nf" option to "-n". - Changed: Logging. - Added: "--ssl" switch to accept https instead of http. - Added: Find VDR 1.7.2+ TS recordings. - Updated: Italian translation (Submitted by Diego Pierotto). - Fixed: epgsearch uses seconds in aux field of timers, not minutes (Reported by Rincewind99 @vdr-portal.de). - Fix bug #507 "EPGsearch custom categories no longer show". - Fixed: Saving the config showed error message "1". - Reworked: Spanish translation (Submitted by Manuel Gomez). - Fixed: failing check whether the process with our pid is a vdradmind - Fixed: always exit with status 1 from --kill if no processes were killed - Improved: pid file error handling - Added: autotimer schedule change tracking option in UI - Fixed: use text/javascript for JavaScript in HTTP headers - Updated: required Perl module documentation - Improved: template caching options (stat ttl, default cache dir is now /var/cache/vdradmin) - Improved: error message when binding the server socket fails - Improved: warn if log file cannot be written to - Fixed: don't try to delete pid file in non-daemon mode. - Improved: include reason in pid file deletion error message. - Added: ability to log to syslog ("LOGFILE = syslog" in config). - Changed: non-daemon mode (-nf) always turns on logging to stderr. 2008-12-20: 3.6.4 - Added: Use ".update" in VDR's video directory to check if recordings cache needs to be refreshed. - Added: CACHE_REC_ENABLED option in vdradmind.conf to enable (1) or disable (0) recordings caching. - Changed: Encode.pm now is optional and no recoding will happen if it's missing. - Updated: Finnish translation 2008-12-13: 3.6.3 - Updated: Spanish translation (Submitted by Rüdiger Jung). - Changed: Process name to "vdradmind" (Based on patch submitted by Ville Skyttä). - Updated: Italian translation (Submitted by Diego Pierotto). - Changed executable's name from "vdradmind.pl" to "vdradmind". - Updated: Dutch translation (Submitted by Roel Koelewijn). - Added Play/Stop/FastForward/etc. buttons to remote controls (based on patch by L.Locke @vdr-portal.de). - Added: epgsearch templates can be created, modified and deleted. - Read used character encoding in SVDRP connections and recode result to the encoding used in the current locale. - Minor bugfixes and improvements. 2008-06-30: 3.6.2 - Changed: No need to set the VFAT option in VDRAdmin-AM any longer as both filename codings will be searched for. - Fixed: some bugs in tv.html. - Fixed: command line options parsing. - Fixed: pattern titles that contain double quotes. - Fixed: timer titles that contain double quotes. - Added: new command line switch "--ipv6" to use IO::Socket::INET6 for networking (See bug report #462). - Updated: Dutch translation (Submitted by Roel Koelewijn). - Added: ST_STREAMDEV_HOST config option to set the name/ip to be used for streaming. - Fixed: m3u files for Xine (Reported by Robert C. Helling). - Updated: Italian translation (Submitted by Diego Pierotto). - Updated: Spanish translation (Submitted by Rüdiger Jung). - Updated: Finnish translation (Submitted by Rolf Ahrenberg). - Changed: include UTF8 locales by default. - Introduced new config options "GUI_POPUP_WIDTH" and "GUI_POPUP_HEIGHT" for setting the prog_detail's window size (Requested by Viking @vdr-portal.de). - Added prev/next arrows in prog_list after each day (Requested by Faudeer @vdr-portal.de). - Show channel in prog_list even if it's not in the current channel list; this is useful if prog_list is called by a link (e.g. timer_list) (Requested by Faudeer @vdr-portal.de). - Added support for modifying EPGSearch blacklists (Requested by dings @vdr-portal.de). - Show stream and switch buttons in prog_summary on channels without EPG information (Reported by Faudeer @vdr-portal.de). - Added: Show channelname in recording's details (Suggested by Stefan Seyfried). - Minor bugfixes and improvements. 2007-12-19: 3.6.1 - Fixed: show textfield if no locales found. - Updated for infoboxes.js. - Fixed: wrong sorting in find results. - Changed: Remove leading and trailing whitespaces from a timer's title (Reported by Derek). - Changed: Minimal required EPGsearch version to v0.9.23. - Added: Support for features introduced in EPGsearch v0.9.23 (e.g. auto delete searches, timeframe for searches). - Fixed: Close connection to VDR after AutoTimer update (Reported by Leo @vdr-portal.de). 2007-09-21: 3.6.0 - Added: missing license information. - Changed: prog_timeline uses global channels array instead of copying it locally. - Fixed: Bug in prog_timeline introduced in 3.6.0beta (Reported by several users). - Updated: Italian translation (Submitted by Diego Pierotto) - Updated: Spanish translation (Submitted by Rüdiger Jung). - Fixed: Channel range in epgsearch_new didn't work since 3.6.0beta (Reported by mblaster4711 @vdr-portal.de). 2007-08-27: 3.6.0rc - Updated: French translation (Submitted by Trois Six). - Updated: Dutch translation (Submitted by Roel Koelewijn). - Updated: Finnish translation (Submitted by Ville Skyttä & Rolf Ahrenberg). - Reworked: configuration part: selected channels work again and settings are only applied if "save" or "apply" is pressed in config menu. - Fixed: initialisation of CHANNEL_WANTED_ config options. 2007-08-17: 3.6.0beta - Added: export of channels in each channel group as m3u playlist in vdr_cmds. - Added: channel list to rc. - Added: VDRAdmin-AM now holds four default channel groups: all channels / selected channels / tv channels / radio channels. - Reworked: Logging; Use "LOGFILE = stderr" if you want logging to stderr. - Added: If background EPG refreshes are enabled, VDRAdmin-AM will try to read the EPG data from VDR at startup and if VDR can't be reached it will try every minute until it can read the EPG data. - Added: New option in configuration for enabling/disabling background EPG refreshes. - Changed: default for tv.html to only show the grabbed picture (for VDR streamingtool). - Added: config option "Show channels without EPG information" - Fixed: wrong background color for some broadcasts having timers in prog_timeline. - Fixed: Last frame now shows "REC" (see bug report #249). - Fixed: Reduce memory usage of EPG tree. - Fixed: Priority and lifetime can be set to "0" (See bug report #232). - Changed: Priority/Lifetime/Buffer Start/Buffer Stop in (Auto)Timer can now be empty ("") which means "use default set in configuration". - New: configure options for AutoTimer: start/stop buffer. - Fixed: Handle symbolic links when find'ing video files for a recording. - Added: "stderr" as special LOGFILE target to log to stderr (=console?). - Fixed: LOGFILE config file option. - Fixed: Allow more than two characters in EPGsearch's "record" action (See bug report #286). - Changed: Join CACHE_TIMEOUT and AT_TIMEOUT to their minimum in CACHE_TIMEOUT. - Added: New buttons in EPG views to edit the EPG entry (Based on patch by Christoph Haubrich). - Added: New "--pid" vdradmind.pl to set the used pidfile. - Added: extended information in m3u file used for livetv streaming (Submitted by Samuli Sorvakko). - Changed: IMDb search URL can be modified. - Added: Optional user defined external search (Based on suggestion by Axel Röhken). - Fixed: Saving of wrong timer if repeating timers have no day set (= "-------"). - Added: Record button to epgsearch result list if no timer is set. - Added: Support for epgsearch's timer checking. - Changed: Minimum required epgsearch release to 0.9.21. - Fixed: Disable EPG_DIRECT because it no longer works with the "lste" speedup patch. - Minor bugfixes and improvements. 2007-01-25: 3.5.3 - Fixed: epgsearch's LSTT/DEFT commands need at least epgsearch v0.9.20. - Added: Klaus Schmidinger's "lste" speedup patch. - Changed: Do not send every HTTP header line in its own TCP packet (Speedup!). - Changed: Display error message if VDRAdmin-AM can't connect to VDR if index.html is requested. - Changed: Added warning in epgsearch edit if neither "title", "subtitle" nor "description" is checked. - Changed: Don't show recording commands drop-down if there are no reccmds. - Fixed: When sorting recordings by name, sort folders by name too. 2006-12-08: 3.5.2 - Fixed: Canceling of "Do you really want to delete?" messages (Reported by KHG_AC @vdr-portal.de). 2006-12-01: 3.5.1 - Added: Italian translation (Submitted by Diego Pierotto). - Bugfixes. 2006-11-24: 3.5.1beta - Changed: Handling of critical/colliding timers on encrypted channels in timer_list (Requested lot's of time in vdr-portal.de). - Fixed: Lost info on selected extepginfos if testing an epgsearch in epgsearch_new (Reported by marpiet). - Fixed: Didn't select the right channel group in epgsearch_new (Reported by viking). - Added: epgsearches can be based on epgsearch's templates (Requires epgsearch >= 0.9.20). 2006-11-10: 3.5.0 - Changed: Don't use "Bitstream Vera Sans" font as default as this looks ugly on Windows (at least for some users). 2006-11-02: 3.5.0rc - Minor bugfixes. 2006-10-27: 3.5.0beta - Added: script to convert existing AutoTimers to epgsearch (autotimer2searchtimer.pl). - Added: Hack for MSIE to always show vertical scroller to prevent horizontal scroller (Submitted by Udo Richter). - Added: Support for epgsearch plugin; AutoTimer now considered deprecated and unsupported. - Minor bugfixes 2006-09-29: 3.4.7 - Autosave now takes care of the number of lines to show in commands menu (Requested by Ronny Kornexl). 2006-09-06: 3.4.7beta - Fixed: Smaller bugs (see ChangeLog). - Changed: Hide select boxes for templates and skins if it contains only a single choice. - Fixed: Another fix for the refering pages problem(s). - Changed: Hide "AutoTimer" menu item unless $FEATURE{AUTOTIMER} is set. - Changed: Use date instead of empty subtitle in timers programed by AutoTimer with activated "Episode" option. - Fixed: Don't show outdated broadcast as search result. - Added: Display warning message if lists is empty. - Added: UTF8 locales patch by Zoolook (see Bug #124). - Fixed: AutoTimer test feature didn't find broadcasts if they were in vdradmind.done. - Removed: HTML::Template dependency. - Changed: Only use Template-Toolkit's Template.pm. - Fixed: Hide "switch" button in prog_summary2 if broadcast is not running (Based on suggestion by Hardy Flor). - Fixed: Initial display of rec_list was empty. - Added: New PLAY and EDIT actions in rec_list. - Added: Remember selected size and interval in TV. - Added: check for features available with VDR's SVDRP, disable missing ones and show them in about.html (ATM used for RENR). - Changed: handling of sorting in rec_list (should always keep the current sorting). - Changed: handling of sorting in at_timer_list (should always keep the current sorting). - New: option to autosave config on exit (also saves sorting state in lists and viewmode in prog_summary). - Added: Czech translation (Submitted by Karel Borkovec). - Changed: handling of sorting in timer_list (should always keep the current sorting). - Changed: Moved favicon.ico from a template's skin folder to the template's main folder. 2006-07-14: 3.4.6 - No changes. 2006-07-11: 3.4.6rc2a - Fixed: "unknown URL" bug if "record" is clicked in prog_detail called from list of repeats (Reported by anso20030). - Added: Hilighting of row beneath mouse pointer in lists. 2006-07-10: 3.4.6rc2 - Reworked: Timeline (Submitted by Torsten Herz). 2006-07-07: 3.4.6rc - Replaced: Makefiles by make.sh (run "./make.sh" for usage information"). - Removed: LinVDR logo. - Changed: colors in timeline. - Fixed: layout problems in prog_summary detail view (Reported by Sven Soltau). - Fixed: moving forward/backward at the end/start of a month (Reported by foobar42). 2006-06-30: 3.4.6beta5 - Changed: "channels" column in timeline uses max 10% of available width. - Fixed: programming a timer in prog_detail in FireFox. - Fixed: HTML warnings. - Fixed: find repeatings containing "&" in prog_detail (Bug #0000104, Reported by hajo). - Changed: TV and remote control to better fit new "default" theme. - Fixed: correct sorting in prog_list2 selectbox at the end of a month (Reported by sirtobi). - Fixed: Extracting VDR version number. 2006-06-26: 3.4.6beta4 - Changed: CSS a little bit. - Rewrote: prog_timeline to make it more dynamic (needs JavaScript) (Submitted by Torsten Herz). - Changed: displaying of audio/video tracks in prog_details (Fixes weird EPG display behaviour). 2006-06-23: 3.4.6beta3 - Fixed: Crash in prog_detail if invalid EPG-ID (Bug #0000077, Reported by Reiner Buehl). - Fixed: Bug #0000034 (Reported by The Unknown). - Added: error page on internal vdradmind.pl errors. - Changed: access_log. - Removed: unused stuff in templates. - Fixed: quote special characters in "find repeatings" URL (Reported by Hans-Joachim Gurt). - Reworked: prog_timeline again (Fixes Bug #0000009, Reported by Georgius, Patch submitted by Torsten Herz). - Fixed: correct sorting in prog_list2 selectbox at the end of a month (Reported by sirtobi). - Changed: dates in prog_list2 selectbox now shows day and month (Requested by sirtobi). - Changed: Removed tabs in configuration menu. - Fixed: "Divide by 0" bug in prog_summary list view (Bug #0000072, Reported by djdagobert). - Changed: Place folders in rec_list at the top (Patch submitted by Frank Jepsen). - Fixed: Remember sorting after returning fom rec_rename (Bug #0000037, Reported by martind). - Fixed: Canceling rec_rename does no longer rename the recording (Bug #0000036, Reported by martind). - Fixed: VDRAdmin-AM didn't start if PID file was empty (Reported and fixed by Hirmke Michael). - Fixed: In prog_list2 starting time also works for other days. - Added: Icons to find repeatings and IMDb lookup in prog_list and prog_list2. - Added: Each AutoTimer can have its own start/stop margins (Requested by many people at vdrportal.de). NOTE: vdradmind.at format changed! 2006-05-24: 3.4.6beta2 - Added: VPS time, audio and video tracks to prog_detail if available. - Added: class names for action icons (info, record...) for hiding single items (not yet finished). - Added: ids for navigation items, see user.css_example for hiding single items. - Changed: Icons for stream and switch TV. - Replaced: "default" skin by "default.png" skin. - Added: Link from pattern title in AutoTimer list to AutoTimer edit (Requested by Tarandor). - Reworked: prog_timeline; still needs some beautification (Based on patch submitted by Torsten Herz). - Fixed: IMDb link in prog_summary listview (Reported by heiwil). - Fixed: detection of valid Locale::gettext calls. 2006-05-19: 3.4.6beta - Added: "next" shortcut in prog_summary to show events starting after the current event (Based on patch by Joachim). - Added: added selectbox in prog_summary to quickly show the epg at a given time (uses times configured in timeline config). - Added: list view in prog_summary which includes a graphical elapsed time representation (Based on patch by Joachim). - Added: selectbox in prog_list2 to quickly jump to a day's epg. - Reworked: prog_detail (incl. recording's details). - Changed: cleaned config menu. - Removed: "bilder" and "copper" theme". - Added: "default.png" theme (nice PNG images, extracted from KDE's Crystal icons). - Reworked: "default" theme (ugly GIF images, extracted and converted from KDE's kdeclassic icons). 2006-05-18: 3.4.5a - Fixed: install.sh problem due to reformated vdradmind.pl :( (Reported by several people). 2006-05-12: 3.4.5 - Fixed: crash if /usr/bin/locale is a directory (Reported by pmeyer). - Changed: reformated vdradmind.pl using perltidy. - Fixed: Only sort by start time in prog_summary if it's a search result (Reported by Toxic-Tonic). - Fixed: install russian catalog (Reported by free-x). - Added: credits for russian translation to about menu. 2006-04-28: 3.4.5rc - Changed: request full "from" email address for sending emails instead of domain only (Requested by siryoda). - Changed: no red background for inactive timers in prog_timeline (Requested by Zimbo). - Changed: result of a search is ordered by the event's start time instead of channel id (Suggested by scorp). - Fixed: crashes when sending emails (Thanks to Ville Skyttä for hints and siryoda for testing). - Fixed: error page sets charset correct. - Added: russian translation (Thanks to Oleg Roitburd and Allrussian-forum translation team) - Fixed: lots of perl warnings. - Updated: localization, French is again up-to-date (Thanks to Trois Six). 2006-04-07: 3.4.4 - Fixed: reccmds didn't run if recording contained special characters (Reported by Ronny Kornexl). - Fixed: remember "unlimited" number of lines to show in vdr_cmds (Reported by Ronny Kornexl). - Changed: set "help" as default in vdr_cmds SVDRP command (Requested by Ronny Kornexl). 2006-03-30: 3.4.4rc - Fixed: new TV grabbing introduced with beta2 (Many thanks to horchi for reporting and testing). - Changed: check if a timer to be programmed by an AutoTimer already exists (Requested by several people). - Added: display AutoTimer information in timer's edit view (Somehow requested by MarkusE). - Fixed: recordings/timers/autotimers containing double-quotes couldn't be deleted (Reported by The Unknown). 2006-03-14: 3.4.4beta2 - Reworked TV grabbing. - Added optional parameters for TV for use with external tools: http://vdradmin-am.ip?aktion=tv_show&size=[full|half|quarter]&interval=[0|1|2|3|5|10|30|60]&tv_only=bla - Fixed program switching in prog_summary, prog_list and prog_detail (Based on suggestions by kayser). - New: buttons to move to previous/next day in timers_list (Requested by BigDiSt). - Moved "help" menu into "about" menu. - Added VDR's "commands.conf" conntent to select box in navigation menu. - Changed defaults for "autotimer checking" in timers as they had been in v3.4.3. - New button on remote controls: Mute (Requested by Rüdiger Jung and Hardy Flor). - Timeline in timer_list will show timers of current day even if a timer starts the day before (Reported by Hardy Flor). 2006-03-08: 3.4.4beta - Added script "convert.sh" to convert the AutoTimer information in VDR's timers.conf to the new format (see "convert.sh" for usage). - Use the summary/aux timer field to store AutoTimer information to be compatible to VDR v1.3.44 and later. - Removed "Add summary to new timers" option. The EPG summary is no longer copied to the timer's summary/aux field (for VDR 1.3.44+) or always copied (VDR 1.3.43-). - Made summary textfield readonly while adding/editing a timer. - Unless NO_EVENTID or NO_EVENTID_ON is used the EPG-ID is stored in every (auto)timer set using VDRAdmin-AM. - For every timer the current start/stop margins are saved in its summary/aux field. These are used for checking AutoTimers by time. - Fixed bug while checking for already programmed (auto)timers if not using EPG-ID. 2006-03-01: 3.4.3 - Don't show streaming button in prog_summary if event is currently not broadcasted (Requested by Hardy Flor). - Show search pattern in prog_summary instead of current time (Reported by Hardy Flor). - Send correct encoded emails for AutoTimer notifications (Thanks a lot to Ferdinand Grassmann for reporting/ideas/testing). - Do not program timers in the past (Reported by Ferdinand Grassmann). - Send default image if TV grabbing fails. - Fixed "Length of base64 data not a multiple of 4" warning (Reported by Johan Larsson). 2006-02-10: 3.4.3rc3 - Changed handling of refering pages; should work much better now. 2006-02-06: 3.4.3rc2 - For timers that are checked by AutoTimer for start/stop times the broadcast's length must at least match 90% of the original timer's length (excluding before/behind buffers). - Reworked detection of already programmed AutoTimers and made it compatible to VDR v1.3.23+ (Based on suggestions by Jouni Karvo). - Don't crash if illegal characters are used for searching (Reported by foobar42). - Fixed error after progamming a timer if VDRAdmin is accessed through apache (Reported by speed). - If there were quotes in an AutoTimer's pattern and you clicked "test" the pattern got cleared (Reported by The_Pit). 2006-01-17: 3.4.3rc - Changed program name to VDRAdmin-AM to make clear it's a fork of VDRAdmin. - Added "Help" and "About" to navigation bar at the left. - Hide "Record" button if prog_detail is opened from timer_list. - After clicking "Record" in prog_detail and leaving timer_new return to page where prog_detail has been opened (Reported by Ferdinand Grassmann). - Timers were re-programmed every CheckTimers() call if setup option "do not add summary to timers" is active (Reported by Ferdinand Grassmann). - Dropped sendEmail dependency. Now uses Net::SMTP modules (Patch by Ville Skyttä). - Don't show EPG images for other events (Fixed by Ferdinand Grassmann). - Changed GRAB so that it doesn't use temporary files for VDR >=1.3.38. - VPS for timers (Requested by reibuehl). - Made extension and mimetype for both live and recordings streaming configurable (Suggested at vdrportal.de). - Understand format of VDR v1.3.38+ "lste" command (Thanks to Marcus Breitenstein). - In skin "default": returning from timer_new didn't scroll to the line where "Rec" has been called in prog_list/prog_list2 (Reported by Foobar42) - Fixed installing of missing Perl modules. 2005-12-06: 0.97-am3.4.2 - Updated de, es and fi translation (got no response by fr translator). - Use the channel name as title if title in timer_new is empty (Requested by Hardy Flor). - Improved handling of dates reported by "lstr". - SMTPAuth for sendEmail. - Fixed: Programming a timer using InternetExplorer, didn't return to the previous page but gave an error (Reported by several people). - Remember sorting after (in)activating selected timers (Reported by Atti). - Updated Template-Toolkit to v2.13. - Reworked sorting in rec_list/timer_list/at_timer_list. - Activate/Inactivate selected timers in timers_list (Requested by Atti). - Event's title in prog_summary/prog_list/prog_list2 links to prog_detail (Requested by Scorp). - Added "Refresh" button in rec_list to refresh the cache of the list of recordings. - Fixed popup if deleting timers/recordings/autotimers containing a "'" (Reported by Saxman2k). - Remember sorting after deleteing or editing timer or autotimer (Reported by Atti). - Improved re-connect to VDR if VDRAdmin crashes. - Set "LANGUAGE" environment variable to "" on startup, so it causes no problems with language setting in VDRAdmin. - Added caching of listing of recordings. Can be adjusted by "CACHE_REC_TIMEOUT=number of minutes" in vdradmind.conf. Defaults to "60", "0" disables caching. - Remember sorting when toggling in timer or autotimer list. - New configuration option for Timers: don't add summary. - Email notification for AutoTimer can be set in configuration menu. - Optimized AutoTimer matching a little bit. - Reworked detection of another VDRAdmin process if pid file exists. - No more config settings that require a VDRAdmin restart. - Find "sendEmail" program in $PATH. - For VDR >=1.3.24 use VDR's timer flags for finding timers that are currently recording. - Fixed sendmail notification for AutoTimer. - If /usr/bin/locale is not available, language can be entered in textfield instead of chosing in selectbox. - Fixed wrong display of double quotes in timer_list and at_timer_list. - Fixed browsing in "recordings" menu (if there are folders having the same name). - Added new skin "default" (InternetExplorer has problems with displaying it). - Removed i18n.pl. - Localization can be set in configuration again. - Added "Transponder" and "CA-System" to tooltips in timer_list. - Show recording's summary and subtitle in rec_edit (Requested by BigDiSt). - Check for and shorten too long summary when programming timer. - Check for too long commands sent to SVDRPort. - Channel select box in TV. - "Test" button in AutoTimer edit for showing results of current settings (Requested by Hardy Flor). - Link from channel name in prog_list2 and timer_list to prog_list. - Bring popups to the front (e.g. help, prog_detail...) (Based on a patch submitted by Ville Skyttä). - Reuse existing TV, RC and help windows (Based on a patch submitted by Ville Skyttä). - Send vdradmin.m3u when streaming. - Tooltips in timer_list, prog_timeline and at_timer_list can be deactivated (Requested by Hardy Flor). - Fixed wrong HTML tags in rec_detail (Reported by foobar42). 2005-10-04: 0.97-am3.4.1 - Fixed some bugs: -> Selected channel is remembered when editing AutoTimers (Reported by Scorp). -> Recording streaming didn't work in some cases (Reported by several people @vdr-portal.de). -> Recording commands didn't work in some cases (Reported by several people @vdr-portal.de). -> Watch TV and remote control didn't work (Reported by several people @vdr-portal.de). -> INFO button in prog_list2 didn't work. -> Getting back from timer_new to prog_summary/prog_list/prog_list2 again scrolls to line with previously selected item (Reported by Scorp). - Updated translations - Fixed some more HTMLtidy warnings. 2005-09-23: 0.97-am3.4 - Send valid "Expires" header (Submitted by Ville Skyttä). - Open failure of vdradmind.done reported wrong filename (Submitted by Ville Skyttä). - Deliver validated HTML (Reported by Ville Skyttä). - Display name of recordings/timers... that will be deleted (Requested by Richard Lithvall). - Channels list in AutoTimer only shows selected channels if selective channels are active for AT. - Added "chmod" for grabbed images of TV so that everyone can read/write the file (Submitted by Udo Richter). - Added "-d" argument to set the configuration folder (Submitted by Rene Bredlau). - Fixed handling for recording on February, 29th for VDR >=1.3.26 (Submitted by Rene Bredlau). - Alternativly use Locale::Messages if Locale::gettext not found (Submitted by Ville Skyttä). - Fixed "send command" error message (Submitted by Ville Skyttä). - Display free disk size as float instead of integer (Submitted by Hardy Flor). - Step forward/backward a day in "Playing today" (Requested by Tüddelkopp) - Enable/disable selective channels in "Playing today" (Requested by Reiner Buehl) - Added images in prog_detail; needs external tool that provides these images; must be configured first! (Requested by several people) - Fixed display of login page (Reported by DrSat) 2005-07-12: 0.97-am3.3 - Fixed problems with "$" in templates (Reported by All-Ex). - Updated all help messages. - Added beautified tooltips in at_timer_list, timer_list and prog_timeline. - Changed saving of AutoTimer patterns: ":" -> "|" and "|" -> "\|". - Added support for user.css for overwriting style.css (Must be located in same folder as vdradmind.conf). See user.css.example. - Removed obsolete files (e.g. images). - Merged style.css and navi.css. - Reworked templates so that they use a lot of CSS (Tested using Konqueror 3.3.2 and Firefox 1.0.4). - Fixed programming timers with special summary when using EPG_DIRECT (timer didn't get programmed) (Thanks to HolgerAusB for giving vital hints). - Allow browsers to cache all files VDRAdmin sends, except "text/html". This should speed up VDRAdmin but changing the skin or css needs a "shift reload". - Added support for VDR v1.3.25's info.vdr (Submitted by vejoun). - Use localized date formates. - Now using "video/x-mpegurl" MIME type instead of "audio/x-mpegurl" for streaming (Suggested by stefan.h). - Added patches supplied by stefan.h: -> using EPG's subtitle when found for AutoTimer else " " (that's the VDR way). -> New config option VDRVFAT to find recordings if VDR has been compiled with or without VFAT define. - Fixed calling reccmds on recordings in subdirs, manual recordings (@rectitle) and repeating timer's recordings without episode title. - Fixed streaming of manual recordings (@rectitle) and repeating timer's recordings without episode title. - VDRAdmin-AM now uses the required charsets setting in templates, so no need to write "&xyz;" things in .po files. - Reworked templates to make better use of CSS (for example: timeline colours can be set by style.css). - EPG_PRUNE now is the number of channels to fetch from VDR (had been one too less before). - Added "install.sh" and "uninstall.sh" ("./install.sh -h" for help) (Requested by several people). - Made "name" columns in lists wrapping again (Reported by vejoun). - Deleting a single recording works again (Reported by vejoun). - Fixed streaming of recordings in subdirs (Reported by vejoun). - Added missing gray sign on deactivated AutoTimers (Reported by vejoun). - Various other minor fixes. 2005-05-12: 0.97-am3.2 - Added "make uninstall" to remove VDRAdmin from your system if you have installed it using "make install". Please always use this before you install a new release! - Fixed programming of repeating timers when day is "D" (Thanks to "maxkr" for reporting this). - Print date in prog_list & prog_list2 in system's locale. Please comment! - More transparent "selected channels" usage. - Added reccmds.conf content to rec_list (needs valid VDRCONFDIR in vdradmind.conf) - AutoTimers can now be limited to certain weekdays (Patch submitted by Magnus Schmidt). - Streaming can be turn on/off for live viewing and recordings viewing (Based on code submitted by Tobias Grimm). - Added streaming button to prog_list2. - Fixed handling of incorrect start/stop times in AutoTimer. - Changed localisation to use gettext() (Thanks to Tobias Grimm for doing most of the needed work). - Language can no longer be set in VDRAdmin, it's taken from your system's setting. Issue "export LANG=" if you need to change it, where is one of "de_DE", "en_EN", "es_ES", "fi_FI" or "fr_FR". - Added Finnish i18n (Submitted by Rolf Ahrenberg). - Fixed ":" & "|" handling in timer's directory (Thanks "vejoun"). - Added links to prog_list on channels in at_timer_list and timer_list. - Added IMDb lookup button to recording's detail view. - Added "Priority" and "Lifetime" tooltip to at_timer_list and timer_list (point mouse to timer's name). - Small changes for streaming recordings: Please update your vdradmind.conf (VIDEODIR & ST_VIDEODIR)! - Non-LinVDR logo on non-LinVDR machines (Posted by Unimatrix0 at vdrportal.de). 2005-04-12: 0.97-am3.1 - Updated Spanish i18n (Thanks to Ruediger Jung). - Added VDR Admin man-page (Thanks to Thomas Schmidt). - Improved detection of another running vdradmind.pl at startup (if vdradmind.pid is found but pid is not a vdradmind.pl vdradmin will start anyway). - Added IMDb lookup button in prog_detail (Suggested by Marcus). - Use configured Streamdev port for live streaming. - Added warning when using EPG_DIRECT. - Updated INSTALL file. - Renamed i18n Español to Spanish (Requested by Ruediger Jung). - Fixed ":" & "|" handling in timer's title and summary (Thanks to Der_Pit for pointing me to that). - Added "Select all" to timer/autotimer/recordings list. - Exchanged priority and lifetime textfields in config.html to match order used at other places (Requested by Ruediger Jung). - Added vdradmin-0.95-0.9pre5-email.diff (Author: blafasel) patch: send email on timers added by AutoTimer (needs sendEmail available here: http://caspian.dotconf.net/menu/Software/SendEmail/). - Fixed timer add/edit where date got set wrong in case it has been entered as "yyyy-mm-dd". - Fixed problems when using MOD_GZIP (Thanks Ville Skyttä). - Fixed Makefile once again (Thanks Zzam for pointing me to this). - Added patches submitted by stefan.h (Thanks!): -> New config option EPG_PRUNE. You can set a channel number up to which VDRAdmin will read EPG. Might reduce memory usage and read-in time. Set to "0" to read all channels. -> Optimizations and bug fixes. - Added install files for Debian (Thanks to Steffen Oberle for requesting and troubleshooting). 2005-04-04: 0.97-am3.0 - Reworked updating of channels and EPG from VDR. - Fixed displaying of repeating timers. - Fixed Makefile to set "$SEARCH_FILES_IN_SYSTEM = 1" on install. - Added Spanish i18n (Submitted by Rüdiger Jung) - Updated French i18n (Submitted by "Trois Six", "map" and "lobotomise") - Fixed some buttons to work with long translations. - Extracted text from templates and moved them to i18n.pl file and moved the i18n.pl files to new folders i18n/$language, resulting in a single template with two skins (bilder & copper). Makes translations and template modification a lot more easier. Included patches submitted by Ville Skyttä: - vdradmin-01-req-zlib.patch: Make Compress::Zlib really optional. - vdradmin-02-defaultconfig.patch: Use preset values from %CONFIG as defaults in --config. - vdradmin-03-errstr.patch: Fix error string output. - vdradmin-04-spelling.patch: Various trivial spelling and phrasing improvements. - vdradmin-05-askconf.patch: Allow unattended "vdradmind.pl --config < /dev/null". - vdradmin-08-writeconfig.patch: Always write config using WriteConfig(). - vdradmin-10-exitcodes.patch: Don't exit with status code 0 if something's wrong. 2005-03-30: 0.97-am2c - Fixed handling of new recordings if VDR is patched with Wareagle-Icons patch (Reported at vdrportal.de). - Fixed handling of MTWTFSS@date in timer (edit & list). - Some smaller template fixes. - Fixed forgotten items with "vdradmin-0.96_For_vdr-1.3_StoreAutotimerChannelID_And_EventIdCheckDisable.diff". - Try harder to avoid browser's caching. - Fixed directory handling in auto_timer: -> if a "%" (variable) is found you are fully responsible for the final recording's title, e.g. you must add %Title% if you want it (other vars: %Title%, %Subtitle%, %Director%, %Date%, %Category%, %Genre%, %Year%, %Country%, %Originaltitle%, %FSK%, %Episode% and %Rating%) -> all "/" will be replaced by "~" (before variable substitution) - Automatic programmed timers have their summary hyperlink back. (Reported by sn123py) - Handle "VPS" in timer listing. - Fixed French translation. 2005-03-23: 0.97-am2b - Added French template (Submitted by Trois Six) - Fixed English/i18n.pl - Removed all "bilder" and "copper" folders in all templates except "Deutsch" and replaced them by links to the folders in "Deutsch". 2005-03-22: 0.97-am2a - Fixed Volume+ and Volume- in TV (Reported by Unimatrix0) - Fixed missplaced channel name prog_summary (Reported by several people) - Added updated English templates (Supplied by C.Y.M) - Now VDRAdmin understands timers format from vdr1.3.22- and vdr1.3.23 (Supplied by Stefan Neuwirth) - Fixed small display problem in timeline. 2005-03-20: 0.97-am2 - TV and remote templates have same remote control. - Reworked summary display of recordings - Summary editbox preserves linefeeds while editing timers - Added stream button in prog_summmary (suggested by Unimatrix0) Added patches: - vdradmin-0.96_For_vdr-1.3_StoreAutotimerChannelID_And_EventIdCheckDisable.diff (posted at the VDR mailinglist by Rantanen Teemu) - vdradmin-0.96_OneShot_Timers_English_Only.diff and merged it to "Deutsch" template (posted at the VDR mailinglist by Rantanen Teemu) - Included changes from vdradmin-0.96-3-ctvdr-1 (see HISTORY.ct). - Fix for timers.conf of vdr1.3.23+ (Submitted by Stefan Neuwirth) - Localnet Patch; no password request if client ip in given ip range) (Author: Roland Behme / Submitted by Reiner Buehl) Templates cleanup: - at_new.html - at_timer_list.html - config.html - error.html - index.html - left.html - noauth.html - noperm.html - prog_details.html (TODO) - prog_list2.html - prog_list.html - prog_summary.html (TODO) - prog_timeline.html - rc.html - rec_edit.html - rec_list.html - timer_list.html - timer_new.html - toolbar.html - tv_flash.html - tv.html Changes that have been forgotten while merging previous patches: - Fixed: timer listing now shows "VPS" instead of "Auto (alt)". - Removed unneeded
. They are still used for display only. 2005-03-06: 0.97-am1 "initial release" This is mainly the lastest vdradmin (v0.97) with different patches applied: - vdradmin-0.97 has been taken from linvdr-0.7. - xpix's BigPatch_0.9pre5 (ported from vdradmin-0.95 to vdradmin-0.97 (see HISTORY.bigpatch). - Included changes from vdradmin-0.95-ct-10 (see HISTORY.ct). - Included vdradmin-0.95_0.9_pre5_fb1.diff (see HISTORY.macfly). - Included vdradmin-0.96-rename.diff which also needs an applied "vdr-aio21_svdrprename.patch" or enAIO-v2.2 patch (Author: slime). My own changes: - Included missing "Was läuft heute?" template (found at www.vdr-portal.de). - Fixed some rendering problems with "New Timer" and "New Autotimer" on KDE's Konqueror. - Beautified recordings listing (at least in my eyes ;-) - Added "Size" selectbox to TV template. vdradmin-am-3.6.13/INSTALL000066400000000000000000000104071443716113400150420ustar00rootroot00000000000000*********************************************************** *** Using Git *** *********************************************************** If this is a Git snapshot you have to perform some steps yourself to get a complete VDRAdmin-AM folder: 1) The Git repository contains no locales (.mo files). You have to create them yourself if you want to use a language other than English: ./make.sh po Please note that you need the "msgfmt" utility for this! *********************************************************** *** Installation *** *********************************************************** 1) Unpack the archive somewhere: $ tar xvjf vdradmin-am-VERSION.tar.bz2 $ cd vdradmin-am-VERSION 2) If you want to run VDRAdmin-AM using a language other than set on your system, then before running it you have to issue: $ export LANG="" Where has to be one of: de_DE, es_ES, fi_FI, fr_FR, nl_NL or ru_RU (en_GB is default). 3) Check if your system provides all requirements and optionally install the missing Perl modules: $ ./make.sh check 4) Now you have to decide whether you want to run VDRAdmin-AM locally (4a) in this directory or install it into your system (4b). 4a) run locally (=no installation) First you have to configure VDRAdmin-AM. This only has to be done once. $ ./vdradmind --config Some questions about the configuration will be asked. Now you're done and you can run VDRAdmin-AM: $ ./vdradmind 4b) install into system $ ./make.sh install Some questions about the configuration will asked. Now you're done and you can run VDRAdmin-AM: $ vdradmind 5) If you want VDRAdmin-AM to run automatically on system boot, you have to add a startup script to the wanted runlevel. Please consult your Linux distribution's documentation. Please also note that you might have to set the wanted language in that startup as shown in (2). 6) No matter how you run VDRAdmin-AM, you now can point your browser to the given parameters (e.g. http://localhost:8001). *********************************************************** *** Removing VDRAdmin-AM from your system *** *********************************************************** 1) Uninstall depends on the kind of installation you did: 1a) run locally (=no installation) There is not much to do. Simply remove to folder VDRAdmin-AM has been created while unpacking: $ rm -rf vdradmin-am-VERSION 1b) installed to your system You need the unpacked VDRAdmin-AM archive. $ cd vdradmin-am-VERSION $ ./make.sh uninstall You might want to delete your VDRAdmin-AM's configuration files: $ rm -rf /etc/vdradmin This of course only works if you didn't change the default install locations! If you've change them you must call "./make.sh uninstall" with those locations. If you don't know what I'm talking about, you probably didn't change the default values ;) 2) You're done! *********************************************************** *** Hide VDRAdmin-AM behind apache *** *********************************************************** you will need apache with mod_proxy and these lines in httpd.conf: ProxyRequests Off ProxyPass /vdradmin/ http://127.0.0.1:8001/ *********************************************************** *** Hint from Martin Neuditschko for apache2 (untested) *** *********************************************************** I have summarized the needed changes for my Apache (Apache2, SuSE 8.2): Following modules have to be activated additionally: proxy, html_proxy, rewrite Following has to be added to the httpd.conf: RewriteEngine On RewriteRule ^/vdradmin(.*) http://localhost:8001$1 [P,L] *********************************************************** *** See who's calling (you need an ISDN card for this) *** *********************************************************** Insert this in your isdn.conf: [MSN] NUMBER = START = { [FLAG] FLAGS = I|O|R PROGRAM = /path/to/vdradmind --displaycall "Call from \$2" } Restart isdnlog. vdradmin-am-3.6.13/LGPL.txt000066400000000000000000000635041443716113400153160ustar00rootroot00000000000000 GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! vdradmin-am-3.6.13/README000066400000000000000000000057101443716113400146720ustar00rootroot00000000000000This is the "VDRAdmin-AM" a web user interface for VDR. Written by: Andreas Mair (andreas AT vdr - developer DOT org) Project's homepage: http://andreas.vdr-developer.org Latest version available at: http://andreas.vdr-developer.org License ------- This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. See the file COPYING for the full GNU GENERAL PUBLIC LICENSE Version 2 (GPLv2). "Bubblehelp infoboxes" (templates/default/infobox.js) is licensed under GNU GENERAL PUBLIC LICENSE Version 2 (GPLv2) *only*. "Crystal Theme Icons" are licensed under GNU LESSER GENERAL PUBLIC LICENSE v2.1 (LGPLv2.1), see LGPL.txt. Requirements ------------ - VDR (http://www.tvdr.de/) - Some Perl modules (see "./install.sh -p"): - Required: - Template - Template::Plugin::JavaScript - CGI - HTTP::Date - IO::Socket - Time::Local - MIME::Base64 - File::Temp - File::Find - URI - URI::Escape - HTTP::Tiny - HTTP::Daemon - Locale::gettext OR Locale::Messages - Optional: - Required for built-in HTTP response compression: - Compress::Zlib - Required for AutoTimer email notification: - Net::SMTP - Authen::SASL - Required for AutoTimer email notification and CRAM-MD5 authentication: - Digest::HMAC_MD5 - Required for syslog logging: - Sys::Syslog - Required for IPv6 support: - IO::Socket::INET6 - Required for SSL support (https): - HTTP::Daemon::SSL Description ----------- VDRAdmin-AM is a web based interface to VDR. Installation ------------ See "INSTALL" file. Options ------- -n, --nofork don't fork, log to stderr. -c, --config run configuration dialog. -d [dir], --cfgdir [dir] use [dir] for configuration files. -k, --kill kill a forked vdradmind[.pl]. -p [name], --pid [name] name of pidfile to use. -6, --ipv6 use IPv6. [EXPERIMENTAL!] -s, --ssl only accept https:// connections. NOTE: this requires server-cert.pem and server-key.pem in the "certs" directory. You can create them for example like this: # openssl req -new -x509 -days 9999 -keyout server-rsa-key.pem -out server-cert.pem # openssl rsa -in server-rsa-key.pem > server-key.pem -l [level], --log [level] set log level for this session [0 - 7]. -h, --help print usage information. Credits ------- See "CREDITS" file. vdradmin-am-3.6.13/README.translators000066400000000000000000000070531443716113400172470ustar00rootroot00000000000000VDRAdmin-AM translators guide ============================== Since vdradmin-0.97-am3.2 almost every text has been extracted from the scripts and templates. This makes it much easier for anybody, who wants to translate VDRAdmin-AM to another language. All you need to do is to let me (mail AT andreas DOT vdr-developer DOT org) know, that you plan to add a new language, so that I can tell you if anybody else is already working on that language. After my OK you can start your work. Howto ----- We've decided to use GNU gettext for translating the user interface to different languages. GNU gettext is widely used among Linux programs of all kind. It comes with a lot of tools and with support for most programming languages. The translations are stored in plain text files with a *.po file extension. Each language has its own file (e.g. de.po, fi.po, ...). You may edit these po-files with any text editor, but we recommend to use a po-editor like poedit [1], kbabel [2] or gtranslator [3]. You must have installed the "gettext" package of your distribution to compile the plain text translations to the binary files needed by VDRAdmin-AM. The basic work flow for a translation looks like this: 1) Copy po/vdradmin.pot to po/.po. See [4] for a list of available language codes. 2) Open the file in your favorite po-editor. Make sure you set the correct encoding and fill in your email and language in the corresponding header fields. poedit makes this pretty easy - just go to catalog/options and fill out the form. 3) Now you can start translating. Keep in mind, that if you translate a message, you should use html entities [5], [6] for special characters. Any text that origins from vdradmind[.pl] must not have html entities. Beside the help texts, you will not need any formating tags. Messages marked as "fuzzy" indicate, that they may have been derived from similar messages and it's not sure, that the translation is correct. Check these translations and correct them if needed or simply mark them as not fuzzy (poedit: edit/mark as fuzzy) 4) To check how your translated texts look like, you have to compile them first to *.mo-files. To do so, you edit "make.sh" first and append your to the "LANGS=" line. Running "./make.sh po" will then create a new *.mo-file from your changed *.po-file. Please note, that you have to restart vdradmind[.pl] after any changes you make to the translation. In order to allow VDRAdmin-AM to select your language, you must have the appropriate locales installed on your system (see "locale -a"). You should make sure, that the correct locale is selected with the LANG and LC_* environment variables. For example: LANG=de_DE ./vdradmind 5) If you are done, send the *.po-file to me: mail AT andreas DOT vdr-developer DOT org 6) When changes have been made to VDRAdmin-AM, that cause some messages to change, the *.po-files will by modified and we will send them to the translators. The process then starts with 2) again and we will include your new translation with the next release. If you have any further questions, please don't hesitate to contact me. --- 2007-12-18, Andreas Mair --- [1] http://www.poedit.org (available for Windows and Linux) [2] http://i18n.kde.org/tools/kbabel/ (KDE) [3] http://gtranslator.sourceforge.net/ (GNOME) [4] http://www.gnu.org/software/gettext/manual/html_chapter/gettext_15.html [5] http://www.w3.org/TR/WD-entities-961125 (English) [6] http://de.selfhtml.org/html/referenz/zeichen.htm (German). vdradmin-am-3.6.13/REQUIREMENTS000066400000000000000000000003341443716113400156550ustar00rootroot00000000000000* In order to function properly you need to have a running Perl installation with some external modules. Please run "./make.sh check" to check required Perl modules and install missing ones. 2006-11-29, Andreas Mair vdradmin-am-3.6.13/autotimer2searchtimer.pl000077500000000000000000000200051443716113400206660ustar00rootroot00000000000000#!/usr/bin/perl # # Convert VDRAdmin-AM autotimer (vdradmin.at) into # epgsearch searchtimer (epgsearch.conf) # # Version: 0.2beta 2006-08-06 # # Author: Mike Constabel (vejoun @ vdrportal) # Andreas Mair (amair @ vdrportal) # # You need: # # - VDRAdmin-AM >= 3.4.6 # - Epgsearch >= 0.9.16 # use Socket; use Getopt::Std; #--------------------------------------------------------------------------- $Usage = qq{ Usage: $0 [options] -i filename -o filename -m 0|1 $0 [options] -i filename -o filename -s -m 0|1 $0 [options] -i filename -s -m 0|1 Action: -i filename input file, vdradmind.at -o filename output file, epgsearch.conf.new (file will be overwritten!) -s send to epgsearch via svdrp (needs running vdr with epgsearch plugin) -m 0|1 which new searchmode for autotimers with active status: yes, once 0 means the whole string must match 1 means every word must match [default] In epgsearch 0 is default, vdradmin only use 1 Options: -r autotimers with regular expressions will be disabled while converting, with this option you can enable the corresponding searchtimers. You should not do this! Check the converted searchtimers and enable them manually! Wrong searchtimers will flood your timers. -d host Host for SVDRP import -p port Port for SVDRP import -h Show this help text }; die $Usage if (!getopts('i:o:srm:d:p:h') || !$opt_i || $opt_h || !($opt_o || $opt_s) || !($opt_m == 0 || $opt_m == 1)); my $AT_FILENAME = $opt_i; my $EPGSEARCH_FILENAME = $opt_o; my $SENDSVDRP = $opt_s ? 1 : 0; my $EnableRegex = $opt_r ? 1 : 0; my $Searchmode = defined $opt_m ? $opt_m : 1; my $Dest = $opt_d ? $opt_d : "localhost"; my $Port = $opt_p ? $opt_p : 2001; my $Timeout = 30; # max. seconds to wait for svdrp response my $conf_str="%i:%s:%i:%s:%s:%i:%s:%i:%i:%i:%i:%i:0:::%i:%i:%s:%i:%s:%s:%s:%s:%s:0:0:0::%i:0:1:1:0:0:0:0:0:1:0:0::1"; # [ID=0], pattern, time?, starttime, stopptime, channel? (0,1), channel, match case (0,1), search mode (0,4), title, subtitle, description, [duration=0], [min=""], [max=""], searchtimer? (0,1), # use week? (0,1), weekday "0", series? (0,1), dir, prio, lft, bstart, bstop, [VPS=0], [action=0], [use ext. epg=0], [ext. epg=""], done? (0,1), [repeats=0], [ctitle=1], [csubtitle=1], [cdescription=0], # [cext. epg=0], [reapeats within days=0], [delete after x days=0], [keep=0], [min before switch=1], [nach x rec pausieren=0], [blacklist=0], [blacklist-id=""], [fuzzy=0] sub AT_Read { my (@at); if (-s $AT_FILENAME) { open(AT_FILE, $AT_FILENAME) || printf("Can't open %s", $AT_FILENAME); while () { chomp; next if ($_ eq ""); my ($active, $pattern, $section, $start, $stop, $episode, $prio, $lft, $channel, $directory, $done, $weekday, $buffers, $bstart, $bstop) = split(/\:/, $_); $pattern =~ s/\|/\:/g; $pattern =~ s/\\:/\|/g; $directory =~ s/\|/\:/g; push( @at, { active => $active, pattern => $pattern, section => $section, start => $start, stop => $stop, buffers => $buffers, bstart => $bstart, bstop => $bstop, episode => $episode, prio => $prio, lft => $lft, channel => $channel, directory => $directory, done => $done, weekdays => $weekday } ); } close(AT_FILE); } return (@at); } sub CONF_Collect { my @at = @_; my @st; my $weekday = $stitle = $ssubtitle = $sdescription = $id = $case = 0; my $mode = $Searchmode; my $pattern; my $directory; for my $at (@at) { if ($at->{pattern} =~ /^\/(.*)\/(i?)$/) { $mode = 4; $case = 1 if ($2 eq "i"); $pattern = $1; } else { $pattern = $at->{pattern}; } $directory = $at->{directory}; $pattern =~ s/\|/\!\^pipe\^\!/g; $pattern =~ s/\:/\|/g; $directory =~ s/\|/\!\^pipe\^\!/g; $directory =~ s/\:/\|/g; $weekday = undef; my $wd_bits = 0; if ($at->{weekdays} =~ /^(\d)(\d)(\d)(\d)(\d)(\d)(\d)$/) { if ($7) { #Sunday $weekday = 0; $wd_bits |= 1; } if ($1) { #Monday $weekday = 1; $wd_bits |= 2; } if ($2) { #Tuesday $weekday = 2; $wd_bits |= 4; } if ($3) { #Wednesday $weekday = 3; $wd_bits |= 8; } if ($4) { #Thursday $weekday = 4; $wd_bits |= 16; } if ($5) { #Friday $weekday = 5; $wd_bits |= 32; } if ($6) { #Saturday $weekday = 6; $wd_bits |= 64; } } if ($wd_bits !~ /^(1|2|4|8|16|32|64)$/) { $weekday = -$wd_bits; } $stitle = $at->{section} & 1 ? 1 : 0; $ssubtitle = $at->{section} & 2 ? 1 : 0; $sdescription = $at->{section} & 4 ? 1 : 0; $id += 1 if ($EPGSEARCH_FILENAME); $data = sprintf $conf_str, $id, $pattern, $at->{start} || $at->{stop} ? 1 : 0, $at->{start} ? sprintf("%04i", $at->{start}) : "", $at->{stop} ? sprintf("%04i", $at->{stop}) : "", $at->{channel} ? 1 : 0, $at->{channel} ? $at->{channel} : "", $case, $mode, $stitle, $ssubtitle, $sdescription, ($at->{active} && ($mode != 4 || $EnableRegex)) ? 1 : 0, $weekday eq -127 || $wd_bits eq 0 ? 0 : 1, $weekday, $at->{episode} ? 1 : 0, $directory, $at->{prio} ? $at->{prio} : "", $at->{lft} ? $at->{lft} : "", $at->{buffers} ? $at->{bstart} : "", $at->{buffers} ? $at->{bstop} : "", $at->{done} ? 1 : 0; #avoid_repeats push @st,$data; } return (@st) } sub Error { print STDERR "@_\n"; close(SOCK); exit 0; } sub SplitLine($) { my ($line)=@_; if ($line =~ /^([0-9]{3})([- ])(.*)$/) { return ($1,$2,$3); } Error("Unidentified Line: $line"); } sub WriteSearchtimerSVDRP { my @str = @_; $SIG{ALRM} = sub { Error("timeout"); }; alarm($Timeout); my $iaddr = inet_aton($Dest) || Error("no host: $Dest"); my $paddr = sockaddr_in($Port, $iaddr); my $proto = getprotobyname('tcp'); socket(SOCK, PF_INET, SOCK_STREAM, $proto) || Error("socket: $!"); connect(SOCK, $paddr) || Error("connect: $!"); select(SOCK); $| = 1; select(STDOUT); while () { chomp; print STDOUT "(1):$_\n"; my ($code,$sep,$data)=SplitLine($_); last if ($code=220 && $sep eq ' '); } foreach my $line (@str) { chomp $line; printf SOCK "PLUG epgsearch NEWS %s\r\n", $line; } while () { chomp; print STDOUT "(2):$_\n"; my ($code,$sep,$data)=SplitLine($_); last if ($code==900 && $sep eq ' '); } print SOCK "quit\r\n"; while () { chomp; print STDOUT "(3):$_\n"; my ($code,$sep,$data)=SplitLine($_); last if ($code==221 && $sep eq ' '); } close(SOCK) || Error("close: $!"); } sub WriteSearchtimerFile { my @str = @_; open(STFILE, ">".$EPGSEARCH_FILENAME) || die("Cannot open file ${EPGSEARCH_FILENAME}!"); print STFILE "#version 2 - DONT TOUCH THIS!\n"; foreach my $line (@str) { chomp $line; printf STFILE "%s\n", $line; } close STFILE } #--------------------------------------------------------------------------- # main my @st; @st = CONF_Collect(AT_Read()); if ( $SENDSVDRP ) { WriteSearchtimerSVDRP(@st); } if ( $EPGSEARCH_FILENAME ) { WriteSearchtimerFile(@st); } vdradmin-am-3.6.13/contrib/000077500000000000000000000000001443716113400154475ustar00rootroot00000000000000vdradmin-am-3.6.13/contrib/HISTORY000066400000000000000000000404731443716113400165430ustar00rootroot00000000000000v0.97 -- unknown (taken from linvdr 0.7) v0.96 -- tom -- Tue Apr 6 15:43:16 CEST 2004 - Reworked timer collision detection (Thanks to Cooper) - Corrected Power button link in the remote control (Thanks to Tobias Grimm) - Solved some javascript issues v0.95 -- tom -- Sat Dec 13 14:55:04 CET 2003 - Added support to listen on specific network adresses (Thanks to Ludwig Nussel) - Added two new parameters (--message, --displaycall) - Added some code from the "vdradmin BigPatch" - Added help system Fixed Bugs: - AutoTimer does not work correct if the specified time range goes over midnight (Thanks to Cooper) - Solved the "daylight saving" problem (2h offset) - Solved some problems with gzip compression v0.94 -- tom, mdo -- Mon Aug 18 06:32:47 CEST 2003 - Cleared up some things in the "timer new"/"timer edit" form: We have now a new line for automatic timer correction, possible values are "program ID" for the Event-ID as key, "recording time" for the start/end time of the recording as keys, and "disabled" for uncorrected timers. - There are two new variables which can be added to the config file vdradmind.conf by hand (no fronted support!): NO_EVENTID = 1 and NO_EVENTID_ON = 23,24,25 will disable the usage of event-ids in general or on channels 23 to 25 for all new timers. So the automatic timer correction -- both for auto timers and for manual edited -- will fall back to "recording time" mode. This is interesting for channels where the Event-ID changes between first show-up in the EPG and the event (thanks to Jan Ekholm for the idea and his help with debugging). - New search string handling in AutoTimer: /regexp/ and /regexp/i are perl regular expression, the second one is case insensitive. The regexp is testet against a string of the form: title~subtitle~summary As you see, all checked fields in the AutoTimer edit form are separated by a tilde (~). So you can explicitly search the title, subtitle and summary entry for matches. I advise you not to use any regular expressions in the AutoTimer, never! There is absolutely *no* syntax check for the regexp! Leave a stray brace and see vdradmin dying (because of a perl syntax error), or enter something like "/.*/" to beam the entire EPG into the timer list and watch VDR dying under the tons of timers. Don't write bug reports if a regexp has filled your harddisk to the very last bit, messed your timer list or killed your VDR: I told you not to use regular expressions! Don't even think about it! All non-regexp are now threatened as space separated list of patterns without any wildcards: Dots are a real dots, braces are real braces, and little furry things from Centaur 5 are real little furry things from Centaur 5. Fixed Bugs: - Month in "Whats on now" calculated wrong (Thanks to Thomas Schmidt) - Day in Event detail calculated wrong (Thanks to Thomas Schmidt) v0.93 -- tom -- Tue Jul 15 12:09:34 CEST 2003 Fixed Bugs: - Several issues with the Internet Explorer - Doesn't delete a recording timer v0.93 -- mdo -- - The 16th bit of the status field of timers will now be used for indicating automatically revised timers ("Auto"). Old timers with status "Auto", using the now deprecated third bit (see v0.24-pre13-mdo), will *in this version* be described as "Auto (alt)" or "Auto (old)" in the timer list. Editing an timer with status "Auto (old)" will correct the flag properly. CAUTION! Using the third bit (as in v0.24-pre13-mdo up to v0.92) is now *deprecated* and the support for the third bit will *definitively* be removed in the next version of vdradmin! Due this change only affects single timers, all old timers will disappear within the next month -- new "Auto" timers will be programmed properly. So before updating to the next version of vdradmin (probably v0.94), check that you don't have any old "Auto" timers left, or they won't be observed/revised any longer (but work anyway). v0.92 -- tom -- Tue Jul 4 10:49:13 CEST 2003 Fixed Bugs: - Several things in the log mechanism - Can't delete multiple Auto Timers at once (Thanks to Tom Pfeifer) - Sometimes wrong display of rec icon (Thanks to Tom Pfeifer) - Recordings frame missing if no recordings on disk (Thanks to Tom Pfeiffer) v0.91 -- tom -- Wed Jun 18 07:36:40 CEST 2003 - Added "Directory" option in Auto Timer (Suggested by Christian Jacobsen) Fixed Bugs: - Can't save complex timer (Thanks to Tom Pfeifer) v0.90 -- tom -- Sun Jun 15 01:20:00 CEST 2003 - New German layout (Thanks to Uwe Kempf) - Translated layout to English - Translated layout to French (Thanks to Olivier Jacques and Laurent DUPERREY) - subfolders in recordings (like in VDR) - Added TV mode - show disk usage in recordings menu (require VDR 1.1.29) - added "install" target, this is mainly for distributors - Reworked Auto Timer (Thanks to cooper) Fixed bugs: - Small patch to make vdradmin work together with the analogtv plugin (Thanks to Andreas Kool) - Added patch to make apache 2.0.40 with it's mod_proxy happy (Thanks to Thomas Sailer) - many, many other small things i don't remember v0.24-pre13-mdo -- cooper -- Tue May 27 03:10:39 CEST 2003 - major changes in AutoTimer(): - for each autotimer the event_id from the EPG will be stored in the higher 16 bits of the status value in the timers.conf. Be prepared to see huge and tiny (negative) numbers in the timers list! - for all autotimers, the 3rd bit in the status value (first row in timers.conf) will be set, along with the 1st bit (plus the high 16 bit as mentioned before) - will only programm new timers, changing existing timers is now the job of CheckTimers() - AutoTimer() will only add new timers, if the event_id and the channel number of the desired event are not in the current timers.conf. If there is no event_id, AutoTimer() will check for the name and start time like in privious versions of vdradmin - new function CheckTimers(): - is called every time just before AutoTimer() - will check every timer of timers.conf with the 3rd bit set in the status value: - if there is an event_id, CheckTimers() will search a event with the same event_id on the same channel in the EPG, and then set title, subtitle, start/stop time, day of recording and summary according to the EPG entry. If there is no matching event_id, nothing happens. - without event_id, CheckTimers() looks for events in the EPG within the margins of the timer, then do a wighting. For the event with the highest wight, CheckTimers() extends the margings of the timer so the event will be fully covered, plus extra time. This will probably fail when multiple events of 10 minutes duration or shorter are within the timer margins -- due the timer will only be extended but never shortened, this should be no real problem. The title of the event is unchecked. If there is no matching EPG entry, nothing happens. - other changes: - the default status for new timers is now 5 (equal to "Auto"), which means they'll be handled by CheckTimers(), an the event_id will be set. CheckTimers() will, as described above, change start/stop time and some more according to the current EPG. To get rid off the automatic observation, set the status to 0 or 1 (Yes/Ja or No/Nein). The side effect is that you'll lose the event_id, and if you set the status back to "Auto" again, CheckTimers() will use the "without event_id" branch to extend the timer margins. - side effects: - the status field (first row) of timers.conf will contain very huge and tiny numbers between -2147483647 and 2147483647, instead of 0, 1 and 3. While this is fully covered by Klaus' documentation, it could be some surprise to other programms parsing the timers.conf or reading the timers list via lstt from SVDRP, like Master Timer and others. - editing a timer via VDR will cause the loss of the event_id and set the status back to 0 or 1 -- so CheckTimers() won't touch it no longer. This is a feature. - the start time of observed timers might be changed while VDR is recording -- resulting in a new file and a little gap between the two recordings. Should be fixed somewhen. - observed timers with ":" in the name will cause unnecessary timer updates because the ":" will cause an inequality between timer title and event title. - the title of obeserved timers will be extended automatically by the subtitle (when in EPG), even if the original title was without subtitle. - double recordings (same start time, same title) are now very improbable, but still possible. Should be managed by CheckTimers() somewhen... v0.23 -- tom -- Sat Feb 15 22:46:01 CET 2003 - Now delivering compressed data (like mod_gzip) if the browser accept this. This makes vdradmin much faster on slow connections. This is experimental, so if you have problems with this set MOD_GZIP to 0 in your vdradmin.conf. Fixed Bugs: - Now opening remote control with target _blank (Thanks to Martin Hillmann) - Saving timers don't work if priority or lifetime less then 10 (Thanks to _cooper_) - Fixed typo in english configuration page (Thanks to Briandorling) v0.22 -- tom -- Thu Jan 16 14:08:31 CET 2003 - Reworked timer sort routine - Included virtual remote control Fixed bugs: - some small layout things v0.21 -- tom -- Mon Dec 30 22:34:37 CET 2002 - Added guest account - Startpage is now selectable Fixed Bugs: - Several things in the Autotimer v0.20 -- tom -- Thu Dec 26 13:21:39 CET 2002 Fixed Bugs: - Using wrong variable to connect to vdr v0.19 -- tom -- Thu Dec 26 03:20:12 CET 2002 Fixed Bugs: - Pictures are no longer missing - "--config" sets wrong variables - Timer sometimes disapeared - AutoTimer doesnt run after timeout - Cant save complex timers - many other small things... v0.18 -- tom -- Tue Dec 17 20:52:09 CET 2002 - vdradmin does not longer use HTTP::Daemon - updated english translation v0.17 -- tom -- Mon Dec 16 14:19:28 CET 2002 - Channels without EPG-data are not longer displayed in program list - No longer add spaces to Summary when changing Timer (Thanks to _cooper_) - Sorts repeating Timers like VDR (Thanks to Emil Naepflein) - Three colors shows how timers conflicts with other timers (Thanks to Emil Naepflein) - Now using HTTP::Daemon to comunicate with clients - vdradmin knows about first-day timers - Code cleanup - Some other things i dont remember v0.16 -- tom -- Sun Jun 9 14:58:57 CEST 2002 Fixed Bugs: - Auto Timer does nothing if no end time was given (this bug was introduced in v0.15) v0.15 -- tom -- Son Jun 2 17:32:44 CEST 2002 Fixed Bugs: - vdradmin exits with "Bad arg length for Socket::unpack..." under some perl versions. (Thanks to Juergen Schmidt) - Saving Auto Timers doesnt work in English theme - Selecting channels for a new Auto Timer doesnt work in German theme. - Auto Timer does not work if the timer goes across midnight _and_ the start time is beyond midnight (Thanks to Andrea Schultz). v0.14 -- tom -- Sat Apr 13 13:33:00 CEST 2002 - English translation added (Thanks to Thilo Wunderlich and Simon Dean) - Translations / Themes are stored in subdirectorys (suggested by Thilo Wunderlich) - internationalized days of week (see template//i18n.pl) - Changed names of Language. If you wish to use your old vdradmind.conf change "LANG = de" in "LANG = Deutsch". Fixed Bugs: - Sometimes the language could not be changed. - Priotity in Auto Timer was lost in some cases. - State row in channels view was lost if the Broadcaster has no EPG - Various small things coming with the internationalisation v0.13 -- tom -- Mit Mar 6 21:09:02 CET 2002 - Added `switch to channel´ function in program overview. - Fixed date bug with vdr > 1.0.0pre1 v0.12 -- tom -- Fre Feb 15 19:44:26 CET 2002 - vdradmin crashed when deleting a timer. fixed. - Fixed many bugs in the timer section - vdradmin is now compatible with apache & mod_proxy (thanks to Marcel Walter) v0.11 -- tom -- Tue Feb 5 21:25:21 CET 2002 - Renamed configuration file. "conffile" -> "vdradmind.conf". If you wish to use your old configuration file, rename it manualy. - Added "auto timer" function. - In timer and recordings menu, multiple entrys can be deleted at once - Some layout changes v0.10 -- tom -- Sam Jan 26 18:27:24 CET 2002 - Added complex timer handling - Fixed broken pipe messages - Some layout changes - Modified search function, it does not longer search the exact pattern (eg. ´one two´ does not search the exact pattern, it now means one _and_ two) - When creating a new timer, the timer is activated by default - After creating a timer from program overview or list you will redirected where you have been (instead of showing timer overview) v0.9 -- tom -- Tue Dec 11 13:38:22 CET 2001 - Whoops, fixed stupid bug in recordings sort mechanism - Added configuration mechanism (--config) - Added kill parameter (--kill) - Added prev/next link in program listing - Adding multiple channels in positive list fails if the list is empty. Fixed. v0.8 -- tom -- Sun Dec 2 11:55:43 CET 2001 - Time was calculated wrong in recordings section v0.7 -- tom -- Sat Dec 1 17:19:48 CET 2001 - vdradmin exits with error message if no recording exists. Fixed. - Added a option which allowes to see only selected channels in program list - List of recordings now sortable by date, time and name - Sorted timers - Time was calculated wrong in the timers section, month's range is 0-11 not 1-12 v0.6 -- tom -- Sun Nov 25 17:31:02 CET 2001 - Broadcasters now sorted case insensitive in channel overview - Encoded '&' very special since IE is too stupid to handle this correctly - Seperated events in channel list by days - Sorted recordings by date _and_ time - Under heavy load vdradmin exits with sigpipe. Fixed. - Added a search function v0.5 -- tom -- Wed Nov 14 12:09:35 CET 2001 - Fixed problem with complex timers in timer overview v0.4 -- tom -- Wed Nov 14 00:58:31 CET 2001 - vdradmin must not longer be started from the directory where it lives in. - Sorted broadcasters by name in 'Was laeuft jetzt?' - Added logging mechanism - Added a 'go!' button in the channel overview - The time field in the channel summary now eats almost everything. (e.g. 1920, 19,20, 19.20, 19:20 produces all the same) - The time buffer (e.g. 5 minutes before/after every movie) was in some cases calculated wrong. Fixed. - A click on the name of a recording shows the summary - Sometimes (if a request was interrupted) the program exits with a SIGPIPE. Fixed. - If a timer was (re)edited the channel selection was wrong - EPG data now stored in a tree (internal). - as ever, other things i don't remember v0.3 -- tom -- Thu Oct 25 21:50:12 CET 2001 - vdradmin has now a integrated webserver. No Apache needed. - A configurating menu added. - Sometimes (if a timer is recording) deleting this timer deletes the next one. Fixed. - EPG and Channel Data now hold in memory. - Several speed improvements. - It's now possible to select the channels listed in 'Was laeuft jetzt?' - I forgot the rest ;) v0.2 -- tom -- Sat Oct 13 01:10:50 CET 2001 - Viewing and deleting recordings a now possible (thanks to Thomas Heiligenmann) - It's now possible to support several languages. vdradmin suports at the moment only German. - The funktion of the 'Was laeuft jetzt?' was extended, it's now possible to show whats going on at eg. twelve a clock (assuming thats now nine - Sometimes in the channel listing two show's have the same color. Fixed. - Channel file was now also cached (to speed up) - Sending "quit\r\n" before closing SVDRP socket - A timer that titel field contains a ":" was not correct displayed - many, many other thins i don't remember v0.1 -- tom -- Tue Oct 9 00:12:12 CET 2001 - Initial release vdradmin-am-3.6.13/contrib/HISTORY.bigpatch000066400000000000000000000065501443716113400203210ustar00rootroot00000000000000README Big Patch ---------------- This is a patch to develop for a better vdradmin. It's designt as Patch for a vanilla vdradmin, i hope you have many fun with this nice program. Version 0.9 * Neue Option bei Autotimer Done on/off (thx gfa4711 & viking) * Done Liste persitent machen ! remove the ffserver stuff, is to buggy and peters solution over samba is better. Version 0.8 Fixes(!) and Features(*): * force an update at start from vdradmind * popup and change_channel moved to library.js * cosmetic changes from tv screen for a better display in mozilla * add refresh 60 sec in prog_summary (thanks to schwarz) * better handling for tv shows , if this show exists in the past, in auto timer * Better unique autotimer ! First klick on timeline produce a empty website .. fixed ! remote background fixed ! scrolling in detail window ! replace '|' to
in detail window (thanks to gestein) Version 0.7 Fixes(!) and Features(*): * Yes! Skins! - a new skin need only a new images directory with a new name in the same dir as 'bilder' - the images in the new skin dir must have the same size and name from the old dir - vdradmin will replace the http request to the new skin dir - vdradmin will also replace the navi.css and style.css, if this exist in skin directory - i.e. you can use a testing skin 'copper', only changes in color and style * Unique Autotimer (like master-timer) - this program only a timer was not come in the past (compare title+subtitle+summary) * timers can now handle more as one card (thanks to Emil Naepflein) - handle parallel recordings on same transponder on one card - handle recordings on cards with CA (only one recording per CA type) ! Cache timeout is now every 60 minutes ! If you not have channels in the right list under config then don't display in timeline Version 0.6 Fixes(!) and Features(*): * timeline is 50% faster * existing timer in timeline is marked now * links to the epg information in timer * redesign tvscreen with remote control ! remove flash plugin, because losse support for this ! timeline has lost epg items Version 0.5 Fixes(!) and Features(*): * only patching to the new Version 0.95 Version 0.4 Fixes(!) and Features(*): * Stream the records to client (very eperimental) need ffmpeg * add new timeline table from müntz and friends * add streamdevurls in prog_list and prog_summary * add a bunch config vars (for stream and streamdev) Version 0.3 Fixes(!) and Features(*): * Timeline: screen to display a better Programguide * Timeline: Pulldownmenu for times at 'was kommt um?' ! Timeline: timeline can open a own window to display the summary, is better for opera users * Timeline: direct input in the right edge of timeline to display a own time ! Timeline: the list of channels is sortet in user order * Timeline: higlightet program if this running now ! Timeline: no 25 Uhr at top of timeline ! Timeline: No break for mac users in the top right edge ! Global: little Bugfixes * Global: epg.data load direct from filesystem * Global: better redirects * Tv: in tv is grab selected on load * Tv: Button to grab the tv picture ! Tv: Ok, the tv screen is fixed ;) * Tv: Preview window as Flash screen, thanks for Albu from vdr-portal.de ! Config: 1x / je Tag is removed * Config: epg is configurable with vdradmin -c * Config: in config screen you can set the timelinescreen as startscreen * Config: switch for flash tv vdradmin-am-3.6.13/contrib/HISTORY.ct000066400000000000000000000073031443716113400171430ustar00rootroot00000000000000vdradmin (0.96-3.ctvdr.1) unstable; urgency=low * New upstream release * changed version numbering to "backports.org"-style to reflect relationship to official debian package * Modified streaming patch to allow streaming of recordings with dot, slash, double underscore and parenthesis in filename * Converted all patches to shorter format for new dpatch * Added dist-var patch, that change vdradmin.pl to search for it's files in system-directories, instead of local, relative paths (taken from official debian version 0.96-3) * Added 02_sectmpfiles.dpatch: use File::Temp to create temporary files, to prevent possible symlink-attacks (Closes: #287601) (taken from official debian version 0.96-3) * Set permissions of /etc/vdradmin/vdradmind.conf to 600 on new installations (users with an existing installation should ensure that the cfg-file has a permission of 600) (taken from official debian version 0.96-3) * using dh_install now * Added manpage for vdradmin.pl (taken from official debian version 0.96-2) * Set section to "web" and architecture to "all", set standards version to 3.6.1 * Fixed depends (no longer depends on vdr, but suggests it) * Added watch file * The vdradmin daemon can now be enabled/disabled in /etc/default/vdradmin (taken from official debian version 0.96-3) * Do not install Base64.pm, Template.pm and RescDescent.pm from upstream anymore, depend on libhtml-template-perl and libparse-rescdescent-perl (Base64.pm is allready provided by perl) (taken from official debian version 0.96-2) * Link /usr/share/vdradmin/template/{English,French}/bilder to /usr/share/vdradmin/template/Deutsch/bilder, this reduces the size of the deb by about 50% (taken from official debian version 0.96-2) * Took over README.Debian from official debian version 0.96-3 * added debian/compat -- Tobias Grimm Thu, 30 Dec 2004 22:20:00 +0100 vdradmin (0.95-ct-10) unstable; urgency=low * Fix rec streaming patch: slashes in dir names and order -- Peter Siering Fri, 29 Oct 2004 11:00:00 +0100 vdradmin (0.95-ct-9) unstable; urgency=low * extracted Peter Sierings modifications as 05_streaming.dpatch -- Tobias Grimm Sat, 21 Mar 2004 16:00:00 +0100 vdradmin (0.95-ct-8) unstable; urgency=low * added fix to rec_stream to skip "new"-char at time -- Tobias Grimm Wed, 17 Feb 2003 21:30:00 +0100 vdradmin (0.95-ct-7) unstable; urgency=low * changed additional_images -patch to work within CVS source-dirs too * added patch to fix problem with vdr's Wareagle Icon Patch (Thanks to HFlor from vdrportal.de) -- Tobias Grimm Sat, 08 Feb 2003 23:50:00 +0100 vdradmin (0.95-ct-6) unstable; urgency=low * vdradmin is distributed as non-native package from now on -- Tobias Grimm Sat, 08 Feb 2003 23:50:00 +0100 vdradmin (0.95-ct-5) unstable; urgency=low * new upstream release * includes fix for using through apache -- Peter Siering Tue, 22 Dec 2003 00:30:00 +0100 vdradmin (0.94-ct-4) unstable; urgency=low * minor streaming fixes, repair init -- Peter Siering Tue, 28 Nov 2003 10:00:00 +0100 vdradmin (0.94-ct-3) unstable; urgency=low * incorporated (live) streaming functions -- Peter Siering Tue, 25 Nov 2003 12:00:00 +0100 vdradmin (0.94-2) unstable; urgency=low * fixed vdradmind.pl location in init skript -- Peter Siering Sun, 16 Nov 2003 12:00:00 +0100 vdradmin (0.94-1) unstable; urgency=low * Initial Release. * includes daylight saving fix -- Peter Siering Thu, 30 Oct 2003 00:13:40 +0100 vdradmin-am-3.6.13/contrib/HISTORY.macfly000066400000000000000000000035171443716113400200130ustar00rootroot00000000000000since i don' know if vdradmin will be maintained in the future, i took the best version i knew of (the one from xpix) and fixed some issues. This is the reason, i have my very own HISTORY-File. macfly-001 - macfly 04.02.2005 - added Template, which was missing - fixed disabled timers in the timeline of timer_list to be grey - fixed disabled timers in the listing of timer_list to be grey - included the patch for handling extended EPG provided by tvm2vdr: if you use autotimer, you can use the following special Tags in the directory-field. They will be replaced with the information from the EPG of the EPG-event: %Title% will become the title of the event %Subtitle% will become the subtitle of the event %Director% will become the director of the event %Date% will become the date of the recording %Category% will become the category of the Event (Spielfilm/Serie/...) %Genre% will become the genre of the Event (Drama/Krimi/..) %Year% will become the year of production %Country% will become the country of production %Originaltitle% will become the original title of the event %FSK% will become the FSK from the event %Epsiode% will become the episode of the event %Rating% will become the rating of the event from the EPG-Provider - made the inputfield of the directory for autotimers i little bit larger - fixed enabling/disabling a timer - added a blacklistfunction. Enter any title into the file vdradmind.bl, one event into one line. If this string is found either(!!) in title or in title~subtitle, this event will not be programmed by autotimer. So you can disable complete episodes (for example when using "Enterprise" as Blacklist-string) or only one (when using "Enterprise~Azati Prime" as Blacklist-string). - removed the
from the events. They are still used for display only. vdradmin-am-3.6.13/contrib/README.Streaming000066400000000000000000000034041443716113400202600ustar00rootroot00000000000000VDRAdmin Streaming ================== The idea of extending VDRAdmin with streaming features originally came from the Debian maintainers of the vdradmin package. For questions about the streaming, they are the right contact persons: Peter Siering , Tobias Grimm You can enable access to the streaming feature, by setting STREAM_ON=1 in vdradmind.conf. vdradmin is not responsible for providing video streams, it's just a frontend to access them. At the configuration page you can now enable/disble live streaming and streaming of recordings. Live Streaming -------------- Live streaming gives you access to the currently selected channel. To use live streaming, you must have the streamdev-server-plugin from Sascha Volkenandt (available at http://streamdev.vdr-developer.org/) installed. This plugin provides access to the currently watched channel, by providing a video stream using the Video Transfer Protocol VTP. By default port 3000 is used, you can change this on the configuration page. Recordings Streaming -------------------- There is no real streaming server for VDR recordings available yet. Our lazy solution right now is, to simply access the recordings using a Samba share. So your first step to make use of the recordings streaming should be, to make your recoordings directory available over the network. The URL, a client should use to access this network share, has to be configured at the configuration page. VDRAadmin will also need direct access to VDR's recordings directory. You have to set this in vdradmind.conf with VIDEODIR, which is by default set to VIDEODIR="/video". Setting up the Client / Browser ------------------------------- !!! TODO !!! -- Tobias Grimm , Sun, 23 Jan 2005 20:00:00 +0100 vdradmin-am-3.6.13/contrib/user.css.example000066400000000000000000000014671443716113400206010ustar00rootroot00000000000000/* The user.css is mainly an example to demonstrate the possibilities */ /* Disable items in navigation bar. For valid ids read navigation.html. */ #rc { display: none; } #tv { display: none; } /* Disable action icons. e.g.: close, switch, record, imdb, info, stream */ /* disable info and stream buttons in lists */ .list .action.info, .list .action.stream { display: none; } /* Disable scrollbars in prog_summary detail view. */ #prog_summary .epg_summary { overflow: auto; } /* Workaround for scrollbar problem in InternetExplorer. */ table#heading, table.list, table#buttons, div#buttons, #at_timer_new .group, #timer_new .group, #rec_edit .group, #vdr_cmds .group, #about .group, #config .group { width: 95%; } /* Change color of links from EPG title to prog_detail. */ .epg_title a { color: blue; } vdradmin-am-3.6.13/contrib/vdradmin-am.spec000066400000000000000000000200351443716113400205220ustar00rootroot00000000000000## supports following defines during RPM build: ## ## specified fork account/branch (EXAMPLE) # # rpmbuild --undefine=_disable_source_fetch -bb -D "fork_account pbiering" -D "fork_branch master" vdradmin-am.spec # ## specific git commit/date on upstream (EXAMPLE) # # rpmbuild --undefine=_disable_source_fetch -bb -D "gitcommit 6ecf728e9a48871481abf5f569e510cd592ce961" -D "gitdate 20160629" vdradmin-am.spec # # ## rebuild from tarball requires related named tar.gz file and also related defines (EXAMPLE) # # rpmbuild -tb vdradmin-am-pbiering-master.tar.gz -D "fork_account pbiering" -D "fork_branch master" %global debug_package %{nil} %global vdradmin_user vdradmin %global vdradmin_group vdradmin %if 0%{?version:1} %define ver %{version} %else %define ver 3.6.13 %endif %if 0%{?release:1} %define rel %{release} %else %define rel 6.1 %endif Name: vdradmin-am BuildArch: noarch Version: %{ver} Summary: Web-based administration tool for vdr License: see /usr/share/doc/vdradmin/COPYING URL: https://github.com/vdr-projects/%{name} Group: Unspecified Conflicts: vdradmin Requires: systemd Requires: vdr Requires: perl(locale) Requires: perl(Template) Requires: perl(Template::Plugin::JavaScript) Requires: perl(CGI) Requires: perl(HTTP::Date) Requires: perl(IO::Socket) Requires: perl(Time::Local) Requires: perl(MIME::Base64) Requires: perl(File::Temp) Requires: perl(File::Find) Requires: perl(URI) Requires: perl(URI::Escape) Requires: perl(HTTP::Tiny) Requires: perl(HTTP::Daemon) Requires: perl(Locale::gettext) Requires: perl(Net::SMTP) Requires: perl(Authen::SASL) Requires: perl(Digest::HMAC_MD5) Requires: perl(Encode) Requires: perl(IO::Socket::INET6) Requires: perl(HTTP::Daemon::SSL) Requires: perl(Compress::Zlib) Requires: perl(Sys::Syslog) Requires: perl(Regexp::IPv6) Requires: perl(File::Temp) Requires: gettext BuildRequires: perl(locale) BuildRequires: perl(Template) BuildRequires: perl(Template::Plugin::JavaScript) BuildRequires: perl(CGI) BuildRequires: perl(HTTP::Date) BuildRequires: perl(IO::Socket) BuildRequires: perl(Time::Local) BuildRequires: perl(MIME::Base64) BuildRequires: perl(File::Temp) BuildRequires: perl(File::Find) BuildRequires: perl(URI) BuildRequires: perl(URI::Escape) BuildRequires: perl(HTTP::Tiny) BuildRequires: perl(HTTP::Daemon) BuildRequires: perl(Locale::gettext) BuildRequires: perl(Net::SMTP) BuildRequires: perl(Authen::SASL) BuildRequires: perl(Digest::HMAC_MD5) BuildRequires: perl(Encode) BuildRequires: perl(IO::Socket::INET6) BuildRequires: perl(HTTP::Daemon::SSL) BuildRequires: perl(Compress::Zlib) BuildRequires: perl(Sys::Syslog) BuildRequires: perl(Regexp::IPv6) BuildRequires: perl(File::Temp) BuildRequires: gettext %if 0%{?gitcommit:1} %global gitshortcommit %(c=%{gitcommit}; echo ${c:0:7}) Release: %{rel}.git.%{gitshortcommit}.%{gitdate}%{?dist} %else %if 0%{?fork_account:1} %global fork_branch_normalized %(echo %{fork_branch} | sed 's/-/_/g') Release: %{rel}%{?fork_account:.%fork_account.%fork_branch_normalized}%{?dist} %else Release: %{rel}%{?dist} %endif %endif %if 0%{?fork_branch:1} Source0: https://github.com/%{fork_account}/%{name}/archive/%{fork_branch}/%{name}-%{fork_account}-%{fork_branch}.tar.gz %else %if 0%{?gitcommit:1} Source0: https://github.com/vdr-projects/%{name}/archive/%{gitcommit}/%{name}-%{gitshortcommit}.tar.gz %else Source0: https://github.com/vdr-projects/%{name}/archive/v%{version}/%{name}-%{version}.tar.gz %endif %endif %description vdradmin-am provides a webinterface for managing the Linux Video Disk Recorder (vdr) %prep %if 0%{?fork_account:1} %setup -q -n %{name}-%{fork_branch} %else %if 0%{?gitcommit:1} %setup -q -n %{name}-%{gitcommit} %else %setup -q -n %{name}-%{version} %endif %endif %build ./make.sh po %install export PREFIX=$RPM_BUILD_ROOT export DESTDIR=$RPM_BUILD_ROOT # run included installer ./install.sh # remove PREFIX implanted by ./install.sh into vdradmin perl -pi -e "s#$RPM_BUILD_ROOT##g" $RPM_BUILD_ROOT/usr/bin/vdradmind # remove packaged File::Temp (available by base repo) to avoid sudden dependency to VMS::Stdio rm $RPM_BUILD_ROOT/usr/share/vdradmin/lib/File/Temp.pm # move to sbin install -d $RPM_BUILD_ROOT/usr/sbin mv $RPM_BUILD_ROOT/usr/bin/vdradmind $RPM_BUILD_ROOT/usr/sbin/ # create directories install -d $RPM_BUILD_ROOT/etc/vdradmin install -d $RPM_BUILD_ROOT/etc/vdradmin/certs install -d $RPM_BUILD_ROOT/etc/sysconfig install -d $RPM_BUILD_ROOT/var/cache/vdradmin install -d $RPM_BUILD_ROOT/var/log/vdradmin install -d $RPM_BUILD_ROOT/var/lib/vdradmin install -d $RPM_BUILD_ROOT/usr/lib/systemd/system install -m 644 contrib/vdradmin.service $RPM_BUILD_ROOT/usr/lib/systemd/system/ # create adjusted default config with random password cat </dev/null; then echo -n "Adding group %{vdradmin_group}.." groupadd --system %{vdradmin_group} echo "..done" fi if ! getent passwd %{vdradmin_user} >/dev/null; then echo -n "Adding user %{vdradmin_user}.." useradd --system --home /var/lib/vdradmin --shell /bin/false \ --comment "VDRAdmin user" --no-create-home \ --gid %{vdradmin_group} \ %{vdradmin_user} echo "...done" fi %post #!/bin/sh -e set -e # ensure vdradmind.at (auto timers) exists ATFILE=/var/lib/vdradmin/vdradmind.at [ -e $ATFILE ] || touch $ATFILE systemctl daemon-reload if [ "$1" = "2" ]; then # upgrade systemctl condrestart vdradmin fi if [ "$1" = "1" ]; then # install echo "Check for default passwords in /etc/vdradmin/vdradmind.conf:" echo "$ egrep '^(USERNAME|PASSWORD)' /etc/vdradmin/vdradmind.conf" fi %preun #!/bin/sh set -e if [ "$1" = "0" ]; then # uninstall systemctl disable --now vdradmin fi %postun if [ "$1" = "0" ]; then if getent passwd %{vdradmin_user} >/dev/null; then userdel %{vdradmin_user} || true fi if getent group %{vdradmin_group} >/dev/null; then groupdel %{vdradmin_group} || true fi fi %files %config(noreplace) /etc/sysconfig/vdradmin %attr(0755,root,root) /usr/sbin/vdradmind /usr/share/doc/vdradmin /usr/share/vdradmin/template %dir %attr(0770,root,vdradmin) /var/cache/vdradmin/ %dir %attr(0770,root,vdradmin) /var/lib/vdradmin/ %dir %attr(0770,root,vdradmin) /var/log/vdradmin/ %dir %attr(0750,root,vdradmin) /etc/vdradmin/certs %dir %attr(0750,vdradmin,video) /etc/vdradmin/ %config(noreplace) %attr(0640,vdradmin,video) /etc/vdradmin/vdradmind.conf /usr/lib/systemd/system/ %dir %doc /usr/share/doc /usr/share/locale /usr/share/man /usr/share/vdradmin/lib %changelog * Sun Jun 04 2023 Peter Bieringer - 3.6.13-6.1 - Release 3.6.13 * Wed Mar 12 2023 Peter Bieringer - 3.6.12-6.1 - Release 3.6.12 * Wed Mar 01 2023 Peter Bieringer - 3.6.11-6.1 - Add missing 'gettext' requirement * Sun Feb 26 2023 Peter Bieringer - 3.6.11-6.0 - Do not package "autotimer" tools for now - Add DESTDIR support - Fix permissions of unit file - Remove included /usr/share/vdradmin/lib/File/Temp.pm (supplied by base repo) * Fri Feb 03 2023 Peter Bieringer - 3.6.10-5.1 - Create spec based on converted from vdradmin-am_3.6.10-4.1_all.deb by alien version 8.95 - Extend/adjust spec and file locations - Add systemd unit and sysconfig file vdradmin-am-3.6.13/contrib/vdradmin.service000066400000000000000000000012321443716113400206330ustar00rootroot00000000000000[Unit] Description=vdradmin-am, the web-based administration tool for VDR Documentation=man:vdradmind(8) Documentation=file:///usr/share/doc/vdradmin/README After=vdr.service After=network.target ConditionPathExists=/etc/vdradmin ConditionPathExists=/etc/vdradmin/vdradmind.conf [Service] EnvironmentFile=-/etc/sysconfig/vdradmin PIDFile=/var/lib/vdradmin/vdradmind.pid Nice=10 Type=forking User=vdradmin Group=vdradmin ExecStart=/usr/sbin/vdradmind --pid /var/lib/vdradmin/vdradmind.pid --cfgdir /etc/vdradmin $OPTS ExecStop=/usr/sbin/vdradmind --pid /var/lib/vdradmin/vdradmind.pid $OPTS --kill Restart=on-failure [Install] WantedBy=multi-user.target vdradmin-am-3.6.13/contrib/vdradmin.sysconfig000066400000000000000000000002151443716113400211770ustar00rootroot00000000000000# Options for vdradmin systemd unit # installed at /etc/sysconfig/vdradmin by the RPM # enable logging with level 5 (notice) OPTS="--log 5" vdradmin-am-3.6.13/contrib/vdradmind.bl_example000066400000000000000000000001131443716113400214440ustar00rootroot00000000000000Dr. Stefan Frank: Der Arzt, dem die Frauen vertrauen Der Prinz von Bel-Air vdradmin-am-3.6.13/convert.pl000077500000000000000000000032451443716113400160330ustar00rootroot00000000000000#!/usr/bin/perl use strict; if(scalar(@ARGV) != 3) { print("Usage: convert.pl \n"); print("\t VDRAdmin-AM's vdradmind.conf\n"); print("\t Source timers.conf\n"); print("\t Destination timers.conf\n"); exit 1; } my %CONFIG; my $CONFFILE = @ARGV[0]; my $timers_in = @ARGV[1]; my $timers_out = @ARGV[2]; ReadConfig(); print("Converting $timers_in to $timers_out\n"); my $in = open(FH_IN, "<$timers_in") if(-e "$timers_in"); my $out = open(FH_OUT, ">$timers_out"); if($in and $out) { while() { chomp; s/#.*//; s/^\s+//; s/\s+$//; next unless length; my ($status, $channel, $day, $start, $stop, $priority, $lifetime, $file, $aux) = split(":", $_); my $autotimer = 1 if($status & 0x8000); my $active = $status & 0x7FFF; my $event_id = $status >> 16; if($autotimer) { $autotimer = 2 if($event_id); $aux .= "|" if($aux); $aux .= "$event_id$autotimer$CONFIG{TM_MARGIN_BEGIN}$CONFIG{TM_MARGIN_END}"; } print(FH_OUT "$active:$channel:$day:$start:$stop:$priority:$lifetime:$file:$aux\n"); } close(FH_IN); close(FH_OUT); print("\nNOTE:\n"); print("Please check the new timers.conf for errors before replacing the old timers.conf!\n"); } else { print("Failed to open files!\n"); exit 1; } sub ReadConfig { if(-e $CONFFILE) { open(CONF, $CONFFILE); while() { chomp; my($key, $value) = split(/ \= /, $_, 2); $CONFIG{$key} = $value; } close(CONF); } else { print "$CONFFILE doesn't exist. Exiting\n"; exit(1); } return(0); } vdradmin-am-3.6.13/install.sh000077500000000000000000000172421443716113400160220ustar00rootroot00000000000000#!/bin/bash # vim:noet:sw=4:ts=4: # Copyright (c) 2005-2014 Andreas Mair # # # Download and patchscript for VDRAdmin-AM # (based on install.sh Copyright (c) 2003 Frank (xpix) Herrmann) PATH=$PATH:/sbin:/bin:/usr/sbin:/usr/bin PREFIX=${PREFIX} LIBDIR=${LIBDIR:-$PREFIX/usr/share/vdradmin} ETCDIR=${ETCDIR:-$PREFIX/etc/vdradmin} DOCDIR=${DOCDIR:-$PREFIX/usr/share/doc/vdradmin} BINDIR=${BINDIR:-$PREFIX/usr/bin} LOCDIR=${LOCDIR:-$PREFIX/usr/share/locale} MANDIR=${MANDIR:-$PREFIX/usr/share/man} LOGDIR=${LOGDIR:-$PREFIX/var/log/vdradmin} CACHEDIR=${CACHEDIR:-$PREFIX/var/cache/vdradmin} PIDFILE=${PIDFILE:-$PREFIX/var/run/vdradmin/vdradmind.pid} VIDEODIR=${VIDEODIR:-/video} EPGIMAGES=${EPGIMAGES:-$VIDEODIR/epgimages} VDRCONF=${VDRCONF:-$VIDEODIR} function usage() { echo "" echo "usage: $(basename $0) [-c | -u | -p | -h]" echo "" echo -e "\t-c : Run \"vdradmind -c\" after installation (=configure)." echo -e "\t-u : Perform uninstall." echo -e "\t-p : List and optionally install required Perl modules." echo -e "\t-h : This message." echo "" exit 0 } function killRunningVDRAdmin() { local KILLED=0 local PID=$(pidof vdradmind) [ "$PID" ] || PID=$(ps a | grep vdradmind.pl | grep perl | grep -v grep | cut -d' ' -f1) if [ "$PID" ]; then KILLED=1 kill $PID fi return $KILLED } # $1 - the Perl module to check for. function checkPerlModule() { [ -z "$1" ] && return 1 local MODULE=$1 local ALT_MODULE=$2 local ALT_MESSAGE= [ "$ALT_MODULE" ] && ALT_MESSAGE=" or $ALT_MODULE" echo -n "Checking for Perl module $MODULE$ALT_MESSAGE... " perl -ce 'BEGIN{$0 =~ /(^.*\/)/; $BASENAME = $1; unshift(@INC, $BASENAME . "lib/");} use '$MODULE >/dev/null 2>&1 if [ $? -eq 2 ]; then if [ "$ALT_MODULE" ]; then perl -ce 'BEGIN{$0 =~ /(^.*\/)/; $BASENAME = $1; unshift(@INC, $BASENAME . "lib/");} use '$ALT_MODULE >/dev/null 2>&1 [ $? -eq 0 ] && echo " $ALT_MODULE found" && return 0 fi echo " MISSING" read -p "Do you want to install $MODULE? [y/N]" [ "$REPLY" = "y" -o "$REPLY" = "Y" ] && su -c "perl -MCPAN -e 'CPAN::install \"$MODULE\"'" else echo " found" fi } function perlModules() { echo "" echo "*** Required ***" checkPerlModule locale checkPerlModule Template checkPerlModule Template::Plugin::JavaScript checkPerlModule CGI checkPerlModule HTTP::Date checkPerlModule IO::Socket checkPerlModule Time::Local checkPerlModule MIME::Base64 checkPerlModule File::Temp checkPerlModule File::Find checkPerlModule URI checkPerlModule URI::Escape checkPerlModule HTTP::Tiny checkPerlModule HTTP::Daemon echo "" echo "You need Locale::gettext OR Locale::Messages" checkPerlModule Locale::gettext Locale::Messages echo "" echo "*** Optional ***" echo "* Required for AutoTimer email notification" checkPerlModule Net::SMTP checkPerlModule Authen::SASL echo "* Required for AutoTimer email notification and CRAM-MD5 authentication" checkPerlModule Digest::HMAC_MD5 echo "* Required if VDR and VDRAdmin-AM use different character encoding" checkPerlModule Encode echo "* Required for IPv6 support" checkPerlModule IO::Socket::INET6 echo "* Required for SSL support (https)" checkPerlModule HTTP::Daemon::SSL echo "* Required if you want to use gzip'ed HTTP responses" checkPerlModule Compress::Zlib echo "* Required if you want to log to syslog" checkPerlModule Sys::Syslog } function makeDir() { [ -z "$1" ] && return 1 local DIR=$1 local MUST_CREATE=${2:-0} if [ -e "$DIR" -a ! -d "$DIR" ]; then echo "$DIR exists but is no directory!" echo "Aborting..." return 1 elif [ -d $DIR -a $MUST_CREATE = 1 ]; then echo "$DIR exists. Please remove it before calling install.sh!" echo "Aborting..." return 1 fi if [ ! -e "$DIR" ]; then mkdir -p "$DIR" if [ $? -ne 0 ]; then echo "Failed to create directory $DIR!" echo "Aborting..." return 1 fi fi return 0 } function doInstall() { echo "" echo "********* Installing VDRAdmin-AM *************" echo "" perlModules makeDir $LIBDIR 1 && cp -r template lib $LIBDIR || exit 1 makeDir $BINDIR || exit 1 makeDir $DOCDIR && cp -r contrib COPYING CREDITS HISTORY INSTALL LGPL.txt README* REQUIREMENTS FAQ $DOCDIR || exit 1 makeDir $MANDIR/man8 && cp vdradmind.pl.1 $MANDIR/man8/vdradmind.8 || exit 1 ( cd locale for lang in * do makeDir $LOCDIR/$lang/LC_MESSAGES/ && install -m 644 $lang/LC_MESSAGES/vdradmin.mo $LOCDIR/$lang/LC_MESSAGES/vdradmin.mo || exit 1 done ) local RESTART= if [ -d $BINDIR ]; then killRunningVDRAdmin if [ $? -ne 0 ] ; then RESTART=1 echo "Killed running VDRAdmin-AM..." fi sed $BINDIR/vdradmind \ -e "s/^\(my \$SEARCH_FILES_IN_SYSTEM *=\) 0;/\1 1;/" \ -e "s:/usr/share/vdradmin/lib:${LIBDIR}/lib:" \ -e "s:/usr/share/vdradmin/template:${LIBDIR}/template:" \ -e "s:/var/log/vdradmin:${LOGDIR}:" \ -e "s:/var/cache/vdradmin:${CACHEDIR}:" \ -e "s:/var/run/vdradmin/vdradmind.pid:${PIDFILE}:" \ -e "s:\(\$ETCDIR *= \)\"/etc/vdradmin\";:\1\"${ETCDIR}\";:" \ -e "s:/usr/share/locale:${LOCDIR}:" \ -e "s:\(\$CONFIG{VIDEODIR} *= \)\"/video\";:\1\"${VIDEODIR}\";:" \ -e "s:\(\$CONFIG{EPGIMAGES} *= \)\"\$CONFIG{VIDEODIR}/epgimages\";:\1\"${EPGIMAGES}\";:" \ -e "s:\(\$CONFIG{VDRCONFDIR} *= \)\"\$CONFIG{VIDEODIR}\";:\1\"${VDRCONF}\";:" chmod a+x $BINDIR/vdradmind if [ "$CONFIG" ]; then echo "Configuring VDRAdmin-AM..." $BINDIR/vdradmind -c fi if [ "$RESTART" ]; then echo "Restarting VDRAdmin-AM..." $BINDIR/vdradmind fi echo "" if [ -e $BINDIR/vdradmind.pl ]; then echo "Removing ancient $BINDIR/vdradmind.pl" rm -f $BINDIR/vdradmind.pl fi for man in man1/vdradmind.pl.1 man1/vdradmind.1; do if [ -e $MANDIR/$man ]; then echo "Removing ancient $MANDIR/$man" rm -f $MANDIR/$man fi done else echo "$BINDIR exists but is no directory!" echo "Aborting..." exit 1 fi echo "" echo "" echo "VDRAdmin-AM has been installed!" echo "" if [ -z "$RESTART" ]; then echo "Run \"$BINDIR/vdradmind\" to start VDRAdmin-AM." echo "" fi echo "NOTE:" echo "If you want to run VDRAdmin-AM in a different language you must set the LANG environment variable (see README)." echo "" echo "NOTE2:" echo "If you would like VDRAdmin-AM to start at system's boot, please modify your system's init scripts." local USED_DIRS="$(echo -e "$ETCDIR\n$LOGDIR\n$CACHEDIR\n$(dirname "$PIDFILE")" | sort -u)" echo echo "NOTE3:" echo "VDRAdmin-AM needs to access some directories:" echo "$USED_DIRS" echo echo "Please check that the user VDRAdmin-AM runs has enough permissions to access them!" exit 0 } function doUninstall() { echo "" echo "********* Uninstalling VDRAdmin-AM *************" echo "" killRunningVDRAdmin if [ -d $DOCDIR ]; then rm -rf $DOCDIR fi if [ -d $LIBDIR ]; then rm -rf $LIBDIR fi if [ -d $CACHEDIR ]; then rm -rf $CACHEDIR fi for man in man1/vdradmind.pl.1 man1/vdradmind.1 man8/vdradmind.8; do if [ -e $MANDIR/$man ]; then rm -f $MANDIR/$man fi done if [ -e $BINDIR/vdradmind.pl ]; then rm -f $BINDIR/vdradmind.pl fi if [ -e $BINDIR/vdradmind ]; then rm -f $BINDIR/vdradmind fi rm -f $LOCDIR/*/LC_MESSAGES/vdradmin.mo echo "" echo "VDRAdmin-AM has been uninstalled!" echo "" if [ -d $ETCDIR ]; then echo "Your configuration files located in $ETCDIR have NOT been deleted!" echo "If you want to get rid of them, please delete them manually!" echo "" fi } UNINSTALL= CONFIG= PERL= while [ "$1" ] do case $1 in -u) UNINSTALL=1;; -c) CONFIG=1;; -p) PERL=1;; -h) usage;; *) echo "Ignoring param \"$1\$.";; esac shift done if [ $(basename $0) = "uninstall.sh" -o "$UNINSTALL" ]; then doUninstall elif [ "$PERL" ]; then echo "" echo "Testing required Perl modules..." perlModules echo "...done." else doInstall fi vdradmin-am-3.6.13/lib/000077500000000000000000000000001443716113400145555ustar00rootroot00000000000000vdradmin-am-3.6.13/lib/File/000077500000000000000000000000001443716113400154345ustar00rootroot00000000000000vdradmin-am-3.6.13/lib/File/Temp.pm000066400000000000000000001767471443716113400167250ustar00rootroot00000000000000package File::Temp; =head1 NAME File::Temp - return name and handle of a temporary file safely =begin __INTERNALS =head1 PORTABILITY This section is at the top in order to provide easier access to porters. It is not expected to be rendered by a standard pod formatting tool. Please skip straight to the SYNOPSIS section if you are not trying to port this module to a new platform. This module is designed to be portable across operating systems and it currently supports Unix, VMS, DOS, OS/2, Windows and Mac OS (Classic). When porting to a new OS there are generally three main issues that have to be solved: =over 4 =item * Can the OS unlink an open file? If it can not then the C<_can_unlink_opened_file> method should be modified. =item * Are the return values from C reliable? By default all the return values from C are compared when unlinking a temporary file using the filename and the handle. Operating systems other than unix do not always have valid entries in all fields. If C fails then the C comparison should be modified accordingly. =item * Security. Systems that can not support a test for the sticky bit on a directory can not use the MEDIUM and HIGH security tests. The C<_can_do_level> method should be modified accordingly. =back =end __INTERNALS =head1 SYNOPSIS use File::Temp qw/ tempfile tempdir /; $fh = tempfile(); ($fh, $filename) = tempfile(); ($fh, $filename) = tempfile( $template, DIR => $dir); ($fh, $filename) = tempfile( $template, SUFFIX => '.dat'); $dir = tempdir( CLEANUP => 1 ); ($fh, $filename) = tempfile( DIR => $dir ); Object interface: require File::Temp; use File::Temp (); $fh = new File::Temp($template); $fname = $fh->filename; $tmp = new File::Temp( UNLINK => 0, SUFFIX => '.dat' ); print $tmp "Some data\n"; print "Filename is $tmp\n"; The following interfaces are provided for compatibility with existing APIs. They should not be used in new code. MkTemp family: use File::Temp qw/ :mktemp /; ($fh, $file) = mkstemp( "tmpfileXXXXX" ); ($fh, $file) = mkstemps( "tmpfileXXXXXX", $suffix); $tmpdir = mkdtemp( $template ); $unopened_file = mktemp( $template ); POSIX functions: use File::Temp qw/ :POSIX /; $file = tmpnam(); $fh = tmpfile(); ($fh, $file) = tmpnam(); Compatibility functions: $unopened_file = File::Temp::tempnam( $dir, $pfx ); =head1 DESCRIPTION C can be used to create and open temporary files in a safe way. There is both a function interface and an object-oriented interface. The File::Temp constructor or the tempfile() function can be used to return the name and the open filehandle of a temporary file. The tempdir() function can be used to create a temporary directory. The security aspect of temporary file creation is emphasized such that a filehandle and filename are returned together. This helps guarantee that a race condition can not occur where the temporary file is created by another process between checking for the existence of the file and its opening. Additional security levels are provided to check, for example, that the sticky bit is set on world writable directories. See L<"safe_level"> for more information. For compatibility with popular C library functions, Perl implementations of the mkstemp() family of functions are provided. These are, mkstemp(), mkstemps(), mkdtemp() and mktemp(). Additionally, implementations of the standard L tmpnam() and tmpfile() functions are provided if required. Implementations of mktemp(), tmpnam(), and tempnam() are provided, but should be used with caution since they return only a filename that was valid when function was called, so cannot guarantee that the file will not exist by the time the caller opens the filename. =cut # 5.6.0 gives us S_IWOTH, S_IWGRP, our and auto-vivifying filehandls # People would like a version on 5.005 so give them what they want :-) use 5.005; use strict; use Carp; use File::Spec 0.8; use File::Path qw/ rmtree /; use Fcntl 1.03; use Errno; require VMS::Stdio if $^O eq 'VMS'; # Need the Symbol package if we are running older perl require Symbol if $] < 5.006; ### For the OO interface use base qw/ IO::Handle /; use overload '""' => "STRINGIFY"; # use 'our' on v5.6.0 use vars qw($VERSION @EXPORT_OK %EXPORT_TAGS $DEBUG $KEEP_ALL); $DEBUG = 0; $KEEP_ALL = 0; # We are exporting functions use base qw/Exporter/; # Export list - to allow fine tuning of export table @EXPORT_OK = qw{ tempfile tempdir tmpnam tmpfile mktemp mkstemp mkstemps mkdtemp unlink0 cleanup }; # Groups of functions for export %EXPORT_TAGS = ( 'POSIX' => [qw/ tmpnam tmpfile /], 'mktemp' => [qw/ mktemp mkstemp mkstemps mkdtemp/], ); # add contents of these tags to @EXPORT Exporter::export_tags('POSIX','mktemp'); # Version number $VERSION = '0.16'; # This is a list of characters that can be used in random filenames my @CHARS = (qw/ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z a b c d e f g h i j k l m n o p q r s t u v w x y z 0 1 2 3 4 5 6 7 8 9 _ /); # Maximum number of tries to make a temp file before failing use constant MAX_TRIES => 1000; # Minimum number of X characters that should be in a template use constant MINX => 4; # Default template when no template supplied use constant TEMPXXX => 'X' x 10; # Constants for the security level use constant STANDARD => 0; use constant MEDIUM => 1; use constant HIGH => 2; # OPENFLAGS. If we defined the flag to use with Sysopen here this gives # us an optimisation when many temporary files are requested my $OPENFLAGS = O_CREAT | O_EXCL | O_RDWR; unless ($^O eq 'MacOS') { for my $oflag (qw/ NOFOLLOW BINARY LARGEFILE EXLOCK NOINHERIT /) { my ($bit, $func) = (0, "Fcntl::O_" . $oflag); no strict 'refs'; $OPENFLAGS |= $bit if eval { # Make sure that redefined die handlers do not cause problems # eg CGI::Carp local $SIG{__DIE__} = sub {}; local $SIG{__WARN__} = sub {}; $bit = &$func(); 1; }; } } # On some systems the O_TEMPORARY flag can be used to tell the OS # to automatically remove the file when it is closed. This is fine # in most cases but not if tempfile is called with UNLINK=>0 and # the filename is requested -- in the case where the filename is to # be passed to another routine. This happens on windows. We overcome # this by using a second open flags variable my $OPENTEMPFLAGS = $OPENFLAGS; unless ($^O eq 'MacOS') { for my $oflag (qw/ TEMPORARY /) { my ($bit, $func) = (0, "Fcntl::O_" . $oflag); no strict 'refs'; $OPENTEMPFLAGS |= $bit if eval { # Make sure that redefined die handlers do not cause problems # eg CGI::Carp local $SIG{__DIE__} = sub {}; local $SIG{__WARN__} = sub {}; $bit = &$func(); 1; }; } } # INTERNAL ROUTINES - not to be used outside of package # Generic routine for getting a temporary filename # modelled on OpenBSD _gettemp() in mktemp.c # The template must contain X's that are to be replaced # with the random values # Arguments: # TEMPLATE - string containing the XXXXX's that is converted # to a random filename and opened if required # Optionally, a hash can also be supplied containing specific options # "open" => if true open the temp file, else just return the name # default is 0 # "mkdir"=> if true, we are creating a temp directory rather than tempfile # default is 0 # "suffixlen" => number of characters at end of PATH to be ignored. # default is 0. # "unlink_on_close" => indicates that, if possible, the OS should remove # the file as soon as it is closed. Usually indicates # use of the O_TEMPORARY flag to sysopen. # Usually irrelevant on unix # Optionally a reference to a scalar can be passed into the function # On error this will be used to store the reason for the error # "ErrStr" => \$errstr # "open" and "mkdir" can not both be true # "unlink_on_close" is not used when "mkdir" is true. # The default options are equivalent to mktemp(). # Returns: # filehandle - open file handle (if called with doopen=1, else undef) # temp name - name of the temp file or directory # For example: # ($fh, $name) = _gettemp($template, "open" => 1); # for the current version, failures are associated with # stored in an error string and returned to give the reason whilst debugging # This routine is not called by any external function sub _gettemp { croak 'Usage: ($fh, $name) = _gettemp($template, OPTIONS);' unless scalar(@_) >= 1; # the internal error string - expect it to be overridden # Need this in case the caller decides not to supply us a value # need an anonymous scalar my $tempErrStr; # Default options my %options = ( "open" => 0, "mkdir" => 0, "suffixlen" => 0, "unlink_on_close" => 0, "ErrStr" => \$tempErrStr, ); # Read the template my $template = shift; if (ref($template)) { # Use a warning here since we have not yet merged ErrStr carp "File::Temp::_gettemp: template must not be a reference"; return (); } # Check that the number of entries on stack are even if (scalar(@_) % 2 != 0) { # Use a warning here since we have not yet merged ErrStr carp "File::Temp::_gettemp: Must have even number of options"; return (); } # Read the options and merge with defaults %options = (%options, @_) if @_; # Make sure the error string is set to undef ${$options{ErrStr}} = undef; # Can not open the file and make a directory in a single call if ($options{"open"} && $options{"mkdir"}) { ${$options{ErrStr}} = "doopen and domkdir can not both be true\n"; return (); } # Find the start of the end of the Xs (position of last X) # Substr starts from 0 my $start = length($template) - 1 - $options{"suffixlen"}; # Check that we have at least MINX x X (eg 'XXXX") at the end of the string # (taking suffixlen into account). Any fewer is insecure. # Do it using substr - no reason to use a pattern match since # we know where we are looking and what we are looking for if (substr($template, $start - MINX + 1, MINX) ne 'X' x MINX) { ${$options{ErrStr}} = "The template must end with at least ". MINX . " 'X' characters\n"; return (); } # Replace all the X at the end of the substring with a # random character or just all the XX at the end of a full string. # Do it as an if, since the suffix adjusts which section to replace # and suffixlen=0 returns nothing if used in the substr directly # and generate a full path from the template my $path = _replace_XX($template, $options{"suffixlen"}); # Split the path into constituent parts - eventually we need to check # whether the directory exists # We need to know whether we are making a temp directory # or a tempfile my ($volume, $directories, $file); my $parent; # parent directory if ($options{"mkdir"}) { # There is no filename at the end ($volume, $directories, $file) = File::Spec->splitpath( $path, 1); # The parent is then $directories without the last directory # Split the directory and put it back together again my @dirs = File::Spec->splitdir($directories); # If @dirs only has one entry (i.e. the directory template) that means # we are in the current directory if ($#dirs == 0) { $parent = File::Spec->curdir; } else { if ($^O eq 'VMS') { # need volume to avoid relative dir spec $parent = File::Spec->catdir($volume, @dirs[0..$#dirs-1]); $parent = 'sys$disk:[]' if $parent eq ''; } else { # Put it back together without the last one $parent = File::Spec->catdir(@dirs[0..$#dirs-1]); # ...and attach the volume (no filename) $parent = File::Spec->catpath($volume, $parent, ''); } } } else { # Get rid of the last filename (use File::Basename for this?) ($volume, $directories, $file) = File::Spec->splitpath( $path ); # Join up without the file part $parent = File::Spec->catpath($volume,$directories,''); # If $parent is empty replace with curdir $parent = File::Spec->curdir unless $directories ne ''; } # Check that the parent directories exist # Do this even for the case where we are simply returning a name # not a file -- no point returning a name that includes a directory # that does not exist or is not writable unless (-d $parent) { ${$options{ErrStr}} = "Parent directory ($parent) is not a directory"; return (); } unless (-w $parent) { ${$options{ErrStr}} = "Parent directory ($parent) is not writable\n"; return (); } # Check the stickiness of the directory and chown giveaway if required # If the directory is world writable the sticky bit # must be set if (File::Temp->safe_level == MEDIUM) { my $safeerr; unless (_is_safe($parent,\$safeerr)) { ${$options{ErrStr}} = "Parent directory ($parent) is not safe ($safeerr)"; return (); } } elsif (File::Temp->safe_level == HIGH) { my $safeerr; unless (_is_verysafe($parent, \$safeerr)) { ${$options{ErrStr}} = "Parent directory ($parent) is not safe ($safeerr)"; return (); } } # Now try MAX_TRIES time to open the file for (my $i = 0; $i < MAX_TRIES; $i++) { # Try to open the file if requested if ($options{"open"}) { my $fh; # If we are running before perl5.6.0 we can not auto-vivify if ($] < 5.006) { $fh = &Symbol::gensym; } # Try to make sure this will be marked close-on-exec # XXX: Win32 doesn't respect this, nor the proper fcntl, # but may have O_NOINHERIT. This may or may not be in Fcntl. local $^F = 2; # Store callers umask my $umask = umask(); # Set a known umask umask(066); # Attempt to open the file my $open_success = undef; if ( $^O eq 'VMS' and $options{"unlink_on_close"} && !$KEEP_ALL) { # make it auto delete on close by setting FAB$V_DLT bit $fh = VMS::Stdio::vmssysopen($path, $OPENFLAGS, 0600, 'fop=dlt'); $open_success = $fh; } else { my $flags = ( ($options{"unlink_on_close"} && !$KEEP_ALL) ? $OPENTEMPFLAGS : $OPENFLAGS ); $open_success = sysopen($fh, $path, $flags, 0600); } if ( $open_success ) { # Reset umask umask($umask) if defined $umask; # Opened successfully - return file handle and name return ($fh, $path); } else { # Reset umask umask($umask) if defined $umask; # Error opening file - abort with error # if the reason was anything but EEXIST unless ($!{EEXIST}) { ${$options{ErrStr}} = "Could not create temp file $path: $!"; return (); } # Loop round for another try } } elsif ($options{"mkdir"}) { # Store callers umask my $umask = umask(); # Set a known umask umask(066); # Open the temp directory if (mkdir( $path, 0700)) { # created okay # Reset umask umask($umask) if defined $umask; return undef, $path; } else { # Reset umask umask($umask) if defined $umask; # Abort with error if the reason for failure was anything # except EEXIST unless ($!{EEXIST}) { ${$options{ErrStr}} = "Could not create directory $path: $!"; return (); } # Loop round for another try } } else { # Return true if the file can not be found # Directory has been checked previously return (undef, $path) unless -e $path; # Try again until MAX_TRIES } # Did not successfully open the tempfile/dir # so try again with a different set of random letters # No point in trying to increment unless we have only # 1 X say and the randomness could come up with the same # file MAX_TRIES in a row. # Store current attempt - in principal this implies that the # 3rd time around the open attempt that the first temp file # name could be generated again. Probably should store each # attempt and make sure that none are repeated my $original = $path; my $counter = 0; # Stop infinite loop my $MAX_GUESS = 50; do { # Generate new name from original template $path = _replace_XX($template, $options{"suffixlen"}); $counter++; } until ($path ne $original || $counter > $MAX_GUESS); # Check for out of control looping if ($counter > $MAX_GUESS) { ${$options{ErrStr}} = "Tried to get a new temp name different to the previous value $MAX_GUESS times.\nSomething wrong with template?? ($template)"; return (); } } # If we get here, we have run out of tries ${ $options{ErrStr} } = "Have exceeded the maximum number of attempts (" . MAX_TRIES . ") to open temp file/dir"; return (); } # Internal routine to return a random character from the # character list. Does not do an srand() since rand() # will do one automatically # No arguments. Return value is the random character # No longer called since _replace_XX runs a few percent faster if # I inline the code. This is important if we are creating thousands of # temporary files. sub _randchar { $CHARS[ int( rand( $#CHARS ) ) ]; } # Internal routine to replace the XXXX... with random characters # This has to be done by _gettemp() every time it fails to # open a temp file/dir # Arguments: $template (the template with XXX), # $ignore (number of characters at end to ignore) # Returns: modified template sub _replace_XX { croak 'Usage: _replace_XX($template, $ignore)' unless scalar(@_) == 2; my ($path, $ignore) = @_; # Do it as an if, since the suffix adjusts which section to replace # and suffixlen=0 returns nothing if used in the substr directly # Alternatively, could simply set $ignore to length($path)-1 # Don't want to always use substr when not required though. if ($ignore) { substr($path, 0, - $ignore) =~ s/X(?=X*\z)/$CHARS[ int( rand( $#CHARS ) ) ]/ge; } else { $path =~ s/X(?=X*\z)/$CHARS[ int( rand( $#CHARS ) ) ]/ge; } return $path; } # Internal routine to force a temp file to be writable after # it is created so that we can unlink it. Windows seems to occassionally # force a file to be readonly when written to certain temp locations sub _force_writable { my $file = shift; my $umask = umask(); umask(066); chmod 0600, $file; umask($umask) if defined $umask; } # internal routine to check to see if the directory is safe # First checks to see if the directory is not owned by the # current user or root. Then checks to see if anyone else # can write to the directory and if so, checks to see if # it has the sticky bit set # Will not work on systems that do not support sticky bit #Args: directory path to check # Optionally: reference to scalar to contain error message # Returns true if the path is safe and false otherwise. # Returns undef if can not even run stat() on the path # This routine based on version written by Tom Christiansen # Presumably, by the time we actually attempt to create the # file or directory in this directory, it may not be safe # anymore... Have to run _is_safe directly after the open. sub _is_safe { my $path = shift; my $err_ref = shift; # Stat path my @info = stat($path); unless (scalar(@info)) { $$err_ref = "stat(path) returned no values"; return 0; }; return 1 if $^O eq 'VMS'; # owner delete control at file level # Check to see whether owner is neither superuser (or a system uid) nor me # Use the real uid from the $< variable # UID is in [4] if ($info[4] > File::Temp->top_system_uid() && $info[4] != $<) { Carp::cluck(sprintf "uid=$info[4] topuid=%s \$<=$< path='$path'", File::Temp->top_system_uid()); $$err_ref = "Directory owned neither by root nor the current user" if ref($err_ref); return 0; } # check whether group or other can write file # use 066 to detect either reading or writing # use 022 to check writability # Do it with S_IWOTH and S_IWGRP for portability (maybe) # mode is in info[2] if (($info[2] & &Fcntl::S_IWGRP) || # Is group writable? ($info[2] & &Fcntl::S_IWOTH) ) { # Is world writable? # Must be a directory unless (-d $path) { $$err_ref = "Path ($path) is not a directory" if ref($err_ref); return 0; } # Must have sticky bit set unless (-k $path) { $$err_ref = "Sticky bit not set on $path when dir is group|world writable" if ref($err_ref); return 0; } } return 1; } # Internal routine to check whether a directory is safe # for temp files. Safer than _is_safe since it checks for # the possibility of chown giveaway and if that is a possibility # checks each directory in the path to see if it is safe (with _is_safe) # If _PC_CHOWN_RESTRICTED is not set, does the full test of each # directory anyway. # Takes optional second arg as scalar ref to error reason sub _is_verysafe { # Need POSIX - but only want to bother if really necessary due to overhead require POSIX; my $path = shift; print "_is_verysafe testing $path\n" if $DEBUG; return 1 if $^O eq 'VMS'; # owner delete control at file level my $err_ref = shift; # Should Get the value of _PC_CHOWN_RESTRICTED if it is defined # and If it is not there do the extensive test my $chown_restricted; $chown_restricted = &POSIX::_PC_CHOWN_RESTRICTED() if eval { &POSIX::_PC_CHOWN_RESTRICTED(); 1}; # If chown_resticted is set to some value we should test it if (defined $chown_restricted) { # Return if the current directory is safe return _is_safe($path,$err_ref) if POSIX::sysconf( $chown_restricted ); } # To reach this point either, the _PC_CHOWN_RESTRICTED symbol # was not avialable or the symbol was there but chown giveaway # is allowed. Either way, we now have to test the entire tree for # safety. # Convert path to an absolute directory if required unless (File::Spec->file_name_is_absolute($path)) { $path = File::Spec->rel2abs($path); } # Split directory into components - assume no file my ($volume, $directories, undef) = File::Spec->splitpath( $path, 1); # Slightly less efficient than having a function in File::Spec # to chop off the end of a directory or even a function that # can handle ../ in a directory tree # Sometimes splitdir() returns a blank at the end # so we will probably check the bottom directory twice in some cases my @dirs = File::Spec->splitdir($directories); # Concatenate one less directory each time around foreach my $pos (0.. $#dirs) { # Get a directory name my $dir = File::Spec->catpath($volume, File::Spec->catdir(@dirs[0.. $#dirs - $pos]), '' ); print "TESTING DIR $dir\n" if $DEBUG; # Check the directory return 0 unless _is_safe($dir,$err_ref); } return 1; } # internal routine to determine whether unlink works on this # platform for files that are currently open. # Returns true if we can, false otherwise. # Currently WinNT, OS/2 and VMS can not unlink an opened file # On VMS this is because the O_EXCL flag is used to open the # temporary file. Currently I do not know enough about the issues # on VMS to decide whether O_EXCL is a requirement. sub _can_unlink_opened_file { if ($^O eq 'MSWin32' || $^O eq 'os2' || $^O eq 'VMS' || $^O eq 'dos' || $^O eq 'MacOS') { return 0; } else { return 1; } } # internal routine to decide which security levels are allowed # see safe_level() for more information on this # Controls whether the supplied security level is allowed # $cando = _can_do_level( $level ) sub _can_do_level { # Get security level my $level = shift; # Always have to be able to do STANDARD return 1 if $level == STANDARD; # Currently, the systems that can do HIGH or MEDIUM are identical if ( $^O eq 'MSWin32' || $^O eq 'os2' || $^O eq 'cygwin' || $^O eq 'dos' || $^O eq 'MacOS' || $^O eq 'mpeix') { return 0; } else { return 1; } } # This routine sets up a deferred unlinking of a specified # filename and filehandle. It is used in the following cases: # - Called by unlink0 if an opened file can not be unlinked # - Called by tempfile() if files are to be removed on shutdown # - Called by tempdir() if directories are to be removed on shutdown # Arguments: # _deferred_unlink( $fh, $fname, $isdir ); # # - filehandle (so that it can be expclicitly closed if open # - filename (the thing we want to remove) # - isdir (flag to indicate that we are being given a directory) # [and hence no filehandle] # Status is not referred to since all the magic is done with an END block { # Will set up two lexical variables to contain all the files to be # removed. One array for files, another for directories They will # only exist in this block. # This means we only have to set up a single END block to remove # all files. # in order to prevent child processes inadvertently deleting the parent # temp files we use a hash to store the temp files and directories # created by a particular process id. # %files_to_unlink contains values that are references to an array of # array references containing the filehandle and filename associated with # the temp file. my (%files_to_unlink, %dirs_to_unlink); # Set up an end block to use these arrays END { cleanup(); } # Cleanup function. Always triggered on END but can be invoked # manually. sub cleanup { if (!$KEEP_ALL) { # Files my @files = (exists $files_to_unlink{$$} ? @{ $files_to_unlink{$$} } : () ); foreach my $file (@files) { # close the filehandle without checking its state # in order to make real sure that this is closed # if its already closed then I dont care about the answer # probably a better way to do this close($file->[0]); # file handle is [0] if (-f $file->[1]) { # file name is [1] _force_writable( $file->[1] ); # for windows unlink $file->[1] or warn "Error removing ".$file->[1]; } } # Dirs my @dirs = (exists $dirs_to_unlink{$$} ? @{ $dirs_to_unlink{$$} } : () ); foreach my $dir (@dirs) { if (-d $dir) { rmtree($dir, $DEBUG, 0); } } # clear the arrays @{ $files_to_unlink{$$} } = () if exists $files_to_unlink{$$}; @{ $dirs_to_unlink{$$} } = () if exists $dirs_to_unlink{$$}; } } # This is the sub called to register a file for deferred unlinking # This could simply store the input parameters and defer everything # until the END block. For now we do a bit of checking at this # point in order to make sure that (1) we have a file/dir to delete # and (2) we have been called with the correct arguments. sub _deferred_unlink { croak 'Usage: _deferred_unlink($fh, $fname, $isdir)' unless scalar(@_) == 3; my ($fh, $fname, $isdir) = @_; warn "Setting up deferred removal of $fname\n" if $DEBUG; # If we have a directory, check that it is a directory if ($isdir) { if (-d $fname) { # Directory exists so store it # first on VMS turn []foo into [.foo] for rmtree $fname = VMS::Filespec::vmspath($fname) if $^O eq 'VMS'; $dirs_to_unlink{$$} = [] unless exists $dirs_to_unlink{$$}; push (@{ $dirs_to_unlink{$$} }, $fname); } else { carp "Request to remove directory $fname could not be completed since it does not exist!\n" if $^W; } } else { if (-f $fname) { # file exists so store handle and name for later removal $files_to_unlink{$$} = [] unless exists $files_to_unlink{$$}; push(@{ $files_to_unlink{$$} }, [$fh, $fname]); } else { carp "Request to remove file $fname could not be completed since it is not there!\n" if $^W; } } } } =head1 OBJECT-ORIENTED INTERFACE This is the primary interface for interacting with C. Using the OO interface a temporary file can be created when the object is constructed and the file can be removed when the object is no longer required. Note that there is no method to obtain the filehandle from the C object. The object itself acts as a filehandle. Also, the object is configured such that it stringifies to the name of the temporary file. =over 4 =item B Create a temporary file object. my $tmp = new File::Temp(); by default the object is constructed as if C was called without options, but with the additional behaviour that the temporary file is removed by the object destructor if UNLINK is set to true (the default). Supported arguments are the same as for C: UNLINK (defaulting to true), DIR and SUFFIX. Additionally, the filename template is specified using the TEMPLATE option. The OPEN option is not supported (the file is always opened). $tmp = new File::Temp( TEMPLATE => 'tempXXXXX', DIR => 'mydir', SUFFIX => '.dat'); Arguments are case insensitive. =cut sub new { my $proto = shift; my $class = ref($proto) || $proto; # read arguments and convert keys to upper case my %args = @_; %args = map { uc($_), $args{$_} } keys %args; # see if they are unlinking (defaulting to yes) my $unlink = (exists $args{UNLINK} ? $args{UNLINK} : 1 ); delete $args{UNLINK}; # template (store it in an error so that it will # disappear from the arg list of tempfile my @template = ( exists $args{TEMPLATE} ? $args{TEMPLATE} : () ); delete $args{TEMPLATE}; # Protect OPEN delete $args{OPEN}; # Open the file and retain file handle and file name my ($fh, $path) = tempfile( @template, %args ); print "Tmp: $fh - $path\n" if $DEBUG; # Store the filename in the scalar slot ${*$fh} = $path; # Store unlink information in hash slot (plus other constructor info) %{*$fh} = %args; # create the object bless $fh, $class; # final method-based configuration $fh->unlink_on_destroy( $unlink ); return $fh; } =item B Return the name of the temporary file associated with this object. $filename = $tmp->filename; This method is called automatically when the object is used as a string. =cut sub filename { my $self = shift; return ${*$self}; } sub STRINGIFY { my $self = shift; return $self->filename; } =item B Control whether the file is unlinked when the object goes out of scope. The file is removed if this value is true and $KEEP_ALL is not. $fh->unlink_on_destroy( 1 ); Default is for the file to be removed. =cut sub unlink_on_destroy { my $self = shift; if (@_) { ${*$self}{UNLINK} = shift; } return ${*$self}{UNLINK}; } =item B When the object goes out of scope, the destructor is called. This destructor will attempt to unlink the file (using C) if the constructor was called with UNLINK set to 1 (the default state if UNLINK is not specified). No error is given if the unlink fails. If the global variable $KEEP_ALL is true, the file will not be removed. =cut sub DESTROY { my $self = shift; if (${*$self}{UNLINK} && !$KEEP_ALL) { print "# ---------> Unlinking $self\n" if $DEBUG; # The unlink1 may fail if the file has been closed # by the caller. This leaves us with the decision # of whether to refuse to remove the file or simply # do an unlink without test. Seems to be silly # to do this when we are trying to be careful # about security _force_writable( $self->filename ); # for windows unlink1( $self, $self->filename ) or unlink($self->filename); } } =back =head1 FUNCTIONS This section describes the recommended interface for generating temporary files and directories. =over 4 =item B This is the basic function to generate temporary files. The behaviour of the file can be changed using various options: $fh = tempfile(); ($fh, $filename) = tempfile(); Create a temporary file in the directory specified for temporary files, as specified by the tmpdir() function in L. ($fh, $filename) = tempfile($template); Create a temporary file in the current directory using the supplied template. Trailing `X' characters are replaced with random letters to generate the filename. At least four `X' characters must be present at the end of the template. ($fh, $filename) = tempfile($template, SUFFIX => $suffix) Same as previously, except that a suffix is added to the template after the `X' translation. Useful for ensuring that a temporary filename has a particular extension when needed by other applications. But see the WARNING at the end. ($fh, $filename) = tempfile($template, DIR => $dir); Translates the template as before except that a directory name is specified. ($fh, $filename) = tempfile($template, UNLINK => 1); Return the filename and filehandle as before except that the file is automatically removed when the program exits (dependent on $KEEP_ALL). Default is for the file to be removed if a file handle is requested and to be kept if the filename is requested. In a scalar context (where no filename is returned) the file is always deleted either (depending on the operating system) on exit or when it is closed (unless $KEEP_ALL is true when the temp file is created). Use the object-oriented interface if fine-grained control of when a file is removed is required. If the template is not specified, a template is always automatically generated. This temporary file is placed in tmpdir() (L) unless a directory is specified explicitly with the DIR option. $fh = tempfile( $template, DIR => $dir ); If called in scalar context, only the filehandle is returned and the file will automatically be deleted when closed on operating systems that support this (see the description of tmpfile() elsewhere in this document). This is the preferred mode of operation, as if you only have a filehandle, you can never create a race condition by fumbling with the filename. On systems that can not unlink an open file or can not mark a file as temporary when it is opened (for example, Windows NT uses the C flag) the file is marked for deletion when the program ends (equivalent to setting UNLINK to 1). The C flag is ignored if present. (undef, $filename) = tempfile($template, OPEN => 0); This will return the filename based on the template but will not open this file. Cannot be used in conjunction with UNLINK set to true. Default is to always open the file to protect from possible race conditions. A warning is issued if warnings are turned on. Consider using the tmpnam() and mktemp() functions described elsewhere in this document if opening the file is not required. Options can be combined as required. =cut sub tempfile { # Can not check for argument count since we can have any # number of args # Default options my %options = ( "DIR" => undef, # Directory prefix "SUFFIX" => '', # Template suffix "UNLINK" => 0, # Do not unlink file on exit "OPEN" => 1, # Open file ); # Check to see whether we have an odd or even number of arguments my $template = (scalar(@_) % 2 == 1 ? shift(@_) : undef); # Read the options and merge with defaults %options = (%options, @_) if @_; # First decision is whether or not to open the file if (! $options{"OPEN"}) { warn "tempfile(): temporary filename requested but not opened.\nPossibly unsafe, consider using tempfile() with OPEN set to true\n" if $^W; } if ($options{"DIR"} and $^O eq 'VMS') { # on VMS turn []foo into [.foo] for concatenation $options{"DIR"} = VMS::Filespec::vmspath($options{"DIR"}); } # Construct the template # Have a choice of trying to work around the mkstemp/mktemp/tmpnam etc # functions or simply constructing a template and using _gettemp() # explicitly. Go for the latter # First generate a template if not defined and prefix the directory # If no template must prefix the temp directory if (defined $template) { if ($options{"DIR"}) { $template = File::Spec->catfile($options{"DIR"}, $template); } } else { if ($options{"DIR"}) { $template = File::Spec->catfile($options{"DIR"}, TEMPXXX); } else { $template = File::Spec->catfile(File::Spec->tmpdir, TEMPXXX); } } # Now add a suffix $template .= $options{"SUFFIX"}; # Determine whether we should tell _gettemp to unlink the file # On unix this is irrelevant and can be worked out after the file is # opened (simply by unlinking the open filehandle). On Windows or VMS # we have to indicate temporary-ness when we open the file. In general # we only want a true temporary file if we are returning just the # filehandle - if the user wants the filename they probably do not # want the file to disappear as soon as they close it (which may be # important if they want a child process to use the file) # For this reason, tie unlink_on_close to the return context regardless # of OS. my $unlink_on_close = ( wantarray ? 0 : 1); # Create the file my ($fh, $path, $errstr); croak "Error in tempfile() using $template: $errstr" unless (($fh, $path) = _gettemp($template, "open" => $options{'OPEN'}, "mkdir"=> 0 , "unlink_on_close" => $unlink_on_close, "suffixlen" => length($options{'SUFFIX'}), "ErrStr" => \$errstr, ) ); # Set up an exit handler that can do whatever is right for the # system. This removes files at exit when requested explicitly or when # system is asked to unlink_on_close but is unable to do so because # of OS limitations. # The latter should be achieved by using a tied filehandle. # Do not check return status since this is all done with END blocks. _deferred_unlink($fh, $path, 0) if $options{"UNLINK"}; # Return if (wantarray()) { if ($options{'OPEN'}) { return ($fh, $path); } else { return (undef, $path); } } else { # Unlink the file. It is up to unlink0 to decide what to do with # this (whether to unlink now or to defer until later) unlink0($fh, $path) or croak "Error unlinking file $path using unlink0"; # Return just the filehandle. return $fh; } } =item B This is the recommended interface for creation of temporary directories. The behaviour of the function depends on the arguments: $tempdir = tempdir(); Create a directory in tmpdir() (see L). $tempdir = tempdir( $template ); Create a directory from the supplied template. This template is similar to that described for tempfile(). `X' characters at the end of the template are replaced with random letters to construct the directory name. At least four `X' characters must be in the template. $tempdir = tempdir ( DIR => $dir ); Specifies the directory to use for the temporary directory. The temporary directory name is derived from an internal template. $tempdir = tempdir ( $template, DIR => $dir ); Prepend the supplied directory name to the template. The template should not include parent directory specifications itself. Any parent directory specifications are removed from the template before prepending the supplied directory. $tempdir = tempdir ( $template, TMPDIR => 1 ); Using the supplied template, create the temporary directory in a standard location for temporary files. Equivalent to doing $tempdir = tempdir ( $template, DIR => File::Spec->tmpdir); but shorter. Parent directory specifications are stripped from the template itself. The C option is ignored if C is set explicitly. Additionally, C is implied if neither a template nor a directory are supplied. $tempdir = tempdir( $template, CLEANUP => 1); Create a temporary directory using the supplied template, but attempt to remove it (and all files inside it) when the program exits. Note that an attempt will be made to remove all files from the directory even if they were not created by this module (otherwise why ask to clean it up?). The directory removal is made with the rmtree() function from the L module. Of course, if the template is not specified, the temporary directory will be created in tmpdir() and will also be removed at program exit. =cut # ' sub tempdir { # Can not check for argument count since we can have any # number of args # Default options my %options = ( "CLEANUP" => 0, # Remove directory on exit "DIR" => '', # Root directory "TMPDIR" => 0, # Use tempdir with template ); # Check to see whether we have an odd or even number of arguments my $template = (scalar(@_) % 2 == 1 ? shift(@_) : undef ); # Read the options and merge with defaults %options = (%options, @_) if @_; # Modify or generate the template # Deal with the DIR and TMPDIR options if (defined $template) { # Need to strip directory path if using DIR or TMPDIR if ($options{'TMPDIR'} || $options{'DIR'}) { # Strip parent directory from the filename # # There is no filename at the end $template = VMS::Filespec::vmspath($template) if $^O eq 'VMS'; my ($volume, $directories, undef) = File::Spec->splitpath( $template, 1); # Last directory is then our template $template = (File::Spec->splitdir($directories))[-1]; # Prepend the supplied directory or temp dir if ($options{"DIR"}) { $template = File::Spec->catdir($options{"DIR"}, $template); } elsif ($options{TMPDIR}) { # Prepend tmpdir $template = File::Spec->catdir(File::Spec->tmpdir, $template); } } } else { if ($options{"DIR"}) { $template = File::Spec->catdir($options{"DIR"}, TEMPXXX); } else { $template = File::Spec->catdir(File::Spec->tmpdir, TEMPXXX); } } # Create the directory my $tempdir; my $suffixlen = 0; if ($^O eq 'VMS') { # dir names can end in delimiters $template =~ m/([\.\]:>]+)$/; $suffixlen = length($1); } if ( ($^O eq 'MacOS') && (substr($template, -1) eq ':') ) { # dir name has a trailing ':' ++$suffixlen; } my $errstr; croak "Error in tempdir() using $template: $errstr" unless ((undef, $tempdir) = _gettemp($template, "open" => 0, "mkdir"=> 1 , "suffixlen" => $suffixlen, "ErrStr" => \$errstr, ) ); # Install exit handler; must be dynamic to get lexical if ( $options{'CLEANUP'} && -d $tempdir) { _deferred_unlink(undef, $tempdir, 1); } # Return the dir name return $tempdir; } =back =head1 MKTEMP FUNCTIONS The following functions are Perl implementations of the mktemp() family of temp file generation system calls. =over 4 =item B Given a template, returns a filehandle to the temporary file and the name of the file. ($fh, $name) = mkstemp( $template ); In scalar context, just the filehandle is returned. The template may be any filename with some number of X's appended to it, for example F. The trailing X's are replaced with unique alphanumeric combinations. =cut sub mkstemp { croak "Usage: mkstemp(template)" if scalar(@_) != 1; my $template = shift; my ($fh, $path, $errstr); croak "Error in mkstemp using $template: $errstr" unless (($fh, $path) = _gettemp($template, "open" => 1, "mkdir"=> 0 , "suffixlen" => 0, "ErrStr" => \$errstr, ) ); if (wantarray()) { return ($fh, $path); } else { return $fh; } } =item B Similar to mkstemp(), except that an extra argument can be supplied with a suffix to be appended to the template. ($fh, $name) = mkstemps( $template, $suffix ); For example a template of C and suffix of C<.dat> would generate a file similar to F. Returns just the filehandle alone when called in scalar context. =cut sub mkstemps { croak "Usage: mkstemps(template, suffix)" if scalar(@_) != 2; my $template = shift; my $suffix = shift; $template .= $suffix; my ($fh, $path, $errstr); croak "Error in mkstemps using $template: $errstr" unless (($fh, $path) = _gettemp($template, "open" => 1, "mkdir"=> 0 , "suffixlen" => length($suffix), "ErrStr" => \$errstr, ) ); if (wantarray()) { return ($fh, $path); } else { return $fh; } } =item B Create a directory from a template. The template must end in X's that are replaced by the routine. $tmpdir_name = mkdtemp($template); Returns the name of the temporary directory created. Returns undef on failure. Directory must be removed by the caller. =cut #' # for emacs sub mkdtemp { croak "Usage: mkdtemp(template)" if scalar(@_) != 1; my $template = shift; my $suffixlen = 0; if ($^O eq 'VMS') { # dir names can end in delimiters $template =~ m/([\.\]:>]+)$/; $suffixlen = length($1); } if ( ($^O eq 'MacOS') && (substr($template, -1) eq ':') ) { # dir name has a trailing ':' ++$suffixlen; } my ($junk, $tmpdir, $errstr); croak "Error creating temp directory from template $template\: $errstr" unless (($junk, $tmpdir) = _gettemp($template, "open" => 0, "mkdir"=> 1 , "suffixlen" => $suffixlen, "ErrStr" => \$errstr, ) ); return $tmpdir; } =item B Returns a valid temporary filename but does not guarantee that the file will not be opened by someone else. $unopened_file = mktemp($template); Template is the same as that required by mkstemp(). =cut sub mktemp { croak "Usage: mktemp(template)" if scalar(@_) != 1; my $template = shift; my ($tmpname, $junk, $errstr); croak "Error getting name to temp file from template $template: $errstr" unless (($junk, $tmpname) = _gettemp($template, "open" => 0, "mkdir"=> 0 , "suffixlen" => 0, "ErrStr" => \$errstr, ) ); return $tmpname; } =back =head1 POSIX FUNCTIONS This section describes the re-implementation of the tmpnam() and tmpfile() functions described in L using the mkstemp() from this module. Unlike the L implementations, the directory used for the temporary file is not specified in a system include file (C) but simply depends on the choice of tmpdir() returned by L. On some implementations this location can be set using the C environment variable, which may not be secure. If this is a problem, simply use mkstemp() and specify a template. =over 4 =item B When called in scalar context, returns the full name (including path) of a temporary file (uses mktemp()). The only check is that the file does not already exist, but there is no guarantee that that condition will continue to apply. $file = tmpnam(); When called in list context, a filehandle to the open file and a filename are returned. This is achieved by calling mkstemp() after constructing a suitable template. ($fh, $file) = tmpnam(); If possible, this form should be used to prevent possible race conditions. See L for information on the choice of temporary directory for a particular operating system. =cut sub tmpnam { # Retrieve the temporary directory name my $tmpdir = File::Spec->tmpdir; croak "Error temporary directory is not writable" if $tmpdir eq ''; # Use a ten character template and append to tmpdir my $template = File::Spec->catfile($tmpdir, TEMPXXX); if (wantarray() ) { return mkstemp($template); } else { return mktemp($template); } } =item B Returns the filehandle of a temporary file. $fh = tmpfile(); The file is removed when the filehandle is closed or when the program exits. No access to the filename is provided. If the temporary file can not be created undef is returned. Currently this command will probably not work when the temporary directory is on an NFS file system. =cut sub tmpfile { # Simply call tmpnam() in a list context my ($fh, $file) = tmpnam(); # Make sure file is removed when filehandle is closed # This will fail on NFS unlink0($fh, $file) or return undef; return $fh; } =back =head1 ADDITIONAL FUNCTIONS These functions are provided for backwards compatibility with common tempfile generation C library functions. They are not exported and must be addressed using the full package name. =over 4 =item B Return the name of a temporary file in the specified directory using a prefix. The file is guaranteed not to exist at the time the function was called, but such guarantees are good for one clock tick only. Always use the proper form of C with C if you must open such a filename. $filename = File::Temp::tempnam( $dir, $prefix ); Equivalent to running mktemp() with $dir/$prefixXXXXXXXX (using unix file convention as an example) Because this function uses mktemp(), it can suffer from race conditions. =cut sub tempnam { croak 'Usage tempnam($dir, $prefix)' unless scalar(@_) == 2; my ($dir, $prefix) = @_; # Add a string to the prefix $prefix .= 'XXXXXXXX'; # Concatenate the directory to the file my $template = File::Spec->catfile($dir, $prefix); return mktemp($template); } =back =head1 UTILITY FUNCTIONS Useful functions for dealing with the filehandle and filename. =over 4 =item B Given an open filehandle and the associated filename, make a safe unlink. This is achieved by first checking that the filename and filehandle initially point to the same file and that the number of links to the file is 1 (all fields returned by stat() are compared). Then the filename is unlinked and the filehandle checked once again to verify that the number of links on that file is now 0. This is the closest you can come to making sure that the filename unlinked was the same as the file whose descriptor you hold. unlink0($fh, $path) or die "Error unlinking file $path safely"; Returns false on error. The filehandle is not closed since on some occasions this is not required. On some platforms, for example Windows NT, it is not possible to unlink an open file (the file must be closed first). On those platforms, the actual unlinking is deferred until the program ends and good status is returned. A check is still performed to make sure that the filehandle and filename are pointing to the same thing (but not at the time the end block is executed since the deferred removal may not have access to the filehandle). Additionally, on Windows NT not all the fields returned by stat() can be compared. For example, the C and C fields seem to be different. Also, it seems that the size of the file returned by stat() does not always agree, with C being more accurate than C, presumably because of caching issues even when using autoflush (this is usually overcome by waiting a while after writing to the tempfile before attempting to C it). Finally, on NFS file systems the link count of the file handle does not always go to zero immediately after unlinking. Currently, this command is expected to fail on NFS disks. This function is disabled if the global variable $KEEP_ALL is true and an unlink on open file is supported. If the unlink is to be deferred to the END block, the file is still registered for removal. =cut sub unlink0 { croak 'Usage: unlink0(filehandle, filename)' unless scalar(@_) == 2; # Read args my ($fh, $path) = @_; cmpstat($fh, $path) or return 0; # attempt remove the file (does not work on some platforms) if (_can_unlink_opened_file()) { # return early (Without unlink) if we have been instructed to retain files. return 1 if $KEEP_ALL; # XXX: do *not* call this on a directory; possible race # resulting in recursive removal croak "unlink0: $path has become a directory!" if -d $path; unlink($path) or return 0; # Stat the filehandle my @fh = stat $fh; print "Link count = $fh[3] \n" if $DEBUG; # Make sure that the link count is zero # - Cygwin provides deferred unlinking, however, # on Win9x the link count remains 1 # On NFS the link count may still be 1 but we cant know that # we are on NFS return ( $fh[3] == 0 or $^O eq 'cygwin' ? 1 : 0); } else { _deferred_unlink($fh, $path, 0); return 1; } } =item B Compare C of filehandle with C of provided filename. This can be used to check that the filename and filehandle initially point to the same file and that the number of links to the file is 1 (all fields returned by stat() are compared). cmpstat($fh, $path) or die "Error comparing handle with file"; Returns false if the stat information differs or if the link count is greater than 1. On certain platofms, eg Windows, not all the fields returned by stat() can be compared. For example, the C and C fields seem to be different in Windows. Also, it seems that the size of the file returned by stat() does not always agree, with C being more accurate than C, presumably because of caching issues even when using autoflush (this is usually overcome by waiting a while after writing to the tempfile before attempting to C it). Not exported by default. =cut sub cmpstat { croak 'Usage: cmpstat(filehandle, filename)' unless scalar(@_) == 2; # Read args my ($fh, $path) = @_; warn "Comparing stat\n" if $DEBUG; # Stat the filehandle - which may be closed if someone has manually # closed the file. Can not turn off warnings without using $^W # unless we upgrade to 5.006 minimum requirement my @fh; { local ($^W) = 0; @fh = stat $fh; } return unless @fh; if ($fh[3] > 1 && $^W) { carp "unlink0: fstat found too many links; SB=@fh" if $^W; } # Stat the path my @path = stat $path; unless (@path) { carp "unlink0: $path is gone already" if $^W; return; } # this is no longer a file, but may be a directory, or worse unless (-f $path) { confess "panic: $path is no longer a file: SB=@fh"; } # Do comparison of each member of the array # On WinNT dev and rdev seem to be different # depending on whether it is a file or a handle. # Cannot simply compare all members of the stat return # Select the ones we can use my @okstat = (0..$#fh); # Use all by default if ($^O eq 'MSWin32') { @okstat = (1,2,3,4,5,7,8,9,10); } elsif ($^O eq 'os2') { @okstat = (0, 2..$#fh); } elsif ($^O eq 'VMS') { # device and file ID are sufficient @okstat = (0, 1); } elsif ($^O eq 'dos') { @okstat = (0,2..7,11..$#fh); } elsif ($^O eq 'mpeix') { @okstat = (0..4,8..10); } # Now compare each entry explicitly by number for (@okstat) { print "Comparing: $_ : $fh[$_] and $path[$_]\n" if $DEBUG; # Use eq rather than == since rdev, blksize, and blocks (6, 11, # and 12) will be '' on platforms that do not support them. This # is fine since we are only comparing integers. unless ($fh[$_] eq $path[$_]) { warn "Did not match $_ element of stat\n" if $DEBUG; return 0; } } return 1; } =item B Similar to C except after file comparison using cmpstat, the filehandle is closed prior to attempting to unlink the file. This allows the file to be removed without using an END block, but does mean that the post-unlink comparison of the filehandle state provided by C is not available. unlink1($fh, $path) or die "Error closing and unlinking file"; Usually called from the object destructor when using the OO interface. Not exported by default. This function is disabled if the global variable $KEEP_ALL is true. =cut sub unlink1 { croak 'Usage: unlink1(filehandle, filename)' unless scalar(@_) == 2; # Read args my ($fh, $path) = @_; cmpstat($fh, $path) or return 0; # Close the file close( $fh ) or return 0; # Make sure the file is writable (for windows) _force_writable( $path ); # return early (without unlink) if we have been instructed to retain files. return 1 if $KEEP_ALL; # remove the file return unlink($path); } =item B Calling this function will cause any temp files or temp directories that are registered for removal to be removed. This happens automatically when the process exits but can be triggered manually if the caller is sure that none of the temp files are required. This method can be registered as an Apache callback. On OSes where temp files are automatically removed when the temp file is closed, calling this function will have no effect other than to remove temporary directories (which may include temporary files). File::Temp::cleanup(); Not exported by default. =back =head1 PACKAGE VARIABLES These functions control the global state of the package. =over 4 =item B Controls the lengths to which the module will go to check the safety of the temporary file or directory before proceeding. Options are: =over 8 =item STANDARD Do the basic security measures to ensure the directory exists and is writable, that the umask() is fixed before opening of the file, that temporary files are opened only if they do not already exist, and that possible race conditions are avoided. Finally the L function is used to remove files safely. =item MEDIUM In addition to the STANDARD security, the output directory is checked to make sure that it is owned either by root or the user running the program. If the directory is writable by group or by other, it is then checked to make sure that the sticky bit is set. Will not work on platforms that do not support the C<-k> test for sticky bit. =item HIGH In addition to the MEDIUM security checks, also check for the possibility of ``chown() giveaway'' using the L sysconf() function. If this is a possibility, each directory in the path is checked in turn for safeness, recursively walking back to the root directory. For platforms that do not support the L C<_PC_CHOWN_RESTRICTED> symbol (for example, Windows NT) it is assumed that ``chown() giveaway'' is possible and the recursive test is performed. =back The level can be changed as follows: File::Temp->safe_level( File::Temp::HIGH ); The level constants are not exported by the module. Currently, you must be running at least perl v5.6.0 in order to run with MEDIUM or HIGH security. This is simply because the safety tests use functions from L that are not available in older versions of perl. The problem is that the version number for Fcntl is the same in perl 5.6.0 and in 5.005_03 even though they are different versions. On systems that do not support the HIGH or MEDIUM safety levels (for example Win NT or OS/2) any attempt to change the level will be ignored. The decision to ignore rather than raise an exception allows portable programs to be written with high security in mind for the systems that can support this without those programs failing on systems where the extra tests are irrelevant. If you really need to see whether the change has been accepted simply examine the return value of C. $newlevel = File::Temp->safe_level( File::Temp::HIGH ); die "Could not change to high security" if $newlevel != File::Temp::HIGH; =cut { # protect from using the variable itself my $LEVEL = STANDARD; sub safe_level { my $self = shift; if (@_) { my $level = shift; if (($level != STANDARD) && ($level != MEDIUM) && ($level != HIGH)) { carp "safe_level: Specified level ($level) not STANDARD, MEDIUM or HIGH - ignoring\n" if $^W; } else { # Dont allow this on perl 5.005 or earlier if ($] < 5.006 && $level != STANDARD) { # Cant do MEDIUM or HIGH checks croak "Currently requires perl 5.006 or newer to do the safe checks"; } # Check that we are allowed to change level # Silently ignore if we can not. $LEVEL = $level if _can_do_level($level); } } return $LEVEL; } } =item TopSystemUID This is the highest UID on the current system that refers to a root UID. This is used to make sure that the temporary directory is owned by a system UID (C, C, C etc) rather than simply by root. This is required since on many unix systems C is not owned by root. Default is to assume that any UID less than or equal to 10 is a root UID. File::Temp->top_system_uid(10); my $topid = File::Temp->top_system_uid; This value can be adjusted to reduce security checking if required. The value is only relevant when C is set to MEDIUM or higher. =cut { my $TopSystemUID = 10; $TopSystemUID = 197108 if $^O eq 'interix'; # "Administrator" sub top_system_uid { my $self = shift; if (@_) { my $newuid = shift; croak "top_system_uid: UIDs should be numeric" unless $newuid =~ /^\d+$/s; $TopSystemUID = $newuid; } return $TopSystemUID; } } =item B<$KEEP_ALL> Controls whether temporary files and directories should be retained regardless of any instructions in the program to remove them automatically. This is useful for debugging but should not be used in production code. $File::Temp::KEEP_ALL = 1; Default is for files to be removed as requested by the caller. In some cases, files will only be retained if this variable is true when the file is created. This means that you can not create a temporary file, set this variable and expect the temp file to still be around when the program exits. =item B<$DEBUG> Controls whether debugging messages should be enabled. $File::Temp::DEBUG = 1; Default is for debugging mode to be disabled. =back =head1 WARNING For maximum security, endeavour always to avoid ever looking at, touching, or even imputing the existence of the filename. You do not know that that filename is connected to the same file as the handle you have, and attempts to check this can only trigger more race conditions. It's far more secure to use the filehandle alone and dispense with the filename altogether. If you need to pass the handle to something that expects a filename then, on a unix system, use C<"/dev/fd/" . fileno($fh)> for arbitrary programs, or more generally C<< "+<=&" . fileno($fh) >> for Perl programs. You will have to clear the close-on-exec bit on that file descriptor before passing it to another process. use Fcntl qw/F_SETFD F_GETFD/; fcntl($tmpfh, F_SETFD, 0) or die "Can't clear close-on-exec flag on temp fh: $!\n"; =head2 Temporary files and NFS Some problems are associated with using temporary files that reside on NFS file systems and it is recommended that a local filesystem is used whenever possible. Some of the security tests will most probably fail when the temp file is not local. Additionally, be aware that the performance of I/O operations over NFS will not be as good as for a local disk. =head2 Forking In some cases files created by File::Temp are removed from within an END block. Since END blocks are triggered when a child process exits (unless C is used by the child) File::Temp takes care to only remove those temp files created by a particular process ID. This means that a child will not attempt to remove temp files created by the parent process. =head2 BINMODE The file returned by File::Temp will have been opened in binary mode if such a mode is available. If that is not correct, use the binmode() function to change the mode of the filehandle. =head1 HISTORY Originally began life in May 1999 as an XS interface to the system mkstemp() function. In March 2000, the OpenBSD mkstemp() code was translated to Perl for total control of the code's security checking, to ensure the presence of the function regardless of operating system and to help with portability. The module was shipped as a standard part of perl from v5.6.1. =head1 SEE ALSO L, L, L, L See L and L, L for different implementations of temporary file handling. =head1 AUTHOR Tim Jenness Etjenness@cpan.orgE Copyright (C) 1999-2005 Tim Jenness and the UK Particle Physics and Astronomy Research Council. All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. Original Perl implementation loosely based on the OpenBSD C code for mkstemp(). Thanks to Tom Christiansen for suggesting that this module should be written and providing ideas for code improvements and security enhancements. =cut 1; vdradmin-am-3.6.13/lib/MIME/000077500000000000000000000000001443716113400153045ustar00rootroot00000000000000vdradmin-am-3.6.13/lib/MIME/Base64.pm000066400000000000000000000132371443716113400166740ustar00rootroot00000000000000# # $Id: Base64.pm,v 2.16 2001/02/24 06:28:10 gisle Exp $ package MIME::Base64; =head1 NAME MIME::Base64 - Encoding and decoding of base64 strings =head1 SYNOPSIS use MIME::Base64; $encoded = encode_base64('Aladdin:open sesame'); $decoded = decode_base64($encoded); =head1 DESCRIPTION This module provides functions to encode and decode strings into the Base64 encoding specified in RFC 2045 - I. The Base64 encoding is designed to represent arbitrary sequences of octets in a form that need not be humanly readable. A 65-character subset ([A-Za-z0-9+/=]) of US-ASCII is used, enabling 6 bits to be represented per printable character. The following functions are provided: =over 4 =item encode_base64($str, [$eol]) Encode data by calling the encode_base64() function. The first argument is the string to encode. The second argument is the line ending sequence to use (it is optional and defaults to C<"\n">). The returned encoded string is broken into lines of no more than 76 characters each and it will end with $eol unless it is empty. Pass an empty string as second argument if you do not want the encoded string broken into lines. =item decode_base64($str) Decode a base64 string by calling the decode_base64() function. This function takes a single argument which is the string to decode and returns the decoded data. Any character not part of the 65-character base64 subset set is silently ignored. Characters occuring after a '=' padding character are never decoded. If the length of the string to decode (after ignoring non-base64 chars) is not a multiple of 4 or padding occurs too ealy, then a warning is generated if perl is running under C<-w>. =back If you prefer not to import these routines into your namespace you can call them as: use MIME::Base64 (); $encoded = MIME::Base64::encode($decoded); $decoded = MIME::Base64::decode($encoded); =head1 DIAGNOSTICS The following warnings might be generated if perl is invoked with the C<-w> switch: =over 4 =item Premature end of base64 data The number of characters to decode is not a multiple of 4. Legal base64 data should be padded with one or two "=" characters to make its length a multiple of 4. The decoded result will anyway be as if the padding was there. =item Premature padding of base64 data The '=' padding character occurs as the first or second character in a base64 quartet. =back =head1 EXAMPLES If you want to encode a large file, you should encode it in chunks that are a multiple of 57 bytes. This ensures that the base64 lines line up and that you do not end up with padding in the middle. 57 bytes of data fills one complete base64 line (76 == 57*4/3): use MIME::Base64 qw(encode_base64); open(FILE, "/var/log/wtmp") or die "$!"; while (read(FILE, $buf, 60*57)) { print encode_base64($buf); } or if you know you have enough memory use MIME::Base64 qw(encode_base64); local($/) = undef; # slurp print encode_base64(); The same approach as a command line: perl -MMIME::Base64 -0777 -ne 'print encode_base64($_)' and Joerg Reichelt and code posted to comp.lang.perl <3pd2lp$6gf@wsinti07.win.tue.nl> by Hans Mulder The XS implementation use code from metamail. Copyright 1991 Bell Communications Research, Inc. (Bellcore) =cut use strict; use vars qw(@ISA @EXPORT $VERSION $OLD_CODE); require Exporter; require DynaLoader; @ISA = qw(Exporter DynaLoader); @EXPORT = qw(encode_base64 decode_base64); $VERSION = '2.12'; eval { bootstrap MIME::Base64 $VERSION; }; if ($@) { # can't bootstrap XS implementation, use perl implementation *encode_base64 = \&old_encode_base64; *decode_base64 = \&old_decode_base64; $OLD_CODE = $@; #warn $@ if $^W; } # Historically this module has been implemented as pure perl code. # The XS implementation runs about 20 times faster, but the Perl # code might be more portable, so it is still here. use integer; sub old_encode_base64 ($;$) { my $res = ""; my $eol = $_[1]; $eol = "\n" unless defined $eol; pos($_[0]) = 0; # ensure start at the beginning $res = join '', map( pack('u',$_)=~ /^.(\S*)/, ($_[0]=~/(.{1,45})/gs)); $res =~ tr|` -_|AA-Za-z0-9+/|; # `# help emacs # fix padding at the end my $padding = (3 - length($_[0]) % 3) % 3; $res =~ s/.{$padding}$/'=' x $padding/e if $padding; # break encoded string into lines of no more than 76 characters each if (length $eol) { $res =~ s/(.{1,76})/$1$eol/g; } return $res; } sub old_decode_base64 ($) { local($^W) = 0; # unpack("u",...) gives bogus warning in 5.00[123] my $str = shift; $str =~ tr|A-Za-z0-9+=/||cd; # remove non-base64 chars if (length($str) % 4) { require Carp; Carp::carp("Length of base64 data not a multiple of 4") } $str =~ s/=+$//; # remove padding $str =~ tr|A-Za-z0-9+/| -_|; # convert to uuencoded format return join'', map( unpack("u", chr(32 + length($_)*3/4) . $_), $str =~ /(.{1,60})/gs); } # Set up aliases so that these functions also can be called as # # MIME::Base64::encode(); # MIME::Base64::decode(); *encode = \&encode_base64; *decode = \&decode_base64; 1; vdradmin-am-3.6.13/lib/Template.pm000066400000000000000000000571551443716113400167030ustar00rootroot00000000000000#============================================================= -*-perl-*- # # Template # # DESCRIPTION # Module implementing a simple, user-oriented front-end to the Template # Toolkit. # # AUTHOR # Andy Wardley # # COPYRIGHT # Copyright (C) 1996-2002 Andy Wardley. All Rights Reserved. # Copyright (C) 1998-2002 Canon Research Centre Europe Ltd. # # This module is free software; you can redistribute it and/or # modify it under the same terms as Perl itself. # # REVISION # $Id: Template.pm,v 2.68 2003/04/29 12:38:58 abw Exp $ # #======================================================================== package Template; use base qw( Template::Base ); require 5.005; use strict; use vars qw( $VERSION $AUTOLOAD $ERROR $DEBUG $BINMODE ); use Template::Base; use Template::Config; use Template::Constants; use Template::Provider; use Template::Service; use File::Basename; use File::Path; ## This is the main version number for the Template Toolkit. ## It is extracted by ExtUtils::MakeMaker and inserted in various places. $VERSION = '2.10'; $ERROR = ''; $DEBUG = 0; # we used to default to binary mode for all win32 files but that make # line endings strange, so we're turning it off and letting users set # it explicitly as an argument to process() # $BINMODE = ($^O eq 'MSWin32') ? 1 : 0; $BINMODE = 0 unless defined $BINMODE; # preload all modules if we're running under mod_perl Template::Config->preload() if $ENV{ MOD_PERL }; #------------------------------------------------------------------------ # process($input, \%replace, $output) # # Main entry point for the Template Toolkit. The Template module # delegates most of the processing effort to the underlying SERVICE # object, an instance of the Template::Service class. #------------------------------------------------------------------------ sub process { my ($self, $template, $vars, $outstream, @opts) = @_; my ($output, $error); my $options = (@opts == 1) && UNIVERSAL::isa($opts[0], 'HASH') ? shift(@opts) : { @opts }; $options->{ binmode } = $BINMODE unless defined $options->{ binmode }; # we're using this for testing in t/output.t and t/filter.t so # don't remove it if you don't want tests to fail... $self->DEBUG("set binmode\n") if $DEBUG && $options->{ binmode }; $output = $self->{ SERVICE }->process($template, $vars); if (defined $output) { $outstream ||= $self->{ OUTPUT }; unless (ref $outstream) { my $outpath = $self->{ OUTPUT_PATH }; $outstream = "$outpath/$outstream" if $outpath; } # send processed template to output stream, checking for error return ($self->error($error)) if ($error = &_output($outstream, \$output, $options)); return 1; } else { return $self->error($self->{ SERVICE }->error); } } #------------------------------------------------------------------------ # service() # # Returns a reference to the the internal SERVICE object which handles # all requests for this Template object #------------------------------------------------------------------------ sub service { my $self = shift; return $self->{ SERVICE }; } #------------------------------------------------------------------------ # context() # # Returns a reference to the the CONTEXT object withint the SERVICE # object. #------------------------------------------------------------------------ sub context { my $self = shift; return $self->{ SERVICE }->{ CONTEXT }; } #======================================================================== # -- PRIVATE METHODS -- #======================================================================== #------------------------------------------------------------------------ # _init(\%config) #------------------------------------------------------------------------ sub _init { my ($self, $config) = @_; # convert any textual DEBUG args to numerical form my $debug = $config->{ DEBUG }; $config->{ DEBUG } = Template::Constants::debug_flags($self, $debug) || return if defined $debug && $debug !~ /^\d+$/; # prepare a namespace handler for any CONSTANTS definition if (my $constants = $config->{ CONSTANTS }) { my $ns = $config->{ NAMESPACE } ||= { }; my $cns = $config->{ CONSTANTS_NAMESPACE } || 'constants'; $constants = Template::Config->constants($constants) || return $self->error(Template::Config->error); $ns->{ $cns } = $constants; } $self->{ SERVICE } = $config->{ SERVICE } || Template::Config->service($config) || return $self->error(Template::Config->error); $self->{ OUTPUT } = $config->{ OUTPUT } || \*STDOUT; $self->{ OUTPUT_PATH } = $config->{ OUTPUT_PATH }; return $self; } #------------------------------------------------------------------------ # _output($where, $text) #------------------------------------------------------------------------ sub _output { my ($where, $textref, $options) = @_; my $reftype; my $error = 0; # call a CODE reference if (($reftype = ref($where)) eq 'CODE') { &$where($$textref); } # print to a glob (such as \*STDOUT) elsif ($reftype eq 'GLOB') { print $where $$textref; } # append output to a SCALAR ref elsif ($reftype eq 'SCALAR') { $$where .= $$textref; } # push onto ARRAY ref elsif ($reftype eq 'ARRAY') { push @$where, $$textref; } # call the print() method on an object that implements the method # (e.g. IO::Handle, Apache::Request, etc) elsif (UNIVERSAL::can($where, 'print')) { $where->print($$textref); } # a simple string is taken as a filename elsif (! $reftype) { local *FP; # make destination directory if it doesn't exist my $dir = dirname($where); eval { mkpath($dir) unless -d $dir; }; if ($@) { # strip file name and line number from error raised by die() ($error = $@) =~ s/ at \S+ line \d+\n?$//; } elsif (open(FP, ">$where")) { binmode FP if $options->{ binmode }; print FP $$textref; close FP; } else { $error = "$where: $!"; } } # give up, we've done our best else { $error = "output_handler() cannot determine target type ($where)\n"; } return $error; } 1; __END__ #------------------------------------------------------------------------ # IMPORTANT NOTE # This documentation is generated automatically from source # templates. Any changes you make here may be lost. # # The 'docsrc' documentation source bundle is available for download # from http://www.template-toolkit.org/docs.html and contains all # the source templates, XML files, scripts, etc., from which the # documentation for the Template Toolkit is built. #------------------------------------------------------------------------ =head1 NAME Template - Front-end module to the Template Toolkit =head1 SYNOPSIS use Template; # some useful options (see below for full list) my $config = { INCLUDE_PATH => '/search/path', # or list ref INTERPOLATE => 1, # expand "$var" in plain text POST_CHOMP => 1, # cleanup whitespace PRE_PROCESS => 'header', # prefix each template EVAL_PERL => 1, # evaluate Perl code blocks }; # create Template object my $template = Template->new($config); # define template variables for replacement my $vars = { var1 => $value, var2 => \%hash, var3 => \@list, var4 => \&code, var5 => $object, }; # specify input filename, or file handle, text reference, etc. my $input = 'myfile.html'; # process input template, substituting variables $template->process($input, $vars) || die $template->error(); =head1 DESCRIPTION This documentation describes the Template module which is the direct Perl interface into the Template Toolkit. It covers the use of the module and gives a brief summary of configuration options and template directives. Please see L for the complete reference manual which goes into much greater depth about the features and use of the Template Toolkit. The L is also available as an introductory guide to using the Template Toolkit. =head1 METHODS =head2 new(\%config) The new() constructor method (implemented by the Template::Base base class) instantiates a new Template object. A reference to a hash array of configuration items may be passed as a parameter. my $tt = Template->new({ INCLUDE_PATH => '/usr/local/templates', EVAL_PERL => 1, }) || die $Template::ERROR, "\n"; A reference to a new Template object is returned, or undef on error. In the latter case, the error message can be retrieved by calling error() as a class method (e.g. Cerror()>) or by examining the $ERROR package variable directly (e.g. C<$Template::ERROR>). my $tt = Template->new(\%config) || die Template->error(), "\n"; my $tt = Template->new(\%config) || die $Template::ERROR, "\n"; For convenience, configuration items may also be specified as a list of items instead of a hash array reference. These are automatically folded into a hash array by the constructor. my $tt = Template->new(INCLUDE_PATH => '/tmp', POST_CHOMP => 1) || die $Template::ERROR, "\n"; =head2 process($template, \%vars, $output, %options) The process() method is called to process a template. The first parameter indicates the input template as one of: a filename relative to INCLUDE_PATH, if defined; a reference to a text string containing the template text; or a file handle reference (e.g. IO::Handle or sub-class) or GLOB (e.g. \*STDIN), from which the template can be read. A reference to a hash array may be passed as the second parameter, containing definitions of template variables. $text = "[% INCLUDE header %]\nHello world!\n[% INCLUDE footer %]"; # filename $tt->process('welcome.tt2') || die $tt->error(), "\n"; # text reference $tt->process(\$text) || die $tt->error(), "\n"; # GLOB $tt->process(\*DATA) || die $tt->error(), "\n"; __END__ [% INCLUDE header %] This is a template defined in the __END__ section which is accessible via the DATA "file handle". [% INCLUDE footer %] By default, the processed template output is printed to STDOUT. The process() method then returns 1 to indicate success. A third parameter may be passed to the process() method to specify a different output location. This value may be one of: a plain string indicating a filename which will be opened (relative to OUTPUT_PATH, if defined) and the output written to; a file GLOB opened ready for output; a reference to a scalar (e.g. a text string) to which output/error is appended; a reference to a subroutine which is called, passing the output as a parameter; or any object reference which implements a 'print' method (e.g. IO::Handle, Apache::Request, etc.) which will be called, passing the generated output as a parameter. Examples: # output filename $tt->process('welcome.tt2', $vars, 'welcome.html') || die $tt->error(), "\n"; # reference to output subroutine sub myout { my $output = shift; ... } $tt->process('welcome.tt2', $vars, \&myout) || die $tt->error(), "\n"; # reference to output text string my $output = ''; $tt->process('welcome.tt2', $vars, \$output) || die $tt->error(), "\n"; print "output: $output\n"; In an Apache/mod_perl handler: sub handler { my $req = shift; ... # direct output to Apache::Request via $req->print($output) $tt->process($file, $vars, $req) || do { $req->log_reason($tt->error()); return SERVER_ERROR; }; return OK; } After the optional third output argument can come an optional reference to a hash or a list of (name, value) pairs providing further options for the output. The only option currently supported is "binmode" which, when set to any true value will ensure that files created (but not any existing file handles passed) will be set to binary mode. # either: hash reference of options $tt->process($infile, $vars, $outfile, { binmode => 1 }) || die $tt->error(), "\n"; # or: list of name, value pairs $tt->process($infile, $vars, $outfile, binmode => 1) || die $tt->error(), "\n"; The OUTPUT configuration item can be used to specify a default output location other than \*STDOUT. The OUTPUT_PATH specifies a directory which should be prefixed to all output locations specified as filenames. my $tt = Template->new({ OUTPUT => sub { ... }, # default OUTPUT_PATH => '/tmp', ... }) || die Template->error(), "\n"; # use default OUTPUT (sub is called) $tt->process('welcome.tt2', $vars) || die $tt->error(), "\n"; # write file to '/tmp/welcome.html' $tt->process('welcome.tt2', $vars, 'welcome.html') || die $tt->error(), "\n"; The process() method returns 1 on success or undef on error. The error message generated in the latter case can be retrieved by calling the error() method. See also L which describes how error handling may be further customised. =head2 error() When called as a class method, it returns the value of the $ERROR package variable. Thus, the following are equivalent. my $tt = Template->new() || die Template->error(), "\n"; my $tt = Template->new() || die $Template::ERROR, "\n"; When called as an object method, it returns the value of the internal _ERROR variable, as set by an error condition in a previous call to process(). $tt->process('welcome.tt2') || die $tt->error(), "\n"; Errors are represented in the Template Toolkit by objects of the Template::Exception class. If the process() method returns a false value then the error() method can be called to return an object of this class. The type() and info() methods can called on the object to retrieve the error type and information string, respectively. The as_string() method can be called to return a string of the form "$type - $info". This method is also overloaded onto the stringification operator allowing the object reference itself to be printed to return the formatted error string. $tt->process('somefile') || do { my $error = $tt->error(); print "error type: ", $error->type(), "\n"; print "error info: ", $error->info(), "\n"; print $error, "\n"; }; =head2 service() The Template module delegates most of the effort of processing templates to an underlying Template::Service object. This method returns a reference to that object. =head2 context() The Template::Service module uses a core Template::Context object for runtime processing of templates. This method returns a reference to that object and is equivalent to $template-Eservice-Econtext(); =head1 CONFIGURATION SUMMARY The following list gives a short summary of each Template Toolkit configuration option. See L for full details. =head2 Template Style and Parsing Options =over 4 =item START_TAG, END_TAG Define tokens that indicate start and end of directives (default: '[%' and '%]'). =item TAG_STYLE Set START_TAG and END_TAG according to a pre-defined style (default: 'template', as above). =item PRE_CHOMP, POST_CHOMP Remove whitespace before/after directives (default: 0/0). =item TRIM Remove leading and trailing whitespace from template output (default: 0). =item INTERPOLATE Interpolate variables embedded like $this or ${this} (default: 0). =item ANYCASE Allow directive keywords in lower case (default: 0 - UPPER only). =back =head2 Template Files and Blocks =over 4 =item INCLUDE_PATH One or more directories to search for templates. =item DELIMITER Delimiter for separating paths in INCLUDE_PATH (default: ':'). =item ABSOLUTE Allow absolute file names, e.g. /foo/bar.html (default: 0). =item RELATIVE Allow relative filenames, e.g. ../foo/bar.html (default: 0). =item DEFAULT Default template to use when another not found. =item BLOCKS Hash array pre-defining template blocks. =item AUTO_RESET Enabled by default causing BLOCK definitions to be reset each time a template is processed. Disable to allow BLOCK definitions to persist. =item RECURSION Flag to permit recursion into templates (default: 0). =back =head2 Template Variables =over 4 =item VARIABLES, PRE_DEFINE Hash array of variables and values to pre-define in the stash. =back =head2 Runtime Processing Options =over 4 =item EVAL_PERL Flag to indicate if PERL/RAWPERL blocks should be processed (default: 0). =item PRE_PROCESS, POST_PROCESS Name of template(s) to process before/after main template. =item PROCESS Name of template(s) to process instead of main template. =item ERROR Name of error template or reference to hash array mapping error types to templates. =item OUTPUT Default output location or handler. =item OUTPUT_PATH Directory into which output files can be written. =item DEBUG Enable debugging messages. =back =head2 Caching and Compiling Options =over 4 =item CACHE_SIZE Maximum number of compiled templates to cache in memory (default: undef - cache all) =item COMPILE_EXT Filename extension for compiled template files (default: undef - don't compile). =item COMPILE_DIR Root of directory in which compiled template files should be written (default: undef - don't compile). =back =head2 Plugins and Filters =over 4 =item PLUGINS Reference to a hash array mapping plugin names to Perl packages. =item PLUGIN_BASE One or more base classes under which plugins may be found. =item LOAD_PERL Flag to indicate regular Perl modules should be loaded if a named plugin can't be found (default: 0). =item FILTERS Hash array mapping filter names to filter subroutines or factories. =back =head2 Compatibility, Customisation and Extension =over 4 =item V1DOLLAR Backwards compatibility flag enabling version 1.* handling (i.e. ignore it) of leading '$' on variables (default: 0 - '$' indicates interpolation). =item LOAD_TEMPLATES List of template providers. =item LOAD_PLUGINS List of plugin providers. =item LOAD_FILTERS List of filter providers. =item TOLERANT Set providers to tolerate errors as declinations (default: 0). =item SERVICE Reference to a custom service object (default: Template::Service). =item CONTEXT Reference to a custom context object (default: Template::Context). =item STASH Reference to a custom stash object (default: Template::Stash). =item PARSER Reference to a custom parser object (default: Template::Parser). =item GRAMMAR Reference to a custom grammar object (default: Template::Grammar). =back =head1 DIRECTIVE SUMMARY The following list gives a short summary of each Template Toolkit directive. See L for full details. =over 4 =item GET Evaluate and print a variable or value. [% GET variable %] # 'GET' keyword is optional [% variable %] [% hash.key %] [% list.n %] [% code(args) %] [% obj.meth(args) %] [% "value: $var" %] =item CALL As per GET but without printing result (e.g. call code) [% CALL variable %] =item SET Assign a values to variables. [% SET variable = value %] # 'SET' also optional [% variable = other_variable variable = 'literal text @ $100' variable = "interpolated text: $var" list = [ val, val, val, val, ... ] list = [ val..val ] hash = { var => val, var => val, ... } %] =item DEFAULT Like SET above, but variables are only set if currently unset (i.e. have no true value). [% DEFAULT variable = value %] =item INSERT Insert a file without any processing performed on the contents. [% INSERT legalese.txt %] =item INCLUDE Process another template file or block and include the output. Variables are localised. [% INCLUDE template %] [% INCLUDE template var = val, ... %] =item PROCESS As INCLUDE above, but without localising variables. [% PROCESS template %] [% PROCESS template var = val, ... %] =item WRAPPER Process the enclosed block WRAPPER ... END block then INCLUDE the named template, passing the block output in the 'content' variable. [% WRAPPER template %] content... [% END %] =item BLOCK Define a named template block for subsequent INCLUDE, PROCESS, etc., [% BLOCK template %] content [% END %] =item FOREACH Repeat the enclosed FOREACH ... END block for each value in the list. [% FOREACH variable = [ val, val, val ] %] # either [% FOREACH variable = list %] # or [% FOREACH list %] # or content... [% variable %] [% END %] =item WHILE Enclosed WHILE ... END block is processed while condition is true. [% WHILE condition %] content [% END %] =item IF / UNLESS / ELSIF / ELSE Enclosed block is processed if the condition is true / false. [% IF condition %] content [% ELSIF condition %] content [% ELSE %] content [% END %] [% UNLESS condition %] content [% # ELSIF/ELSE as per IF, above %] content [% END %] =item SWITCH / CASE Multi-way switch/case statement. [% SWITCH variable %] [% CASE val1 %] content [% CASE [ val2, val3 ] %] content [% CASE %] # or [% CASE DEFAULT %] content [% END %] =item MACRO Define a named macro. [% MACRO name %] [% MACRO name(arg1, arg2) %] ... [% name %] [% name(val1, val2) %] =item FILTER Process enclosed FILTER ... END block then pipe through a filter. [% FILTER name %] # either [% FILTER name( params ) %] # or [% FILTER alias = name( params ) %] # or content [% END %] =item USE Load a "plugin" module, or any regular Perl module if LOAD_PERL option is set. [% USE name %] # either [% USE name( params ) %] # or [% USE var = name( params ) %] # or ... [% name.method %] [% var.method %] =item PERL / RAWPERL Evaluate enclosed blocks as Perl code (requires EVAL_PERL option to be set). [% PERL %] # perl code goes here $stash->set('foo', 10); print "set 'foo' to ", $stash->get('foo'), "\n"; print $context->include('footer', { var => $val }); [% END %] [% RAWPERL %] # raw perl code goes here, no magic but fast. $output .= 'some output'; [% END %] =item TRY / THROW / CATCH / FINAL Exception handling. [% TRY %] content [% THROW type info %] [% CATCH type %] catch content [% error.type %] [% error.info %] [% CATCH %] # or [% CATCH DEFAULT %] content [% FINAL %] this block is always processed [% END %] =item NEXT Jump straight to the next item in a FOREACH/WHILE loop. [% NEXT %] =item LAST Break out of FOREACH/WHILE loop. [% LAST %] =item RETURN Stop processing current template and return to including templates. [% RETURN %] =item STOP Stop processing all templates and return to caller. [% STOP %] =item TAGS Define new tag style or characters (default: [% %]). [% TAGS html %] [% TAGS %] =item COMMENTS Ignored and deleted. [% # this is a comment to the end of line foo = 'bar' %] [%# placing the '#' immediately inside the directive tag comments out the entire directive %] =back =head1 AUTHOR Andy Wardley Eabw@andywardley.comE L =head1 VERSION Template Toolkit version 2.10, released on 24 July 2003. =head1 COPYRIGHT Copyright (C) 1996-2003 Andy Wardley. All Rights Reserved. Copyright (C) 1998-2002 Canon Research Centre Europe Ltd. This module is free software; you can redistribute it and/or modify it under the same terms as Perl itself. vdradmin-am-3.6.13/lib/Template/000077500000000000000000000000001443716113400163305ustar00rootroot00000000000000vdradmin-am-3.6.13/lib/Template/Base.pm000066400000000000000000000172251443716113400175470ustar00rootroot00000000000000#============================================================= -*-perl-*- # # Template::Base # # DESCRIPTION # Base class module implementing common functionality for various other # Template Toolkit modules. # # AUTHOR # Andy Wardley # # COPYRIGHT # Copyright (C) 1996-2000 Andy Wardley. All Rights Reserved. # Copyright (C) 1998-2000 Canon Research Centre Europe Ltd. # # This module is free software; you can redistribute it and/or # modify it under the same terms as Perl itself. # #------------------------------------------------------------------------ # # $Id: Base.pm,v 2.62 2003/04/24 09:14:38 abw Exp $ # #======================================================================== package Template::Base; require 5.004; use strict; use vars qw( $VERSION ); use Template::Constants; $VERSION = sprintf("%d.%02d", q$Revision: 2.62 $ =~ /(\d+)\.(\d+)/); #------------------------------------------------------------------------ # new(\%params) # # General purpose constructor method which expects a hash reference of # configuration parameters, or a list of name => value pairs which are # folded into a hash. Blesses a hash into an object and calls its # _init() method, passing the parameter hash reference. Returns a new # object derived from Template::Base, or undef on error. #------------------------------------------------------------------------ sub new { my $class = shift; my ($argnames, @args, $arg, $cfg); # $class->error(''); # always clear package $ERROR var? { no strict qw( refs ); $argnames = \@{"$class\::BASEARGS"} || [ ]; } # shift off all mandatory args, returning error if undefined or null foreach $arg (@$argnames) { return $class->error("no $arg specified") unless ($cfg = shift); push(@args, $cfg); } # fold all remaining args into a hash, or use provided hash ref # local $" = ', '; # print STDERR "args: [@_]\n"; $cfg = defined $_[0] && UNIVERSAL::isa($_[0], 'HASH') ? shift : { @_ }; my $self = bless { map { ($_ => shift @args) } @$argnames, _ERROR => '', DEBUG => 0, }, $class; return $self->_init($cfg) ? $self : $class->error($self->error); } #------------------------------------------------------------------------ # error() # error($msg, ...) # # May be called as a class or object method to set or retrieve the # package variable $ERROR (class method) or internal member # $self->{ _ERROR } (object method). The presence of parameters indicates # that the error value should be set. Undef is then returned. In the # abscence of parameters, the current error value is returned. #------------------------------------------------------------------------ sub error { my $self = shift; my $errvar; { no strict qw( refs ); $errvar = ref $self ? \$self->{ _ERROR } : \${"$self\::ERROR"}; } if (@_) { $$errvar = ref($_[0]) ? shift : join('', @_); return undef; } else { return $$errvar; } } #------------------------------------------------------------------------ # _init() # # Initialisation method called by the new() constructor and passing a # reference to a hash array containing any configuration items specified # as constructor arguments. Should return $self on success or undef on # error, via a call to the error() method to set the error message. #------------------------------------------------------------------------ sub _init { my ($self, $config) = @_; return $self; } sub DEBUG { my $self = shift; print STDERR "DEBUG: ", @_; } sub debug { my $self = shift; my $msg = join('', @_); my ($pkg, $file, $line) = caller(); unless ($msg =~ /\n$/) { $msg .= ($self->{ DEBUG } & Template::Constants::DEBUG_CALLER) ? " at $file line $line\n" : "\n"; } print STDERR "[$pkg] $msg"; } 1; __END__ #------------------------------------------------------------------------ # IMPORTANT NOTE # This documentation is generated automatically from source # templates. Any changes you make here may be lost. # # The 'docsrc' documentation source bundle is available for download # from http://www.template-toolkit.org/docs.html and contains all # the source templates, XML files, scripts, etc., from which the # documentation for the Template Toolkit is built. #------------------------------------------------------------------------ =head1 NAME Template::Base - Base class module implementing common functionality =head1 SYNOPSIS package My::Module; use base qw( Template::Base ); sub _init { my ($self, $config) = @_; $self->{ doodah } = $config->{ doodah } || return $self->error("No 'doodah' specified"); return $self; } package main; my $object = My::Module->new({ doodah => 'foobar' }) || die My::Module->error(); =head1 DESCRIPTION Base class module which implements a constructor and error reporting functionality for various Template Toolkit modules. =head1 PUBLIC METHODS =head2 new(\%config) Constructor method which accepts a reference to a hash array or a list of C value> parameters which are folded into a hash. The _init() method is then called, passing the configuration hash and should return true/false to indicate success or failure. A new object reference is returned, or undef on error. Any error message raised can be examined via the error() class method or directly via the package variable ERROR in the derived class. my $module = My::Module->new({ ... }) || die My::Module->error(), "\n"; my $module = My::Module->new({ ... }) || die "constructor error: $My::Module::ERROR\n"; =head2 error($msg, ...) May be called as an object method to get/set the internal _ERROR member or as a class method to get/set the $ERROR variable in the derived class's package. my $module = My::Module->new({ ... }) || die My::Module->error(), "\n"; $module->do_something() || die $module->error(), "\n"; When called with parameters (multiple params are concatenated), this method will set the relevant variable and return undef. This is most often used within object methods to report errors to the caller. package My::Module; sub foobar { my $self = shift; # some other code... return $self->error('some kind of error...') if $some_condition; } =head2 debug($msg, ...) Generates a debugging message by concatenating all arguments passed into a string and printing it to STDERR. A prefix is added to indicate the module of the caller. package My::Module; sub foobar { my $self = shift; $self->debug('called foobar()'); # some other code... } When the foobar() method is called, the following message is sent to STDERR: [My::Module] called foobar() Objects can set an internal DEBUG value which the debug() method will examine. If this value sets the relevant bits to indicate DEBUG_CALLER then the file and line number of the caller will be appened to the message. use Template::Constants qw( :debug ); my $module = My::Module->new({ DEBUG => DEBUG_SERVICE | DEBUG_CONTEXT | DEBUG_CALLER, }); $module->foobar(); This generates an error message such as: [My::Module] called foobar() at My/Module.pm line 6 =head1 AUTHOR Andy Wardley Eabw@andywardley.comE L =head1 VERSION 2.62, distributed as part of the Template Toolkit version 2.10, released on 24 July 2003. =head1 COPYRIGHT Copyright (C) 1996-2003 Andy Wardley. All Rights Reserved. Copyright (C) 1998-2002 Canon Research Centre Europe Ltd. This module is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =head1 SEE ALSO L vdradmin-am-3.6.13/lib/Template/Config.pm000066400000000000000000000343741443716113400201060ustar00rootroot00000000000000#============================================================= -*-perl-*- # # Template::Config # # DESCRIPTION # Template Toolkit configuration module. # # AUTHOR # Andy Wardley # # COPYRIGHT # Copyright (C) 1996-2000 Andy Wardley. All Rights Reserved. # Copyright (C) 1998-2000 Canon Research Centre Europe Ltd. # # This module is free software; you can redistribute it and/or # modify it under the same terms as Perl itself. # #------------------------------------------------------------------------ # # $Id: Config.pm,v 2.62 2003/04/24 09:14:38 abw Exp $ # #======================================================================== package Template::Config; require 5.004; use strict; use base qw( Template::Base ); use vars qw( $VERSION $DEBUG $ERROR $INSTDIR $PARSER $PROVIDER $PLUGINS $FILTERS $ITERATOR $LATEX_PATH $PDFLATEX_PATH $DVIPS_PATH $STASH $SERVICE $CONTEXT $CONSTANTS @PRELOAD ); $VERSION = sprintf("%d.%02d", q$Revision: 2.62 $ =~ /(\d+)\.(\d+)/); $DEBUG = 0 unless defined $DEBUG; $ERROR = ''; $CONTEXT = 'Template::Context'; $FILTERS = 'Template::Filters'; $ITERATOR = 'Template::Iterator'; $PARSER = 'Template::Parser'; $PLUGINS = 'Template::Plugins'; $PROVIDER = 'Template::Provider'; $SERVICE = 'Template::Service'; $STASH = 'Template::Stash'; $CONSTANTS = 'Template::Namespace::Constants'; @PRELOAD = ( $CONTEXT, $FILTERS, $ITERATOR, $PARSER, $PLUGINS, $PROVIDER, $SERVICE, $STASH ); # the following is set at installation time by the Makefile.PL $INSTDIR = ''; # LaTeX executable paths set at installation time by the Makefile.PL # Empty strings cause the latex(pdf|dvi|ps) filters to throw an error. $LATEX_PATH = ''; $PDFLATEX_PATH = ''; $DVIPS_PATH = ''; #======================================================================== # --- CLASS METHODS --- #======================================================================== #------------------------------------------------------------------------ # preload($module, $module, ...) # # Preloads all the standard TT modules that are likely to be used, along # with any other passed as arguments. #------------------------------------------------------------------------ sub preload { my $class = shift; foreach my $module (@PRELOAD, @_) { $class->load($module) || return; }; return 1; } #------------------------------------------------------------------------ # load($module) # # Load a module via require(). Any occurences of '::' in the module name # are be converted to '/' and '.pm' is appended. Returns 1 on success # or undef on error. Use $class->error() to examine the error string. #------------------------------------------------------------------------ sub load { my ($class, $module) = @_; $module =~ s[::][/]g; $module .= '.pm'; # print STDERR "loading $module\n" # if $DEBUG; eval { require $module; }; return $@ ? $class->error("failed to load $module: $@") : 1; } #------------------------------------------------------------------------ # parser(\%params) # # Instantiate a new parser object of the class whose name is denoted by # the package variable $PARSER (default: Template::Parser). Returns # a reference to a newly instantiated parser object or undef on error. # The class error() method can be called without arguments to examine # the error message generated by this failure. #------------------------------------------------------------------------ sub parser { my $class = shift; my $params = defined($_[0]) && UNIVERSAL::isa($_[0], 'HASH') ? shift : { @_ }; return undef unless $class->load($PARSER); return $PARSER->new($params) || $class->error("failed to create parser: ", $PARSER->error); } #------------------------------------------------------------------------ # provider(\%params) # # Instantiate a new template provider object (default: Template::Provider). # Returns an object reference or undef on error, as above. #------------------------------------------------------------------------ sub provider { my $class = shift; my $params = defined($_[0]) && UNIVERSAL::isa($_[0], 'HASH') ? shift : { @_ }; return undef unless $class->load($PROVIDER); return $PROVIDER->new($params) || $class->error("failed to create template provider: ", $PROVIDER->error); } #------------------------------------------------------------------------ # plugins(\%params) # # Instantiate a new plugins provider object (default: Template::Plugins). # Returns an object reference or undef on error, as above. #------------------------------------------------------------------------ sub plugins { my $class = shift; my $params = defined($_[0]) && UNIVERSAL::isa($_[0], 'HASH') ? shift : { @_ }; return undef unless $class->load($PLUGINS); return $PLUGINS->new($params) || $class->error("failed to create plugin provider: ", $PLUGINS->error); } #------------------------------------------------------------------------ # filters(\%params) # # Instantiate a new filters provider object (default: Template::Filters). # Returns an object reference or undef on error, as above. #------------------------------------------------------------------------ sub filters { my $class = shift; my $params = defined($_[0]) && UNIVERSAL::isa($_[0], 'HASH') ? shift : { @_ }; return undef unless $class->load($FILTERS); return $FILTERS->new($params) || $class->error("failed to create filter provider: ", $FILTERS->error); } #------------------------------------------------------------------------ # iterator(\@list) # # Instantiate a new Template::Iterator object (default: Template::Iterator). # Returns an object reference or undef on error, as above. #------------------------------------------------------------------------ sub iterator { my $class = shift; my $list = shift; return undef unless $class->load($ITERATOR); return $ITERATOR->new($list, @_) || $class->error("failed to create iterator: ", $ITERATOR->error); } #------------------------------------------------------------------------ # stash(\%vars) # # Instantiate a new template variable stash object (default: # Template::Stash). Returns object or undef, as above. #------------------------------------------------------------------------ sub stash { my $class = shift; my $params = defined($_[0]) && UNIVERSAL::isa($_[0], 'HASH') ? shift : { @_ }; return undef unless $class->load($STASH); return $STASH->new($params) || $class->error("failed to create stash: ", $STASH->error); } #------------------------------------------------------------------------ # context(\%params) # # Instantiate a new template context object (default: Template::Context). # Returns object or undef, as above. #------------------------------------------------------------------------ sub context { my $class = shift; my $params = defined($_[0]) && UNIVERSAL::isa($_[0], 'HASH') ? shift : { @_ }; return undef unless $class->load($CONTEXT); return $CONTEXT->new($params) || $class->error("failed to create context: ", $CONTEXT->error); } #------------------------------------------------------------------------ # service(\%params) # # Instantiate a new template context object (default: Template::Service). # Returns object or undef, as above. #------------------------------------------------------------------------ sub service { my $class = shift; my $params = defined($_[0]) && UNIVERSAL::isa($_[0], 'HASH') ? shift : { @_ }; return undef unless $class->load($SERVICE); return $SERVICE->new($params) || $class->error("failed to create context: ", $SERVICE->error); } #------------------------------------------------------------------------ # constants(\%params) # # Instantiate a new namespace handler for compile time constant folding # (default: Template::Namespace::Constants). # Returns object or undef, as above. #------------------------------------------------------------------------ sub constants { my $class = shift; my $params = defined($_[0]) && UNIVERSAL::isa($_[0], 'HASH') ? shift : { @_ }; return undef unless $class->load($CONSTANTS); return $CONSTANTS->new($params) || $class->error("failed to create constants namespace: ", $CONSTANTS->error); } #------------------------------------------------------------------------ # instdir($dir) # # Returns the root installation directory appended with any local # component directory passed as an argument. #------------------------------------------------------------------------ sub instdir { my ($class, $dir) = @_; my $inst = $INSTDIR || return $class->error("no installation directory"); $inst =~ s[/$][]g; $inst .= "/$dir" if $dir; return $inst; } #------------------------------------------------------------------------ # latexpaths() # # Returns a reference to a three element array: # [latex_path, pdf2latex_path, dvips_path] # These values are determined by Makefile.PL at installation time # and are used by the latex(pdf|dvi|ps) filters. #------------------------------------------------------------------------ sub latexpaths { return [$LATEX_PATH, $PDFLATEX_PATH, $DVIPS_PATH]; } #======================================================================== # This should probably be moved somewhere else in the long term, but for # now it ensures that Template::TieString is available even if the # Template::Directive module hasn't been loaded, as is the case when # using compiled templates and Template::Parser hasn't yet been loaded # on demand. #======================================================================== #------------------------------------------------------------------------ # simple package for tying $output variable to STDOUT, used by perl() #------------------------------------------------------------------------ package Template::TieString; sub TIEHANDLE { my ($class, $textref) = @_; bless $textref, $class; } sub PRINT { my $self = shift; $$self .= join('', @_); } 1; __END__ #------------------------------------------------------------------------ # IMPORTANT NOTE # This documentation is generated automatically from source # templates. Any changes you make here may be lost. # # The 'docsrc' documentation source bundle is available for download # from http://www.template-toolkit.org/docs.html and contains all # the source templates, XML files, scripts, etc., from which the # documentation for the Template Toolkit is built. #------------------------------------------------------------------------ =head1 NAME Template::Config - Factory module for instantiating other TT2 modules =head1 SYNOPSIS use Template::Config; =head1 DESCRIPTION This module implements various methods for loading and instantiating other modules that comprise the Template Toolkit. It provides a consistent way to create toolkit components and allows custom modules to be used in place of the regular ones. Package variables such as $STASH, $SERVICE, $CONTEXT, etc., contain the default module/package name for each component (Template::Stash, Template::Service and Template::Context, respectively) and are used by the various factory methods (stash(), service() and context()) to load the appropriate module. Changing these package variables will cause subsequent calls to the relevant factory method to load and instantiate an object from the new class. =head1 PUBLIC METHODS =head2 load($module) Load a module via require(). Any occurences of '::' in the module name are be converted to '/' and '.pm' is appended. Returns 1 on success or undef on error. Use $class-Eerror() to examine the error string. =head2 preload() This method preloads all the other Template::* modules that are likely to be used. It is called by the Template module when running under mod_perl ($ENV{MOD_PERL} is set). =head2 parser(\%config) Instantiate a new parser object of the class whose name is denoted by the package variable $PARSER (default: Template::Parser). Returns a reference to a newly instantiated parser object or undef on error. =head2 provider(\%config) Instantiate a new template provider object (default: Template::Provider). Returns an object reference or undef on error, as above. =head2 plugins(\%config) Instantiate a new plugins provider object (default: Template::Plugins). Returns an object reference or undef on error, as above. =head2 filters(\%config) Instantiate a new filter provider object (default: Template::Filters). Returns an object reference or undef on error, as above. =head2 stash(\%vars) Instantiate a new stash object (Template::Stash or Template::Stash::XS depending on the default set at installation time) using the contents of the optional hash array passed by parameter as initial variable definitions. Returns an object reference or undef on error, as above. =head2 context(\%config) Instantiate a new template context object (default: Template::Context). Returns an object reference or undef on error, as above. =head2 service(\%config) Instantiate a new template service object (default: Template::Service). Returns an object reference or undef on error, as above. =head2 instdir($dir) Returns the root directory of the Template Toolkit installation under which optional components are installed. Any relative directory specified as an argument will be appended to the returned directory. # e.g. returns '/usr/local/tt2' my $ttroot = Template::Config->instdir() || die "$Template::Config::ERROR\n"; # e.g. returns '/usr/local/tt2/templates' my $template = Template::Config->instdir('templates') || die "$Template::Config::ERROR\n"; Returns undef and sets $Template::Config::ERROR appropriately if the optional components of the Template Toolkit have not been installed. =head1 AUTHOR Andy Wardley Eabw@andywardley.comE L =head1 VERSION 2.62, distributed as part of the Template Toolkit version 2.10, released on 24 July 2003. =head1 COPYRIGHT Copyright (C) 1996-2003 Andy Wardley. All Rights Reserved. Copyright (C) 1998-2002 Canon Research Centre Europe Ltd. This module is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =head1 SEE ALSO L vdradmin-am-3.6.13/lib/Template/Constants.pm000066400000000000000000000235631443716113400206530ustar00rootroot00000000000000#============================================================= -*-Perl-*- # # Template::Constants.pm # # DESCRIPTION # Definition of constants for the Template Toolkit. # # AUTHOR # Andy Wardley # # COPYRIGHT # Copyright (C) 1996-2000 Andy Wardley. All Rights Reserved. # Copyright (C) 1998-2000 Canon Research Centre Europe Ltd. # # This module is free software; you can redistribute it and/or # modify it under the same terms as Perl itself. # #---------------------------------------------------------------------------- # # $Id: Constants.pm,v 2.62 2003/04/24 09:14:38 abw Exp $ # #============================================================================ package Template::Constants; require 5.004; require Exporter; use strict; use vars qw( $VERSION @ISA @EXPORT_OK %EXPORT_TAGS ); use vars qw( $DEBUG_OPTIONS @STATUS @ERROR @CHOMP @DEBUG); @ISA = qw( Exporter ); $VERSION = sprintf("%d.%02d", q$Revision: 2.62 $ =~ /(\d+)\.(\d+)/); #======================================================================== # ----- EXPORTER ----- #======================================================================== # STATUS constants returned by directives use constant STATUS_OK => 0; # ok use constant STATUS_RETURN => 1; # ok, block ended by RETURN use constant STATUS_STOP => 2; # ok, stoppped by STOP use constant STATUS_DONE => 3; # ok, iterator done use constant STATUS_DECLINED => 4; # ok, declined to service request use constant STATUS_ERROR => 255; # error condition # ERROR constants for indicating exception types use constant ERROR_RETURN => 'return'; # return a status code use constant ERROR_FILE => 'file'; # file error: I/O, parse, recursion use constant ERROR_VIEW => 'view'; # view error use constant ERROR_UNDEF => 'undef'; # undefined variable value used use constant ERROR_PERL => 'perl'; # error in [% PERL %] block use constant ERROR_FILTER => 'filter'; # filter error use constant ERROR_PLUGIN => 'plugin'; # plugin error # CHOMP constants for PRE_CHOMP and POST_CHOMP use constant CHOMP_NONE => 0; # do not remove whitespace use constant CHOMP_ALL => 1; # remove whitespace use constant CHOMP_COLLAPSE => 2; # collapse whitespace to a single space # DEBUG constants to enable various debugging options use constant DEBUG_OFF => 0; # do nothing use constant DEBUG_ON => 1; # basic debugging flag use constant DEBUG_UNDEF => 2; # throw undef on undefined variables use constant DEBUG_VARS => 4; # general variable debugging use constant DEBUG_DIRS => 8; # directive debugging use constant DEBUG_STASH => 16; # general stash debugging use constant DEBUG_CONTEXT => 32; # context debugging use constant DEBUG_PARSER => 64; # parser debugging use constant DEBUG_PROVIDER => 128; # provider debugging use constant DEBUG_PLUGINS => 256; # plugins debugging use constant DEBUG_FILTERS => 512; # filters debugging use constant DEBUG_SERVICE => 1024; # context debugging use constant DEBUG_ALL => 2047; # everything # extra debugging flags use constant DEBUG_CALLER => 4096; # add caller file/line use constant DEBUG_FLAGS => 4096; # bitmask to extraxt flags $DEBUG_OPTIONS = { &DEBUG_OFF => off => off => &DEBUG_OFF, &DEBUG_ON => on => on => &DEBUG_ON, &DEBUG_UNDEF => undef => undef => &DEBUG_UNDEF, &DEBUG_VARS => vars => vars => &DEBUG_VARS, &DEBUG_DIRS => dirs => dirs => &DEBUG_DIRS, &DEBUG_STASH => stash => stash => &DEBUG_STASH, &DEBUG_CONTEXT => context => context => &DEBUG_CONTEXT, &DEBUG_PARSER => parser => parser => &DEBUG_PARSER, &DEBUG_PROVIDER => provider => provider => &DEBUG_PROVIDER, &DEBUG_PLUGINS => plugins => plugins => &DEBUG_PLUGINS, &DEBUG_FILTERS => filters => filters => &DEBUG_FILTERS, &DEBUG_SERVICE => service => service => &DEBUG_SERVICE, &DEBUG_ALL => all => all => &DEBUG_ALL, &DEBUG_CALLER => caller => caller => &DEBUG_CALLER, }; @STATUS = qw( STATUS_OK STATUS_RETURN STATUS_STOP STATUS_DONE STATUS_DECLINED STATUS_ERROR ); @ERROR = qw( ERROR_FILE ERROR_VIEW ERROR_UNDEF ERROR_PERL ERROR_RETURN ERROR_FILTER ERROR_PLUGIN ); @CHOMP = qw( CHOMP_NONE CHOMP_ALL CHOMP_COLLAPSE ); @DEBUG = qw( DEBUG_OFF DEBUG_ON DEBUG_UNDEF DEBUG_VARS DEBUG_DIRS DEBUG_STASH DEBUG_CONTEXT DEBUG_PARSER DEBUG_PROVIDER DEBUG_PLUGINS DEBUG_FILTERS DEBUG_SERVICE DEBUG_ALL DEBUG_CALLER DEBUG_FLAGS ); @EXPORT_OK = ( @STATUS, @ERROR, @CHOMP, @DEBUG ); %EXPORT_TAGS = ( 'all' => [ @EXPORT_OK ], 'status' => [ @STATUS ], 'error' => [ @ERROR ], 'chomp' => [ @CHOMP ], 'debug' => [ @DEBUG ], ); sub debug_flags { my ($self, $debug) = @_; my (@flags, $flag, $value); $debug = $self unless defined($debug) || ref($self); if ($debug =~ /^\d+$/) { foreach $flag (@DEBUG) { next if $flag =~ /^DEBUG_(OFF|ALL|FLAGS)$/; # don't trash the original my $copy = $flag; $flag =~ s/^DEBUG_//; $flag = lc $flag; return $self->error("no value for flag: $flag") unless defined($value = $DEBUG_OPTIONS->{ $flag }); $flag = $value; if ($debug & $flag) { $value = $DEBUG_OPTIONS->{ $flag }; return $self->error("no value for flag: $flag") unless defined $value; push(@flags, $value); } } return wantarray ? @flags : join(', ', @flags); } else { @flags = split(/\W+/, $debug); $debug = 0; foreach $flag (@flags) { $value = $DEBUG_OPTIONS->{ $flag }; return $self->error("unknown debug flag: $flag") unless defined $value; $debug |= $value; } return $debug; } } 1; __END__ #------------------------------------------------------------------------ # IMPORTANT NOTE # This documentation is generated automatically from source # templates. Any changes you make here may be lost. # # The 'docsrc' documentation source bundle is available for download # from http://www.template-toolkit.org/docs.html and contains all # the source templates, XML files, scripts, etc., from which the # documentation for the Template Toolkit is built. #------------------------------------------------------------------------ =head1 NAME Template::Constants - Defines constants for the Template Toolkit =head1 SYNOPSIS use Template::Constants qw( :status :error :all ); =head1 DESCRIPTION The Template::Constants modules defines, and optionally exports into the caller's namespace, a number of constants used by the Template package. Constants may be used by specifying the Template::Constants package explicitly: use Template::Constants; print Template::Constants::STATUS_DECLINED; Constants may be imported into the caller's namespace by naming them as options to the C statement: use Template::Constants qw( STATUS_DECLINED ); print STATUS_DECLINED; Alternatively, one of the following tagset identifiers may be specified to import sets of constants; :status, :error, :all. use Template::Constants qw( :status ); print STATUS_DECLINED; See L for more information on exporting variables. =head1 EXPORTABLE TAG SETS The following tag sets and associated constants are defined: :status STATUS_OK # no problem, continue STATUS_RETURN # ended current block then continue (ok) STATUS_STOP # controlled stop (ok) STATUS_DONE # iterator is all done (ok) STATUS_DECLINED # provider declined to service request (ok) STATUS_ERROR # general error condition (not ok) :error ERROR_RETURN # return a status code (e.g. 'stop') ERROR_FILE # file error: I/O, parse, recursion ERROR_UNDEF # undefined variable value used ERROR_PERL # error in [% PERL %] block ERROR_FILTER # filter error ERROR_PLUGIN # plugin error :chomp # for PRE_CHOMP and POST_CHOMP CHOMP_NONE # do not remove whitespace CHOMP_ALL # remove whitespace CHOMP_COLLAPSE # collapse whitespace to a single space :debug DEBUG_OFF # do nothing DEBUG_ON # basic debugging flag DEBUG_UNDEF # throw undef on undefined variables DEBUG_VARS # general variable debugging DEBUG_DIRS # directive debugging DEBUG_STASH # general stash debugging DEBUG_CONTEXT # context debugging DEBUG_PARSER # parser debugging DEBUG_PROVIDER # provider debugging DEBUG_PLUGINS # plugins debugging DEBUG_FILTERS # filters debugging DEBUG_SERVICE # context debugging DEBUG_ALL # everything DEBUG_CALLER # add caller file/line info DEBUG_FLAGS # bitmap used internally :all All the above constants. =head1 AUTHOR Andy Wardley Eabw@andywardley.comE L =head1 VERSION 2.62, distributed as part of the Template Toolkit version 2.10, released on 24 July 2003. =head1 COPYRIGHT Copyright (C) 1996-2003 Andy Wardley. All Rights Reserved. Copyright (C) 1998-2002 Canon Research Centre Europe Ltd. This module is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =head1 SEE ALSO L, L vdradmin-am-3.6.13/lib/Template/Context.pm000066400000000000000000001447751443716113400203340ustar00rootroot00000000000000#============================================================= -*-Perl-*- # # Template::Context # # DESCRIPTION # Module defining a context in which a template document is processed. # This is the runtime processing interface through which templates # can access the functionality of the Template Toolkit. # # AUTHOR # Andy Wardley # # COPYRIGHT # Copyright (C) 1996-2000 Andy Wardley. All Rights Reserved. # Copyright (C) 1998-2000 Canon Research Centre Europe Ltd. # # This module is free software; you can redistribute it and/or # modify it under the same terms as Perl itself. # # REVISION # $Id: Context.pm,v 2.81 2003/07/24 11:32:35 abw Exp $ # #============================================================================ package Template::Context; require 5.004; use strict; use vars qw( $VERSION $DEBUG $AUTOLOAD $DEBUG_FORMAT ); use base qw( Template::Base ); use Template::Base; use Template::Config; use Template::Constants; use Template::Exception; $VERSION = sprintf("%d.%02d", q$Revision: 2.81 $ =~ /(\d+)\.(\d+)/); $DEBUG_FORMAT = "\n## \$file line \$line : [% \$text %] ##\n"; #======================================================================== # ----- PUBLIC METHODS ----- #======================================================================== #------------------------------------------------------------------------ # template($name) # # General purpose method to fetch a template and return it in compiled # form. In the usual case, the $name parameter will be a simple string # containing the name of a template (e.g. 'header'). It may also be # a reference to Template::Document object (or sub-class) or a Perl # sub-routine. These are considered to be compiled templates and are # returned intact. Finally, it may be a reference to any other kind # of valid input source accepted by Template::Provider (e.g. scalar # ref, glob, IO handle, etc). # # Templates may be cached at one of 3 different levels. The internal # BLOCKS member is a local cache which holds references to all # template blocks used or imported via PROCESS since the context's # reset() method was last called. This is checked first and if the # template is not found, the method then walks down the BLOCKSTACK # list. This contains references to the block definition tables in # any enclosing Template::Documents that we're visiting (e.g. we've # been called via an INCLUDE and we want to access a BLOCK defined in # the template that INCLUDE'd us). If nothing is defined, then we # iterate through the LOAD_TEMPLATES providers list as a 'chain of # responsibility' (see Design Patterns) asking each object to fetch() # the template if it can. # # Returns the compiled template. On error, undef is returned and # the internal ERROR value (read via error()) is set to contain an # error message of the form "$name: $error". #------------------------------------------------------------------------ sub template { my ($self, $name) = @_; my ($prefix, $blocks, $defblocks, $provider, $template, $error); my ($shortname, $blockname, $providers); $self->debug("template($name)") if $self->{ DEBUG }; # references to Template::Document (or sub-class) objects objects, or # CODE references are assumed to be pre-compiled templates and are # returned intact return $name if UNIVERSAL::isa($name, 'Template::Document') || ref($name) eq 'CODE'; $shortname = $name; unless (ref $name) { $self->debug("looking for block [$name]") if $self->{ DEBUG }; # we first look in the BLOCKS hash for a BLOCK that may have # been imported from a template (via PROCESS) return $template if ($template = $self->{ BLOCKS }->{ $name }); # then we iterate through the BLKSTACK list to see if any of the # Template::Documents we're visiting define this BLOCK foreach $blocks (@{ $self->{ BLKSTACK } }) { return $template if $blocks && ($template = $blocks->{ $name }); } # now it's time to ask the providers, so we look to see if any # prefix is specified to indicate the desired provider set. if ($^O eq 'MSWin32') { # let C:/foo through $prefix = $1 if $shortname =~ s/^(\w{2,})://o; } else { $prefix = $1 if $shortname =~ s/^(\w+)://; } if (defined $prefix) { $providers = $self->{ PREFIX_MAP }->{ $prefix } || return $self->throw(Template::Constants::ERROR_FILE, "no providers for template prefix '$prefix'"); } } $providers = $self->{ PREFIX_MAP }->{ default } || $self->{ LOAD_TEMPLATES } unless $providers; # Finally we try the regular template providers which will # handle references to files, text, etc., as well as templates # reference by name. If $blockname = ''; while ($shortname) { $self->debug("asking providers for [$shortname] [$blockname]") if $self->{ DEBUG }; foreach my $provider (@$providers) { ($template, $error) = $provider->fetch($shortname, $prefix); if ($error) { if ($error == Template::Constants::STATUS_ERROR) { # $template contains exception object if (UNIVERSAL::isa($template, 'Template::Exception') && $template->type() eq Template::Constants::ERROR_FILE) { $self->throw($template); } else { $self->throw( Template::Constants::ERROR_FILE, $template ); } } # DECLINE is ok, carry on } elsif (length $blockname) { return $template if $template = $template->blocks->{ $blockname }; } else { return $template; } } last if ref $shortname || ! $self->{ EXPOSE_BLOCKS }; $shortname =~ s{/([^/]+)$}{} || last; $blockname = length $blockname ? "$1/$blockname" : $1; } $self->throw(Template::Constants::ERROR_FILE, "$name: not found"); } #------------------------------------------------------------------------ # plugin($name, \@args) # # Calls on each of the LOAD_PLUGINS providers in turn to fetch() (i.e. load # and instantiate) a plugin of the specified name. Additional parameters # passed are propagated to the new() constructor for the plugin. # Returns a reference to a new plugin object or other reference. On # error, undef is returned and the appropriate error message is set for # subsequent retrieval via error(). #------------------------------------------------------------------------ sub plugin { my ($self, $name, $args) = @_; my ($provider, $plugin, $error); $self->debug("plugin($name, ", defined $args ? @$args : '[ ]', ')') if $self->{ DEBUG }; # request the named plugin from each of the LOAD_PLUGINS providers in turn foreach my $provider (@{ $self->{ LOAD_PLUGINS } }) { ($plugin, $error) = $provider->fetch($name, $args, $self); return $plugin unless $error; if ($error == Template::Constants::STATUS_ERROR) { $self->throw($plugin) if ref $plugin; $self->throw(Template::Constants::ERROR_PLUGIN, $plugin); } } $self->throw(Template::Constants::ERROR_PLUGIN, "$name: plugin not found"); } #------------------------------------------------------------------------ # filter($name, \@args, $alias) # # Similar to plugin() above, but querying the LOAD_FILTERS providers to # return filter instances. An alias may be provided which is used to # save the returned filter in a local cache. #------------------------------------------------------------------------ sub filter { my ($self, $name, $args, $alias) = @_; my ($provider, $filter, $error); $self->debug("filter($name, ", defined $args ? @$args : '[ ]', defined $alias ? $alias : '', ')') if $self->{ DEBUG }; # use any cached version of the filter if no params provided return $filter if ! $args && ! ref $name && ($filter = $self->{ FILTER_CACHE }->{ $name }); # request the named filter from each of the FILTERS providers in turn foreach my $provider (@{ $self->{ LOAD_FILTERS } }) { ($filter, $error) = $provider->fetch($name, $args, $self); last unless $error; if ($error == Template::Constants::STATUS_ERROR) { $self->throw($filter) if ref $filter; $self->throw(Template::Constants::ERROR_FILTER, $filter); } # return $self->error($filter) # if $error == &Template::Constants::STATUS_ERROR; } return $self->error("$name: filter not found") unless $filter; # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # commented out by abw on 19 Nov 2001 to fix problem with xmlstyle # plugin which may re-define a filter by calling define_filter() # multiple times. With the automatic aliasing/caching below, any # new filter definition isn't seen. Don't think this will cause # any problems as filters explicitly supplied with aliases will # still work as expected. # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # alias defaults to name if undefined # $alias = $name # unless defined($alias) or ref($name) or $args; # cache FILTER if alias is valid $self->{ FILTER_CACHE }->{ $alias } = $filter if $alias; return $filter; } #------------------------------------------------------------------------ # view(\%config) # # Create a new Template::View bound to this context. #------------------------------------------------------------------------ sub view { my $self = shift; require Template::View; return Template::View->new($self, @_) || $self->throw(&Template::Constants::ERROR_VIEW, $Template::View::ERROR); } #------------------------------------------------------------------------ # process($template, \%params) [% PROCESS template var=val ... %] # process($template, \%params, $local) [% INCLUDE template var=val ... %] # # Processes the template named or referenced by the first parameter. # The optional second parameter may reference a hash array of variable # definitions. These are set before the template is processed by # calling update() on the stash. Note that, unless the third parameter # is true, the context is not localised and these, and any other # variables set in the template will retain their new values after this # method returns. The third parameter is in place so that this method # can handle INCLUDE calls: the stash will be localized. # # Returns the output of processing the template. Errors are thrown # as Template::Exception objects via die(). #------------------------------------------------------------------------ sub process { my ($self, $template, $params, $localize) = @_; my ($trim, $blocks) = @$self{ qw( TRIM BLOCKS ) }; my (@compiled, $name, $compiled); my ($stash, $tblocks, $error, $tmpout); my $output = ''; $template = [ $template ] unless ref $template eq 'ARRAY'; $self->debug("process([ ", join(', '), @$template, ' ], ', defined $params ? $params : '', ', ', $localize ? '' : '', ')') if $self->{ DEBUG }; # fetch compiled template for each name specified foreach $name (@$template) { push(@compiled, $self->template($name)); } if ($localize) { # localise the variable stash with any parameters passed $stash = $self->{ STASH } = $self->{ STASH }->clone($params); } else { # update stash with any new parameters passed $self->{ STASH }->update($params); $stash = $self->{ STASH }; } eval { foreach $name (@$template) { $compiled = shift @compiled; my $element = ref $compiled eq 'CODE' ? { (name => (ref $name ? '' : $name), modtime => time()) } : $compiled; $stash->set('component', $element); unless ($localize) { # merge any local blocks defined in the Template::Document # into our local BLOCKS cache @$blocks{ keys %$tblocks } = values %$tblocks if UNIVERSAL::isa($compiled, 'Template::Document') && ($tblocks = $compiled->blocks()); } if (ref $compiled eq 'CODE') { $tmpout = &$compiled($self); } elsif (ref $compiled) { $tmpout = $compiled->process($self); } else { $self->throw('file', "invalid template reference: $compiled"); } if ($trim) { for ($tmpout) { s/^\s+//; s/\s+$//; } } $output .= $tmpout; } }; $error = $@; if ($localize) { # ensure stash is delocalised before dying $self->{ STASH } = $self->{ STASH }->declone(); } $self->throw(ref $error ? $error : (Template::Constants::ERROR_FILE, $error)) if $error; return $output; } #------------------------------------------------------------------------ # include($template, \%params) [% INCLUDE template var = val, ... %] # # Similar to process() above but processing the template in a local # context. Any variables passed by reference to a hash as the second # parameter will be set before the template is processed and then # revert to their original values before the method returns. Similarly, # any changes made to non-global variables within the template will # persist only until the template is processed. # # Returns the output of processing the template. Errors are thrown # as Template::Exception objects via die(). #------------------------------------------------------------------------ sub include { my ($self, $template, $params) = @_; return $self->process($template, $params, 'localize me!'); } #------------------------------------------------------------------------ # insert($file) # # Insert the contents of a file without parsing. #------------------------------------------------------------------------ sub insert { my ($self, $file) = @_; my ($prefix, $providers, $text, $error); my $output = ''; my $files = ref $file eq 'ARRAY' ? $file : [ $file ]; $self->debug("insert([ ", join(', '), @$files, " ])") if $self->{ DEBUG }; FILE: foreach $file (@$files) { my $name = $file; if ($^O eq 'MSWin32') { # let C:/foo through $prefix = $1 if $name =~ s/^(\w{2,})://o; } else { $prefix = $1 if $name =~ s/^(\w+)://; } if (defined $prefix) { $providers = $self->{ PREFIX_MAP }->{ $prefix } || return $self->throw(Template::Constants::ERROR_FILE, "no providers for file prefix '$prefix'"); } else { $providers = $self->{ PREFIX_MAP }->{ default } || $self->{ LOAD_TEMPLATES }; } foreach my $provider (@$providers) { ($text, $error) = $provider->load($name, $prefix); next FILE unless $error; if ($error == Template::Constants::STATUS_ERROR) { $self->throw($text) if ref $text; $self->throw(Template::Constants::ERROR_FILE, $text); } } $self->throw(Template::Constants::ERROR_FILE, "$file: not found"); } continue { $output .= $text; } return $output; } #------------------------------------------------------------------------ # throw($type, $info, \$output) [% THROW errtype "Error info" %] # # Throws a Template::Exception object by calling die(). This method # may be passed a reference to an existing Template::Exception object; # a single value containing an error message which is used to # instantiate a Template::Exception of type 'undef'; or a pair of # values representing the exception type and info from which a # Template::Exception object is instantiated. e.g. # # $context->throw($exception); # $context->throw("I'm sorry Dave, I can't do that"); # $context->throw('denied', "I'm sorry Dave, I can't do that"); # # An optional third parameter can be supplied in the last case which # is a reference to the current output buffer containing the results # of processing the template up to the point at which the exception # was thrown. The RETURN and STOP directives, for example, use this # to propagate output back to the user, but it can safely be ignored # in most cases. # # This method rides on a one-way ticket to die() oblivion. It does not # return in any real sense of the word, but should get caught by a # surrounding eval { } block (e.g. a BLOCK or TRY) and handled # accordingly, or returned to the caller as an uncaught exception. #------------------------------------------------------------------------ sub throw { my ($self, $error, $info, $output) = @_; local $" = ', '; # die! die! die! if (UNIVERSAL::isa($error, 'Template::Exception')) { die $error; } elsif (defined $info) { die (Template::Exception->new($error, $info, $output)); } else { $error ||= ''; die (Template::Exception->new('undef', $error, $output)); } # not reached } #------------------------------------------------------------------------ # catch($error, \$output) # # Called by various directives after catching an error thrown via die() # from within an eval { } block. The first parameter contains the errror # which may be a sanitized reference to a Template::Exception object # (such as that raised by the throw() method above, a plugin object, # and so on) or an error message thrown via die from somewhere in user # code. The latter are coerced into 'undef' Template::Exception objects. # Like throw() above, a reference to a scalar may be passed as an # additional parameter to represent the current output buffer # localised within the eval block. As exceptions are thrown upwards # and outwards from nested blocks, the catch() method reconstructs the # correct output buffer from these fragments, storing it in the # exception object for passing further onwards and upwards. # # Returns a reference to a Template::Exception object.. #------------------------------------------------------------------------ sub catch { my ($self, $error, $output) = @_; if (UNIVERSAL::isa($error, 'Template::Exception')) { $error->text($output) if $output; return $error; } else { return Template::Exception->new('undef', $error, $output); } } #------------------------------------------------------------------------ # localise(\%params) # delocalise() # # The localise() method creates a local copy of the current stash, # allowing the existing state of variables to be saved and later # restored via delocalise(). # # A reference to a hash array may be passed containing local variable # definitions which should be added to the cloned namespace. These # values persist until delocalisation. #------------------------------------------------------------------------ sub localise { my $self = shift; $self->{ STASH } = $self->{ STASH }->clone(@_); } sub delocalise { my $self = shift; $self->{ STASH } = $self->{ STASH }->declone(); } #------------------------------------------------------------------------ # visit($blocks) # # Each Template::Document calls the visit() method on the context # before processing itself. It passes a reference to the hash array # of named BLOCKs defined within the document, allowing them to be # added to the internal BLKSTACK list which is subsequently used by # template() to resolve templates. # from a provider. #------------------------------------------------------------------------ sub visit { my ($self, $blocks) = @_; unshift(@{ $self->{ BLKSTACK } }, $blocks) } #------------------------------------------------------------------------ # leave() # # The leave() method is called when the document has finished # processing itself. This removes the entry from the BLKSTACK list # that was added visit() above. For persistance of BLOCK definitions, # the process() method (i.e. the PROCESS directive) does some extra # magic to copy BLOCKs into a shared hash. #------------------------------------------------------------------------ sub leave { my $self = shift; shift(@{ $self->{ BLKSTACK } }); } #------------------------------------------------------------------------ # define_block($name, $block) # # Adds a new BLOCK definition to the local BLOCKS cache. $block may # be specified as a reference to a sub-routine or Template::Document # object or as text which is compiled into a template. Returns a true # value (the $block reference or compiled block reference) if # succesful or undef on failure. Call error() to retrieve the # relevent error message (i.e. compilation failure). #------------------------------------------------------------------------ sub define_block { my ($self, $name, $block) = @_; $block = $self->template(\$block) || return undef unless ref $block; $self->{ BLOCKS }->{ $name } = $block; } #------------------------------------------------------------------------ # define_filter($name, $filter, $is_dynamic) # # Adds a new FILTER definition to the local FILTER_CACHE. #------------------------------------------------------------------------ sub define_filter { my ($self, $name, $filter, $is_dynamic) = @_; my ($result, $error); $filter = [ $filter, 1 ] if $is_dynamic; foreach my $provider (@{ $self->{ LOAD_FILTERS } }) { ($result, $error) = $provider->store($name, $filter); return 1 unless $error; $self->throw(&Template::Constants::ERROR_FILTER, $result) if $error == &Template::Constants::STATUS_ERROR; } $self->throw(&Template::Constants::ERROR_FILTER, "FILTER providers declined to store filter $name"); } #------------------------------------------------------------------------ # reset() # # Reset the state of the internal BLOCKS hash to clear any BLOCK # definitions imported via the PROCESS directive. Any original # BLOCKS definitions passed to the constructor will be restored. #------------------------------------------------------------------------ sub reset { my ($self, $blocks) = @_; $self->{ BLKSTACK } = [ ]; $self->{ BLOCKS } = { %{ $self->{ INIT_BLOCKS } } }; } #------------------------------------------------------------------------ # stash() # # Simple accessor methods to return the STASH values. This is likely # to be called quite often so we provide a direct method rather than # relying on the slower AUTOLOAD. #------------------------------------------------------------------------ sub stash { return $_[0]->{ STASH }; } #------------------------------------------------------------------------ # define_vmethod($type, $name, \&sub) # # Passes $type, $name, and &sub on to stash->define_vmethod(). #------------------------------------------------------------------------ sub define_vmethod { my $self = shift; $self->stash->define_vmethod(@_); } #------------------------------------------------------------------------ # debugging($command, @args, \%params) # # Method for controlling the debugging status of the context. The first # argument can be 'on' or 'off' to enable/disable debugging, 'format' # to define the format of the debug message, or 'msg' to generate a # debugging message reporting the file, line, message text, etc., # according to the current debug format. #------------------------------------------------------------------------ sub debugging { my $self = shift; my $hash = ref $_[-1] eq 'HASH' ? pop : { }; my @args = @_; # print "*** debug(@args)\n"; if (@args) { if ($args[0] =~ /^on|1$/i) { $self->{ DEBUG_DIRS } = 1; shift(@args); } elsif ($args[0] =~ /^off|0$/i) { $self->{ DEBUG_DIRS } = 0; shift(@args); } } if (@args) { if ($args[0] =~ /^msg$/i) { return unless $self->{ DEBUG_DIRS }; my $format = $self->{ DEBUG_FORMAT }; $format = $DEBUG_FORMAT unless defined $format; $format =~ s/\$(\w+)/$hash->{ $1 }/ge; return $format; } elsif ($args[0] =~ /^format$/i) { $self->{ DEBUG_FORMAT } = $args[1]; } # else ignore } return ''; } #------------------------------------------------------------------------ # AUTOLOAD # # Provides pseudo-methods for read-only access to various internal # members. For example, templates(), plugins(), filters(), # eval_perl(), load_perl(), etc. These aren't called very often, or # may never be called at all. #------------------------------------------------------------------------ sub AUTOLOAD { my $self = shift; my $method = $AUTOLOAD; my $result; $method =~ s/.*:://; return if $method eq 'DESTROY'; warn "no such context method/member: $method\n" unless defined ($result = $self->{ uc $method }); return $result; } #------------------------------------------------------------------------ # DESTROY # # Stash may contain references back to the Context via macro closures, # etc. This breaks the circular references. #------------------------------------------------------------------------ sub DESTROY { my $self = shift; undef $self->{ STASH }; } #======================================================================== # -- PRIVATE METHODS -- #======================================================================== #------------------------------------------------------------------------ # _init(\%config) # # Initialisation method called by Template::Base::new() #------------------------------------------------------------------------ sub _init { my ($self, $config) = @_; my ($name, $item, $method, $block, $blocks); my @itemlut = ( LOAD_TEMPLATES => 'provider', LOAD_PLUGINS => 'plugins', LOAD_FILTERS => 'filters' ); # LOAD_TEMPLATE, LOAD_PLUGINS, LOAD_FILTERS - lists of providers while (($name, $method) = splice(@itemlut, 0, 2)) { $item = $config->{ $name } || Template::Config->$method($config) || return $self->error($Template::Config::ERROR); $self->{ $name } = ref $item eq 'ARRAY' ? $item : [ $item ]; } my $providers = $self->{ LOAD_TEMPLATES }; my $prefix_map = $self->{ PREFIX_MAP } = $config->{ PREFIX_MAP } || { }; while (my ($key, $val) = each %$prefix_map) { $prefix_map->{ $key } = [ ref $val ? $val : map { $providers->[$_] } split(/\D+/, $val) ] unless ref $val eq 'ARRAY'; # print(STDERR "prefix $key => $val => [", # join(', ', @{ $prefix_map->{ $key } }), "]\n"); } # STASH $self->{ STASH } = $config->{ STASH } || do { my $predefs = $config->{ VARIABLES } || $config->{ PRE_DEFINE } || { }; # hack to get stash to know about debug mode $predefs->{ _DEBUG } = ( ($config->{ DEBUG } || 0) & &Template::Constants::DEBUG_UNDEF ) ? 1 : 0 unless defined $predefs->{ _DEBUG }; Template::Config->stash($predefs) || return $self->error($Template::Config::ERROR); }; # compile any template BLOCKS specified as text $blocks = $config->{ BLOCKS } || { }; $self->{ INIT_BLOCKS } = $self->{ BLOCKS } = { map { $block = $blocks->{ $_ }; $block = $self->template(\$block) || return undef unless ref $block; ($_ => $block); } keys %$blocks }; # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # RECURSION - flag indicating is recursion into templates is supported # EVAL_PERL - flag indicating if PERL blocks should be processed # TRIM - flag to remove leading and trailing whitespace from output # BLKSTACK - list of hashes of BLOCKs defined in current template(s) # CONFIG - original configuration hash # EXPOSE_BLOCKS - make blocks visible as pseudo-files # DEBUG_FORMAT - format for generating template runtime debugging messages # DEBUG - format for generating template runtime debugging messages $self->{ RECURSION } = $config->{ RECURSION } || 0; $self->{ EVAL_PERL } = $config->{ EVAL_PERL } || 0; $self->{ TRIM } = $config->{ TRIM } || 0; $self->{ BLKSTACK } = [ ]; $self->{ CONFIG } = $config; $self->{ EXPOSE_BLOCKS } = defined $config->{ EXPOSE_BLOCKS } ? $config->{ EXPOSE_BLOCKS } : 0; $self->{ DEBUG_FORMAT } = $config->{ DEBUG_FORMAT }; $self->{ DEBUG_DIRS } = ($config->{ DEBUG } || 0) & Template::Constants::DEBUG_DIRS; $self->{ DEBUG } = defined $config->{ DEBUG } ? $config->{ DEBUG } & ( Template::Constants::DEBUG_CONTEXT | Template::Constants::DEBUG_FLAGS ) : $DEBUG; return $self; } #------------------------------------------------------------------------ # _dump() # # Debug method which returns a string representing the internal state # of the context object. #------------------------------------------------------------------------ sub _dump { my $self = shift; my $output = "[Template::Context] {\n"; my $format = " %-16s => %s\n"; my $key; foreach $key (qw( RECURSION EVAL_PERL TRIM )) { $output .= sprintf($format, $key, $self->{ $key }); } foreach my $pname (qw( LOAD_TEMPLATES LOAD_PLUGINS LOAD_FILTERS )) { my $provtext = "[\n"; foreach my $prov (@{ $self->{ $pname } }) { $provtext .= $prov->_dump(); # $provtext .= ",\n"; } $provtext =~ s/\n/\n /g; $provtext =~ s/\s+$//; $provtext .= ",\n ]"; $output .= sprintf($format, $pname, $provtext); } $output .= sprintf($format, STASH => $self->{ STASH }->_dump()); $output .= '}'; return $output; } 1; __END__ #------------------------------------------------------------------------ # IMPORTANT NOTE # This documentation is generated automatically from source # templates. Any changes you make here may be lost. # # The 'docsrc' documentation source bundle is available for download # from http://www.template-toolkit.org/docs.html and contains all # the source templates, XML files, scripts, etc., from which the # documentation for the Template Toolkit is built. #------------------------------------------------------------------------ =head1 NAME Template::Context - Runtime context in which templates are processed =head1 SYNOPSIS use Template::Context; # constructor $context = Template::Context->new(\%config) || die $Template::Context::ERROR; # fetch (load and compile) a template $template = $context->template($template_name); # fetch (load and instantiate) a plugin object $plugin = $context->plugin($name, \@args); # fetch (return or create) a filter subroutine $filter = $context->filter($name, \@args, $alias); # process/include a template, errors are thrown via die() $output = $context->process($template, \%vars); $output = $context->include($template, \%vars); # raise an exception via die() $context->throw($error_type, $error_message, \$output_buffer); # catch an exception, clean it up and fix output buffer $exception = $context->catch($exception, \$output_buffer); # save/restore the stash to effect variable localisation $new_stash = $context->localise(\%vars); $old_stash = $context->delocalise(); # add new BLOCK or FILTER definitions $context->define_block($name, $block); $context->define_filter($name, \&filtersub, $is_dynamic); # reset context, clearing any imported BLOCK definitions $context->reset(); # methods for accessing internal items $stash = $context->stash(); $tflag = $context->trim(); $epflag = $context->eval_perl(); $providers = $context->templates(); $providers = $context->plugins(); $providers = $context->filters(); ... =head1 DESCRIPTION The Template::Context module defines an object class for representing a runtime context in which templates are processed. It provides an interface to the fundamental operations of the Template Toolkit processing engine through which compiled templates (i.e. Perl code constructed from the template source) can process templates, load plugins and filters, raise exceptions and so on. A default Template::Context object is created by the Template module. Any Template::Context options may be passed to the Template new() constructor method and will be forwarded to the Template::Context constructor. use Template; my $template = Template->new({ TRIM => 1, EVAL_PERL => 1, BLOCKS => { header => 'This is the header', footer => 'This is the footer', }, }); Similarly, the Template::Context constructor will forward all configuration parameters onto other default objects (e.g. Template::Provider, Template::Plugins, Template::Filters, etc.) that it may need to instantiate. $context = Template::Context->new({ INCLUDE_PATH => '/home/abw/templates', # provider option TAG_STYLE => 'html', # parser option }); A Template::Context object (or subclass/derivative) can be explicitly instantiated and passed to the Template new() constructor method as the CONTEXT item. use Template; use Template::Context; my $context = Template::Context->new({ TRIM => 1 }); my $template = Template->new({ CONTEXT => $context }); The Template module uses the Template::Config context() factory method to create a default context object when required. The $Template::Config::CONTEXT package variable may be set to specify an alternate context module. This will be loaded automatically and its new() constructor method called by the context() factory method when a default context object is required. use Template; $Template::Config::CONTEXT = 'MyOrg::Template::Context'; my $template = Template->new({ EVAL_PERL => 1, EXTRA_MAGIC => 'red hot', # your extra config items ... }); =head1 METHODS =head2 new(\%params) The new() constructor method is called to instantiate a Template::Context object. Configuration parameters may be specified as a HASH reference or as a list of (name =E value) pairs. my $context = Template::Context->new({ INCLUDE_PATH => 'header', POST_PROCESS => 'footer', }); my $context = Template::Context->new( EVAL_PERL => 1 ); The new() method returns a Template::Context object (or sub-class) or undef on error. In the latter case, a relevant error message can be retrieved by the error() class method or directly from the $Template::Context::ERROR package variable. my $context = Template::Context->new(\%config) || die Template::Context->error(); my $context = Template::Context->new(\%config) || die $Template::Context::ERROR; The following configuration items may be specified. =over 4 =item VARIABLES, PRE_DEFINE The VARIABLES option (or PRE_DEFINE - they're equivalent) can be used to specify a hash array of template variables that should be used to pre-initialise the stash when it is created. These items are ignored if the STASH item is defined. my $context = Template::Context->new({ VARIABLES => { title => 'A Demo Page', author => 'Joe Random Hacker', version => 3.14, }, }; or my $context = Template::Context->new({ PRE_DEFINE => { title => 'A Demo Page', author => 'Joe Random Hacker', version => 3.14, }, }; =item BLOCKS The BLOCKS option can be used to pre-define a default set of template blocks. These should be specified as a reference to a hash array mapping template names to template text, subroutines or Template::Document objects. my $context = Template::Context->new({ BLOCKS => { header => 'The Header. [% title %]', footer => sub { return $some_output_text }, another => Template::Document->new({ ... }), }, }); =item TRIM The TRIM option can be set to have any leading and trailing whitespace automatically removed from the output of all template files and BLOCKs. By example, the following BLOCK definition [% BLOCK foo %] Line 1 of foo [% END %] will be processed is as "\nLine 1 of foo\n". When INCLUDEd, the surrounding newlines will also be introduced. before [% INCLUDE foo %] after output: before Line 1 of foo after With the TRIM option set to any true value, the leading and trailing newlines (which count as whitespace) will be removed from the output of the BLOCK. before Line 1 of foo after The TRIM option is disabled (0) by default. =item EVAL_PERL This flag is used to indicate if PERL and/or RAWPERL blocks should be evaluated. By default, it is disabled and any PERL or RAWPERL blocks encountered will raise exceptions of type 'perl' with the message 'EVAL_PERL not set'. Note however that any RAWPERL blocks should always contain valid Perl code, regardless of the EVAL_PERL flag. The parser will fail to compile templates that contain invalid Perl code in RAWPERL blocks and will throw a 'file' exception. When using compiled templates (see L and L), the EVAL_PERL has an affect when the template is compiled, and again when the templates is subsequently processed, possibly in a different context to the one that compiled it. If the EVAL_PERL is set when a template is compiled, then all PERL and RAWPERL blocks will be included in the compiled template. If the EVAL_PERL option isn't set, then Perl code will be generated which B throws a 'perl' exception with the message 'EVAL_PERL not set' B the compiled template code is run. Thus, you must have EVAL_PERL set if you want your compiled templates to include PERL and RAWPERL blocks. At some point in the future, using a different invocation of the Template Toolkit, you may come to process such a pre-compiled template. Assuming the EVAL_PERL option was set at the time the template was compiled, then the output of any RAWPERL blocks will be included in the compiled template and will get executed when the template is processed. This will happen regardless of the runtime EVAL_PERL status. Regular PERL blocks are a little more cautious, however. If the EVAL_PERL flag isn't set for the I context, that is, the one which is trying to process it, then it will throw the familiar 'perl' exception with the message, 'EVAL_PERL not set'. Thus you can compile templates to include PERL blocks, but optionally disable them when you process them later. Note however that it is possible for a PERL block to contain a Perl "BEGIN { # some code }" block which will always get run regardless of the runtime EVAL_PERL status. Thus, if you set EVAL_PERL when compiling templates, it is assumed that you trust the templates to Do The Right Thing. Otherwise you must accept the fact that there's no bulletproof way to prevent any included code from trampling around in the living room of the runtime environment, making a real nuisance of itself if it really wants to. If you don't like the idea of such uninvited guests causing a bother, then you can accept the default and keep EVAL_PERL disabled. =item RECURSION The template processor will raise a file exception if it detects direct or indirect recursion into a template. Setting this option to any true value will allow templates to include each other recursively. =item LOAD_TEMPLATES The LOAD_TEMPLATE option can be used to provide a reference to a list of Template::Provider objects or sub-classes thereof which will take responsibility for loading and compiling templates. my $context = Template::Context->new({ LOAD_TEMPLATES => [ MyOrg::Template::Provider->new({ ... }), Template::Provider->new({ ... }), ], }); When a PROCESS, INCLUDE or WRAPPER directive is encountered, the named template may refer to a locally defined BLOCK or a file relative to the INCLUDE_PATH (or an absolute or relative path if the appropriate ABSOLUTE or RELATIVE options are set). If a BLOCK definition can't be found (see the Template::Context template() method for a discussion of BLOCK locality) then each of the LOAD_TEMPLATES provider objects is queried in turn via the fetch() method to see if it can supply the required template. Each provider can return a compiled template, an error, or decline to service the request in which case the responsibility is passed to the next provider. If none of the providers can service the request then a 'not found' error is returned. The same basic provider mechanism is also used for the INSERT directive but it bypasses any BLOCK definitions and doesn't attempt is to parse or process the contents of the template file. This is an implementation of the 'Chain of Responsibility' design pattern as described in "Design Patterns", Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides), Addision-Wesley, ISBN 0-201-63361-2, page 223 . If LOAD_TEMPLATES is undefined, a single default provider will be instantiated using the current configuration parameters. For example, the Template::Provider INCLUDE_PATH option can be specified in the Template::Context configuration and will be correctly passed to the provider's constructor method. my $context = Template::Context->new({ INCLUDE_PATH => '/here:/there', }); =item LOAD_PLUGINS The LOAD_PLUGINS options can be used to specify a list of provider objects (i.e. they implement the fetch() method) which are responsible for loading and instantiating template plugin objects. The Template::Content plugin() method queries each provider in turn in a "Chain of Responsibility" as per the template() and filter() methods. my $context = Template::Context->new({ LOAD_PLUGINS => [ MyOrg::Template::Plugins->new({ ... }), Template::Plugins->new({ ... }), ], }); By default, a single Template::Plugins object is created using the current configuration hash. Configuration items destined for the Template::Plugins constructor may be added to the Template::Context constructor. my $context = Template::Context->new({ PLUGIN_BASE => 'MyOrg::Template::Plugins', LOAD_PERL => 1, }); =item LOAD_FILTERS The LOAD_FILTERS option can be used to specify a list of provider objects (i.e. they implement the fetch() method) which are responsible for returning and/or creating filter subroutines. The Template::Context filter() method queries each provider in turn in a "Chain of Responsibility" as per the template() and plugin() methods. my $context = Template::Context->new({ LOAD_FILTERS => [ MyTemplate::Filters->new(), Template::Filters->new(), ], }); By default, a single Template::Filters object is created for the LOAD_FILTERS list. =item STASH A reference to a Template::Stash object or sub-class which will take responsibility for managing template variables. my $stash = MyOrg::Template::Stash->new({ ... }); my $context = Template::Context->new({ STASH => $stash, }); If unspecified, a default stash object is created using the VARIABLES configuration item to initialise the stash variables. These may also be specified as the PRE_DEFINE option for backwards compatibility with version 1. my $context = Template::Context->new({ VARIABLES => { id => 'abw', name => 'Andy Wardley', }, }; =item DEBUG The DEBUG option can be used to enable various debugging features of the Template::Context module. use Template::Constants qw( :debug ); my $template = Template->new({ DEBUG => DEBUG_CONTEXT | DEBUG_DIRS, }); The DEBUG value can include any of the following. Multiple values should be combined using the logical OR operator, '|'. =over 4 =item DEBUG_CONTEXT Enables general debugging messages for the L module. =item DEBUG_DIRS This option causes the Template Toolkit to generate comments indicating the source file, line and original text of each directive in the template. These comments are embedded in the template output using the format defined in the DEBUG_FORMAT configuration item, or a simple default format if unspecified. For example, the following template fragment: Hello World would generate this output: ## input text line 1 : ## Hello ## input text line 2 : World ## World =back =back =head2 template($name) Returns a compiled template by querying each of the LOAD_TEMPLATES providers (instances of Template::Provider, or sub-class) in turn. $template = $context->template('header'); On error, a Template::Exception object of type 'file' is thrown via die(). This can be caught by enclosing the call to template() in an eval block and examining $@. eval { $template = $context->template('header'); }; if ($@) { print "failed to fetch template: $@\n"; } =head2 plugin($name, \@args) Instantiates a plugin object by querying each of the LOAD_PLUGINS providers. The default LOAD_PLUGINS provider is a Template::Plugins object which attempts to load plugin modules, according the various configuration items such as PLUGIN_BASE, LOAD_PERL, etc., and then instantiate an object via new(). A reference to a list of constructor arguments may be passed as the second parameter. These are forwarded to the plugin constructor. Returns a reference to a plugin (which is generally an object, but doesn't have to be). Errors are thrown as Template::Exception objects of type 'plugin'. $plugin = $context->plugin('DBI', 'dbi:msql:mydbname'); =head2 filter($name, \@args, $alias) Instantiates a filter subroutine by querying the LOAD_FILTERS providers. The default LOAD_FILTERS providers is a Template::Filters object. Additional arguments may be passed by list reference along with an optional alias under which the filter will be cached for subsequent use. The filter is cached under its own $name if $alias is undefined. Subsequent calls to filter($name) will return the cached entry, if defined. Specifying arguments bypasses the caching mechanism and always creates a new filter. Errors are thrown as Template::Exception objects of typre 'filter'. # static filter (no args) $filter = $context->filter('html'); # dynamic filter (args) aliased to 'padright' $filter = $context->filter('format', '%60s', 'padright'); # retrieve previous filter via 'padright' alias $filter = $context->filter('padright'); =head2 process($template, \%vars) Processes a template named or referenced by the first parameter and returns the output generated. An optional reference to a hash array may be passed as the second parameter, containing variable definitions which will be set before the template is processed. The template is processed in the current context, with no localisation of variables performed. Errors are thrown as Template::Exception objects via die(). $output = $context->process('header', { title => 'Hello World' }); =head2 include($template, \%vars) Similar to process() above, but using localised variables. Changes made to any variables will only persist until the include() method completes. $output = $context->include('header', { title => 'Hello World' }); =head2 throw($error_type, $error_message, \$output) Raises an exception in the form of a Template::Exception object by calling die(). This method may be passed a reference to an existing Template::Exception object; a single value containing an error message which is used to instantiate a Template::Exception of type 'undef'; or a pair of values representing the exception type and info from which a Template::Exception object is instantiated. e.g. $context->throw($exception); $context->throw("I'm sorry Dave, I can't do that"); $context->throw('denied', "I'm sorry Dave, I can't do that"); The optional third parameter may be a reference to the current output buffer. This is then stored in the exception object when created, allowing the catcher to examine and use the output up to the point at which the exception was raised. $output .= 'blah blah blah'; $output .= 'more rhubarb'; $context->throw('yack', 'Too much yacking', \$output); =head2 catch($exception, \$output) Catches an exception thrown, either as a reference to a Template::Exception object or some other value. In the latter case, the error string is promoted to a Template::Exception object of 'undef' type. This method also accepts a reference to the current output buffer which is passed to the Template::Exception constructor, or is appended to the output buffer stored in an existing Template::Exception object, if unique (i.e. not the same reference). By this process, the correct state of the output buffer can be reconstructed for simple or nested throws. =head2 define_block($name, $block) Adds a new block definition to the internal BLOCKS cache. The first argument should contain the name of the block and the second a reference to a Template::Document object or template sub-routine, or template text which is automatically compiled into a template sub-routine. Returns a true value (the sub-routine or Template::Document reference) on success or undef on failure. The relevant error message can be retrieved by calling the error() method. =head2 define_filter($name, \&filter, $is_dynamic) Adds a new filter definition by calling the store() method on each of the LOAD_FILTERS providers until accepted (in the usual case, this is accepted straight away by the one and only Template::Filters provider). The first argument should contain the name of the filter and the second a reference to a filter subroutine. The optional third argument can be set to any true value to indicate that the subroutine is a dynamic filter factory. Returns a true value or throws a 'filter' exception on error. =head2 localise(\%vars) Clones the stash to create a context with localised variables. Returns a reference to the newly cloned stash object which is also stored internally. $stash = $context->localise(); =head2 delocalise() Restore the stash to its state prior to localisation. $stash = $context->delocalise(); =head2 visit(\%blocks) This method is called by Template::Document objects immediately before they process their content. It is called to register any local BLOCK definitions with the context object so that they may be subsequently delivered on request. =head2 leave() Compliment to visit(), above. Called by Template::Document objects immediately after they process their content. =head2 reset() Clears the local BLOCKS cache of any BLOCK definitions. Any initial set of BLOCKS specified as a configuration item to the constructor will be reinstated. =head2 AUTOLOAD An AUTOLOAD method provides access to context configuration items. $stash = $context->stash(); $tflag = $context->trim(); $epflag = $context->eval_perl(); ... =head1 AUTHOR Andy Wardley Eabw@andywardley.comE L =head1 VERSION 2.81, distributed as part of the Template Toolkit version 2.10, released on 24 July 2003. =head1 COPYRIGHT Copyright (C) 1996-2003 Andy Wardley. All Rights Reserved. Copyright (C) 1998-2002 Canon Research Centre Europe Ltd. This module is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =head1 SEE ALSO L, L, L, L, L, L, L, L vdradmin-am-3.6.13/lib/Template/Directive.pm000066400000000000000000000647231443716113400206200ustar00rootroot00000000000000#================================================================= -*-Perl-*- # # Template::Directive # # DESCRIPTION # Factory module for constructing templates from Perl code. # # AUTHOR # Andy Wardley # # WARNING # Much of this module is hairy, even furry in places. It needs # a lot of tidying up and may even be moved into a different place # altogether. The generator code is often inefficient, particulary in # being very anal about pretty-printing the Perl code all neatly, but # at the moment, that's still high priority for the sake of easier # debugging. # # COPYRIGHT # Copyright (C) 1996-2000 Andy Wardley. All Rights Reserved. # Copyright (C) 1998-2000 Canon Research Centre Europe Ltd. # # This module is free software; you can redistribute it and/or # modify it under the same terms as Perl itself. # #---------------------------------------------------------------------------- # # $Id: Directive.pm,v 2.17 2002/08/08 11:59:15 abw Exp $ # #============================================================================ package Template::Directive; require 5.004; use strict; use Template::Base; use Template::Constants; use Template::Exception; use base qw( Template::Base ); use vars qw( $VERSION $DEBUG $PRETTY $WHILE_MAX ); $VERSION = sprintf("%d.%02d", q$Revision: 2.17 $ =~ /(\d+)\.(\d+)/); $WHILE_MAX = 1000 unless defined $WHILE_MAX; $PRETTY = 0 unless defined $PRETTY; my $OUTPUT = '$output .= '; sub _init { my ($self, $config) = @_; $self->{ NAMESPACE } = $config->{ NAMESPACE }; return $self; } sub pad { my ($text, $pad) = @_; $pad = ' ' x ($pad * 4); $text =~ s/^(?!#line)/$pad/gm; $text; } #======================================================================== # FACTORY METHODS # # These methods are called by the parser to construct directive instances. #======================================================================== #------------------------------------------------------------------------ # template($block) #------------------------------------------------------------------------ sub template { my ($class, $block) = @_; $block = pad($block, 2) if $PRETTY; return "sub { return '' }" unless $block =~ /\S/; return <stash; my \$output = ''; my \$error; eval { BLOCK: { $block } }; if (\$@) { \$error = \$context->catch(\$@, \\\$output); die \$error unless \$error->type eq 'return'; } return \$output; } EOF } #------------------------------------------------------------------------ # anon_block($block) [% BLOCK %] ... [% END %] #------------------------------------------------------------------------ sub anon_block { my ($class, $block) = @_; $block = pad($block, 2) if $PRETTY; return <catch(\$@, \\\$output); die \$error unless \$error->type eq 'return'; } \$output; }; EOF } #------------------------------------------------------------------------ # block($blocktext) #------------------------------------------------------------------------ sub block { my ($class, $block) = @_; return join("\n", @{ $block || [] }); } #------------------------------------------------------------------------ # textblock($text) #------------------------------------------------------------------------ sub textblock { my ($class, $text) = @_; return "$OUTPUT " . &text($class, $text) . ';'; } #------------------------------------------------------------------------ # text($text) #------------------------------------------------------------------------ sub text { my ($class, $text) = @_; for ($text) { s/(["\$\@\\])/\\$1/g; s/\n/\\n/g; } return '"' . $text . '"'; } #------------------------------------------------------------------------ # quoted(\@items) "foo$bar" #------------------------------------------------------------------------ sub quoted { my ($class, $items) = @_; return '' unless @$items; return ("('' . " . $items->[0] . ')') if scalar @$items == 1; return '(' . join(' . ', @$items) . ')'; # my $r = '(' . join(' . ', @$items) . ' . "")'; # print STDERR "[$r]\n"; # return $r; } #------------------------------------------------------------------------ # ident(\@ident) foo.bar(baz) #------------------------------------------------------------------------ sub ident { my ($class, $ident) = @_; return "''" unless @$ident; my $ns; # does the first element of the identifier have a NAMESPACE # handler defined? if (ref $class && @$ident > 2 && ($ns = $class->{ NAMESPACE })) { my $key = $ident->[0]; $key =~ s/^'(.+)'$/$1/s; if ($ns = $ns->{ $key }) { return $ns->ident($ident); } } if (scalar @$ident <= 2 && ! $ident->[1]) { $ident = $ident->[0]; } else { $ident = '[' . join(', ', @$ident) . ']'; } return "\$stash->get($ident)"; } #------------------------------------------------------------------------ # identref(\@ident) \foo.bar(baz) #------------------------------------------------------------------------ sub identref { my ($class, $ident) = @_; return "''" unless @$ident; if (scalar @$ident <= 2 && ! $ident->[1]) { $ident = $ident->[0]; } else { $ident = '[' . join(', ', @$ident) . ']'; } return "\$stash->getref($ident)"; } #------------------------------------------------------------------------ # assign(\@ident, $value, $default) foo = bar #------------------------------------------------------------------------ sub assign { my ($class, $var, $val, $default) = @_; if (ref $var) { if (scalar @$var == 2 && ! $var->[1]) { $var = $var->[0]; } else { $var = '[' . join(', ', @$var) . ']'; } } $val .= ', 1' if $default; return "\$stash->set($var, $val)"; } #------------------------------------------------------------------------ # args(\@args) foo, bar, baz = qux #------------------------------------------------------------------------ sub args { my ($class, $args) = @_; my $hash = shift @$args; push(@$args, '{ ' . join(', ', @$hash) . ' }') if @$hash; return '0' unless @$args; return '[ ' . join(', ', @$args) . ' ]'; } #------------------------------------------------------------------------ # filenames(\@names) #------------------------------------------------------------------------ sub filenames { my ($class, $names) = @_; if (@$names > 1) { $names = '[ ' . join(', ', @$names) . ' ]'; } else { $names = shift @$names; } return $names; } #------------------------------------------------------------------------ # get($expr) [% foo %] #------------------------------------------------------------------------ sub get { my ($class, $expr) = @_; return "$OUTPUT $expr;"; } #------------------------------------------------------------------------ # call($expr) [% CALL bar %] #------------------------------------------------------------------------ sub call { my ($class, $expr) = @_; $expr .= ';'; return $expr; } #------------------------------------------------------------------------ # set(\@setlist) [% foo = bar, baz = qux %] #------------------------------------------------------------------------ sub set { my ($class, $setlist) = @_; my $output; while (my ($var, $val) = splice(@$setlist, 0, 2)) { $output .= &assign($class, $var, $val) . ";\n"; } chomp $output; return $output; } #------------------------------------------------------------------------ # default(\@setlist) [% DEFAULT foo = bar, baz = qux %] #------------------------------------------------------------------------ sub default { my ($class, $setlist) = @_; my $output; while (my ($var, $val) = splice(@$setlist, 0, 2)) { $output .= &assign($class, $var, $val, 1) . ";\n"; } chomp $output; return $output; } #------------------------------------------------------------------------ # insert(\@nameargs) [% INSERT file %] # # => [ [ $file, ... ], \@args ] #------------------------------------------------------------------------ sub insert { my ($class, $nameargs) = @_; my ($file, $args) = @$nameargs; $file = $class->filenames($file); return "$OUTPUT \$context->insert($file);"; } #------------------------------------------------------------------------ # include(\@nameargs) [% INCLUDE template foo = bar %] # # => [ [ $file, ... ], \@args ] #------------------------------------------------------------------------ sub include { my ($class, $nameargs) = @_; my ($file, $args) = @$nameargs; my $hash = shift @$args; $file = $class->filenames($file); $file .= @$hash ? ', { ' . join(', ', @$hash) . ' }' : ''; return "$OUTPUT \$context->include($file);"; } #------------------------------------------------------------------------ # process(\@nameargs) [% PROCESS template foo = bar %] # # => [ [ $file, ... ], \@args ] #------------------------------------------------------------------------ sub process { my ($class, $nameargs) = @_; my ($file, $args) = @$nameargs; my $hash = shift @$args; $file = $class->filenames($file); $file .= @$hash ? ', { ' . join(', ', @$hash) . ' }' : ''; return "$OUTPUT \$context->process($file);"; } #------------------------------------------------------------------------ # if($expr, $block, $else) [% IF foo < bar %] # ... # [% ELSE %] # ... # [% END %] #------------------------------------------------------------------------ sub if { my ($class, $expr, $block, $else) = @_; my @else = $else ? @$else : (); $else = pop @else; $block = pad($block, 1) if $PRETTY; my $output = "if ($expr) {\n$block\n}\n"; foreach my $elsif (@else) { ($expr, $block) = @$elsif; $block = pad($block, 1) if $PRETTY; $output .= "elsif ($expr) {\n$block\n}\n"; } if (defined $else) { $else = pad($else, 1) if $PRETTY; $output .= "else {\n$else\n}\n"; } return $output; } #------------------------------------------------------------------------ # foreach($target, $list, $args, $block) [% FOREACH x = [ foo bar ] %] # ... # [% END %] #------------------------------------------------------------------------ sub foreach { my ($class, $target, $list, $args, $block) = @_; $args = shift @$args; $args = @$args ? ', { ' . join(', ', @$args) . ' }' : ''; my ($loop_save, $loop_set, $loop_restore, $setiter); if ($target) { $loop_save = 'eval { $oldloop = ' . &ident($class, ["'loop'"]) . ' }'; $loop_set = "\$stash->{'$target'} = \$value"; $loop_restore = "\$stash->set('loop', \$oldloop)"; } else { $loop_save = '$stash = $context->localise()'; # $loop_set = "\$stash->set('import', \$value) " # . "if ref \$value eq 'HASH'"; $loop_set = "\$stash->get(['import', [\$value]]) " . "if ref \$value eq 'HASH'"; $loop_restore = '$stash = $context->delocalise()'; } $block = pad($block, 3) if $PRETTY; return <iterator(\$list) || die \$Template::Config::ERROR, "\\n"; } (\$value, \$error) = \$list->get_first(); $loop_save; \$stash->set('loop', \$list); eval { LOOP: while (! \$error) { $loop_set; $block; (\$value, \$error) = \$list->get_next(); } }; $loop_restore; die \$@ if \$@; \$error = 0 if \$error && \$error eq Template::Constants::STATUS_DONE; die \$error if \$error; }; EOF } #------------------------------------------------------------------------ # next() [% NEXT %] # # Next iteration of a FOREACH loop (experimental) #------------------------------------------------------------------------ sub next { return <get_next(); next LOOP; EOF } #------------------------------------------------------------------------ # wrapper(\@nameargs, $block) [% WRAPPER template foo = bar %] # # => [ [$file,...], \@args ] #------------------------------------------------------------------------ sub wrapper { my ($class, $nameargs, $block) = @_; my ($file, $args) = @$nameargs; my $hash = shift @$args; local $" = ', '; # print STDERR "wrapper([@$file], { @$hash })\n"; return $class->multi_wrapper($file, $hash, $block) if @$file > 1; $file = shift @$file; $block = pad($block, 1) if $PRETTY; push(@$hash, "'content'", '$output'); $file .= @$hash ? ', { ' . join(', ', @$hash) . ' }' : ''; return <include($file); }; EOF } sub multi_wrapper { my ($class, $file, $hash, $block) = @_; $block = pad($block, 1) if $PRETTY; push(@$hash, "'content'", '$output'); $hash = @$hash ? ', { ' . join(', ', @$hash) . ' }' : ''; $file = join(', ', reverse @$file); # print STDERR "multi wrapper: $file\n"; return <include(\$_$hash); } \$output; }; EOF } #------------------------------------------------------------------------ # while($expr, $block) [% WHILE x < 10 %] # ... # [% END %] #------------------------------------------------------------------------ sub while { my ($class, $expr, $block) = @_; $block = pad($block, 2) if $PRETTY; return < $WHILE_MAX iterations)\\n" unless \$failsafe; }; EOF } #------------------------------------------------------------------------ # switch($expr, \@case) [% SWITCH %] # [% CASE foo %] # ... # [% END %] #------------------------------------------------------------------------ sub switch { my ($class, $expr, $case) = @_; my @case = @$case; my ($match, $block, $default); my $caseblock = ''; $default = pop @case; foreach $case (@case) { $match = $case->[0]; $block = $case->[1]; $block = pad($block, 1) if $PRETTY; $caseblock .= <[0] || do { $default ||= $catch->[1]; next; }; $mblock = $catch->[1]; $mblock = pad($mblock, 1) if $PRETTY; push(@$handlers, "'$match'"); $catchblock .= $n++ ? "elsif (\$handler eq '$match') {\n$mblock\n}\n" : "if (\$handler eq '$match') {\n$mblock\n}\n"; } $catchblock .= "\$error = 0;"; $catchblock = pad($catchblock, 3) if $PRETTY; if ($default) { $default = pad($default, 1) if $PRETTY; $default = "else {\n # DEFAULT\n$default\n \$error = '';\n}"; } else { $default = '# NO DEFAULT'; } $default = pad($default, 2) if $PRETTY; $handlers = join(', ', @$handlers); return <catch(\$@, \\\$output); die \$error if \$error->type =~ /^return|stop\$/; \$stash->set('error', \$error); \$stash->set('e', \$error); if (defined (\$handler = \$error->select_handler($handlers))) { $catchblock } $default } $final }; EOF } #------------------------------------------------------------------------ # throw(\@nameargs) [% THROW foo "bar error" %] # # => [ [$type], \@args ] #------------------------------------------------------------------------ sub throw { my ($class, $nameargs) = @_; my ($type, $args) = @$nameargs; my $hash = shift(@$args); my $info = shift(@$args); $type = shift @$type; # uses same parser production as INCLUDE # etc., which allow multiple names # e.g. INCLUDE foo+bar+baz if (! $info) { $args = "$type, undef"; } elsif (@$hash || @$args) { local $" = ', '; my $i = 0; $args = "$type, { args => [ " . join(', ', $info, @$args) . ' ], ' . join(', ', (map { "'" . $i++ . "' => $_" } ($info, @$args)), @$hash) . ' }'; } else { $args = "$type, $info"; } return "\$context->throw($args, \\\$output);"; } #------------------------------------------------------------------------ # clear() [% CLEAR %] # # NOTE: this is redundant, being hard-coded (for now) into Parser.yp #------------------------------------------------------------------------ sub clear { return "\$output = '';"; } #------------------------------------------------------------------------ # break() [% BREAK %] # # NOTE: this is redundant, being hard-coded (for now) into Parser.yp #------------------------------------------------------------------------ sub break { return 'last LOOP;'; } #------------------------------------------------------------------------ # return() [% RETURN %] #------------------------------------------------------------------------ sub return { return "\$context->throw('return', '', \\\$output);"; } #------------------------------------------------------------------------ # stop() [% STOP %] #------------------------------------------------------------------------ sub stop { return "\$context->throw('stop', '', \\\$output);"; } #------------------------------------------------------------------------ # use(\@lnameargs) [% USE alias = plugin(args) %] # # => [ [$file, ...], \@args, $alias ] #------------------------------------------------------------------------ sub use { my ($class, $lnameargs) = @_; my ($file, $args, $alias) = @$lnameargs; $file = shift @$file; # same production rule as INCLUDE $alias ||= $file; $args = &args($class, $args); $file .= ", $args" if $args; # my $set = &assign($class, $alias, '$plugin'); return "# USE\n" . "\$stash->set($alias,\n" . " \$context->plugin($file));"; } #------------------------------------------------------------------------ # view(\@nameargs, $block) [% VIEW name args %] # # => [ [$file, ... ], \@args ] #------------------------------------------------------------------------ sub view { my ($class, $nameargs, $block, $defblocks) = @_; my ($name, $args) = @$nameargs; my $hash = shift @$args; $name = shift @$name; # same production rule as INCLUDE $block = pad($block, 1) if $PRETTY; if (%$defblocks) { $defblocks = join(",\n", map { "'$_' => $defblocks->{ $_ }" } keys %$defblocks); $defblocks = pad($defblocks, 1) if $PRETTY; $defblocks = "{\n$defblocks\n}"; push(@$hash, "'blocks'", $defblocks); } $hash = @$hash ? '{ ' . join(', ', @$hash) . ' }' : ''; return <get('view'); my \$view = \$context->view($hash); \$stash->set($name, \$view); \$stash->set('view', \$view); $block \$stash->set('view', \$oldv); \$view->seal(); \$output; }; EOF } #------------------------------------------------------------------------ # perl($block) #------------------------------------------------------------------------ sub perl { my ($class, $block) = @_; $block = pad($block, 1) if $PRETTY; return <throw('perl', 'EVAL_PERL not set') unless \$context->eval_perl(); $OUTPUT do { my \$output = "package Template::Perl;\\n"; $block local(\$Template::Perl::context) = \$context; local(\$Template::Perl::stash) = \$stash; my \$result = ''; tie *Template::Perl::PERLOUT, 'Template::TieString', \\\$result; my \$save_stdout = select *Template::Perl::PERLOUT; eval \$output; select \$save_stdout; \$context->throw(\$@) if \$@; \$result; }; EOF } #------------------------------------------------------------------------ # no_perl() #------------------------------------------------------------------------ sub no_perl { my $class = shift; return "\$context->throw('perl', 'EVAL_PERL not set');"; } #------------------------------------------------------------------------ # rawperl($block) # # NOTE: perhaps test context EVAL_PERL switch at compile time rather than # runtime? #------------------------------------------------------------------------ sub rawperl { my ($class, $block, $line) = @_; for ($block) { s/^\n+//; s/\n+$//; } $block = pad($block, 1) if $PRETTY; $line = $line ? " (starting line $line)" : ''; return <filter($name) || \$context->throw(\$context->error); $block &\$filter(\$output); }; EOF } #------------------------------------------------------------------------ # capture($name, $block) #------------------------------------------------------------------------ sub capture { my ($class, $name, $block) = @_; if (ref $name) { if (scalar @$name == 2 && ! $name->[1]) { $name = $name->[0]; } else { $name = '[' . join(', ', @$name) . ']'; } } $block = pad($block, 1) if $PRETTY; return <set($name, do { my \$output = ''; $block \$output; }); EOF } #------------------------------------------------------------------------ # macro($name, $block, \@args) #------------------------------------------------------------------------ sub macro { my ($class, $ident, $block, $args) = @_; $block = pad($block, 2) if $PRETTY; if ($args) { my $nargs = scalar @$args; $args = join(', ', map { "'$_'" } @$args); $args = $nargs > 1 ? "\@args{ $args } = splice(\@_, 0, $nargs)" : "\$args{ $args } = shift"; return <set('$ident', sub { my \$output = ''; my (%args, \$params); $args; \$params = shift; \$params = { } unless ref(\$params) eq 'HASH'; \$params = { \%args, %\$params }; my \$stash = \$context->localise(\$params); eval { $block }; \$stash = \$context->delocalise(); die \$@ if \$@; return \$output; }); EOF } else { return <set('$ident', sub { my \$params = \$_[0] if ref(\$_[0]) eq 'HASH'; my \$output = ''; my \$stash = \$context->localise(\$params); eval { $block }; \$stash = \$context->delocalise(); die \$@ if \$@; return \$output; }); EOF } } sub debug { my ($class, $nameargs) = @_; my ($file, $args) = @$nameargs; my $hash = shift @$args; $args = join(', ', @$file, @$args); $args .= @$hash ? ', { ' . join(', ', @$hash) . ' }' : ''; return "$OUTPUT \$context->debugging($args); ## DEBUG ##"; } 1; __END__ vdradmin-am-3.6.13/lib/Template/Document.pm000066400000000000000000000347531443716113400204600ustar00rootroot00000000000000##============================================================= -*-Perl-*- # # Template::Document # # DESCRIPTION # Module defining a class of objects which encapsulate compiled # templates, storing additional block definitions and metadata # as well as the compiled Perl sub-routine representing the main # template content. # # AUTHOR # Andy Wardley # # COPYRIGHT # Copyright (C) 1996-2000 Andy Wardley. All Rights Reserved. # Copyright (C) 1998-2000 Canon Research Centre Europe Ltd. # # This module is free software; you can redistribute it and/or # modify it under the same terms as Perl itself. # #---------------------------------------------------------------------------- # # $Id: Document.pm,v 2.65 2003/04/24 09:14:38 abw Exp $ # #============================================================================ package Template::Document; require 5.004; use strict; use vars qw( $VERSION $ERROR $COMPERR $DEBUG $AUTOLOAD ); use base qw( Template::Base ); use Template::Constants; $VERSION = sprintf("%d.%02d", q$Revision: 2.65 $ =~ /(\d+)\.(\d+)/); #======================================================================== # ----- PUBLIC METHODS ----- #======================================================================== #------------------------------------------------------------------------ # new(\%document) # # Creates a new self-contained Template::Document object which # encapsulates a compiled Perl sub-routine, $block, any additional # BLOCKs defined within the document ($defblocks, also Perl sub-routines) # and additional $metadata about the document. #------------------------------------------------------------------------ sub new { my ($class, $doc) = @_; my ($block, $defblocks, $metadata) = @$doc{ qw( BLOCK DEFBLOCKS METADATA ) }; $defblocks ||= { }; $metadata ||= { }; # evaluate Perl code in $block to create sub-routine reference if necessary unless (ref $block) { local $SIG{__WARN__} = \&catch_warnings; $COMPERR = ''; # DON'T LOOK NOW! - blindly untainting can make you go blind! $block =~ /(.*)/s; $block = $1; $block = eval $block; # $COMPERR .= "[$@]" if $@; # return $class->error($COMPERR) return $class->error($@) unless defined $block; } # same for any additional BLOCK definitions @$defblocks{ keys %$defblocks } = # MORE BLIND UNTAINTING - turn away if you're squeamish map { ref($_) ? $_ : ( /(.*)/s && eval($1) or return $class->error($@) ) } values %$defblocks; bless { %$metadata, _BLOCK => $block, _DEFBLOCKS => $defblocks, _HOT => 0, }, $class; } #------------------------------------------------------------------------ # block() # # Returns a reference to the internal sub-routine reference, _BLOCK, # that constitutes the main document template. #------------------------------------------------------------------------ sub block { return $_[0]->{ _BLOCK }; } #------------------------------------------------------------------------ # blocks() # # Returns a reference to a hash array containing any BLOCK definitions # from the template. The hash keys are the BLOCK nameand the values # are references to Template::Document objects. Returns 0 (# an empty hash) # if no blocks are defined. #------------------------------------------------------------------------ sub blocks { return $_[0]->{ _DEFBLOCKS }; } #------------------------------------------------------------------------ # process($context) # # Process the document in a particular context. Checks for recursion, # registers the document with the context via visit(), processes itself, # and then unwinds with a large gin and tonic. #------------------------------------------------------------------------ sub process { my ($self, $context) = @_; my $defblocks = $self->{ _DEFBLOCKS }; my $output; # check we're not already visiting this template return $context->throw(Template::Constants::ERROR_FILE, "recursion into '$self->{ name }'") if $self->{ _HOT } && ! $context->{ RECURSION }; ## RETURN ## $context->visit($defblocks); $self->{ _HOT } = 1; eval { my $block = $self->{ _BLOCK }; $output = &$block($context); }; $self->{ _HOT } = 0; $context->leave(); die $context->catch($@) if $@; return $output; } #------------------------------------------------------------------------ # AUTOLOAD # # Provides pseudo-methods for read-only access to various internal # members. #------------------------------------------------------------------------ sub AUTOLOAD { my $self = shift; my $method = $AUTOLOAD; $method =~ s/.*:://; return if $method eq 'DESTROY'; # my ($pkg, $file, $line) = caller(); # print STDERR "called $self->AUTOLOAD($method) from $file line $line\n"; return $self->{ $method }; } #======================================================================== # ----- PRIVATE METHODS ----- #======================================================================== #------------------------------------------------------------------------ # _dump() # # Debug method which returns a string representing the internal state # of the object. #------------------------------------------------------------------------ sub _dump { my $self = shift; my $dblks; my $output = "$self : $self->{ name }\n"; $output .= "BLOCK: $self->{ _BLOCK }\nDEFBLOCKS:\n"; if ($dblks = $self->{ _DEFBLOCKS }) { foreach my $b (keys %$dblks) { $output .= " $b: $dblks->{ $b }\n"; } } return $output; } #======================================================================== # ----- CLASS METHODS ----- #======================================================================== #------------------------------------------------------------------------ # as_perl($content) # # This method expects a reference to a hash passed as the first argument # containing 3 items: # METADATA # a hash of template metadata # BLOCK # string containing Perl sub definition for main block # DEFBLOCKS # hash containing further subs for addional BLOCK defs # It returns a string containing Perl code which, when evaluated and # executed, will instantiate a new Template::Document object with the # above data. On error, it returns undef with an appropriate error # message set in $ERROR. #------------------------------------------------------------------------ sub as_perl { my ($class, $content) = @_; my ($block, $defblocks, $metadata) = @$content{ qw( BLOCK DEFBLOCKS METADATA ) }; $block =~ s/\n/\n /g; $block =~ s/\s+$//; $defblocks = join('', map { my $code = $defblocks->{ $_ }; $code =~ s/\n/\n /g; $code =~ s/\s*$//; " '$_' => $code,\n"; } keys %$defblocks); $defblocks =~ s/\s+$//; $metadata = join('', map { my $x = $metadata->{ $_ }; $x =~ s/(['\\])/\\$1/g; " '$_' => '$x',\n"; } keys %$metadata); $metadata =~ s/\s+$//; return <new({ METADATA => { $metadata }, BLOCK => $block, DEFBLOCKS => { $defblocks }, }); EOF } #------------------------------------------------------------------------ # write_perl_file($filename, \%content) # # This method calls as_perl() to generate the Perl code to represent a # compiled template with the content passed as the second argument. # It then writes this to the file denoted by the first argument. # # Returns 1 on success. On error, sets the $ERROR package variable # to contain an error message and returns undef. #------------------------------------------------------------------------ sub write_perl_file { my ($class, $file, $content) = @_; my ($fh, $tmpfile); return $class->error("invalid filename: $file") unless $file =~ /^(.+)$/s; eval { require File::Temp; require File::Basename; ($fh, $tmpfile) = File::Temp::tempfile( DIR => File::Basename::dirname($file) ); print $fh $class->as_perl($content) || die $!; close($fh); }; return $class->error($@) if $@; return rename($tmpfile, $file) || $class->error($!); } #------------------------------------------------------------------------ # catch_warnings($msg) # # Installed as #------------------------------------------------------------------------ sub catch_warnings { $COMPERR .= join('', @_); } 1; __END__ #------------------------------------------------------------------------ # IMPORTANT NOTE # This documentation is generated automatically from source # templates. Any changes you make here may be lost. # # The 'docsrc' documentation source bundle is available for download # from http://www.template-toolkit.org/docs.html and contains all # the source templates, XML files, scripts, etc., from which the # documentation for the Template Toolkit is built. #------------------------------------------------------------------------ =head1 NAME Template::Document - Compiled template document object =head1 SYNOPSIS use Template::Document; $doc = Template::Document->new({ BLOCK => sub { # some perl code; return $some_text }, DEFBLOCKS => { header => sub { # more perl code; return $some_text }, footer => sub { # blah blah blah; return $some_text }, }, METADATA => { author => 'Andy Wardley', version => 3.14, } }) || die $Template::Document::ERROR; print $doc->process($context); =head1 DESCRIPTION This module defines an object class whose instances represent compiled template documents. The Template::Parser module creates a Template::Document instance to encapsulate a template as it is compiled into Perl code. The constructor method, new(), expects a reference to a hash array containing the BLOCK, DEFBLOCKS and METADATA items. The BLOCK item should contain a reference to a Perl subroutine or a textual representation of Perl code, as generated by the Template::Parser module, which is then evaluated into a subroutine reference using eval(). The DEFLOCKS item should reference a hash array containing further named BLOCKs which may be defined in the template. The keys represent BLOCK names and the values should be subroutine references or text strings of Perl code as per the main BLOCK item. The METADATA item should reference a hash array of metadata items relevant to the document. The process() method can then be called on the instantiated Template::Document object, passing a reference to a Template::Content object as the first parameter. This will install any locally defined blocks (DEFBLOCKS) in the the contexts() BLOCKS cache (via a call to visit()) so that they may be subsequently resolved by the context. The main BLOCK subroutine is then executed, passing the context reference on as a parameter. The text returned from the template subroutine is then returned by the process() method, after calling the context leave() method to permit cleanup and de-registration of named BLOCKS previously installed. An AUTOLOAD method provides access to the METADATA items for the document. The Template::Service module installs a reference to the main Template::Document object in the stash as the 'template' variable. This allows metadata items to be accessed from within templates, including PRE_PROCESS templates. header: [% template.title %] </head> ... Template::Document objects are usually created by the Template::Parser but can be manually instantiated or sub-classed to provide custom template components. =head1 METHODS =head2 new(\%config) Constructor method which accept a reference to a hash array containing the structure as shown in this example: $doc = Template::Document->new({ BLOCK => sub { # some perl code; return $some_text }, DEFBLOCKS => { header => sub { # more perl code; return $some_text }, footer => sub { # blah blah blah; return $some_text }, }, METADATA => { author => 'Andy Wardley', version => 3.14, } }) || die $Template::Document::ERROR; BLOCK and DEFBLOCKS items may be expressed as references to Perl subroutines or as text strings containing Perl subroutine definitions, as is generated by the Template::Parser module. These are evaluated into subroutine references using eval(). Returns a new Template::Document object or undef on error. The error() class method can be called, or the $ERROR package variable inspected to retrieve the relevant error message. =head2 process($context) Main processing routine for the compiled template document. A reference to a Template::Context object should be passed as the first parameter. The method installs any locally defined blocks via a call to the context visit() method, processes it's own template, passing the context reference by parameter and then calls leave() in the context to allow cleanup. print $doc->process($context); Returns a text string representing the generated output for the template. Errors are thrown via die(). =head2 block() Returns a reference to the main BLOCK subroutine. =head2 blocks() Returns a reference to the hash array of named DEFBLOCKS subroutines. =head2 AUTOLOAD An autoload method returns METADATA items. print $doc->author(); =head1 PACKAGE SUB-ROUTINES =head2 write_perl_file(\%config) This package subroutine is provided to effect persistance of compiled templates. If the COMPILE_EXT option (to indicate a file extension for saving compiled templates) then the Template::Parser module calls this subroutine before calling the new() constructor. At this stage, the parser has a representation of the template as text strings containing Perl code. We can write that to a file, enclosed in a small wrapper which will allow us to susequently require() the file and have Perl parse and compile it into a Template::Document. Thus we have persistance of compiled templates. =head1 AUTHOR Andy Wardley E<lt>abw@andywardley.comE<gt> L<http://www.andywardley.com/|http://www.andywardley.com/> =head1 VERSION 2.65, distributed as part of the Template Toolkit version 2.10, released on 24 July 2003. =head1 COPYRIGHT Copyright (C) 1996-2003 Andy Wardley. All Rights Reserved. Copyright (C) 1998-2002 Canon Research Centre Europe Ltd. This module is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =head1 SEE ALSO L<Template|Template>, L<Template::Parser|Template::Parser> ���������������������vdradmin-am-3.6.13/lib/Template/Exception.pm��������������������������������������������������������0000664�0000000�0000000�00000015544�14437161134�0020635�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#============================================================= -*-Perl-*- # # Template::Exception # # DESCRIPTION # Module implementing a generic exception class used for error handling # in the Template Toolkit. # # AUTHOR # Andy Wardley <abw@kfs.org> # # COPYRIGHT # Copyright (C) 1996-2000 Andy Wardley. All Rights Reserved. # Copyright (C) 1998-2000 Canon Research Centre Europe Ltd. # # This module is free software; you can redistribute it and/or # modify it under the same terms as Perl itself. # #------------------------------------------------------------------------ # # $Id: Exception.pm,v 2.59 2003/04/24 09:14:38 abw Exp $ # #======================================================================== package Template::Exception; require 5.005; use strict; use vars qw( $VERSION ); use constant TYPE => 0; use constant INFO => 1; use constant TEXT => 2; use overload q|""| => "as_string", fallback => 1; $VERSION = sprintf("%d.%02d", q$Revision: 2.59 $ =~ /(\d+)\.(\d+)/); #------------------------------------------------------------------------ # new($type, $info, \$text) # # Constructor method used to instantiate a new Template::Exception # object. The first parameter should contain the exception type. This # can be any arbitrary string of the caller's choice to represent a # specific exception. The second parameter should contain any # information (i.e. error message or data reference) relevant to the # specific exception event. The third optional parameter may be a # reference to a scalar containing output text from the template # block up to the point where the exception was thrown. #------------------------------------------------------------------------ sub new { my ($class, $type, $info, $textref) = @_; bless [ $type, $info, $textref ], $class; } #------------------------------------------------------------------------ # type() # info() # type_info() # # Accessor methods to return the internal TYPE and INFO fields. #------------------------------------------------------------------------ sub type { $_[0]->[ TYPE ]; } sub info { $_[0]->[ INFO ]; } sub type_info { my $self = shift; @$self[ TYPE, INFO ]; } #------------------------------------------------------------------------ # text() # text(\$pretext) # # Method to return the text referenced by the TEXT member. A text # reference may be passed as a parameter to supercede the existing # member. The existing text is added to the *end* of the new text # before being stored. This facility is provided for template blocks # to gracefully de-nest when an exception occurs and allows them to # reconstruct their output in the correct order. #------------------------------------------------------------------------ sub text { my ($self, $newtextref) = @_; my $textref = $self->[ TEXT ]; if ($newtextref) { $$newtextref .= $$textref if $textref && $textref ne $newtextref; $self->[ TEXT ] = $newtextref; return ''; } elsif ($textref) { return $$textref; } else { return ''; } } #------------------------------------------------------------------------ # as_string() # # Accessor method to return a string indicating the exception type and # information. #------------------------------------------------------------------------ sub as_string { my $self = shift; return $self->[ TYPE ] . ' error - ' . $self->[ INFO ]; } #------------------------------------------------------------------------ # select_handler(@types) # # Selects the most appropriate handler for the exception TYPE, from # the list of types passed in as parameters. The method returns the # item which is an exact match for TYPE or the closest, more # generic handler (e.g. foo being more generic than foo.bar, etc.) #------------------------------------------------------------------------ sub select_handler { my ($self, @options) = @_; my $type = $self->[ TYPE ]; my %hlut; @hlut{ @options } = (1) x @options; while ($type) { return $type if $hlut{ $type }; # strip .element from the end of the exception type to find a # more generic handler $type =~ s/\.?[^\.]*$//; } return undef; } 1; __END__ #------------------------------------------------------------------------ # IMPORTANT NOTE # This documentation is generated automatically from source # templates. Any changes you make here may be lost. # # The 'docsrc' documentation source bundle is available for download # from http://www.template-toolkit.org/docs.html and contains all # the source templates, XML files, scripts, etc., from which the # documentation for the Template Toolkit is built. #------------------------------------------------------------------------ =head1 NAME Template::Exception - Exception handling class module =head1 SYNOPSIS use Template::Exception; my $exception = Template::Exception->new($type, $info); $type = $exception->type; $info = $exception->info; ($type, $info) = $exception->type_info; print $exception->as_string(); $handler = $exception->select_handler(\@candidates); =head1 DESCRIPTION The Template::Exception module defines an object class for representing exceptions within the template processing life cycle. Exceptions can be raised by modules within the Template Toolkit, or can be generated and returned by user code bound to template variables. Exceptions can be raised in a template using the THROW directive, [% THROW user.login 'no user id: please login' %] or by calling the throw() method on the current Template::Context object, $context->throw('user.passwd', 'Incorrect Password'); $context->throw('Incorrect Password'); # type 'undef' or from Perl code by calling die() with a Template::Exception object, die (Template::Exception->new('user.denied', 'Invalid User ID')); or by simply calling die() with an error string. This is automagically caught and converted to an exception of 'undef' type which can then be handled in the usual way. die "I'm sorry Dave, I can't do that"; Each exception is defined by its type and a information component (e.g. error message). The type can be any identifying string and may contain dotted components (e.g. 'foo', 'foo.bar', 'foo.bar.baz'). Exception types are considered to be hierarchical such that 'foo.bar' would be a specific type of the more general 'foo' type. =head1 AUTHOR Andy Wardley E<lt>abw@andywardley.comE<gt> L<http://www.andywardley.com/|http://www.andywardley.com/> =head1 VERSION 2.59, distributed as part of the Template Toolkit version 2.10, released on 24 July 2003. =head1 COPYRIGHT Copyright (C) 1996-2003 Andy Wardley. All Rights Reserved. Copyright (C) 1998-2002 Canon Research Centre Europe Ltd. This module is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =head1 SEE ALSO L<Template|Template>, L<Template::Context|Template::Context> ������������������������������������������������������������������������������������������������������������������������������������������������������������vdradmin-am-3.6.13/lib/Template/Filters.pm����������������������������������������������������������0000664�0000000�0000000�00000126662�14437161134�0020313�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#============================================================= -*-Perl-*- # # Template::Filters # # DESCRIPTION # Defines filter plugins as used by the FILTER directive. # # AUTHORS # Andy Wardley <abw@kfs.org>, with a number of filters contributed # by Leslie Michael Orchard <deus_x@nijacode.com> # # COPYRIGHT # Copyright (C) 1996-2000 Andy Wardley. All Rights Reserved. # Copyright (C) 1998-2000 Canon Research Centre Europe Ltd. # # This module is free software; you can redistribute it and/or # modify it under the same terms as Perl itself. # #---------------------------------------------------------------------------- # # $Id: Filters.pm,v 2.72 2003/07/01 12:43:55 darren Exp $ # #============================================================================ package Template::Filters; require 5.004; use strict; use base qw( Template::Base ); use vars qw( $VERSION $DEBUG $FILTERS $URI_ESCAPES $PLUGIN_FILTER ); use Template::Constants; $VERSION = sprintf("%d.%02d", q$Revision: 2.72 $ =~ /(\d+)\.(\d+)/); #------------------------------------------------------------------------ # standard filters, defined in one of the following forms: # name => \&static_filter # name => [ \&subref, $is_dynamic ] # If the $is_dynamic flag is set then the sub-routine reference # is called to create a new filter each time it is requested; if # not set, then it is a single, static sub-routine which is returned # for every filter request for that name. #------------------------------------------------------------------------ $FILTERS = { # static filters 'html' => \&html_filter, 'html_para' => \&html_paragraph, 'html_break' => \&html_para_break, 'html_para_break' => \&html_para_break, 'html_line_break' => \&html_line_break, 'uri' => \&uri_filter, 'upper' => sub { uc $_[0] }, 'lower' => sub { lc $_[0] }, 'ucfirst' => sub { ucfirst $_[0] }, 'lcfirst' => sub { lcfirst $_[0] }, 'stderr' => sub { print STDERR @_; return '' }, 'trim' => sub { for ($_[0]) { s/^\s+//; s/\s+$// }; $_[0] }, 'null' => sub { return '' }, 'collapse' => sub { for ($_[0]) { s/^\s+//; s/\s+$//; s/\s+/ /g }; $_[0] }, # dynamic filters 'html_entity' => [ \&html_entity_filter_factory, 1 ], 'indent' => [ \&indent_filter_factory, 1 ], 'format' => [ \&format_filter_factory, 1 ], 'truncate' => [ \&truncate_filter_factory, 1 ], 'repeat' => [ \&repeat_filter_factory, 1 ], 'replace' => [ \&replace_filter_factory, 1 ], 'remove' => [ \&remove_filter_factory, 1 ], 'eval' => [ \&eval_filter_factory, 1 ], 'evaltt' => [ \&eval_filter_factory, 1 ], # alias 'perl' => [ \&perl_filter_factory, 1 ], 'evalperl' => [ \&perl_filter_factory, 1 ], # alias 'redirect' => [ \&redirect_filter_factory, 1 ], 'file' => [ \&redirect_filter_factory, 1 ], # alias 'stdout' => [ \&stdout_filter_factory, 1 ], 'latex' => [ \&latex_filter_factory, 1 ], }; # name of module implementing plugin filters $PLUGIN_FILTER = 'Template::Plugin::Filter'; #======================================================================== # -- PUBLIC METHODS -- #======================================================================== #------------------------------------------------------------------------ # fetch($name, \@args, $context) # # Attempts to instantiate or return a reference to a filter sub-routine # named by the first parameter, $name, with additional constructor # arguments passed by reference to a list as the second parameter, # $args. A reference to the calling Template::Context object is # passed as the third paramter. # # Returns a reference to a filter sub-routine or a pair of values # (undef, STATUS_DECLINED) or ($error, STATUS_ERROR) to decline to # deliver the filter or to indicate an error. #------------------------------------------------------------------------ sub fetch { my ($self, $name, $args, $context) = @_; my ($factory, $is_dynamic, $filter, $error); $self->debug("fetch($name, ", defined $args ? ('[ ', join(', ', @$args), ' ]') : '<no args>', ', ', defined $context ? $context : '<no context>', ')') if $self->{ DEBUG }; # allow $name to be specified as a reference to # a plugin filter object; any other ref is # assumed to be a coderef and hence already a filter; # non-refs are assumed to be regular name lookups if (ref $name) { if (UNIVERSAL::isa($name, $PLUGIN_FILTER)) { $factory = $name->factory() || return $self->error($name->error()); } else { return $name; } } else { return (undef, Template::Constants::STATUS_DECLINED) unless ($factory = $self->{ FILTERS }->{ $name } || $FILTERS->{ $name }); } # factory can be an [ $code, $dynamic ] or just $code if (ref $factory eq 'ARRAY') { ($factory, $is_dynamic) = @$factory; } else { $is_dynamic = 0; } if (ref $factory eq 'CODE') { if ($is_dynamic) { # if the dynamic flag is set then the sub-routine is a # factory which should be called to create the actual # filter... eval { ($filter, $error) = &$factory($context, $args ? @$args : ()); }; $error ||= $@; $error = "invalid FILTER for '$name' (not a CODE ref)" unless $error || ref($filter) eq 'CODE'; } else { # ...otherwise, it's a static filter sub-routine $filter = $factory; } } else { $error = "invalid FILTER entry for '$name' (not a CODE ref)"; } if ($error) { return $self->{ TOLERANT } ? (undef, Template::Constants::STATUS_DECLINED) : ($error, Template::Constants::STATUS_ERROR) ; } else { return $filter; } } #------------------------------------------------------------------------ # store($name, \&filter) # # Stores a new filter in the internal FILTERS hash. The first parameter # is the filter name, the second a reference to a subroutine or # array, as per the standard $FILTERS entries. #------------------------------------------------------------------------ sub store { my ($self, $name, $filter) = @_; $self->debug("store($name, $filter)") if $self->{ DEBUG }; $self->{ FILTERS }->{ $name } = $filter; return 1; } #======================================================================== # -- PRIVATE METHODS -- #======================================================================== #------------------------------------------------------------------------ # _init(\%config) # # Private initialisation method. #------------------------------------------------------------------------ sub _init { my ($self, $params) = @_; $self->{ FILTERS } = $params->{ FILTERS } || { }; $self->{ TOLERANT } = $params->{ TOLERANT } || 0; $self->{ DEBUG } = ( $params->{ DEBUG } || 0 ) & Template::Constants::DEBUG_FILTERS; return $self; } #------------------------------------------------------------------------ # _dump() # # Debug method #------------------------------------------------------------------------ sub _dump { my $self = shift; my $output = "[Template::Filters] {\n"; my $format = " %-16s => %s\n"; my $key; foreach $key (qw( TOLERANT )) { my $val = $self->{ $key }; $val = '<undef>' unless defined $val; $output .= sprintf($format, $key, $val); } my $filters = $self->{ FILTERS }; $filters = join('', map { sprintf(" $format", $_, $filters->{ $_ }); } keys %$filters); $filters = "{\n$filters }"; $output .= sprintf($format, 'FILTERS (local)' => $filters); $filters = $FILTERS; $filters = join('', map { my $f = $filters->{ $_ }; my ($ref, $dynamic) = ref $f eq 'ARRAY' ? @$f : ($f, 0); sprintf(" $format", $_, $dynamic ? 'dynamic' : 'static'); } sort keys %$filters); $filters = "{\n$filters }"; $output .= sprintf($format, 'FILTERS (global)' => $filters); $output .= '}'; return $output; } #======================================================================== # -- STATIC FILTER SUBS -- #======================================================================== #------------------------------------------------------------------------ # uri_filter() [% FILTER uri %] # # URI escape a string. This code is borrowed from Gisle Aas' URI::Escape # module. For something so simple, I can't see any validation in making # the user install the URI modules just for this, so we cut and paste. # # URI::Escape is Copyright 1995-2000 Gisle Aas. #------------------------------------------------------------------------ sub uri_filter { my $text = shift; # construct and cache a lookup table for escapes (faster than # doing a sprintf() for every character in every string each # time) $URI_ESCAPES ||= { map { ( chr($_), sprintf("%%%02X", $_) ) } (0..255), }; $text =~ s/([^;\/?:@&=+\$,A-Za-z0-9\-_.!~*'()])/$URI_ESCAPES->{$1}/g; $text; } #------------------------------------------------------------------------ # html_filter() [% FILTER html %] # # Convert any '<', '>' or '&' characters to the HTML equivalents, '<', # '>' and '&', respectively. #------------------------------------------------------------------------ sub html_filter { my $text = shift; for ($text) { s/&/&/g; s/</</g; s/>/>/g; s/"/"/g; } return $text; } #------------------------------------------------------------------------ # html_paragraph() [% FILTER html_para %] # # Wrap each paragraph of text (delimited by two or more newlines) in the # <p>...</p> HTML tags. #------------------------------------------------------------------------ sub html_paragraph { my $text = shift; return "<p>\n" . join("\n</p>\n\n<p>\n", split(/(?:\r?\n){2,}/, $text)) . "</p>\n"; } #------------------------------------------------------------------------ # html_para_break() [% FILTER html_para_break %] # # Join each paragraph of text (delimited by two or more newlines) with # <br><br> HTML tags. #------------------------------------------------------------------------ sub html_para_break { my $text = shift; $text =~ s|(\r?\n){2,}|$1<br />$1<br />$1|g; return $text; } #------------------------------------------------------------------------ # html_line_break() [% FILTER html_line_break %] # # replaces any newlines with <br> HTML tags. #------------------------------------------------------------------------ sub html_line_break { my $text = shift; $text =~ s|(\r?\n)|<br />$1|g; return $text; } #======================================================================== # -- DYNAMIC FILTER FACTORIES -- #======================================================================== #------------------------------------------------------------------------ # html_entity_filter_factory(\%options) [% FILTER html %] # # Dynamic version of the static html filter which attempts to locate the # Apache::Util or HTML::Entities modules to perform full entity encoding # of the text passed. Returns an exception if one or other of the # modules can't be located. #------------------------------------------------------------------------ sub html_entity_filter_factory { my $context = shift; # if Apache::Util is installed then we use it eval { require Apache::Util; Apache::Util::escape_html(''); }; return \&Apache::Util::escape_html unless $@; # otherwise if HTML::Entities is installed then we use that eval { require HTML::Entities; }; return \&HTML::Entities::encode_entities unless $@; return (undef, Template::Exception->new( html_entity => 'cannot locate Apache::Util or HTML::Entities' )); } #------------------------------------------------------------------------ # indent_filter_factory($pad) [% FILTER indent(pad) %] # # Create a filter to indent text by a fixed pad string or when $pad is # numerical, a number of space. #------------------------------------------------------------------------ sub indent_filter_factory { my ($context, $pad) = @_; $pad = 4 unless defined $pad; $pad = ' ' x $pad if $pad =~ /^\d+$/; return sub { my $text = shift; $text = '' unless defined $text; $text =~ s/^/$pad/mg; return $text; } } #------------------------------------------------------------------------ # format_filter_factory() [% FILTER format(format) %] # # Create a filter to format text according to a printf()-like format # string. #------------------------------------------------------------------------ sub format_filter_factory { my ($context, $format) = @_; $format = '%s' unless defined $format; return sub { my $text = shift; $text = '' unless defined $text; return join("\n", map{ sprintf($format, $_) } split(/\n/, $text)); } } #------------------------------------------------------------------------ # repeat_filter_factory($n) [% FILTER repeat(n) %] # # Create a filter to repeat text n times. #------------------------------------------------------------------------ sub repeat_filter_factory { my ($context, $iter) = @_; $iter = 1 unless defined $iter and length $iter; return sub { my $text = shift; $text = '' unless defined $text; return join('\n', $text) x $iter; } } #------------------------------------------------------------------------ # replace_filter_factory($s, $r) [% FILTER replace(search, replace) %] # # Create a filter to replace 'search' text with 'replace' #------------------------------------------------------------------------ sub replace_filter_factory { my ($context, $search, $replace) = @_; $search = '' unless defined $search; $replace = '' unless defined $replace; return sub { my $text = shift; $text = '' unless defined $text; $text =~ s/$search/$replace/g; return $text; } } #------------------------------------------------------------------------ # remove_filter_factory($text) [% FILTER remove(text) %] # # Create a filter to remove 'search' string from the input text. #------------------------------------------------------------------------ sub remove_filter_factory { my ($context, $search) = @_; return sub { my $text = shift; $text = '' unless defined $text; $text =~ s/$search//g; return $text; } } #------------------------------------------------------------------------ # truncate_filter_factory($n) [% FILTER truncate(n) %] # # Create a filter to truncate text after n characters. #------------------------------------------------------------------------ sub truncate_filter_factory { my ($context, $len) = @_; $len = 32 unless defined $len; return sub { my $text = shift; return $text if length $text < $len; return substr($text, 0, $len - 3) . "..."; } } #------------------------------------------------------------------------ # eval_filter_factory [% FILTER eval %] # # Create a filter to evaluate template text. #------------------------------------------------------------------------ sub eval_filter_factory { my $context = shift; return sub { my $text = shift; $context->process(\$text); } } #------------------------------------------------------------------------ # perl_filter_factory [% FILTER perl %] # # Create a filter to process Perl text iff the context EVAL_PERL flag # is set. #------------------------------------------------------------------------ sub perl_filter_factory { my $context = shift; my $stash = $context->stash; return (undef, Template::Exception->new('perl', 'EVAL_PERL is not set')) unless $context->eval_perl(); return sub { my $text = shift; local($Template::Perl::context) = $context; local($Template::Perl::stash) = $stash; my $out = eval <<EOF; package Template::Perl; \$stash = \$context->stash(); $text EOF $context->throw($@) if $@; return $out; } } #------------------------------------------------------------------------ # redirect_filter_factory($context, $file) [% FILTER redirect(file) %] # # Create a filter to redirect the block text to a file. #------------------------------------------------------------------------ sub redirect_filter_factory { my ($context, $file, $options) = @_; my $outpath = $context->config->{ OUTPUT_PATH }; return (undef, Template::Exception->new('redirect', 'OUTPUT_PATH is not set')) unless $outpath; $options = { binmode => $options } unless ref $options; sub { my $text = shift; my $outpath = $context->config->{ OUTPUT_PATH } || return ''; $outpath .= "/$file"; my $error = Template::_output($outpath, \$text, $options); die Template::Exception->new('redirect', $error) if $error; return ''; } } #------------------------------------------------------------------------ # stdout_filter_factory($context, $binmode) [% FILTER stdout(binmode) %] # # Create a filter to print a block to stdout, with an optional binmode. #------------------------------------------------------------------------ sub stdout_filter_factory { my ($context, $options) = @_; $options = { binmode => $options } unless ref $options; sub { my $text = shift; binmode(STDOUT) if $options->{ binmode }; print STDOUT $text; return ''; } } #------------------------------------------------------------------------ # latex_filter_factory($context, $outputType) [% FILTER latex(outputType) %] # # Return a filter sub that converts a (hopefully) complete LaTeX source # file to either "ps", "dvi", or "pdf". Output type should be "ps", "dvi" # or "pdf" (pdf is default). # # Creates a temporary directory below File::Spec->tmpdir() (often /tmp) # and writes the text into doc.tex. It then runs either pdflatex or # latex and optionally dvips. Based on the exit status either returns # the entire doc.(pdf|ps|dvi) output or throws an error with a summary # of the error messages from doc.log. # # Written by Craig Barratt, Apr 28 2001. # Win32 additions by Richard Tietjen. #------------------------------------------------------------------------ use File::Path; use File::Spec; use Cwd; sub latex_filter_factory { my($context, $output) = @_; $output = lc($output); my $fName = "latex"; my($LaTeXPath, $PdfLaTeXPath, $DviPSPath) = @{Template::Config->latexpaths()}; if ( $output eq "ps" || $output eq "dvi" ) { $context->throw($fName, "latex not installed (see Template::Config::LATEX_PATH)") if ( $LaTeXPath eq "" ); } else { $output = "pdf"; $LaTeXPath = $PdfLaTeXPath; $context->throw($fName, "pdflatex not installed (see Template::Config::PDFLATEX_PATH)") if ( $LaTeXPath eq "" ); } if ( $output eq "ps" && $DviPSPath eq "" ) { $context->throw($fName, "dvips not installed (see Template::Config::DVIPS_PATH)"); } if ( $^O !~ /^(MacOS|os2|VMS)$/i ) { return sub { local(*FH); my $text = shift; my $tmpRootDir = File::Spec->tmpdir(); my $cnt = 0; my($tmpDir, $fileName, $devnull); my $texDoc = 'doc'; do { $tmpDir = File::Spec->catdir($tmpRootDir, "tt2latex$$" . "_$cnt"); $cnt++; } while ( -e $tmpDir ); mkpath($tmpDir, 0, 0700); $context->throw($fName, "can't create temp dir $tmpDir") if ( !-d $tmpDir ); $fileName = File::Spec->catfile($tmpDir, "$texDoc.tex"); $devnull = File::Spec->devnull(); if ( !open(FH, ">$fileName") ) { rmtree($tmpDir); $context->throw($fName, "can't open $fileName for output"); } print(FH $text); close(FH); # latex must run in tmpDir directory my $currDir = cwd(); if ( !chdir($tmpDir) ) { rmtree($tmpDir); $context->throw($fName, "can't chdir $tmpDir"); } # # We don't need to quote the backslashes on windows, but we # do on other OSs # my $LaTeX_arg = "\\nonstopmode\\input{$texDoc}"; $LaTeX_arg = "'$LaTeX_arg'" if ( $^O ne 'MSWin32' ); if ( system("$LaTeXPath $LaTeX_arg" . " 1>$devnull 2>$devnull 0<$devnull") ) { my $texErrs = ""; $fileName = File::Spec->catfile($tmpDir, "$texDoc.log"); if ( open(FH, "<$fileName") ) { my $state = 0; # # Try to extract just the interesting errors from # the verbose log file # while ( <FH> ) { # # TeX errors seems to start with a "!" at the # start of the line, and are followed several # lines later by a line designator of the # form "l.nnn" where nnn is the line number. # We make sure we pick up every /^!/ line, and # the first /^l.\d/ line after each /^!/ line. # if ( /^(!.*)/ ) { $texErrs .= $1 . "\n"; $state = 1; } if ( $state == 1 && /^(l\.\d.*)/ ) { $texErrs .= $1 . "\n"; $state = 0; } } close(FH); } else { $texErrs = "Unable to open $fileName\n"; } my $ok = chdir($currDir); rmtree($tmpDir); $context->throw($fName, "can't chdir $currDir") if ( !$ok ); $context->throw($fName, "latex exited with errors:\n$texErrs"); } if ( $output eq "ps" ) { $fileName = File::Spec->catfile($tmpDir, "$texDoc.dvi"); if ( system("$DviPSPath $texDoc -o" . " 1>$devnull 2>$devnull 0<$devnull") ) { my $ok = chdir($currDir); rmtree($tmpDir); $context->throw($fName, "can't chdir $currDir") if ( !$ok ); $context->throw($fName, "can't run $DviPSPath $fileName"); } } if ( !chdir($currDir) ) { rmtree($tmpDir); $context->throw($fName, "can't chdir $currDir"); } my $retStr; $fileName = File::Spec->catfile($tmpDir, "$texDoc.$output"); if ( open(FH, $fileName) ) { local $/ = undef; # slurp file in one go binmode(FH); $retStr = <FH>; close(FH); } else { rmtree($tmpDir); $context->throw($fName, "Can't open output file $fileName"); } rmtree($tmpDir); return $retStr; } } else { $context->throw("$fName not yet supported on $^O OS." . " Please contribute code!!"); } } 1; __END__ #------------------------------------------------------------------------ # IMPORTANT NOTE # This documentation is generated automatically from source # templates. Any changes you make here may be lost. # # The 'docsrc' documentation source bundle is available for download # from http://www.template-toolkit.org/docs.html and contains all # the source templates, XML files, scripts, etc., from which the # documentation for the Template Toolkit is built. #------------------------------------------------------------------------ =head1 NAME Template::Filters - Post-processing filters for template blocks =head1 SYNOPSIS use Template::Filters; $filters = Template::Filters->new(\%config); ($filter, $error) = $filters->fetch($name, \@args, $context); =head1 DESCRIPTION The Template::Filters module implements a provider for creating and/or returning subroutines that implement the standard filters. Additional custom filters may be provided via the FILTERS options. =head1 METHODS =head2 new(\%params) Constructor method which instantiates and returns a reference to a Template::Filters object. A reference to a hash array of configuration items may be passed as a parameter. These are described below. my $filters = Template::Filters->new({ FILTERS => { ... }, }); my $template = Template->new({ LOAD_FILTERS => [ $filters ], }); A default Template::Filters module is created by the Template.pm module if the LOAD_FILTERS option isn't specified. All configuration parameters are forwarded to the constructor. $template = Template->new({ FILTERS => { ... }, }); =head2 fetch($name, \@args, $context) Called to request that a filter of a given name be provided. The name of the filter should be specified as the first parameter. This should be one of the standard filters or one specified in the FILTERS configuration hash. The second argument should be a reference to an array containing configuration parameters for the filter. This may be specified as 0, or undef where no parameters are provided. The third argument should be a reference to the current Template::Context object. The method returns a reference to a filter sub-routine on success. It may also return (undef, STATUS_DECLINE) to decline the request, to allow delegation onto other filter providers in the LOAD_FILTERS chain of responsibility. On error, ($error, STATUS_ERROR) is returned where $error is an error message or Template::Exception object indicating the error that occurred. When the TOLERANT option is set, errors are automatically downgraded to a STATUS_DECLINE response. =head1 CONFIGURATION OPTIONS The following list details the configuration options that can be provided to the Template::Filters new() constructor. =over 4 =item FILTERS The FILTERS option can be used to specify custom filters which can then be used with the FILTER directive like any other. These are added to the standard filters which are available by default. Filters specified via this option will mask any standard filters of the same name. The FILTERS option should be specified as a reference to a hash array in which each key represents the name of a filter. The corresponding value should contain a reference to an array containing a subroutine reference and a flag which indicates if the filter is static (0) or dynamic (1). A filter may also be specified as a solitary subroutine reference and is assumed to be static. $filters = Template::Filters->new({ FILTERS => { 'sfilt1' => \&static_filter, # static 'sfilt2' => [ \&static_filter, 0 ], # same as above 'dfilt1' => [ \&dyanamic_filter_factory, 1 ], }, }); Additional filters can be specified at any time by calling the define_filter() method on the current Template::Context object. The method accepts a filter name, a reference to a filter subroutine and an optional flag to indicate if the filter is dynamic. my $context = $template->context(); $context->define_filter('new_html', \&new_html); $context->define_filter('new_repeat', \&new_repeat, 1); Static filters are those where a single subroutine reference is used for all invocations of a particular filter. Filters that don't accept any configuration parameters (e.g. 'html') can be implemented statically. The subroutine reference is simply returned when that particular filter is requested. The subroutine is called to filter the output of a template block which is passed as the only argument. The subroutine should return the modified text. sub static_filter { my $text = shift; # do something to modify $text... return $text; } The following template fragment: [% FILTER sfilt1 %] Blah blah blah. [% END %] is approximately equivalent to: &static_filter("\nBlah blah blah.\n"); Filters that can accept parameters (e.g. 'truncate') should be implemented dynamically. In this case, the subroutine is taken to be a filter 'factory' that is called to create a unique filter subroutine each time one is requested. A reference to the current Template::Context object is passed as the first parameter, followed by any additional parameters specified. The subroutine should return another subroutine reference (usually a closure) which implements the filter. sub dynamic_filter_factory { my ($context, @args) = @_; return sub { my $text = shift; # do something to modify $text... return $text; } } The following template fragment: [% FILTER dfilt1(123, 456) %] Blah blah blah [% END %] is approximately equivalent to: my $filter = &dynamic_filter_factory($context, 123, 456); &$filter("\nBlah blah blah.\n"); See the FILTER directive for further examples. =item TOLERANT The TOLERANT flag is used by the various Template Toolkit provider modules (Template::Provider, Template::Plugins, Template::Filters) to control their behaviour when errors are encountered. By default, any errors are reported as such, with the request for the particular resource (template, plugin, filter) being denied and an exception raised. When the TOLERANT flag is set to any true values, errors will be silently ignored and the provider will instead return STATUS_DECLINED. This allows a subsequent provider to take responsibility for providing the resource, rather than failing the request outright. If all providers decline to service the request, either through tolerated failure or a genuine disinclination to comply, then a 'E<lt>resourceE<gt> not found' exception is raised. =item DEBUG The DEBUG option can be used to enable debugging messages from the Template::Filters module by setting it to include the DEBUG_FILTERS value. use Template::Constants qw( :debug ); my $template = Template->new({ DEBUG => DEBUG_FILTERS | DEBUG_PLUGINS, }); =back =head1 TEMPLATE TOOLKIT FILTERS The following standard filters are distributed with the Template Toolkit. =head2 format(format) The 'format' filter takes a format string as a parameter (as per printf()) and formats each line of text accordingly. [% FILTER format('<!-- %-40s -->') %] This is a block of text filtered through the above format. [% END %] output: <!-- This is a block of text filtered --> <!-- through the above format. --> =head2 upper Folds the input to UPPER CASE. [% "hello world" FILTER upper %] output: HELLO WORLD =head2 lower Folds the input to lower case. [% "Hello World" FILTER lower %] output: hello world =head2 ucfirst Folds the first character of the input to UPPER CASE. [% "hello" FILTER ucfirst %] output: Hello =head2 lcfirst Folds the first character of the input to lower case. [% "HELLO" FILTER lcfirst %] output: hELLO =head2 trim Trims any leading or trailing whitespace from the input text. Particularly useful in conjunction with INCLUDE, PROCESS, etc., having the same effect as the TRIM configuration option. [% INCLUDE myfile | trim %] =head2 collapse Collapse any whitespace sequences in the input text into a single space. Leading and trailing whitespace (which would be reduced to a single space) is removed, as per trim. [% FILTER collapse %] The cat sat on the mat [% END %] output: The cat sat on the mat =head2 html Converts the characters 'E<lt>', 'E<gt>' and '&' to '<', '>' and '&', respectively, protecting them from being interpreted as representing HTML tags or entities. [% FILTER html %] Binary "<=>" returns -1, 0, or 1 depending on... [% END %] output: Binary "<=>" returns -1, 0, or 1 depending on... =head2 html_entity The html filter is fast and simple but it doesn't encode the full range of HTML entities that your text may contain. The html_entity filter uses either the Apache::Util module (which is written in C and is therefore faster) or the HTML::Entities module (written in Perl but equally as comprehensive) to perform the encoding. If one or other of these modules are installed on your system then the text will be encoded (via the escape_html() or encode_entities() subroutines respectively) to convert all extended characters into their appropriate HTML entities (e.g. converting 'é' to 'é'). If neither module is available on your system then an 'html_entity' exception will be thrown reporting an appropriate message. For further information on HTML entity encoding, see http://www.w3.org/TR/REC-html40/sgml/entities.html. =head2 html_para This filter formats a block of text into HTML paragraphs. A sequence of two or more newlines is used as the delimiter for paragraphs which are then wrapped in HTML E<lt>pE<gt>...E<lt>/pE<gt> tags. [% FILTER html_para %] The cat sat on the mat. Mary had a little lamb. [% END %] output: <p> The cat sat on the mat. </p> <p> Mary had a little lamb. </p> =head2 html_break / html_para_break Similar to the html_para filter described above, but uses the HTML tag sequence E<lt>brE<gt>E<lt>brE<gt> to join paragraphs. [% FILTER html_break %] The cat sat on the mat. Mary had a little lamb. [% END %] output: The cat sat on the mat. <br> <br> Mary had a little lamb. =head2 html_line_break This filter replaces any newlines with E<lt>brE<gt> HTML tags, thus preserving the line breaks of the original text in the HTML output. [% FILTER html_line_break %] The cat sat on the mat. Mary had a little lamb. [% END %] output: The cat sat on the mat.<br> Mary had a little lamb.<br> =head2 uri This filter URI escapes the input text, converting any characters outside of the permitted URI character set (as defined by RFC 2396) into a C<%nn> hex escape. [% 'my file.html' | uri %] output: my%20file.html Note that URI escaping isn't always enough when generating hyperlinks in an HTML document. The C<&> character, for example, is valid in a URI and will not be escaped by the URI filter. In this case you should also filter the text through the 'html' filter. <a href="[% filename | uri | html %]">click here</a> =head2 indent(pad) Indents the text block by a fixed pad string or width. The 'pad' argument can be specified as a string, or as a numerical value to indicate a pad width (spaces). Defaults to 4 spaces if unspecified. [% FILTER indent('ME> ') %] blah blah blah cabbages, rhubard, onions [% END %] output: ME> blah blah blah ME> cabbages, rhubard, onions =head2 truncate(length) Truncates the text block to the length specified, or a default length of 32. Truncated text will be terminated with '...' (i.e. the '...' falls inside the required length, rather than appending to it). [% FILTER truncate(21) %] I have much to say on this matter that has previously been said on more than one occasion. [% END %] output: I have much to say... =head2 repeat(iterations) Repeats the text block for as many iterations as are specified (default: 1). [% FILTER repeat(3) %] We want more beer and we want more beer, [% END %] We are the more beer wanters! output: We want more beer and we want more beer, We want more beer and we want more beer, We want more beer and we want more beer, We are the more beer wanters! =head2 remove(string) Searches the input text for any occurrences of the specified string and removes them. A Perl regular expression may be specified as the search string. [% "The cat sat on the mat" FILTER remove('\s+') %] output: Thecatsatonthemat =head2 replace(search, replace) Similar to the remove filter described above, but taking a second parameter which is used as a replacement string for instances of the search string. [% "The cat sat on the mat" | replace('\s+', '_') %] output: The_cat_sat_on_the_mat =head2 redirect(file, options) The 'redirect' filter redirects the output of the block into a separate file, specified relative to the OUTPUT_PATH configuration item. [% FOREACH user = myorg.userlist %] [% FILTER redirect("users/${user.id}.html") %] [% INCLUDE userinfo %] [% END %] [% END %] or more succinctly, using side-effect notation: [% INCLUDE userinfo FILTER redirect("users/${user.id}.html") FOREACH user = myorg.userlist %] A 'file' exception will be thrown if the OUTPUT_PATH option is undefined. An optional 'binmode' argument can follow the filename to explicitly set the output file to binary mode. [% PROCESS my/png/generator FILTER redirect("images/logo.png", binmode=1) %] For backwards compatibility with earlier versions, a single true/false value can be used to set binary mode. [% PROCESS my/png/generator FILTER redirect("images/logo.png", 1) %] For the sake of future compatibility and clarity, if nothing else, we would strongly recommend you explicitly use the named 'binmode' option as shown in the first example. =head2 eval / evaltt The 'eval' filter evaluates the block as template text, processing any directives embedded within it. This allows template variables to contain template fragments, or for some method to be provided for returning template fragments from an external source such as a database, which can then be processed in the template as required. my $vars = { fragment => "The cat sat on the [% place %]", }; $template->process($file, $vars); The following example: [% fragment | eval %] is therefore equivalent to The cat sat on the [% place %] The 'evaltt' filter is provided as an alias for 'eval'. =head2 perl / evalperl The 'perl' filter evaluates the block as Perl code. The EVAL_PERL option must be set to a true value or a 'perl' exception will be thrown. [% my_perl_code | perl %] In most cases, the [% PERL %] ... [% END %] block should suffice for evaluating Perl code, given that template directives are processed before being evaluate as Perl. Thus, the previous example could have been written in the more verbose form: [% PERL %] [% my_perl_code %] [% END %] as well as [% FILTER perl %] [% my_perl_code %] [% END %] The 'evalperl' filter is provided as an alias for 'perl' for backwards compatibility. =head2 stdout(options) The stdout filter prints the output generated by the enclosing block to STDOUT. The 'binmode' option can be passed as either a named parameter or a single argument to set STDOUT to binary mode (see the binmode perl function). [% PROCESS something/cool FILTER stdout(binmode=1) # recommended %] [% PROCESS something/cool FILTER stdout(1) # alternate %] The stdout filter can be used to force binmode on STDOUT, or also inside redirect, null or stderr blocks to make sure that particular output goes to stdout. See the null filter below for an example. =head2 stderr The stderr filter prints the output generated by the enclosing block to STDERR. =head2 null The null filter prints nothing. This is useful for plugins whose methods return values that you don't want to appear in the output. Rather than assigning every plugin method call to a dummy variable to silence it, you can wrap the block in a null filter: [% FILTER null; USE im = GD.Image(100,100); black = im.colorAllocate(0, 0, 0); red = im.colorAllocate(255,0, 0); blue = im.colorAllocate(0, 0, 255); im.arc(50,50,95,75,0,360,blue); im.fill(50,50,red); im.png | stdout(1); END; -%] Notice the use of the stdout filter to ensure that a particular expression generates output to stdout (in this case in binary mode). =head2 latex(outputType) Passes the text block to LaTeX and produces either PDF, DVI or PostScript output. The 'outputType' argument determines the output format and it should be set to one of the strings: "pdf" (default), "dvi", or "ps". The text block should be a complete LaTeX source file. [% FILTER latex("pdf") -%] \documentclass{article} \begin{document} \title{A Sample TT2 \LaTeX\ Source File} \author{Craig Barratt} \maketitle \section{Introduction} This is some text. \end{document} [% END -%] The output will be a PDF file. You should be careful not to prepend or append any extraneous characters or text outside the FILTER block, since this text will wrap the (binary) output of the latex filter. Notice the END directive uses '-%]' for the END_TAG to remove the trailing new line. One example where you might prepend text is in a CGI script where you might include the Content-Type before the latex output, eg: Content-Type: application/pdf [% FILTER latex("pdf") -%] \documentclass{article} \begin{document} ... \end{document} [% END -%] In other cases you might use the redirect filter to put the output into a file, rather than delivering it to stdout. This might be suitable for batch scripts: [% output = FILTER latex("pdf") -%] \documentclass{article} \begin{document} ... \end{document} [% END; output | redirect("document.pdf", 1) -%] (Notice the second argument to redirect to force binary mode.) Note that the latex filter runs one or two external programs, so it isn't very fast. But for modest documents the performance is adequate, even for interactive applications. A error of type 'latex' will be thrown if there is an error reported by latex, pdflatex or dvips. =head1 AUTHOR Andy Wardley E<lt>abw@andywardley.comE<gt> L<http://www.andywardley.com/|http://www.andywardley.com/> =head1 VERSION 2.72, distributed as part of the Template Toolkit version 2.10, released on 24 July 2003. =head1 COPYRIGHT Copyright (C) 1996-2003 Andy Wardley. All Rights Reserved. Copyright (C) 1998-2002 Canon Research Centre Europe Ltd. This module is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =head1 SEE ALSO L<Template|Template>, L<Template::Context|Template::Context>, L<Template::Manual::Filters|Template::Manual::Filters> ������������������������������������������������������������������������������vdradmin-am-3.6.13/lib/Template/Grammar.pm����������������������������������������������������������0000664�0000000�0000000�00000274130�14437161134�0020263�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#============================================================= -*-Perl-*- # # Template::Grammar # # DESCRIPTION # Grammar file for the Template Toolkit language containing token # definitions and parser state/rules tables generated by Parse::Yapp. # # AUTHOR # Andy Wardley <abw@kfs.org> # # COPYRIGHT # Copyright (C) 1996-2000 Andy Wardley. All Rights Reserved. # Copyright (C) 1998-2000 Canon Research Centre Europe Ltd. # # This module is free software; you can redistribute it and/or # modify it under the same terms as Perl itself. # #------------------------------------------------------------------------ # # NOTE: this module is constructed from the parser/Grammar.pm.skel # file by running the parser/yc script. You only need to do this if # you have modified the grammar in the parser/Parser.yp file and need # to-recompile it. See the README in the 'parser' directory for more # information (sub-directory of the Template distribution). # #------------------------------------------------------------------------ # # $Id: Grammar.pm,v 2.19 2003/04/29 12:47:22 abw Exp $ # #======================================================================== package Template::Grammar; require 5.004; use strict; use vars qw( $VERSION ); $VERSION = sprintf("%d.%02d", q$Revision: 2.19 $ =~ /(\d+)\.(\d+)/); my (@RESERVED, %CMPOP, $LEXTABLE, $RULES, $STATES); my ($factory, $rawstart); #======================================================================== # Reserved words, comparison and binary operators #======================================================================== @RESERVED = qw( GET CALL SET DEFAULT INSERT INCLUDE PROCESS WRAPPER BLOCK END USE PLUGIN FILTER MACRO PERL RAWPERL TO STEP AND OR NOT DIV MOD IF UNLESS ELSE ELSIF FOR NEXT WHILE SWITCH CASE META IN TRY THROW CATCH FINAL LAST RETURN STOP CLEAR VIEW DEBUG ); # for historical reasons, != and == are converted to ne and eq to perform # stringwise comparison (mainly because it doesn't generate "non-numerical # comparison" warnings which != and == can) but the others (e.g. < > <= >=) # are not converted to their stringwise equivalents. I added 'gt' et al, # briefly for v2.04d and then took them out again in 2.04e. %CMPOP = qw( != ne == eq < < > > >= >= <= <= ); #======================================================================== # Lexer Token Table #======================================================================== # lookup table used by lexer is initialised with special-cases $LEXTABLE = { 'FOREACH' => 'FOR', 'BREAK' => 'LAST', '&&' => 'AND', '||' => 'OR', '!' => 'NOT', '|' => 'FILTER', '.' => 'DOT', '_' => 'CAT', '..' => 'TO', # ':' => 'MACRO', '=' => 'ASSIGN', '=>' => 'ASSIGN', # '->' => 'ARROW', ',' => 'COMMA', '\\' => 'REF', 'and' => 'AND', # explicitly specified so that qw( and or 'or' => 'OR', # not ) can always be used in lower case, 'not' => 'NOT', # regardless of ANYCASE flag 'mod' => 'MOD', 'div' => 'DIV', }; # localise the temporary variables needed to complete lexer table { # my @tokens = qw< ( ) [ ] { } ${ $ / ; : ? >; my @tokens = qw< ( ) [ ] { } ${ $ + / ; : ? >; my @cmpop = keys %CMPOP; # my @binop = qw( + - * % ); # '/' above, in @tokens my @binop = qw( - * % ); # '+' and '/' above, in @tokens # fill lexer table, slice by slice, with reserved words and operators @$LEXTABLE{ @RESERVED, @cmpop, @binop, @tokens } = ( @RESERVED, ('CMPOP') x @cmpop, ('BINOP') x @binop, @tokens ); } #======================================================================== # CLASS METHODS #======================================================================== sub new { my $class = shift; bless { LEXTABLE => $LEXTABLE, STATES => $STATES, RULES => $RULES, }, $class; } # update method to set package-scoped $factory lexical sub install_factory { my ($self, $new_factory) = @_; $factory = $new_factory; } #======================================================================== # States #======================================================================== $STATES = [ {#State 0 ACTIONS => { 'SET' => 1, 'PERL' => 40, 'NOT' => 38, 'IDENT' => 2, 'CLEAR' => 41, 'UNLESS' => 3, 'IF' => 44, "\$" => 43, 'STOP' => 6, 'CALL' => 45, 'THROW' => 8, 'GET' => 47, "[" => 9, 'TRY' => 10, 'LAST' => 49, 'DEBUG' => 51, 'RAWPERL' => 13, 'META' => 15, 'INCLUDE' => 17, "(" => 53, 'SWITCH' => 54, 'MACRO' => 18, 'WRAPPER' => 55, ";" => -18, 'FOR' => 21, 'NEXT' => 22, 'LITERAL' => 57, 'TEXT' => 24, "\"" => 60, 'PROCESS' => 61, 'RETURN' => 64, 'FILTER' => 25, 'INSERT' => 65, 'NUMBER' => 26, 'REF' => 27, 'WHILE' => 67, 'BLOCK' => 28, 'DEFAULT' => 69, "{" => 30, 'USE' => 32, 'VIEW' => 36, "\${" => 37 }, DEFAULT => -3, GOTOS => { 'item' => 39, 'node' => 23, 'rawperl' => 59, 'term' => 58, 'loop' => 4, 'use' => 63, 'expr' => 62, 'capture' => 42, 'statement' => 5, 'view' => 7, 'wrapper' => 46, 'atomexpr' => 48, 'chunk' => 11, 'defblock' => 66, 'atomdir' => 12, 'anonblock' => 50, 'template' => 52, 'sterm' => 68, 'defblockname' => 14, 'filter' => 29, 'ident' => 16, 'perl' => 31, 'setlist' => 70, 'chunks' => 33, 'switch' => 34, 'try' => 35, 'assign' => 19, 'block' => 72, 'directive' => 71, 'macro' => 20, 'condition' => 73, 'lterm' => 56 } }, {#State 1 ACTIONS => { "\$" => 43, 'LITERAL' => 75, 'IDENT' => 2, "\${" => 37 }, GOTOS => { 'setlist' => 76, 'item' => 39, 'assign' => 19, 'node' => 23, 'ident' => 74 } }, {#State 2 DEFAULT => -130 }, {#State 3 ACTIONS => { 'NOT' => 38, "{" => 30, 'LITERAL' => 78, 'IDENT' => 2, "\"" => 60, "(" => 53, "\$" => 43, "[" => 9, 'NUMBER' => 26, 'REF' => 27, "\${" => 37 }, GOTOS => { 'expr' => 79, 'sterm' => 68, 'item' => 39, 'node' => 23, 'ident' => 77, 'term' => 58, 'lterm' => 56 } }, {#State 4 DEFAULT => -23 }, {#State 5 ACTIONS => { ";" => 80 } }, {#State 6 DEFAULT => -37 }, {#State 7 DEFAULT => -14 }, {#State 8 ACTIONS => { "\"" => 89, "\$" => 86, 'LITERAL' => 88, 'FILENAME' => 83, 'IDENT' => 81, 'NUMBER' => 84 }, GOTOS => { 'filepart' => 87, 'names' => 91, 'nameargs' => 90, 'filename' => 85, 'name' => 82 } }, {#State 9 ACTIONS => { "{" => 30, 'LITERAL' => 78, 'IDENT' => 2, "\"" => 60, "\$" => 43, "[" => 9, 'NUMBER' => 26, 'REF' => 27, "]" => 94, "\${" => 37 }, GOTOS => { 'sterm' => 96, 'item' => 39, 'range' => 93, 'node' => 23, 'ident' => 77, 'term' => 95, 'list' => 92, 'lterm' => 56 } }, {#State 10 ACTIONS => { ";" => 97 } }, {#State 11 DEFAULT => -5 }, {#State 12 ACTIONS => { ";" => -20 }, DEFAULT => -27 }, {#State 13 DEFAULT => -78, GOTOS => { '@5-1' => 98 } }, {#State 14 ACTIONS => { 'IDENT' => 99 }, DEFAULT => -87, GOTOS => { 'blockargs' => 102, 'metadata' => 101, 'meta' => 100 } }, {#State 15 ACTIONS => { 'IDENT' => 99 }, GOTOS => { 'metadata' => 103, 'meta' => 100 } }, {#State 16 ACTIONS => { 'DOT' => 104, 'ASSIGN' => 105 }, DEFAULT => -109 }, {#State 17 ACTIONS => { "\"" => 89, "\$" => 86, 'LITERAL' => 88, 'FILENAME' => 83, 'IDENT' => 81, 'NUMBER' => 84 }, GOTOS => { 'filepart' => 87, 'names' => 91, 'nameargs' => 106, 'filename' => 85, 'name' => 82 } }, {#State 18 ACTIONS => { 'IDENT' => 107 } }, {#State 19 DEFAULT => -149 }, {#State 20 DEFAULT => -12 }, {#State 21 ACTIONS => { "{" => 30, 'LITERAL' => 78, 'IDENT' => 108, "\"" => 60, "\$" => 43, "[" => 9, 'NUMBER' => 26, 'REF' => 27, "\${" => 37 }, GOTOS => { 'sterm' => 68, 'item' => 39, 'loopvar' => 110, 'node' => 23, 'ident' => 77, 'term' => 109, 'lterm' => 56 } }, {#State 22 DEFAULT => -40 }, {#State 23 DEFAULT => -127 }, {#State 24 DEFAULT => -6 }, {#State 25 ACTIONS => { "\"" => 117, "\$" => 114, 'LITERAL' => 116, 'FILENAME' => 83, 'IDENT' => 111, 'NUMBER' => 84, "\${" => 37 }, GOTOS => { 'filepart' => 87, 'names' => 91, 'nameargs' => 118, 'filename' => 85, 'lvalue' => 112, 'lnameargs' => 115, 'item' => 113, 'name' => 82 } }, {#State 26 DEFAULT => -113 }, {#State 27 ACTIONS => { "\$" => 43, 'IDENT' => 2, "\${" => 37 }, GOTOS => { 'item' => 39, 'node' => 23, 'ident' => 119 } }, {#State 28 ACTIONS => { 'LITERAL' => 124, 'FILENAME' => 83, 'IDENT' => 120, 'NUMBER' => 84 }, DEFAULT => -87, GOTOS => { 'blockargs' => 123, 'filepart' => 87, 'filename' => 122, 'blockname' => 121, 'metadata' => 101, 'meta' => 100 } }, {#State 29 DEFAULT => -43 }, {#State 30 ACTIONS => { "\$" => 43, 'LITERAL' => 129, 'IDENT' => 2, "\${" => 37 }, DEFAULT => -119, GOTOS => { 'params' => 128, 'hash' => 125, 'item' => 126, 'param' => 127 } }, {#State 31 DEFAULT => -25 }, {#State 32 ACTIONS => { "\"" => 117, "\$" => 114, 'LITERAL' => 116, 'FILENAME' => 83, 'IDENT' => 111, 'NUMBER' => 84, "\${" => 37 }, GOTOS => { 'filepart' => 87, 'names' => 91, 'nameargs' => 118, 'filename' => 85, 'lvalue' => 112, 'lnameargs' => 130, 'item' => 113, 'name' => 82 } }, {#State 33 ACTIONS => { 'SET' => 1, 'PERL' => 40, 'NOT' => 38, 'IDENT' => 2, 'CLEAR' => 41, 'UNLESS' => 3, 'IF' => 44, "\$" => 43, 'STOP' => 6, 'CALL' => 45, 'THROW' => 8, 'GET' => 47, "[" => 9, 'TRY' => 10, 'LAST' => 49, 'DEBUG' => 51, 'RAWPERL' => 13, 'META' => 15, 'INCLUDE' => 17, "(" => 53, 'SWITCH' => 54, 'MACRO' => 18, 'WRAPPER' => 55, ";" => -18, 'FOR' => 21, 'NEXT' => 22, 'LITERAL' => 57, 'TEXT' => 24, "\"" => 60, 'PROCESS' => 61, 'RETURN' => 64, 'FILTER' => 25, 'INSERT' => 65, 'NUMBER' => 26, 'REF' => 27, 'WHILE' => 67, 'BLOCK' => 28, 'DEFAULT' => 69, "{" => 30, 'USE' => 32, 'VIEW' => 36, "\${" => 37 }, DEFAULT => -2, GOTOS => { 'item' => 39, 'node' => 23, 'rawperl' => 59, 'term' => 58, 'loop' => 4, 'use' => 63, 'expr' => 62, 'capture' => 42, 'statement' => 5, 'view' => 7, 'wrapper' => 46, 'atomexpr' => 48, 'chunk' => 131, 'defblock' => 66, 'atomdir' => 12, 'anonblock' => 50, 'sterm' => 68, 'defblockname' => 14, 'filter' => 29, 'ident' => 16, 'perl' => 31, 'setlist' => 70, 'try' => 35, 'switch' => 34, 'assign' => 19, 'directive' => 71, 'macro' => 20, 'condition' => 73, 'lterm' => 56 } }, {#State 34 DEFAULT => -22 }, {#State 35 DEFAULT => -24 }, {#State 36 ACTIONS => { "\"" => 89, "\$" => 86, 'LITERAL' => 88, 'FILENAME' => 83, 'IDENT' => 81, 'NUMBER' => 84 }, GOTOS => { 'filepart' => 87, 'names' => 91, 'nameargs' => 132, 'filename' => 85, 'name' => 82 } }, {#State 37 ACTIONS => { "\"" => 60, "\$" => 43, 'LITERAL' => 78, 'IDENT' => 2, 'REF' => 27, 'NUMBER' => 26, "\${" => 37 }, GOTOS => { 'sterm' => 133, 'item' => 39, 'node' => 23, 'ident' => 77 } }, {#State 38 ACTIONS => { 'NOT' => 38, "{" => 30, 'LITERAL' => 78, 'IDENT' => 2, "\"" => 60, "(" => 53, "\$" => 43, "[" => 9, 'NUMBER' => 26, 'REF' => 27, "\${" => 37 }, GOTOS => { 'expr' => 134, 'sterm' => 68, 'item' => 39, 'node' => 23, 'ident' => 77, 'term' => 58, 'lterm' => 56 } }, {#State 39 ACTIONS => { "(" => 135 }, DEFAULT => -128 }, {#State 40 ACTIONS => { ";" => 136 } }, {#State 41 DEFAULT => -38 }, {#State 42 DEFAULT => -11 }, {#State 43 ACTIONS => { 'IDENT' => 137 } }, {#State 44 ACTIONS => { 'NOT' => 38, "{" => 30, 'LITERAL' => 78, 'IDENT' => 2, "\"" => 60, "(" => 53, "\$" => 43, "[" => 9, 'NUMBER' => 26, 'REF' => 27, "\${" => 37 }, GOTOS => { 'expr' => 138, 'sterm' => 68, 'item' => 39, 'node' => 23, 'ident' => 77, 'term' => 58, 'lterm' => 56 } }, {#State 45 ACTIONS => { 'NOT' => 38, "{" => 30, 'LITERAL' => 78, 'IDENT' => 2, "\"" => 60, "(" => 53, "\$" => 43, "[" => 9, 'NUMBER' => 26, 'REF' => 27, "\${" => 37 }, GOTOS => { 'expr' => 139, 'sterm' => 68, 'item' => 39, 'node' => 23, 'ident' => 77, 'term' => 58, 'lterm' => 56 } }, {#State 46 DEFAULT => -42 }, {#State 47 ACTIONS => { 'NOT' => 38, "{" => 30, 'LITERAL' => 78, 'IDENT' => 2, "\"" => 60, "(" => 53, "\$" => 43, "[" => 9, 'NUMBER' => 26, 'REF' => 27, "\${" => 37 }, GOTOS => { 'expr' => 140, 'sterm' => 68, 'item' => 39, 'node' => 23, 'ident' => 77, 'term' => 58, 'lterm' => 56 } }, {#State 48 ACTIONS => { 'IF' => 144, 'FILTER' => 143, 'FOR' => 142, 'WHILE' => 146, 'WRAPPER' => 145, 'UNLESS' => 141 } }, {#State 49 DEFAULT => -39 }, {#State 50 DEFAULT => -10 }, {#State 51 ACTIONS => { "\"" => 89, "\$" => 86, 'LITERAL' => 88, 'FILENAME' => 83, 'IDENT' => 81, 'NUMBER' => 84 }, GOTOS => { 'filepart' => 87, 'names' => 91, 'nameargs' => 147, 'filename' => 85, 'name' => 82 } }, {#State 52 ACTIONS => { '' => 148 } }, {#State 53 ACTIONS => { 'NOT' => 38, "{" => 30, 'LITERAL' => 57, 'IDENT' => 2, "\"" => 60, "(" => 53, "\$" => 43, "[" => 9, 'NUMBER' => 26, 'REF' => 27, "\${" => 37 }, GOTOS => { 'sterm' => 68, 'item' => 39, 'node' => 23, 'ident' => 149, 'term' => 58, 'expr' => 151, 'assign' => 150, 'lterm' => 56 } }, {#State 54 ACTIONS => { 'NOT' => 38, "{" => 30, 'LITERAL' => 78, 'IDENT' => 2, "\"" => 60, "(" => 53, "\$" => 43, "[" => 9, 'NUMBER' => 26, 'REF' => 27, "\${" => 37 }, GOTOS => { 'expr' => 152, 'sterm' => 68, 'item' => 39, 'node' => 23, 'ident' => 77, 'term' => 58, 'lterm' => 56 } }, {#State 55 ACTIONS => { "\"" => 89, "\$" => 86, 'LITERAL' => 88, 'FILENAME' => 83, 'IDENT' => 81, 'NUMBER' => 84 }, GOTOS => { 'filepart' => 87, 'names' => 91, 'nameargs' => 153, 'filename' => 85, 'name' => 82 } }, {#State 56 DEFAULT => -103 }, {#State 57 ACTIONS => { 'ASSIGN' => 154 }, DEFAULT => -112 }, {#State 58 DEFAULT => -146 }, {#State 59 DEFAULT => -15 }, {#State 60 DEFAULT => -176, GOTOS => { 'quoted' => 155 } }, {#State 61 ACTIONS => { "\"" => 89, "\$" => 86, 'LITERAL' => 88, 'FILENAME' => 83, 'IDENT' => 81, 'NUMBER' => 84 }, GOTOS => { 'filepart' => 87, 'names' => 91, 'nameargs' => 156, 'filename' => 85, 'name' => 82 } }, {#State 62 ACTIONS => { ";" => -16, "+" => 157, 'CAT' => 163, 'CMPOP' => 164, "?" => 158, 'DIV' => 159, 'MOD' => 165, "/" => 166, 'AND' => 160, 'BINOP' => 161, 'OR' => 162 }, DEFAULT => -26 }, {#State 63 DEFAULT => -13 }, {#State 64 DEFAULT => -36 }, {#State 65 ACTIONS => { "\"" => 89, "\$" => 86, 'LITERAL' => 88, 'FILENAME' => 83, 'IDENT' => 81, 'NUMBER' => 84 }, GOTOS => { 'filepart' => 87, 'names' => 91, 'nameargs' => 167, 'filename' => 85, 'name' => 82 } }, {#State 66 DEFAULT => -9 }, {#State 67 ACTIONS => { 'NOT' => 38, "{" => 30, 'LITERAL' => 78, 'IDENT' => 2, "\"" => 60, "(" => 53, "\$" => 43, "[" => 9, 'NUMBER' => 26, 'REF' => 27, "\${" => 37 }, GOTOS => { 'expr' => 168, 'sterm' => 68, 'item' => 39, 'node' => 23, 'ident' => 77, 'term' => 58, 'lterm' => 56 } }, {#State 68 DEFAULT => -104 }, {#State 69 ACTIONS => { "\$" => 43, 'LITERAL' => 75, 'IDENT' => 2, "\${" => 37 }, GOTOS => { 'setlist' => 169, 'item' => 39, 'assign' => 19, 'node' => 23, 'ident' => 74 } }, {#State 70 ACTIONS => { "\$" => 43, 'COMMA' => 171, 'LITERAL' => 75, 'IDENT' => 2, "\${" => 37 }, DEFAULT => -19, GOTOS => { 'item' => 39, 'assign' => 170, 'node' => 23, 'ident' => 74 } }, {#State 71 DEFAULT => -8 }, {#State 72 DEFAULT => -1 }, {#State 73 DEFAULT => -21 }, {#State 74 ACTIONS => { 'ASSIGN' => 172, 'DOT' => 104 } }, {#State 75 ACTIONS => { 'ASSIGN' => 154 } }, {#State 76 ACTIONS => { "\$" => 43, 'COMMA' => 171, 'LITERAL' => 75, 'IDENT' => 2, "\${" => 37 }, DEFAULT => -30, GOTOS => { 'item' => 39, 'assign' => 170, 'node' => 23, 'ident' => 74 } }, {#State 77 ACTIONS => { 'DOT' => 104 }, DEFAULT => -109 }, {#State 78 DEFAULT => -112 }, {#State 79 ACTIONS => { 'CMPOP' => 164, "?" => 158, ";" => 173, "+" => 157, 'MOD' => 165, 'DIV' => 159, "/" => 166, 'AND' => 160, 'CAT' => 163, 'BINOP' => 161, 'OR' => 162 } }, {#State 80 DEFAULT => -7 }, {#State 81 DEFAULT => -173 }, {#State 82 DEFAULT => -166 }, {#State 83 DEFAULT => -172 }, {#State 84 DEFAULT => -174 }, {#State 85 ACTIONS => { 'DOT' => 174 }, DEFAULT => -168 }, {#State 86 ACTIONS => { "\$" => 43, 'IDENT' => 2, "\${" => 37 }, GOTOS => { 'item' => 39, 'node' => 23, 'ident' => 175 } }, {#State 87 DEFAULT => -171 }, {#State 88 DEFAULT => -169 }, {#State 89 DEFAULT => -176, GOTOS => { 'quoted' => 176 } }, {#State 90 DEFAULT => -35 }, {#State 91 ACTIONS => { "+" => 177, "(" => 178 }, DEFAULT => -156, GOTOS => { 'args' => 179 } }, {#State 92 ACTIONS => { "{" => 30, 'COMMA' => 182, 'LITERAL' => 78, 'IDENT' => 2, "\"" => 60, "\$" => 43, "[" => 9, 'NUMBER' => 26, 'REF' => 27, "]" => 180, "\${" => 37 }, GOTOS => { 'sterm' => 68, 'item' => 39, 'node' => 23, 'ident' => 77, 'term' => 181, 'lterm' => 56 } }, {#State 93 ACTIONS => { "]" => 183 } }, {#State 94 DEFAULT => -107 }, {#State 95 DEFAULT => -116 }, {#State 96 ACTIONS => { 'TO' => 184 }, DEFAULT => -104 }, {#State 97 ACTIONS => { 'SET' => 1, 'PERL' => 40, 'NOT' => 38, 'IDENT' => 2, 'CLEAR' => 41, 'UNLESS' => 3, 'IF' => 44, "\$" => 43, 'STOP' => 6, 'CALL' => 45, 'THROW' => 8, 'GET' => 47, "[" => 9, 'TRY' => 10, 'LAST' => 49, 'DEBUG' => 51, 'RAWPERL' => 13, 'META' => 15, 'INCLUDE' => 17, "(" => 53, 'SWITCH' => 54, 'MACRO' => 18, 'WRAPPER' => 55, ";" => -18, 'FOR' => 21, 'NEXT' => 22, 'LITERAL' => 57, 'TEXT' => 24, "\"" => 60, 'PROCESS' => 61, 'RETURN' => 64, 'FILTER' => 25, 'INSERT' => 65, 'NUMBER' => 26, 'REF' => 27, 'WHILE' => 67, 'BLOCK' => 28, 'DEFAULT' => 69, "{" => 30, 'USE' => 32, 'VIEW' => 36, "\${" => 37 }, DEFAULT => -3, GOTOS => { 'item' => 39, 'node' => 23, 'rawperl' => 59, 'term' => 58, 'loop' => 4, 'use' => 63, 'expr' => 62, 'capture' => 42, 'statement' => 5, 'view' => 7, 'wrapper' => 46, 'atomexpr' => 48, 'chunk' => 11, 'defblock' => 66, 'atomdir' => 12, 'anonblock' => 50, 'sterm' => 68, 'defblockname' => 14, 'filter' => 29, 'ident' => 16, 'perl' => 31, 'setlist' => 70, 'chunks' => 33, 'try' => 35, 'switch' => 34, 'assign' => 19, 'block' => 185, 'directive' => 71, 'macro' => 20, 'condition' => 73, 'lterm' => 56 } }, {#State 98 ACTIONS => { ";" => 186 } }, {#State 99 ACTIONS => { 'ASSIGN' => 187 } }, {#State 100 DEFAULT => -99 }, {#State 101 ACTIONS => { 'COMMA' => 189, 'IDENT' => 99 }, DEFAULT => -86, GOTOS => { 'meta' => 188 } }, {#State 102 ACTIONS => { ";" => 190 } }, {#State 103 ACTIONS => { 'COMMA' => 189, 'IDENT' => 99 }, DEFAULT => -17, GOTOS => { 'meta' => 188 } }, {#State 104 ACTIONS => { "\$" => 43, 'IDENT' => 2, 'NUMBER' => 192, "\${" => 37 }, GOTOS => { 'item' => 39, 'node' => 191 } }, {#State 105 ACTIONS => { 'SET' => 1, 'PERL' => 40, 'NOT' => 38, 'IDENT' => 2, 'CLEAR' => 41, 'UNLESS' => 3, 'IF' => 44, "\$" => 43, 'STOP' => 6, 'CALL' => 45, 'THROW' => 8, 'GET' => 47, "[" => 9, 'TRY' => 10, 'LAST' => 49, 'DEBUG' => 51, 'INCLUDE' => 17, "(" => 53, 'SWITCH' => 54, 'WRAPPER' => 55, 'FOR' => 21, 'NEXT' => 22, 'LITERAL' => 57, "\"" => 60, 'PROCESS' => 61, 'FILTER' => 25, 'RETURN' => 64, 'INSERT' => 65, 'NUMBER' => 26, 'REF' => 27, 'WHILE' => 67, 'BLOCK' => 193, 'DEFAULT' => 69, "{" => 30, "\${" => 37 }, GOTOS => { 'item' => 39, 'node' => 23, 'term' => 58, 'loop' => 4, 'expr' => 195, 'wrapper' => 46, 'atomexpr' => 48, 'atomdir' => 12, 'mdir' => 194, 'sterm' => 68, 'filter' => 29, 'ident' => 149, 'perl' => 31, 'setlist' => 70, 'switch' => 34, 'try' => 35, 'assign' => 19, 'directive' => 196, 'condition' => 73, 'lterm' => 56 } }, {#State 106 DEFAULT => -33 }, {#State 107 ACTIONS => { 'SET' => 1, 'PERL' => 40, 'NOT' => 38, 'IDENT' => 2, 'CLEAR' => 41, 'UNLESS' => 3, 'IF' => 44, "\$" => 43, 'STOP' => 6, 'CALL' => 45, 'THROW' => 8, 'GET' => 47, "[" => 9, 'TRY' => 10, 'LAST' => 49, 'DEBUG' => 51, 'INCLUDE' => 17, "(" => 198, 'SWITCH' => 54, 'WRAPPER' => 55, 'FOR' => 21, 'NEXT' => 22, 'LITERAL' => 57, "\"" => 60, 'PROCESS' => 61, 'FILTER' => 25, 'RETURN' => 64, 'INSERT' => 65, 'NUMBER' => 26, 'REF' => 27, 'WHILE' => 67, 'BLOCK' => 193, 'DEFAULT' => 69, "{" => 30, "\${" => 37 }, GOTOS => { 'item' => 39, 'node' => 23, 'term' => 58, 'loop' => 4, 'expr' => 199, 'wrapper' => 46, 'atomexpr' => 48, 'atomdir' => 12, 'mdir' => 197, 'sterm' => 68, 'filter' => 29, 'ident' => 149, 'perl' => 31, 'setlist' => 70, 'switch' => 34, 'try' => 35, 'assign' => 19, 'directive' => 196, 'condition' => 73, 'lterm' => 56 } }, {#State 108 ACTIONS => { 'IN' => 201, 'ASSIGN' => 200 }, DEFAULT => -130 }, {#State 109 DEFAULT => -156, GOTOS => { 'args' => 202 } }, {#State 110 ACTIONS => { ";" => 203 } }, {#State 111 ACTIONS => { 'ASSIGN' => -130 }, DEFAULT => -173 }, {#State 112 ACTIONS => { 'ASSIGN' => 204 } }, {#State 113 DEFAULT => -159 }, {#State 114 ACTIONS => { "\$" => 43, 'IDENT' => 205, "\${" => 37 }, GOTOS => { 'item' => 39, 'node' => 23, 'ident' => 175 } }, {#State 115 ACTIONS => { ";" => 206 } }, {#State 116 ACTIONS => { 'ASSIGN' => -161 }, DEFAULT => -169 }, {#State 117 DEFAULT => -176, GOTOS => { 'quoted' => 207 } }, {#State 118 DEFAULT => -158 }, {#State 119 ACTIONS => { 'DOT' => 104 }, DEFAULT => -110 }, {#State 120 ACTIONS => { 'ASSIGN' => 187 }, DEFAULT => -173 }, {#State 121 DEFAULT => -83 }, {#State 122 ACTIONS => { 'DOT' => 174 }, DEFAULT => -84 }, {#State 123 ACTIONS => { ";" => 208 } }, {#State 124 DEFAULT => -85 }, {#State 125 ACTIONS => { "}" => 209 } }, {#State 126 ACTIONS => { 'ASSIGN' => 210 } }, {#State 127 DEFAULT => -122 }, {#State 128 ACTIONS => { "\$" => 43, 'COMMA' => 212, 'LITERAL' => 129, 'IDENT' => 2, "\${" => 37 }, DEFAULT => -118, GOTOS => { 'item' => 126, 'param' => 211 } }, {#State 129 ACTIONS => { 'ASSIGN' => 213 } }, {#State 130 DEFAULT => -73 }, {#State 131 DEFAULT => -4 }, {#State 132 ACTIONS => { ";" => 214 } }, {#State 133 ACTIONS => { "}" => 215 } }, {#State 134 ACTIONS => { "+" => 157, 'CAT' => 163, 'CMPOP' => 164, 'DIV' => 159, 'MOD' => 165, "/" => 166, 'BINOP' => 161 }, DEFAULT => -142 }, {#State 135 DEFAULT => -156, GOTOS => { 'args' => 216 } }, {#State 136 DEFAULT => -76, GOTOS => { '@4-2' => 217 } }, {#State 137 DEFAULT => -132 }, {#State 138 ACTIONS => { 'CMPOP' => 164, "?" => 158, ";" => 218, "+" => 157, 'MOD' => 165, 'DIV' => 159, "/" => 166, 'AND' => 160, 'CAT' => 163, 'BINOP' => 161, 'OR' => 162 } }, {#State 139 ACTIONS => { "+" => 157, 'CAT' => 163, 'CMPOP' => 164, "?" => 158, 'DIV' => 159, 'MOD' => 165, "/" => 166, 'AND' => 160, 'BINOP' => 161, 'OR' => 162 }, DEFAULT => -29 }, {#State 140 ACTIONS => { "+" => 157, 'CAT' => 163, 'CMPOP' => 164, "?" => 158, 'DIV' => 159, 'MOD' => 165, "/" => 166, 'AND' => 160, 'BINOP' => 161, 'OR' => 162 }, DEFAULT => -28 }, {#State 141 ACTIONS => { 'NOT' => 38, "{" => 30, 'LITERAL' => 78, 'IDENT' => 2, "\"" => 60, "(" => 53, "\$" => 43, "[" => 9, 'NUMBER' => 26, 'REF' => 27, "\${" => 37 }, GOTOS => { 'expr' => 219, 'sterm' => 68, 'item' => 39, 'node' => 23, 'ident' => 77, 'term' => 58, 'lterm' => 56 } }, {#State 142 ACTIONS => { "{" => 30, 'LITERAL' => 78, 'IDENT' => 108, "\"" => 60, "\$" => 43, "[" => 9, 'NUMBER' => 26, 'REF' => 27, "\${" => 37 }, GOTOS => { 'sterm' => 68, 'item' => 39, 'loopvar' => 220, 'node' => 23, 'ident' => 77, 'term' => 109, 'lterm' => 56 } }, {#State 143 ACTIONS => { "\"" => 117, "\$" => 114, 'LITERAL' => 116, 'FILENAME' => 83, 'IDENT' => 111, 'NUMBER' => 84, "\${" => 37 }, GOTOS => { 'filepart' => 87, 'names' => 91, 'nameargs' => 118, 'filename' => 85, 'lvalue' => 112, 'lnameargs' => 221, 'item' => 113, 'name' => 82 } }, {#State 144 ACTIONS => { 'NOT' => 38, "{" => 30, 'LITERAL' => 78, 'IDENT' => 2, "\"" => 60, "(" => 53, "\$" => 43, "[" => 9, 'NUMBER' => 26, 'REF' => 27, "\${" => 37 }, GOTOS => { 'expr' => 222, 'sterm' => 68, 'item' => 39, 'node' => 23, 'ident' => 77, 'term' => 58, 'lterm' => 56 } }, {#State 145 ACTIONS => { "\"" => 89, "\$" => 86, 'LITERAL' => 88, 'FILENAME' => 83, 'IDENT' => 81, 'NUMBER' => 84 }, GOTOS => { 'filepart' => 87, 'names' => 91, 'nameargs' => 223, 'filename' => 85, 'name' => 82 } }, {#State 146 ACTIONS => { 'NOT' => 38, "{" => 30, 'LITERAL' => 78, 'IDENT' => 2, "\"" => 60, "(" => 53, "\$" => 43, "[" => 9, 'NUMBER' => 26, 'REF' => 27, "\${" => 37 }, GOTOS => { 'expr' => 224, 'sterm' => 68, 'item' => 39, 'node' => 23, 'ident' => 77, 'term' => 58, 'lterm' => 56 } }, {#State 147 DEFAULT => -41 }, {#State 148 DEFAULT => 0 }, {#State 149 ACTIONS => { 'DOT' => 104, 'ASSIGN' => 172 }, DEFAULT => -109 }, {#State 150 ACTIONS => { ")" => 225 } }, {#State 151 ACTIONS => { 'CMPOP' => 164, "?" => 158, "+" => 157, 'MOD' => 165, 'DIV' => 159, "/" => 166, 'AND' => 160, 'CAT' => 163, 'BINOP' => 161, ")" => 226, 'OR' => 162 } }, {#State 152 ACTIONS => { 'CMPOP' => 164, "?" => 158, ";" => 227, "+" => 157, 'MOD' => 165, 'DIV' => 159, "/" => 166, 'AND' => 160, 'CAT' => 163, 'BINOP' => 161, 'OR' => 162 } }, {#State 153 ACTIONS => { ";" => 228 } }, {#State 154 ACTIONS => { 'NOT' => 38, "{" => 30, 'LITERAL' => 78, 'IDENT' => 2, "\"" => 60, "(" => 53, "\$" => 43, "[" => 9, 'NUMBER' => 26, 'REF' => 27, "\${" => 37 }, GOTOS => { 'expr' => 229, 'sterm' => 68, 'item' => 39, 'node' => 23, 'ident' => 77, 'term' => 58, 'lterm' => 56 } }, {#State 155 ACTIONS => { "\"" => 234, 'TEXT' => 231, ";" => 233, "\$" => 43, 'IDENT' => 2, "\${" => 37 }, GOTOS => { 'item' => 39, 'node' => 23, 'ident' => 230, 'quotable' => 232 } }, {#State 156 DEFAULT => -34 }, {#State 157 ACTIONS => { 'NOT' => 38, "{" => 30, 'LITERAL' => 78, 'IDENT' => 2, "\"" => 60, "(" => 53, "\$" => 43, "[" => 9, 'NUMBER' => 26, 'REF' => 27, "\${" => 37 }, GOTOS => { 'expr' => 235, 'sterm' => 68, 'item' => 39, 'node' => 23, 'ident' => 77, 'term' => 58, 'lterm' => 56 } }, {#State 158 ACTIONS => { 'NOT' => 38, "{" => 30, 'LITERAL' => 78, 'IDENT' => 2, "\"" => 60, "(" => 53, "\$" => 43, "[" => 9, 'NUMBER' => 26, 'REF' => 27, "\${" => 37 }, GOTOS => { 'expr' => 236, 'sterm' => 68, 'item' => 39, 'node' => 23, 'ident' => 77, 'term' => 58, 'lterm' => 56 } }, {#State 159 ACTIONS => { 'NOT' => 38, "{" => 30, 'LITERAL' => 78, 'IDENT' => 2, "\"" => 60, "(" => 53, "\$" => 43, "[" => 9, 'NUMBER' => 26, 'REF' => 27, "\${" => 37 }, GOTOS => { 'expr' => 237, 'sterm' => 68, 'item' => 39, 'node' => 23, 'ident' => 77, 'term' => 58, 'lterm' => 56 } }, {#State 160 ACTIONS => { 'NOT' => 38, "{" => 30, 'LITERAL' => 78, 'IDENT' => 2, "\"" => 60, "(" => 53, "\$" => 43, "[" => 9, 'NUMBER' => 26, 'REF' => 27, "\${" => 37 }, GOTOS => { 'expr' => 238, 'sterm' => 68, 'item' => 39, 'node' => 23, 'ident' => 77, 'term' => 58, 'lterm' => 56 } }, {#State 161 ACTIONS => { 'NOT' => 38, "{" => 30, 'LITERAL' => 78, 'IDENT' => 2, "\"" => 60, "(" => 53, "\$" => 43, "[" => 9, 'NUMBER' => 26, 'REF' => 27, "\${" => 37 }, GOTOS => { 'expr' => 239, 'sterm' => 68, 'item' => 39, 'node' => 23, 'ident' => 77, 'term' => 58, 'lterm' => 56 } }, {#State 162 ACTIONS => { 'NOT' => 38, "{" => 30, 'LITERAL' => 78, 'IDENT' => 2, "\"" => 60, "(" => 53, "\$" => 43, "[" => 9, 'NUMBER' => 26, 'REF' => 27, "\${" => 37 }, GOTOS => { 'expr' => 240, 'sterm' => 68, 'item' => 39, 'node' => 23, 'ident' => 77, 'term' => 58, 'lterm' => 56 } }, {#State 163 ACTIONS => { 'NOT' => 38, "{" => 30, 'LITERAL' => 78, 'IDENT' => 2, "\"" => 60, "(" => 53, "\$" => 43, "[" => 9, 'NUMBER' => 26, 'REF' => 27, "\${" => 37 }, GOTOS => { 'expr' => 241, 'sterm' => 68, 'item' => 39, 'node' => 23, 'ident' => 77, 'term' => 58, 'lterm' => 56 } }, {#State 164 ACTIONS => { 'NOT' => 38, "{" => 30, 'LITERAL' => 78, 'IDENT' => 2, "\"" => 60, "(" => 53, "\$" => 43, "[" => 9, 'NUMBER' => 26, 'REF' => 27, "\${" => 37 }, GOTOS => { 'expr' => 242, 'sterm' => 68, 'item' => 39, 'node' => 23, 'ident' => 77, 'term' => 58, 'lterm' => 56 } }, {#State 165 ACTIONS => { 'NOT' => 38, "{" => 30, 'LITERAL' => 78, 'IDENT' => 2, "\"" => 60, "(" => 53, "\$" => 43, "[" => 9, 'NUMBER' => 26, 'REF' => 27, "\${" => 37 }, GOTOS => { 'expr' => 243, 'sterm' => 68, 'item' => 39, 'node' => 23, 'ident' => 77, 'term' => 58, 'lterm' => 56 } }, {#State 166 ACTIONS => { 'NOT' => 38, "{" => 30, 'LITERAL' => 78, 'IDENT' => 2, "\"" => 60, "(" => 53, "\$" => 43, "[" => 9, 'NUMBER' => 26, 'REF' => 27, "\${" => 37 }, GOTOS => { 'expr' => 244, 'sterm' => 68, 'item' => 39, 'node' => 23, 'ident' => 77, 'term' => 58, 'lterm' => 56 } }, {#State 167 DEFAULT => -32 }, {#State 168 ACTIONS => { 'CMPOP' => 164, "?" => 158, ";" => 245, "+" => 157, 'MOD' => 165, 'DIV' => 159, "/" => 166, 'AND' => 160, 'CAT' => 163, 'BINOP' => 161, 'OR' => 162 } }, {#State 169 ACTIONS => { "\$" => 43, 'COMMA' => 171, 'LITERAL' => 75, 'IDENT' => 2, "\${" => 37 }, DEFAULT => -31, GOTOS => { 'item' => 39, 'assign' => 170, 'node' => 23, 'ident' => 74 } }, {#State 170 DEFAULT => -147 }, {#State 171 DEFAULT => -148 }, {#State 172 ACTIONS => { 'NOT' => 38, "{" => 30, 'LITERAL' => 78, 'IDENT' => 2, "\"" => 60, "(" => 53, "\$" => 43, "[" => 9, 'NUMBER' => 26, 'REF' => 27, "\${" => 37 }, GOTOS => { 'expr' => 246, 'sterm' => 68, 'item' => 39, 'node' => 23, 'ident' => 77, 'term' => 58, 'lterm' => 56 } }, {#State 173 ACTIONS => { 'SET' => 1, 'PERL' => 40, 'NOT' => 38, 'IDENT' => 2, 'CLEAR' => 41, 'UNLESS' => 3, 'IF' => 44, "\$" => 43, 'STOP' => 6, 'CALL' => 45, 'THROW' => 8, 'GET' => 47, "[" => 9, 'TRY' => 10, 'LAST' => 49, 'DEBUG' => 51, 'RAWPERL' => 13, 'META' => 15, 'INCLUDE' => 17, "(" => 53, 'SWITCH' => 54, 'MACRO' => 18, 'WRAPPER' => 55, ";" => -18, 'FOR' => 21, 'NEXT' => 22, 'LITERAL' => 57, 'TEXT' => 24, "\"" => 60, 'PROCESS' => 61, 'RETURN' => 64, 'FILTER' => 25, 'INSERT' => 65, 'NUMBER' => 26, 'REF' => 27, 'WHILE' => 67, 'BLOCK' => 28, 'DEFAULT' => 69, "{" => 30, 'USE' => 32, 'VIEW' => 36, "\${" => 37 }, DEFAULT => -3, GOTOS => { 'item' => 39, 'node' => 23, 'rawperl' => 59, 'term' => 58, 'loop' => 4, 'use' => 63, 'expr' => 62, 'capture' => 42, 'statement' => 5, 'view' => 7, 'wrapper' => 46, 'atomexpr' => 48, 'chunk' => 11, 'defblock' => 66, 'atomdir' => 12, 'anonblock' => 50, 'sterm' => 68, 'defblockname' => 14, 'filter' => 29, 'ident' => 16, 'perl' => 31, 'setlist' => 70, 'chunks' => 33, 'try' => 35, 'switch' => 34, 'assign' => 19, 'block' => 247, 'directive' => 71, 'macro' => 20, 'condition' => 73, 'lterm' => 56 } }, {#State 174 ACTIONS => { 'FILENAME' => 83, 'IDENT' => 81, 'NUMBER' => 84 }, GOTOS => { 'filepart' => 248 } }, {#State 175 ACTIONS => { 'DOT' => 104 }, DEFAULT => -156, GOTOS => { 'args' => 249 } }, {#State 176 ACTIONS => { "\"" => 250, 'TEXT' => 231, ";" => 233, "\$" => 43, 'IDENT' => 2, "\${" => 37 }, GOTOS => { 'item' => 39, 'node' => 23, 'ident' => 230, 'quotable' => 232 } }, {#State 177 ACTIONS => { "\"" => 89, 'LITERAL' => 88, 'FILENAME' => 83, 'IDENT' => 81, 'NUMBER' => 84 }, GOTOS => { 'filepart' => 87, 'filename' => 85, 'name' => 251 } }, {#State 178 DEFAULT => -156, GOTOS => { 'args' => 252 } }, {#State 179 ACTIONS => { "{" => 30, 'COMMA' => 258, 'LITERAL' => 256, 'IDENT' => 2, "\"" => 60, "\$" => 43, "[" => 9, 'NUMBER' => 26, 'REF' => 27, "\${" => 37 }, DEFAULT => -163, GOTOS => { 'sterm' => 68, 'item' => 254, 'param' => 255, 'node' => 23, 'ident' => 253, 'term' => 257, 'lterm' => 56 } }, {#State 180 DEFAULT => -105 }, {#State 181 DEFAULT => -114 }, {#State 182 DEFAULT => -115 }, {#State 183 DEFAULT => -106 }, {#State 184 ACTIONS => { "\"" => 60, "\$" => 43, 'LITERAL' => 78, 'IDENT' => 2, 'REF' => 27, 'NUMBER' => 26, "\${" => 37 }, GOTOS => { 'sterm' => 259, 'item' => 39, 'node' => 23, 'ident' => 77 } }, {#State 185 ACTIONS => { 'FINAL' => 260, 'CATCH' => 262 }, DEFAULT => -72, GOTOS => { 'final' => 261 } }, {#State 186 ACTIONS => { 'TEXT' => 263 } }, {#State 187 ACTIONS => { "\"" => 266, 'LITERAL' => 265, 'NUMBER' => 264 } }, {#State 188 DEFAULT => -97 }, {#State 189 DEFAULT => -98 }, {#State 190 ACTIONS => { 'SET' => 1, 'PERL' => 40, 'NOT' => 38, 'IDENT' => 2, 'CLEAR' => 41, 'UNLESS' => 3, 'IF' => 44, "\$" => 43, 'STOP' => 6, 'CALL' => 45, 'THROW' => 8, 'GET' => 47, "[" => 9, 'TRY' => 10, 'LAST' => 49, 'DEBUG' => 51, 'RAWPERL' => 13, 'META' => 15, 'INCLUDE' => 17, "(" => 53, 'SWITCH' => 54, 'MACRO' => 18, 'WRAPPER' => 55, ";" => -18, 'FOR' => 21, 'NEXT' => 22, 'LITERAL' => 57, 'TEXT' => 24, "\"" => 60, 'PROCESS' => 61, 'RETURN' => 64, 'FILTER' => 25, 'INSERT' => 65, 'NUMBER' => 26, 'REF' => 27, 'WHILE' => 67, 'BLOCK' => 28, 'DEFAULT' => 69, "{" => 30, 'USE' => 32, 'VIEW' => 36, "\${" => 37 }, DEFAULT => -3, GOTOS => { 'item' => 39, 'node' => 23, 'rawperl' => 59, 'term' => 58, 'loop' => 4, 'use' => 63, 'expr' => 62, 'capture' => 42, 'statement' => 5, 'view' => 7, 'wrapper' => 46, 'atomexpr' => 48, 'chunk' => 11, 'defblock' => 66, 'atomdir' => 12, 'anonblock' => 50, 'template' => 267, 'sterm' => 68, 'defblockname' => 14, 'filter' => 29, 'ident' => 16, 'perl' => 31, 'setlist' => 70, 'chunks' => 33, 'try' => 35, 'switch' => 34, 'assign' => 19, 'block' => 72, 'directive' => 71, 'macro' => 20, 'condition' => 73, 'lterm' => 56 } }, {#State 191 DEFAULT => -125 }, {#State 192 DEFAULT => -126 }, {#State 193 ACTIONS => { ";" => 268 } }, {#State 194 DEFAULT => -89 }, {#State 195 ACTIONS => { ";" => -150, "+" => 157, 'LITERAL' => -150, 'IDENT' => -150, 'CAT' => 163, "\$" => -150, 'CMPOP' => 164, "?" => 158, 'DIV' => 159, 'MOD' => 165, 'COMMA' => -150, "/" => 166, 'AND' => 160, 'BINOP' => 161, 'OR' => 162, "\${" => -150 }, DEFAULT => -26 }, {#State 196 DEFAULT => -92 }, {#State 197 DEFAULT => -91 }, {#State 198 ACTIONS => { 'NOT' => 38, "{" => 30, 'LITERAL' => 57, 'IDENT' => 269, "\"" => 60, "(" => 53, "\$" => 43, "[" => 9, 'NUMBER' => 26, 'REF' => 27, "\${" => 37 }, GOTOS => { 'sterm' => 68, 'item' => 39, 'margs' => 270, 'node' => 23, 'ident' => 149, 'term' => 58, 'expr' => 151, 'assign' => 150, 'lterm' => 56 } }, {#State 199 ACTIONS => { "+" => 157, 'CAT' => 163, 'CMPOP' => 164, "?" => 158, 'DIV' => 159, 'MOD' => 165, "/" => 166, 'AND' => 160, 'BINOP' => 161, 'OR' => 162 }, DEFAULT => -26 }, {#State 200 ACTIONS => { "{" => 30, 'LITERAL' => 78, 'IDENT' => 2, "\"" => 60, "\$" => 43, "[" => 9, 'NUMBER' => 26, 'REF' => 27, "\${" => 37 }, GOTOS => { 'sterm' => 68, 'item' => 39, 'node' => 23, 'ident' => 77, 'term' => 271, 'lterm' => 56 } }, {#State 201 ACTIONS => { "{" => 30, 'LITERAL' => 78, 'IDENT' => 2, "\"" => 60, "\$" => 43, "[" => 9, 'NUMBER' => 26, 'REF' => 27, "\${" => 37 }, GOTOS => { 'sterm' => 68, 'item' => 39, 'node' => 23, 'ident' => 77, 'term' => 272, 'lterm' => 56 } }, {#State 202 ACTIONS => { "{" => 30, 'COMMA' => 258, 'LITERAL' => 256, 'IDENT' => 2, "\"" => 60, "\$" => 43, "[" => 9, 'NUMBER' => 26, 'REF' => 27, "\${" => 37 }, DEFAULT => -64, GOTOS => { 'sterm' => 68, 'item' => 254, 'param' => 255, 'node' => 23, 'ident' => 253, 'term' => 257, 'lterm' => 56 } }, {#State 203 DEFAULT => -56, GOTOS => { '@1-3' => 273 } }, {#State 204 ACTIONS => { "\"" => 89, "\$" => 86, 'LITERAL' => 88, 'FILENAME' => 83, 'IDENT' => 81, 'NUMBER' => 84 }, GOTOS => { 'filepart' => 87, 'names' => 91, 'nameargs' => 274, 'filename' => 85, 'name' => 82 } }, {#State 205 ACTIONS => { 'ASSIGN' => -132 }, DEFAULT => -130 }, {#State 206 ACTIONS => { 'SET' => 1, 'PERL' => 40, 'NOT' => 38, 'IDENT' => 2, 'CLEAR' => 41, 'UNLESS' => 3, 'IF' => 44, "\$" => 43, 'STOP' => 6, 'CALL' => 45, 'THROW' => 8, 'GET' => 47, "[" => 9, 'TRY' => 10, 'LAST' => 49, 'DEBUG' => 51, 'RAWPERL' => 13, 'META' => 15, 'INCLUDE' => 17, "(" => 53, 'SWITCH' => 54, 'MACRO' => 18, 'WRAPPER' => 55, ";" => -18, 'FOR' => 21, 'NEXT' => 22, 'LITERAL' => 57, 'TEXT' => 24, "\"" => 60, 'PROCESS' => 61, 'RETURN' => 64, 'FILTER' => 25, 'INSERT' => 65, 'NUMBER' => 26, 'REF' => 27, 'WHILE' => 67, 'BLOCK' => 28, 'DEFAULT' => 69, "{" => 30, 'USE' => 32, 'VIEW' => 36, "\${" => 37 }, DEFAULT => -3, GOTOS => { 'item' => 39, 'node' => 23, 'rawperl' => 59, 'term' => 58, 'loop' => 4, 'use' => 63, 'expr' => 62, 'capture' => 42, 'statement' => 5, 'view' => 7, 'wrapper' => 46, 'atomexpr' => 48, 'chunk' => 11, 'defblock' => 66, 'atomdir' => 12, 'anonblock' => 50, 'sterm' => 68, 'defblockname' => 14, 'filter' => 29, 'ident' => 16, 'perl' => 31, 'setlist' => 70, 'chunks' => 33, 'try' => 35, 'switch' => 34, 'assign' => 19, 'block' => 275, 'directive' => 71, 'macro' => 20, 'condition' => 73, 'lterm' => 56 } }, {#State 207 ACTIONS => { "\"" => 276, 'TEXT' => 231, ";" => 233, "\$" => 43, 'IDENT' => 2, "\${" => 37 }, GOTOS => { 'item' => 39, 'node' => 23, 'ident' => 230, 'quotable' => 232 } }, {#State 208 ACTIONS => { 'SET' => 1, 'PERL' => 40, 'NOT' => 38, 'IDENT' => 2, 'CLEAR' => 41, 'UNLESS' => 3, 'IF' => 44, "\$" => 43, 'STOP' => 6, 'CALL' => 45, 'THROW' => 8, 'GET' => 47, "[" => 9, 'TRY' => 10, 'LAST' => 49, 'DEBUG' => 51, 'RAWPERL' => 13, 'META' => 15, 'INCLUDE' => 17, "(" => 53, 'SWITCH' => 54, 'MACRO' => 18, 'WRAPPER' => 55, ";" => -18, 'FOR' => 21, 'NEXT' => 22, 'LITERAL' => 57, 'TEXT' => 24, "\"" => 60, 'PROCESS' => 61, 'RETURN' => 64, 'FILTER' => 25, 'INSERT' => 65, 'NUMBER' => 26, 'REF' => 27, 'WHILE' => 67, 'BLOCK' => 28, 'DEFAULT' => 69, "{" => 30, 'USE' => 32, 'VIEW' => 36, "\${" => 37 }, DEFAULT => -3, GOTOS => { 'item' => 39, 'node' => 23, 'rawperl' => 59, 'term' => 58, 'loop' => 4, 'use' => 63, 'expr' => 62, 'capture' => 42, 'statement' => 5, 'view' => 7, 'wrapper' => 46, 'atomexpr' => 48, 'chunk' => 11, 'defblock' => 66, 'atomdir' => 12, 'anonblock' => 50, 'sterm' => 68, 'defblockname' => 14, 'filter' => 29, 'ident' => 16, 'perl' => 31, 'setlist' => 70, 'chunks' => 33, 'try' => 35, 'switch' => 34, 'assign' => 19, 'block' => 277, 'directive' => 71, 'macro' => 20, 'condition' => 73, 'lterm' => 56 } }, {#State 209 DEFAULT => -108 }, {#State 210 ACTIONS => { 'NOT' => 38, "{" => 30, 'LITERAL' => 78, 'IDENT' => 2, "\"" => 60, "(" => 53, "\$" => 43, "[" => 9, 'NUMBER' => 26, 'REF' => 27, "\${" => 37 }, GOTOS => { 'expr' => 278, 'sterm' => 68, 'item' => 39, 'node' => 23, 'ident' => 77, 'term' => 58, 'lterm' => 56 } }, {#State 211 DEFAULT => -120 }, {#State 212 DEFAULT => -121 }, {#State 213 ACTIONS => { 'NOT' => 38, "{" => 30, 'LITERAL' => 78, 'IDENT' => 2, "\"" => 60, "(" => 53, "\$" => 43, "[" => 9, 'NUMBER' => 26, 'REF' => 27, "\${" => 37 }, GOTOS => { 'expr' => 279, 'sterm' => 68, 'item' => 39, 'node' => 23, 'ident' => 77, 'term' => 58, 'lterm' => 56 } }, {#State 214 DEFAULT => -74, GOTOS => { '@3-3' => 280 } }, {#State 215 DEFAULT => -131 }, {#State 216 ACTIONS => { "{" => 30, 'COMMA' => 258, 'LITERAL' => 256, 'IDENT' => 2, "\"" => 60, "\$" => 43, "[" => 9, 'NUMBER' => 26, 'REF' => 27, ")" => 281, "\${" => 37 }, GOTOS => { 'sterm' => 68, 'item' => 254, 'param' => 255, 'node' => 23, 'ident' => 253, 'term' => 257, 'lterm' => 56 } }, {#State 217 ACTIONS => { 'SET' => 1, 'PERL' => 40, 'NOT' => 38, 'IDENT' => 2, 'CLEAR' => 41, 'UNLESS' => 3, 'IF' => 44, "\$" => 43, 'STOP' => 6, 'CALL' => 45, 'THROW' => 8, 'GET' => 47, "[" => 9, 'TRY' => 10, 'LAST' => 49, 'DEBUG' => 51, 'RAWPERL' => 13, 'META' => 15, 'INCLUDE' => 17, "(" => 53, 'SWITCH' => 54, 'MACRO' => 18, 'WRAPPER' => 55, ";" => -18, 'FOR' => 21, 'NEXT' => 22, 'LITERAL' => 57, 'TEXT' => 24, "\"" => 60, 'PROCESS' => 61, 'RETURN' => 64, 'FILTER' => 25, 'INSERT' => 65, 'NUMBER' => 26, 'REF' => 27, 'WHILE' => 67, 'BLOCK' => 28, 'DEFAULT' => 69, "{" => 30, 'USE' => 32, 'VIEW' => 36, "\${" => 37 }, DEFAULT => -3, GOTOS => { 'item' => 39, 'node' => 23, 'rawperl' => 59, 'term' => 58, 'loop' => 4, 'use' => 63, 'expr' => 62, 'capture' => 42, 'statement' => 5, 'view' => 7, 'wrapper' => 46, 'atomexpr' => 48, 'chunk' => 11, 'defblock' => 66, 'atomdir' => 12, 'anonblock' => 50, 'sterm' => 68, 'defblockname' => 14, 'filter' => 29, 'ident' => 16, 'perl' => 31, 'setlist' => 70, 'chunks' => 33, 'try' => 35, 'switch' => 34, 'assign' => 19, 'block' => 282, 'directive' => 71, 'macro' => 20, 'condition' => 73, 'lterm' => 56 } }, {#State 218 ACTIONS => { 'SET' => 1, 'PERL' => 40, 'NOT' => 38, 'IDENT' => 2, 'CLEAR' => 41, 'UNLESS' => 3, 'IF' => 44, "\$" => 43, 'STOP' => 6, 'CALL' => 45, 'THROW' => 8, 'GET' => 47, "[" => 9, 'TRY' => 10, 'LAST' => 49, 'DEBUG' => 51, 'RAWPERL' => 13, 'META' => 15, 'INCLUDE' => 17, "(" => 53, 'SWITCH' => 54, 'MACRO' => 18, 'WRAPPER' => 55, ";" => -18, 'FOR' => 21, 'NEXT' => 22, 'LITERAL' => 57, 'TEXT' => 24, "\"" => 60, 'PROCESS' => 61, 'RETURN' => 64, 'FILTER' => 25, 'INSERT' => 65, 'NUMBER' => 26, 'REF' => 27, 'WHILE' => 67, 'BLOCK' => 28, 'DEFAULT' => 69, "{" => 30, 'USE' => 32, 'VIEW' => 36, "\${" => 37 }, DEFAULT => -3, GOTOS => { 'item' => 39, 'node' => 23, 'rawperl' => 59, 'term' => 58, 'loop' => 4, 'use' => 63, 'expr' => 62, 'capture' => 42, 'statement' => 5, 'view' => 7, 'wrapper' => 46, 'atomexpr' => 48, 'chunk' => 11, 'defblock' => 66, 'atomdir' => 12, 'anonblock' => 50, 'sterm' => 68, 'defblockname' => 14, 'filter' => 29, 'ident' => 16, 'perl' => 31, 'setlist' => 70, 'chunks' => 33, 'try' => 35, 'switch' => 34, 'assign' => 19, 'block' => 283, 'directive' => 71, 'macro' => 20, 'condition' => 73, 'lterm' => 56 } }, {#State 219 ACTIONS => { 'CMPOP' => 164, "?" => 158, "+" => 157, 'MOD' => 165, 'DIV' => 159, "/" => 166, 'AND' => 160, 'CAT' => 163, 'BINOP' => 161, 'OR' => 162 }, DEFAULT => -47 }, {#State 220 DEFAULT => -58 }, {#State 221 DEFAULT => -81 }, {#State 222 ACTIONS => { 'CMPOP' => 164, "?" => 158, "+" => 157, 'MOD' => 165, 'DIV' => 159, "/" => 166, 'AND' => 160, 'CAT' => 163, 'BINOP' => 161, 'OR' => 162 }, DEFAULT => -45 }, {#State 223 DEFAULT => -66 }, {#State 224 ACTIONS => { 'CMPOP' => 164, "?" => 158, "+" => 157, 'MOD' => 165, 'DIV' => 159, "/" => 166, 'AND' => 160, 'CAT' => 163, 'BINOP' => 161, 'OR' => 162 }, DEFAULT => -61 }, {#State 225 DEFAULT => -144 }, {#State 226 DEFAULT => -145 }, {#State 227 ACTIONS => { 'SET' => 1, 'PERL' => 40, 'NOT' => 38, 'IDENT' => 2, 'CLEAR' => 41, 'UNLESS' => 3, 'IF' => 44, "\$" => 43, 'STOP' => 6, 'CALL' => 45, 'THROW' => 8, 'GET' => 47, "[" => 9, 'TRY' => 10, 'LAST' => 49, 'DEBUG' => 51, 'RAWPERL' => 13, 'META' => 15, 'INCLUDE' => 17, "(" => 53, 'SWITCH' => 54, 'MACRO' => 18, 'WRAPPER' => 55, ";" => -18, 'FOR' => 21, 'NEXT' => 22, 'LITERAL' => 57, 'TEXT' => 24, "\"" => 60, 'PROCESS' => 61, 'RETURN' => 64, 'FILTER' => 25, 'INSERT' => 65, 'NUMBER' => 26, 'REF' => 27, 'WHILE' => 67, 'BLOCK' => 28, 'DEFAULT' => 69, "{" => 30, 'USE' => 32, 'VIEW' => 36, "\${" => 37 }, DEFAULT => -3, GOTOS => { 'item' => 39, 'node' => 23, 'rawperl' => 59, 'term' => 58, 'loop' => 4, 'use' => 63, 'expr' => 62, 'capture' => 42, 'statement' => 5, 'view' => 7, 'wrapper' => 46, 'atomexpr' => 48, 'chunk' => 11, 'defblock' => 66, 'atomdir' => 12, 'anonblock' => 50, 'sterm' => 68, 'defblockname' => 14, 'filter' => 29, 'ident' => 16, 'perl' => 31, 'setlist' => 70, 'chunks' => 33, 'try' => 35, 'switch' => 34, 'assign' => 19, 'block' => 284, 'directive' => 71, 'macro' => 20, 'condition' => 73, 'lterm' => 56 } }, {#State 228 ACTIONS => { 'SET' => 1, 'PERL' => 40, 'NOT' => 38, 'IDENT' => 2, 'CLEAR' => 41, 'UNLESS' => 3, 'IF' => 44, "\$" => 43, 'STOP' => 6, 'CALL' => 45, 'THROW' => 8, 'GET' => 47, "[" => 9, 'TRY' => 10, 'LAST' => 49, 'DEBUG' => 51, 'RAWPERL' => 13, 'META' => 15, 'INCLUDE' => 17, "(" => 53, 'SWITCH' => 54, 'MACRO' => 18, 'WRAPPER' => 55, ";" => -18, 'FOR' => 21, 'NEXT' => 22, 'LITERAL' => 57, 'TEXT' => 24, "\"" => 60, 'PROCESS' => 61, 'RETURN' => 64, 'FILTER' => 25, 'INSERT' => 65, 'NUMBER' => 26, 'REF' => 27, 'WHILE' => 67, 'BLOCK' => 28, 'DEFAULT' => 69, "{" => 30, 'USE' => 32, 'VIEW' => 36, "\${" => 37 }, DEFAULT => -3, GOTOS => { 'item' => 39, 'node' => 23, 'rawperl' => 59, 'term' => 58, 'loop' => 4, 'use' => 63, 'expr' => 62, 'capture' => 42, 'statement' => 5, 'view' => 7, 'wrapper' => 46, 'atomexpr' => 48, 'chunk' => 11, 'defblock' => 66, 'atomdir' => 12, 'anonblock' => 50, 'sterm' => 68, 'defblockname' => 14, 'filter' => 29, 'ident' => 16, 'perl' => 31, 'setlist' => 70, 'chunks' => 33, 'try' => 35, 'switch' => 34, 'assign' => 19, 'block' => 285, 'directive' => 71, 'macro' => 20, 'condition' => 73, 'lterm' => 56 } }, {#State 229 ACTIONS => { "+" => 157, 'CAT' => 163, 'CMPOP' => 164, "?" => 158, 'DIV' => 159, 'MOD' => 165, "/" => 166, 'AND' => 160, 'BINOP' => 161, 'OR' => 162 }, DEFAULT => -151 }, {#State 230 ACTIONS => { 'DOT' => 104 }, DEFAULT => -177 }, {#State 231 DEFAULT => -178 }, {#State 232 DEFAULT => -175 }, {#State 233 DEFAULT => -179 }, {#State 234 DEFAULT => -111 }, {#State 235 ACTIONS => { 'DIV' => 159, 'MOD' => 165, "/" => 166 }, DEFAULT => -135 }, {#State 236 ACTIONS => { ":" => 286, 'CMPOP' => 164, "?" => 158, "+" => 157, 'MOD' => 165, 'DIV' => 159, "/" => 166, 'AND' => 160, 'CAT' => 163, 'BINOP' => 161, 'OR' => 162 } }, {#State 237 ACTIONS => { 'MOD' => 165 }, DEFAULT => -136 }, {#State 238 ACTIONS => { "+" => 157, 'CAT' => 163, 'CMPOP' => 164, 'DIV' => 159, 'MOD' => 165, "/" => 166, 'BINOP' => 161 }, DEFAULT => -140 }, {#State 239 ACTIONS => { "+" => 157, 'DIV' => 159, 'MOD' => 165, "/" => 166 }, DEFAULT => -133 }, {#State 240 ACTIONS => { "+" => 157, 'CAT' => 163, 'CMPOP' => 164, 'DIV' => 159, 'MOD' => 165, "/" => 166, 'BINOP' => 161 }, DEFAULT => -141 }, {#State 241 ACTIONS => { "+" => 157, 'CMPOP' => 164, 'DIV' => 159, 'MOD' => 165, "/" => 166, 'BINOP' => 161 }, DEFAULT => -139 }, {#State 242 ACTIONS => { "+" => 157, 'DIV' => 159, 'MOD' => 165, "/" => 166, 'BINOP' => 161 }, DEFAULT => -138 }, {#State 243 DEFAULT => -137 }, {#State 244 ACTIONS => { 'DIV' => 159, 'MOD' => 165 }, DEFAULT => -134 }, {#State 245 DEFAULT => -59, GOTOS => { '@2-3' => 287 } }, {#State 246 ACTIONS => { "+" => 157, 'CAT' => 163, 'CMPOP' => 164, "?" => 158, 'DIV' => 159, 'MOD' => 165, "/" => 166, 'AND' => 160, 'BINOP' => 161, 'OR' => 162 }, DEFAULT => -150 }, {#State 247 ACTIONS => { 'ELSIF' => 290, 'ELSE' => 288 }, DEFAULT => -50, GOTOS => { 'else' => 289 } }, {#State 248 DEFAULT => -170 }, {#State 249 ACTIONS => { "{" => 30, 'COMMA' => 258, 'LITERAL' => 256, 'IDENT' => 2, "\"" => 60, "\$" => 43, "[" => 9, 'NUMBER' => 26, 'REF' => 27, "\${" => 37 }, DEFAULT => -162, GOTOS => { 'sterm' => 68, 'item' => 254, 'param' => 255, 'node' => 23, 'ident' => 253, 'term' => 257, 'lterm' => 56 } }, {#State 250 DEFAULT => -167 }, {#State 251 DEFAULT => -165 }, {#State 252 ACTIONS => { "{" => 30, 'COMMA' => 258, 'LITERAL' => 256, 'IDENT' => 2, "\"" => 60, "\$" => 43, "[" => 9, 'NUMBER' => 26, 'REF' => 27, ")" => 291, "\${" => 37 }, GOTOS => { 'sterm' => 68, 'item' => 254, 'param' => 255, 'node' => 23, 'ident' => 253, 'term' => 257, 'lterm' => 56 } }, {#State 253 ACTIONS => { 'DOT' => 104, 'ASSIGN' => 292 }, DEFAULT => -109 }, {#State 254 ACTIONS => { "(" => 135, 'ASSIGN' => 210 }, DEFAULT => -128 }, {#State 255 DEFAULT => -153 }, {#State 256 ACTIONS => { 'ASSIGN' => 213 }, DEFAULT => -112 }, {#State 257 DEFAULT => -152 }, {#State 258 DEFAULT => -155 }, {#State 259 DEFAULT => -117 }, {#State 260 ACTIONS => { ";" => 293 } }, {#State 261 ACTIONS => { 'END' => 294 } }, {#State 262 ACTIONS => { ";" => 296, 'DEFAULT' => 297, 'FILENAME' => 83, 'IDENT' => 81, 'NUMBER' => 84 }, GOTOS => { 'filepart' => 87, 'filename' => 295 } }, {#State 263 ACTIONS => { 'END' => 298 } }, {#State 264 DEFAULT => -102 }, {#State 265 DEFAULT => -100 }, {#State 266 ACTIONS => { 'TEXT' => 299 } }, {#State 267 ACTIONS => { 'END' => 300 } }, {#State 268 ACTIONS => { 'SET' => 1, 'PERL' => 40, 'NOT' => 38, 'IDENT' => 2, 'CLEAR' => 41, 'UNLESS' => 3, 'IF' => 44, "\$" => 43, 'STOP' => 6, 'CALL' => 45, 'THROW' => 8, 'GET' => 47, "[" => 9, 'TRY' => 10, 'LAST' => 49, 'DEBUG' => 51, 'RAWPERL' => 13, 'META' => 15, 'INCLUDE' => 17, "(" => 53, 'SWITCH' => 54, 'MACRO' => 18, 'WRAPPER' => 55, ";" => -18, 'FOR' => 21, 'NEXT' => 22, 'LITERAL' => 57, 'TEXT' => 24, "\"" => 60, 'PROCESS' => 61, 'RETURN' => 64, 'FILTER' => 25, 'INSERT' => 65, 'NUMBER' => 26, 'REF' => 27, 'WHILE' => 67, 'BLOCK' => 28, 'DEFAULT' => 69, "{" => 30, 'USE' => 32, 'VIEW' => 36, "\${" => 37 }, DEFAULT => -3, GOTOS => { 'item' => 39, 'node' => 23, 'rawperl' => 59, 'term' => 58, 'loop' => 4, 'use' => 63, 'expr' => 62, 'capture' => 42, 'statement' => 5, 'view' => 7, 'wrapper' => 46, 'atomexpr' => 48, 'chunk' => 11, 'defblock' => 66, 'atomdir' => 12, 'anonblock' => 50, 'sterm' => 68, 'defblockname' => 14, 'filter' => 29, 'ident' => 16, 'perl' => 31, 'setlist' => 70, 'chunks' => 33, 'try' => 35, 'switch' => 34, 'assign' => 19, 'block' => 301, 'directive' => 71, 'macro' => 20, 'condition' => 73, 'lterm' => 56 } }, {#State 269 ACTIONS => { 'COMMA' => -96, 'IDENT' => -96, ")" => -96 }, DEFAULT => -130 }, {#State 270 ACTIONS => { 'COMMA' => 304, 'IDENT' => 302, ")" => 303 } }, {#State 271 DEFAULT => -156, GOTOS => { 'args' => 305 } }, {#State 272 DEFAULT => -156, GOTOS => { 'args' => 306 } }, {#State 273 ACTIONS => { 'SET' => 1, 'PERL' => 40, 'NOT' => 38, 'IDENT' => 2, 'CLEAR' => 41, 'UNLESS' => 3, 'IF' => 44, "\$" => 43, 'STOP' => 6, 'CALL' => 45, 'THROW' => 8, 'GET' => 47, "[" => 9, 'TRY' => 10, 'LAST' => 49, 'DEBUG' => 51, 'RAWPERL' => 13, 'META' => 15, 'INCLUDE' => 17, "(" => 53, 'SWITCH' => 54, 'MACRO' => 18, 'WRAPPER' => 55, ";" => -18, 'FOR' => 21, 'NEXT' => 22, 'LITERAL' => 57, 'TEXT' => 24, "\"" => 60, 'PROCESS' => 61, 'RETURN' => 64, 'FILTER' => 25, 'INSERT' => 65, 'NUMBER' => 26, 'REF' => 27, 'WHILE' => 67, 'BLOCK' => 28, 'DEFAULT' => 69, "{" => 30, 'USE' => 32, 'VIEW' => 36, "\${" => 37 }, DEFAULT => -3, GOTOS => { 'item' => 39, 'node' => 23, 'rawperl' => 59, 'term' => 58, 'loop' => 4, 'use' => 63, 'expr' => 62, 'capture' => 42, 'statement' => 5, 'view' => 7, 'wrapper' => 46, 'atomexpr' => 48, 'chunk' => 11, 'defblock' => 66, 'atomdir' => 12, 'anonblock' => 50, 'sterm' => 68, 'defblockname' => 14, 'filter' => 29, 'ident' => 16, 'perl' => 31, 'setlist' => 70, 'chunks' => 33, 'try' => 35, 'switch' => 34, 'assign' => 19, 'block' => 307, 'directive' => 71, 'macro' => 20, 'condition' => 73, 'lterm' => 56 } }, {#State 274 DEFAULT => -157 }, {#State 275 ACTIONS => { 'END' => 308 } }, {#State 276 ACTIONS => { 'ASSIGN' => -160 }, DEFAULT => -167 }, {#State 277 ACTIONS => { 'END' => 309 } }, {#State 278 ACTIONS => { "+" => 157, 'CAT' => 163, 'CMPOP' => 164, "?" => 158, 'DIV' => 159, 'MOD' => 165, "/" => 166, 'AND' => 160, 'BINOP' => 161, 'OR' => 162 }, DEFAULT => -124 }, {#State 279 ACTIONS => { "+" => 157, 'CAT' => 163, 'CMPOP' => 164, "?" => 158, 'DIV' => 159, 'MOD' => 165, "/" => 166, 'AND' => 160, 'BINOP' => 161, 'OR' => 162 }, DEFAULT => -123 }, {#State 280 ACTIONS => { 'SET' => 1, 'PERL' => 40, 'NOT' => 38, 'IDENT' => 2, 'CLEAR' => 41, 'UNLESS' => 3, 'IF' => 44, "\$" => 43, 'STOP' => 6, 'CALL' => 45, 'THROW' => 8, 'GET' => 47, "[" => 9, 'TRY' => 10, 'LAST' => 49, 'DEBUG' => 51, 'RAWPERL' => 13, 'META' => 15, 'INCLUDE' => 17, "(" => 53, 'SWITCH' => 54, 'MACRO' => 18, 'WRAPPER' => 55, ";" => -18, 'FOR' => 21, 'NEXT' => 22, 'LITERAL' => 57, 'TEXT' => 24, "\"" => 60, 'PROCESS' => 61, 'RETURN' => 64, 'FILTER' => 25, 'INSERT' => 65, 'NUMBER' => 26, 'REF' => 27, 'WHILE' => 67, 'BLOCK' => 28, 'DEFAULT' => 69, "{" => 30, 'USE' => 32, 'VIEW' => 36, "\${" => 37 }, DEFAULT => -3, GOTOS => { 'item' => 39, 'node' => 23, 'rawperl' => 59, 'term' => 58, 'loop' => 4, 'use' => 63, 'expr' => 62, 'capture' => 42, 'statement' => 5, 'view' => 7, 'wrapper' => 46, 'atomexpr' => 48, 'chunk' => 11, 'defblock' => 66, 'atomdir' => 12, 'anonblock' => 50, 'sterm' => 68, 'defblockname' => 14, 'filter' => 29, 'ident' => 16, 'perl' => 31, 'setlist' => 70, 'chunks' => 33, 'try' => 35, 'switch' => 34, 'assign' => 19, 'block' => 310, 'directive' => 71, 'macro' => 20, 'condition' => 73, 'lterm' => 56 } }, {#State 281 DEFAULT => -129 }, {#State 282 ACTIONS => { 'END' => 311 } }, {#State 283 ACTIONS => { 'ELSIF' => 290, 'ELSE' => 288 }, DEFAULT => -50, GOTOS => { 'else' => 312 } }, {#State 284 ACTIONS => { 'CASE' => 313 }, DEFAULT => -55, GOTOS => { 'case' => 314 } }, {#State 285 ACTIONS => { 'END' => 315 } }, {#State 286 ACTIONS => { 'NOT' => 38, "{" => 30, 'LITERAL' => 78, 'IDENT' => 2, "\"" => 60, "(" => 53, "\$" => 43, "[" => 9, 'NUMBER' => 26, 'REF' => 27, "\${" => 37 }, GOTOS => { 'expr' => 316, 'sterm' => 68, 'item' => 39, 'node' => 23, 'ident' => 77, 'term' => 58, 'lterm' => 56 } }, {#State 287 ACTIONS => { 'SET' => 1, 'PERL' => 40, 'NOT' => 38, 'IDENT' => 2, 'CLEAR' => 41, 'UNLESS' => 3, 'IF' => 44, "\$" => 43, 'STOP' => 6, 'CALL' => 45, 'THROW' => 8, 'GET' => 47, "[" => 9, 'TRY' => 10, 'LAST' => 49, 'DEBUG' => 51, 'RAWPERL' => 13, 'META' => 15, 'INCLUDE' => 17, "(" => 53, 'SWITCH' => 54, 'MACRO' => 18, 'WRAPPER' => 55, ";" => -18, 'FOR' => 21, 'NEXT' => 22, 'LITERAL' => 57, 'TEXT' => 24, "\"" => 60, 'PROCESS' => 61, 'RETURN' => 64, 'FILTER' => 25, 'INSERT' => 65, 'NUMBER' => 26, 'REF' => 27, 'WHILE' => 67, 'BLOCK' => 28, 'DEFAULT' => 69, "{" => 30, 'USE' => 32, 'VIEW' => 36, "\${" => 37 }, DEFAULT => -3, GOTOS => { 'item' => 39, 'node' => 23, 'rawperl' => 59, 'term' => 58, 'loop' => 4, 'use' => 63, 'expr' => 62, 'capture' => 42, 'statement' => 5, 'view' => 7, 'wrapper' => 46, 'atomexpr' => 48, 'chunk' => 11, 'defblock' => 66, 'atomdir' => 12, 'anonblock' => 50, 'sterm' => 68, 'defblockname' => 14, 'filter' => 29, 'ident' => 16, 'perl' => 31, 'setlist' => 70, 'chunks' => 33, 'try' => 35, 'switch' => 34, 'assign' => 19, 'block' => 317, 'directive' => 71, 'macro' => 20, 'condition' => 73, 'lterm' => 56 } }, {#State 288 ACTIONS => { ";" => 318 } }, {#State 289 ACTIONS => { 'END' => 319 } }, {#State 290 ACTIONS => { 'NOT' => 38, "{" => 30, 'LITERAL' => 78, 'IDENT' => 2, "\"" => 60, "(" => 53, "\$" => 43, "[" => 9, 'NUMBER' => 26, 'REF' => 27, "\${" => 37 }, GOTOS => { 'expr' => 320, 'sterm' => 68, 'item' => 39, 'node' => 23, 'ident' => 77, 'term' => 58, 'lterm' => 56 } }, {#State 291 DEFAULT => -164 }, {#State 292 ACTIONS => { 'NOT' => 38, "{" => 30, 'LITERAL' => 78, 'IDENT' => 2, "\"" => 60, "(" => 53, "\$" => 43, "[" => 9, 'NUMBER' => 26, 'REF' => 27, "\${" => 37 }, GOTOS => { 'expr' => 321, 'sterm' => 68, 'item' => 39, 'node' => 23, 'ident' => 77, 'term' => 58, 'lterm' => 56 } }, {#State 293 ACTIONS => { 'SET' => 1, 'PERL' => 40, 'NOT' => 38, 'IDENT' => 2, 'CLEAR' => 41, 'UNLESS' => 3, 'IF' => 44, "\$" => 43, 'STOP' => 6, 'CALL' => 45, 'THROW' => 8, 'GET' => 47, "[" => 9, 'TRY' => 10, 'LAST' => 49, 'DEBUG' => 51, 'RAWPERL' => 13, 'META' => 15, 'INCLUDE' => 17, "(" => 53, 'SWITCH' => 54, 'MACRO' => 18, 'WRAPPER' => 55, ";" => -18, 'FOR' => 21, 'NEXT' => 22, 'LITERAL' => 57, 'TEXT' => 24, "\"" => 60, 'PROCESS' => 61, 'RETURN' => 64, 'FILTER' => 25, 'INSERT' => 65, 'NUMBER' => 26, 'REF' => 27, 'WHILE' => 67, 'BLOCK' => 28, 'DEFAULT' => 69, "{" => 30, 'USE' => 32, 'VIEW' => 36, "\${" => 37 }, DEFAULT => -3, GOTOS => { 'item' => 39, 'node' => 23, 'rawperl' => 59, 'term' => 58, 'loop' => 4, 'use' => 63, 'expr' => 62, 'capture' => 42, 'statement' => 5, 'view' => 7, 'wrapper' => 46, 'atomexpr' => 48, 'chunk' => 11, 'defblock' => 66, 'atomdir' => 12, 'anonblock' => 50, 'sterm' => 68, 'defblockname' => 14, 'filter' => 29, 'ident' => 16, 'perl' => 31, 'setlist' => 70, 'chunks' => 33, 'try' => 35, 'switch' => 34, 'assign' => 19, 'block' => 322, 'directive' => 71, 'macro' => 20, 'condition' => 73, 'lterm' => 56 } }, {#State 294 DEFAULT => -67 }, {#State 295 ACTIONS => { 'DOT' => 174, ";" => 323 } }, {#State 296 ACTIONS => { 'SET' => 1, 'PERL' => 40, 'NOT' => 38, 'IDENT' => 2, 'CLEAR' => 41, 'UNLESS' => 3, 'IF' => 44, "\$" => 43, 'STOP' => 6, 'CALL' => 45, 'THROW' => 8, 'GET' => 47, "[" => 9, 'TRY' => 10, 'LAST' => 49, 'DEBUG' => 51, 'RAWPERL' => 13, 'META' => 15, 'INCLUDE' => 17, "(" => 53, 'SWITCH' => 54, 'MACRO' => 18, 'WRAPPER' => 55, ";" => -18, 'FOR' => 21, 'NEXT' => 22, 'LITERAL' => 57, 'TEXT' => 24, "\"" => 60, 'PROCESS' => 61, 'RETURN' => 64, 'FILTER' => 25, 'INSERT' => 65, 'NUMBER' => 26, 'REF' => 27, 'WHILE' => 67, 'BLOCK' => 28, 'DEFAULT' => 69, "{" => 30, 'USE' => 32, 'VIEW' => 36, "\${" => 37 }, DEFAULT => -3, GOTOS => { 'item' => 39, 'node' => 23, 'rawperl' => 59, 'term' => 58, 'loop' => 4, 'use' => 63, 'expr' => 62, 'capture' => 42, 'statement' => 5, 'view' => 7, 'wrapper' => 46, 'atomexpr' => 48, 'chunk' => 11, 'defblock' => 66, 'atomdir' => 12, 'anonblock' => 50, 'sterm' => 68, 'defblockname' => 14, 'filter' => 29, 'ident' => 16, 'perl' => 31, 'setlist' => 70, 'chunks' => 33, 'try' => 35, 'switch' => 34, 'assign' => 19, 'block' => 324, 'directive' => 71, 'macro' => 20, 'condition' => 73, 'lterm' => 56 } }, {#State 297 ACTIONS => { ";" => 325 } }, {#State 298 DEFAULT => -79 }, {#State 299 ACTIONS => { "\"" => 326 } }, {#State 300 DEFAULT => -82 }, {#State 301 ACTIONS => { 'END' => 327 } }, {#State 302 DEFAULT => -94 }, {#State 303 ACTIONS => { 'SET' => 1, 'PERL' => 40, 'NOT' => 38, 'IDENT' => 2, 'CLEAR' => 41, 'UNLESS' => 3, 'IF' => 44, "\$" => 43, 'STOP' => 6, 'CALL' => 45, 'THROW' => 8, 'GET' => 47, "[" => 9, 'TRY' => 10, 'LAST' => 49, 'DEBUG' => 51, 'INCLUDE' => 17, "(" => 53, 'SWITCH' => 54, 'WRAPPER' => 55, 'FOR' => 21, 'NEXT' => 22, 'LITERAL' => 57, "\"" => 60, 'PROCESS' => 61, 'FILTER' => 25, 'RETURN' => 64, 'INSERT' => 65, 'NUMBER' => 26, 'REF' => 27, 'WHILE' => 67, 'BLOCK' => 193, 'DEFAULT' => 69, "{" => 30, "\${" => 37 }, GOTOS => { 'item' => 39, 'node' => 23, 'term' => 58, 'loop' => 4, 'expr' => 199, 'wrapper' => 46, 'atomexpr' => 48, 'atomdir' => 12, 'mdir' => 328, 'sterm' => 68, 'filter' => 29, 'ident' => 149, 'perl' => 31, 'setlist' => 70, 'switch' => 34, 'try' => 35, 'assign' => 19, 'directive' => 196, 'condition' => 73, 'lterm' => 56 } }, {#State 304 DEFAULT => -95 }, {#State 305 ACTIONS => { "{" => 30, 'COMMA' => 258, 'LITERAL' => 256, 'IDENT' => 2, "\"" => 60, "\$" => 43, "[" => 9, 'NUMBER' => 26, 'REF' => 27, "\${" => 37 }, DEFAULT => -62, GOTOS => { 'sterm' => 68, 'item' => 254, 'param' => 255, 'node' => 23, 'ident' => 253, 'term' => 257, 'lterm' => 56 } }, {#State 306 ACTIONS => { "{" => 30, 'COMMA' => 258, 'LITERAL' => 256, 'IDENT' => 2, "\"" => 60, "\$" => 43, "[" => 9, 'NUMBER' => 26, 'REF' => 27, "\${" => 37 }, DEFAULT => -63, GOTOS => { 'sterm' => 68, 'item' => 254, 'param' => 255, 'node' => 23, 'ident' => 253, 'term' => 257, 'lterm' => 56 } }, {#State 307 ACTIONS => { 'END' => 329 } }, {#State 308 DEFAULT => -80 }, {#State 309 DEFAULT => -88 }, {#State 310 ACTIONS => { 'END' => 330 } }, {#State 311 DEFAULT => -77 }, {#State 312 ACTIONS => { 'END' => 331 } }, {#State 313 ACTIONS => { ";" => 332, 'DEFAULT' => 334, "{" => 30, 'LITERAL' => 78, 'IDENT' => 2, "\"" => 60, "\$" => 43, "[" => 9, 'NUMBER' => 26, 'REF' => 27, "\${" => 37 }, GOTOS => { 'sterm' => 68, 'item' => 39, 'node' => 23, 'ident' => 77, 'term' => 333, 'lterm' => 56 } }, {#State 314 ACTIONS => { 'END' => 335 } }, {#State 315 DEFAULT => -65 }, {#State 316 ACTIONS => { "+" => 157, 'CAT' => 163, 'CMPOP' => 164, "?" => 158, 'DIV' => 159, 'MOD' => 165, "/" => 166, 'AND' => 160, 'BINOP' => 161, 'OR' => 162 }, DEFAULT => -143 }, {#State 317 ACTIONS => { 'END' => 336 } }, {#State 318 ACTIONS => { 'SET' => 1, 'PERL' => 40, 'NOT' => 38, 'IDENT' => 2, 'CLEAR' => 41, 'UNLESS' => 3, 'IF' => 44, "\$" => 43, 'STOP' => 6, 'CALL' => 45, 'THROW' => 8, 'GET' => 47, "[" => 9, 'TRY' => 10, 'LAST' => 49, 'DEBUG' => 51, 'RAWPERL' => 13, 'META' => 15, 'INCLUDE' => 17, "(" => 53, 'SWITCH' => 54, 'MACRO' => 18, 'WRAPPER' => 55, ";" => -18, 'FOR' => 21, 'NEXT' => 22, 'LITERAL' => 57, 'TEXT' => 24, "\"" => 60, 'PROCESS' => 61, 'RETURN' => 64, 'FILTER' => 25, 'INSERT' => 65, 'NUMBER' => 26, 'REF' => 27, 'WHILE' => 67, 'BLOCK' => 28, 'DEFAULT' => 69, "{" => 30, 'USE' => 32, 'VIEW' => 36, "\${" => 37 }, DEFAULT => -3, GOTOS => { 'item' => 39, 'node' => 23, 'rawperl' => 59, 'term' => 58, 'loop' => 4, 'use' => 63, 'expr' => 62, 'capture' => 42, 'statement' => 5, 'view' => 7, 'wrapper' => 46, 'atomexpr' => 48, 'chunk' => 11, 'defblock' => 66, 'atomdir' => 12, 'anonblock' => 50, 'sterm' => 68, 'defblockname' => 14, 'filter' => 29, 'ident' => 16, 'perl' => 31, 'setlist' => 70, 'chunks' => 33, 'try' => 35, 'switch' => 34, 'assign' => 19, 'block' => 337, 'directive' => 71, 'macro' => 20, 'condition' => 73, 'lterm' => 56 } }, {#State 319 DEFAULT => -46 }, {#State 320 ACTIONS => { 'CMPOP' => 164, "?" => 158, ";" => 338, "+" => 157, 'MOD' => 165, 'DIV' => 159, "/" => 166, 'AND' => 160, 'CAT' => 163, 'BINOP' => 161, 'OR' => 162 } }, {#State 321 ACTIONS => { "+" => 157, 'CAT' => 163, 'CMPOP' => 164, "?" => 158, 'DIV' => 159, 'MOD' => 165, "/" => 166, 'AND' => 160, 'BINOP' => 161, 'OR' => 162 }, DEFAULT => -154 }, {#State 322 DEFAULT => -71 }, {#State 323 ACTIONS => { 'SET' => 1, 'PERL' => 40, 'NOT' => 38, 'IDENT' => 2, 'CLEAR' => 41, 'UNLESS' => 3, 'IF' => 44, "\$" => 43, 'STOP' => 6, 'CALL' => 45, 'THROW' => 8, 'GET' => 47, "[" => 9, 'TRY' => 10, 'LAST' => 49, 'DEBUG' => 51, 'RAWPERL' => 13, 'META' => 15, 'INCLUDE' => 17, "(" => 53, 'SWITCH' => 54, 'MACRO' => 18, 'WRAPPER' => 55, ";" => -18, 'FOR' => 21, 'NEXT' => 22, 'LITERAL' => 57, 'TEXT' => 24, "\"" => 60, 'PROCESS' => 61, 'RETURN' => 64, 'FILTER' => 25, 'INSERT' => 65, 'NUMBER' => 26, 'REF' => 27, 'WHILE' => 67, 'BLOCK' => 28, 'DEFAULT' => 69, "{" => 30, 'USE' => 32, 'VIEW' => 36, "\${" => 37 }, DEFAULT => -3, GOTOS => { 'item' => 39, 'node' => 23, 'rawperl' => 59, 'term' => 58, 'loop' => 4, 'use' => 63, 'expr' => 62, 'capture' => 42, 'statement' => 5, 'view' => 7, 'wrapper' => 46, 'atomexpr' => 48, 'chunk' => 11, 'defblock' => 66, 'atomdir' => 12, 'anonblock' => 50, 'sterm' => 68, 'defblockname' => 14, 'filter' => 29, 'ident' => 16, 'perl' => 31, 'setlist' => 70, 'chunks' => 33, 'try' => 35, 'switch' => 34, 'assign' => 19, 'block' => 339, 'directive' => 71, 'macro' => 20, 'condition' => 73, 'lterm' => 56 } }, {#State 324 ACTIONS => { 'FINAL' => 260, 'CATCH' => 262 }, DEFAULT => -72, GOTOS => { 'final' => 340 } }, {#State 325 ACTIONS => { 'SET' => 1, 'PERL' => 40, 'NOT' => 38, 'IDENT' => 2, 'CLEAR' => 41, 'UNLESS' => 3, 'IF' => 44, "\$" => 43, 'STOP' => 6, 'CALL' => 45, 'THROW' => 8, 'GET' => 47, "[" => 9, 'TRY' => 10, 'LAST' => 49, 'DEBUG' => 51, 'RAWPERL' => 13, 'META' => 15, 'INCLUDE' => 17, "(" => 53, 'SWITCH' => 54, 'MACRO' => 18, 'WRAPPER' => 55, ";" => -18, 'FOR' => 21, 'NEXT' => 22, 'LITERAL' => 57, 'TEXT' => 24, "\"" => 60, 'PROCESS' => 61, 'RETURN' => 64, 'FILTER' => 25, 'INSERT' => 65, 'NUMBER' => 26, 'REF' => 27, 'WHILE' => 67, 'BLOCK' => 28, 'DEFAULT' => 69, "{" => 30, 'USE' => 32, 'VIEW' => 36, "\${" => 37 }, DEFAULT => -3, GOTOS => { 'item' => 39, 'node' => 23, 'rawperl' => 59, 'term' => 58, 'loop' => 4, 'use' => 63, 'expr' => 62, 'capture' => 42, 'statement' => 5, 'view' => 7, 'wrapper' => 46, 'atomexpr' => 48, 'chunk' => 11, 'defblock' => 66, 'atomdir' => 12, 'anonblock' => 50, 'sterm' => 68, 'defblockname' => 14, 'filter' => 29, 'ident' => 16, 'perl' => 31, 'setlist' => 70, 'chunks' => 33, 'try' => 35, 'switch' => 34, 'assign' => 19, 'block' => 341, 'directive' => 71, 'macro' => 20, 'condition' => 73, 'lterm' => 56 } }, {#State 326 DEFAULT => -101 }, {#State 327 DEFAULT => -93 }, {#State 328 DEFAULT => -90 }, {#State 329 DEFAULT => -57 }, {#State 330 DEFAULT => -75 }, {#State 331 DEFAULT => -44 }, {#State 332 ACTIONS => { 'SET' => 1, 'PERL' => 40, 'NOT' => 38, 'IDENT' => 2, 'CLEAR' => 41, 'UNLESS' => 3, 'IF' => 44, "\$" => 43, 'STOP' => 6, 'CALL' => 45, 'THROW' => 8, 'GET' => 47, "[" => 9, 'TRY' => 10, 'LAST' => 49, 'DEBUG' => 51, 'RAWPERL' => 13, 'META' => 15, 'INCLUDE' => 17, "(" => 53, 'SWITCH' => 54, 'MACRO' => 18, 'WRAPPER' => 55, ";" => -18, 'FOR' => 21, 'NEXT' => 22, 'LITERAL' => 57, 'TEXT' => 24, "\"" => 60, 'PROCESS' => 61, 'RETURN' => 64, 'FILTER' => 25, 'INSERT' => 65, 'NUMBER' => 26, 'REF' => 27, 'WHILE' => 67, 'BLOCK' => 28, 'DEFAULT' => 69, "{" => 30, 'USE' => 32, 'VIEW' => 36, "\${" => 37 }, DEFAULT => -3, GOTOS => { 'item' => 39, 'node' => 23, 'rawperl' => 59, 'term' => 58, 'loop' => 4, 'use' => 63, 'expr' => 62, 'capture' => 42, 'statement' => 5, 'view' => 7, 'wrapper' => 46, 'atomexpr' => 48, 'chunk' => 11, 'defblock' => 66, 'atomdir' => 12, 'anonblock' => 50, 'sterm' => 68, 'defblockname' => 14, 'filter' => 29, 'ident' => 16, 'perl' => 31, 'setlist' => 70, 'chunks' => 33, 'try' => 35, 'switch' => 34, 'assign' => 19, 'block' => 342, 'directive' => 71, 'macro' => 20, 'condition' => 73, 'lterm' => 56 } }, {#State 333 ACTIONS => { ";" => 343 } }, {#State 334 ACTIONS => { ";" => 344 } }, {#State 335 DEFAULT => -51 }, {#State 336 DEFAULT => -60 }, {#State 337 DEFAULT => -49 }, {#State 338 ACTIONS => { 'SET' => 1, 'PERL' => 40, 'NOT' => 38, 'IDENT' => 2, 'CLEAR' => 41, 'UNLESS' => 3, 'IF' => 44, "\$" => 43, 'STOP' => 6, 'CALL' => 45, 'THROW' => 8, 'GET' => 47, "[" => 9, 'TRY' => 10, 'LAST' => 49, 'DEBUG' => 51, 'RAWPERL' => 13, 'META' => 15, 'INCLUDE' => 17, "(" => 53, 'SWITCH' => 54, 'MACRO' => 18, 'WRAPPER' => 55, ";" => -18, 'FOR' => 21, 'NEXT' => 22, 'LITERAL' => 57, 'TEXT' => 24, "\"" => 60, 'PROCESS' => 61, 'RETURN' => 64, 'FILTER' => 25, 'INSERT' => 65, 'NUMBER' => 26, 'REF' => 27, 'WHILE' => 67, 'BLOCK' => 28, 'DEFAULT' => 69, "{" => 30, 'USE' => 32, 'VIEW' => 36, "\${" => 37 }, DEFAULT => -3, GOTOS => { 'item' => 39, 'node' => 23, 'rawperl' => 59, 'term' => 58, 'loop' => 4, 'use' => 63, 'expr' => 62, 'capture' => 42, 'statement' => 5, 'view' => 7, 'wrapper' => 46, 'atomexpr' => 48, 'chunk' => 11, 'defblock' => 66, 'atomdir' => 12, 'anonblock' => 50, 'sterm' => 68, 'defblockname' => 14, 'filter' => 29, 'ident' => 16, 'perl' => 31, 'setlist' => 70, 'chunks' => 33, 'try' => 35, 'switch' => 34, 'assign' => 19, 'block' => 345, 'directive' => 71, 'macro' => 20, 'condition' => 73, 'lterm' => 56 } }, {#State 339 ACTIONS => { 'FINAL' => 260, 'CATCH' => 262 }, DEFAULT => -72, GOTOS => { 'final' => 346 } }, {#State 340 DEFAULT => -70 }, {#State 341 ACTIONS => { 'FINAL' => 260, 'CATCH' => 262 }, DEFAULT => -72, GOTOS => { 'final' => 347 } }, {#State 342 DEFAULT => -54 }, {#State 343 ACTIONS => { 'SET' => 1, 'PERL' => 40, 'NOT' => 38, 'IDENT' => 2, 'CLEAR' => 41, 'UNLESS' => 3, 'IF' => 44, "\$" => 43, 'STOP' => 6, 'CALL' => 45, 'THROW' => 8, 'GET' => 47, "[" => 9, 'TRY' => 10, 'LAST' => 49, 'DEBUG' => 51, 'RAWPERL' => 13, 'META' => 15, 'INCLUDE' => 17, "(" => 53, 'SWITCH' => 54, 'MACRO' => 18, 'WRAPPER' => 55, ";" => -18, 'FOR' => 21, 'NEXT' => 22, 'LITERAL' => 57, 'TEXT' => 24, "\"" => 60, 'PROCESS' => 61, 'RETURN' => 64, 'FILTER' => 25, 'INSERT' => 65, 'NUMBER' => 26, 'REF' => 27, 'WHILE' => 67, 'BLOCK' => 28, 'DEFAULT' => 69, "{" => 30, 'USE' => 32, 'VIEW' => 36, "\${" => 37 }, DEFAULT => -3, GOTOS => { 'item' => 39, 'node' => 23, 'rawperl' => 59, 'term' => 58, 'loop' => 4, 'use' => 63, 'expr' => 62, 'capture' => 42, 'statement' => 5, 'view' => 7, 'wrapper' => 46, 'atomexpr' => 48, 'chunk' => 11, 'defblock' => 66, 'atomdir' => 12, 'anonblock' => 50, 'sterm' => 68, 'defblockname' => 14, 'filter' => 29, 'ident' => 16, 'perl' => 31, 'setlist' => 70, 'chunks' => 33, 'try' => 35, 'switch' => 34, 'assign' => 19, 'block' => 348, 'directive' => 71, 'macro' => 20, 'condition' => 73, 'lterm' => 56 } }, {#State 344 ACTIONS => { 'SET' => 1, 'PERL' => 40, 'NOT' => 38, 'IDENT' => 2, 'CLEAR' => 41, 'UNLESS' => 3, 'IF' => 44, "\$" => 43, 'STOP' => 6, 'CALL' => 45, 'THROW' => 8, 'GET' => 47, "[" => 9, 'TRY' => 10, 'LAST' => 49, 'DEBUG' => 51, 'RAWPERL' => 13, 'META' => 15, 'INCLUDE' => 17, "(" => 53, 'SWITCH' => 54, 'MACRO' => 18, 'WRAPPER' => 55, ";" => -18, 'FOR' => 21, 'NEXT' => 22, 'LITERAL' => 57, 'TEXT' => 24, "\"" => 60, 'PROCESS' => 61, 'RETURN' => 64, 'FILTER' => 25, 'INSERT' => 65, 'NUMBER' => 26, 'REF' => 27, 'WHILE' => 67, 'BLOCK' => 28, 'DEFAULT' => 69, "{" => 30, 'USE' => 32, 'VIEW' => 36, "\${" => 37 }, DEFAULT => -3, GOTOS => { 'item' => 39, 'node' => 23, 'rawperl' => 59, 'term' => 58, 'loop' => 4, 'use' => 63, 'expr' => 62, 'capture' => 42, 'statement' => 5, 'view' => 7, 'wrapper' => 46, 'atomexpr' => 48, 'chunk' => 11, 'defblock' => 66, 'atomdir' => 12, 'anonblock' => 50, 'sterm' => 68, 'defblockname' => 14, 'filter' => 29, 'ident' => 16, 'perl' => 31, 'setlist' => 70, 'chunks' => 33, 'try' => 35, 'switch' => 34, 'assign' => 19, 'block' => 349, 'directive' => 71, 'macro' => 20, 'condition' => 73, 'lterm' => 56 } }, {#State 345 ACTIONS => { 'ELSIF' => 290, 'ELSE' => 288 }, DEFAULT => -50, GOTOS => { 'else' => 350 } }, {#State 346 DEFAULT => -68 }, {#State 347 DEFAULT => -69 }, {#State 348 ACTIONS => { 'CASE' => 313 }, DEFAULT => -55, GOTOS => { 'case' => 351 } }, {#State 349 DEFAULT => -53 }, {#State 350 DEFAULT => -48 }, {#State 351 DEFAULT => -52 } ]; #======================================================================== # Rules #======================================================================== $RULES = [ [#Rule 0 '$start', 2, undef ], [#Rule 1 'template', 1, sub #line 64 "Parser.yp" { $factory->template($_[1]) } ], [#Rule 2 'block', 1, sub #line 67 "Parser.yp" { $factory->block($_[1]) } ], [#Rule 3 'block', 0, sub #line 68 "Parser.yp" { $factory->block() } ], [#Rule 4 'chunks', 2, sub #line 71 "Parser.yp" { push(@{$_[1]}, $_[2]) if defined $_[2]; $_[1] } ], [#Rule 5 'chunks', 1, sub #line 73 "Parser.yp" { defined $_[1] ? [ $_[1] ] : [ ] } ], [#Rule 6 'chunk', 1, sub #line 76 "Parser.yp" { $factory->textblock($_[1]) } ], [#Rule 7 'chunk', 2, undef ], [#Rule 8 'statement', 1, undef ], [#Rule 9 'statement', 1, undef ], [#Rule 10 'statement', 1, undef ], [#Rule 11 'statement', 1, undef ], [#Rule 12 'statement', 1, undef ], [#Rule 13 'statement', 1, undef ], [#Rule 14 'statement', 1, undef ], [#Rule 15 'statement', 1, undef ], [#Rule 16 'statement', 1, sub #line 89 "Parser.yp" { $factory->get($_[1]) } ], [#Rule 17 'statement', 2, sub #line 90 "Parser.yp" { $_[0]->add_metadata($_[2]); } ], [#Rule 18 'statement', 0, undef ], [#Rule 19 'directive', 1, sub #line 94 "Parser.yp" { $factory->set($_[1]) } ], [#Rule 20 'directive', 1, undef ], [#Rule 21 'directive', 1, undef ], [#Rule 22 'directive', 1, undef ], [#Rule 23 'directive', 1, undef ], [#Rule 24 'directive', 1, undef ], [#Rule 25 'directive', 1, undef ], [#Rule 26 'atomexpr', 1, sub #line 108 "Parser.yp" { $factory->get($_[1]) } ], [#Rule 27 'atomexpr', 1, undef ], [#Rule 28 'atomdir', 2, sub #line 112 "Parser.yp" { $factory->get($_[2]) } ], [#Rule 29 'atomdir', 2, sub #line 113 "Parser.yp" { $factory->call($_[2]) } ], [#Rule 30 'atomdir', 2, sub #line 114 "Parser.yp" { $factory->set($_[2]) } ], [#Rule 31 'atomdir', 2, sub #line 115 "Parser.yp" { $factory->default($_[2]) } ], [#Rule 32 'atomdir', 2, sub #line 116 "Parser.yp" { $factory->insert($_[2]) } ], [#Rule 33 'atomdir', 2, sub #line 117 "Parser.yp" { $factory->include($_[2]) } ], [#Rule 34 'atomdir', 2, sub #line 118 "Parser.yp" { $factory->process($_[2]) } ], [#Rule 35 'atomdir', 2, sub #line 119 "Parser.yp" { $factory->throw($_[2]) } ], [#Rule 36 'atomdir', 1, sub #line 120 "Parser.yp" { $factory->return() } ], [#Rule 37 'atomdir', 1, sub #line 121 "Parser.yp" { $factory->stop() } ], [#Rule 38 'atomdir', 1, sub #line 122 "Parser.yp" { "\$output = '';"; } ], [#Rule 39 'atomdir', 1, sub #line 123 "Parser.yp" { $_[0]->{ INFOR } || $_[0]->{ INWHILE } ? 'last LOOP;' : 'last;' } ], [#Rule 40 'atomdir', 1, sub #line 126 "Parser.yp" { $_[0]->{ INFOR } ? $factory->next() : ($_[0]->{ INWHILE } ? 'next LOOP;' : 'next;') } ], [#Rule 41 'atomdir', 2, sub #line 131 "Parser.yp" { if ($_[2]->[0]->[0] =~ /^'(on|off)'$/) { $_[0]->{ DEBUG_DIRS } = ($1 eq 'on'); $factory->debug($_[2]); } else { $_[0]->{ DEBUG_DIRS } ? $factory->debug($_[2]) : ''; } } ], [#Rule 42 'atomdir', 1, undef ], [#Rule 43 'atomdir', 1, undef ], [#Rule 44 'condition', 6, sub #line 144 "Parser.yp" { $factory->if(@_[2, 4, 5]) } ], [#Rule 45 'condition', 3, sub #line 145 "Parser.yp" { $factory->if(@_[3, 1]) } ], [#Rule 46 'condition', 6, sub #line 147 "Parser.yp" { $factory->if("!($_[2])", @_[4, 5]) } ], [#Rule 47 'condition', 3, sub #line 148 "Parser.yp" { $factory->if("!($_[3])", $_[1]) } ], [#Rule 48 'else', 5, sub #line 152 "Parser.yp" { unshift(@{$_[5]}, [ @_[2, 4] ]); $_[5]; } ], [#Rule 49 'else', 3, sub #line 154 "Parser.yp" { [ $_[3] ] } ], [#Rule 50 'else', 0, sub #line 155 "Parser.yp" { [ undef ] } ], [#Rule 51 'switch', 6, sub #line 159 "Parser.yp" { $factory->switch(@_[2, 5]) } ], [#Rule 52 'case', 5, sub #line 163 "Parser.yp" { unshift(@{$_[5]}, [ @_[2, 4] ]); $_[5]; } ], [#Rule 53 'case', 4, sub #line 165 "Parser.yp" { [ $_[4] ] } ], [#Rule 54 'case', 3, sub #line 166 "Parser.yp" { [ $_[3] ] } ], [#Rule 55 'case', 0, sub #line 167 "Parser.yp" { [ undef ] } ], [#Rule 56 '@1-3', 0, sub #line 170 "Parser.yp" { $_[0]->{ INFOR }++ } ], [#Rule 57 'loop', 6, sub #line 171 "Parser.yp" { $_[0]->{ INFOR }--; $factory->foreach(@{$_[2]}, $_[5]) } ], [#Rule 58 'loop', 3, sub #line 175 "Parser.yp" { $factory->foreach(@{$_[3]}, $_[1]) } ], [#Rule 59 '@2-3', 0, sub #line 176 "Parser.yp" { $_[0]->{ INWHILE }++ } ], [#Rule 60 'loop', 6, sub #line 177 "Parser.yp" { $_[0]->{ INWHILE }--; $factory->while(@_[2, 5]) } ], [#Rule 61 'loop', 3, sub #line 179 "Parser.yp" { $factory->while(@_[3, 1]) } ], [#Rule 62 'loopvar', 4, sub #line 182 "Parser.yp" { [ @_[1, 3, 4] ] } ], [#Rule 63 'loopvar', 4, sub #line 183 "Parser.yp" { [ @_[1, 3, 4] ] } ], [#Rule 64 'loopvar', 2, sub #line 184 "Parser.yp" { [ 0, @_[1, 2] ] } ], [#Rule 65 'wrapper', 5, sub #line 188 "Parser.yp" { $factory->wrapper(@_[2, 4]) } ], [#Rule 66 'wrapper', 3, sub #line 190 "Parser.yp" { $factory->wrapper(@_[3, 1]) } ], [#Rule 67 'try', 5, sub #line 194 "Parser.yp" { $factory->try(@_[3, 4]) } ], [#Rule 68 'final', 5, sub #line 198 "Parser.yp" { unshift(@{$_[5]}, [ @_[2,4] ]); $_[5]; } ], [#Rule 69 'final', 5, sub #line 201 "Parser.yp" { unshift(@{$_[5]}, [ undef, $_[4] ]); $_[5]; } ], [#Rule 70 'final', 4, sub #line 204 "Parser.yp" { unshift(@{$_[4]}, [ undef, $_[3] ]); $_[4]; } ], [#Rule 71 'final', 3, sub #line 206 "Parser.yp" { [ $_[3] ] } ], [#Rule 72 'final', 0, sub #line 207 "Parser.yp" { [ 0 ] } ], [#Rule 73 'use', 2, sub #line 210 "Parser.yp" { $factory->use($_[2]) } ], [#Rule 74 '@3-3', 0, sub #line 213 "Parser.yp" { $_[0]->push_defblock(); } ], [#Rule 75 'view', 6, sub #line 214 "Parser.yp" { $factory->view(@_[2,5], $_[0]->pop_defblock) } ], [#Rule 76 '@4-2', 0, sub #line 218 "Parser.yp" { ${$_[0]->{ INPERL }}++; } ], [#Rule 77 'perl', 5, sub #line 219 "Parser.yp" { ${$_[0]->{ INPERL }}--; $_[0]->{ EVAL_PERL } ? $factory->perl($_[4]) : $factory->no_perl(); } ], [#Rule 78 '@5-1', 0, sub #line 225 "Parser.yp" { ${$_[0]->{ INPERL }}++; $rawstart = ${$_[0]->{'LINE'}}; } ], [#Rule 79 'rawperl', 5, sub #line 227 "Parser.yp" { ${$_[0]->{ INPERL }}--; $_[0]->{ EVAL_PERL } ? $factory->rawperl($_[4], $rawstart) : $factory->no_perl(); } ], [#Rule 80 'filter', 5, sub #line 234 "Parser.yp" { $factory->filter(@_[2,4]) } ], [#Rule 81 'filter', 3, sub #line 236 "Parser.yp" { $factory->filter(@_[3,1]) } ], [#Rule 82 'defblock', 5, sub #line 241 "Parser.yp" { my $name = join('/', @{ $_[0]->{ DEFBLOCKS } }); pop(@{ $_[0]->{ DEFBLOCKS } }); $_[0]->define_block($name, $_[4]); undef } ], [#Rule 83 'defblockname', 2, sub #line 248 "Parser.yp" { push(@{ $_[0]->{ DEFBLOCKS } }, $_[2]); $_[2]; } ], [#Rule 84 'blockname', 1, undef ], [#Rule 85 'blockname', 1, sub #line 254 "Parser.yp" { $_[1] =~ s/^'(.*)'$/$1/; $_[1] } ], [#Rule 86 'blockargs', 1, undef ], [#Rule 87 'blockargs', 0, undef ], [#Rule 88 'anonblock', 5, sub #line 262 "Parser.yp" { local $" = ', '; print STDERR "experimental block args: [@{ $_[2] }]\n" if $_[2]; $factory->anon_block($_[4]) } ], [#Rule 89 'capture', 3, sub #line 268 "Parser.yp" { $factory->capture(@_[1, 3]) } ], [#Rule 90 'macro', 6, sub #line 272 "Parser.yp" { $factory->macro(@_[2, 6, 4]) } ], [#Rule 91 'macro', 3, sub #line 273 "Parser.yp" { $factory->macro(@_[2, 3]) } ], [#Rule 92 'mdir', 1, undef ], [#Rule 93 'mdir', 4, sub #line 277 "Parser.yp" { $_[3] } ], [#Rule 94 'margs', 2, sub #line 280 "Parser.yp" { push(@{$_[1]}, $_[2]); $_[1] } ], [#Rule 95 'margs', 2, sub #line 281 "Parser.yp" { $_[1] } ], [#Rule 96 'margs', 1, sub #line 282 "Parser.yp" { [ $_[1] ] } ], [#Rule 97 'metadata', 2, sub #line 285 "Parser.yp" { push(@{$_[1]}, @{$_[2]}); $_[1] } ], [#Rule 98 'metadata', 2, undef ], [#Rule 99 'metadata', 1, undef ], [#Rule 100 'meta', 3, sub #line 290 "Parser.yp" { for ($_[3]) { s/^'//; s/'$//; s/\\'/'/g }; [ @_[1,3] ] } ], [#Rule 101 'meta', 5, sub #line 293 "Parser.yp" { [ @_[1,4] ] } ], [#Rule 102 'meta', 3, sub #line 294 "Parser.yp" { [ @_[1,3] ] } ], [#Rule 103 'term', 1, undef ], [#Rule 104 'term', 1, undef ], [#Rule 105 'lterm', 3, sub #line 306 "Parser.yp" { "[ $_[2] ]" } ], [#Rule 106 'lterm', 3, sub #line 307 "Parser.yp" { "[ $_[2] ]" } ], [#Rule 107 'lterm', 2, sub #line 308 "Parser.yp" { "[ ]" } ], [#Rule 108 'lterm', 3, sub #line 309 "Parser.yp" { "{ $_[2] }" } ], [#Rule 109 'sterm', 1, sub #line 312 "Parser.yp" { $factory->ident($_[1]) } ], [#Rule 110 'sterm', 2, sub #line 313 "Parser.yp" { $factory->identref($_[2]) } ], [#Rule 111 'sterm', 3, sub #line 314 "Parser.yp" { $factory->quoted($_[2]) } ], [#Rule 112 'sterm', 1, undef ], [#Rule 113 'sterm', 1, undef ], [#Rule 114 'list', 2, sub #line 319 "Parser.yp" { "$_[1], $_[2]" } ], [#Rule 115 'list', 2, undef ], [#Rule 116 'list', 1, undef ], [#Rule 117 'range', 3, sub #line 324 "Parser.yp" { $_[1] . '..' . $_[3] } ], [#Rule 118 'hash', 1, undef ], [#Rule 119 'hash', 0, sub #line 329 "Parser.yp" { "" } ], [#Rule 120 'params', 2, sub #line 332 "Parser.yp" { "$_[1], $_[2]" } ], [#Rule 121 'params', 2, undef ], [#Rule 122 'params', 1, undef ], [#Rule 123 'param', 3, sub #line 337 "Parser.yp" { "$_[1] => $_[3]" } ], [#Rule 124 'param', 3, sub #line 338 "Parser.yp" { "$_[1] => $_[3]" } ], [#Rule 125 'ident', 3, sub #line 341 "Parser.yp" { push(@{$_[1]}, @{$_[3]}); $_[1] } ], [#Rule 126 'ident', 3, sub #line 342 "Parser.yp" { push(@{$_[1]}, map {($_, 0)} split(/\./, $_[3])); $_[1]; } ], [#Rule 127 'ident', 1, undef ], [#Rule 128 'node', 1, sub #line 348 "Parser.yp" { [ $_[1], 0 ] } ], [#Rule 129 'node', 4, sub #line 349 "Parser.yp" { [ $_[1], $factory->args($_[3]) ] } ], [#Rule 130 'item', 1, sub #line 352 "Parser.yp" { "'$_[1]'" } ], [#Rule 131 'item', 3, sub #line 353 "Parser.yp" { $_[2] } ], [#Rule 132 'item', 2, sub #line 354 "Parser.yp" { $_[0]->{ V1DOLLAR } ? "'$_[2]'" : $factory->ident(["'$_[2]'", 0]) } ], [#Rule 133 'expr', 3, sub #line 359 "Parser.yp" { "$_[1] $_[2] $_[3]" } ], [#Rule 134 'expr', 3, sub #line 360 "Parser.yp" { "$_[1] $_[2] $_[3]" } ], [#Rule 135 'expr', 3, sub #line 361 "Parser.yp" { "$_[1] $_[2] $_[3]" } ], [#Rule 136 'expr', 3, sub #line 362 "Parser.yp" { "int($_[1] / $_[3])" } ], [#Rule 137 'expr', 3, sub #line 363 "Parser.yp" { "$_[1] % $_[3]" } ], [#Rule 138 'expr', 3, sub #line 364 "Parser.yp" { "$_[1] $CMPOP{ $_[2] } $_[3]" } ], [#Rule 139 'expr', 3, sub #line 365 "Parser.yp" { "$_[1] . $_[3]" } ], [#Rule 140 'expr', 3, sub #line 366 "Parser.yp" { "$_[1] && $_[3]" } ], [#Rule 141 'expr', 3, sub #line 367 "Parser.yp" { "$_[1] || $_[3]" } ], [#Rule 142 'expr', 2, sub #line 368 "Parser.yp" { "! $_[2]" } ], [#Rule 143 'expr', 5, sub #line 369 "Parser.yp" { "$_[1] ? $_[3] : $_[5]" } ], [#Rule 144 'expr', 3, sub #line 370 "Parser.yp" { $factory->assign(@{$_[2]}) } ], [#Rule 145 'expr', 3, sub #line 371 "Parser.yp" { "($_[2])" } ], [#Rule 146 'expr', 1, undef ], [#Rule 147 'setlist', 2, sub #line 375 "Parser.yp" { push(@{$_[1]}, @{$_[2]}); $_[1] } ], [#Rule 148 'setlist', 2, undef ], [#Rule 149 'setlist', 1, undef ], [#Rule 150 'assign', 3, sub #line 381 "Parser.yp" { [ $_[1], $_[3] ] } ], [#Rule 151 'assign', 3, sub #line 382 "Parser.yp" { [ @_[1,3] ] } ], [#Rule 152 'args', 2, sub #line 389 "Parser.yp" { push(@{$_[1]}, $_[2]); $_[1] } ], [#Rule 153 'args', 2, sub #line 390 "Parser.yp" { push(@{$_[1]->[0]}, $_[2]); $_[1] } ], [#Rule 154 'args', 4, sub #line 391 "Parser.yp" { push(@{$_[1]->[0]}, "'', " . $factory->assign(@_[2,4])); $_[1] } ], [#Rule 155 'args', 2, sub #line 393 "Parser.yp" { $_[1] } ], [#Rule 156 'args', 0, sub #line 394 "Parser.yp" { [ [ ] ] } ], [#Rule 157 'lnameargs', 3, sub #line 404 "Parser.yp" { push(@{$_[3]}, $_[1]); $_[3] } ], [#Rule 158 'lnameargs', 1, undef ], [#Rule 159 'lvalue', 1, undef ], [#Rule 160 'lvalue', 3, sub #line 409 "Parser.yp" { $factory->quoted($_[2]) } ], [#Rule 161 'lvalue', 1, undef ], [#Rule 162 'nameargs', 3, sub #line 413 "Parser.yp" { [ [$factory->ident($_[2])], $_[3] ] } ], [#Rule 163 'nameargs', 2, sub #line 414 "Parser.yp" { [ @_[1,2] ] } ], [#Rule 164 'nameargs', 4, sub #line 415 "Parser.yp" { [ @_[1,3] ] } ], [#Rule 165 'names', 3, sub #line 418 "Parser.yp" { push(@{$_[1]}, $_[3]); $_[1] } ], [#Rule 166 'names', 1, sub #line 419 "Parser.yp" { [ $_[1] ] } ], [#Rule 167 'name', 3, sub #line 422 "Parser.yp" { $factory->quoted($_[2]) } ], [#Rule 168 'name', 1, sub #line 423 "Parser.yp" { "'$_[1]'" } ], [#Rule 169 'name', 1, undef ], [#Rule 170 'filename', 3, sub #line 435 "Parser.yp" { "$_[1].$_[3]" } ], [#Rule 171 'filename', 1, undef ], [#Rule 172 'filepart', 1, undef ], [#Rule 173 'filepart', 1, undef ], [#Rule 174 'filepart', 1, undef ], [#Rule 175 'quoted', 2, sub #line 449 "Parser.yp" { push(@{$_[1]}, $_[2]) if defined $_[2]; $_[1] } ], [#Rule 176 'quoted', 0, sub #line 451 "Parser.yp" { [ ] } ], [#Rule 177 'quotable', 1, sub #line 454 "Parser.yp" { $factory->ident($_[1]) } ], [#Rule 178 'quotable', 1, sub #line 455 "Parser.yp" { $factory->text($_[1]) } ], [#Rule 179 'quotable', 1, sub #line 456 "Parser.yp" { undef } ] ]; 1; ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������vdradmin-am-3.6.13/lib/Template/Iterator.pm���������������������������������������������������������0000664�0000000�0000000�00000032004�14437161134�0020456�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#============================================================= -*-Perl-*- # # Template::Iterator # # DESCRIPTION # # Module defining an iterator class which is used by the FOREACH # directive for iterating through data sets. This may be # sub-classed to define more specific iterator types. # # An iterator is an object which provides a consistent way to # navigate through data which may have a complex underlying form. # This implementation uses the get_first() and get_next() methods to # iterate through a dataset. The get_first() method is called once # to perform any data initialisation and return the first value, # then get_next() is called repeatedly to return successive values. # Both these methods return a pair of values which are the data item # itself and a status code. The default implementation handles # iteration through an array (list) of elements which is passed by # reference to the constructor. An empty list is used if none is # passed. The module may be sub-classed to provide custom # implementations which iterate through any kind of data in any # manner as long as it can conforms to the get_first()/get_next() # interface. The object also implements the get_all() method for # returning all remaining elements as a list reference. # # For further information on iterators see "Design Patterns", by the # "Gang of Four" (Erich Gamma, Richard Helm, Ralph Johnson, John # Vlissides), Addision-Wesley, ISBN 0-201-63361-2. # # AUTHOR # Andy Wardley <abw@kfs.org> # # COPYRIGHT # Copyright (C) 1996-2000 Andy Wardley. All Rights Reserved. # Copyright (C) 1998-2000 Canon Research Centre Europe Ltd. # # This module is free software; you can redistribute it and/or # modify it under the same terms as Perl itself. # #---------------------------------------------------------------------------- # # $Id: Iterator.pm,v 2.59 2003/04/24 09:14:38 abw Exp $ # #============================================================================ package Template::Iterator; require 5.004; use strict; use vars qw( $VERSION $DEBUG $AUTOLOAD ); # AUTO? use base qw( Template::Base ); use Template::Constants; use Template::Exception; $VERSION = sprintf("%d.%02d", q$Revision: 2.59 $ =~ /(\d+)\.(\d+)/); $DEBUG = 0 unless defined $DEBUG; #======================================================================== # ----- CLASS METHODS ----- #======================================================================== #------------------------------------------------------------------------ # new(\@target, \%options) # # Constructor method which creates and returns a reference to a new # Template::Iterator object. A reference to the target data (array # or hash) may be passed for the object to iterate through. #------------------------------------------------------------------------ sub new { my $class = shift; my $data = shift || [ ]; my $params = shift || { }; if (ref $data eq 'HASH') { # map a hash into a list of { key => ???, value => ??? } hashes, # one for each key, sorted by keys $data = [ map { { key => $_, value => $data->{ $_ } } } sort keys %$data ]; } elsif (UNIVERSAL::can($data, 'as_list')) { $data = $data->as_list(); } elsif (ref $data ne 'ARRAY') { # coerce any non-list data into an array reference $data = [ $data ] ; } bless { _DATA => $data, _ERROR => '', }, $class; } #======================================================================== # ----- PUBLIC OBJECT METHODS ----- #======================================================================== #------------------------------------------------------------------------ # get_first() # # Initialises the object for iterating through the target data set. The # first record is returned, if defined, along with the STATUS_OK value. # If there is no target data, or the data is an empty set, then undef # is returned with the STATUS_DONE value. #------------------------------------------------------------------------ sub get_first { my $self = shift; my $data = $self->{ _DATA }; $self->{ _DATASET } = $self->{ _DATA }; my $size = scalar @$data; my $index = 0; return (undef, Template::Constants::STATUS_DONE) unless $size; # initialise various counters, flags, etc. @$self{ qw( SIZE MAX INDEX COUNT FIRST LAST ) } = ( $size, $size - 1, $index, 1, 1, $size > 1 ? 0 : 1, undef ); @$self{ qw( PREV NEXT ) } = ( undef, $self->{ _DATASET }->[ $index + 1 ]); return $self->{ _DATASET }->[ $index ]; } #------------------------------------------------------------------------ # get_next() # # Called repeatedly to access successive elements in the data set. # Should only be called after calling get_first() or a warning will # be raised and (undef, STATUS_DONE) returned. #------------------------------------------------------------------------ sub get_next { my $self = shift; my ($max, $index) = @$self{ qw( MAX INDEX ) }; my $data = $self->{ _DATASET }; # warn about incorrect usage unless (defined $index) { my ($pack, $file, $line) = caller(); warn("iterator get_next() called before get_first() at $file line $line\n"); return (undef, Template::Constants::STATUS_DONE); ## RETURN ## } # if there's still some data to go... if ($index < $max) { # update counters and flags $index++; @$self{ qw( INDEX COUNT FIRST LAST ) } = ( $index, $index + 1, 0, $index == $max ? 1 : 0 ); @$self{ qw( PREV NEXT ) } = @$data[ $index - 1, $index + 1 ]; return $data->[ $index ]; ## RETURN ## } else { return (undef, Template::Constants::STATUS_DONE); ## RETURN ## } } #------------------------------------------------------------------------ # get_all() # # Method which returns all remaining items in the iterator as a Perl list # reference. May be called at any time in the life-cycle of the iterator. # The get_first() method will be called automatically if necessary, and # then subsequent get_next() calls are made, storing each returned # result until the list is exhausted. #------------------------------------------------------------------------ sub get_all { my $self = shift; my ($max, $index) = @$self{ qw( MAX INDEX ) }; my @data; # if there's still some data to go... if ($index < $max) { $index++; @data = @{ $self->{ _DATASET } } [ $index..$max ]; # update counters and flags @$self{ qw( INDEX COUNT FIRST LAST ) } = ( $max, $max + 1, 0, 1 ); return \@data; ## RETURN ## } else { return (undef, Template::Constants::STATUS_DONE); ## RETURN ## } } #------------------------------------------------------------------------ # AUTOLOAD # # Provides access to internal fields (e.g. size, first, last, max, etc) #------------------------------------------------------------------------ sub AUTOLOAD { my $self = shift; my $item = $AUTOLOAD; $item =~ s/.*:://; return if $item eq 'DESTROY'; # alias NUMBER to COUNT for backwards compatability $item = 'COUNT' if $item =~ /NUMBER/i; return $self->{ uc $item }; } #======================================================================== # ----- PRIVATE DEBUG METHODS ----- #======================================================================== #------------------------------------------------------------------------ # _dump() # # Debug method which returns a string detailing the internal state of # the iterator object. #------------------------------------------------------------------------ sub _dump { my $self = shift; join('', " Data: ", $self->{ _DATA }, "\n", " Index: ", $self->{ INDEX }, "\n", "Number: ", $self->{ NUMBER }, "\n", " Max: ", $self->{ MAX }, "\n", " Size: ", $self->{ SIZE }, "\n", " First: ", $self->{ FIRST }, "\n", " Last: ", $self->{ LAST }, "\n", "\n" ); } 1; __END__ #------------------------------------------------------------------------ # IMPORTANT NOTE # This documentation is generated automatically from source # templates. Any changes you make here may be lost. # # The 'docsrc' documentation source bundle is available for download # from http://www.template-toolkit.org/docs.html and contains all # the source templates, XML files, scripts, etc., from which the # documentation for the Template Toolkit is built. #------------------------------------------------------------------------ =head1 NAME Template::Iterator - Data iterator used by the FOREACH directive =head1 SYNOPSIS my $iter = Template::Iterator->new(\@data, \%options); =head1 DESCRIPTION The Template::Iterator module defines a generic data iterator for use by the FOREACH directive. It may be used as the base class for custom iterators. =head1 PUBLIC METHODS =head2 new($data) Constructor method. A reference to a list of values is passed as the first parameter. Subsequent calls to get_first() and get_next() calls will return each element from the list. my $iter = Template::Iterator->new([ 'foo', 'bar', 'baz' ]); The constructor will also accept a reference to a hash array and will expand it into a list in which each entry is a hash array containing a 'key' and 'value' item, sorted according to the hash keys. my $iter = Template::Iterator->new({ foo => 'Foo Item', bar => 'Bar Item', }); This is equivalent to: my $iter = Template::Iterator->new([ { key => 'bar', value => 'Bar Item' }, { key => 'foo', value => 'Foo Item' }, ]); When passed a single item which is not an array reference, the constructor will automatically create a list containing that single item. my $iter = Template::Iterator->new('foo'); This is equivalent to: my $iter = Template::Iterator->new([ 'foo' ]); Note that a single item which is an object based on a blessed ARRAY references will NOT be treated as an array and will be folded into a list containing that one object reference. my $list = bless [ 'foo', 'bar' ], 'MyListClass'; my $iter = Template::Iterator->new($list); equivalent to: my $iter = Template::Iterator->new([ $list ]); If the object provides an as_list() method then the Template::Iterator constructor will call that method to return the list of data. For example: package MyListObject; sub new { my $class = shift; bless [ @_ ], $class; } package main; my $list = MyListObject->new('foo', 'bar'); my $iter = Template::Iterator->new($list); This is then functionally equivalent to: my $iter = Template::Iterator->new([ $list ]); The iterator will return only one item, a reference to the MyListObject object, $list. By adding an as_list() method to the MyListObject class, we can force the Template::Iterator constructor to treat the object as a list and use the data contained within. package MyListObject; ... sub as_list { my $self = shift; return $self; } package main; my $list = MyListObject->new('foo', 'bar'); my $iter = Template::Iterator->new($list); The iterator will now return the two item, 'foo' and 'bar', which the MyObjectList encapsulates. =head2 get_first() Returns a ($value, $error) pair for the first item in the iterator set. The $error returned may be zero or undefined to indicate a valid datum was successfully returned. Returns an error of STATUS_DONE if the list is empty. =head2 get_next() Returns a ($value, $error) pair for the next item in the iterator set. Returns an error of STATUS_DONE if all items in the list have been visited. =head2 get_all() Returns a (\@values, $error) pair for all remaining items in the iterator set. Returns an error of STATUS_DONE if all items in the list have been visited. =head2 size() Returns the size of the data set or undef if unknown. =head2 max() Returns the maximum index number (i.e. the index of the last element) which is equivalent to size() - 1. =head2 index() Returns the current index number which is in the range 0 to max(). =head2 count() Returns the current iteration count in the range 1 to size(). This is equivalent to index() + 1. Note that number() is supported as an alias for count() for backwards compatability. =head2 first() Returns a boolean value to indicate if the iterator is currently on the first iteration of the set. =head2 last() Returns a boolean value to indicate if the iterator is currently on the last iteration of the set. =head2 prev() Returns the previous item in the data set, or undef if the iterator is on the first item. =head2 next() Returns the next item in the data set or undef if the iterator is on the last item. =head1 AUTHOR Andy Wardley E<lt>abw@andywardley.comE<gt> L<http://www.andywardley.com/|http://www.andywardley.com/> =head1 VERSION 2.59, distributed as part of the Template Toolkit version 2.10, released on 24 July 2003. =head1 COPYRIGHT Copyright (C) 1996-2003 Andy Wardley. All Rights Reserved. Copyright (C) 1998-2002 Canon Research Centre Europe Ltd. This module is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =head1 SEE ALSO L<Template|Template> ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������vdradmin-am-3.6.13/lib/Template/Namespace/����������������������������������������������������������0000775�0000000�0000000�00000000000�14437161134�0020224�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������vdradmin-am-3.6.13/lib/Template/Namespace/Constants.pm����������������������������������������������0000664�0000000�0000000�00000011727�14437161134�0022546�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#================================================================= -*-Perl-*- # # Template::Namespace::Constants # # DESCRIPTION # Plugin compiler module for performing constant folding at compile time # on variables in a particular namespace. # # AUTHOR # Andy Wardley <abw@andywardley.com> # # COPYRIGHT # Copyright (C) 1996-2002 Andy Wardley. All Rights Reserved. # Copyright (C) 1998-2002 Canon Research Centre Europe Ltd. # # This module is free software; you can redistribute it and/or # modify it under the same terms as Perl itself. # # REVISION # $Id: Constants.pm,v 1.17 2003/04/24 09:14:42 abw Exp $ # #============================================================================ package Template::Namespace::Constants; use strict; use Template::Base; use Template::Config; use Template::Directive; use Template::Exception; use base qw( Template::Base ); use vars qw( $VERSION $DEBUG ); $VERSION = sprintf("%d.%02d", q$Revision: 1.17 $ =~ /(\d+)\.(\d+)/); $DEBUG = 0 unless defined $DEBUG; sub _init { my ($self, $config) = @_; $self->{ STASH } = Template::Config->stash($config) || return $self->error(Template::Config->error()); return $self; } #------------------------------------------------------------------------ # ident(\@ident) foo.bar(baz) #------------------------------------------------------------------------ sub ident { my ($self, $ident) = @_; my @save = @$ident; # discard first node indicating constants namespace splice(@$ident, 0, 2); my $nelems = @$ident / 2; my ($e, $result); local $" = ', '; print STDERR "constant ident [ @$ident ] " if $DEBUG; foreach $e (0..$nelems-1) { # node name must be a constant unless ($ident->[$e * 2] =~ s/^'(.+)'$/$1/s) { $self->DEBUG(" * deferred (non-constant item: ", $ident->[$e * 2], ")\n") if $DEBUG; return Template::Directive->ident(\@save); } # if args is non-zero then it must be eval'ed if ($ident->[$e * 2 + 1]) { my $args = $ident->[$e * 2 + 1]; my $comp = eval "$args"; if ($@) { $self->DEBUG(" * deferred (non-constant args: $args)\n") if $DEBUG; return Template::Directive->ident(\@save); } $self->DEBUG("($args) ") if $comp && $DEBUG; $ident->[$e * 2 + 1] = $comp; } } $result = $self->{ STASH }->get($ident); if (! length $result || ref $result) { my $reason = length $result ? 'reference' : 'no result'; $self->DEBUG(" * deferred ($reason)\n") if $DEBUG; return Template::Directive->ident(\@save); } $result =~ s/'/\\'/g; $self->DEBUG(" * resolved => '$result'\n") if $DEBUG; return "'$result'"; } 1; __END__ #------------------------------------------------------------------------ # IMPORTANT NOTE # This documentation is generated automatically from source # templates. Any changes you make here may be lost. # # The 'docsrc' documentation source bundle is available for download # from http://www.template-toolkit.org/docs.html and contains all # the source templates, XML files, scripts, etc., from which the # documentation for the Template Toolkit is built. #------------------------------------------------------------------------ =head1 NAME Template::Namespace::Constants - Compile time constant folding =head1 SYNOPSIS # easy way to define constants use Template; my $tt = Template->new({ CONSTANTS => { pi => 3.14, e => 2.718, }, }); # nitty-gritty, hands-dirty way use Template::Namespace::Constants; my $tt = Template->new({ NAMESPACE => { constants => Template::Namespace::Constants->new({ pi => 3.14, e => 2.718, }, }, }); =head1 DESCRIPTION The Template::Namespace::Constants module implements a namespace handler which is plugged into the Template::Directive compiler module. This then performs compile time constant folding of variables in a particular namespace. =head1 PUBLIC METHODS =head2 new(\%constants) The new() constructor method creates and returns a reference to a new Template::Namespace::Constants object. This creates an internal stash to store the constant variable definitions passed as arguments. my $handler = Template::Namespace::Constants->new({ pi => 3.14, e => 2.718, }); =head2 ident(\@ident) Method called to resolve a variable identifier into a compiled form. In this case, the method fetches the corresponding constant value from its internal stash and returns it. =head1 AUTHOR Andy Wardley E<lt>abw@andywardley.comE<gt> L<http://www.andywardley.com/|http://www.andywardley.com/> =head1 VERSION 1.17, distributed as part of the Template Toolkit version 2.10, released on 24 July 2003. =head1 COPYRIGHT Copyright (C) 1996-2003 Andy Wardley. All Rights Reserved. Copyright (C) 1998-2002 Canon Research Centre Europe Ltd. This module is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =head1 SEE ALSO L<Template::Directive|Template::Directive> �����������������������������������������vdradmin-am-3.6.13/lib/Template/Parser.pm�����������������������������������������������������������0000664�0000000�0000000�00000121044�14437161134�0020124�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#============================================================= -*-Perl-*- # # Template::Parser # # DESCRIPTION # This module implements a LALR(1) parser and assocated support # methods to parse template documents into the appropriate "compiled" # format. Much of the parser DFA code (see _parse() method) is based # on Francois Desarmenien's Parse::Yapp module. Kudos to him. # # AUTHOR # Andy Wardley <abw@kfs.org> # # COPYRIGHT # Copyright (C) 1996-2000 Andy Wardley. All Rights Reserved. # Copyright (C) 1998-2000 Canon Research Centre Europe Ltd. # # This module is free software; you can redistribute it and/or # modify it under the same terms as Perl itself. # # The following copyright notice appears in the Parse::Yapp # documentation. # # The Parse::Yapp module and its related modules and shell # scripts are copyright (c) 1998 Francois Desarmenien, # France. All rights reserved. # # You may use and distribute them under the terms of either # the GNU General Public License or the Artistic License, as # specified in the Perl README file. # #---------------------------------------------------------------------------- # # $Id: Parser.pm,v 2.75 2003/07/01 12:44:56 darren Exp $ # #============================================================================ package Template::Parser; require 5.004; use strict; use vars qw( $VERSION $DEBUG $ERROR ); use base qw( Template::Base ); use vars qw( $TAG_STYLE $DEFAULT_STYLE $QUOTED_ESCAPES ); use Template::Constants qw( :status :chomp ); use Template::Directive; use Template::Grammar; # parser state constants use constant CONTINUE => 0; use constant ACCEPT => 1; use constant ERROR => 2; use constant ABORT => 3; $VERSION = sprintf("%d.%02d", q$Revision: 2.75 $ =~ /(\d+)\.(\d+)/); $DEBUG = 0 unless defined $DEBUG; $ERROR = ''; #======================================================================== # -- COMMON TAG STYLES -- #======================================================================== $TAG_STYLE = { 'default' => [ '\[%', '%\]' ], 'template1' => [ '[\[%]%', '%[\]%]' ], 'metatext' => [ '%%', '%%' ], 'html' => [ '<!--', '-->' ], 'mason' => [ '<%', '>' ], 'asp' => [ '<%', '%>' ], 'php' => [ '<\?', '\?>' ], 'star' => [ '\[\*', '\*\]' ], }; $TAG_STYLE->{ template } = $TAG_STYLE->{ tt2 } = $TAG_STYLE->{ default }; $DEFAULT_STYLE = { START_TAG => $TAG_STYLE->{ default }->[0], END_TAG => $TAG_STYLE->{ default }->[1], # TAG_STYLE => 'default', ANYCASE => 0, INTERPOLATE => 0, PRE_CHOMP => 0, POST_CHOMP => 0, V1DOLLAR => 0, EVAL_PERL => 0, }; $QUOTED_ESCAPES = { n => "\n", r => "\r", t => "\t", }; #======================================================================== # ----- PUBLIC METHODS ----- #======================================================================== #------------------------------------------------------------------------ # new(\%config) # # Constructor method. #------------------------------------------------------------------------ sub new { my $class = shift; my $config = $_[0] && UNIVERSAL::isa($_[0], 'HASH') ? shift(@_) : { @_ }; my ($tagstyle, $debug, $start, $end, $defaults, $grammar, $hash, $key, $udef); my $self = bless { START_TAG => undef, END_TAG => undef, TAG_STYLE => 'default', ANYCASE => 0, INTERPOLATE => 0, PRE_CHOMP => 0, POST_CHOMP => 0, V1DOLLAR => 0, EVAL_PERL => 0, GRAMMAR => undef, _ERROR => '', FACTORY => 'Template::Directive', }, $class; # update self with any relevant keys in config foreach $key (keys %$self) { $self->{ $key } = $config->{ $key } if defined $config->{ $key }; } $self->{ FILEINFO } = [ ]; # DEBUG config item can be a bitmask if (defined ($debug = $config->{ DEBUG })) { $self->{ DEBUG } = $debug & ( Template::Constants::DEBUG_PARSER | Template::Constants::DEBUG_FLAGS ); $self->{ DEBUG_DIRS } = $debug & Template::Constants::DEBUG_DIRS; } # package variable can be set to 1 to support previous behaviour elsif ($DEBUG == 1) { $self->{ DEBUG } = Template::Constants::DEBUG_PARSER; $self->{ DEBUG_DIRS } = 0; } # otherwise let $DEBUG be a bitmask else { $self->{ DEBUG } = $DEBUG & ( Template::Constants::DEBUG_PARSER | Template::Constants::DEBUG_FLAGS ); $self->{ DEBUG_DIRS } = $DEBUG & Template::Constants::DEBUG_DIRS; } $grammar = $self->{ GRAMMAR } ||= do { require Template::Grammar; Template::Grammar->new(); }; # build a FACTORY object to include any NAMESPACE definitions, # but only if FACTORY isn't already an object if ($config->{ NAMESPACE } && ! ref $self->{ FACTORY }) { my $fclass = $self->{ FACTORY }; $self->{ FACTORY } = $fclass->new( NAMESPACE => $config->{ NAMESPACE } ) || return $class->error($fclass->error()); } # # determine START_TAG and END_TAG for specified (or default) TAG_STYLE # $tagstyle = $self->{ TAG_STYLE } || 'default'; # return $class->error("Invalid tag style: $tagstyle") # unless defined ($start = $TAG_STYLE->{ $tagstyle }); # ($start, $end) = @$start; # # $self->{ START_TAG } ||= $start; # $self->{ END_TAG } ||= $end; # load grammar rules, states and lex table @$self{ qw( LEXTABLE STATES RULES ) } = @$grammar{ qw( LEXTABLE STATES RULES ) }; $self->new_style($config) || return $class->error($self->error()); return $self; } #------------------------------------------------------------------------ # new_style(\%config) # # Install a new (stacked) parser style. This feature is currently # experimental but should mimic the previous behaviour with regard to # TAG_STYLE, START_TAG, END_TAG, etc. #------------------------------------------------------------------------ sub new_style { my ($self, $config) = @_; my $styles = $self->{ STYLE } ||= [ ]; my ($tagstyle, $tags, $start, $end, $key); # clone new style from previous or default style my $style = { %{ $styles->[-1] || $DEFAULT_STYLE } }; # expand START_TAG and END_TAG from specified TAG_STYLE if ($tagstyle = $config->{ TAG_STYLE }) { return $self->error("Invalid tag style: $tagstyle") unless defined ($tags = $TAG_STYLE->{ $tagstyle }); ($start, $end) = @$tags; $config->{ START_TAG } ||= $start; $config->{ END_TAG } ||= $end; } foreach $key (keys %$DEFAULT_STYLE) { $style->{ $key } = $config->{ $key } if defined $config->{ $key }; } push(@$styles, $style); return $style; } #------------------------------------------------------------------------ # old_style() # # Pop the current parser style and revert to the previous one. See # new_style(). ** experimental ** #------------------------------------------------------------------------ sub old_style { my $self = shift; my $styles = $self->{ STYLE }; return $self->error('only 1 parser style remaining') unless (@$styles > 1); pop @$styles; return $styles->[-1]; } #------------------------------------------------------------------------ # parse($text, $data) # # Parses the text string, $text and returns a hash array representing # the compiled template block(s) as Perl code, in the format expected # by Template::Document. #------------------------------------------------------------------------ sub parse { my ($self, $text, $info) = @_; my ($tokens, $block); $info->{ DEBUG } = $self->{ DEBUG_DIRS } unless defined $info->{ DEBUG }; # print "info: { ", join(', ', map { "$_ => $info->{ $_ }" } keys %$info), " }\n"; # store for blocks defined in the template (see define_block()) my $defblock = $self->{ DEFBLOCK } = { }; my $metadata = $self->{ METADATA } = [ ]; $self->{ _ERROR } = ''; # split file into TEXT/DIRECTIVE chunks $tokens = $self->split_text($text) || return undef; ## RETURN ## push(@{ $self->{ FILEINFO } }, $info); # parse chunks $block = $self->_parse($tokens, $info); pop(@{ $self->{ FILEINFO } }); return undef unless $block; ## RETURN ## $self->debug("compiled main template document block:\n$block") if $self->{ DEBUG } & Template::Constants::DEBUG_PARSER; return { BLOCK => $block, DEFBLOCKS => $defblock, METADATA => { @$metadata }, }; } #------------------------------------------------------------------------ # split_text($text) # # Split input template text into directives and raw text chunks. #------------------------------------------------------------------------ sub split_text { my ($self, $text) = @_; my ($pre, $dir, $prelines, $dirlines, $postlines, $chomp, $tags, @tags); my $style = $self->{ STYLE }->[-1]; my ($start, $end, $prechomp, $postchomp, $interp ) = @$style{ qw( START_TAG END_TAG PRE_CHOMP POST_CHOMP INTERPOLATE ) }; my @tokens = (); my $line = 1; return \@tokens ## RETURN ## unless defined $text && length $text; # extract all directives from the text while ($text =~ s/ ^(.*?) # $1 - start of line up to directive (?: $start # start of tag (.*?) # $2 - tag contents $end # end of tag ) //sx) { ($pre, $dir) = ($1, $2); $pre = '' unless defined $pre; $dir = '' unless defined $dir; $postlines = 0; # denotes lines chomped $prelines = ($pre =~ tr/\n//); # NULL - count only $dirlines = ($dir =~ tr/\n//); # ditto # the directive CHOMP options may modify the preceding text for ($dir) { # remove leading whitespace and check for a '-' chomp flag s/^([-+\#])?\s*//s; if ($1 && $1 eq '#') { # comment out entire directive except for any chomp flag $dir = ($dir =~ /([-+])$/) ? $1 : ''; } else { $chomp = ($1 && $1 eq '+') ? 0 : ($1 || $prechomp); # my $space = $prechomp == &Template::Constants::CHOMP_COLLAPSE my $space = $prechomp == CHOMP_COLLAPSE ? ' ' : ''; # chomp off whitespace and newline preceding directive $chomp and $pre =~ s/(\n|^)([ \t]*)\Z/($1||$2) ? $space : ''/me and $1 eq "\n" and $prelines++; } # remove trailing whitespace and check for a '-' chomp flag s/\s*([-+])?\s*$//s; $chomp = ($1 && $1 eq '+') ? 0 : ($1 || $postchomp); my $space = $postchomp == &Template::Constants::CHOMP_COLLAPSE ? ' ' : ''; $postlines++ if $chomp and $text =~ s/ ^ ([ \t]*)\n # whitespace to newline (?:(.|\n)|$) # any char (not EOF) / (($1||$2) ? $space : '') . (defined $2 ? $2 : '') /ex; } # any text preceding the directive can now be added if (length $pre) { push(@tokens, $interp ? [ $pre, $line, 'ITEXT' ] : ('TEXT', $pre) ); $line += $prelines; } # and now the directive, along with line number information if (length $dir) { # the TAGS directive is a compile-time switch if ($dir =~ /^TAGS\s+(.*)/i) { my @tags = split(/\s+/, $1); if (scalar @tags > 1) { ($start, $end) = map { quotemeta($_) } @tags; } elsif ($tags = $TAG_STYLE->{ $tags[0] }) { ($start, $end) = @$tags; } else { warn "invalid TAGS style: $tags[0]\n"; } } else { # DIRECTIVE is pushed as [ $dirtext, $line_no(s), \@tokens ] push(@tokens, [ $dir, ($dirlines ? sprintf("%d-%d", $line, $line + $dirlines) : $line), $self->tokenise_directive($dir) ]); } } # update line counter to include directive lines and any extra # newline chomped off the start of the following text $line += $dirlines + $postlines; } # anything remaining in the string is plain text push(@tokens, $interp ? [ $text, $line, 'ITEXT' ] : ( 'TEXT', $text) ) if length $text; return \@tokens; ## RETURN ## } #------------------------------------------------------------------------ # interpolate_text($text, $line) # # Examines $text looking for any variable references embedded like # $this or like ${ this }. #------------------------------------------------------------------------ sub interpolate_text { my ($self, $text, $line) = @_; my @tokens = (); my ($pre, $var, $dir); while ($text =~ / ( (?: \\. | [^\$] ){1,3000} ) # escaped or non-'$' character [$1] | ( \$ (?: # embedded variable [$2] (?: \{ ([^\}]*) \} ) # ${ ... } [$3] | ([\w\.]+) # $word [$4] ) ) /gx) { ($pre, $var, $dir) = ($1, $3 || $4, $2); # preceding text if (defined($pre) && length($pre)) { $line += $pre =~ tr/\n//; $pre =~ s/\\\$/\$/g; push(@tokens, 'TEXT', $pre); } # $variable reference if ($var) { $line += $dir =~ tr/\n/ /; push(@tokens, [ $dir, $line, $self->tokenise_directive($var) ]); } # other '$' reference - treated as text elsif ($dir) { $line += $dir =~ tr/\n//; push(@tokens, 'TEXT', $dir); } } return \@tokens; } #------------------------------------------------------------------------ # tokenise_directive($text) # # Called by the private _parse() method when it encounters a DIRECTIVE # token in the list provided by the split_text() or interpolate_text() # methods. The directive text is passed by parameter. # # The method splits the directive into individual tokens as recognised # by the parser grammar (see Template::Grammar for details). It # constructs a list of tokens each represented by 2 elements, as per # split_text() et al. The first element contains the token type, the # second the token itself. # # The method tokenises the string using a complex (but fast) regex. # For a deeper understanding of the regex magic at work here, see # Jeffrey Friedl's excellent book "Mastering Regular Expressions", # from O'Reilly, ISBN 1-56592-257-3 # # Returns a reference to the list of chunks (each one being 2 elements) # identified in the directive text. On error, the internal _ERROR string # is set and undef is returned. #------------------------------------------------------------------------ sub tokenise_directive { my ($self, $text, $line) = @_; my ($token, $uctoken, $type, $lookup); my $lextable = $self->{ LEXTABLE }; my $style = $self->{ STYLE }->[-1]; my ($anycase, $start, $end) = @$style{ qw( ANYCASE START_TAG END_TAG ) }; my @tokens = ( ); while ($text =~ / # strip out any comments (\#[^\n]*) | # a quoted phrase matches in $3 (["']) # $2 - opening quote, ' or " ( # $3 - quoted text buffer (?: # repeat group (no backreference) \\\\ # an escaped backslash \\ | # ...or... \\\2 # an escaped quote \" or \' (match $1) | # ...or... . # any other character | \n )*? # non-greedy repeat ) # end of $3 \2 # match opening quote | # an unquoted number matches in $4 (-?\d+(?:\.\d+)?) # numbers | # filename matches in $5 ( \/?\w+(?:(?:\/|::?)\w*)+ | \/\w+) | # an identifier matches in $6 (\w+) # variable identifier | # an unquoted word or symbol matches in $7 ( [(){}\[\]:;,\/\\] # misc parenthesis and symbols # | \-> # arrow operator (for future?) | [+\-*] # math operations | \$\{? # dollar with option left brace | => # like '=' | [=!<>]?= | [!<>] # eqality tests | &&? | \|\|? # boolean ops | \.\.? # n..n sequence | \S+ # something unquoted ) # end of $7 /gmxo) { # ignore comments to EOL next if $1; # quoted string if (defined ($token = $3)) { # double-quoted string may include $variable references if ($2 eq '"') { if ($token =~ /[\$\\]/) { $type = 'QUOTED'; # unescape " and \ but leave \$ escaped so that # interpolate_text() doesn't incorrectly treat it # as a variable reference # $token =~ s/\\([\\"])/$1/g; for ($token) { s/\\([^\$nrt])/$1/g; s/\\([nrt])/$QUOTED_ESCAPES->{ $1 }/ge; } push(@tokens, ('"') x 2, @{ $self->interpolate_text($token) }, ('"') x 2); next; } else { $type = 'LITERAL'; $token =~ s['][\\']g; $token = "'$token'"; } } else { $type = 'LITERAL'; $token = "'$token'"; } } # number elsif (defined ($token = $4)) { $type = 'NUMBER'; } elsif (defined($token = $5)) { $type = 'FILENAME'; } elsif (defined($token = $6)) { # reserved words may be in lower case unless case sensitive $uctoken = $anycase ? uc $token : $token; if (defined ($type = $lextable->{ $uctoken })) { $token = $uctoken; } else { $type = 'IDENT'; } } elsif (defined ($token = $7)) { # reserved words may be in lower case unless case sensitive $uctoken = $anycase ? uc $token : $token; unless (defined ($type = $lextable->{ $uctoken })) { $type = 'UNQUOTED'; } } push(@tokens, $type, $token); # print(STDERR " +[ $type, $token ]\n") # if $DEBUG; } # print STDERR "tokenise directive() returning:\n [ @tokens ]\n" # if $DEBUG; return \@tokens; ## RETURN ## } #------------------------------------------------------------------------ # define_block($name, $block) # # Called by the parser 'defblock' rule when a BLOCK definition is # encountered in the template. The name of the block is passed in the # first parameter and a reference to the compiled block is passed in # the second. This method stores the block in the $self->{ DEFBLOCK } # hash which has been initialised by parse() and will later be used # by the same method to call the store() method on the calling cache # to define the block "externally". #------------------------------------------------------------------------ sub define_block { my ($self, $name, $block) = @_; my $defblock = $self->{ DEFBLOCK } || return undef; $self->debug("compiled block '$name':\n$block") if $self->{ DEBUG } & Template::Constants::DEBUG_PARSER; $defblock->{ $name } = $block; return undef; } sub push_defblock { my $self = shift; my $stack = $self->{ DEFBLOCK_STACK } ||= []; push(@$stack, $self->{ DEFBLOCK } ); $self->{ DEFBLOCK } = { }; } sub pop_defblock { my $self = shift; my $defs = $self->{ DEFBLOCK }; my $stack = $self->{ DEFBLOCK_STACK } || return $defs; return $defs unless @$stack; $self->{ DEFBLOCK } = pop @$stack; return $defs; } #------------------------------------------------------------------------ # add_metadata(\@setlist) #------------------------------------------------------------------------ sub add_metadata { my ($self, $setlist) = @_; my $metadata = $self->{ METADATA } || return undef; push(@$metadata, @$setlist); return undef; } #======================================================================== # ----- PRIVATE METHODS ----- #======================================================================== #------------------------------------------------------------------------ # _parse(\@tokens, \@info) # # Parses the list of input tokens passed by reference and returns a # Template::Directive::Block object which contains the compiled # representation of the template. # # This is the main parser DFA loop. See embedded comments for # further details. # # On error, undef is returned and the internal _ERROR field is set to # indicate the error. This can be retrieved by calling the error() # method. #------------------------------------------------------------------------ sub _parse { my ($self, $tokens, $info) = @_; my ($token, $value, $text, $line, $inperl); my ($state, $stateno, $status, $action, $lookup, $coderet, @codevars); my ($lhs, $len, $code); # rule contents my $stack = [ [ 0, undef ] ]; # DFA stack # DEBUG # local $" = ', '; # retrieve internal rule and state tables my ($states, $rules) = @$self{ qw( STATES RULES ) }; # call the grammar set_factory method to install emitter factory $self->{ GRAMMAR }->install_factory($self->{ FACTORY }); $line = $inperl = 0; $self->{ LINE } = \$line; $self->{ INPERL } = \$inperl; $status = CONTINUE; my $in_string = 0; while(1) { # get state number and state $stateno = $stack->[-1]->[0]; $state = $states->[$stateno]; # see if any lookaheads exist for the current state if (exists $state->{'ACTIONS'}) { # get next token and expand any directives (i.e. token is an # array ref) onto the front of the token list while (! defined $token && @$tokens) { $token = shift(@$tokens); if (ref $token) { ($text, $line, $token) = @$token; if (ref $token) { if ($info->{ DEBUG } && ! $in_string) { # - - - - - - - - - - - - - - - - - - - - - - - - - # This is gnarly. Look away now if you're easily # frightened. We're pushing parse tokens onto the # pending list to simulate a DEBUG directive like so: # [% DEBUG msg line='20' text='INCLUDE foo' %] # - - - - - - - - - - - - - - - - - - - - - - - - - my $dtext = $text; $dtext =~ s[(['\\])][\\$1]g; unshift(@$tokens, DEBUG => 'DEBUG', IDENT => 'msg', IDENT => 'line', ASSIGN => '=', LITERAL => "'$line'", IDENT => 'text', ASSIGN => '=', LITERAL => "'$dtext'", IDENT => 'file', ASSIGN => '=', LITERAL => "'$info->{ name }'", (';') x 2, @$token, (';') x 2); } else { unshift(@$tokens, @$token, (';') x 2); } $token = undef; # force redo } elsif ($token eq 'ITEXT') { if ($inperl) { # don't perform interpolation in PERL blocks $token = 'TEXT'; $value = $text; } else { unshift(@$tokens, @{ $self->interpolate_text($text, $line) }); $token = undef; # force redo } } } else { # toggle string flag to indicate if we're crossing # a string boundary $in_string = ! $in_string if $token eq '"'; $value = shift(@$tokens); } }; # clear undefined token to avoid 'undefined variable blah blah' # warnings and let the parser logic pick it up in a minute $token = '' unless defined $token; # get the next state for the current lookahead token $action = defined ($lookup = $state->{'ACTIONS'}->{ $token }) ? $lookup : defined ($lookup = $state->{'DEFAULT'}) ? $lookup : undef; } else { # no lookahead actions $action = $state->{'DEFAULT'}; } # ERROR: no ACTION last unless defined $action; # - - - - - - - - - - - - - - - - - - - - - - - - - - - - # shift (+ive ACTION) # - - - - - - - - - - - - - - - - - - - - - - - - - - - - if ($action > 0) { push(@$stack, [ $action, $value ]); $token = $value = undef; redo; }; # - - - - - - - - - - - - - - - - - - - - - - - - - - - - # reduce (-ive ACTION) # - - - - - - - - - - - - - - - - - - - - - - - - - - - - ($lhs, $len, $code) = @{ $rules->[ -$action ] }; # no action imples ACCEPTance $action or $status = ACCEPT; # use dummy sub if code ref doesn't exist $code = sub { $_[1] } unless $code; @codevars = $len ? map { $_->[1] } @$stack[ -$len .. -1 ] : (); eval { $coderet = &$code( $self, @codevars ); }; if ($@) { my $err = $@; chomp $err; return $self->_parse_error($err); } # reduce stack by $len splice(@$stack, -$len, $len); # ACCEPT return $coderet ## RETURN ## if $status == ACCEPT; # ABORT return undef ## RETURN ## if $status == ABORT; # ERROR last if $status == ERROR; } continue { push(@$stack, [ $states->[ $stack->[-1][0] ]->{'GOTOS'}->{ $lhs }, $coderet ]), } # ERROR ## RETURN ## return $self->_parse_error('unexpected end of input') unless defined $value; # munge text of last directive to make it readable # $text =~ s/\n/\\n/g; return $self->_parse_error("unexpected end of directive", $text) if $value eq ';'; # end of directive SEPARATOR return $self->_parse_error("unexpected token ($value)", $text); } #------------------------------------------------------------------------ # _parse_error($msg, $dirtext) # # Method used to handle errors encountered during the parse process # in the _parse() method. #------------------------------------------------------------------------ sub _parse_error { my ($self, $msg, $text) = @_; my $line = $self->{ LINE }; $line = ref($line) ? $$line : $line; $line = 'unknown' unless $line; $msg .= "\n [% $text %]" if defined $text; return $self->error("line $line: $msg"); } #------------------------------------------------------------------------ # _dump() # # Debug method returns a string representing the internal state of the # object. #------------------------------------------------------------------------ sub _dump { my $self = shift; my $output = "[Template::Parser] {\n"; my $format = " %-16s => %s\n"; my $key; foreach $key (qw( START_TAG END_TAG TAG_STYLE ANYCASE INTERPOLATE PRE_CHOMP POST_CHOMP V1DOLLAR )) { my $val = $self->{ $key }; $val = '<undef>' unless defined $val; $output .= sprintf($format, $key, $val); } $output .= '}'; return $output; } 1; __END__ #------------------------------------------------------------------------ # IMPORTANT NOTE # This documentation is generated automatically from source # templates. Any changes you make here may be lost. # # The 'docsrc' documentation source bundle is available for download # from http://www.template-toolkit.org/docs.html and contains all # the source templates, XML files, scripts, etc., from which the # documentation for the Template Toolkit is built. #------------------------------------------------------------------------ =head1 NAME Template::Parser - LALR(1) parser for compiling template documents =head1 SYNOPSIS use Template::Parser; $parser = Template::Parser->new(\%config); $template = $parser->parse($text) || die $parser->error(), "\n"; =head1 DESCRIPTION The Template::Parser module implements a LALR(1) parser and associated methods for parsing template documents into Perl code. =head1 PUBLIC METHODS =head2 new(\%params) The new() constructor creates and returns a reference to a new Template::Parser object. A reference to a hash may be supplied as a parameter to provide configuration values. These may include: =over =item START_TAG, END_TAG The START_TAG and END_TAG options are used to specify character sequences or regular expressions that mark the start and end of a template directive. The default values for START_TAG and END_TAG are '[%' and '%]' respectively, giving us the familiar directive style: [% example %] Any Perl regex characters can be used and therefore should be escaped (or use the Perl C<quotemeta> function) if they are intended to represent literal characters. my $parser = Template::Parser->new({ START_TAG => quotemeta('<+'), END_TAG => quotemeta('+>'), }); example: <+ INCLUDE foobar +> The TAGS directive can also be used to set the START_TAG and END_TAG values on a per-template file basis. [% TAGS <+ +> %] =item TAG_STYLE The TAG_STYLE option can be used to set both START_TAG and END_TAG according to pre-defined tag styles. my $parser = Template::Parser->new({ TAG_STYLE => 'star', }); Available styles are: template [% ... %] (default) template1 [% ... %] or %% ... %% (TT version 1) metatext %% ... %% (Text::MetaText) star [* ... *] (TT alternate) php <? ... ?> (PHP) asp <% ... %> (ASP) mason <% ... > (HTML::Mason) html <!-- ... --> (HTML comments) Any values specified for START_TAG and/or END_TAG will over-ride those defined by a TAG_STYLE. The TAGS directive may also be used to set a TAG_STYLE [% TAGS html %] <!-- INCLUDE header --> =item PRE_CHOMP, POST_CHOMP Anything outside a directive tag is considered plain text and is generally passed through unaltered (but see the INTERPOLATE option). This includes all whitespace and newlines characters surrounding directive tags. Directives that don't generate any output will leave gaps in the output document. Example: Foo [% a = 10 %] Bar Output: Foo Bar The PRE_CHOMP and POST_CHOMP options can help to clean up some of this extraneous whitespace. Both are disabled by default. my $parser = Template::Parser->new({ PRE_CHOMP => 1, POST_CHOMP => 1, }); With PRE_CHOMP set to 1, the newline and whitespace preceding a directive at the start of a line will be deleted. This has the effect of concatenating a line that starts with a directive onto the end of the previous line. Foo <----------. | ,---(PRE_CHOMP)----' | `-- [% a = 10 %] --. | ,---(POST_CHOMP)---' | `-> Bar With POST_CHOMP set to 1, any whitespace after a directive up to and including the newline will be deleted. This has the effect of joining a line that ends with a directive onto the start of the next line. If PRE_CHOMP or POST_CHOMP is set to 2, then instead of removing all the whitespace, the whitespace will be collapsed to a single space. This is useful for HTML, where (usually) a contiguous block of whitespace is rendered the same as a single space. You may use the CHOMP_NONE, CHOMP_ALL, and CHOMP_COLLAPSE constants from the Template::Constants module to deactivate chomping, remove all whitespace, or collapse whitespace to a single space. PRE_CHOMP and POST_CHOMP can be activated for individual directives by placing a '-' immediately at the start and/or end of the directive. [% FOREACH user = userlist %] [%- user -%] [% END %] The '-' characters activate both PRE_CHOMP and POST_CHOMP for the one directive '[%- name -%]'. Thus, the template will be processed as if written: [% FOREACH user = userlist %][% user %][% END %] Note that this is the same as if PRE_CHOMP and POST_CHOMP were set to CHOMP_ALL; the only way to get the CHOMP_COLLAPSE behavior is to set PRE_CHOMP or POST_CHOMP accordingly. If PRE_CHOMP or POST_CHOMP is already set to CHOMP_COLLAPSE, using '-' will give you CHOMP_COLLAPSE behavior, not CHOMP_ALL behavior. Similarly, '+' characters can be used to disable PRE_CHOMP or POST_CHOMP (i.e. leave the whitespace/newline intact) options on a per-directive basis. [% FOREACH user = userlist %] User: [% user +%] [% END %] With POST_CHOMP enabled, the above example would be parsed as if written: [% FOREACH user = userlist %]User: [% user %] [% END %] =item INTERPOLATE The INTERPOLATE flag, when set to any true value will cause variable references in plain text (i.e. not surrounded by START_TAG and END_TAG) to be recognised and interpolated accordingly. my $parser = Template::Parser->new({ INTERPOLATE => 1, }); Variables should be prefixed by a '$' to identify them. Curly braces can be used in the familiar Perl/shell style to explicitly scope the variable name where required. # INTERPOLATE => 0 <a href="http://[% server %]/[% help %]"> <img src="[% images %]/help.gif"></a> [% myorg.name %] # INTERPOLATE => 1 <a href="http://$server/$help"> <img src="$images/help.gif"></a> $myorg.name # explicit scoping with { } <img src="$images/${icon.next}.gif"> Note that a limitation in Perl's regex engine restricts the maximum length of an interpolated template to around 32 kilobytes or possibly less. Files that exceed this limit in size will typically cause Perl to dump core with a segmentation fault. If you routinely process templates of this size then you should disable INTERPOLATE or split the templates in several smaller files or blocks which can then be joined backed together via PROCESS or INCLUDE. =item ANYCASE By default, directive keywords should be expressed in UPPER CASE. The ANYCASE option can be set to allow directive keywords to be specified in any case. # ANYCASE => 0 (default) [% INCLUDE foobar %] # OK [% include foobar %] # ERROR [% include = 10 %] # OK, 'include' is a variable # ANYCASE => 1 [% INCLUDE foobar %] # OK [% include foobar %] # OK [% include = 10 %] # ERROR, 'include' is reserved word One side-effect of enabling ANYCASE is that you cannot use a variable of the same name as a reserved word, regardless of case. The reserved words are currently: GET CALL SET DEFAULT INSERT INCLUDE PROCESS WRAPPER IF UNLESS ELSE ELSIF FOR FOREACH WHILE SWITCH CASE USE PLUGIN FILTER MACRO PERL RAWPERL BLOCK META TRY THROW CATCH FINAL NEXT LAST BREAK RETURN STOP CLEAR TO STEP AND OR NOT MOD DIV END The only lower case reserved words that cannot be used for variables, regardless of the ANYCASE option, are the operators: and or not mod div =item V1DOLLAR In version 1 of the Template Toolkit, an optional leading '$' could be placed on any template variable and would be silently ignored. # VERSION 1 [% $foo %] === [% foo %] [% $hash.$key %] === [% hash.key %] To interpolate a variable value the '${' ... '}' construct was used. Typically, one would do this to index into a hash array when the key value was stored in a variable. example: my $vars = { users => { aba => { name => 'Alan Aardvark', ... }, abw => { name => 'Andy Wardley', ... }, ... }, uid => 'aba', ... }; $template->process('user/home.html', $vars) || die $template->error(), "\n"; 'user/home.html': [% user = users.${uid} %] # users.aba Name: [% user.name %] # Alan Aardvark This was inconsistent with double quoted strings and also the INTERPOLATE mode, where a leading '$' in text was enough to indicate a variable for interpolation, and the additional curly braces were used to delimit variable names where necessary. Note that this use is consistent with UNIX and Perl conventions, among others. # double quoted string interpolation [% name = "$title ${user.name}" %] # INTERPOLATE = 1 <img src="$images/help.gif"></a> <img src="$images/${icon.next}.gif"> For version 2, these inconsistencies have been removed and the syntax clarified. A leading '$' on a variable is now used exclusively to indicate that the variable name should be interpolated (e.g. subsituted for its value) before being used. The earlier example from version 1: # VERSION 1 [% user = users.${uid} %] Name: [% user.name %] can now be simplified in version 2 as: # VERSION 2 [% user = users.$uid %] Name: [% user.name %] The leading dollar is no longer ignored and has the same effect of interpolation as '${' ... '}' in version 1. The curly braces may still be used to explicitly scope the interpolated variable name where necessary. e.g. [% user = users.${me.id} %] Name: [% user.name %] The rule applies for all variables, both within directives and in plain text if processed with the INTERPOLATE option. This means that you should no longer (if you ever did) add a leading '$' to a variable inside a directive, unless you explicitly want it to be interpolated. One obvious side-effect is that any version 1 templates with variables using a leading '$' will no longer be processed as expected. Given the following variable definitions, [% foo = 'bar' bar = 'baz' %] version 1 would interpret the following as: # VERSION 1 [% $foo %] => [% GET foo %] => bar whereas version 2 interprets it as: # VERSION 2 [% $foo %] => [% GET $foo %] => [% GET bar %] => baz In version 1, the '$' is ignored and the value for the variable 'foo' is retrieved and printed. In version 2, the variable '$foo' is first interpolated to give the variable name 'bar' whose value is then retrieved and printed. The use of the optional '$' has never been strongly recommended, but to assist in backwards compatibility with any version 1 templates that may rely on this "feature", the V1DOLLAR option can be set to 1 (default: 0) to revert the behaviour and have leading '$' characters ignored. my $parser = Template::Parser->new({ V1DOLLAR => 1, }); =item GRAMMAR The GRAMMAR configuration item can be used to specify an alternate grammar for the parser. This allows a modified or entirely new template language to be constructed and used by the Template Toolkit. Source templates are compiled to Perl code by the Template::Parser using the Template::Grammar (by default) to define the language structure and semantics. Compiled templates are thus inherently "compatible" with each other and there is nothing to prevent any number of different template languages being compiled and used within the same Template Toolkit processing environment (other than the usual time and memory constraints). The Template::Grammar file is constructed from a YACC like grammar (using Parse::YAPP) and a skeleton module template. These files are provided, along with a small script to rebuild the grammar, in the 'parser' sub-directory of the distribution. You don't have to know or worry about these unless you want to hack on the template language or define your own variant. There is a README file in the same directory which provides some small guidance but it is assumed that you know what you're doing if you venture herein. If you grok LALR parsers, then you should find it comfortably familiar. By default, an instance of the default Template::Grammar will be created and used automatically if a GRAMMAR item isn't specified. use MyOrg::Template::Grammar; my $parser = Template::Parser->new({ GRAMMAR = MyOrg::Template::Grammar->new(); }); =item DEBUG The DEBUG option can be used to enable various debugging features of the Template::Parser module. use Template::Constants qw( :debug ); my $template = Template->new({ DEBUG => DEBUG_PARSER | DEBUG_DIRS, }); The DEBUG value can include any of the following. Multiple values should be combined using the logical OR operator, '|'. =over 4 =item DEBUG_PARSER This flag causes the L<Template::Parser|Template::Parser> to generate debugging messages that show the Perl code generated by parsing and compiling each template. =item DEBUG_DIRS This option causes the Template Toolkit to generate comments indicating the source file, line and original text of each directive in the template. These comments are embedded in the template output using the format defined in the DEBUG_FORMAT configuration item, or a simple default format if unspecified. For example, the following template fragment: Hello World would generate this output: ## input text line 1 : ## Hello ## input text line 2 : World ## World =back =back =head2 parse($text) The parse() method parses the text passed in the first parameter and returns a reference to a Template::Document object which contains the compiled representation of the template text. On error, undef is returned. Example: $doc = $parser->parse($text) || die $parser->error(); =head1 AUTHOR Andy Wardley E<lt>abw@andywardley.comE<gt> L<http://www.andywardley.com/|http://www.andywardley.com/> =head1 VERSION 2.75, distributed as part of the Template Toolkit version 2.10, released on 24 July 2003. =head1 COPYRIGHT Copyright (C) 1996-2003 Andy Wardley. All Rights Reserved. Copyright (C) 1998-2002 Canon Research Centre Europe Ltd. This module is free software; you can redistribute it and/or modify it under the same terms as Perl itself. The original Template::Parser module was derived from a standalone parser generated by version 0.16 of the Parse::Yapp module. The following copyright notice appears in the Parse::Yapp documentation. The Parse::Yapp module and its related modules and shell scripts are copyright (c) 1998 Francois Desarmenien, France. All rights reserved. You may use and distribute them under the terms of either the GNU General Public License or the Artistic License, as specified in the Perl README file. =head1 SEE ALSO L<Template|Template>, L<Template::Grammar|Template::Grammar>, L<Template::Directive|Template::Directive> ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������vdradmin-am-3.6.13/lib/Template/Plugin.pm�����������������������������������������������������������0000664�0000000�0000000�00000026130�14437161134�0020126�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#============================================================= -*-Perl-*- # # Template::Plugin # # DESCRIPTION # # Module defining a base class for a plugin object which can be loaded # and instantiated via the USE directive. # # AUTHOR # Andy Wardley <abw@kfs.org> # # COPYRIGHT # Copyright (C) 1996-2000 Andy Wardley. All Rights Reserved. # Copyright (C) 1998-2000 Canon Research Centre Europe Ltd. # # This module is free software; you can redistribute it and/or # modify it under the same terms as Perl itself. # #---------------------------------------------------------------------------- # # $Id: Plugin.pm,v 2.60 2003/04/24 09:14:38 abw Exp $ # #============================================================================ package Template::Plugin; require 5.004; use strict; use Template::Base; use vars qw( $VERSION $DEBUG $ERROR $AUTOLOAD ); use base qw( Template::Base ); $VERSION = sprintf("%d.%02d", q$Revision: 2.60 $ =~ /(\d+)\.(\d+)/); $DEBUG = 0; #======================================================================== # ----- CLASS METHODS ----- #======================================================================== #------------------------------------------------------------------------ # load() # # Class method called when the plugin module is first loaded. It # returns the name of a class (by default, its own class) or a prototype # object which will be used to instantiate new objects. The new() # method is then called against the class name (class method) or # prototype object (object method) to create a new instances of the # object. #------------------------------------------------------------------------ sub load { return $_[0]; } #------------------------------------------------------------------------ # new($context, $delegate, @params) # # Object constructor which is called by the Template::Context to # instantiate a new Plugin object. This base class constructor is # used as a general mechanism to load and delegate to other Perl # modules. The context is passed as the first parameter, followed by # a reference to a delegate object or the name of the module which # should be loaded and instantiated. Any additional parameters passed # to the USE directive are forwarded to the new() constructor. # # A plugin object is returned which has an AUTOLOAD method to delegate # requests to the underlying object. #------------------------------------------------------------------------ sub new { my $class = shift; bless { }, $class; } sub old_new { my ($class, $context, $delclass, @params) = @_; my ($delegate, $delmod); return $class->error("no context passed to $class constructor\n") unless defined $context; if (ref $delclass) { # $delclass contains a reference to a delegate object $delegate = $delclass; } else { # delclass is the name of a module to load and instantiate ($delmod = $delclass) =~ s|::|/|g; eval { require "$delmod.pm"; $delegate = $delclass->new(@params) || die "failed to instantiate $delclass object\n"; }; return $class->error($@) if $@; } bless { _CONTEXT => $context, _DELEGATE => $delegate, _PARAMS => \@params, }, $class; } #------------------------------------------------------------------------ # fail($error) # # Version 1 error reporting function, now replaced by error() inherited # from Template::Base. Raises a "deprecated function" warning and then # calls error(). #------------------------------------------------------------------------ sub fail { my $class = shift; my ($pkg, $file, $line) = caller(); warn "Template::Plugin::fail() is deprecated at $file line $line. Please use error()\n"; $class->error(@_); } #======================================================================== # ----- OBJECT METHODS ----- #======================================================================== #------------------------------------------------------------------------ # AUTOLOAD # # General catch-all method which delegates all calls to the _DELEGATE # object. #------------------------------------------------------------------------ sub OLD_AUTOLOAD { my $self = shift; my $method = $AUTOLOAD; $method =~ s/.*:://; return if $method eq 'DESTROY'; if (ref $self eq 'HASH') { my $delegate = $self->{ _DELEGATE } || return; return $delegate->$method(@_); } my ($pkg, $file, $line) = caller(); # warn "no such '$method' method called on $self at $file line $line\n"; return undef; } 1; __END__ #------------------------------------------------------------------------ # IMPORTANT NOTE # This documentation is generated automatically from source # templates. Any changes you make here may be lost. # # The 'docsrc' documentation source bundle is available for download # from http://www.template-toolkit.org/docs.html and contains all # the source templates, XML files, scripts, etc., from which the # documentation for the Template Toolkit is built. #------------------------------------------------------------------------ =head1 NAME Template::Plugin - Base class for Template Toolkit plugins =head1 SYNOPSIS package MyOrg::Template::Plugin::MyPlugin; use base qw( Template::Plugin ); use Template::Plugin; use MyModule; sub new { my $class = shift; my $context = shift; bless { ... }, $class; } =head1 DESCRIPTION A "plugin" for the Template Toolkit is simply a Perl module which exists in a known package location (e.g. Template::Plugin::*) and conforms to a regular standard, allowing it to be loaded and used automatically. The Template::Plugin module defines a base class from which other plugin modules can be derived. A plugin does not have to be derived from Template::Plugin but should at least conform to its object-oriented interface. It is recommended that you create plugins in your own package namespace to avoid conflict with toolkit plugins. e.g. package MyOrg::Template::Plugin::FooBar; Use the PLUGIN_BASE option to specify the namespace that you use. e.g. use Template; my $template = Template->new({ PLUGIN_BASE => 'MyOrg::Template::Plugin', }); =head1 PLUGIN API The following methods form the basic interface between the Template Toolkit and plugin modules. =over 4 =item load($context) This method is called by the Template Toolkit when the plugin module is first loaded. It is called as a package method and thus implicitly receives the package name as the first parameter. A reference to the Template::Context object loading the plugin is also passed. The default behaviour for the load() method is to simply return the class name. The calling context then uses this class name to call the new() package method. package MyPlugin; sub load { # called as MyPlugin->load($context) my ($class, $context) = @_; return $class; # returns 'MyPlugin' } =item new($context, @params) This method is called to instantiate a new plugin object for the USE directive. It is called as a package method against the class name returned by load(). A reference to the Template::Context object creating the plugin is passed, along with any additional parameters specified in the USE directive. sub new { # called as MyPlugin->new($context) my ($class, $context, @params) = @_; bless { _CONTEXT => $context, }, $class; # returns blessed MyPlugin object } =item error($error) This method, inherited from the Template::Base module, is used for reporting and returning errors. It can be called as a package method to set/return the $ERROR package variable, or as an object method to set/return the object _ERROR member. When called with an argument, it sets the relevant variable and returns undef. When called without an argument, it returns the value of the variable. sub new { my ($class, $context, $dsn) = @_; return $class->error('No data source specified') unless $dsn; bless { _DSN => $dsn, }, $class; } ... my $something = MyModule->new() || die MyModule->error(), "\n"; $something->do_something() || die $something->error(), "\n"; =back =head1 DEEPER MAGIC The Template::Context object that handles the loading and use of plugins calls the new() and error() methods against the package name returned by the load() method. In pseudo-code terms, it might look something like this: $class = MyPlugin->load($context); # returns 'MyPlugin' $object = $class->new($context, @params) # MyPlugin->new(...) || die $class->error(); # MyPlugin->error() The load() method may alterately return a blessed reference to an object instance. In this case, new() and error() are then called as I<object> methods against that prototype instance. package YourPlugin; sub load { my ($class, $context) = @_; bless { _CONTEXT => $context, }, $class; } sub new { my ($self, $context, @params) = @_; return $self; } In this example, we have implemented a 'Singleton' plugin. One object gets created when load() is called and this simply returns itself for each call to new(). Another implementation might require individual objects to be created for every call to new(), but with each object sharing a reference to some other object to maintain cached data, database handles, etc. This pseudo-code example demonstrates the principle. package MyServer; sub load { my ($class, $context) = @_; bless { _CONTEXT => $context, _CACHE => { }, }, $class; } sub new { my ($self, $context, @params) = @_; MyClient->new($self, @params); } sub add_to_cache { ... } sub get_from_cache { ... } package MyClient; sub new { my ($class, $server, $blah) = @_; bless { _SERVER => $server, _BLAH => $blah, }, $class; } sub get { my $self = shift; $self->{ _SERVER }->get_from_cache(@_); } sub put { my $self = shift; $self->{ _SERVER }->add_to_cache(@_); } When the plugin is loaded, a MyServer instance is created. The new() method is called against this object which instantiates and returns a MyClient object, primed to communicate with the creating MyServer. =head1 Template::Plugin Delegation As of version 2.01, the Template::Plugin module no longer provides an AUTOLOAD method to delegate to other objects or classes. This was a badly designed feature that caused more trouble than good. You can easily add your own AUTOLOAD method to perform delegation if you require this kind of functionality. =head1 AUTHOR Andy Wardley E<lt>abw@andywardley.comE<gt> L<http://www.andywardley.com/|http://www.andywardley.com/> =head1 VERSION 2.60, distributed as part of the Template Toolkit version 2.10, released on 24 July 2003. =head1 COPYRIGHT Copyright (C) 1996-2003 Andy Wardley. All Rights Reserved. Copyright (C) 1998-2002 Canon Research Centre Europe Ltd. This module is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =head1 SEE ALSO L<Template|Template>, L<Template::Plugins|Template::Plugins>, L<Template::Context|Template::Context> ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������vdradmin-am-3.6.13/lib/Template/Plugin/�������������������������������������������������������������0000775�0000000�0000000�00000000000�14437161134�0017566�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������vdradmin-am-3.6.13/lib/Template/Plugin/Date.pm������������������������������������������������������0000664�0000000�0000000�00000024764�14437161134�0021016�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#============================================================= -*-Perl-*- # # Template::Plugin::Date # # DESCRIPTION # # Plugin to generate formatted date strings. # # AUTHORS # Thierry-Michel Barral <kktos@electron-libre.com> # Andy Wardley <abw@cre.canon.co.uk> # # COPYRIGHT # Copyright (C) 2000 Thierry-Michel Barral, Andy Wardley. # # This module is free software; you can redistribute it and/or # modify it under the same terms as Perl itself. # #---------------------------------------------------------------------------- # # $Id: Date.pm,v 2.66 2003/04/24 09:14:43 abw Exp $ # #============================================================================ package Template::Plugin::Date; use strict; use vars qw( $VERSION $FORMAT @LOCALE_SUFFIX ); use base qw( Template::Plugin ); use Template::Plugin; use POSIX (); $VERSION = sprintf("%d.%02d", q$Revision: 2.66 $ =~ /(\d+)\.(\d+)/); $FORMAT = '%H:%M:%S %d-%b-%Y'; # default strftime() format @LOCALE_SUFFIX = qw( .ISO8859-1 .ISO_8859-15 .US-ASCII .UTF-8 ); #------------------------------------------------------------------------ # new(\%options) #------------------------------------------------------------------------ sub new { my ($class, $context, $params) = @_; bless { $params ? %$params : () }, $class; } #------------------------------------------------------------------------ # now() # # Call time() to return the current system time in seconds since the epoch. #------------------------------------------------------------------------ sub now { return time(); } #------------------------------------------------------------------------ # format() # format($time) # format($time, $format) # format($time, $format, $locale) # format($time, $format, $locale, $gmt_flag) # format(\%named_params); # # Returns a formatted time/date string for the specified time, $time, # (or the current system time if unspecified) using the $format, $locale, # and $gmt values specified as arguments or internal values set defined # at construction time). Specifying a Perl-true value for $gmt will # override the local time zone and force the output to be for GMT. # Any or all of the arguments may be specified as named parameters which # get passed as a hash array reference as the final argument. # ------------------------------------------------------------------------ sub format { my $self = shift; my $params = ref($_[$#_]) eq 'HASH' ? pop(@_) : { }; my $time = shift(@_) || $params->{ time } || $self->{ time } || $self->now(); my $format = @_ ? shift(@_) : ($params->{ format } || $self->{ format } || $FORMAT); my $locale = @_ ? shift(@_) : ($params->{ locale } || $self->{ locale }); my $gmt = @_ ? shift(@_) : ($params->{ gmt } || $self->{ gmt }); my (@date, $datestr); if ($time =~ /^\d+$/) { # $time is now in seconds since epoch if ($gmt) { @date = (gmtime($time))[0..6]; } else { @date = (localtime($time))[0..6]; } } else { # if $time is numeric, then we assume it's seconds since the epoch # otherwise, we try to parse it as a 'H:M:S D:M:Y' string @date = (split(/(?:\/| |:|-)/, $time))[2,1,0,3..5]; return (undef, Template::Exception->new('date', "bad time/date string: expects 'h:m:s d:m:y' got: '$time'")) unless @date >= 6 && defined $date[5]; $date[4] -= 1; # correct month number 1-12 to range 0-11 $date[5] -= 1900; # convert absolute year to years since 1900 $time = &POSIX::mktime(@date); } if ($locale) { # format the date in a specific locale, saving and subsequently # restoring the current locale. my $old_locale = &POSIX::setlocale(&POSIX::LC_ALL); # some systems expect locales to have a particular suffix for my $suffix ('', @LOCALE_SUFFIX) { my $try_locale = $locale.$suffix; my $setlocale = &POSIX::setlocale(&POSIX::LC_ALL, $try_locale); if (defined $setlocale && $try_locale eq $setlocale) { $locale = $try_locale; last; } } $datestr = &POSIX::strftime($format, @date); &POSIX::setlocale(&POSIX::LC_ALL, $old_locale); } else { $datestr = &POSIX::strftime($format, @date); } return $datestr; } sub calc { my $self = shift; eval { require "Date/Calc.pm" }; $self->throw("failed to load Date::Calc: $@") if $@; return Template::Plugin::Date::Calc->new('no context'); } sub manip { my $self = shift; eval { require "Date/Manip.pm" }; $self->throw("failed to load Date::Manip: $@") if $@; return Template::Plugin::Date::Manip->new('no context'); } sub throw { my $self = shift; die (Template::Exception->new('date', join(', ', @_))); } package Template::Plugin::Date::Calc; use base qw( Template::Plugin ); use vars qw( $AUTOLOAD ); *throw = \&Template::Plugin::Date::throw; sub AUTOLOAD { my $self = shift; my $method = $AUTOLOAD; $method =~ s/.*:://; return if $method eq 'DESTROY'; my $sub = \&{"Date::Calc::$method"}; $self->throw("no such Date::Calc method: $method") unless $sub; &$sub(@_); } package Template::Plugin::Date::Manip; use base qw( Template::Plugin ); use vars qw( $AUTOLOAD ); *throw = \&Template::Plugin::Date::throw; sub AUTOLOAD { my $self = shift; my $method = $AUTOLOAD; $method =~ s/.*:://; return if $method eq 'DESTROY'; my $sub = \&{"Date::Manip::$method"}; $self->throw("no such Date::Manip method: $method") unless $sub; &$sub(@_); } 1; __END__ #------------------------------------------------------------------------ # IMPORTANT NOTE # This documentation is generated automatically from source # templates. Any changes you make here may be lost. # # The 'docsrc' documentation source bundle is available for download # from http://www.template-toolkit.org/docs.html and contains all # the source templates, XML files, scripts, etc., from which the # documentation for the Template Toolkit is built. #------------------------------------------------------------------------ =head1 NAME Template::Plugin::Date - Plugin to generate formatted date strings =head1 SYNOPSIS [% USE date %] # use current time and default format [% date.format %] # specify time as seconds since epoch or 'h:m:s d-m-y' string [% date.format(960973980) %] [% date.format('4:20:36 21/12/2000') %] # specify format [% date.format(mytime, '%H:%M:%S') %] # specify locale [% date.format(date.now, '%a %d %b %y', 'en_GB') %] # named parameters [% date.format(mytime, format = '%H:%M:%S') %] [% date.format(locale = 'en_GB') %] [% date.format(time = date.now, format = '%H:%M:%S', locale = 'en_GB) %] # specify default format to plugin [% USE date(format = '%H:%M:%S', locale = 'de_DE') %] [% date.format %] ... =head1 DESCRIPTION The Date plugin provides an easy way to generate formatted time and date strings by delegating to the POSIX strftime() routine. The plugin can be loaded via the familiar USE directive. [% USE date %] This creates a plugin object with the default name of 'date'. An alternate name can be specified as such: [% USE myname = date %] The plugin provides the format() method which accepts a time value, a format string and a locale name. All of these parameters are optional with the current system time, default format ('%H:%M:%S %d-%b-%Y') and current locale being used respectively, if undefined. Default values for the time, format and/or locale may be specified as named parameters in the USE directive. [% USE date(format = '%a %d-%b-%Y', locale = 'fr_FR') %] When called without any parameters, the format() method returns a string representing the current system time, formatted by strftime() according to the default format and for the default locale (which may not be the current one, if locale is set in the USE directive). [% date.format %] The plugin allows a time/date to be specified as seconds since the epoch, as is returned by time(). File last modified: [% date.format(filemod_time) %] The time/date can also be specified as a string of the form 'h:m:s d/m/y'. Any of the characters : / - or space may be used to delimit fields. [% USE day = date(format => '%A', locale => 'en_GB') %] [% day.format('4:20:00 9-13-2000') %] Output: Tuesday A format string can also be passed to the format() method, and a locale specification may follow that. [% date.format(filemod, '%d-%b-%Y') %] [% date.format(filemod, '%d-%b-%Y', 'en_GB') %] A fourth parameter allows you to force output in GMT, in the case of seconds-since-the-epoch input: [% date.format(filemod, '%d-%b-%Y', 'en_GB', 1) %] Note that in this case, if the local time is not GMT, then also specifying '%Z' (time zone) in the format parameter will lead to an extremely misleading result. Any or all of these parameters may be named. Positional parameters should always be in the order ($time, $format, $locale). [% date.format(format => '%H:%M:%S') %] [% date.format(time => filemod, format => '%H:%M:%S') %] [% date.format(mytime, format => '%H:%M:%S') %] [% date.format(mytime, format => '%H:%M:%S', locale => 'fr_FR') %] [% date.format(mytime, format => '%H:%M:%S', gmt => 1) %] ...etc... The now() method returns the current system time in seconds since the epoch. [% date.format(date.now, '%A') %] The calc() method can be used to create an interface to the Date::Calc module (if installed on your system). [% calc = date.calc %] [% calc.Monday_of_Week(22, 2001).join('/') %] The manip() method can be used to create an interface to the Date::Manip module (if installed on your system). [% manip = date.manip %] [% manip.UnixDate("Noon Yesterday","%Y %b %d %H:%M") %] =head1 AUTHORS Thierry-Michel Barral E<lt>kktos@electron-libre.comE<gt> wrote the original plugin. Andy Wardley E<lt>abw@cre.canon.co.ukE<gt> provided some minor fixups/enhancements, a test script and documentation. Mark D. Mills E<lt>mark@hostile.orgE<gt> cloned Date::Manip from the cute Date::Calc sub-plugin. =head1 VERSION 2.66, distributed as part of the Template Toolkit version 2.10, released on 24 July 2003. =head1 COPYRIGHT Copyright (C) 2000 Thierry-Michel Barral, Andy Wardley. This module is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =head1 SEE ALSO L<Template::Plugin|Template::Plugin>, L<POSIX|POSIX> ������������vdradmin-am-3.6.13/lib/Template/Plugin/HTML.pm������������������������������������������������������0000664�0000000�0000000�00000011754�14437161134�0020700�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#============================================================= -*-Perl-*- # # Template::Plugin::HTML # # DESCRIPTION # # Template Toolkit plugin providing useful functionality for generating # HTML. # # AUTHOR # Andy Wardley <abw@kfs.org> # # COPYRIGHT # Copyright (C) 1996-2001 Andy Wardley. All Rights Reserved. # Copyright (C) 1998-2001 Canon Research Centre Europe Ltd. # # This module is free software; you can redistribute it and/or # modify it under the same terms as Perl itself. # #---------------------------------------------------------------------------- # # $Id: HTML.pm,v 1.1 2006/10/27 10:00:31 amair Exp $ # #============================================================================ package Template::Plugin::HTML; require 5.004; use strict; use vars qw( $VERSION ); use base qw( Template::Plugin ); use Template::Plugin; $VERSION = sprintf("%d.%02d", q$Revision: 1.1 $ =~ /(\d+)\.(\d+)/); sub new { my ($class, $context, @args) = @_; my $hash = ref $args[-1] eq 'HASH' ? pop @args : { }; bless { _SORTED => $hash->{ sorted } || 0, }, $class; } sub element { my ($self, $name, $attr) = @_; ($name, $attr) = %$name if ref $name eq 'HASH'; return '' unless defined $name and length $name; $attr = $self->attributes($attr); $attr = " $attr" if $attr; return "<$name$attr>"; } sub attributes { my ($self, $hash) = @_; return '' unless UNIVERSAL::isa($hash, 'HASH'); my @keys = keys %$hash; @keys = sort @keys if $self->{ _SORTED }; join(' ', map { "$_=\"" . $self->escape( $hash->{ $_ } ) . '"'; } @keys); } sub escape { my ($self, $text) = @_; for ($text) { s/&/&/g; s/</</g; s/>/>/g; s/"/"/g; } $text; } sub url { my ($self, $text) = @_; return undef unless defined $text; $text =~ s/([^a-zA-Z0-9_.-])/uc sprintf("%%%02x",ord($1))/eg; return $text; } 1; __END__ #------------------------------------------------------------------------ # IMPORTANT NOTE # This documentation is generated automatically from source # templates. Any changes you make here may be lost. # # The 'docsrc' documentation source bundle is available for download # from http://www.template-toolkit.org/docs.html and contains all # the source templates, XML files, scripts, etc., from which the # documentation for the Template Toolkit is built. #------------------------------------------------------------------------ =head1 NAME Template::Plugin::HTML - Plugin to create HTML elements =head1 SYNOPSIS [% USE HTML %] [% HTML.escape("if (a < b && c > d) ..." %] [% HTML.element(table => { border => 1, cellpadding => 2 }) %] [% HTML.attributes(border => 1, cellpadding => 2) %] =head1 DESCRIPTION The HTML plugin is very new and very basic, implementing a few useful methods for generating HTML. It is likely to be extended in the future or integrated with a larger project to generate HTML elements in a generic way (as discussed recently on the mod_perl mailing list). =head1 METHODS =head2 escape(text) Returns the source text with any HTML reserved characters such as E<lt>, E<gt>, etc., correctly esacped to their entity equivalents. =head2 attributes(hash) Returns the elements of the hash array passed by reference correctly formatted (e.g. values quoted and correctly escaped) as attributes for an HTML element. =head2 element(type, attributes) Generates an HTML element of the specified type and with the attributes provided as an optional hash array reference as the second argument or as named arguments. [% HTML.element(table => { border => 1, cellpadding => 2 }) %] [% HTML.element('table', border=1, cellpadding=2) %] [% HTML.element(table => attribs) %] =head1 DEBUGGING The HTML plugin accepts a 'sorted' option as a constructor argument which, when set to any true value, causes the attributes generated by the attributes() method (either directly or via element()) to be returned in sorted order. Order of attributes isn't important in HTML, but this is provided mainly for the purposes of debugging where it is useful to have attributes generated in a deterministic order rather than whatever order the hash happened to feel like returning the keys in. [% USE HTML(sorted=1) %] [% HTML.element( foo => { charlie => 1, bravo => 2, alpha => 3 } ) %] generates: <foo alpha="3" bravo="2" charlie="1"> =head1 AUTHOR Andy Wardley E<lt>abw@andywardley.comE<gt> L<http://www.andywardley.com/|http://www.andywardley.com/> =head1 VERSION 2.57, distributed as part of the Template Toolkit version 2.14, released on 04 October 2004. =head1 COPYRIGHT Copyright (C) 1996-2004 Andy Wardley. All Rights Reserved. Copyright (C) 1998-2002 Canon Research Centre Europe Ltd. This module is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =head1 SEE ALSO L<Template::Plugin|Template::Plugin> =cut # Local Variables: # mode: perl # perl-indent-level: 4 # indent-tabs-mode: nil # End: # # vim: expandtab shiftwidth=4: ��������������������vdradmin-am-3.6.13/lib/Template/Plugin/JavaScript.pm������������������������������������������������0000664�0000000�0000000�00000002523�14437161134�0022174�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������package Template::Plugin::JavaScript; use strict; use vars qw($VERSION); $VERSION = '0.01'; require Template::Plugin; use base qw(Template::Plugin); use vars qw($FILTER_NAME); $FILTER_NAME = 'js'; sub new { my($self, $context, @args) = @_; my $name = $args[0] || $FILTER_NAME; $context->define_filter($name, \&encode_js, 0); return $self; } sub encode_js { local $_ = shift; return '' unless defined $_; s!(['"])!\\$1!g; s!\n!\\n!g; s!\f!\\f!g; s!\r!\\r!g; s!\t!\\t!g; $_; } 1; __END__ =head1 NAME Template::Plugin::JavaScript - Encodes text to be safe in JavaScript =head1 SYNOPSIS [% USE JavaScript %] <script type="text/javascript"> document.write("[% sometext | js %]"); </script> =head1 DESCRIPTION Template::Plugin::JavaScript is a TT filter that filters text so it can be safely used in JavaScript quotes. [% USE JavaScript %] document.write("[% FILTER js %] Here's some text going on. [% END %]"); will become: document.write("\nHere\'s some text going on.\n"); =head1 AUTHOR The original idea comes from Movable Type's C<encode_js> global filter. Tatsuhiko Miyagawa E<lt>miyagawa@bulknews.netE<gt> This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =head1 SEE ALSO L<Apache::JavaScript::DocumentWrite> =cut �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������vdradmin-am-3.6.13/lib/Template/Plugins.pm����������������������������������������������������������0000664�0000000�0000000�00000075411�14437161134�0020317�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#============================================================= -*-Perl-*- # # Template::Plugins # # DESCRIPTION # Plugin provider which handles the loading of plugin modules and # instantiation of plugin objects. # # AUTHORS # Andy Wardley <abw@kfs.org> # # COPYRIGHT # Copyright (C) 1996-2000 Andy Wardley. All Rights Reserved. # Copyright (C) 1998-2000 Canon Research Centre Europe Ltd. # # This module is free software; you can redistribute it and/or # modify it under the same terms as Perl itself. # #---------------------------------------------------------------------------- # # $Id: Plugins.pm,v 2.65 2003/04/24 09:14:38 abw Exp $ # #============================================================================ package Template::Plugins; require 5.004; use strict; use base qw( Template::Base ); use vars qw( $VERSION $DEBUG $STD_PLUGINS ); use Template::Constants; $VERSION = sprintf("%d.%02d", q$Revision: 2.65 $ =~ /(\d+)\.(\d+)/); $STD_PLUGINS = { 'autoformat' => 'Template::Plugin::Autoformat', 'cgi' => 'Template::Plugin::CGI', 'datafile' => 'Template::Plugin::Datafile', 'date' => 'Template::Plugin::Date', 'debug' => 'Template::Plugin::Debug', 'directory' => 'Template::Plugin::Directory', 'dbi' => 'Template::Plugin::DBI', 'dumper' => 'Template::Plugin::Dumper', 'file' => 'Template::Plugin::File', 'format' => 'Template::Plugin::Format', 'html' => 'Template::Plugin::HTML', 'image' => 'Template::Plugin::Image', 'iterator' => 'Template::Plugin::Iterator', 'pod' => 'Template::Plugin::Pod', 'table' => 'Template::Plugin::Table', 'url' => 'Template::Plugin::URL', 'view' => 'Template::Plugin::View', 'wrap' => 'Template::Plugin::Wrap', 'xmlstyle' => 'Template::Plugin::XML::Style', }; #======================================================================== # -- PUBLIC METHODS -- #======================================================================== #------------------------------------------------------------------------ # fetch($name, \@args, $context) # # General purpose method for requesting instantiation of a plugin # object. The name of the plugin is passed as the first parameter. # The internal FACTORY lookup table is consulted to retrieve the # appropriate factory object or class name. If undefined, the _load() # method is called to attempt to load the module and return a factory # class/object which is then cached for subsequent use. A reference # to the calling context should be passed as the third parameter. # This is passed to the _load() class method. The new() method is # then called against the factory class name or prototype object to # instantiate a new plugin object, passing any arguments specified by # list reference as the second parameter. e.g. where $factory is the # class name 'MyClass', the new() method is called as a class method, # $factory->new(...), equivalent to MyClass->new(...) . Where # $factory is a prototype object, the new() method is called as an # object method, $myobject->new(...). This latter approach allows # plugins to act as Singletons, cache shared data, etc. # # Returns a reference to a plugin, (undef, STATUS_DECLINE) to decline # the request or ($error, STATUS_ERROR) on error. #------------------------------------------------------------------------ sub fetch { my ($self, $name, $args, $context) = @_; my ($factory, $plugin, $error); $self->debug("fetch($name, ", defined $args ? ('[ ', join(', ', @$args), ' ]') : '<no args>', ', ', defined $context ? $context : '<no context>', ')') if $self->{ DEBUG }; # NOTE: # the $context ref gets passed as the first parameter to all regular # plugins, but not to those loaded via LOAD_PERL; to hack around # this until we have a better implementation, we pass the $args # reference to _load() and let it unshift the first args in the # LOAD_PERL case $args ||= [ ]; unshift @$args, $context; $factory = $self->{ FACTORY }->{ $name } ||= do { ($factory, $error) = $self->_load($name, $context); return ($factory, $error) if $error; ## RETURN $factory; }; # call the new() method on the factory object or class name eval { if (ref $factory eq 'CODE') { defined( $plugin = &$factory(@$args) ) || die "$name plugin failed\n"; } else { defined( $plugin = $factory->new(@$args) ) || die "$name plugin failed: ", $factory->error(), "\n"; } }; if ($error = $@) { # chomp $error; return $self->{ TOLERANT } ? (undef, Template::Constants::STATUS_DECLINED) : ($error, Template::Constants::STATUS_ERROR); } return $plugin; } #======================================================================== # -- PRIVATE METHODS -- #======================================================================== #------------------------------------------------------------------------ # _init(\%config) # # Private initialisation method. #------------------------------------------------------------------------ sub _init { my ($self, $params) = @_; my ($pbase, $plugins, $factory) = @$params{ qw( PLUGIN_BASE PLUGINS PLUGIN_FACTORY ) }; $plugins ||= { }; if (ref $pbase ne 'ARRAY') { $pbase = $pbase ? [ $pbase ] : [ ]; } push(@$pbase, 'Template::Plugin'); $self->{ PLUGIN_BASE } = $pbase; $self->{ PLUGINS } = { %$STD_PLUGINS, %$plugins }; $self->{ TOLERANT } = $params->{ TOLERANT } || 0; $self->{ LOAD_PERL } = $params->{ LOAD_PERL } || 0; $self->{ FACTORY } = $factory || { }; $self->{ DEBUG } = ( $params->{ DEBUG } || 0 ) & Template::Constants::DEBUG_PLUGINS; return $self; } #------------------------------------------------------------------------ # _load($name, $context) # # Private method which attempts to load a plugin module and determine the # correct factory name or object by calling the load() class method in # the loaded module. #------------------------------------------------------------------------ sub _load { my ($self, $name, $context) = @_; my ($factory, $module, $base, $pkg, $file, $ok, $error); if ($module = $self->{ PLUGINS }->{ $name }) { # plugin module name is explicitly stated in PLUGIN_NAME $pkg = $module; ($file = $module) =~ s|::|/|g; $file =~ s|::|/|g; $self->debug("loading $module.pm (PLUGIN_NAME)") if $self->{ DEBUG }; $ok = eval { require "$file.pm" }; $error = $@; } else { # try each of the PLUGIN_BASE values to build module name ($module = $name) =~ s/\./::/g; foreach $base (@{ $self->{ PLUGIN_BASE } }) { $pkg = $base . '::' . $module; ($file = $pkg) =~ s|::|/|g; $self->debug("loading $file.pm (PLUGIN_BASE)") if $self->{ DEBUG }; $ok = eval { require "$file.pm" }; last unless $@; $error .= "$@\n" unless ($@ =~ /^Can\'t locate $file\.pm/); } } if ($ok) { $self->debug("calling $pkg->load()") if $self->{ DEBUG }; $factory = eval { $pkg->load($context) }; $error = ''; if ($@ || ! $factory) { $error = $@ || 'load() returned a false value'; } } elsif ($self->{ LOAD_PERL }) { # fallback - is it a regular Perl module? ($file = $module) =~ s|::|/|g; eval { require "$file.pm" }; if ($@) { $error = $@; } else { # this is a regular Perl module so the new() constructor # isn't expecting a $context reference as the first argument; # so we construct a closure which removes it before calling # $module->new(@_); $factory = sub { shift; $module->new(@_); }; $error = ''; } } if ($factory) { $self->debug("$name => $factory") if $self->{ DEBUG }; return $factory; } elsif ($error) { return $self->{ TOLERANT } ? (undef, Template::Constants::STATUS_DECLINED) : ($error, Template::Constants::STATUS_ERROR); } else { return (undef, Template::Constants::STATUS_DECLINED); } } #------------------------------------------------------------------------ # _dump() # # Debug method which constructs and returns text representing the current # state of the object. #------------------------------------------------------------------------ sub _dump { my $self = shift; my $output = "[Template::Plugins] {\n"; my $format = " %-16s => %s\n"; my $key; foreach $key (qw( TOLERANT LOAD_PERL )) { $output .= sprintf($format, $key, $self->{ $key }); } local $" = ', '; my $fkeys = join(", ", keys %{$self->{ FACTORY }}); my $plugins = $self->{ PLUGINS }; $plugins = join('', map { sprintf(" $format", $_, $plugins->{ $_ }); } keys %$plugins); $plugins = "{\n$plugins }"; $output .= sprintf($format, 'PLUGIN_BASE', "[ @{ $self->{ PLUGIN_BASE } } ]"); $output .= sprintf($format, 'PLUGINS', $plugins); $output .= sprintf($format, 'FACTORY', $fkeys); $output .= '}'; return $output; } 1; __END__ #------------------------------------------------------------------------ # IMPORTANT NOTE # This documentation is generated automatically from source # templates. Any changes you make here may be lost. # # The 'docsrc' documentation source bundle is available for download # from http://www.template-toolkit.org/docs.html and contains all # the source templates, XML files, scripts, etc., from which the # documentation for the Template Toolkit is built. #------------------------------------------------------------------------ =head1 NAME Template::Plugins - Plugin provider module =head1 SYNOPSIS use Template::Plugins; $plugin_provider = Template::Plugins->new(\%options); ($plugin, $error) = $plugin_provider->fetch($name, @args); =head1 DESCRIPTION The Template::Plugins module defines a provider class which can be used to load and instantiate Template Toolkit plugin modules. =head1 METHODS =head2 new(\%params) Constructor method which instantiates and returns a reference to a Template::Plugins object. A reference to a hash array of configuration items may be passed as a parameter. These are described below. Note that the Template.pm front-end module creates a Template::Plugins provider, passing all configuration items. Thus, the examples shown below in the form: $plugprov = Template::Plugins->new({ PLUGIN_BASE => 'MyTemplate::Plugin', LOAD_PERL => 1, ... }); can also be used via the Template module as: $ttengine = Template->new({ PLUGIN_BASE => 'MyTemplate::Plugin', LOAD_PERL => 1, ... }); as well as the more explicit form of: $plugprov = Template::Plugins->new({ PLUGIN_BASE => 'MyTemplate::Plugin', LOAD_PERL => 1, ... }); $ttengine = Template->new({ LOAD_PLUGINS => [ $plugprov ], }); =head2 fetch($name, @args) Called to request that a plugin of a given name be provided. The relevant module is first loaded (if necessary) and the load() class method called to return the factory class name (usually the same package name) or a factory object (a prototype). The new() method is then called as a class or object method against the factory, passing all remaining parameters. Returns a reference to a new plugin object or ($error, STATUS_ERROR) on error. May also return (undef, STATUS_DECLINED) to decline to serve the request. If TOLERANT is set then all errors will be returned as declines. =head1 CONFIGURATION OPTIONS The following list details the configuration options that can be provided to the Template::Plugins new() constructor. =over 4 =item PLUGINS The PLUGINS options can be used to provide a reference to a hash array that maps plugin names to Perl module names. A number of standard plugins are defined (e.g. 'table', 'cgi', 'dbi', etc.) which map to their corresponding Template::Plugin::* counterparts. These can be redefined by values in the PLUGINS hash. my $plugins = Template::Plugins->new({ PLUGINS => { cgi => 'MyOrg::Template::Plugin::CGI', foo => 'MyOrg::Template::Plugin::Foo', bar => 'MyOrg::Template::Plugin::Bar', }, }); The USE directive is used to create plugin objects and does so by calling the plugin() method on the current Template::Context object. If the plugin name is defined in the PLUGINS hash then the corresponding Perl module is loaded via require(). The context then calls the load() class method which should return the class name (default and general case) or a prototype object against which the new() method can be called to instantiate individual plugin objects. If the plugin name is not defined in the PLUGINS hash then the PLUGIN_BASE and/or LOAD_PERL options come into effect. =item PLUGIN_BASE If a plugin is not defined in the PLUGINS hash then the PLUGIN_BASE is used to attempt to construct a correct Perl module name which can be successfully loaded. The PLUGIN_BASE can be specified as a single value or as a reference to an array of multiple values. The default PLUGIN_BASE value, 'Template::Plugin', is always added the the end of the PLUGIN_BASE list (a single value is first converted to a list). Each value should contain a Perl package name to which the requested plugin name is appended. example 1: my $plugins = Template::Plugins->new({ PLUGIN_BASE => 'MyOrg::Template::Plugin', }); [% USE Foo %] # => MyOrg::Template::Plugin::Foo or Template::Plugin::Foo example 2: my $plugins = Template::Plugins->new({ PLUGIN_BASE => [ 'MyOrg::Template::Plugin', 'YourOrg::Template::Plugin' ], }); [% USE Foo %] # => MyOrg::Template::Plugin::Foo or YourOrg::Template::Plugin::Foo or Template::Plugin::Foo =item LOAD_PERL If a plugin cannot be loaded using the PLUGINS or PLUGIN_BASE approaches then the provider can make a final attempt to load the module without prepending any prefix to the module path. This allows regular Perl modules (i.e. those that don't reside in the Template::Plugin or some other such namespace) to be loaded and used as plugins. By default, the LOAD_PERL option is set to 0 and no attempt will be made to load any Perl modules that aren't named explicitly in the PLUGINS hash or reside in a package as named by one of the PLUGIN_BASE components. Plugins loaded using the PLUGINS or PLUGIN_BASE receive a reference to the current context object as the first argument to the new() constructor. Modules loaded using LOAD_PERL are assumed to not conform to the plugin interface. They must provide a new() class method for instantiating objects but it will not receive a reference to the context as the first argument. Plugin modules should provide a load() class method (or inherit the default one from the Template::Plugin base class) which is called the first time the plugin is loaded. Regular Perl modules need not. In all other respects, regular Perl objects and Template Toolkit plugins are identical. If a particular Perl module does not conform to the common, but not unilateral, new() constructor convention then a simple plugin wrapper can be written to interface to it. =item TOLERANT The TOLERANT flag is used by the various Template Toolkit provider modules (Template::Provider, Template::Plugins, Template::Filters) to control their behaviour when errors are encountered. By default, any errors are reported as such, with the request for the particular resource (template, plugin, filter) being denied and an exception raised. When the TOLERANT flag is set to any true values, errors will be silently ignored and the provider will instead return STATUS_DECLINED. This allows a subsequent provider to take responsibility for providing the resource, rather than failing the request outright. If all providers decline to service the request, either through tolerated failure or a genuine disinclination to comply, then a 'E<lt>resourceE<gt> not found' exception is raised. =item DEBUG The DEBUG option can be used to enable debugging messages from the Template::Plugins module by setting it to include the DEBUG_PLUGINS value. use Template::Constants qw( :debug ); my $template = Template->new({ DEBUG => DEBUG_FILTERS | DEBUG_PLUGINS, }); =back =head1 TEMPLATE TOOLKIT PLUGINS The following plugin modules are distributed with the Template Toolkit. Some of the plugins interface to external modules (detailed below) which should be downloaded from any CPAN site and installed before using the plugin. =head2 Autoformat The Autoformat plugin is an interface to Damian Conway's Text::Autoformat Perl module which provides advanced text wrapping and formatting. See L<Template::Plugin::Autoformat> and L<Text::Autoformat> for further details. [% USE autoformat(left=10, right=20) %] [% autoformat(mytext) %] # call autoformat sub [% mytext FILTER autoformat %] # or use autoformat filter The Text::Autoformat module is available from CPAN: http://www.cpan.org/modules/by-module/Text/ =head2 CGI The CGI plugin is a wrapper around Lincoln Stein's E<lt>lstein@genome.wi.mit.eduE<gt> CGI.pm module. The plugin is distributed with the Template Toolkit (see L<Template::Plugin::CGI>) and the CGI module itself is distributed with recent versions Perl, or is available from CPAN. [% USE CGI %] [% CGI.param('param_name') %] [% CGI.start_form %] [% CGI.popup_menu( Name => 'color', Values => [ 'Green', 'Brown' ] ) %] [% CGI.end_form %] =head2 Datafile Provides an interface to data stored in a plain text file in a simple delimited format. The first line in the file specifies field names which should be delimiter by any non-word character sequence. Subsequent lines define data using the same delimiter as int he first line. Blank lines and comments (lines starting '#') are ignored. See L<Template::Plugin::Datafile> for further details. /tmp/mydata: # define names for each field id : email : name : tel # here's the data fred : fred@here.com : Fred Smith : 555-1234 bill : bill@here.com : Bill White : 555-5678 example: [% USE userlist = datafile('/tmp/mydata') %] [% FOREACH user = userlist %] [% user.name %] ([% user.id %]) [% END %] =head2 Date The Date plugin provides an easy way to generate formatted time and date strings by delegating to the POSIX strftime() routine. See L<Template::Plugin::Date> and L<POSIX> for further details. [% USE date %] [% date.format %] # current time/date File last modified: [% date.format(template.modtime) %] =head2 Directory The Directory plugin provides a simple interface to a directory and the files within it. See L<Template::Plugin::Directory> for further details. [% USE dir = Directory('/tmp') %] [% FOREACH file = dir.files %] # all the plain files in the directory [% END %] [% FOREACH file = dir.dirs %] # all the sub-directories [% END %] =head2 DBI The DBI plugin, developed by Simon Matthews E<lt>sam@knowledgepool.comE<gt>, brings the full power of Tim Bunce's E<lt>Tim.Bunce@ig.co.ukE<gt> database interface module (DBI) to your templates. See L<Template::Plugin::DBI> and L<DBI> for further details. [% USE DBI('dbi:driver:database', 'user', 'pass') %] [% FOREACH user = DBI.query( 'SELECT * FROM users' ) %] [% user.id %] [% user.name %] [% END %] The DBI and relevant DBD modules are available from CPAN: http://www.cpan.org/modules/by-module/DBI/ =head2 Dumper The Dumper plugin provides an interface to the Data::Dumper module. See L<Template::Plugin::Dumper> and L<Data::Dumper> for futher details. [% USE dumper(indent=0, pad="<br>") %] [% dumper.dump(myvar, yourvar) %] =head2 File The File plugin provides a general abstraction for files and can be used to fetch information about specific files within a filesystem. See L<Template::Plugin::File> for further details. [% USE File('/tmp/foo.html') %] [% File.name %] # foo.html [% File.dir %] # /tmp [% File.mtime %] # modification time =head2 Filter This module implements a base class plugin which can be subclassed to easily create your own modules that define and install new filters. package MyOrg::Template::Plugin::MyFilter; use Template::Plugin::Filter; use base qw( Template::Plugin::Filter ); sub filter { my ($self, $text) = @_; # ...mungify $text... return $text; } # now load it... [% USE MyFilter %] # ...and use the returned object as a filter [% FILTER $MyFilter %] ... [% END %] See L<Template::Plugin::Filter> for further details. =head2 Format The Format plugin provides a simple way to format text according to a printf()-like format. See L<Template::Plugin::Format> for further details. [% USE bold = format('<b>%s</b>') %] [% bold('Hello') %] =head2 GD::Image, GD::Polygon, GD::Constants These plugins provide access to the GD graphics library via Lincoln D. Stein's GD.pm interface. These plugins allow PNG, JPEG and other graphical formats to be generated. [% FILTER null; USE im = GD.Image(100,100); # allocate some colors black = im.colorAllocate(0, 0, 0); red = im.colorAllocate(255,0, 0); blue = im.colorAllocate(0, 0, 255); # Draw a blue oval im.arc(50,50,95,75,0,360,blue); # And fill it with red im.fill(50,50,red); # Output image in PNG format im.png | stdout(1); END; -%] See L<Template::Plugin::GD::Image> for further details. =head2 GD::Text, GD::Text::Align, GD::Text::Wrap These plugins provide access to Martien Verbruggen's GD::Text, GD::Text::Align and GD::Text::Wrap modules. These plugins allow the layout, alignment and wrapping of text when drawing text in GD images. [% FILTER null; USE gd = GD.Image(200,400); USE gdc = GD.Constants; black = gd.colorAllocate(0, 0, 0); green = gd.colorAllocate(0, 255, 0); txt = "This is some long text. " | repeat(10); USE wrapbox = GD.Text.Wrap(gd, line_space => 4, color => green, text => txt, ); wrapbox.set_font(gdc.gdMediumBoldFont); wrapbox.set(align => 'center', width => 160); wrapbox.draw(20, 20); gd.png | stdout(1); END; -%] See L<Template::Plugin::GD::Text>, L<Template::Plugin::GD::Text::Align> and L<Template::Plugin::GD::Text::Wrap> for further details. =head2 GD::Graph::lines, GD::Graph::bars, GD::Graph::points, GD::Graph::linespoin ts, GD::Graph::area, GD::Graph::mixed, GD::Graph::pie These plugins provide access to Martien Verbruggen's GD::Graph module that allows graphs, plots and charts to be created. These plugins allow graphs, plots and charts to be generated in PNG, JPEG and other graphical formats. [% FILTER null; data = [ ["1st","2nd","3rd","4th","5th","6th"], [ 4, 2, 3, 4, 3, 3.5] ]; USE my_graph = GD.Graph.pie(250, 200); my_graph.set( title => 'A Pie Chart', label => 'Label', axislabelclr => 'black', pie_height => 36, transparent => 0, ); my_graph.plot(data).png | stdout(1); END; -%] See L<Template::Plugin::GD::Graph::lines>, L<Template::Plugin::GD::Graph::bars>, L<Template::Plugin::GD::Graph::points>, L<Template::Plugin::GD::Graph::linespoints>, L<Template::Plugin::GD::Graph::area>, L<Template::Plugin::GD::Graph::mixed>, L<Template::Plugin::GD::Graph::pie>, and L<GD::Graph>, for more details. =head2 GD::Graph::bars3d, GD::Graph::lines3d, GD::Graph::pie3d These plugins provide access to Jeremy Wadsack's GD::Graph3d module. This allows 3D bar charts and 3D lines plots to be generated. [% FILTER null; data = [ ["1st","2nd","3rd","4th","5th","6th","7th", "8th", "9th"], [ 1, 2, 5, 6, 3, 1.5, 1, 3, 4], ]; USE my_graph = GD.Graph.bars3d(); my_graph.set( x_label => 'X Label', y_label => 'Y label', title => 'A 3d Bar Chart', y_max_value => 8, y_tick_number => 8, y_label_skip => 2, # shadows bar_spacing => 8, shadow_depth => 4, shadowclr => 'dred', transparent => 0, my_graph.plot(data).png | stdout(1); END; -%] See L<Template::Plugin::GD::Graph::lines3d>, L<Template::Plugin::GD::Graph::bars3d>, and L<Template::Plugin::GD::Graph::pie3d> for more details. =head2 HTML The HTML plugin is very new and very basic, implementing a few useful methods for generating HTML. It is likely to be extended in the future or integrated with a larger project to generate HTML elements in a generic way (as discussed recently on the mod_perl mailing list). [% USE HTML %] [% HTML.escape("if (a < b && c > d) ..." %] [% HTML.attributes(border => 1, cellpadding => 2) %] [% HTML.element(table => { border => 1, cellpadding => 2 }) %] See L<Template::Plugin::HTML> for further details. =head2 Iterator The Iterator plugin provides a way to create a Template::Iterator object to iterate over a data set. An iterator is created automatically by the FOREACH directive and is aliased to the 'loop' variable. This plugin allows an iterator to be explicitly created with a given name, or the default plugin name, 'iterator'. See L<Template::Plugin::Iterator> for further details. [% USE iterator(list, args) %] [% FOREACH item = iterator %] [% '<ul>' IF iterator.first %] <li>[% item %] [% '</ul>' IF iterator.last %] [% END %] =head2 Pod This plugin provides an interface to the L<Pod::POM|Pod::POM> module which parses POD documents into an internal object model which can then be traversed and presented through the Template Toolkit. [% USE Pod(podfile) %] [% FOREACH head1 = Pod.head1; FOREACH head2 = head1/head2; ... END; END %] =head2 String The String plugin implements an object-oriented interface for manipulating strings. See L<Template::Plugin::String> for further details. [% USE String 'Hello' %] [% String.append(' World') %] [% msg = String.new('Another string') %] [% msg.replace('string', 'text') %] The string "[% msg %]" is [% msg.length %] characters long. =head2 Table The Table plugin allows you to format a list of data items into a virtual table by specifying a fixed number of rows or columns, with an optional overlap. See L<Template::Plugin::Table> for further details. [% USE table(list, rows=10, overlap=1) %] [% FOREACH item = table.col(3) %] [% item %] [% END %] =head2 URL The URL plugin provides a simple way of contructing URLs from a base part and a variable set of parameters. See L<Template::Plugin::URL> for further details. [% USE mycgi = url('/cgi-bin/bar.pl', debug=1) %] [% mycgi %] # ==> /cgi/bin/bar.pl?debug=1 [% mycgi(mode='submit') %] # ==> /cgi/bin/bar.pl?mode=submit&debug=1 =head2 Wrap The Wrap plugin uses the Text::Wrap module by David Muir Sharnoff E<lt>muir@idiom.comE<gt> (with help from Tim Pierce and many many others) to provide simple paragraph formatting. See L<Template::Plugin::Wrap> and L<Text::Wrap> for further details. [% USE wrap %] [% wrap(mytext, 40, '* ', ' ') %] # use wrap sub [% mytext FILTER wrap(40) -%] # or wrap FILTER The Text::Wrap module is available from CPAN: http://www.cpan.org/modules/by-module/Text/ =head2 XML::DOM The XML::DOM plugin gives access to the XML Document Object Module via Clark Cooper E<lt>cooper@sch.ge.comE<gt> and Enno Derksen's E<lt>enno@att.comE<gt> XML::DOM module. See L<Template::Plugin::XML::DOM> and L<XML::DOM> for further details. [% USE dom = XML.DOM %] [% doc = dom.parse(filename) %] [% FOREACH node = doc.getElementsByTagName('CODEBASE') %] * [% node.getAttribute('href') %] [% END %] The plugin requires the XML::DOM module, available from CPAN: http://www.cpan.org/modules/by-module/XML/ =head2 XML::RSS The XML::RSS plugin is a simple interface to Jonathan Eisenzopf's E<lt>eisen@pobox.comE<gt> XML::RSS module. A RSS (Rich Site Summary) file is typically used to store short news 'headlines' describing different links within a site. This plugin allows you to parse RSS files and format the contents accordingly using templates. See L<Template::Plugin::XML::RSS> and L<XML::RSS> for further details. [% USE news = XML.RSS(filename) %] [% FOREACH item = news.items %] <a href="[% item.link %]">[% item.title %]</a> [% END %] The XML::RSS module is available from CPAN: http://www.cpan.org/modules/by-module/XML/ =head2 XML::Simple This plugin implements an interface to the L<XML::Simple|XML::Simple> module. [% USE xml = XML.Simple(xml_file_or_text) %] [% xml.head.title %] See L<Template::Plugin::XML::Simple> for further details. =head2 XML::Style This plugin defines a filter for performing simple stylesheet based transformations of XML text. [% USE xmlstyle table = { attributes = { border = 0 cellpadding = 4 cellspacing = 1 } } %] [% FILTER xmlstyle %] <table> <tr> <td>Foo</td> <td>Bar</td> <td>Baz</td> </tr> </table> [% END %] See L<Template::Plugin::XML::Style> for further details. =head2 XML::XPath The XML::XPath plugin provides an interface to Matt Sergeant's E<lt>matt@sergeant.orgE<gt> XML::XPath module. See L<Template::Plugin::XML::XPath> and L<XML::XPath> for further details. [% USE xpath = XML.XPath(xmlfile) %] [% FOREACH page = xpath.findnodes('/html/body/page') %] [% page.getAttribute('title') %] [% END %] The plugin requires the XML::XPath module, available from CPAN: http://www.cpan.org/modules/by-module/XML/ =head1 BUGS / ISSUES =over 4 =item * It might be worthwhile being able to distinguish between absolute module names and those which should be applied relative to PLUGIN_BASE directories. For example, use 'MyNamespace::MyModule' to denote absolute module names (e.g. LOAD_PERL), and 'MyNamespace.MyModule' to denote relative to PLUGIN_BASE. =back =head1 AUTHOR Andy Wardley E<lt>abw@andywardley.comE<gt> L<http://www.andywardley.com/|http://www.andywardley.com/> =head1 VERSION 2.65, distributed as part of the Template Toolkit version 2.10, released on 24 July 2003. =head1 COPYRIGHT Copyright (C) 1996-2003 Andy Wardley. All Rights Reserved. Copyright (C) 1998-2002 Canon Research Centre Europe Ltd. This module is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =head1 SEE ALSO L<Template|Template>, L<Template::Plugin|Template::Plugin>, L<Template::Context|Template::Context> �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������vdradmin-am-3.6.13/lib/Template/Provider.pm���������������������������������������������������������0000664�0000000�0000000�00000124653�14437161134�0020473�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#============================================================= -*-Perl-*- # # Template::Provider # # DESCRIPTION # This module implements a class which handles the loading, compiling # and caching of templates. Multiple Template::Provider objects can # be stacked and queried in turn to effect a Chain-of-Command between # them. A provider will attempt to return the requested template, # an error (STATUS_ERROR) or decline to provide the template # (STATUS_DECLINE), allowing subsequent providers to attempt to # deliver it. See 'Design Patterns' for further details. # # AUTHOR # Andy Wardley <abw@kfs.org> # # COPYRIGHT # Copyright (C) 1996-2000 Andy Wardley. All Rights Reserved. # Copyright (C) 1998-2000 Canon Research Centre Europe Ltd. # # This module is free software; you can redistribute it and/or # modify it under the same terms as Perl itself. # # TODO: # * optional provider prefix (e.g. 'http:') # * fold ABSOLUTE and RELATIVE test cases into one regex? # #---------------------------------------------------------------------------- # # $Id: Provider.pm,v 2.70 2003/04/24 09:14:38 abw Exp $ # #============================================================================ package Template::Provider; require 5.004; use strict; use vars qw( $VERSION $DEBUG $ERROR $DOCUMENT $STAT_TTL $MAX_DIRS ); use base qw( Template::Base ); use Template::Config; use Template::Constants; use Template::Document; use File::Basename; use File::Spec; $VERSION = sprintf("%d.%02d", q$Revision: 2.70 $ =~ /(\d+)\.(\d+)/); # name of document class $DOCUMENT = 'Template::Document' unless defined $DOCUMENT; # maximum time between performing stat() on file to check staleness $STAT_TTL = 1 unless defined $STAT_TTL; # maximum number of directories in an INCLUDE_PATH, to prevent runaways $MAX_DIRS = 64 unless defined $MAX_DIRS; use constant PREV => 0; use constant NAME => 1; use constant DATA => 2; use constant LOAD => 3; use constant NEXT => 4; use constant STAT => 5; $DEBUG = 0 unless defined $DEBUG; #======================================================================== # -- PUBLIC METHODS -- #======================================================================== #------------------------------------------------------------------------ # fetch($name) # # Returns a compiled template for the name specified by parameter. # The template is returned from the internal cache if it exists, or # loaded and then subsequently cached. The ABSOLUTE and RELATIVE # configuration flags determine if absolute (e.g. '/something...') # and/or relative (e.g. './something') paths should be honoured. The # INCLUDE_PATH is otherwise used to find the named file. $name may # also be a reference to a text string containing the template text, # or a file handle from which the content is read. The compiled # template is not cached in these latter cases given that there is no # filename to cache under. A subsequent call to store($name, # $compiled) can be made to cache the compiled template for future # fetch() calls, if necessary. # # Returns a compiled template or (undef, STATUS_DECLINED) if the # template could not be found. On error (e.g. the file was found # but couldn't be read or parsed), the pair ($error, STATUS_ERROR) # is returned. The TOLERANT configuration option can be set to # downgrade any errors to STATUS_DECLINE. #------------------------------------------------------------------------ sub fetch { my ($self, $name) = @_; my ($data, $error); if (ref $name) { # $name can be a reference to a scalar, GLOB or file handle ($data, $error) = $self->_load($name); ($data, $error) = $self->_compile($data) unless $error; $data = $data->{ data } unless $error; } elsif (File::Spec->file_name_is_absolute($name)) { # absolute paths (starting '/') allowed if ABSOLUTE set ($data, $error) = $self->{ ABSOLUTE } ? $self->_fetch($name) : $self->{ TOLERANT } ? (undef, Template::Constants::STATUS_DECLINED) : ("$name: absolute paths are not allowed (set ABSOLUTE option)", Template::Constants::STATUS_ERROR); } elsif ($name =~ m[^\.+/]) { # anything starting "./" is relative to cwd, allowed if RELATIVE set ($data, $error) = $self->{ RELATIVE } ? $self->_fetch($name) : $self->{ TOLERANT } ? (undef, Template::Constants::STATUS_DECLINED) : ("$name: relative paths are not allowed (set RELATIVE option)", Template::Constants::STATUS_ERROR); } else { # otherwise, it's a file name relative to INCLUDE_PATH ($data, $error) = $self->{ INCLUDE_PATH } ? $self->_fetch_path($name) : (undef, Template::Constants::STATUS_DECLINED); } # $self->_dump_cache() # if $DEBUG > 1; return ($data, $error); } #------------------------------------------------------------------------ # store($name, $data) # # Store a compiled template ($data) in the cached as $name. #------------------------------------------------------------------------ sub store { my ($self, $name, $data) = @_; $self->_store($name, { data => $data, load => 0, }); } #------------------------------------------------------------------------ # load($name) # # Load a template without parsing/compiling it, suitable for use with # the INSERT directive. There's some duplication with fetch() and at # some point this could be reworked to integrate them a little closer. #------------------------------------------------------------------------ sub load { my ($self, $name) = @_; my ($data, $error); my $path = $name; if (File::Spec->file_name_is_absolute($name)) { # absolute paths (starting '/') allowed if ABSOLUTE set $error = "$name: absolute paths are not allowed (set ABSOLUTE option)" unless $self->{ ABSOLUTE }; } elsif ($name =~ m[^\.+/]) { # anything starting "./" is relative to cwd, allowed if RELATIVE set $error = "$name: relative paths are not allowed (set RELATIVE option)" unless $self->{ RELATIVE }; } else { INCPATH: { # otherwise, it's a file name relative to INCLUDE_PATH my $paths = $self->paths() || return ($self->error(), Template::Constants::STATUS_ERROR); foreach my $dir (@$paths) { $path = "$dir/$name"; last INCPATH if -f $path; } undef $path; # not found } } if (defined $path && ! $error) { local $/ = undef; # slurp files in one go local *FH; if (open(FH, $path)) { $data = <FH>; close(FH); } else { $error = "$name: $!"; } } if ($error) { return $self->{ TOLERANT } ? (undef, Template::Constants::STATUS_DECLINED) : ($error, Template::Constants::STATUS_ERROR); } elsif (! defined $path) { return (undef, Template::Constants::STATUS_DECLINED); } else { return ($data, Template::Constants::STATUS_OK); } } #------------------------------------------------------------------------ # include_path(\@newpath) # # Accessor method for the INCLUDE_PATH setting. If called with an # argument, this method will replace the existing INCLUDE_PATH with # the new value. #------------------------------------------------------------------------ sub include_path { my ($self, $path) = @_; $self->{ INCLUDE_PATH } = $path if $path; return $self->{ INCLUDE_PATH }; } #------------------------------------------------------------------------ # paths() # # Evaluates the INCLUDE_PATH list, ignoring any blank entries, and # calling and subroutine or object references to return dynamically # generated path lists. Returns a reference to a new list of paths # or undef on error. #------------------------------------------------------------------------ sub paths { my $self = shift; my @ipaths = @{ $self->{ INCLUDE_PATH } }; my (@opaths, $dpaths, $dir); my $count = $MAX_DIRS; while (@ipaths && --$count) { $dir = shift @ipaths || next; # $dir can be a sub or object ref which returns a reference # to a dynamically generated list of search paths. if (ref $dir eq 'CODE') { eval { $dpaths = &$dir() }; if ($@) { chomp $@; return $self->error($@); } unshift(@ipaths, @$dpaths); next; } elsif (UNIVERSAL::can($dir, 'paths')) { $dpaths = $dir->paths() || return $self->error($dir->error()); unshift(@ipaths, @$dpaths); next; } else { push(@opaths, $dir); } } return $self->error("INCLUDE_PATH exceeds $MAX_DIRS directories") if @ipaths; return \@opaths; } #------------------------------------------------------------------------ # DESTROY # # The provider cache is implemented as a doubly linked list which Perl # cannot free by itself due to the circular references between NEXT <=> # PREV items. This cleanup method walks the list deleting all the NEXT/PREV # references, allowing the proper cleanup to occur and memory to be # repooled. #------------------------------------------------------------------------ sub DESTROY { my $self = shift; my ($slot, $next); $slot = $self->{ HEAD }; while ($slot) { $next = $slot->[ NEXT ]; undef $slot->[ PREV ]; undef $slot->[ NEXT ]; $slot = $next; } undef $self->{ HEAD }; undef $self->{ TAIL }; } #======================================================================== # -- PRIVATE METHODS -- #======================================================================== #------------------------------------------------------------------------ # _init() # # Initialise the cache. #------------------------------------------------------------------------ sub _init { my ($self, $params) = @_; my $size = $params->{ CACHE_SIZE }; my $path = $params->{ INCLUDE_PATH } || '.'; my $cdir = $params->{ COMPILE_DIR } || ''; my $dlim = $params->{ DELIMITER }; my $debug; # tweak delim to ignore C:/ unless (defined $dlim) { $dlim = ($^O eq 'MSWin32') ? ':(?!\\/)' : ':'; } # coerce INCLUDE_PATH to an array ref, if not already so $path = [ split(/$dlim/, $path) ] unless ref $path eq 'ARRAY'; # don't allow a CACHE_SIZE 1 because it breaks things and the # additional checking isn't worth it $size = 2 if defined $size && ($size == 1 || $size < 0); if (defined ($debug = $params->{ DEBUG })) { $self->{ DEBUG } = $debug & ( Template::Constants::DEBUG_PROVIDER | Template::Constants::DEBUG_FLAGS ); } else { $self->{ DEBUG } = $DEBUG; } if ($self->{ DEBUG }) { local $" = ', '; $self->debug("creating cache of ", defined $size ? $size : 'unlimited', " slots for [ @$path ]"); } # create COMPILE_DIR and sub-directories representing each INCLUDE_PATH # element in which to store compiled files if ($cdir) { # Stas' hack # # this is a hack to solve the problem with INCLUDE_PATH using # # relative dirs # my $segments = 0; # for (@$path) { # my $c = 0; # $c++ while m|\.\.|g; # $segments = $c if $c > $segments; # } # $cdir .= "/".join "/",('hack') x $segments if $segments; # require File::Path; foreach my $dir (@$path) { next if ref $dir; my $wdir = $dir; $wdir =~ s[:][]g if $^O eq 'MSWin32'; $wdir =~ /(.*)/; # untaint &File::Path::mkpath(File::Spec->catfile($cdir, $1)); } } $self->{ LOOKUP } = { }; $self->{ SLOTS } = 0; $self->{ SIZE } = $size; $self->{ INCLUDE_PATH } = $path; $self->{ DELIMITER } = $dlim; $self->{ COMPILE_DIR } = $cdir; $self->{ COMPILE_EXT } = $params->{ COMPILE_EXT } || ''; $self->{ ABSOLUTE } = $params->{ ABSOLUTE } || 0; $self->{ RELATIVE } = $params->{ RELATIVE } || 0; $self->{ TOLERANT } = $params->{ TOLERANT } || 0; $self->{ DOCUMENT } = $params->{ DOCUMENT } || $DOCUMENT; $self->{ PARSER } = $params->{ PARSER }; $self->{ DEFAULT } = $params->{ DEFAULT }; # $self->{ PREFIX } = $params->{ PREFIX }; $self->{ PARAMS } = $params; return $self; } #------------------------------------------------------------------------ # _fetch($name) # # Fetch a file from cache or disk by specification of an absolute or # relative filename. No search of the INCLUDE_PATH is made. If the # file is found and loaded, it is compiled and cached. #------------------------------------------------------------------------ sub _fetch { my ($self, $name) = @_; my $size = $self->{ SIZE }; my ($slot, $data, $error); $self->debug("_fetch($name)") if $self->{ DEBUG }; my $compiled = $self->_compiled_filename($name); if (defined $size && ! $size) { # caching disabled so load and compile but don't cache if ($compiled && -f $compiled && (stat($name))[9] <= (stat($compiled))[9]) { $data = $self->_load_compiled($compiled); $error = $self->error() unless $data; } else { ($data, $error) = $self->_load($name); ($data, $error) = $self->_compile($data, $compiled) unless $error; $data = $data->{ data } unless $error; } } elsif ($slot = $self->{ LOOKUP }->{ $name }) { # cached entry exists, so refresh slot and extract data ($data, $error) = $self->_refresh($slot); $data = $slot->[ DATA ] unless $error; } else { # nothing in cache so try to load, compile and cache if ($compiled && -f $compiled && (stat($name))[9] <= (stat($compiled))[9]) { $data = $self->_load_compiled($compiled); $error = $self->error() unless $data; $self->store($name, $data) unless $error; } else { ($data, $error) = $self->_load($name); ($data, $error) = $self->_compile($data, $compiled) unless $error; $data = $self->_store($name, $data) unless $error; } } return ($data, $error); } #------------------------------------------------------------------------ # _fetch_path($name) # # Fetch a file from cache or disk by specification of an absolute cache # name (e.g. 'header') or filename relative to one of the INCLUDE_PATH # directories. If the file isn't already cached and can be found and # loaded, it is compiled and cached under the full filename. #------------------------------------------------------------------------ sub _fetch_path { my ($self, $name) = @_; my ($size, $compext, $compdir) = @$self{ qw( SIZE COMPILE_EXT COMPILE_DIR ) }; my ($dir, $paths, $path, $compiled, $slot, $data, $error); local *FH; $self->debug("_fetch_path($name)") if $self->{ DEBUG }; # caching is enabled if $size is defined and non-zero or undefined my $caching = (! defined $size || $size); INCLUDE: { # the template may have been stored using a non-filename name if ($caching && ($slot = $self->{ LOOKUP }->{ $name })) { # cached entry exists, so refresh slot and extract data ($data, $error) = $self->_refresh($slot); $data = $slot->[ DATA ] unless $error; last INCLUDE; } $paths = $self->paths() || do { $error = Template::Constants::STATUS_ERROR; $data = $self->error(); last INCLUDE; }; # search the INCLUDE_PATH for the file, in cache or on disk foreach $dir (@$paths) { $path = "$dir/$name"; $self->debug("searching path: $path\n") if $self->{ DEBUG }; if ($caching && ($slot = $self->{ LOOKUP }->{ $path })) { # cached entry exists, so refresh slot and extract data ($data, $error) = $self->_refresh($slot); $data = $slot->[ DATA ] unless $error; last INCLUDE; } elsif (-f $path) { $compiled = $self->_compiled_filename($path) if $compext || $compdir; if ($compiled && -f $compiled && (stat($path))[9] <= (stat($compiled))[9]) { if ($data = $self->_load_compiled($compiled)) { # store in cache $data = $self->store($path, $data); $error = Template::Constants::STATUS_OK; last INCLUDE; } else { warn($self->error(), "\n"); } } # $compiled is set if an attempt to write the compiled # template to disk should be made ($data, $error) = $self->_load($path, $name); ($data, $error) = $self->_compile($data, $compiled) unless $error; $data = $self->_store($path, $data) unless $error || ! $caching; $data = $data->{ data } if ! $caching; # all done if $error is OK or ERROR last INCLUDE if ! $error || $error == Template::Constants::STATUS_ERROR; } } # template not found, so look for a DEFAULT template my $default; if (defined ($default = $self->{ DEFAULT }) && $name ne $default) { $name = $default; redo INCLUDE; } ($data, $error) = (undef, Template::Constants::STATUS_DECLINED); } # INCLUDE return ($data, $error); } sub _compiled_filename { my ($self, $file) = @_; my ($compext, $compdir) = @$self{ qw( COMPILE_EXT COMPILE_DIR ) }; my ($path, $compiled); return undef unless $compext || $compdir; $path = $file; $path =~ /^(.+)$/s or die "invalid filename: $path"; $path =~ s[:][]g if $^O eq 'MSWin32'; $compiled = "$path$compext"; $compiled = File::Spec->catfile($compdir, $compiled) if length $compdir; return $compiled; } sub _load_compiled { my ($self, $file) = @_; my $compiled; # load compiled template via require(); we zap any # %INC entry to ensure it is reloaded (we don't # want 1 returned by require() to say it's in memory) delete $INC{ $file }; eval { $compiled = require $file; }; return $@ ? $self->error("compiled template $compiled: $@") : $compiled; } #------------------------------------------------------------------------ # _load($name, $alias) # # Load template text from a string ($name = scalar ref), GLOB or file # handle ($name = ref), or from an absolute filename ($name = scalar). # Returns a hash array containing the following items: # name filename or $alias, if provided, or 'input text', etc. # text template text # time modification time of file, or current time for handles/strings # load time file was loaded (now!) # # On error, returns ($error, STATUS_ERROR), or (undef, STATUS_DECLINED) # if TOLERANT is set. #------------------------------------------------------------------------ sub _load { my ($self, $name, $alias) = @_; my ($data, $error); my $tolerant = $self->{ TOLERANT }; my $now = time; local $/ = undef; # slurp files in one go local *FH; $alias = $name unless defined $alias or ref $name; $self->debug("_load($name, ", defined $alias ? $alias : '<no alias>', ')') if $self->{ DEBUG }; LOAD: { if (ref $name eq 'SCALAR') { # $name can be a SCALAR reference to the input text... $data = { name => defined $alias ? $alias : 'input text', text => $$name, time => $now, load => 0, }; } elsif (ref $name) { # ...or a GLOB or file handle... my $text = <$name>; $data = { name => defined $alias ? $alias : 'input file handle', text => $text, time => $now, load => 0, }; } elsif (-f $name) { if (open(FH, $name)) { my $text = <FH>; $data = { name => $alias, text => $text, time => (stat $name)[9], load => $now, }; } elsif ($tolerant) { ($data, $error) = (undef, Template::Constants::STATUS_DECLINED); } else { $data = "$alias: $!"; $error = Template::Constants::STATUS_ERROR; } } else { ($data, $error) = (undef, Template::Constants::STATUS_DECLINED); } } return ($data, $error); } #------------------------------------------------------------------------ # _refresh(\@slot) # # Private method called to mark a cache slot as most recently used. # A reference to the slot array should be passed by parameter. The # slot is relocated to the head of the linked list. If the file from # which the data was loaded has been upated since it was compiled, then # it is re-loaded from disk and re-compiled. #------------------------------------------------------------------------ sub _refresh { my ($self, $slot) = @_; my ($head, $file, $data, $error); $self->debug("_refresh([ ", join(', ', map { defined $_ ? $_ : '<undef>' } @$slot), '])') if $self->{ DEBUG }; # if it's more than $STAT_TTL seconds since we last performed a # stat() on the file then we need to do it again and see if the file # time has changed if ( (time - $slot->[ STAT ]) > $STAT_TTL && stat $slot->[ NAME ] ) { $slot->[ STAT ] = time; if ( (stat(_))[9] != $slot->[ LOAD ]) { $self->debug("refreshing cache file ", $slot->[ NAME ]) if $self->{ DEBUG }; ($data, $error) = $self->_load($slot->[ NAME ], $slot->[ DATA ]->{ name }); ($data, $error) = $self->_compile($data) unless $error; unless ($error) { $slot->[ DATA ] = $data->{ data }; $slot->[ LOAD ] = $data->{ time }; } } } unless( $self->{ HEAD } == $slot ) { # remove existing slot from usage chain... if ($slot->[ PREV ]) { $slot->[ PREV ]->[ NEXT ] = $slot->[ NEXT ]; } else { $self->{ HEAD } = $slot->[ NEXT ]; } if ($slot->[ NEXT ]) { $slot->[ NEXT ]->[ PREV ] = $slot->[ PREV ]; } else { $self->{ TAIL } = $slot->[ PREV ]; } # ..and add to start of list $head = $self->{ HEAD }; $head->[ PREV ] = $slot if $head; $slot->[ PREV ] = undef; $slot->[ NEXT ] = $head; $self->{ HEAD } = $slot; } return ($data, $error); } #------------------------------------------------------------------------ # _store($name, $data) # # Private method called to add a data item to the cache. If the cache # size limit has been reached then the oldest entry at the tail of the # list is removed and its slot relocated to the head of the list and # reused for the new data item. If the cache is under the size limit, # or if no size limit is defined, then the item is added to the head # of the list. #------------------------------------------------------------------------ sub _store { my ($self, $name, $data, $compfile) = @_; my $size = $self->{ SIZE }; my ($slot, $head); # extract the load time and compiled template from the data # my $load = $data->{ load }; my $load = (stat($name))[9]; $data = $data->{ data }; $self->debug("_store($name, $data)") if $self->{ DEBUG }; if (defined $size && $self->{ SLOTS } >= $size) { # cache has reached size limit, so reuse oldest entry $self->debug("reusing oldest cache entry (size limit reached: $size)\nslots: $self->{ SLOTS }") if $self->{ DEBUG }; # remove entry from tail of list $slot = $self->{ TAIL }; $slot->[ PREV ]->[ NEXT ] = undef; $self->{ TAIL } = $slot->[ PREV ]; # remove name lookup for old node delete $self->{ LOOKUP }->{ $slot->[ NAME ] }; # add modified node to head of list $head = $self->{ HEAD }; $head->[ PREV ] = $slot if $head; @$slot = ( undef, $name, $data, $load, $head, time ); $self->{ HEAD } = $slot; # add name lookup for new node $self->{ LOOKUP }->{ $name } = $slot; } else { # cache is under size limit, or none is defined $self->debug("adding new cache entry") if $self->{ DEBUG }; # add new node to head of list $head = $self->{ HEAD }; $slot = [ undef, $name, $data, $load, $head, time ]; $head->[ PREV ] = $slot if $head; $self->{ HEAD } = $slot; $self->{ TAIL } = $slot unless $self->{ TAIL }; # add lookup from name to slot and increment nslots $self->{ LOOKUP }->{ $name } = $slot; $self->{ SLOTS }++; } return $data; } #------------------------------------------------------------------------ # _compile($data) # # Private method called to parse the template text and compile it into # a runtime form. Creates and delegates a Template::Parser object to # handle the compilation, or uses a reference passed in PARSER. On # success, the compiled template is stored in the 'data' item of the # $data hash and returned. On error, ($error, STATUS_ERROR) is returned, # or (undef, STATUS_DECLINED) if the TOLERANT flag is set. # The optional $compiled parameter may be passed to specify # the name of a compiled template file to which the generated Perl # code should be written. Errors are (for now...) silently # ignored, assuming that failures to open a file for writing are # intentional (e.g directory write permission). #------------------------------------------------------------------------ sub _compile { my ($self, $data, $compfile) = @_; my $text = $data->{ text }; my ($parsedoc, $error); $self->debug("_compile($data, ", defined $compfile ? $compfile : '<no compfile>', ')') if $self->{ DEBUG }; my $parser = $self->{ PARSER } ||= Template::Config->parser($self->{ PARAMS }) || return (Template::Config->error(), Template::Constants::STATUS_ERROR); # discard the template text - we don't need it any more delete $data->{ text }; # call parser to compile template into Perl code if ($parsedoc = $parser->parse($text, $data)) { $parsedoc->{ METADATA } = { 'name' => $data->{ name }, 'modtime' => $data->{ time }, %{ $parsedoc->{ METADATA } }, }; # write the Perl code to the file $compfile, if defined if ($compfile) { my $basedir = &File::Basename::dirname($compfile); $basedir =~ /(.*)/; $basedir = $1; &File::Path::mkpath($basedir) unless -d $basedir; my $docclass = $self->{ DOCUMENT }; $error = 'cache failed to write ' . &File::Basename::basename($compfile) . ': ' . $docclass->error() unless $docclass->write_perl_file($compfile, $parsedoc); # set atime and mtime of newly compiled file, don't bother # if time is undef if (!defined($error) && defined $data->{ time }) { my ($cfile) = $compfile =~ /^(.+)$/s or do { return("invalid filename: $compfile", Template::Constants::STATUS_ERROR); }; my ($ctime) = $data->{ time } =~ /^(\d+)$/; unless ($ctime || $ctime eq 0) { return("invalid time: $ctime", Template::Constants::STATUS_ERROR); } utime($ctime, $ctime, $cfile); } } unless ($error) { return $data ## RETURN ## if $data->{ data } = Template::Document->new($parsedoc); $error = $Template::Document::ERROR; } } else { $error = Template::Exception->new( 'parse', "$data->{ name } " . $parser->error() ); } # return STATUS_ERROR, or STATUS_DECLINED if we're being tolerant return $self->{ TOLERANT } ? (undef, Template::Constants::STATUS_DECLINED) : ($error, Template::Constants::STATUS_ERROR) } #------------------------------------------------------------------------ # _dump() # # Debug method which returns a string representing the internal object # state. #------------------------------------------------------------------------ sub _dump { my $self = shift; my $size = $self->{ SIZE }; my $parser = $self->{ PARSER }; $parser = $parser ? $parser->_dump() : '<no parser>'; $parser =~ s/\n/\n /gm; $size = 'unlimited' unless defined $size; my $output = "[Template::Provider] {\n"; my $format = " %-16s => %s\n"; my $key; $output .= sprintf($format, 'INCLUDE_PATH', '[ ' . join(', ', @{ $self->{ INCLUDE_PATH } }) . ' ]'); $output .= sprintf($format, 'CACHE_SIZE', $size); foreach $key (qw( ABSOLUTE RELATIVE TOLERANT DELIMITER COMPILE_EXT COMPILE_DIR )) { $output .= sprintf($format, $key, $self->{ $key }); } $output .= sprintf($format, 'PARSER', $parser); local $" = ', '; my $lookup = $self->{ LOOKUP }; $lookup = join('', map { sprintf(" $format", $_, defined $lookup->{ $_ } ? ('[ ' . join(', ', map { defined $_ ? $_ : '<undef>' } @{ $lookup->{ $_ } }) . ' ]') : '<undef>'); } sort keys %$lookup); $lookup = "{\n$lookup }"; $output .= sprintf($format, LOOKUP => $lookup); $output .= '}'; return $output; } #------------------------------------------------------------------------ # _dump_cache() # # Debug method which prints the current state of the cache to STDERR. #------------------------------------------------------------------------ sub _dump_cache { my $self = shift; my ($node, $lut, $count); $count = 0; if ($node = $self->{ HEAD }) { while ($node) { $lut->{ $node } = $count++; $node = $node->[ NEXT ]; } $node = $self->{ HEAD }; print STDERR "CACHE STATE:\n"; print STDERR " HEAD: ", $self->{ HEAD }->[ NAME ], "\n"; print STDERR " TAIL: ", $self->{ TAIL }->[ NAME ], "\n"; while ($node) { my ($prev, $name, $data, $load, $next) = @$node; # $name = '...' . substr($name, -10) if length $name > 10; $prev = $prev ? "#$lut->{ $prev }<-": '<undef>'; $next = $next ? "->#$lut->{ $next }": '<undef>'; print STDERR " #$lut->{ $node } : [ $prev, $name, $data, $load, $next ]\n"; $node = $node->[ NEXT ]; } } } 1; __END__ #------------------------------------------------------------------------ # IMPORTANT NOTE # This documentation is generated automatically from source # templates. Any changes you make here may be lost. # # The 'docsrc' documentation source bundle is available for download # from http://www.template-toolkit.org/docs.html and contains all # the source templates, XML files, scripts, etc., from which the # documentation for the Template Toolkit is built. #------------------------------------------------------------------------ =head1 NAME Template::Provider - Provider module for loading/compiling templates =head1 SYNOPSIS $provider = Template::Provider->new(\%options); ($template, $error) = $provider->fetch($name); =head1 DESCRIPTION The Template::Provider is used to load, parse, compile and cache template documents. This object may be sub-classed to provide more specific facilities for loading, or otherwise providing access to templates. The Template::Context objects maintain a list of Template::Provider objects which are polled in turn (via fetch()) to return a requested template. Each may return a compiled template, raise an error, or decline to serve the reqest, giving subsequent providers a chance to do so. This is the "Chain of Responsiblity" pattern. See 'Design Patterns' for further information. This documentation needs work. =head1 PUBLIC METHODS =head2 new(\%options) Constructor method which instantiates and returns a new Template::Provider object. The optional parameter may be a hash reference containing any of the following items: =over 4 =item INCLUDE_PATH The INCLUDE_PATH is used to specify one or more directories in which template files are located. When a template is requested that isn't defined locally as a BLOCK, each of the INCLUDE_PATH directories is searched in turn to locate the template file. Multiple directories can be specified as a reference to a list or as a single string where each directory is delimited by ':'. my $provider = Template::Provider->new({ INCLUDE_PATH => '/usr/local/templates', }); my $provider = Template::Provider->new({ INCLUDE_PATH => '/usr/local/templates:/tmp/my/templates', }); my $provider = Template::Provider->new({ INCLUDE_PATH => [ '/usr/local/templates', '/tmp/my/templates' ], }); On Win32 systems, a little extra magic is invoked, ignoring delimiters that have ':' followed by a '/' or '\'. This avoids confusion when using directory names like 'C:\Blah Blah'. When specified as a list, the INCLUDE_PATH path can contain elements which dynamically generate a list of INCLUDE_PATH directories. These generator elements can be specified as a reference to a subroutine or an object which implements a paths() method. my $provider = Template::Provider->new({ INCLUDE_PATH => [ '/usr/local/templates', \&incpath_generator, My::IncPath::Generator->new( ... ) ], }); Each time a template is requested and the INCLUDE_PATH examined, the subroutine or object method will be called. A reference to a list of directories should be returned. Generator subroutines should report errors using die(). Generator objects should return undef and make an error available via its error() method. For example: sub incpath_generator { # ...some code... if ($all_is_well) { return \@list_of_directories; } else { die "cannot generate INCLUDE_PATH...\n"; } } or: package My::IncPath::Generator; # Template::Base (or Class::Base) provides error() method use Template::Base; use base qw( Template::Base ); sub paths { my $self = shift; # ...some code... if ($all_is_well) { return \@list_of_directories; } else { return $self->error("cannot generate INCLUDE_PATH...\n"); } } 1; =item DELIMITER Used to provide an alternative delimiter character sequence for separating paths specified in the INCLUDE_PATH. The default value for DELIMITER is ':'. # tolerate Silly Billy's file system conventions my $provider = Template::Provider->new({ DELIMITER => '; ', INCLUDE_PATH => 'C:/HERE/NOW; D:/THERE/THEN', }); # better solution: install Linux! :-) On Win32 systems, the default delimiter is a little more intelligent, splitting paths only on ':' characters that aren't followed by a '/'. This means that the following should work as planned, splitting the INCLUDE_PATH into 2 separate directories, C:/foo and C:/bar. # on Win32 only my $provider = Template::Provider->new({ INCLUDE_PATH => 'C:/Foo:C:/Bar' }); However, if you're using Win32 then it's recommended that you explicitly set the DELIMITER character to something else (e.g. ';') rather than rely on this subtle magic. =item ABSOLUTE The ABSOLUTE flag is used to indicate if templates specified with absolute filenames (e.g. '/foo/bar') should be processed. It is disabled by default and any attempt to load a template by such a name will cause a 'file' exception to be raised. my $provider = Template::Provider->new({ ABSOLUTE => 1, }); # this is why it's disabled by default [% INSERT /etc/passwd %] On Win32 systems, the regular expression for matching absolute pathnames is tweaked slightly to also detect filenames that start with a driver letter and colon, such as: C:/Foo/Bar =item RELATIVE The RELATIVE flag is used to indicate if templates specified with filenames relative to the current directory (e.g. './foo/bar' or '../../some/where/else') should be loaded. It is also disabled by default, and will raise a 'file' error if such template names are encountered. my $provider = Template::Provider->new({ RELATIVE => 1, }); [% INCLUDE ../logs/error.log %] =item DEFAULT The DEFAULT option can be used to specify a default template which should be used whenever a specified template can't be found in the INCLUDE_PATH. my $provider = Template::Provider->new({ DEFAULT => 'notfound.html', }); If a non-existant template is requested through the Template process() method, or by an INCLUDE, PROCESS or WRAPPER directive, then the DEFAULT template will instead be processed, if defined. Note that the DEFAULT template is not used when templates are specified with absolute or relative filenames, or as a reference to a input file handle or text string. =item CACHE_SIZE The Template::Provider module caches compiled templates to avoid the need to re-parse template files or blocks each time they are used. The CACHE_SIZE option is used to limit the number of compiled templates that the module should cache. By default, the CACHE_SIZE is undefined and all compiled templates are cached. When set to any positive value, the cache will be limited to storing no more than that number of compiled templates. When a new template is loaded and compiled and the cache is full (i.e. the number of entries == CACHE_SIZE), the least recently used compiled template is discarded to make room for the new one. The CACHE_SIZE can be set to 0 to disable caching altogether. my $provider = Template::Provider->new({ CACHE_SIZE => 64, # only cache 64 compiled templates }); my $provider = Template::Provider->new({ CACHE_SIZE => 0, # don't cache any compiled templates }); =item COMPILE_EXT From version 2 onwards, the Template Toolkit has the ability to compile templates to Perl code and save them to disk for subsequent use (i.e. cache persistence). The COMPILE_EXT option may be provided to specify a filename extension for compiled template files. It is undefined by default and no attempt will be made to read or write any compiled template files. my $provider = Template::Provider->new({ COMPILE_EXT => '.ttc', }); If COMPILE_EXT is defined (and COMPILE_DIR isn't, see below) then compiled template files with the COMPILE_EXT extension will be written to the same directory from which the source template files were loaded. Compiling and subsequent reuse of templates happens automatically whenever the COMPILE_EXT or COMPILE_DIR options are set. The Template Toolkit will automatically reload and reuse compiled files when it finds them on disk. If the corresponding source file has been modified since the compiled version as written, then it will load and re-compile the source and write a new compiled version to disk. This form of cache persistence offers significant benefits in terms of time and resources required to reload templates. Compiled templates can be reloaded by a simple call to Perl's require(), leaving Perl to handle all the parsing and compilation. This is a Good Thing. =item COMPILE_DIR The COMPILE_DIR option is used to specify an alternate directory root under which compiled template files should be saved. my $provider = Template::Provider->new({ COMPILE_DIR => '/tmp/ttc', }); The COMPILE_EXT option may also be specified to have a consistent file extension added to these files. my $provider1 = Template::Provider->new({ COMPILE_DIR => '/tmp/ttc', COMPILE_EXT => '.ttc1', }); my $provider2 = Template::Provider->new({ COMPILE_DIR => '/tmp/ttc', COMPILE_EXT => '.ttc2', }); When COMPILE_EXT is undefined, the compiled template files have the same name as the original template files, but reside in a different directory tree. Each directory in the INCLUDE_PATH is replicated in full beneath the COMPILE_DIR directory. This example: my $provider = Template::Provider->new({ COMPILE_DIR => '/tmp/ttc', INCLUDE_PATH => '/home/abw/templates:/usr/share/templates', }); would create the following directory structure: /tmp/ttc/home/abw/templates/ /tmp/ttc/usr/share/templates/ Files loaded from different INCLUDE_PATH directories will have their compiled forms save in the relevant COMPILE_DIR directory. On Win32 platforms a filename may by prefixed by a drive letter and colon. e.g. C:/My Templates/header The colon will be silently stripped from the filename when it is added to the COMPILE_DIR value(s) to prevent illegal filename being generated. Any colon in COMPILE_DIR elements will be left intact. For example: # Win32 only my $provider = Template::Provider->new({ DELIMITER => ';', COMPILE_DIR => 'C:/TT2/Cache', INCLUDE_PATH => 'C:/TT2/Templates;D:/My Templates', }); This would create the following cache directories: C:/TT2/Cache/C/TT2/Templates C:/TT2/Cache/D/My Templates =item TOLERANT The TOLERANT flag is used by the various Template Toolkit provider modules (Template::Provider, Template::Plugins, Template::Filters) to control their behaviour when errors are encountered. By default, any errors are reported as such, with the request for the particular resource (template, plugin, filter) being denied and an exception raised. When the TOLERANT flag is set to any true values, errors will be silently ignored and the provider will instead return STATUS_DECLINED. This allows a subsequent provider to take responsibility for providing the resource, rather than failing the request outright. If all providers decline to service the request, either through tolerated failure or a genuine disinclination to comply, then a 'E<lt>resourceE<gt> not found' exception is raised. =item PARSER The Template::Parser module implements a parser object for compiling templates into Perl code which can then be executed. A default object of this class is created automatically and then used by the Template::Provider whenever a template is loaded and requires compilation. The PARSER option can be used to provide a reference to an alternate parser object. my $provider = Template::Provider->new({ PARSER => MyOrg::Template::Parser->new({ ... }), }); =item DEBUG The DEBUG option can be used to enable debugging messages from the Template::Provider module by setting it to include the DEBUG_PROVIDER value. use Template::Constants qw( :debug ); my $template = Template->new({ DEBUG => DEBUG_PROVIDER, }); =back =head2 fetch($name) Returns a compiled template for the name specified. If the template cannot be found then (undef, STATUS_DECLINED) is returned. If an error occurs (e.g. read error, parse error) then ($error, STATUS_ERROR) is returned, where $error is the error message generated. If the TOLERANT flag is set the the method returns (undef, STATUS_DECLINED) instead of returning an error. =head2 store($name, $template) Stores the compiled template, $template, in the cache under the name, $name. Susbequent calls to fetch($name) will return this template in preference to any disk-based file. =head2 include_path(\@newpath)) Accessor method for the INCLUDE_PATH setting. If called with an argument, this method will replace the existing INCLUDE_PATH with the new value. =head2 paths() This method generates a copy of the INCLUDE_PATH list. Any elements in the list which are dynamic generators (e.g. references to subroutines or objects implementing a paths() method) will be called and the list of directories returned merged into the output list. It is possible to provide a generator which returns itself, thus sending this method into an infinite loop. To detect and prevent this from happening, the C<$MAX_DIRS> package variable, set to 64 by default, limits the maximum number of paths that can be added to, or generated for the output list. If this number is exceeded then the method will immediately return an error reporting as much. =head1 AUTHOR Andy Wardley E<lt>abw@andywardley.comE<gt> L<http://www.andywardley.com/|http://www.andywardley.com/> =head1 VERSION 2.70, distributed as part of the Template Toolkit version 2.10, released on 24 July 2003. =head1 COPYRIGHT Copyright (C) 1996-2003 Andy Wardley. All Rights Reserved. Copyright (C) 1998-2002 Canon Research Centre Europe Ltd. This module is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =head1 SEE ALSO L<Template|Template>, L<Template::Parser|Template::Parser>, L<Template::Context|Template::Context> �������������������������������������������������������������������������������������vdradmin-am-3.6.13/lib/Template/Service.pm����������������������������������������������������������0000664�0000000�0000000�00000052573�14437161134�0020302�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#============================================================= -*-Perl-*- # # Template::Service # # DESCRIPTION # Module implementing a template processing service which wraps a # template within PRE_PROCESS and POST_PROCESS templates and offers # ERROR recovery. # # AUTHOR # Andy Wardley <abw@kfs.org> # # COPYRIGHT # Copyright (C) 1996-2000 Andy Wardley. All Rights Reserved. # Copyright (C) 1998-2000 Canon Research Centre Europe Ltd. # # This module is free software; you can redistribute it and/or # modify it under the same terms as Perl itself. # #---------------------------------------------------------------------------- # # $Id: Service.pm,v 2.70 2003/04/29 12:39:37 abw Exp $ # #============================================================================ package Template::Service; require 5.004; use strict; use vars qw( $VERSION $DEBUG $ERROR ); use base qw( Template::Base ); use Template::Base; use Template::Config; use Template::Exception; use Template::Constants; $VERSION = sprintf("%d.%02d", q$Revision: 2.70 $ =~ /(\d+)\.(\d+)/); $DEBUG = 0 unless defined $DEBUG; #======================================================================== # ----- PUBLIC METHODS ----- #======================================================================== #------------------------------------------------------------------------ # process($template, \%params) # # Process a template within a service framework. A service may encompass # PRE_PROCESS and POST_PROCESS templates and an ERROR hash which names # templates to be substituted for the main template document in case of # error. Each service invocation begins by resetting the state of the # context object via a call to reset(). The AUTO_RESET option may be set # to 0 (default: 1) to bypass this step. #------------------------------------------------------------------------ sub process { my ($self, $template, $params) = @_; my $context = $self->{ CONTEXT }; my ($name, $output, $procout, $error); $output = ''; $self->debug("process($template, ", defined $params ? $params : '<no params>', ')') if $self->{ DEBUG }; $context->reset() if $self->{ AUTO_RESET }; # pre-request compiled template from context so that we can alias it # in the stash for pre-processed templates to reference eval { $template = $context->template($template) }; return $self->error($@) if $@; # localise the variable stash with any parameters passed # and set the 'template' variable $params ||= { }; $params->{ template } = $template unless ref $template eq 'CODE'; $context->localise($params); SERVICE: { # PRE_PROCESS eval { foreach $name (@{ $self->{ PRE_PROCESS } }) { $self->debug("PRE_PROCESS: $name") if $self->{ DEBUG }; $output .= $context->process($name); } }; last SERVICE if ($error = $@); # PROCESS eval { foreach $name (@{ $self->{ PROCESS } || [ $template ] }) { $self->debug("PROCESS: $name") if $self->{ DEBUG }; $procout .= $context->process($name); } }; if ($error = $@) { last SERVICE unless defined ($procout = $self->_recover(\$error)); } if (defined $procout) { # WRAPPER eval { foreach $name (reverse @{ $self->{ WRAPPER } }) { $self->debug("WRAPPER: $name") if $self->{ DEBUG }; $procout = $context->process($name, { content => $procout }); } }; last SERVICE if ($error = $@); $output .= $procout; } # POST_PROCESS eval { foreach $name (@{ $self->{ POST_PROCESS } }) { $self->debug("POST_PROCESS: $name") if $self->{ DEBUG }; $output .= $context->process($name); } }; last SERVICE if ($error = $@); } $context->delocalise(); delete $params->{ template }; if ($error) { # $error = $error->as_string if ref $error; return $self->error($error); } return $output; } #------------------------------------------------------------------------ # context() # # Returns the internal CONTEXT reference. #------------------------------------------------------------------------ sub context { return $_[0]->{ CONTEXT }; } #======================================================================== # -- PRIVATE METHODS -- #======================================================================== sub _init { my ($self, $config) = @_; my ($item, $data, $context, $block, $blocks); my $delim = $config->{ DELIMITER }; $delim = ':' unless defined $delim; # coerce PRE_PROCESS, PROCESS and POST_PROCESS to arrays if necessary, # by splitting on non-word characters foreach $item (qw( PRE_PROCESS PROCESS POST_PROCESS WRAPPER )) { $data = $config->{ $item }; $self->{ $item } = [ ], next unless (defined $data); $data = [ split($delim, $data || '') ] unless ref $data eq 'ARRAY'; $self->{ $item } = $data; } # unset PROCESS option unless explicitly specified in config $self->{ PROCESS } = undef unless defined $config->{ PROCESS }; $self->{ ERROR } = $config->{ ERROR } || $config->{ ERRORS }; $self->{ AUTO_RESET } = defined $config->{ AUTO_RESET } ? $config->{ AUTO_RESET } : 1; $self->{ DEBUG } = ( $config->{ DEBUG } || 0 ) & Template::Constants::DEBUG_SERVICE; $context = $self->{ CONTEXT } = $config->{ CONTEXT } || Template::Config->context($config) || return $self->error(Template::Config->error); return $self; } #------------------------------------------------------------------------ # _recover(\$exception) # # Examines the internal ERROR hash array to find a handler suitable # for the exception object passed by reference. Selecting the handler # is done by delegation to the exception's select_handler() method, # passing the set of handler keys as arguments. A 'default' handler # may also be provided. The handler value represents the name of a # template which should be processed. #------------------------------------------------------------------------ sub _recover { my ($self, $error) = @_; my $context = $self->{ CONTEXT }; my ($hkey, $handler, $output); # there shouldn't ever be a non-exception object received at this # point... unless a module like CGI::Carp messes around with the # DIE handler. return undef unless (ref $$error); # a 'stop' exception is thrown by [% STOP %] - we return the output # buffer stored in the exception object return $$error->text() if $$error->type() eq 'stop'; my $handlers = $self->{ ERROR } || return undef; ## RETURN if (ref $handlers eq 'HASH') { if ($hkey = $$error->select_handler(keys %$handlers)) { $handler = $handlers->{ $hkey }; $self->debug("using error handler for $hkey") if $self->{ DEBUG }; } elsif ($handler = $handlers->{ default }) { # use default handler $self->debug("using default error handler") if $self->{ DEBUG }; } else { return undef; ## RETURN } } else { $handler = $handlers; $self->debug("using default error handler") if $self->{ DEBUG }; } eval { $handler = $context->template($handler) }; if ($@) { $$error = $@; return undef; ## RETURN }; $context->stash->set('error', $$error); eval { $output .= $context->process($handler); }; if ($@) { $$error = $@; return undef; ## RETURN } return $output; } #------------------------------------------------------------------------ # _dump() # # Debug method which return a string representing the internal object # state. #------------------------------------------------------------------------ sub _dump { my $self = shift; my $context = $self->{ CONTEXT }->_dump(); $context =~ s/\n/\n /gm; my $error = $self->{ ERROR }; $error = join('', "{\n", (map { " $_ => $error->{ $_ }\n" } keys %$error), "}\n") if ref $error; local $" = ', '; return <<EOF; $self PRE_PROCESS => [ @{ $self->{ PRE_PROCESS } } ] POST_PROCESS => [ @{ $self->{ POST_PROCESS } } ] ERROR => $error CONTEXT => $context EOF } 1; __END__ #------------------------------------------------------------------------ # IMPORTANT NOTE # This documentation is generated automatically from source # templates. Any changes you make here may be lost. # # The 'docsrc' documentation source bundle is available for download # from http://www.template-toolkit.org/docs.html and contains all # the source templates, XML files, scripts, etc., from which the # documentation for the Template Toolkit is built. #------------------------------------------------------------------------ =head1 NAME Template::Service - General purpose template processing service =head1 SYNOPSIS use Template::Service; my $service = Template::Service->new({ PRE_PROCESS => [ 'config', 'header' ], POST_PROCESS => 'footer', ERROR => { user => 'user/index.html', dbi => 'error/database', default => 'error/default', }, }); my $output = $service->process($template_name, \%replace) || die $service->error(), "\n"; =head1 DESCRIPTION The Template::Service module implements an object class for providing a consistent template processing service. Standard header (PRE_PROCESS) and footer (POST_PROCESS) templates may be specified which are prepended and appended to all templates processed by the service (but not any other templates or blocks INCLUDEd or PROCESSed from within). An ERROR hash may be specified which redirects the service to an alternate template file in the case of uncaught exceptions being thrown. This allows errors to be automatically handled by the service and a guaranteed valid response to be generated regardless of any processing problems encountered. A default Template::Service object is created by the Template module. Any Template::Service options may be passed to the Template new() constructor method and will be forwarded to the Template::Service constructor. use Template; my $template = Template->new({ PRE_PROCESS => 'header', POST_PROCESS => 'footer', }); Similarly, the Template::Service constructor will forward all configuration parameters onto other default objects (e.g. Template::Context) that it may need to instantiate. A Template::Service object (or subclass/derivative) can be explicitly instantiated and passed to the Template new() constructor method as the SERVICE item. use Template; use Template::Service; my $service = Template::Service->new({ PRE_PROCESS => 'header', POST_PROCESS => 'footer', }); my $template = Template->new({ SERVICE => $service, }); The Template::Service module can be sub-classed to create custom service handlers. use Template; use MyOrg::Template::Service; my $service = MyOrg::Template::Service->new({ PRE_PROCESS => 'header', POST_PROCESS => 'footer', COOL_OPTION => 'enabled in spades', }); my $template = Template->new({ SERVICE => $service, }); The Template module uses the Template::Config service() factory method to create a default service object when required. The $Template::Config::SERVICE package variable may be set to specify an alternate service module. This will be loaded automatically and its new() constructor method called by the service() factory method when a default service object is required. Thus the previous example could be written as: use Template; $Template::Config::SERVICE = 'MyOrg::Template::Service'; my $template = Template->new({ PRE_PROCESS => 'header', POST_PROCESS => 'footer', COOL_OPTION => 'enabled in spades', }); =head1 METHODS =head2 new(\%config) The new() constructor method is called to instantiate a Template::Service object. Configuration parameters may be specified as a HASH reference or as a list of (name =E<gt> value) pairs. my $service1 = Template::Service->new({ PRE_PROCESS => 'header', POST_PROCESS => 'footer', }); my $service2 = Template::Service->new( ERROR => 'error.html' ); The new() method returns a Template::Service object (or sub-class) or undef on error. In the latter case, a relevant error message can be retrieved by the error() class method or directly from the $Template::Service::ERROR package variable. my $service = Template::Service->new(\%config) || die Template::Service->error(); my $service = Template::Service->new(\%config) || die $Template::Service::ERROR; The following configuration items may be specified: =over 4 =item PRE_PROCESS, POST_PROCESS These values may be set to contain the name(s) of template files (relative to INCLUDE_PATH) which should be processed immediately before and/or after each template. These do not get added to templates processed into a document via directives such as INCLUDE, PROCESS, WRAPPER etc. my $service = Template::Service->new({ PRE_PROCESS => 'header', POST_PROCESS => 'footer', }; Multiple templates may be specified as a reference to a list. Each is processed in the order defined. my $service = Template::Service->new({ PRE_PROCESS => [ 'config', 'header' ], POST_PROCESS => 'footer', }; Alternately, multiple template may be specified as a single string, delimited by ':'. This delimiter string can be changed via the DELIMITER option. my $service = Template::Service->new({ PRE_PROCESS => 'config:header', POST_PROCESS => 'footer', }; The PRE_PROCESS and POST_PROCESS templates are evaluated in the same variable context as the main document and may define or update variables for subsequent use. config: [% # set some site-wide variables bgcolor = '#ffffff' version = 2.718 %] header: [% DEFAULT title = 'My Funky Web Site' %] <html> <head> <title>[% title %] footer:
Version [% version %] The Template::Document object representing the main template being processed is available within PRE_PROCESS and POST_PROCESS templates as the 'template' variable. Metadata items defined via the META directive may be accessed accordingly. $service->process('mydoc.html', $vars); mydoc.html: [% META title = 'My Document Title' %] blah blah blah ... header: [% template.title %] =item PROCESS The PROCESS option may be set to contain the name(s) of template files (relative to INCLUDE_PATH) which should be processed instead of the main template passed to the Template::Service process() method. This can be used to apply consistent wrappers around all templates, similar to the use of PRE_PROCESS and POST_PROCESS templates. my $service = Template::Service->new({ PROCESS => 'content', }; # processes 'content' instead of 'foo.html' $service->process('foo.html'); A reference to the original template is available in the 'template' variable. Metadata items can be inspected and the template can be processed by specifying it as a variable reference (i.e. prefixed by '$') to an INCLUDE, PROCESS or WRAPPER directive. content: [% template.title %] [% PROCESS $template %]
© Copyright [% template.copyright %] foo.html: [% META title = 'The Foo Page' author = 'Fred Foo' copyright = '2000 Fred Foo' %]

[% template.title %]

Welcome to the Foo Page, blah blah blah output: The Foo Page

The Foo Page

Welcome to the Foo Page, blah blah blah
© Copyright 2000 Fred Foo =item ERROR The ERROR (or ERRORS if you prefer) configuration item can be used to name a single template or specify a hash array mapping exception types to templates which should be used for error handling. If an uncaught exception is raised from within a template then the appropriate error template will instead be processed. If specified as a single value then that template will be processed for all uncaught exceptions. my $service = Template::Service->new({ ERROR => 'error.html' }); If the ERROR item is a hash reference the keys are assumed to be exception types and the relevant template for a given exception will be selected. A 'default' template may be provided for the general case. Note that 'ERROR' can be pluralised to 'ERRORS' if you find it more appropriate in this case. my $service = Template::Service->new({ ERRORS => { user => 'user/index.html', dbi => 'error/database', default => 'error/default', }, }); In this example, any 'user' exceptions thrown will cause the 'user/index.html' template to be processed, 'dbi' errors are handled by 'error/database' and all others by the 'error/default' template. Any PRE_PROCESS and/or POST_PROCESS templates will also be applied to these error templates. Note that exception types are hierarchical and a 'foo' handler will catch all 'foo.*' errors (e.g. foo.bar, foo.bar.baz) if a more specific handler isn't defined. Be sure to quote any exception types that contain periods to prevent Perl concatenating them into a single string (i.e. C is parsed as 'user'.'passwd'). my $service = Template::Service->new({ ERROR => { 'user.login' => 'user/login.html', 'user.passwd' => 'user/badpasswd.html', 'user' => 'user/index.html', 'default' => 'error/default', }, }); In this example, any template processed by the $service object, or other templates or code called from within, can raise a 'user.login' exception and have the service redirect to the 'user/login.html' template. Similarly, a 'user.passwd' exception has a specific handling template, 'user/badpasswd.html', while all other 'user' or 'user.*' exceptions cause a redirection to the 'user/index.html' page. All other exception types are handled by 'error/default'. Exceptions can be raised in a template using the THROW directive, [% THROW user.login 'no user id: please login' %] or by calling the throw() method on the current Template::Context object, $context->throw('user.passwd', 'Incorrect Password'); $context->throw('Incorrect Password'); # type 'undef' or from Perl code by calling die() with a Template::Exception object, die (Template::Exception->new('user.denied', 'Invalid User ID')); or by simply calling die() with an error string. This is automagically caught and converted to an exception of 'undef' type which can then be handled in the usual way. die "I'm sorry Dave, I can't do that"; =item AUTO_RESET The AUTO_RESET option is set by default and causes the local BLOCKS cache for the Template::Context object to be reset on each call to the Template process() method. This ensures that any BLOCKs defined within a template will only persist until that template is finished processing. This prevents BLOCKs defined in one processing request from interfering with other independent requests subsequently processed by the same context object. The BLOCKS item may be used to specify a default set of block definitions for the Template::Context object. Subsequent BLOCK definitions in templates will over-ride these but they will be reinstated on each reset if AUTO_RESET is enabled (default), or if the Template::Context reset() method is called. =item DEBUG The DEBUG option can be used to enable debugging messages from the Template::Service module by setting it to include the DEBUG_SERVICE value. use Template::Constants qw( :debug ); my $template = Template->new({ DEBUG => DEBUG_SERVICE, }); =back =head2 process($input, \%replace) The process() method is called to process a template specified as the first parameter, $input. This may be a file name, file handle (e.g. GLOB or IO::Handle) or a reference to a text string containing the template text. An additional hash reference may be passed containing template variable definitions. The method processes the template, adding any PRE_PROCESS or POST_PROCESS templates defined, and returns the output text. An uncaught exception thrown by the template will be handled by a relevant ERROR handler if defined. Errors that occur in the PRE_PROCESS or POST_PROCESS templates, or those that occur in the main input template and aren't handled, cause the method to return undef to indicate failure. The appropriate error message can be retrieved via the error() method. $service->process('myfile.html', { title => 'My Test File' }) || die $service->error(); =head2 context() Returns a reference to the internal context object which is, by default, an instance of the Template::Context class. =head2 error() Returns the most recent error message. =head1 AUTHOR Andy Wardley Eabw@andywardley.comE L =head1 VERSION 2.70, distributed as part of the Template Toolkit version 2.10, released on 24 July 2003. =head1 COPYRIGHT Copyright (C) 1996-2003 Andy Wardley. All Rights Reserved. Copyright (C) 1998-2002 Canon Research Centre Europe Ltd. This module is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =head1 SEE ALSO L, L vdradmin-am-3.6.13/lib/Template/Stash.pm000066400000000000000000000774041443716113400177640ustar00rootroot00000000000000#============================================================= -*-Perl-*- # # Template::Stash # # DESCRIPTION # Definition of an object class which stores and manages access to # variables for the Template Toolkit. # # AUTHOR # Andy Wardley # # COPYRIGHT # Copyright (C) 1996-2003 Andy Wardley. All Rights Reserved. # Copyright (C) 1998-2000 Canon Research Centre Europe Ltd. # # This module is free software; you can redistribute it and/or # modify it under the same terms as Perl itself. # #---------------------------------------------------------------------------- # # $Id: Stash.pm,v 2.78 2003/07/24 12:13:32 abw Exp $ # #============================================================================ package Template::Stash; require 5.004; use strict; use vars qw( $VERSION $DEBUG $ROOT_OPS $SCALAR_OPS $HASH_OPS $LIST_OPS ); $VERSION = sprintf("%d.%02d", q$Revision: 2.78 $ =~ /(\d+)\.(\d+)/); #======================================================================== # -- PACKAGE VARIABLES AND SUBS -- #======================================================================== #------------------------------------------------------------------------ # Definitions of various pseudo-methods. ROOT_OPS are merged into all # new Template::Stash objects, and are thus default global functions. # SCALAR_OPS are methods that can be called on a scalar, and ditto # respectively for LIST_OPS and HASH_OPS #------------------------------------------------------------------------ $ROOT_OPS = { 'inc' => sub { local $^W = 0; my $item = shift; ++$item }, 'dec' => sub { local $^W = 0; my $item = shift; --$item }, # import => \&hash_import, defined $ROOT_OPS ? %$ROOT_OPS : (), }; $SCALAR_OPS = { 'item' => sub { $_[0] }, 'list' => sub { [ $_[0] ] }, 'hash' => sub { { value => $_[0] } }, 'length' => sub { length $_[0] }, 'size' => sub { return 1 }, 'defined' => sub { return 1 }, 'repeat' => sub { my ($str, $count) = @_; $str = '' unless defined $str; $count ||= 1; return $str x $count; }, 'search' => sub { my ($str, $pattern) = @_; return $str unless defined $str and defined $pattern; return $str =~ /$pattern/; }, 'replace' => sub { my ($str, $search, $replace) = @_; $replace = '' unless defined $replace; return $str unless defined $str and defined $search; $str =~ s/$search/$replace/g; # print STDERR "s [ $search ] [ $replace ] g\n"; # eval "\$str =~ s$search$replaceg"; return $str; }, 'match' => sub { my ($str, $search) = @_; return $str unless defined $str and defined $search; my @matches = ($str =~ /$search/); return @matches ? \@matches : ''; }, 'split' => sub { my ($str, $split, @args) = @_; $str = '' unless defined $str; return [ defined $split ? split($split, $str, @args) : split(' ', $str, @args) ]; }, 'chunk' => sub { my ($string, $size) = @_; my @list; $size ||= 1; if ($size < 0) { # sexeger! It's faster to reverse the string, search # it from the front and then reverse the output than to # search it from the end, believe it nor not! $string = reverse $string; $size = -$size; unshift(@list, scalar reverse $1) while ($string =~ /((.{$size})|(.+))/g); } else { push(@list, $1) while ($string =~ /((.{$size})|(.+))/g); } return \@list; }, defined $SCALAR_OPS ? %$SCALAR_OPS : (), }; $HASH_OPS = { 'item' => sub { my ($hash, $item) = @_; $item = '' unless defined $item; $hash->{ $item }; }, 'hash' => sub { $_[0] }, 'size' => sub { scalar keys %{$_[0]} }, 'keys' => sub { [ keys %{ $_[0] } ] }, 'values' => sub { [ values %{ $_[0] } ] }, 'each' => sub { [ %{ $_[0] } ] }, 'list' => sub { my ($hash, $what) = @_; $what ||= ''; return ($what eq 'keys') ? [ keys %$hash ] : ($what eq 'values') ? [ values %$hash ] : ($what eq 'each') ? [ %$hash ] : [ map { { key => $_ , value => $hash->{ $_ } } } keys %$hash ]; }, 'exists' => sub { exists $_[0]->{ $_[1] } }, 'defined' => sub { defined $_[0]->{ $_[1] } }, 'import' => \&hash_import, 'sort' => sub { my ($hash) = @_; [ sort { lc $hash->{$a} cmp lc $hash->{$b} } (keys %$hash) ]; }, 'nsort' => sub { my ($hash) = @_; [ sort { $hash->{$a} <=> $hash->{$b} } (keys %$hash) ]; }, defined $HASH_OPS ? %$HASH_OPS : (), }; $LIST_OPS = { 'item' => sub { $_[0]->[ $_[1] || 0 ] }, 'list' => sub { $_[0] }, 'hash' => sub { my $list = shift; my $n = 0; return { map { ($n++, $_) } @$list }; }, 'push' => sub { my $list = shift; push(@$list, shift); return '' }, 'pop' => sub { my $list = shift; pop(@$list) }, 'unshift' => sub { my $list = shift; unshift(@$list, shift); return '' }, 'shift' => sub { my $list = shift; shift(@$list) }, 'max' => sub { local $^W = 0; my $list = shift; $#$list; }, 'size' => sub { local $^W = 0; my $list = shift; $#$list + 1; }, 'first' => sub { my $list = shift; return $list->[0] unless @_; return [ @$list[0..$_[0]-1] ]; }, 'last' => sub { my $list = shift; return $list->[-1] unless @_; return [ @$list[-$_[0]..-1] ]; }, 'reverse' => sub { my $list = shift; [ reverse @$list ] }, 'grep' => sub { my ($list, $pattern) = @_; $pattern ||= ''; return [ grep /$pattern/, @$list ]; }, 'join' => sub { my ($list, $joint) = @_; join(defined $joint ? $joint : ' ', map { defined $_ ? $_ : '' } @$list) }, 'sort' => sub { $^W = 0; my ($list, $field) = @_; return $list unless @$list > 1; # no need to sort 1 item lists return $field # Schwartzian Transform ? map { $_->[0] } # for case insensitivity sort { $a->[1] cmp $b->[1] } map { [ $_, lc(ref($_) eq 'HASH' ? $_->{ $field } : UNIVERSAL::can($_, $field) ? $_->$field() : $_) ] } @$list : map { $_->[0] } sort { $a->[1] cmp $b->[1] } map { [ $_, lc $_ ] } @$list }, 'nsort' => sub { my ($list, $field) = @_; return $list unless $#$list; # no need to sort 1 item lists return $field # Schwartzian Transform ? map { $_->[0] } # for case insensitivity sort { $a->[1] <=> $b->[1] } map { [ $_, lc(ref($_) eq 'HASH' ? $_->{ $field } : UNIVERSAL::can($_, $field) ? $_->$field() : $_) ] } @$list : map { $_->[0] } sort { $a->[1] <=> $b->[1] } map { [ $_, lc $_ ] } @$list }, 'unique' => sub { my %u; [ grep { ++$u{$_} == 1 } @{$_[0]} ] }, 'merge' => sub { my $list = shift; return [ @$list, grep defined, map ref eq 'ARRAY' ? @$_ : undef, @_ ]; }, 'slice' => sub { my ($list, $from, $to) = @_; $from ||= 0; $to = $#$list unless defined $to; return [ @$list[$from..$to] ]; }, 'splice' => sub { my ($list, $offset, $length, @replace) = @_; if (@replace) { # @replace can contain a list of multiple replace items, or # be a single reference to a list @replace = @{ $replace[0] } if @replace == 1 && ref $replace[0] eq 'ARRAY'; return [ splice @$list, $offset, $length, @replace ]; } elsif (defined $length) { return [ splice @$list, $offset, $length ]; } elsif (defined $offset) { return [ splice @$list, $offset ]; } else { return [ splice(@$list) ]; } }, defined $LIST_OPS ? %$LIST_OPS : (), }; sub hash_import { my ($hash, $imp) = @_; $imp = {} unless ref $imp eq 'HASH'; @$hash{ keys %$imp } = values %$imp; return ''; } #------------------------------------------------------------------------ # define_vmethod($type, $name, \&sub) # # Defines a virtual method of type $type (SCALAR, HASH, or LIST), with # name $name, that invokes &sub when called. It is expected that &sub # be able to handle the type that it will be called upon. #------------------------------------------------------------------------ sub define_vmethod { my ($class, $type, $name, $sub) = @_; my $op; $type = lc $type; if ($type =~ /^scalar|item$/) { $op = $SCALAR_OPS; } elsif ($type eq 'hash') { $op = $HASH_OPS; } elsif ($type =~ /^list|array$/) { $op = $LIST_OPS; } else { die "invalid vmethod type: $type\n"; } $op->{ $name } = $sub; return 1; } #======================================================================== # ----- CLASS METHODS ----- #======================================================================== #------------------------------------------------------------------------ # new(\%params) # # Constructor method which creates a new Template::Stash object. # An optional hash reference may be passed containing variable # definitions that will be used to initialise the stash. # # Returns a reference to a newly created Template::Stash. #------------------------------------------------------------------------ sub new { my $class = shift; my $params = ref $_[0] eq 'HASH' ? shift(@_) : { @_ }; my $self = { global => { }, %$params, %$ROOT_OPS, '_PARENT' => undef, }; bless $self, $class; } #======================================================================== # ----- PUBLIC OBJECT METHODS ----- #======================================================================== #------------------------------------------------------------------------ # clone(\%params) # # Creates a copy of the current stash object to effect localisation # of variables. The new stash is blessed into the same class as the # parent (which may be a derived class) and has a '_PARENT' member added # which contains a reference to the parent stash that created it # ($self). This member is used in a successive declone() method call to # return the reference to the parent. # # A parameter may be provided which should reference a hash of # variable/values which should be defined in the new stash. The # update() method is called to define these new variables in the cloned # stash. # # Returns a reference to a cloned Template::Stash. #------------------------------------------------------------------------ sub clone { my ($self, $params) = @_; $params ||= { }; # look out for magical 'import' argument which imports another hash my $import = $params->{ import }; if (defined $import && UNIVERSAL::isa($import, 'HASH')) { delete $params->{ import }; } else { undef $import; } my $clone = bless { %$self, # copy all parent members %$params, # copy all new data '_PARENT' => $self, # link to parent }, ref $self; # perform hash import if defined &{ $HASH_OPS->{ import }}($clone, $import) if defined $import; return $clone; } #------------------------------------------------------------------------ # declone($export) # # Returns a reference to the PARENT stash. When called in the following # manner: # $stash = $stash->declone(); # the reference count on the current stash will drop to 0 and be "freed" # and the caller will be left with a reference to the parent. This # contains the state of the stash before it was cloned. #------------------------------------------------------------------------ sub declone { my $self = shift; $self->{ _PARENT } || $self; } #------------------------------------------------------------------------ # get($ident) # # Returns the value for an variable stored in the stash. The variable # may be specified as a simple string, e.g. 'foo', or as an array # reference representing compound variables. In the latter case, each # pair of successive elements in the list represent a node in the # compound variable. The first is the variable name, the second a # list reference of arguments or 0 if undefined. So, the compound # variable [% foo.bar('foo').baz %] would be represented as the list # [ 'foo', 0, 'bar', ['foo'], 'baz', 0 ]. Returns the value of the # identifier or an empty string if undefined. Errors are thrown via # die(). #------------------------------------------------------------------------ sub get { my ($self, $ident, $args) = @_; my ($root, $result); $root = $self; if (ref $ident eq 'ARRAY' || ($ident =~ /\./) && ($ident = [ map { s/\(.*$//; ($_, 0) } split(/\./, $ident) ])) { my $size = $#$ident; # if $ident is a list reference, then we evaluate each item in the # identifier against the previous result, using the root stash # ($self) as the first implicit 'result'... foreach (my $i = 0; $i <= $size; $i += 2) { $result = $self->_dotop($root, @$ident[$i, $i+1]); last unless defined $result; $root = $result; } } else { $result = $self->_dotop($root, $ident, $args); } return defined $result ? $result : $self->undefined($ident, $args); } #------------------------------------------------------------------------ # set($ident, $value, $default) # # Updates the value for a variable in the stash. The first parameter # should be the variable name or array, as per get(). The second # parameter should be the intended value for the variable. The third, # optional parameter is a flag which may be set to indicate 'default' # mode. When set true, the variable will only be updated if it is # currently undefined or has a false value. The magical 'IMPORT' # variable identifier may be used to indicate that $value is a hash # reference whose values should be imported. Returns the value set, # or an empty string if not set (e.g. default mode). In the case of # IMPORT, returns the number of items imported from the hash. #------------------------------------------------------------------------ sub set { my ($self, $ident, $value, $default) = @_; my ($root, $result, $error); $root = $self; ELEMENT: { if (ref $ident eq 'ARRAY' || ($ident =~ /\./) && ($ident = [ map { s/\(.*$//; ($_, 0) } split(/\./, $ident) ])) { # a compound identifier may contain multiple elements (e.g. # foo.bar.baz) and we must first resolve all but the last, # using _dotop() with the $lvalue flag set which will create # intermediate hashes if necessary... my $size = $#$ident; foreach (my $i = 0; $i < $size - 2; $i += 2) { $result = $self->_dotop($root, @$ident[$i, $i+1], 1); last ELEMENT unless defined $result; $root = $result; } # then we call _assign() to assign the value to the last element $result = $self->_assign($root, @$ident[$size-1, $size], $value, $default); } else { $result = $self->_assign($root, $ident, 0, $value, $default); } } return defined $result ? $result : ''; } #------------------------------------------------------------------------ # getref($ident) # # Returns a "reference" to a particular item. This is represented as a # closure which will return the actual stash item when called. # WARNING: still experimental! #------------------------------------------------------------------------ sub getref { my ($self, $ident, $args) = @_; my ($root, $item, $result); $root = $self; if (ref $ident eq 'ARRAY') { my $size = $#$ident; foreach (my $i = 0; $i <= $size; $i += 2) { ($item, $args) = @$ident[$i, $i + 1]; last if $i >= $size - 2; # don't evaluate last node last unless defined ($root = $self->_dotop($root, $item, $args)); } } else { $item = $ident; } if (defined $root) { return sub { my @args = (@{$args||[]}, @_); $self->_dotop($root, $item, \@args); } } else { return sub { '' }; } } #------------------------------------------------------------------------ # update(\%params) # # Update multiple variables en masse. No magic is performed. Simple # variable names only. #------------------------------------------------------------------------ sub update { my ($self, $params) = @_; # look out for magical 'import' argument to import another hash my $import = $params->{ import }; if (defined $import && UNIVERSAL::isa($import, 'HASH')) { @$self{ keys %$import } = values %$import; delete $params->{ import }; } @$self{ keys %$params } = values %$params; } #------------------------------------------------------------------------ # undefined($ident, $args) # # Method called when a get() returns an undefined value. Can be redefined # in a subclass to implement alternate handling. #------------------------------------------------------------------------ sub undefined { my ($self, $ident, $args); return ''; } #======================================================================== # ----- PRIVATE OBJECT METHODS ----- #======================================================================== #------------------------------------------------------------------------ # _dotop($root, $item, \@args, $lvalue) # # This is the core 'dot' operation method which evaluates elements of # variables against their root. All variables have an implicit root # which is the stash object itself (a hash). Thus, a non-compound # variable 'foo' is actually '(stash.)foo', the compound 'foo.bar' is # '(stash.)foo.bar'. The first parameter is a reference to the current # root, initially the stash itself. The second parameter contains the # name of the variable element, e.g. 'foo'. The third optional # parameter is a reference to a list of any parenthesised arguments # specified for the variable, which are passed to sub-routines, object # methods, etc. The final parameter is an optional flag to indicate # if this variable is being evaluated on the left side of an assignment # (e.g. foo.bar.baz = 10). When set true, intermediated hashes will # be created (e.g. bar) if necessary. # # Returns the result of evaluating the item against the root, having # performed any variable "magic". The value returned can then be used # as the root of the next _dotop() in a compound sequence. Returns # undef if the variable is undefined. #------------------------------------------------------------------------ sub _dotop { my ($self, $root, $item, $args, $lvalue) = @_; my $rootref = ref $root; my $atroot = ($root eq $self); my ($value, @result); $args ||= [ ]; $lvalue ||= 0; # print STDERR "_dotop(root=$root, item=$item, args=[@$args])\n" # if $DEBUG; # return undef without an error if either side of the dot is unviable # or if an attempt is made to access a private member, starting _ or . return undef unless defined($root) and defined($item) and $item !~ /^[\._]/; if ($atroot || $rootref eq 'HASH') { # if $root is a regular HASH or a Template::Stash kinda HASH (the # *real* root of everything). We first lookup the named key # in the hash, or create an empty hash in its place if undefined # and the $lvalue flag is set. Otherwise, we check the HASH_OPS # pseudo-methods table, calling the code if found, or return undef. if (defined($value = $root->{ $item })) { return $value unless ref $value eq 'CODE'; ## RETURN @result = &$value(@$args); ## @result } elsif ($lvalue) { # we create an intermediate hash if this is an lvalue return $root->{ $item } = { }; ## RETURN } # ugly hack: only allow import vmeth to be called on root stash elsif (($value = $HASH_OPS->{ $item }) && ! $atroot || $item eq 'import') { @result = &$value($root, @$args); ## @result } elsif ( ref $item eq 'ARRAY' ) { # hash slice return [@$root{@$item}]; ## RETURN } } elsif ($rootref eq 'ARRAY') { # if root is an ARRAY then we check for a LIST_OPS pseudo-method # (except for l-values for which it doesn't make any sense) # or return the numerical index into the array, or undef if (($value = $LIST_OPS->{ $item }) && ! $lvalue) { @result = &$value($root, @$args); ## @result } elsif ($item =~ /^-?\d+$/) { $value = $root->[$item]; return $value unless ref $value eq 'CODE'; ## RETURN @result = &$value(@$args); ## @result } elsif ( ref $item eq 'ARRAY' ) { # array slice return [@$root[@$item]]; ## RETURN } } # NOTE: we do the can-can because UNIVSERAL::isa($something, 'UNIVERSAL') # doesn't appear to work with CGI, returning true for the first call # and false for all subsequent calls. elsif (ref($root) && UNIVERSAL::can($root, 'can')) { # if $root is a blessed reference (i.e. inherits from the # UNIVERSAL object base class) then we call the item as a method. # If that fails then we try to fallback on HASH behaviour if # possible. eval { @result = $root->$item(@$args); }; if ($@) { # temporary hack - required to propogate errors thrown # by views; if $@ is a ref (e.g. Template::Exception # object then we assume it's a real error that needs # real throwing die $@ if ref($@) || ($@ !~ /Can't locate object method/); # failed to call object method, so try some fallbacks if (UNIVERSAL::isa($root, 'HASH') && defined($value = $root->{ $item })) { return $value unless ref $value eq 'CODE'; ## RETURN @result = &$value(@$args); } elsif (UNIVERSAL::isa($root, 'ARRAY') && ($value = $LIST_OPS->{ $item })) { @result = &$value($root, @$args); } elsif ($value = $SCALAR_OPS->{ $item }) { @result = &$value($root, @$args); } elsif ($value = $LIST_OPS->{ $item }) { @result = &$value([$root], @$args); } elsif ($self->{ _DEBUG }) { @result = (undef, $@); } } } elsif (($value = $SCALAR_OPS->{ $item }) && ! $lvalue) { # at this point, it doesn't look like we've got a reference to # anything we know about, so we try the SCALAR_OPS pseudo-methods # table (but not for l-values) @result = &$value($root, @$args); ## @result } elsif (($value = $LIST_OPS->{ $item }) && ! $lvalue) { # last-ditch: can we promote a scalar to a one-element # list and apply a LIST_OPS virtual method? @result = &$value([$root], @$args); } elsif ($self->{ _DEBUG }) { die "don't know how to access [ $root ].$item\n"; ## DIE } else { @result = (); } # fold multiple return items into a list unless first item is undef if (defined $result[0]) { return ## RETURN scalar @result > 1 ? [ @result ] : $result[0]; } elsif (defined $result[1]) { die $result[1]; ## DIE } elsif ($self->{ _DEBUG }) { die "$item is undefined\n"; ## DIE } return undef; } #------------------------------------------------------------------------ # _assign($root, $item, \@args, $value, $default) # # Similar to _dotop() above, but assigns a value to the given variable # instead of simply returning it. The first three parameters are the # root item, the item and arguments, as per _dotop(), followed by the # value to which the variable should be set and an optional $default # flag. If set true, the variable will only be set if currently false # (undefined/zero) #------------------------------------------------------------------------ sub _assign { my ($self, $root, $item, $args, $value, $default) = @_; my $rootref = ref $root; my $atroot = ($root eq $self); my $result; $args ||= [ ]; $default ||= 0; # print(STDERR "_assign(root=$root, item=$item, args=[@$args], \n", # "value=$value, default=$default)\n") # if $DEBUG; # return undef without an error if either side of the dot is unviable # or if an attempt is made to update a private member, starting _ or . return undef ## RETURN unless $root and defined $item and $item !~ /^[\._]/; if ($rootref eq 'HASH' || $atroot) { # if ($item eq 'IMPORT' && UNIVERSAL::isa($value, 'HASH')) { # # import hash entries into root hash # @$root{ keys %$value } = values %$value; # return ''; ## RETURN # } # if the root is a hash we set the named key return ($root->{ $item } = $value) ## RETURN unless $default && $root->{ $item }; } elsif ($rootref eq 'ARRAY' && $item =~ /^-?\d+$/) { # or set a list item by index number return ($root->[$item] = $value) ## RETURN unless $default && $root->{ $item }; } elsif (UNIVERSAL::isa($root, 'UNIVERSAL')) { # try to call the item as a method of an object return $root->$item(@$args, $value) ## RETURN unless $default && $root->$item(); # 2 issues: # - method call should be wrapped in eval { } # - fallback on hash methods if object method not found # # eval { $result = $root->$item(@$args, $value); }; # # if ($@) { # die $@ if ref($@) || ($@ !~ /Can't locate object method/); # # # failed to call object method, so try some fallbacks # if (UNIVERSAL::isa($root, 'HASH') && exists $root->{ $item }) { # $result = ($root->{ $item } = $value) # unless $default && $root->{ $item }; # } # } # return $result; ## RETURN } else { die "don't know how to assign to [$root].[$item]\n"; ## DIE } return undef; } #------------------------------------------------------------------------ # _dump() # # Debug method which returns a string representing the internal state # of the object. The method calls itself recursively to dump sub-hashes. #------------------------------------------------------------------------ sub _dump { my $self = shift; return "[Template::Stash] " . $self->_dump_frame(2); } sub _dump_frame { my ($self, $indent) = @_; $indent ||= 1; my $buffer = ' '; my $pad = $buffer x $indent; my $text = "{\n"; local $" = ', '; my ($key, $value); return $text . "...excessive recursion, terminating\n" if $indent > 32; foreach $key (keys %$self) { $value = $self->{ $key }; $value = '' unless defined $value; next if $key =~ /^\./; if (ref($value) eq 'ARRAY') { $value = '[ ' . join(', ', map { defined $_ ? $_ : '' } @$value) . ' ]'; } elsif (ref $value eq 'HASH') { $value = _dump_frame($value, $indent + 1); } $text .= sprintf("$pad%-16s => $value\n", $key); } $text .= $buffer x ($indent - 1) . '}'; return $text; } 1; __END__ #------------------------------------------------------------------------ # IMPORTANT NOTE # This documentation is generated automatically from source # templates. Any changes you make here may be lost. # # The 'docsrc' documentation source bundle is available for download # from http://www.template-toolkit.org/docs.html and contains all # the source templates, XML files, scripts, etc., from which the # documentation for the Template Toolkit is built. #------------------------------------------------------------------------ =head1 NAME Template::Stash - Magical storage for template variables =head1 SYNOPSIS use Template::Stash; my $stash = Template::Stash->new(\%vars); # get variable values $value = $stash->get($variable); $value = $stash->get(\@compound); # set variable value $stash->set($variable, $value); $stash->set(\@compound, $value); # default variable value $stash->set($variable, $value, 1); $stash->set(\@compound, $value, 1); # set variable values en masse $stash->update(\%new_vars) # methods for (de-)localising variables $stash = $stash->clone(\%new_vars); $stash = $stash->declone(); =head1 DESCRIPTION The Template::Stash module defines an object class which is used to store variable values for the runtime use of the template processor. Variable values are stored internally in a hash reference (which itself is blessed to create the object) and are accessible via the get() and set() methods. Variables may reference hash arrays, lists, subroutines and objects as well as simple values. The stash automatically performs the right magic when dealing with variables, calling code or object methods, indexing into lists, hashes, etc. The stash has clone() and declone() methods which are used by the template processor to make temporary copies of the stash for localising changes made to variables. =head1 PUBLIC METHODS =head2 new(\%params) The new() constructor method creates and returns a reference to a new Template::Stash object. my $stash = Template::Stash->new(); A hash reference may be passed to provide variables and values which should be used to initialise the stash. my $stash = Template::Stash->new({ var1 => 'value1', var2 => 'value2' }); =head2 get($variable) The get() method retrieves the variable named by the first parameter. $value = $stash->get('var1'); Dotted compound variables can be retrieved by specifying the variable elements by reference to a list. Each node in the variable occupies two entries in the list. The first gives the name of the variable element, the second is a reference to a list of arguments for that element, or 0 if none. [% foo.bar(10).baz(20) %] $stash->get([ 'foo', 0, 'bar', [ 10 ], 'baz', [ 20 ] ]); =head2 set($variable, $value, $default) The set() method sets the variable name in the first parameter to the value specified in the second. $stash->set('var1', 'value1'); If the third parameter evaluates to a true value, the variable is set only if it did not have a true value before. $stash->set('var2', 'default_value', 1); Dotted compound variables may be specified as per get() above. [% foo.bar = 30 %] $stash->set([ 'foo', 0, 'bar', 0 ], 30); The magical variable 'IMPORT' can be specified whose corresponding value should be a hash reference. The contents of the hash array are copied (i.e. imported) into the current namespace. # foo.bar = baz, foo.wiz = waz $stash->set('foo', { 'bar' => 'baz', 'wiz' => 'waz' }); # import 'foo' into main namespace: foo = baz, wiz = waz $stash->set('IMPORT', $stash->get('foo')); =head2 clone(\%params) The clone() method creates and returns a new Template::Stash object which represents a localised copy of the parent stash. Variables can be freely updated in the cloned stash and when declone() is called, the original stash is returned with all its members intact and in the same state as they were before clone() was called. For convenience, a hash of parameters may be passed into clone() which is used to update any simple variable (i.e. those that don't contain any namespace elements like 'foo' and 'bar' but not 'foo.bar') variables while cloning the stash. For adding and updating complex variables, the set() method should be used after calling clone(). This will correctly resolve and/or create any necessary namespace hashes. A cloned stash maintains a reference to the stash that it was copied from in its '_PARENT' member. =head2 declone() The declone() method returns the '_PARENT' reference and can be used to restore the state of a stash as described above. =head1 AUTHOR Andy Wardley Eabw@andywardley.comE L =head1 VERSION 2.78, distributed as part of the Template Toolkit version 2.10, released on 24 July 2003. =head1 COPYRIGHT Copyright (C) 1996-2003 Andy Wardley. All Rights Reserved. Copyright (C) 1998-2002 Canon Research Centre Europe Ltd. This module is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =head1 SEE ALSO L, L vdradmin-am-3.6.13/lib/Template/Stash/000077500000000000000000000000001443716113400174125ustar00rootroot00000000000000vdradmin-am-3.6.13/lib/Template/Stash/Context.pm000066400000000000000000000642351443716113400214060ustar00rootroot00000000000000#============================================================= -*-Perl-*- # # Template::Stash::Context # # DESCRIPTION # This is an alternate stash object which includes a patch from # Craig Barratt to implement various new virtual methods to allow # dotted template variable to denote if object methods and subroutines # should be called in scalar or list context. It adds a little overhead # to each stash call and I'm a little wary of doing that. So for now, # it's implemented as a separate stash module which will allow us to # test it out, benchmark it and switch it in or out as we require. # # This is what Craig has to say about it: # # Here's a better set of features for the core. Attached is a new version # of Stash.pm (based on TT2.02) that: # # - supports the special op "scalar" that forces scalar context on # function calls, eg: # # cgi.param("foo").scalar # # calls cgi.param("foo") in scalar context (unlike my wimpy # scalar op from last night). Array context is the default. # # With non-function operands, scalar behaves like the perl # version (eg: no-op for scalar, size for arrays, etc). # # - supports the special op "ref" that behaves like the perl ref. # If applied to a function the function is not called. Eg: # # cgi.param("foo").ref # # does *not* call cgi.param and evaluates to "CODE". Similarly, # HASH.ref, ARRAY.ref return what you expect. # # - adds a new scalar and list op called "array" that is a no-op for # arrays and promotes scalars to one-element arrays. # # - allows scalar ops to be applied to arrays and hashes in place, # eg: ARRAY.repeat(3) repeats each element in place. # # - allows list ops to be applied to scalars by promoting the scalars # to one-element arrays (like an implicit "array"). So you can # do things like SCALAR.size, SCALAR.join and get a useful result. # # This also means you can now use x.0 to safely get the first element # whether x is an array or scalar. # # The new Stash.pm passes the TT2.02 test suite. But I haven't tested the # new features very much. One nagging implementation problem is that the # "scalar" and "ref" ops have higher precedence than user variable names. # # AUTHORS # Andy Wardley # Craig Barratt # # COPYRIGHT # Copyright (C) 1996-2001 Andy Wardley. All Rights Reserved. # Copyright (C) 1998-2001 Canon Research Centre Europe Ltd. # # This module is free software; you can redistribute it and/or # modify it under the same terms as Perl itself. # #---------------------------------------------------------------------------- # # $Id: Context.pm,v 1.53 2003/04/24 09:14:47 abw Exp $ # #============================================================================ package Template::Stash::Context; require 5.004; use strict; use Template::Stash; use vars qw( $VERSION $DEBUG $ROOT_OPS $SCALAR_OPS $HASH_OPS $LIST_OPS ); $VERSION = sprintf("%d.%02d", q$Revision: 1.53 $ =~ /(\d+)\.(\d+)/); #======================================================================== # -- PACKAGE VARIABLES AND SUBS -- #======================================================================== #------------------------------------------------------------------------ # copy virtual methods from those in the regular Template::Stash #------------------------------------------------------------------------ $ROOT_OPS = { %$Template::Stash::ROOT_OPS, defined $ROOT_OPS ? %$ROOT_OPS : (), }; $SCALAR_OPS = { %$Template::Stash::SCALAR_OPS, 'array' => sub { return [$_[0]] }, defined $SCALAR_OPS ? %$SCALAR_OPS : (), }; $LIST_OPS = { %$Template::Stash::LIST_OPS, 'array' => sub { return $_[0] }, defined $LIST_OPS ? %$LIST_OPS : (), }; $HASH_OPS = { %$Template::Stash::HASH_OPS, defined $HASH_OPS ? %$HASH_OPS : (), }; #======================================================================== # ----- CLASS METHODS ----- #======================================================================== #------------------------------------------------------------------------ # new(\%params) # # Constructor method which creates a new Template::Stash object. # An optional hash reference may be passed containing variable # definitions that will be used to initialise the stash. # # Returns a reference to a newly created Template::Stash. #------------------------------------------------------------------------ sub new { my $class = shift; my $params = ref $_[0] eq 'HASH' ? shift(@_) : { @_ }; my $self = { global => { }, %$params, %$ROOT_OPS, '_PARENT' => undef, }; bless $self, $class; } #======================================================================== # ----- PUBLIC OBJECT METHODS ----- #======================================================================== #------------------------------------------------------------------------ # clone(\%params) # # Creates a copy of the current stash object to effect localisation # of variables. The new stash is blessed into the same class as the # parent (which may be a derived class) and has a '_PARENT' member added # which contains a reference to the parent stash that created it # ($self). This member is used in a successive declone() method call to # return the reference to the parent. # # A parameter may be provided which should reference a hash of # variable/values which should be defined in the new stash. The # update() method is called to define these new variables in the cloned # stash. # # Returns a reference to a cloned Template::Stash. #------------------------------------------------------------------------ sub clone { my ($self, $params) = @_; $params ||= { }; # look out for magical 'import' argument which imports another hash my $import = $params->{ import }; if (defined $import && UNIVERSAL::isa($import, 'HASH')) { delete $params->{ import }; } else { undef $import; } my $clone = bless { %$self, # copy all parent members %$params, # copy all new data '_PARENT' => $self, # link to parent }, ref $self; # perform hash import if defined &{ $HASH_OPS->{ import }}($clone, $import) if defined $import; return $clone; } #------------------------------------------------------------------------ # declone($export) # # Returns a reference to the PARENT stash. When called in the following # manner: # $stash = $stash->declone(); # the reference count on the current stash will drop to 0 and be "freed" # and the caller will be left with a reference to the parent. This # contains the state of the stash before it was cloned. #------------------------------------------------------------------------ sub declone { my $self = shift; $self->{ _PARENT } || $self; } #------------------------------------------------------------------------ # get($ident) # # Returns the value for an variable stored in the stash. The variable # may be specified as a simple string, e.g. 'foo', or as an array # reference representing compound variables. In the latter case, each # pair of successive elements in the list represent a node in the # compound variable. The first is the variable name, the second a # list reference of arguments or 0 if undefined. So, the compound # variable [% foo.bar('foo').baz %] would be represented as the list # [ 'foo', 0, 'bar', ['foo'], 'baz', 0 ]. Returns the value of the # identifier or an empty string if undefined. Errors are thrown via # die(). #------------------------------------------------------------------------ sub get { my ($self, $ident, $args) = @_; my ($root, $result); $root = $self; if (ref $ident eq 'ARRAY' || ($ident =~ /\./) && ($ident = [ map { s/\(.*$//; ($_, 0) } split(/\./, $ident) ])) { my $size = $#$ident; # if $ident is a list reference, then we evaluate each item in the # identifier against the previous result, using the root stash # ($self) as the first implicit 'result'... foreach (my $i = 0; $i <= $size; $i += 2) { if ( $i + 2 <= $size && ($ident->[$i+2] eq "scalar" || $ident->[$i+2] eq "ref") ) { $result = $self->_dotop($root, @$ident[$i, $i+1], 0, $ident->[$i+2]); $i += 2; } else { $result = $self->_dotop($root, @$ident[$i, $i+1]); } last unless defined $result; $root = $result; } } else { $result = $self->_dotop($root, $ident, $args); } return defined $result ? $result : ''; } #------------------------------------------------------------------------ # set($ident, $value, $default) # # Updates the value for a variable in the stash. The first parameter # should be the variable name or array, as per get(). The second # parameter should be the intended value for the variable. The third, # optional parameter is a flag which may be set to indicate 'default' # mode. When set true, the variable will only be updated if it is # currently undefined or has a false value. The magical 'IMPORT' # variable identifier may be used to indicate that $value is a hash # reference whose values should be imported. Returns the value set, # or an empty string if not set (e.g. default mode). In the case of # IMPORT, returns the number of items imported from the hash. #------------------------------------------------------------------------ sub set { my ($self, $ident, $value, $default) = @_; my ($root, $result, $error); $root = $self; ELEMENT: { if (ref $ident eq 'ARRAY' || ($ident =~ /\./) && ($ident = [ map { s/\(.*$//; ($_, 0) } split(/\./, $ident) ])) { # a compound identifier may contain multiple elements (e.g. # foo.bar.baz) and we must first resolve all but the last, # using _dotop() with the $lvalue flag set which will create # intermediate hashes if necessary... my $size = $#$ident; foreach (my $i = 0; $i < $size - 2; $i += 2) { $result = $self->_dotop($root, @$ident[$i, $i+1], 1); last ELEMENT unless defined $result; $root = $result; } # then we call _assign() to assign the value to the last element $result = $self->_assign($root, @$ident[$size-1, $size], $value, $default); } else { $result = $self->_assign($root, $ident, 0, $value, $default); } } return defined $result ? $result : ''; } #------------------------------------------------------------------------ # getref($ident) # # Returns a "reference" to a particular item. This is represented as a # closure which will return the actual stash item when called. # WARNING: still experimental! #------------------------------------------------------------------------ sub getref { my ($self, $ident, $args) = @_; my ($root, $item, $result); $root = $self; if (ref $ident eq 'ARRAY') { my $size = $#$ident; foreach (my $i = 0; $i <= $size; $i += 2) { ($item, $args) = @$ident[$i, $i + 1]; last if $i >= $size - 2; # don't evaluate last node last unless defined ($root = $self->_dotop($root, $item, $args)); } } else { $item = $ident; } if (defined $root) { return sub { my @args = (@{$args||[]}, @_); $self->_dotop($root, $item, \@args); } } else { return sub { '' }; } } #------------------------------------------------------------------------ # update(\%params) # # Update multiple variables en masse. No magic is performed. Simple # variable names only. #------------------------------------------------------------------------ sub update { my ($self, $params) = @_; # look out for magical 'import' argument to import another hash my $import = $params->{ import }; if (defined $import && UNIVERSAL::isa($import, 'HASH')) { @$self{ keys %$import } = values %$import; delete $params->{ import }; } @$self{ keys %$params } = values %$params; } #======================================================================== # ----- PRIVATE OBJECT METHODS ----- #======================================================================== #------------------------------------------------------------------------ # _dotop($root, $item, \@args, $lvalue, $nextItem) # # This is the core 'dot' operation method which evaluates elements of # variables against their root. All variables have an implicit root # which is the stash object itself (a hash). Thus, a non-compound # variable 'foo' is actually '(stash.)foo', the compound 'foo.bar' is # '(stash.)foo.bar'. The first parameter is a reference to the current # root, initially the stash itself. The second parameter contains the # name of the variable element, e.g. 'foo'. The third optional # parameter is a reference to a list of any parenthesised arguments # specified for the variable, which are passed to sub-routines, object # methods, etc. The final parameter is an optional flag to indicate # if this variable is being evaluated on the left side of an assignment # (e.g. foo.bar.baz = 10). When set true, intermediated hashes will # be created (e.g. bar) if necessary. # # Returns the result of evaluating the item against the root, having # performed any variable "magic". The value returned can then be used # as the root of the next _dotop() in a compound sequence. Returns # undef if the variable is undefined. #------------------------------------------------------------------------ sub _dotop { my ($self, $root, $item, $args, $lvalue, $nextItem) = @_; my $rootref = ref $root; my ($value, @result, $ret, $retVal); $nextItem ||= ""; my $scalarContext = 1 if ( $nextItem eq "scalar" ); my $returnRef = 1 if ( $nextItem eq "ref" ); $args ||= [ ]; $lvalue ||= 0; # print STDERR "_dotop(root=$root, item=$item, args=[@$args])\n" # if $DEBUG; # return undef without an error if either side of the dot is unviable # or if an attempt is made to access a private member, starting _ or . return undef unless defined($root) and defined($item) and $item !~ /^[\._]/; if (ref(\$root) eq "SCALAR" && !$lvalue && (($value = $LIST_OPS->{ $item }) || $item =~ /^-?\d+$/) ) { # # Promote scalar to one element list, to be processed below. # $rootref = 'ARRAY'; $root = [$root]; } if ($rootref eq __PACKAGE__ || $rootref eq 'HASH') { # if $root is a regular HASH or a Template::Stash kinda HASH (the # *real* root of everything). We first lookup the named key # in the hash, or create an empty hash in its place if undefined # and the $lvalue flag is set. Otherwise, we check the HASH_OPS # pseudo-methods table, calling the code if found, or return undef. if (defined($value = $root->{ $item })) { ($ret, $retVal, @result) = _dotop_return($value, $args, $returnRef, $scalarContext); return $retVal if ( $ret ); ## RETURN } elsif ($lvalue) { # we create an intermediate hash if this is an lvalue return $root->{ $item } = { }; ## RETURN } elsif ($value = $HASH_OPS->{ $item }) { @result = &$value($root, @$args); ## @result } elsif (ref $item eq 'ARRAY') { # hash slice return [@$root{@$item}]; ## RETURN } elsif ($value = $SCALAR_OPS->{ $item }) { # # Apply scalar ops to every hash element, in place. # foreach my $key ( keys %$root ) { $root->{$key} = &$value($root->{$key}, @$args); } } } elsif ($rootref eq 'ARRAY') { # if root is an ARRAY then we check for a LIST_OPS pseudo-method # (except for l-values for which it doesn't make any sense) # or return the numerical index into the array, or undef if (($value = $LIST_OPS->{ $item }) && ! $lvalue) { @result = &$value($root, @$args); ## @result } elsif (($value = $SCALAR_OPS->{ $item }) && ! $lvalue) { # # Apply scalar ops to every array element, in place. # for ( my $i = 0 ; $i < @$root ; $i++ ) { $root->[$i] = &$value($root->[$i], @$args); ## @result } } elsif ($item =~ /^-?\d+$/) { $value = $root->[$item]; ($ret, $retVal, @result) = _dotop_return($value, $args, $returnRef, $scalarContext); return $retVal if ( $ret ); ## RETURN } elsif (ref $item eq 'ARRAY' ) { # array slice return [@$root[@$item]]; ## RETURN } } # NOTE: we do the can-can because UNIVSERAL::isa($something, 'UNIVERSAL') # doesn't appear to work with CGI, returning true for the first call # and false for all subsequent calls. elsif (ref($root) && UNIVERSAL::can($root, 'can')) { # if $root is a blessed reference (i.e. inherits from the # UNIVERSAL object base class) then we call the item as a method. # If that fails then we try to fallback on HASH behaviour if # possible. return ref $root->can($item) if ( $returnRef ); ## RETURN eval { @result = $scalarContext ? scalar $root->$item(@$args) : $root->$item(@$args); ## @result }; if ($@) { # failed to call object method, so try some fallbacks if (UNIVERSAL::isa($root, 'HASH') && defined($value = $root->{ $item })) { ($ret, $retVal, @result) = _dotop_return($value, $args, $returnRef, $scalarContext); return $retVal if ( $ret ); ## RETURN } elsif (UNIVERSAL::isa($root, 'ARRAY') && ($value = $LIST_OPS->{ $item })) { @result = &$value($root, @$args); } else { @result = (undef, $@); } } } elsif (($value = $SCALAR_OPS->{ $item }) && ! $lvalue) { # at this point, it doesn't look like we've got a reference to # anything we know about, so we try the SCALAR_OPS pseudo-methods # table (but not for l-values) @result = &$value($root, @$args); ## @result } elsif ($self->{ _DEBUG }) { die "don't know how to access [ $root ].$item\n"; ## DIE } else { @result = (); } # fold multiple return items into a list unless first item is undef if (defined $result[0]) { return ref(@result > 1 ? [ @result ] : $result[0]) if ( $returnRef ); ## RETURN if ( $scalarContext ) { return scalar @result if ( @result > 1 ); ## RETURN return scalar(@{$result[0]}) if ( ref $result[0] eq "ARRAY" ); return scalar(%{$result[0]}) if ( ref $result[0] eq "HASH" ); return $result[0]; ## RETURN } else { return @result > 1 ? [ @result ] : $result[0]; ## RETURN } } elsif (defined $result[1]) { die $result[1]; ## DIE } elsif ($self->{ _DEBUG }) { die "$item is undefined\n"; ## DIE } return undef; } #------------------------------------------------------------------------ # ($ret, $retVal, @result) = _dotop_return($value, $args, $returnRef, # $scalarContext); # # Handle the various return processing for _dotop #------------------------------------------------------------------------ sub _dotop_return { my($value, $args, $returnRef, $scalarContext) = @_; my(@result); return (1, ref $value) if ( $returnRef ); ## RETURN if ( $scalarContext ) { return (1, scalar(@$value)) if ref $value eq 'ARRAY'; ## RETURN return (1, scalar(%$value)) if ref $value eq 'HASH'; ## RETURN return (1, scalar($value)) unless ref $value eq 'CODE'; ## RETURN; @result = scalar &$value(@$args) ## @result; } else { return (1, $value) unless ref $value eq 'CODE'; ## RETURN @result = &$value(@$args); ## @result } return (0, undef, @result); } #------------------------------------------------------------------------ # _assign($root, $item, \@args, $value, $default) # # Similar to _dotop() above, but assigns a value to the given variable # instead of simply returning it. The first three parameters are the # root item, the item and arguments, as per _dotop(), followed by the # value to which the variable should be set and an optional $default # flag. If set true, the variable will only be set if currently false # (undefined/zero) #------------------------------------------------------------------------ sub _assign { my ($self, $root, $item, $args, $value, $default) = @_; my $rootref = ref $root; my $result; $args ||= [ ]; $default ||= 0; # print(STDERR "_assign(root=$root, item=$item, args=[@$args], \n", # "value=$value, default=$default)\n") # if $DEBUG; # return undef without an error if either side of the dot is unviable # or if an attempt is made to update a private member, starting _ or . return undef ## RETURN unless $root and defined $item and $item !~ /^[\._]/; if ($rootref eq 'HASH' || $rootref eq __PACKAGE__) { # if ($item eq 'IMPORT' && UNIVERSAL::isa($value, 'HASH')) { # # import hash entries into root hash # @$root{ keys %$value } = values %$value; # return ''; ## RETURN # } # if the root is a hash we set the named key return ($root->{ $item } = $value) ## RETURN unless $default && $root->{ $item }; } elsif ($rootref eq 'ARRAY' && $item =~ /^-?\d+$/) { # or set a list item by index number return ($root->[$item] = $value) ## RETURN unless $default && $root->{ $item }; } elsif (UNIVERSAL::isa($root, 'UNIVERSAL')) { # try to call the item as a method of an object return $root->$item(@$args, $value); ## RETURN } else { die "don't know how to assign to [$root].[$item]\n"; ## DIE } return undef; } #------------------------------------------------------------------------ # _dump() # # Debug method which returns a string representing the internal state # of the object. The method calls itself recursively to dump sub-hashes. #------------------------------------------------------------------------ sub _dump { my $self = shift; my $indent = shift || 1; my $buffer = ' '; my $pad = $buffer x $indent; my $text = ''; local $" = ', '; my ($key, $value); return $text . "...excessive recursion, terminating\n" if $indent > 32; foreach $key (keys %$self) { $value = $self->{ $key }; $value = '' unless defined $value; if (ref($value) eq 'ARRAY') { $value = "$value [@$value]"; } $text .= sprintf("$pad%-8s => $value\n", $key); next if $key =~ /^\./; if (UNIVERSAL::isa($value, 'HASH')) { $text .= _dump($value, $indent + 1); } } $text; } 1; __END__ #------------------------------------------------------------------------ # IMPORTANT NOTE # This documentation is generated automatically from source # templates. Any changes you make here may be lost. # # The 'docsrc' documentation source bundle is available for download # from http://www.template-toolkit.org/docs.html and contains all # the source templates, XML files, scripts, etc., from which the # documentation for the Template Toolkit is built. #------------------------------------------------------------------------ =head1 NAME Template::Stash::Context - Experimetal stash allowing list/scalar context definition =head1 SYNOPSIS use Template; use Template::Stash::Context; my $stash = Template::Stash::Context->new(\%vars); my $tt2 = Template->new({ STASH => $stash }); =head1 DESCRIPTION This is an alternate stash object which includes a patch from Craig Barratt to implement various new virtual methods to allow dotted template variable to denote if object methods and subroutines should be called in scalar or list context. It adds a little overhead to each stash call and I'm a little wary of applying that to the core default stash without investigating the effects first. So for now, it's implemented as a separate stash module which will allow us to test it out, benchmark it and switch it in or out as we require. This is what Craig has to say about it: Here's a better set of features for the core. Attached is a new version of Stash.pm (based on TT2.02) that: * supports the special op "scalar" that forces scalar context on function calls, eg: cgi.param("foo").scalar calls cgi.param("foo") in scalar context (unlike my wimpy scalar op from last night). Array context is the default. With non-function operands, scalar behaves like the perl version (eg: no-op for scalar, size for arrays, etc). * supports the special op "ref" that behaves like the perl ref. If applied to a function the function is not called. Eg: cgi.param("foo").ref does *not* call cgi.param and evaluates to "CODE". Similarly, HASH.ref, ARRAY.ref return what you expect. * adds a new scalar and list op called "array" that is a no-op for arrays and promotes scalars to one-element arrays. * allows scalar ops to be applied to arrays and hashes in place, eg: ARRAY.repeat(3) repeats each element in place. * allows list ops to be applied to scalars by promoting the scalars to one-element arrays (like an implicit "array"). So you can do things like SCALAR.size, SCALAR.join and get a useful result. This also means you can now use x.0 to safely get the first element whether x is an array or scalar. The new Stash.pm passes the TT2.02 test suite. But I haven't tested the new features very much. One nagging implementation problem is that the "scalar" and "ref" ops have higher precedence than user variable names. =head1 AUTHOR Andy Wardley Eabw@andywardley.comE L =head1 VERSION 1.53, distributed as part of the Template Toolkit version 2.10, released on 24 July 2003. =head1 COPYRIGHT Copyright (C) 1996-2003 Andy Wardley. All Rights Reserved. Copyright (C) 1998-2002 Canon Research Centre Europe Ltd. This module is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =head1 SEE ALSO L vdradmin-am-3.6.13/lib/Template/Stash/XS.pm000066400000000000000000000114431443716113400203050ustar00rootroot00000000000000#============================================================= -*-Perl-*- # # Template::Stash::XS # # DESCRIPTION # # Perl bootstrap for XS module. Inherits methods from # Template::Stash when not implemented in the XS module. # #======================================================================== package Template::Stash::XS; use Template; use Template::Stash; BEGIN { require DynaLoader; @Template::Stash::XS::ISA = qw( DynaLoader Template::Stash ); eval { bootstrap Template::Stash::XS $Template::VERSION; }; if ($@) { die "Couldn't load Template::Stash::XS $Template::VERSION:\n\n$@\n"; } } sub DESTROY { # no op 1; } # catch missing method calls here so perl doesn't barf # trying to load *.al files sub AUTOLOAD { my ($self, @args) = @_; my @c = caller(0); my $auto = $AUTOLOAD; $auto =~ s/.*:://; $self =~ s/=.*//; die "Can't locate object method \"$auto\"" . " via package \"$self\" at $c[1] line $c[2]\n"; } 1; __END__ #------------------------------------------------------------------------ # IMPORTANT NOTE # This documentation is generated automatically from source # templates. Any changes you make here may be lost. # # The 'docsrc' documentation source bundle is available for download # from http://www.template-toolkit.org/docs.html and contains all # the source templates, XML files, scripts, etc., from which the # documentation for the Template Toolkit is built. #------------------------------------------------------------------------ =head1 NAME Template::Stash::XS - Experimetal high-speed stash written in XS =head1 SYNOPSIS use Template; use Template::Stash::XS; my $stash = Template::Stash::XS->new(\%vars); my $tt2 = Template->new({ STASH => $stash }); =head1 DESCRIPTION This module loads the XS version of Template::Stash::XS. It should behave very much like the old one, but run about twice as fast. See the synopsis above for usage information. Only a few methods (such as get and set) have been implemented in XS. The others are inherited from Template::Stash. =head1 NOTE To always use the XS version of Stash, modify the Template/Config.pm module near line 45: $STASH = 'Template::Stash::XS'; If you make this change, then there is no need to explicitly create an instance of Template::Stash::XS as seen in the SYNOPSIS above. Just use Template as normal. Alternatively, in your code add this line before creating a Template object: $Template::Config::STASH = 'Template::Stash::XS'; To use the original, pure-perl version restore this line in Template/Config.pm: $STASH = 'Template::Stash'; Or in your code: $Template::Config::STASH = 'Template::Stash'; You can elect to have this performed once for you at installation time by answering 'y' or 'n' to the question that asks if you want to make the XS Stash the default. =head1 BUGS Please report bugs to the Template Toolkit mailing list templates@template-toolkit.org As of version 2.05 of the Template Toolkit, use of the XS Stash is known to have 2 potentially troublesome side effects. The first problem is that accesses to tied hashes (e.g. Apache::Session) may not work as expected. This should be fixed in an imminent release. If you are using tied hashes then it is suggested that you use the regular Stash by default, or write a thin wrapper around your tied hashes to enable the XS Stash to access items via regular method calls. The second potential problem is that enabling the XS Stash causes all the Template Toolkit modules to be installed in an architecture dependant library, e.g. in /usr/lib/perl5/site_perl/5.6.0/i386-linux/Template instead of /usr/lib/perl5/site_perl/5.6.0/Template At the time of writing, we're not sure why this is happening but it's likely that this is either a bug or intentional feature in the Perl ExtUtils::MakeMaker module. As far as I know, Perl always checks the architecture dependant directories before the architecture independant ones. Therefore, a newer version of the Template Toolkit installed with the XS Stash enabled should be used by Perl in preference to any existing version using the regular stash. However, if you install a future version of the Template Toolkit with the XS Stash disabled, you may find that Perl continues to use the older version with XS Stash enabled in preference. =head1 AUTHORS Andy Wardley Eabw@tt2.orgE Doug Steinwand Edsteinwand@citysearch.comE =head1 VERSION Template Toolkit version 2.10, released on 24 July 2003. =head1 COPYRIGHT Copyright (C) 1996-2003 Andy Wardley. All Rights Reserved. Copyright (C) 1998-2002 Canon Research Centre Europe Ltd. This module is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =head1 SEE ALSO L vdradmin-am-3.6.13/lib/Template/Test.pm000066400000000000000000000512731443716113400176150ustar00rootroot00000000000000#============================================================= -*-Perl-*- # # Template::Test # # DESCRIPTION # Module defining a test harness which processes template input and # then compares the output against pre-define expected output. # Generates test output compatible with Test::Harness. This was # originally the t/texpect.pl script. # # AUTHOR # Andy Wardley # # COPYRIGHT # Copyright (C) 1996-2000 Andy Wardley. All Rights Reserved. # Copyright (C) 1998-2000 Canon Research Centre Europe Ltd. # # This module is free software; you can redistribute it and/or # modify it under the same terms as Perl itself. # #---------------------------------------------------------------------------- # # $Id: Test.pm,v 2.64 2003/04/29 12:29:49 abw Exp $ # #============================================================================ package Template::Test; require 5.004; use strict; use vars qw( @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS $VERSION $DEBUG $EXTRA $PRESERVE $REASON $NO_FLUSH $loaded %callsign); use Template qw( :template ); use Exporter; $VERSION = sprintf("%d.%02d", q$Revision: 2.64 $ =~ /(\d+)\.(\d+)/); $DEBUG = 0; @ISA = qw( Exporter ); @EXPORT = qw( ntests ok is match flush skip_all test_expect callsign banner ); @EXPORT_OK = ( 'assert' ); %EXPORT_TAGS = ( all => [ @EXPORT_OK, @EXPORT ] ); $| = 1; $REASON = 'not applicable on this platform'; $NO_FLUSH = 0; $EXTRA = 0; # any extra tests to come after test_expect() $PRESERVE = 0 # don't mangle newlines in output/expect unless defined $PRESERVE; # always set binmode on Win32 machines so that any output generated # is true to what we expect $Template::BINMODE = ($^O eq 'MSWin32') ? 1 : 0; my @results = (); my ($ntests, $ok_count); *is = \&match; END { # ensure flush() is called to print any cached results flush(); } #------------------------------------------------------------------------ # ntests($n) # # Declare how many (more) tests are expected to come. If ok() is called # before ntests() then the results are cached instead of being printed # to STDOUT. When ntests() is called, the total number of tests # (including any cached) is known and the "1..$ntests" line can be # printed along with the cached results. After that, calls to ok() # generated printed output immediately. #------------------------------------------------------------------------ sub ntests { $ntests = shift; # add any pre-declared extra tests, or pre-stored test @results, to # the grand total of tests $ntests += $EXTRA + scalar @results; $ok_count = 1; print $ntests ? "1..$ntests\n" : "1..$ntests # skipped: $REASON\n"; # flush cached results foreach my $pre_test (@results) { ok(@$pre_test); } } #------------------------------------------------------------------------ # ok($truth, $msg) # # Tests the value passed for truth and generates an "ok $n" or "not ok $n" # line accordingly. If ntests() hasn't been called then we cached # results for later, instead. #------------------------------------------------------------------------ sub ok { my ($ok, $msg) = @_; # cache results if ntests() not yet called unless ($ok_count) { push(@results, [ $ok, $msg ]); return $ok; } $msg = defined $msg ? " - $msg" : ''; if ($ok) { print "ok ", $ok_count++, "$msg\n"; } else { print STDERR "FAILED $ok_count: $msg\n" if defined $msg; print "not ok ", $ok_count++, "$msg\n"; } } #------------------------------------------------------------------------ # assert($truth, $error) # # Test value for truth, die if false. #------------------------------------------------------------------------ sub assert { my ($ok, $err) = @_; return ok(1) if $ok; # failed my ($pkg, $file, $line) = caller(); $err ||= "assert failed"; $err .= " at $file line $line\n"; ok(0); die $err; } #------------------------------------------------------------------------ # match( $result, $expect ) #------------------------------------------------------------------------ sub match { my ($result, $expect, $msg) = @_; my $count = $ok_count ? $ok_count : scalar @results + 1; # force stringification of $result to avoid 'no eq method' overload errors $result = "$result" if ref $result; if ($result eq $expect) { return ok(1, $msg); } else { print STDERR "FAILED $count:\n expect: [$expect]\n result: [$result]\n"; return ok(0, $msg); } } #------------------------------------------------------------------------ # flush() # # Flush any tests results. #------------------------------------------------------------------------ sub flush { ntests(0) unless $ok_count || $NO_FLUSH; } #------------------------------------------------------------------------ # skip_all($reason) # # Skip all tests, setting $REASON to contain any message passed. Calls # exit(0) which triggers flush() which generates a "1..0 # $REASON" # string to keep to test harness happy. #------------------------------------------------------------------------ sub skip_all { $REASON = join('', @_); exit(0); } #------------------------------------------------------------------------ # test_expect($input, $template, \%replace) # # This is the main testing sub-routine. The $input parameter should be a # text string or a filehandle reference (e.g. GLOB or IO::Handle) from # which the input text can be read. The input should contain a number # of tests which are split up and processed individually, comparing the # generated output against the expected output. Tests should be defined # as follows: # # -- test -- # test input # -- expect -- # expected output # # -- test -- # etc... # # The number of tests is determined and ntests() is called to generate # the "0..$n" line compatible with Test::Harness. Each test input is # then processed by the Template object passed as the second parameter, # $template. This may also be a hash reference containing configuration # which are used to instantiate a Template object, or may be left # undefined in which case a default Template object will be instantiated. # The third parameter, also optional, may be a reference to a hash array # defining template variables. This is passed to the template process() # method. #------------------------------------------------------------------------ sub test_expect { my ($src, $tproc, $params) = @_; my ($input, @tests); my ($output, $expect, $match); my $count = 0; my $ttprocs; # read input text eval { local $/ = undef; $input = ref $src ? <$src> : $src; }; if ($@) { ntests(1); ok(0); warn "Cannot read input text from $src\n"; return undef; } # remove any comment lines $input =~ s/^#.*?\n//gm; # remove anything before '-- start --' and/or after '-- stop --' $input = $' if $input =~ /\s*--\s*start\s*--\s*/; $input = $` if $input =~ /\s*--\s*stop\s*--\s*/; @tests = split(/^\s*--\s*test\s*--\s*\n/im, $input); # if the first line of the file was '--test--' (optional) then the # first test will be empty and can be discarded shift(@tests) if $tests[0] =~ /^\s*$/; ntests(3 + scalar(@tests) * 2); # first test is that Template loaded OK, which it did ok(1, 'running test_expect()'); # optional second param may contain a Template reference or a HASH ref # of constructor options, or may be undefined if (ref($tproc) eq 'HASH') { # create Template object using hash of config items $tproc = Template->new($tproc) || die Template->error(), "\n"; } elsif (ref($tproc) eq 'ARRAY') { # list of [ name => $tproc, name => $tproc ], use first $tproc $ttprocs = { @$tproc }; $tproc = $tproc->[1]; } elsif (! ref $tproc) { $tproc = Template->new() || die Template->error(), "\n"; } # otherwise, we assume it's a Template reference # test: template processor created OK ok($tproc, 'template processor is engaged'); # third test is that the input read ok, which it did ok(1, 'input read and split into ' . scalar @tests . ' tests'); # the remaining tests are defined in @tests... foreach $input (@tests) { $count++; my $name = ''; if ($input =~ s/^\s*-- name:? (.*?) --\s*\n//im) { $name = $1; } else { $name = "template text $count"; } # split input by a line like "-- expect --" ($input, $expect) = split(/^\s*--\s*expect\s*--\s*\n/im, $input); $expect = '' unless defined $expect; $output = ''; # input text may be prefixed with "-- use name --" to indicate a # Template object in the $ttproc hash which we should use if ($input =~ s/^\s*--\s*use\s+(\S+)\s*--\s*\n//im) { my $ttname = $1; my $ttlookup; if ($ttlookup = $ttprocs->{ $ttname }) { $tproc = $ttlookup; } else { warn "no such template object to use: $ttname\n"; } } # process input text $tproc->process(\$input, $params, \$output) || do { warn "Template process failed: ", $tproc->error(), "\n"; # report failure and automatically fail the expect match ok(0, "$name process FAILED: " . subtext($input)); ok(0, '(obviously did not match expected)'); next; }; # processed OK ok(1, "$name processed OK: " . subtext($input)); # another hack: if the '-- expect --' section starts with # '-- process --' then we process the expected output # before comparing it with the generated output. This is # slightly twisted but it makes it possible to run tests # where the expected output isn't static. See t/date.t for # an example. if ($expect =~ s/^\s*--+\s*process\s*--+\s*\n//im) { my $out; $tproc->process(\$expect, $params, \$out) || do { warn("Template process failed (expect): ", $tproc->error(), "\n"); # report failure and automatically fail the expect match ok(0, "failed to process expected output [" . subtext($expect) . ']'); next; }; $expect = $out; }; # strip any trailing blank lines from expected and real output foreach ($expect, $output) { s/\n*\Z//mg; } $match = ($expect eq $output) ? 1 : 0; if (! $match || $DEBUG) { print "MATCH FAILED\n" unless $match; my ($copyi, $copye, $copyo) = ($input, $expect, $output); unless ($PRESERVE) { foreach ($copyi, $copye, $copyo) { s/\n/\\n/g; } } printf(" input: [%s]\nexpect: [%s]\noutput: [%s]\n", $copyi, $copye, $copyo); } ok($match, $match ? "$name matched expected" : "$name did not match expected"); }; } #------------------------------------------------------------------------ # callsign() # # Returns a hash array mapping lower a..z to their phonetic alphabet # equivalent. #------------------------------------------------------------------------ sub callsign { my %callsign; @callsign{ 'a'..'z' } = qw( alpha bravo charlie delta echo foxtrot golf hotel india juliet kilo lima mike november oscar papa quebec romeo sierra tango umbrella victor whisky x-ray yankee zulu ); return \%callsign; } #------------------------------------------------------------------------ # banner($text) # # Prints a banner with the specified text if $DEBUG is set. #------------------------------------------------------------------------ sub banner { return unless $DEBUG; my $text = join('', @_); my $count = $ok_count ? $ok_count - 1 : scalar @results; print "-" x 72, "\n$text ($count tests completed)\n", "-" x 72, "\n"; } sub subtext { my $text = shift; $text =~ s/\s*$//sg; $text = substr($text, 0, 32) . '...' if length $text > 32; $text =~ s/\n/\\n/g; return $text; } 1; __END__ #------------------------------------------------------------------------ # IMPORTANT NOTE # This documentation is generated automatically from source # templates. Any changes you make here may be lost. # # The 'docsrc' documentation source bundle is available for download # from http://www.template-toolkit.org/docs.html and contains all # the source templates, XML files, scripts, etc., from which the # documentation for the Template Toolkit is built. #------------------------------------------------------------------------ =head1 NAME Template::Test - Module for automating TT2 test scripts =head1 SYNOPSIS use Template::Test; $Template::Test::DEBUG = 0; # set this true to see each test running $Template::Test::EXTRA = 2; # 2 extra tests follow test_expect()... # ok() can be called any number of times before test_expect ok( $true_or_false ) # test_expect() splits $input into individual tests, processes each # and compares generated output against expected output test_expect($input, $template, \%replace ); # $input is text or filehandle (e.g. DATA section after __END__) test_expect( $text ); test_expect( \*DATA ); # $template is a Template object or configuration hash my $template_cfg = { ... }; test_expect( $input, $template_cfg ); my $template_obj = Template->new($template_cfg); test_expect( $input, $template_obj ); # $replace is a hash reference of template variables my $replace = { a => 'alpha', b => 'bravo' }; test_expect( $input, $template, $replace ); # ok() called after test_expect should be declared in $EXTRA (2) ok( $true_or_false ) ok( $true_or_false ) =head1 DESCRIPTION The Template::Test module defines the test_expect() and other related subroutines which can be used to automate test scripts for the Template Toolkit. See the numerous tests in the 't' sub-directory of the distribution for examples of use. The test_expect() subroutine splits an input document into a number of separate tests, processes each one using the Template Toolkit and then compares the generated output against an expected output, also specified in the input document. It generates the familiar "ok/not ok" output compatible with Test::Harness. The test input should be specified as a text string or a reference to a filehandle (e.g. GLOB or IO::Handle) from which it can be read. In particular, this allows the test input to be placed after the __END__ marker and read via the DATA filehandle. use Template::Test; test_expect(\*DATA); __END__ # this is the first test (this is a comment) -- test -- blah blah blah [% foo %] -- expect -- blah blah blah value_of_foo # here's the second test (no surprise, so is this) -- test -- more blah blah [% bar %] -- expect -- more blah blah value_of_bar Blank lines between test sections are generally ignored. Any line starting with '#' is treated as a comment and is ignored. The second and third parameters to test_expect() are optional. The second may be either a reference to a Template object which should be used to process the template fragments, or a reference to a hash array containing configuration values which should be used to instantiate a new Template object. # pass reference to config hash my $config = { INCLUDE_PATH => '/here/there:/every/where', POST_CHOMP => 1, }; test_expect(\*DATA, $config); # or create Template object explicitly my $template = Template->new($config); test_expect(\*DATA, $template); The third parameter may be used to reference a hash array of template variable which should be defined when processing the tests. This is passed to the Template process() method. my $replace = { a => 'alpha', b => 'bravo', }; test_expect(\*DATA, $config, $replace); The second parameter may be left undefined to specify a default Template configuration. test_expect(\*DATA, undef, $replace); For testing the output of different Template configurations, a reference to a list of named Template objects also may be passed as the second parameter. my $tt1 = Template->new({ ... }); my $tt2 = Template->new({ ... }); my @tts = [ one => $tt1, two => $tt1 ]; The first object in the list is used by default. Other objects may be switched in with the '-- use $name --' marker. This should immediately follow a '-- test --' line. That object will then be used for the rest of the test, or until a different object is selected. -- test -- -- use one -- [% blah %] -- expect -- blah, blah -- test -- still using one... -- expect -- ... -- test -- -- use two -- [% blah %] -- expect -- blah, blah, more blah The test_expect() sub counts the number of tests, and then calls ntests() to generate the familiar "1..$ntests\n" test harness line. Each test defined generates two test numbers. The first indicates that the input was processed without error, and the second that the output matches that expected. Additional test may be run before test_expect() by calling ok(). These test results are cached until ntests() is called and the final number of tests can be calculated. Then, the "1..$ntests" line is output, along with "ok $n" / "not ok $n" lines for each of the cached test result. Subsequent calls to ok() then generate an output line immediately. my $something = SomeObject->new(); ok( $something ); my $other = AnotherThing->new(); ok( $other ); test_expect(\*DATA); If any tests are to follow after test_expect() is called then these should be pre-declared by setting the $EXTRA package variable. This value (default: 0) is added to the grand total calculated by ntests(). The results of the additional tests are also registered by calling ok(). $Template::Test::EXTRA = 2; # can call ok() any number of times before test_expect() ok( $did_that_work ); ok( $make_sure ); ok( $dead_certain ); # number of tests... test_expect(\*DATA, $config, $replace); # here's those $EXTRA tests ok( defined $some_result && ref $some_result eq 'ARRAY' ); ok( $some_result->[0] eq 'some expected value' ); If you don't want to call test_expect() at all then you can call ntests($n) to declare the number of tests and generate the test header line. After that, simply call ok() for each test passing a true or false values to indicate that the test passed or failed. ntests(2); ok(1); ok(0); If you're really lazy, you can just call ok() and not bother declaring the number of tests at all. All tests results will be cached until the end of the script and then printed in one go before the program exits. ok( $x ); ok( $y ); You can identify only a specific part of the input file for testing using the '-- start --' and '-- stop --' markers. Anything before the first '-- start --' is ignored, along with anything after the next '-- stop --' marker. -- test -- this is test 1 (not performed) -- expect -- this is test 1 (not performed) -- start -- -- test -- this is test 2 -- expect -- this is test 2 -- stop -- ... For historical reasons and general utility, the module also defines a 'callsign' subroutine which returns a hash mapping a..z to their phonetic alphabet equivalent (e.g. radio callsigns). This is used by many of the test scripts as a "known source" of variable values. test_expect(\*DATA, $config, callsign()); A banner() subroutine is also provided which prints a simple banner including any text passed as parameters, if $DEBUG is set. banner('Testing something-or-other'); example output: #------------------------------------------------------------ # Testing something-or-other (27 tests completed) #------------------------------------------------------------ The $DEBUG package variable can be set to enable debugging mode. The $PRESERVE package variable can be set to stop the test_expect() from converting newlines in the output and expected output into the literal strings '\n'. =head1 HISTORY This module started its butt-ugly life as the t/texpect.pl script. It was cleaned up to became the Template::Test module some time around version 0.29. It underwent further cosmetic surgery for version 2.00 but still retains some rear-end resemblances. =head1 BUGS / KNOWN "FEATURES" Imports all methods by default. This is generally a Bad Thing, but this module is only used in test scripts (i.e. at build time) so a) we don't really care and b) it saves typing. The line splitter may be a bit dumb, especially if it sees lines like -- this -- that aren't supposed to be special markers. So don't do that. =head1 AUTHOR Andy Wardley Eabw@andywardley.comE L =head1 VERSION 2.64, distributed as part of the Template Toolkit version 2.10, released on 24 July 2003. =head1 COPYRIGHT Copyright (C) 1996-2003 Andy Wardley. All Rights Reserved. Copyright (C) 1998-2002 Canon Research Centre Europe Ltd. This module is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =head1 SEE ALSO L vdradmin-am-3.6.13/lib/Template/View.pm000066400000000000000000000547401443716113400176120ustar00rootroot00000000000000#============================================================= -*-Perl-*- # # Template::View # # DESCRIPTION # A custom view of a template processing context. Can be used to # implement custom "skins". # # AUTHOR # Andy Wardley # # COPYRIGHT # Copyright (C) 2000 Andy Wardley. All Rights Reserved. # # This module is free software; you can redistribute it and/or # modify it under the same terms as Perl itself. # # TODO # * allowing print to have a hash ref as final args will cause problems # if you do this: [% view.print(hash1, hash2, hash3) %]. Current # work-around is to do [% view.print(hash1); view.print(hash2); # view.print(hash3) %] or [% view.print(hash1, hash2, hash3, { }) %] # # REVISION # $Id: View.pm,v 2.8 2002/04/15 15:53:37 abw Exp $ # #============================================================================ package Template::View; require 5.004; use strict; use vars qw( $VERSION $DEBUG $AUTOLOAD @BASEARGS $MAP ); use base qw( Template::Base ); $VERSION = sprintf("%d.%02d", q$Revision: 2.8 $ =~ /(\d+)\.(\d+)/); $DEBUG = 0 unless defined $DEBUG; @BASEARGS = qw( context ); $MAP = { HASH => 'hash', ARRAY => 'list', TEXT => 'text', default => '', }; #$DEBUG = 1; #------------------------------------------------------------------------ # _init(\%config) # # Initialisation method called by the Template::Base class new() # constructor. $self->{ context } has already been set, by virtue of # being named in @BASEARGS. Remaining config arguments are presented # as a hash reference. #------------------------------------------------------------------------ sub _init { my ($self, $config) = @_; # move 'context' somewhere more private $self->{ _CONTEXT } = $self->{ context }; delete $self->{ context }; # generate table mapping object types to templates my $map = $config->{ map } || { }; $map->{ default } = $config->{ default } unless defined $map->{ default }; $self->{ map } = { %$MAP, %$map, }; # local BLOCKs definition table $self->{ _BLOCKS } = $config->{ blocks } || { }; # name of presentation method which printed objects might provide $self->{ method } = defined $config->{ method } ? $config->{ method } : 'present'; # view is sealed by default preventing variable update after # definition, however we don't actually seal a view until the # END of the view definition my $sealed = $config->{ sealed }; $sealed = 1 unless defined $sealed; $self->{ sealed } = $sealed ? 1 : 0; # copy remaining config items from $config or set defaults foreach my $arg (qw( base prefix suffix notfound silent )) { $self->{ $arg } = $config->{ $arg } || ''; } # name of data item used by view() $self->{ item } = $config->{ item } || 'item'; # map methods of form ${include_prefix}_foobar() to include('foobar')? $self->{ include_prefix } = $config->{ include_prefix } || 'include_'; # what about mapping foobar() to include('foobar')? $self->{ include_naked } = defined $config->{ include_naked } ? $config->{ include_naked } : 1; # map methods of form ${view_prefix}_foobar() to include('foobar')? $self->{ view_prefix } = $config->{ view_prefix } || 'view_'; # what about mapping foobar() to view('foobar')? $self->{ view_naked } = $config->{ view_naked } || 0; # the view is initially unsealed, allowing directives in the initial # view template to create data items via the AUTOLOAD; once sealed via # call to seal(), the AUTOLOAD will not update any internal items. delete @$config{ qw( base method map default prefix suffix notfound item include_prefix include_naked silent sealed view_prefix view_naked blocks ) }; $config = { %{ $self->{ base }->{ data } }, %$config } if $self->{ base }; $self->{ data } = $config; $self->{ SEALED } = 0; return $self; } #------------------------------------------------------------------------ # seal() # unseal() # # Seal or unseal the view to allow/prevent new datat items from being # automatically created by the AUTOLOAD method. #------------------------------------------------------------------------ sub seal { my $self = shift; $self->{ SEALED } = $self->{ sealed }; } sub unseal { my $self = shift; $self->{ SEALED } = 0; } #------------------------------------------------------------------------ # clone(\%config) # # Cloning method which takes a copy of $self and then applies to it any # modifications specified in the $config hash passed as an argument. # Configuration items may also be specified as a list of "name => $value" # arguments. Returns a reference to the cloned Template::View object. # # NOTE: may need to copy BLOCKS??? #------------------------------------------------------------------------ sub clone { my $self = shift; my $clone = bless { %$self }, ref $self; my $config = ref $_[0] eq 'HASH' ? shift : { @_ }; # merge maps $clone->{ map } = { %{ $self->{ map } }, %{ $config->{ map } || { } }, }; # "map => { default=>'xxx' }" can be specified as "default => 'xxx'" $clone->{ map }->{ default } = $config->{ default } if defined $config->{ default }; # update any remaining config items my @args = qw( base prefix suffix notfound item method include_prefix include_naked view_prefix view_naked ); foreach my $arg (@args) { $clone->{ $arg } = $config->{ $arg } if defined $config->{ $arg }; } push(@args, qw( default map )); delete @$config{ @args }; # anything left is data my $data = $clone->{ data } = { %{ $self->{ data } } }; @$data{ keys %$config } = values %$config; return $clone; } #------------------------------------------------------------------------ # print(@items, ..., \%config) # # Prints @items in turn by mapping each to an approriate template using # the internal 'map' hash. If an entry isn't found and the item is an # object that implements the method named in the internal 'method' item, # (default: 'present'), then the method will be called passing a reference # to $self, against which the presenter method may make callbacks (e.g. # to view_item()). If the presenter method isn't implemented, then the # 'default' map entry is consulted and used if defined. The final argument # may be a reference to a hash array providing local overrides to the internal # defaults for various items (prefix, suffix, etc). In the presence # of this parameter, a clone of the current object is first made, applying # any configuration updates, and control is then delegated to it. #------------------------------------------------------------------------ sub print { my $self = shift; # if final config hash is specified then create a clone and delegate to it # NOTE: potential problem when called print(\%data_hash1, \%data_hash2); if ((scalar @_ > 1) && (ref $_[-1] eq 'HASH')) { my $cfg = pop @_; my $clone = $self->clone($cfg) || return; return $clone->print(@_) || $self->error($clone->error()); } my ($item, $type, $template, $present); my $method = $self->{ method }; my $map = $self->{ map }; my $output = ''; # print each argument foreach $item (@_) { my $newtype; if (! ($type = ref $item)) { # non-references are TEXT $type = 'TEXT'; $template = $map->{ $type }; } elsif (! defined ($template = $map->{ $type })) { # no specific map entry for object, maybe it implements a # 'present' (or other) method? # $self->DEBUG("determining if $item can $method\n") if $DEBUG; if ( $method && UNIVERSAL::can($item, $method) ) { $self->DEBUG("Calling \$item->$method\n") if $DEBUG; $present = $item->$method($self); ## call item method # undef returned indicates error, note that we expect # $item to have called error() on the view return unless defined $present; $output .= $present; next; ## NEXT } elsif ( UNIVERSAL::isa($item, 'HASH' ) && defined($newtype = $item->{$method}) && defined($template = $map->{"$method=>$newtype"})) { } elsif ( defined($newtype) && defined($template = $map->{"$method=>*"}) ) { $template =~ s/\*/$newtype/; } elsif (! ($template = $map->{ default }) ) { # default not defined, so construct template name from type ($template = $type) =~ s/\W+/_/g; } } # else { # $self->DEBUG("defined map type for $type: $template\n"); # } $self->DEBUG("printing view '", $template || '', "', $item\n") if $DEBUG; $output .= $self->view($template, $item) if $template; } return $output; } #------------------------------------------------------------------------ # view($template, $item, \%vars) # # Wrapper around include() which expects a template name, $template, # followed by a data item, $item, and optionally, a further hash array # of template variables. The $item is added as an entry to the $vars # hash (which is created empty if not passed as an argument) under the # name specified by the internal 'item' member, which is appropriately # 'item' by default. Thus an external object present() method can # callback against this object method, simply passing a data item to # be displayed. The external object doesn't have to know what the # view expects the item to be called in the $vars hash. #------------------------------------------------------------------------ sub view { my ($self, $template, $item) = splice(@_, 0, 3); my $vars = ref $_[0] eq 'HASH' ? shift : { @_ }; $vars->{ $self->{ item } } = $item if defined $item; $self->include($template, $vars); } #------------------------------------------------------------------------ # include($template, \%vars) # # INCLUDE a template, $template, mapped according to the current prefix, # suffix, default, etc., where $vars is an optional hash reference # containing template variable definitions. If the template isn't found # then the method will default to any 'notfound' template, if defined # as an internal item. #------------------------------------------------------------------------ sub include { my ($self, $template, $vars) = @_; my $context = $self->{ _CONTEXT }; $template = $self->template($template); $vars = { } unless ref $vars eq 'HASH'; $vars->{ view } ||= $self; $context->include( $template, $vars ); # DEBUGGING # my $out = $context->include( $template, $vars ); # print STDERR "VIEW return [$out]\n"; # return $out; } #------------------------------------------------------------------------ # template($template) # # Returns a compiled template for the specified template name, according # to the current configuration parameters. #------------------------------------------------------------------------ sub template { my ($self, $name) = @_; my $context = $self->{ _CONTEXT }; return $context->throw(Template::Constants::ERROR_VIEW, "no view template specified") unless $name; my $notfound = $self->{ notfound }; my $base = $self->{ base }; my ($template, $block, $error); return $block if ($block = $self->{ _BLOCKS }->{ $name }); # try the named template $template = $self->template_name($name); $self->DEBUG("looking for $template\n") if $DEBUG; eval { $template = $context->template($template) }; # try asking the base view if not found if (($error = $@) && $base) { $self->DEBUG("asking base for $name\n") if $DEBUG; eval { $template = $base->template($name) }; } # try the 'notfound' template (if defined) if that failed if (($error = $@) && $notfound) { unless ($template = $self->{ _BLOCKS }->{ $notfound }) { $notfound = $self->template_name($notfound); $self->DEBUG("not found, looking for $notfound\n") if $DEBUG; eval { $template = $context->template($notfound) }; return $context->throw(Template::Constants::ERROR_VIEW, $error) if $@; # return first error } } elsif ($error) { $self->DEBUG("no 'notfound'\n") if $DEBUG; return $context->throw(Template::Constants::ERROR_VIEW, $error); } return $template; } #------------------------------------------------------------------------ # template_name($template) # # Returns the name of the specified template with any appropriate prefix # and/or suffix added. #------------------------------------------------------------------------ sub template_name { my ($self, $template) = @_; $template = $self->{ prefix } . $template . $self->{ suffix } if $template; $self->DEBUG("template name: $template\n") if $DEBUG; return $template; } #------------------------------------------------------------------------ # default($val) # # Special case accessor to retrieve/update 'default' as an alias for # '$map->{ default }'. #------------------------------------------------------------------------ sub default { my $self = shift; return @_ ? ($self->{ map }->{ default } = shift) : $self->{ map }->{ default }; } #------------------------------------------------------------------------ # AUTOLOAD # # Returns/updates public internal data items (i.e. not prefixed '_' or # '.') or presents a view if the method matches the view_prefix item, # e.g. view_foo(...) => view('foo', ...). Similarly, the # include_prefix is used, if defined, to map include_foo(...) to # include('foo', ...). If that fails then the entire method name will # be used as the name of a template to include iff the include_named # parameter is set (default: 1). Last attempt is to match the entire # method name to a view() call, iff view_naked is set. Otherwise, a # 'view' exception is raised reporting the error "no such view member: # $method". #------------------------------------------------------------------------ sub AUTOLOAD { my $self = shift; my $item = $AUTOLOAD; $item =~ s/.*:://; return if $item eq 'DESTROY'; if ($item =~ /^[\._]/) { return $self->{ _CONTEXT }->throw(Template::Constants::ERROR_VIEW, "attempt to view private member: $item"); } elsif (exists $self->{ $item }) { # update existing config item (e.g. 'prefix') if unsealed return $self->{ _CONTEXT }->throw(Template::Constants::ERROR_VIEW, "cannot update config item in sealed view: $item") if @_ && $self->{ SEALED }; $self->DEBUG("accessing item: $item\n") if $DEBUG; return @_ ? ($self->{ $item } = shift) : $self->{ $item }; } elsif (exists $self->{ data }->{ $item }) { # get/update existing data item (must be unsealed to update) if (@_ && $self->{ SEALED }) { return $self->{ _CONTEXT }->throw(Template::Constants::ERROR_VIEW, "cannot update item in sealed view: $item") unless $self->{ silent }; # ignore args if silent @_ = (); } $self->DEBUG(@_ ? "updating data item: $item <= $_[0]\n" : "returning data item: $item\n") if $DEBUG; return @_ ? ($self->{ data }->{ $item } = shift) : $self->{ data }->{ $item }; } elsif (@_ && ! $self->{ SEALED }) { # set data item if unsealed $self->DEBUG("setting unsealed data: $item => @_\n") if $DEBUG; $self->{ data }->{ $item } = shift; } elsif ($item =~ s/^$self->{ view_prefix }//) { $self->DEBUG("returning view($item)\n") if $DEBUG; return $self->view($item, @_); } elsif ($item =~ s/^$self->{ include_prefix }//) { $self->DEBUG("returning include($item)\n") if $DEBUG; return $self->include($item, @_); } elsif ($self->{ include_naked }) { $self->DEBUG("returning naked include($item)\n") if $DEBUG; return $self->include($item, @_); } elsif ($self->{ view_naked }) { $self->DEBUG("returning naked view($item)\n") if $DEBUG; return $self->view($item, @_); } else { return $self->{ _CONTEXT }->throw(Template::Constants::ERROR_VIEW, "no such view member: $item"); } } 1; __END__ =head1 NAME Template::View - customised view of a template processing context =head1 SYNOPSIS # define a view [% VIEW view # some standard args prefix => 'my_', suffix => '.tt2', notfound => 'no_such_file' ... # any other data title => 'My View title' other_item => 'Joe Random Data' ... %] # add new data definitions, via 'my' self reference [% my.author = "$abw.name <$abw.email>" %] [% my.copy = "© Copyright 2000 $my.author" %] # define a local block [% BLOCK header %] This is the header block, title: [% title or my.title %] [% END %] [% END %] # access data items for view [% view.title %] [% view.other_item %] # access blocks directly ('include_naked' option, set by default) [% view.header %] [% view.header(title => 'New Title') %] # non-local templates have prefix/suffix attached [% view.footer %] # => [% INCLUDE my_footer.tt2 %] # more verbose form of block access [% view.include( 'header', title => 'The Header Title' ) %] [% view.include_header( title => 'The Header Title' ) %] # very short form of above ('include_naked' option, set by default) [% view.header( title => 'The Header Title' ) %] # non-local templates have prefix/suffix attached [% view.footer %] # => [% INCLUDE my_footer.tt2 %] # fallback on the 'notfound' template ('my_no_such_file.tt2') # if template not found [% view.include('missing') %] [% view.include_missing %] [% view.missing %] # print() includes a template relevant to argument type [% view.print("some text") %] # type=TEXT, template='text' [% BLOCK my_text.tt2 %] # 'text' with prefix/suffix Text: [% item %] [% END %] # now print() a hash ref, mapped to 'hash' template [% view.print(some_hash_ref) %] # type=HASH, template='hash' [% BLOCK my_hash.tt2 %] # 'hash' with prefix/suffix hash keys: [% item.keys.sort.join(', ') [% END %] # now print() a list ref, mapped to 'list' template [% view.print(my_list_ref) %] # type=ARRAY, template='list' [% BLOCK my_list.tt2 %] # 'list' with prefix/suffix list: [% item.join(', ') %] [% END %] # print() maps 'My::Object' to 'My_Object' [% view.print(myobj) %] [% BLOCK my_My_Object.tt2 %] [% item.this %], [% item.that %] [% END %] # update mapping table [% view.map.ARRAY = 'my_list_template' %] [% view.map.TEXT = 'my_text_block' %] # change prefix, suffix, item name, etc. [% view.prefix = 'your_' %] [% view.default = 'anyobj' %] ... =head1 DESCRIPTION TODO =head1 METHODS =head2 new($context, \%config) Creates a new Template::View presenting a custom view of the specified $context object. A reference to a hash array of configuration options may be passed as the second argument. =over 4 =item prefix Prefix added to all template names. [% USE view(prefix => 'my_') %] [% view.view('foo', a => 20) %] # => my_foo =item suffix Suffix added to all template names. [% USE view(suffix => '.tt2') %] [% view.view('foo', a => 20) %] # => foo.tt2 =item map Hash array mapping reference types to template names. The print() method uses this to determine which template to use to present any particular item. The TEXT, HASH and ARRAY items default to 'test', 'hash' and 'list' appropriately. [% USE view(map => { ARRAY => 'my_list', HASH => 'your_hash', My::Foo => 'my_foo', } ) %] [% view.print(some_text) %] # => text [% view.print(a_list) %] # => my_list [% view.print(a_hash) %] # => your_hash [% view.print(a_foo) %] # => my_foo [% BLOCK text %] Text: [% item %] [% END %] [% BLOCK my_list %] list: [% item.join(', ') %] [% END %] [% BLOCK your_hash %] hash keys: [% item.keys.sort.join(', ') [% END %] [% BLOCK my_foo %] Foo: [% item.this %], [% item.that %] [% END %] =item method Name of a method which objects passed to print() may provide for presenting themselves to the view. If a specific map entry can't be found for an object reference and it supports the method (default: 'present') then the method will be called, passing the view as an argument. The object can then make callbacks against the view to present itself. package Foo; sub present { my ($self, $view) = @_; return "a regular view of a Foo\n"; } sub debug { my ($self, $view) = @_; return "a debug view of a Foo\n"; } In a template: [% USE view %] [% view.print(my_foo_object) %] # a regular view of a Foo [% USE view(method => 'debug') %] [% view.print(my_foo_object) %] # a debug view of a Foo =item default Default template to use if no specific map entry is found for an item. [% USE view(default => 'my_object') %] [% view.print(objref) %] # => my_object If no map entry or default is provided then the view will attempt to construct a template name from the object class, substituting any sequence of non-word characters to single underscores, e.g. # 'fubar' is an object of class Foo::Bar [% view.print(fubar) %] # => Foo_Bar Any current prefix and suffix will be added to both the default template name and any name constructed from the object class. =item notfound Fallback template to use if any other isn't found. =item item Name of the template variable to which the print() method assigns the current item. Defaults to 'item'. [% USE view %] [% BLOCK list %] [% item.join(', ') %] [% END %] [% view.print(a_list) %] [% USE view(item => 'thing') %] [% BLOCK list %] [% thing.join(', ') %] [% END %] [% view.print(a_list) %] =item view_prefix Prefix of methods which should be mapped to view() by AUTOLOAD. Defaults to 'view_'. [% USE view %] [% view.view_header() %] # => view('header') [% USE view(view_prefix => 'show_me_the_' %] [% view.show_me_the_header() %] # => view('header') =item view_naked Flag to indcate if any attempt should be made to map method names to template names where they don't match the view_prefix. Defaults to 0. [% USE view(view_naked => 1) %] [% view.header() %] # => view('header') =back =head2 print( $obj1, $obj2, ... \%config) TODO =head2 view( $template, \%vars, \%config ); TODO =head1 AUTHOR Andy Wardley Eabw@kfs.orgE =head1 REVISION $Revision: 2.8 $ =head1 COPYRIGHT Copyright (C) 2000 Andy Wardley. All Rights Reserved. This module is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =head1 SEE ALSO L, =cut vdradmin-am-3.6.13/lib/URI/000077500000000000000000000000001443716113400152145ustar00rootroot00000000000000vdradmin-am-3.6.13/lib/URI/Escape.pm000066400000000000000000000147141443716113400167610ustar00rootroot00000000000000# # $Id: Escape.pm,v 3.28 2004/11/05 13:58:31 gisle Exp $ # package URI::Escape; use strict; =head1 NAME URI::Escape - Escape and unescape unsafe characters =head1 SYNOPSIS use URI::Escape; $safe = uri_escape("10% is enough\n"); $verysafe = uri_escape("foo", "\0-\377"); $str = uri_unescape($safe); =head1 DESCRIPTION This module provides functions to escape and unescape URI strings as defined by RFC 2396 (and updated by RFC 2732). A URI consists of a restricted set of characters, denoted as C in RFC 2396. The restricted set of characters consists of digits, letters, and a few graphic symbols chosen from those common to most of the character encodings and input facilities available to Internet users: "A" .. "Z", "a" .. "z", "0" .. "9", ";", "/", "?", ":", "@", "&", "=", "+", "$", ",", "[", "]", # reserved "-", "_", ".", "!", "~", "*", "'", "(", ")" In addition, any byte (octet) can be represented in a URI by an escape sequence: a triplet consisting of the character "%" followed by two hexadecimal digits. A byte can also be represented directly by a character, using the US-ASCII character for that octet (iff the character is part of C). Some of the C characters are I for use as delimiters or as part of certain URI components. These must be escaped if they are to be treated as ordinary data. Read RFC 2396 for further details. The functions provided (and exported by default) from this module are: =over 4 =item uri_escape( $string ) =item uri_escape( $string, $unsafe ) Replaces each unsafe character in the $string with the corresponding escape sequence and returns the result. The $string argument should be a string of bytes. The uri_escape() function will croak if given a characters with code above 255. Use uri_escape_utf8() if you know you have such chars or/and want chars in the 128 .. 255 range treated as UTF-8. The uri_escape() function takes an optional second argument that overrides the set of characters that are to be escaped. The set is specified as a string that can be used in a regular expression character class (between [ ]). E.g.: "\x00-\x1f\x7f-\xff" # all control and hi-bit characters "a-z" # all lower case characters "^A-Za-z" # everything not a letter The default set of characters to be escaped is all those which are I part of the C character class shown above as well as the reserved characters. I.e. the default is: "^A-Za-z0-9\-_.!~*'()" =item uri_escape_utf8( $string ) =item uri_escape_utf8( $string, $unsafe ) Works like uri_escape(), but will encode chars as UTF-8 before escaping them. This makes this function able do deal with characters with code above 255 in $string. Note that chars in the 128 .. 255 range will be escaped differently by this function compared to what uri_escape() would. For chars in the 0 .. 127 range there is no difference. The call: $uri = uri_escape_utf8($string); will be the same as: use Encode qw(encode); $uri = uri_escape(encode("UTF-8", $string)); but will even work for perl-5.6 for chars in the 128 .. 255 range. Note: Javascript has a function called escape() that produce the sequence "%uXXXX" for chars in the 256 .. 65535 range. This function has really nothing to do with URI escaping but some folks got confused since it "does the right thing" in the 0 .. 255 range. Because of this you sometimes see "URIs" with these kind of escapes. The JavaScript encodeURI() function is similar to uri_escape_utf8(). =item uri_unescape($string,...) Returns a string with each %XX sequence replaced with the actual byte (octet). This does the same as: $string =~ s/%([0-9A-Fa-f]{2})/chr(hex($1))/eg; but does not modify the string in-place as this RE would. Using the uri_unescape() function instead of the RE might make the code look cleaner and is a few characters less to type. In a simple benchmark test I did, calling the function (instead of the inline RE above) if a few chars were unescaped was something like 40% slower, and something like 700% slower if none were. If you are going to unescape a lot of times it might be a good idea to inline the RE. If the uri_unescape() function is passed multiple strings, then each one is returned unescaped. =back The module can also export the C<%escapes> hash, which contains the mapping from all 256 bytes to the corresponding escape codes. Lookup in this hash is faster than evaluating C each time. =head1 SEE ALSO L =head1 COPYRIGHT Copyright 1995-2004 Gisle Aas. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut use vars qw(@ISA @EXPORT @EXPORT_OK $VERSION); use vars qw(%escapes); require Exporter; @ISA = qw(Exporter); @EXPORT = qw(uri_escape uri_unescape); @EXPORT_OK = qw(%escapes uri_escape_utf8); $VERSION = sprintf("%d.%02d", q$Revision: 3.28 $ =~ /(\d+)\.(\d+)/); use Carp (); # Build a char->hex map for (0..255) { $escapes{chr($_)} = sprintf("%%%02X", $_); } my %subst; # compiled patternes sub uri_escape { my($text, $patn) = @_; return undef unless defined $text; if (defined $patn){ unless (exists $subst{$patn}) { # Because we can't compile the regex we fake it with a cached sub (my $tmp = $patn) =~ s,/,\\/,g; eval "\$subst{\$patn} = sub {\$_[0] =~ s/([$tmp])/\$escapes{\$1} || _fail_hi(\$1)/ge; }"; Carp::croak("uri_escape: $@") if $@; } &{$subst{$patn}}($text); } else { # Default unsafe characters. RFC 2732 ^(uric - reserved) $text =~ s/([^A-Za-z0-9\-_.!~*'()])/$escapes{$1} || _fail_hi($1)/ge; } $text; } sub _fail_hi { my $chr = shift; Carp::croak(sprintf "Can't escape \\x{%04X}, try uri_escape_utf8() instead", ord($chr)); } sub uri_escape_utf8 { my $text = shift; if ($] < 5.008) { $text =~ s/([^\0-\x7F])/do {my $o = ord($1); sprintf("%c%c", 0xc0 | ($o >> 6), 0x80 | ($o & 0x3f)) }/ge; } else { utf8::encode($text); } return uri_escape($text, @_); } sub uri_unescape { # Note from RFC1630: "Sequences which start with a percent sign # but are not followed by two hexadecimal characters are reserved # for future extension" my $str = shift; if (@_ && wantarray) { # not executed for the common case of a single argument my @str = ($str, @_); # need to copy foreach (@str) { s/%([0-9A-Fa-f]{2})/chr(hex($1))/eg; } return @str; } $str =~ s/%([0-9A-Fa-f]{2})/chr(hex($1))/eg if defined $str; $str; } 1; vdradmin-am-3.6.13/make.sh000077500000000000000000000043301443716113400152630ustar00rootroot00000000000000#!/bin/bash LANGS="cs de es fr fi hu it nl ru" DIST_FILES="autotimer2searchtimer.pl ChangeLog COPYING CREDITS FAQ HISTORY INSTALL LGPL.txt README README.translators REQUIREMENTS contrib convert.pl install.sh lib locale make.sh template uninstall.sh vdradmind vdradmind.pl vdradmind.pl.1" INSTALL_SH=./install.sh TMPDIR=/tmp # Print usage information and exit # function Usage() { echo "Usage: $0 " echo echo "Available actions:" echo " install - install VDRAdmin-AM" echo " uninstall - uninstall VDRAdmin-AM" echo " po - convert .po files to .mo files" echo " dist - create distribution archive" echo " cl - create ChangeLog file." echo " check - check requirements" exit 1 } # Print error message and exit. # function Error() { [ "$1" ] && echo $* exit 1 } # Compile and install locales. # function do_po() { [ -d locale ] && rm -rf locale/* for PO in po/*.po do L=$(basename $PO .po) [ -d locale/$L/LC_MESSAGES/ ] || mkdir -p locale/$L/LC_MESSAGES/ msgfmt po/$L.po -o po/$L.mo install -m 644 po/$L.mo locale/$L/LC_MESSAGES/vdradmin.mo rm -f po/$L.mo done } # Extract VDRAdmin-AM version from vdradmind.pl # function getVersion() { grep "^my \$VERSION" vdradmind.pl | sed -e 's/^[^\"]*\"\([^\"]*\)\".*$/\1/' } # Create tar.bz2 for distribution. # function do_dist() { local DIST_NAME=vdradmin-am-$(getVersion) mkdir -p $TMPDIR/$DIST_NAME cp -a $DIST_FILES $TMPDIR/$DIST_NAME mkdir -p $TMPDIR/$DIST_NAME/po cp -a po/*.po po/*.pot $TMPDIR/$DIST_NAME/po ( cd $TMPDIR tar --exclude '.#*' --exclude '.nfs*' -cjf $DIST_NAME.tar.bz2 $DIST_NAME rm -rf $TMPDIR/$DIST_NAME ) mv $TMPDIR/$DIST_NAME.tar.bz2 . } # create ChangeLog file. # function do_cl() { git log > ChangeLog } # check requirements. # function do_check() { $INSTALL_SH -p } [ "$1" ] || Usage [ -x $INSTALL_SH ] || Error "$INSTALL_SH not found!" while [ $1 ] do case $1 in install) $INSTALL_SH -c ;; uninstall) $INSTALL_SH -u ;; po) do_po ;; local) do_po ;; dist) do_po do_cl do_dist ;; cl) do_cl; ;; check) do_check; ;; help|-h|--help) Usage; ;; *) Error "Unknown command \"$1\"" ;; esac [ $? -ne 0 ] && exit 1 shift done vdradmin-am-3.6.13/po/000077500000000000000000000000001443716113400144255ustar00rootroot00000000000000vdradmin-am-3.6.13/po/cs.po000066400000000000000000001532161443716113400154020ustar00rootroot00000000000000# Copyright (C) Andreas Mair # This file is distributed under the same license as the VDRAdmin-AM package. # # Karel Borkovec , 2006. # msgid "" msgstr "" "Project-Id-Version: cs\n" "Report-Msgid-Bugs-To: Andreas Mair \n" "POT-Creation-Date: 2012-07-09 12:23+0200\n" "PO-Revision-Date: 2011-11-18 23:43+0200\n" "Last-Translator: Ville Skyttä \n" "Language-Team: Czech \n" "Language: cs\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Generator: KBabel 1.11.2\n" msgid "About" msgstr "O programu" msgid "License" msgstr "" #, fuzzy msgid "Authors" msgstr "Auto-ÄŒasovaÄ" msgid "Current author (VDRAdmin-AM branch):" msgstr "SouÄasný autor (VDRAdmin-AM):" #, fuzzy msgid "Original author (VDRAdmin):" msgstr "Původní jméno nahrávky:" msgid "Translation Team" msgstr "PÅ™ekladatelský tým" msgid "English:" msgstr "AngliÄtina:" msgid "German:" msgstr "NÄ›mÄina:" msgid "French:" msgstr "FrancouzÅ¡tina:" msgid "At the moment unmaintained, former translations by:" msgstr "" msgid "Spanish:" msgstr "Å panÄ›lÅ¡tina:" msgid "Finnish:" msgstr "FinÅ¡tina:" msgid "Dutch:" msgstr "HolandÅ¡tina:" msgid "Russian:" msgstr "RuÅ¡tina:" #, fuzzy msgid "Czech:" msgstr "FrancouzÅ¡tina:" msgid "Italian:" msgstr "" msgid "Hungarian:" msgstr "" #, fuzzy msgid "Information" msgstr "Informace" msgid "VDRAdmin-AM version:" msgstr "Verze VDRAdminu-AM:" msgid "VDR version:" msgstr "Verze VDR:" msgid "Supported features in VDR:" msgstr "Podporované vlastnosti ve VDR:" msgid "EPGSearch" msgstr "" msgid "EPGSearch Plugin" msgstr "" msgid "LiveTV Streaming" msgstr "TV streamování" msgid "Streamdev Plugin" msgstr "" msgid "Xineliboutput Plugin" msgstr "" msgid "Rename Recordings (Liemikuutio Patch)" msgstr "PÅ™ejmenování nahrávek (Liemikuutio Patch)" msgid "Getting Help and Reporting Bugs" msgstr "Rady a nahlaÅ¡ování chyb" msgid "If you need help please first try to use the online help you'll find on some pages. You can access it by clicking \"\"." msgstr "Pokud si nevíte rady, použijte prosím nejdříve on-line nápovÄ›du na různých webech. KliknÄ›te zde \"\"." msgid "If this doesn't provide the information you need you can try to get help at VDR-Portal if you understand German language. Please use the announcement thread if possible, search for:" msgstr "Jestliže tato nápovÄ›da neobsahuje informace, které potÅ™ebujete zkuste se zeptat na nÄ›meckém portálu VDR-Portal (nÄ›mecký jazyk je samozÅ™ejmostí, popÅ™. angliÄtina). Využijte tzv. ANNOUNCE vlákno, hledat:" msgid "If you think you have found a bug please check that it's a new one and report it in the VDRAdmin-AM BugTracking system." msgstr "Pokud si myslíte, že jste naÅ¡el chybu, prosím zkontrolujte zda již není nahlášena, popÅ™. ji nahlaÅ¡te zde: VDRAdmin-AM BugTracking system." msgid "AutoTimer" msgstr "Auto-ÄŒasovaÄ" msgid "Priority:" msgstr "Priorita:" msgid "Lifetime:" msgstr "" msgid "New AutoTimer" msgstr "Nové Äasování" msgid "Help" msgstr "NápovÄ›da" msgid "Active" msgstr "Aktivovat" msgid "Channel" msgstr "Kanál" msgid "Start" msgstr "Start" msgid "Stop" msgstr "Stop" msgid "Name" msgstr "Jméno" msgid "Select all/none" msgstr "Vybrat vÅ¡e/Nic" msgid "Yes" msgstr "Ano" msgid "No" msgstr "Ne" msgid "Edit" msgstr "Upravit" msgid "Delete timer?" msgstr "Smazat ÄasovaÄ?" msgid "Delete" msgstr "Smazat" msgid "Force Update" msgstr "Vynutit úpravu" msgid "Delete Selected AutoTimers" msgstr "Smazat vybraný AutoÄŒasovaÄ?" msgid "Delete all selected timers?" msgstr "Vymazat vÅ¡echny vybrané ÄasovaÄe?" #, fuzzy msgid "No AutoTimers defined!" msgstr "Nové Äasování" msgid "Add New AutoTimer" msgstr "PÅ™idat nový AutoÄŒasovaÄ" msgid "Edit AutoTimer" msgstr "Upravit AutoÄŒasovaÄ" msgid "AutoTimer Active:" msgstr "Aktivní AutoÄŒasovaÄ:" msgid "oneshot" msgstr "" msgid "Search Patterns:" msgstr "Vyhledávací znaky:" msgid "Search in:" msgstr "Hledat v:" msgid "Title" msgstr "Název" msgid "Subtitle" msgstr "Titulky" msgid "Description" msgstr "Popis" msgid "Search only on these days:" msgstr "Hledat pouze v tyto dny:" msgid "Monday" msgstr "PondÄ›lí" msgid "Tuesday" msgstr "Úterý" msgid "Wednesday" msgstr "StÅ™eda" msgid "Thursday" msgstr "ÄŒtvrtek" msgid "Friday" msgstr "Pátek" msgid "Saturday" msgstr "Sobota" msgid "Sunday" msgstr "NedÄ›le" msgid "Channel:" msgstr "Kanál" msgid "all" msgstr "vÅ¡e" msgid "Starts After:" msgstr "ZaÄátek po:" msgid "o'clock" msgstr "hodin" msgid "Ends Before:" msgstr "Konec pÅ™ed:" msgid "Override Start/Stop Margins:" msgstr "" msgid "Time Margin at Start:" msgstr "" msgid "minutes" msgstr "minuty" msgid "Time Margin at Stop:" msgstr "" msgid "Episode:" msgstr "Epizoda:" msgid "Remember programmed timers:" msgstr "Zapamatovat naprogramovaný ÄasovaÄ:" msgid "Directory:" msgstr "Složka:" msgid "Save" msgstr "Uložit" msgid "Test" msgstr "Test:" msgid "Cancel" msgstr "ZruÅ¡it" msgid "Broadcasted" msgstr "Vysíláno" msgid "Stored in" msgstr "Uloženo v:" #, fuzzy msgid "No matches found!" msgstr "Nefunguje" msgid "Configuration" msgstr "Nastavení" msgid "General Settings" msgstr "Obecné nastavení" msgid "Template:" msgstr "Å ablona:" msgid "Skin:" msgstr "Skin:" msgid "Login Page:" msgstr "Úvodní strana:" msgid "Number of channels to use:" msgstr "PoÄet kanálů k použití:" msgid "Local net (no login required):" msgstr "Lokální síť (login není vyžadován):" msgid "Language:" msgstr "Jazyk:" msgid "Save settings on exit:" msgstr "Uložit nastavení pÅ™i vypnutí:" msgid "VDR" msgstr "VDR" msgid "Number of DVB cards:" msgstr "PoÄet DVB karet:" msgid "Path to recordings:" msgstr "Složka s nahrávkami:" msgid "Path to configuration files:" msgstr "Složka s konfiguraÄními soubory:" msgid "Path to EPG images:" msgstr "Cesta k EPG souborům:" msgid "Identification" msgstr "Identifikace" msgid "Username:" msgstr "Uživ. jméno:" msgid "Password:" msgstr "Heslo:" msgid "Guest Account:" msgstr "Guest úÄet:" msgid "Guest Username:" msgstr "Guest uživ. jméno:" msgid "Guest Password:" msgstr "Guest heslo:" msgid "Timeline" msgstr "ÄŒasová přímka" msgid "Hours:" msgstr "Hodiny:" msgid "Times:" msgstr "ÄŒasy:" msgid "Also used for other EPG views!" msgstr "Použít pro ostatní EPG náhledy!" msgid "Tooltips:" msgstr "Tipy:" msgid "Electronic Program Guide (EPG)" msgstr "" msgid "Day begins at:" msgstr "" msgid "Show Subtitle:" msgstr "" msgid "Show Summary:" msgstr "" msgid "Active:" msgstr "Aktivní:" msgid "Send email after programming timer:" msgstr "Poslat email po nastavení ÄasovaÄe:" msgid "Send email as:" msgstr "Odesílatel emailu:" msgid "Send email to:" msgstr "Komu:" msgid "Mail server:" msgstr "PoÅ¡tovní server:" msgid "SMTPAuth user:" msgstr "SMTPAuth uživatel:" msgid "SMTPAuth password:" msgstr "SMTPAuth heslo:" msgid "Track schedule changes by:" msgstr "" msgid "Broadcast time" msgstr "" msgid "Event id" msgstr "" msgid "Timer" msgstr "ÄŒasovaÄ" msgid "Tooltips in timeline:" msgstr "Tipy v Äasové přímce:" msgid "Tooltips in list:" msgstr "Tipy v seznamu:" msgid "Streaming" msgstr "Streamování" msgid "Live Streaming:" msgstr "Live Streamování:" msgid "HTTP Port of Streamdev (also possible 3000/ts):" msgstr "HTTP Port pro Streamdev (možno 3000/ts):" msgid "HTTP Port of Xineliboutput (e.g. 37890):" msgstr "" msgid "Recordings Streaming:" msgstr "Nahrávání streamu:" msgid "Path to VDR Recordings on your workstation:" msgstr "Cesta ke složce s VDR nahrávkami na VaÅ¡em PC:" msgid "MIME type for live streaming:" msgstr "MIME typ pro live streamování:" msgid "Suffix for live streaming:" msgstr "Přípona pro live streamování:" msgid "MIME type for recordings streaming:" msgstr "MIME typ pro nahrávky streamu:" msgid "Suffix for recordings streaming:" msgstr "Přípona pro nahrávky streamu:" msgid "Bandwidth of Streams:" msgstr "Šířka pásma pro streamy:" #, fuzzy msgid "External Search" msgstr "hledat" msgid "URL:" msgstr "" #, fuzzy msgid "Title:" msgstr "Název" #, fuzzy msgid "User-defined search:" msgstr "Žádný ÄasovaÄ není definován!" msgid "Expert" msgstr "Expert:" msgid "Update EPG data in background:" msgstr "" msgid "Update EPG every:" msgstr "" msgid "Channel Selections" msgstr "VýbÄ›r kanálů" msgid "Show channels without EPG information:" msgstr "" msgid "In \"AutoTimer\"?" msgstr "V \"AutoÄŒasovaÄi\"?" msgid "Apply" msgstr "Použij" #, fuzzy msgid "EPG Search Blacklists" msgstr "hledat" #, fuzzy msgid "New Blacklist" msgstr "PÅ™idat nový AutoÄŒasovaÄ" #, fuzzy msgid "Search pattern" msgstr "Vyhledávací znaky:" msgid "From" msgstr "" #, fuzzy msgid "To" msgstr "Nahoru" #, fuzzy msgid "Delete blacklist?" msgstr "Smazat ÄasovaÄ?" #, fuzzy msgid "Delete Selected Blacklists" msgstr "Vymazat vybrané ÄasovaÄe" #, fuzzy msgid "Delete all selected blacklists?" msgstr "Vymazat vÅ¡echny vybrané ÄasovaÄe?" #, fuzzy msgid "EPG search" msgstr "hledat" #, fuzzy msgid "EPG Search" msgstr "hledat" #, fuzzy msgid "Use template" msgstr "Å ablona:" #, fuzzy msgid "New Search" msgstr "hledat" #, fuzzy msgid "Edit Template" msgstr "Å ablona:" #, fuzzy msgid "Settings" msgstr "Obecné nastavení" #, fuzzy msgid "Action" msgstr "Aktivovat" #, fuzzy msgid "Find" msgstr "Pátek" msgid "Show Favorites" msgstr "" #, fuzzy msgid "Delete Selected Searches" msgstr "Vymazat vybrané ÄasovaÄe" #, fuzzy msgid "Delete all selected searches?" msgstr "Vymazat vÅ¡echny vybrané ÄasovaÄe?" #, fuzzy msgid "Execute Selected Searches" msgstr "Vymazat vybrané ÄasovaÄe" #, fuzzy msgid "Duration" msgstr "Délka:" msgid "More Information" msgstr "Více informací" msgid "Channels" msgstr "Kanály" msgid "Record" msgstr "Nahrávání" #, fuzzy msgid "Add New Blacklist" msgstr "PÅ™idat nový AutoÄŒasovaÄ" #, fuzzy msgid "Edit Blacklist" msgstr "PÅ™idat nový AutoÄŒasovaÄ" #, fuzzy msgid "Add New Template" msgstr "PÅ™idat nový AutoÄŒasovaÄ" #, fuzzy msgid "Add New Search" msgstr "PÅ™idat nový AutoÄŒasovaÄ" #, fuzzy msgid "Edit Search" msgstr "hledat" msgid "Small search pattern.\\nDo you really want to use it?" msgstr "" msgid "You didn't select at least one of\\ntitle, subtitle or description.\\nDo you really want to use this search?" msgstr "" #, fuzzy msgid "Hide results" msgstr "Hledat v:" #, fuzzy msgid "Name:" msgstr "Jméno" #, fuzzy msgid "Search Term:" msgstr "Hledat v:" #, fuzzy msgid "Search Mode:" msgstr "Hledat v:" msgid "phrase" msgstr "" msgid "all words" msgstr "" msgid "at least one word" msgstr "" msgid "match exactly" msgstr "" msgid "regular expression" msgstr "" msgid "fuzzy" msgstr "" msgid "Tolerance for \"fuzzy\":" msgstr "" msgid "Match Case:" msgstr "" msgid "Use extended EPG info:" msgstr "" msgid "Ignore missing categories?" msgstr "" #, fuzzy msgid "Use Channel:" msgstr "Kanál" #, fuzzy msgid "no" msgstr "nyní" #, fuzzy msgid "interval" msgstr "Interval:" #, fuzzy msgid "channel group" msgstr "Kanál" msgid "only FTA" msgstr "" #, fuzzy msgid "Range:" msgstr "Jazyk:" #, fuzzy msgid "Channel Group:" msgstr "Kanál" #, fuzzy msgid "Use Time:" msgstr "Uživ. jméno:" #, fuzzy msgid "Start After:" msgstr "ZaÄátek po:" #, fuzzy msgid "Start Before:" msgstr "ZaÄátek po:" #, fuzzy msgid "Use Duration:" msgstr "Délka:" #, fuzzy msgid "Min. Duration:" msgstr "Délka:" msgid "hh:mm" msgstr "" #, fuzzy msgid "Max. Duration:" msgstr "Délka:" msgid "Use Day of Week:" msgstr "" #, fuzzy msgid "Use Blacklists:" msgstr "PÅ™idat nový AutoÄŒasovaÄ" #, fuzzy msgid "selection" msgstr "Naladit TV" msgid "Use in Favorites Menu:" msgstr "" #, fuzzy msgid "Use as Search Timer:" msgstr "Hledat v:" #, fuzzy msgid "yes" msgstr "Ano" #, fuzzy msgid "user-defined" msgstr "Žádný ÄasovaÄ není definován!" msgid "record" msgstr "nahrát" msgid "announce by OSD" msgstr "" msgid "switch only" msgstr "" msgid "announce and switch" msgstr "" msgid "announce by mail" msgstr "" #, fuzzy msgid "First day:" msgstr "Pátek" #, fuzzy msgid "Last day:" msgstr "Pátek" msgid "Auto delete:" msgstr "" #, fuzzy msgid "count recordings" msgstr "Nahrávky" #, fuzzy msgid "count days" msgstr "PondÄ›lí" #, fuzzy msgid "After ... recordings:" msgstr "Nahrávky" #, fuzzy msgid "After ... days after first recording:" msgstr "Nahrávky" msgid "Settings for action \"record\"" msgstr "" #, fuzzy msgid "Series Recording:" msgstr "PÅ™ejmenovat nahrávku" #, fuzzy msgid "Delete Recordings After ... Days:" msgstr "Smazat nahrávku?" #, fuzzy msgid "Keep ... Recordings:" msgstr "Nahrávky" #, fuzzy msgid "Pause, when ... recordings exist:" msgstr "Složka s nahrávkami:" msgid "Avoid Repeats:" msgstr "" msgid "Allowed Repeats:" msgstr "" msgid "Only Repeats Within ... Days:" msgstr "" msgid "Compare:" msgstr "" msgid "Minimal match of description in %:" msgstr "" #, fuzzy msgid "VPS:" msgstr "VPS" msgid "Settings for action \"switch only\"" msgstr "" msgid "Switch ... Minutes Before Start:" msgstr "" msgid "Unmute sound:" msgstr "" msgid "Settings for action \"announce and switch\"" msgstr "" msgid "Ask ... Minutes Before Start:" msgstr "" #, fuzzy msgid "Delete template" msgstr "Å ablona:" #, fuzzy msgid "Delete this template?" msgstr "Smazat ÄasovaÄ?" #, fuzzy msgid "Save as template" msgstr "Å ablona:" msgid "Run" msgstr "Spustit" msgid "Error!" msgstr "Chyba!" msgid "

Here you will find a listing of automatic timers (AutoTimer) known to VDRAdmin-AM.

The list shows some information on AutoTimers. You can change the list's sorting by clicking the columns heading.

For each AutoTimer you have the following options:

Set its state
By clicking on \"Yes\" or \"No\" in the \"Active\" column to toggle the activity.
Quickly view its priority and lifetime
By pointing the mouse cursor to the AutoTimer's title.
Edit the AutoTimer
You can edit an AutoTimer by clicking \"edit\".
Delete the AutoTimer
To delete an AutoTimer you click \"delete\".

Each AutoTimer's state is indicated by differently coloured images:
\"on\" AutoTimer is OK and will automatically program matching broadcasts.
\"inactive\" AutoTimer is not active.

In addition to these functions you can add a new AutoTimer by clicking at the top and you can delete a number of AutoTimers at once by checking the box in the last column of those timers and clicking .

Click to force VDRAdmin-AM to reconnect to VDR, fetch the current EPG and check for matching AutoTimers.

" msgstr "

Seznam AutoÄŒasovaÄů ve VDRAdmin-AM.

Seznam zobrazuje nÄ›které informace, lze mÄ›nit Å™azení položek dle hlaviÄek sloupců.

Pro každý ÄasovaÄ máte k dispozici následující možnosti:

Nastavení stavu
Kliknutím na \"Ano\" nebo \"Ne\"v \"Aktivním\" sloupci urÄujícím aktivitu.
Rychlý pohled na prioritu a dobu trvání
Najetím kurzoru myÅ¡i na název AutoÄŒasovaÄe.
Upravení AutoÄŒasovaÄe
Upravovat AutoÄasovaÄ lze kliknutím na \"edit\".
Smazání AutoÄŒasovaÄe
Smazat AutoÄŒasovaÄ lze kliknutím na \"delete\".

Každý stav AutoÄasovaÄe je indikován různÄ› barevnými obrázky
\"on\"AutoÄasovaÄ je v pořádku a automaticky bude spuÅ¡tÄ›n.
\"inactive\"AutoÄŒasovaÄ není aktivní.

Navíc k tÄ›mto funkcím lze jeÅ¡tÄ› pÅ™idat nový AutoÄŒasovaÄ kliknutím na nahoÅ™e na stránce a také lze smazat více AutoÄŒasovaÄů zároveň zaÅ¡krtnutím boxů v posledním sloupci a kliknutím na .

KliknÄ›te zde k vynucení re-connectu k VDR, stáhnutí aktuálního EPG a kontroly AutoÄŒasovaÄů.

" msgid "

Here you can edit an automatic timer's (AutoTimer) settings.

AutoTimer is a key feature of VDRAdmin-AM. An AutoTimer consists of one or more search terms and some other settings, that are looked for regularly in the Electronic Program Guide (EPG). On match AutoTimer adds a timer in VDR automatically for that broadcast. That's very comfortable for irregularly broadcasted series or movies you don't want to miss.

" msgstr "" msgid "Activate or deactivate this AutoTimer. Deactivated AutoTimers are still stored in the AutoTimer list so that they can be activated again, but they do not record anything meanwhile. Above that you can set this to \"oneshot\" so this AutoTimer only programs the (one!) next matching broadcast." msgstr "" msgid "Choosing the right search items decides whether only the wanted broadcasts or broadcasts having similar names or even nothing gets recorded.
Case doesn't matter, \"X-Files\" matches anything \"x-files\" will match. You can set multiple search items by separating them with spaces. Broadcasts will match only if they match all configured search items.
You'd better only use letters and numbers for search items, as the EPG often miss colons, brackets and other characters.
Experts can also use regular expressions, but you have to get needed information from the VDRAdmin-AM sources (undocumented feature).

You can exclude broadcasts so that they don't get recorded even if they would match an AutoTimer. Therefore you have to enter that titles into the file vdradmind.bl, one event a line. This file must be located in your VDRAdmin-AM's configuration folder. If this string is found either in the EPG's title or in title~subtitle, this event will not be programmed by AutoTimer. So you can disable complete episodes (for example when using \"Enterprise\" as blacklist string) or only one episode (when using \"Enterprise~Azati Prime\" as blacklist string)." msgstr "" #, fuzzy msgid "Here you can define the EPG sections where VDRAdmin-AM should look for the search pattern." msgstr "Zde můžete nastavit jakou lokalizaci VDRAdmin-AM chcete používat." msgid "Use these checkboxes to limit searching for matching broadcasts to a set of weekdays." msgstr "" msgid "The channel to look for matching broadcasts or \"all\" to search in all known or wanted channels. You can define the wanted channels for AutoTimer in \"Configuration\"." msgstr "" #, fuzzy msgid "A broadcast must start after the time entered here to match. The first text field is for \"hour\", the second for \"minute\"." msgstr "Toto je Äas kdy by VDR mÄ›lo zaÄít nahrávat. První textové pole je pro \"hodinu\" a druhé pro \"minutu\"." #, fuzzy msgid "A broadcast must end before the time entered here to match. The first text field is for \"hour\", the second for \"minute\"." msgstr "Toto je Äas kdy by VDR mÄ›lo zaÄít nahrávat. První textové pole je pro \"hodinu\" a druhé pro \"minutu\"." msgid "Set this option to \"yes\" if all timers programed by this AutoTimer should have individual start/stop margins and enter the values in the next two text boxes." msgstr "" msgid "The number of minutes VDRAdmin-AM subtracts from the broadcast's start time found in the EPG." msgstr "" msgid "The number of minutes VDRAdmin-AM adds to the broadcast's stop time found in the EPG." msgstr "" msgid "An integer in the range 0...99, defining the priority of this timer and of recordings created by this timer. 0 represents the lowest value, 99 the highest. The priority is used to decide which timer shall be started in case there are two or more timers with the exact same start time. The first timer in the list with the highest priority will be used.

This value is also stored with the recording and is later used to decide which recording to remove from disk in order to free space for a new recording. If the disk runs full and a new recording needs more space, an existing recording with the lowest priority (and which has exceeded its guaranteed lifetime) will be removed.

If all available DVB cards are currently occupied, a timer with a higher priority will interrupt the timer with the lowest priority in order to start recording." msgstr "An integer in the range 0...99, defining the priority of this timer and of recordings created by this timer. 0 represents the lowest value, 99 the highest. The priority is used to decide which timer shall be started in case there are two or more timers with the exact same start time. The first timer in the list with the highest priority will be used.

This value is also stored with the recording and is later used to decide which recording to remove from disk in order to free space for a new recording. If the disk runs full and a new recording needs more space, an existing recording with the lowest priority (and which has exceeded its guaranteed lifetime) will be removed.

If all available DVB cards are currently occupied, a timer with a higher priority will interrupt the timer with the lowest priority in order to start recording." msgid "The guaranteed lifetime (in days) of a recording created by this timer. 0 means that this recording may be automatically deleted at any time by a new recording with higher priority. 99 means that this recording will never be automatically deleted. Any number in the range 1...98 means that this recording may not be automatically deleted in favour of a new recording, until the given number of days since the start time of the recording has passed by." msgstr "The guaranteed lifetime (in days) of a recording created by this timer. 0 means that this recording may be automatically deleted at any time by a new recording with higher priority. 99 means that this recording will never be automatically deleted. Any number in the range 1...98 means that this recording may not be automatically deleted in favour of a new recording, until the given number of days since the start time of the recording has passed by." msgid "Check this box if you want VDRAdmin-AM to append the broadcast's EPG subtitle to the recording's file name." msgstr "" msgid "If you enable this VDRAdmin-AM will track timers it has already programmed automatically. This is useful if want to deactivate or delete timers that have been programmed automatically in the timers listing." msgstr "" msgid "The directory this AutoTimer will place the recordings in. If the name shall contain subdirectories, these have to be delimited by '~' (since the '/' character may be part of a regular programme name).
VDRAdmin-AM will append the matching broadcast's title and subtitle (if the \"Episode\" checkbox is marked) to the directory given here.

You can also use the following keywords that are replaced in the final file name by the values supplied by for example tvm2vdr:
  • %Title% - will become the title of the event.
  • %Subtitle% - will become the subtitle of the event.
  • %Director% - will become the director of the event.
  • %Date% - will become the date of the recording.
  • %Category% - will become the category of the event (Spielfilm/Serie/...).
  • %Genre% - will become the genre of the event (Drama/Krimi/..).
  • %Year% - will become the year of production.
  • %Country% - will become the country of production.
  • %Originaltitle% - will become the original title of the event.
  • %FSK% - will become the FSK from the event.
  • %Episode% - will become the episode's title of the event.
  • %Rating% - will become the rating of the event from the EPG provider.

Note:

If you use the above keywords it's in your own responsibility to supply the complete file name for the recordings! VDRAdmin-AM will not append anything to the resulting string." msgstr "" msgid "

Here you can change general settings and base settings for timers, AutoTimers, channel selection and streaming parameters.

" msgstr "

Zde můžete zmÄ›nit obecné nastavení a základní nastavení pro ÄasovaÄe, AutoÄŒasovaÄe, výbÄ›r kanálů a parametry streamu.

" msgid "The skin you want to use." msgstr "Skin, který chcete použít:" msgid "The page you want to see at first connect to VDRAdmin-AM." msgstr "Stránka, kterou chcete zobrazit jako první pÅ™i spuÅ¡tÄ›ní VDRAdmin-AM." msgid "VDRAdmin-AM will load the given number of channels from VDR and present only those in any fields where channels can be selected. This also limits the EPG information VDRAdmin-AM will read so that you can use this to reduce VDRAdmin-AM's memory consumption and increase its performance. 0 turns this feature off and VDRAdmin-AM will use all available channels." msgstr "VDRAdmin-AM will load the given number of channels from VDR and present only those in any fields where channels can be selected. This also limits the EPG information VDRAdmin-AM will read so that you can use this to reduce VDRAdmin-AM's memory consumption and increase its performance. 0 turns this feature off and VDRAdmin-AM will use all available channels." #, fuzzy msgid "Here you can specify subnets from which access to VDRAdmin-AM does not require logging in. For example: \"192.168.0.0/24\" will include any IP starting with \"192.168.0.\", \"192.168.0.123/32\" will only match \"192.168.0.123\". Multiple subnets can be specified by separating them with spaces or commas." msgstr "Zde můžete zadat jednu nebo celý rozsah IP adres, které se budou moci pÅ™ihlásit bez pÅ™ihlaÅ¡ovacích údajů. NapÅ™. \"192.168.0.0/24\" zahrnuje vÅ¡echny IP z rozsahu \"192.168.0.\", \"192.168.0.123/32\" vyhovuje pouze \"192.168.0.123\"." msgid "Here you can set the localization VDRAdmin-AM should use." msgstr "Zde můžete nastavit jakou lokalizaci VDRAdmin-AM chcete používat." msgid "With this option the settings will be saved if VDRAdmin-AM exits. This will also save settings not available on the \"Configuration\" menu like interval and size in TV, sorting in the lists and current view in \"What's on now\"." msgstr "" msgid "Top" msgstr "Nahoru" msgid "The number of DVB cards VDR can access. Depending on this value VDRAdmin-AM will calculate critical timers in the Timer menu." msgstr "PoÄet DVB karet na které lze pÅ™istupovat. Na této hodnotÄ› závisí výpoÄet kritických ÄasovaÄů v ÄŒasovaÄ menu." msgid "The path to VDR's recordings. It's used so that VDRAdmin-AM can locate the recordings when using Recordings Streaming and reccmds.conf in the Recordings menu." msgstr "Cesta k VDR nahrávkám. Použito, aby mohl VDRAdmin-AM najít nahrávky, když používá Nahrávání Streamu a reccmds.conf v Nahrávky menu." msgid "The path where VDR's configuration files are located. If this directory contains the file reccmds.conf its content is shown in a selectbox in the Recordings menu." msgstr "Cesta kde jsou uloženy konfiguraÄní soubory VDR. Pokud tato složka obsahuje soubor reccmds.conf, jeho obsah je zobrazen v slectboxu v Nahrávky menu." msgid "The path where the EPG images are stored." msgstr "Cesta kde jsou uloženy EPG data." msgid "The username for the main user, i.e. the user having the most privileges." msgstr "Uživatelské jméno hlavního uživatele, toho který má nejvÄ›tší práva." msgid "The main user's password." msgstr "Heslo hlavního uživatele." msgid "If you want a user account having only limited privileges, this is for you. The guest user cannot modify anything, it's only allowed to view the EPG, timers, AutoTimers and recordings listings." msgstr "Pokud chcete mít úÄet uživatele s limitovanými právy, je toto pro vás. Guest úÄet nemůže nic mÄ›nit, pouze si může prohlížet EPG, ÄasovaÄe, AutoÄŒasovaÄe a koukat na nahrávky." msgid "The username for the guest user." msgstr "Uživatelské jméno pro guest úÄet." msgid "The guest user's password." msgstr "Guest heslo." msgid "The number of hours to show in the timeline." msgstr "PoÄet hodin zobrazovaných v Äasové přímce." msgid "A comma separated list of times in hh:mm format that appear in the selectbox placed at the top." msgstr "Čárkou oddÄ›lený seznam Äasů v tomto formátu hh:mm, který se bude zobrazovat v selectboxu ve vrchní Äásti stránky." msgid "Here you can (de-)activate the tooltips." msgstr "Tady můžete (de-)aktivovat nástrojové tipy." msgid "The time after which events are shown on a new day. For example setting 03:00 means that today's schedule will include any event starting before 03:00 tomorrow. Applies only to the 'Playing Today?' list." msgstr "" msgid "Show the 'Subtitle' text for each event. Not all broadcasters use this field." msgstr "" msgid "Show the 'Summary' text for each event." msgstr "" msgid "Activate or deactivate the AutoTimer function." msgstr "Aktivace a Deaktivace funkce AutoÄŒasovaÄe." msgid "VDRAdmin-AM will send an email whenever an event matches an AutoTimer and a timer has been programmed if you enable this feature." msgstr "VDRAdmin-AM vám zaÅ¡le e-mail kdykoli, když se nastaví ÄŒasovaÄ, atd... pokud aktivujete tuto vlastnost." msgid "Here you set the sending email address of the generated email." msgstr "Zde zapiÅ¡te e-mailovou adresu ze které budou vygenerované e-maily odcházet." msgid "The email address the email is sent to." msgstr "Zde zapiÅ¡te e-mailovou adresu na kterou se budou zasílat vygenerované e-maily." msgid "The outgoing mail server." msgstr "Odchozí poÅ¡tovní server." msgid "If you need to authenticate yourself at the outgoing mail server, you have to supply the username and the password below. Leaving this field empty will disable SMTPAuth." msgstr "Pokud potÅ™ebujete používat SMTP autentifikaci tak vyplňte jméno a heslo níže. Vynechání znamená vypnutí této funkce." msgid "The password for the SMTPAuth user." msgstr "Heslo pro SMTP autentifikaci." msgid "Here you can (de-)activate the tooltips in the timeline." msgstr "Zde můžete (de-)aktivovat nástrojové tipy v Äasové přímce." msgid "Here you can (de-)activate the tooltips in the list." msgstr "Zde můžete (de-)aktivovat nástrojové tipy v seznamu." msgid "Add summary to new timers:" msgstr "PÅ™idat souhrn k novým ÄasovaÄům:" msgid "If you don't want VDRAdmin-AM to add the summary taken from EPG to new timers you can switch it off here." msgstr "Pokud nechcete aby VDRAdmin-AM pÅ™idával souhrn EPG k novým ÄŒasovaÄům, zde to můžete vypnout." msgid "Enable or disable live streaming using the streamdev plugin. You also have to set the correct HTTP Port for Streamdev below." msgstr "Zapnout nebo vypnout streamování za použití streamdev pluginu. Také musíte zadat správný HTTP Port pro Streamdev" msgid "Here you have to set the port number your VDR's streamdev server listens for connections. Additionally you can also provide the stream type you like to use." msgstr "Zde musíte zadat Äíslo portu na kterém naslouchá Váš streamdev server. Také můžete zadat typ streamu, který by jste chtÄ›li použít." msgid "Enable or disable streaming of recordings.
Well actually this is no real \"streaming\", but you have to setup your workstation so that it can access VDR's recordings. You can use for example Samba or NFS for this. VDRAdmin-AM simply generates a playlist that contains all parts of the recording and sends this to your browser. If your browser and media player are configured correctly you will see the recording on your workstation's display." msgstr "" msgid "This is the path where your workstation can access VDR's recordings. This depends on your VDR and workstation setup, for example \"\\\\vdr\\videos\" or \"V:\\\" (on Windows) or \"/mnt/videos\" (on Linux)." msgstr "" msgid "The MIME type to send when using live streaming. Defaults to \"video/x-mpegurl\"." msgstr "" msgid "The suffix to use for live streaming. Defaults to \"m3u\"." msgstr "" msgid "The MIME type to send when using recordings streaming. Defaults to \"video/x-mpegurl\"." msgstr "" #, fuzzy msgid "The suffix to use for recordings streaming. Defaults to \"m3u\"." msgstr "Přípona pro nahrávky streamu:" msgid "

Here you can define two external searches that you can access in the EPG views. You simply have to find the required URL and where the search pattern has to be located. %TITLE% will be substituted by the broadcast's EPG title.

" msgstr "" msgid "Some examples:" msgstr "" msgid "Please change the hostname to your local needs!" msgstr "" msgid "

This section is for experts only, i.e. you know what you are doing!

" msgstr "" msgid "If set to \"yes\" VDRAdmin-AM will periodically refresh its local EPG cache. Else the EPG will be refreshed if the user accesses any EPG view at the web interface and the timeout set at \"Update EPG every\" has been reached." msgstr "" #, fuzzy msgid "The interval, the EPG data is refreshed from VDR and AutoTimer updates are performed (if AutoTimer feature is used)." msgstr "Interval, ve kterém budou kontrolována EPG data pro obnovu AutoÄŒasovaÄů." msgid "

If you want to limit the number of channels used in some parts of VDRAdmin-AM, this is for you!

Use the radio buttons to activate or deactivate the wanted channels in the named menu.

To add channels to the list of wanted channels you have to select them in the left side selectbox and click . If you want to remove channels from the list of wanted channels you have to select them in the right side selectbox and click .

" msgstr "" msgid "Usually channels that don't have EPG information are hidden in all EPG views. If you don't want them to be hidden you have to set this option to \"yes\"." msgstr "" msgid "Edit Timer" msgstr "Upravit ÄasovaÄ" #, fuzzy msgid "Edit EPG" msgstr "Upravit" #, fuzzy msgid "

Here you can edit the descriptive fields of an existing EPG entry.

" msgstr "

Zde můžete upravit nastavení ÄŒasovaÄe.

" #, fuzzy msgid "Channel (readonly)" msgstr "Kanál" msgid "This is the channel of the EPG entry. It cannot be changed." msgstr "" #, fuzzy msgid "Time (readonly)" msgstr "Pouze pro Ätení" msgid "This is the start and end time of the entry. It cannot be changed." msgstr "" msgid "Change this string to give this EPG Entry a new title. It must consist of only one line of text." msgstr "" msgid "Change this string to give this EPG Entry a new subtitle. It must consist of only one line of text." msgstr "" msgid "Change the text in this field to edit the description of this entry. The text can consist of one or more lines." msgstr "" #, fuzzy msgid "VPS (readonly)" msgstr "Pouze pro Ätení" msgid "If available this field shows the vps time of the EPG entry. It cannot be changed." msgstr "" #, fuzzy msgid "Video tracks (readonly)" msgstr "Video stopy:" msgid "If available this field shows the video track(s). It cannot be changed." msgstr "" #, fuzzy msgid "Audio tracks (readonly)" msgstr "Audio stopy:" msgid "If available this field shows the audio track(s). It cannot be changed." msgstr "" msgid "No Help Available" msgstr "NápovÄ›da není dostupná" msgid "

No help available yet. For adding or changing text please contact amair.sob@googlemail.com.

" msgstr "

Nápověda zatím není dostupná. Pro přidání nebo změnu textu pište prosím sem: amair.sob@googlemail.com.

" msgid "Recordings" msgstr "Nahrávky" msgid "

Here you will find a listing of recordings known to VDR. The headline will also show you VDR's total and free disk space.

The listing showing you some information on the recordings. You can change the list's sorting by clicking the columns heading. Above the list you'll see the navigation path. If you want to view the contents of previous folders you'll have to click on its name in that path.

Each row contains this information:

Date
The date when the recording has been done. In case of folders this will show the number of recordings the folder contains.
Time
The time when the recording has been done. In case of folders this will show the number of new recordings the folder contains.
Name
The recording's or folder's name. Click it to show the recording's summary or descend into the folder.
Rename (\"edit\")
Rename a recording.

Note:

This only works if VDR has the MOVR or RENR SVDRP command which is not a core VDR feature but provided by the Liemikuutio patch set.
Delete (\"delete\")
Delete a recording.
Stream (\"stream\")
This column is only shown if you activated and configured Recordings Streaming in the Configuration menu. You can watch the recording at your workstation.

In addition to these functions you can delete a number of recordings at once by checking the box in the last but one column of those recordings and clicking .

If you've set the path the VDR's configuration files and have entries in VDR's reccmds.conf you can run those commands for the selected recording by selecting the wanted command in the select box locate next to Commands: and pressing the button.

Use to force reloading of VDR's recordings listing.

" msgstr "" msgid "

Here you will find a listing of timers known to VDR.

On top you will find a chart showing a day's timers graphically. This provides an quick overview on what's going on at the specified day and helps you in finding conflicting timers. Moving the mouse cursor above any timer box will display a tooltip containing the timer's title, priority, lifetime and duration.

Below the chart you'll find the timers list showing you some information on the timers. You can change the list's sorting by clicking the columns heading.

For each timer you have the following options:

Set its state
By clicking on \"Yes\", \"No\", \"VPS\" or \"Auto\" in the \"Active\" column.
Quickly view its priority and lifetime
By pointing the mouse cursor to the timer's title.
View its EPG entry
Timers that have set AutoTimer Checking to \"Transmission Identification\" will show you the corresponding EPG entry if you click on the timer's title.
Edit the timer
You can edit a timer by clicking \"edit\".
Delete the timer
To delete a timer you click \"delete\".

Each timer's state is indicated by differently coloured boxes (in the chart view) or images (in the list view):
    / \"on\" Timer is OK and will record.
    / \"problem\" Timer conflicts with other timers. That's not critical, as long as you have enough DVB cards for the parallel recordings.
    / \"impossible\" Timer is critical and will most likely not record.
    / \"inactive\" Timer is not active.

In addition to these functions you can add a new timer by clicking at the top and you can delete a number of timers at once by checking the box in the last column of those timers and clicking .

You can and selected timers.

" msgstr "" msgid "

Here you can edit a timer's settings.

" msgstr "

Zde můžete upravit nastavení ÄŒasovaÄe.

" msgid "Timer Active:" msgstr "ÄŒasovaÄ aktivní" msgid "Activate or deactivate this timer. Deactivated timers are still stored in the timer list so that they can be activated again, but they do not record anything meanwhile." msgstr "" msgid "AutoTimer Checking:" msgstr "Kontrola AutoÄŒasovaÄů:" msgid "Depending on how this timer has been programmed you have up to three possible settings:" msgstr "" #, fuzzy msgid "Transmission Identification" msgstr "Identifikace" msgid "Monitor this timer using the identification provided in the EPG. Please note that this only works if the provided identification is a fix and unique value! This option is not available with timers programmed in VDR." msgstr "" msgid "Time" msgstr "ÄŒas" msgid "Monitor this timer using the start and stop time." msgstr "Sledovat tento ÄasovaÄ pomocí zaÄátku a konce nahrávání." msgid "off" msgstr "off" msgid "Do not monitor this timer." msgstr "Nesledovat tento ÄŒasovaÄ." msgid "The channel to record." msgstr "Kanál k nahrávání." msgid "Day Of Recording:" msgstr "Den nahrávání" msgid "The day when the timer should get active. You can enter the day in two formats:
  • Two digits (DD). This will use the current month and year.
  • ISO norm (YYYY-MM-DD). Program your timers as far in the future as you like.
In case you want to program a repeating timer you can use the seven checkboxes below the text field. Check the box for each day you want the timer to get active." msgstr "" msgid "Start Time:" msgstr "ZaÄátek nahrávání:" msgid "This is the time when the timer should start recording. The first text field is for \"hour\", the second for \"minute\"." msgstr "Toto je Äas kdy by VDR mÄ›lo zaÄít nahrávat. První textové pole je pro \"hodinu\" a druhé pro \"minutu\"." msgid "End Time:" msgstr "Konec Äasu:" msgid "This is the time when the timer should stop recording. The first text field is for \"hour\", the second for \"minute\"." msgstr "Toto je Äas kdy by VDR mÄ›lo ukonÄit nahrávání. První textové pole je pro \"hodinu\" a druhé pro \"minutu\"." msgid "Title of Recording:" msgstr "Název nahrávky:" msgid "The file name this timer will give to a recording. If the name shall contain subdirectories, these have to be delimited by '~' (since the '/' character may be part of a regular programme name).

The special keywords TITLE and EPISODE, if present, will be replaced by the title and episode information from the EPG data at the time of recording (if that data is available). If at the time of recording either of these cannot be determined, TITLE will default to the channel name, and EPISODE will default to a blank." msgstr "" msgid "Summary:" msgstr "Souhrn:" msgid "Arbitrary text that describes the recording made by this timer. If this field is not empty, its contents will be written into the summary.vdr or info.vdr file of the recording." msgstr "Libovolný text popisující nahrávku z ÄasovaÄe. Jestliže pole není prázdné, tak text bude zapsán do souboru summary.vdr nebo info.vdr," msgid "Your Browser does not support frames!" msgstr "Váš prohlížeÄ nepodporuje rámy!" msgid "What's On Now?" msgstr "Co běží nyní?" msgid "Playing Today?" msgstr "Co poběží dnes?" msgid "Remote Control" msgstr "Dálkové ovládání" msgid "Watch TV" msgstr "Sleduj TV" #, fuzzy msgid "Commands" msgstr "Příkazy:" #, fuzzy msgid "Search" msgstr "hledat" msgid "Authorization Required" msgstr "Autentifikace je nutná" msgid "This server could not verify that you are authorized to access the document requested. Either you supplied the wrong credentials (e.g. bad password), or your browser doesn't understand how to supply the credentials required." msgstr "Server nemohl rozpoznat, zda jste autorizován k přístupu k tomuto dokumentu. BuÄ jste vložil Å¡patná údaje (napÅ™. heslo) nebo Váš prohlížeÄ nepodporuje pÅ™edávání parametrů, které jsou vyžadované." msgid "VPS" msgstr "VPS" msgid "close" msgstr "zavřít" msgid "view" msgstr "náhled" #, fuzzy msgid "search" msgstr "hledat" #, fuzzy msgid "edit" msgstr "Upravit" msgid "Length" msgstr "" msgid "Video tracks:" msgstr "Video stopy:" msgid "Audio tracks:" msgstr "Audio stopy:" msgid "Subtitles:" msgstr "Titulky:" #, fuzzy msgid "Video tracks" msgstr "Video stopy:" #, fuzzy msgid "Audio tracks" msgstr "Audio stopy:" msgid "TV select" msgstr "Naladit TV" msgid "Stream" msgstr "Stream" #, fuzzy msgid "Channel group:" msgstr "Kanál" msgid "Go!" msgstr "Start!" msgid "Search for other show times" msgstr "Hledat jiné vysílací Äasy" #, fuzzy msgid "No Information" msgstr "Více informací" #, fuzzy msgid "No EPG information available" msgstr "Žádné informace" msgid "Playing Today" msgstr "Běží dnes" msgid "starting at" msgstr "zaÄíná v" msgid "What's on:" msgstr "Co běží:" msgid "at" msgstr "v" msgid "now" msgstr "nyní" msgid "to" msgstr "do" msgid "Duration:" msgstr "Délka:" msgid "min" msgstr "min" msgid "at:" msgstr "v:" msgid "You need JavaScript to use the timeline!" msgstr "K používání Äasové linie potÅ™ebujete JavaScript!" msgid "Rename Recording" msgstr "PÅ™ejmenovat nahrávku" msgid "Original Name of Recording:" msgstr "Původní jméno nahrávky:" msgid "New Name of Recording:" msgstr "Nové jméno nahrávky:" msgid "Subtitle:" msgstr "Titulky:" msgid "Rename" msgstr "PÅ™ejmenovat" msgid "Total:" msgstr "Celkové:" msgid "h" msgstr "h" msgid "Free:" msgstr "Volno:" msgid "Date" msgstr "Datum" msgid "Total" msgstr "Celkem" msgid "New" msgstr "Nový" msgid "Play" msgstr "Hrát" msgid "Cut" msgstr "StÅ™ihnout" msgid "Delete recording?" msgstr "Smazat nahrávku?" msgid "Refresh" msgstr "Obnovit" msgid "Commands:" msgstr "Příkazy:" msgid "Really run this command?" msgstr "Opravdu spustit tento příkaz?" msgid "stream all recordings" msgstr "" msgid "Delete Selected Recordings" msgstr "Smazat oznaÄené nahrávky" msgid "Delete all selected recordings?" msgstr "Smazat vÅ¡echny oznaÄené nahrávky?" #, fuzzy msgid "No recordings available" msgstr "NápovÄ›da není dostupná" msgid "Transponder:" msgstr "Transponder:" msgid "CA-System:" msgstr "CA-System:" msgid "New Timer" msgstr "Nový ÄasovaÄ" msgid "Edit timer status?" msgstr "Upravit ÄasovaÄ?" msgid "This timer is inactive!" msgstr "ÄŒasovaÄ není aktivní!" msgid "This timer is impossible!" msgstr "Tento ÄasovaÄ není možné nastavit!" msgid "No more timers on other transponders possible!" msgstr "Žádné další ÄasovaÄe na ostatních transpondérech nejsou možné!" msgid "Timer OK." msgstr "ÄŒasovaÄ je v cajku." msgid "Auto" msgstr "Auto" msgid "activate" msgstr "aktivní" msgid "inactivate" msgstr "deaktivovat" msgid "selected timers" msgstr "vybrané ÄasovaÄe" msgid "Delete Selected Timers" msgstr "Vymazat vybrané ÄasovaÄe" msgid "No timers defined!" msgstr "Žádný ÄasovaÄ není definován!" msgid "Create New Timer" msgstr "VytvoÅ™it nový ÄasovaÄ" msgid "Buffer:" msgstr "Zásobník:" msgid "Use VPS:" msgstr "Použít VPS:" msgid "readonly" msgstr "Pouze pro Ätení" msgid "Timer has been set by AutoTimer pattern:" msgstr "ÄŒasovaÄ byl nastaven podle AutoÄŒasovaÄe" msgid "TV" msgstr "TV" msgid "Interval:" msgstr "Interval:" msgid "sec." msgstr "sec." msgid "G" msgstr "G" msgid "Grab the picture!" msgstr "Ulož obrázek!" msgid "Size:" msgstr "Velikost:" msgid "Open in separate window" msgstr "OtevÅ™i v samostatném oknÄ›" msgid "VDR Commands" msgstr "VDR příkazy" msgid "Export channels as playlist:" msgstr "" msgid "Number of lines to show:" msgstr "PoÄet zobrazených řádků:" msgid "unlimited" msgstr "neomezený" msgid "SVDRP commands:" msgstr "SVDRP příkazy:" msgid "Commands defined in commands.conf:" msgstr "Příkazy definované v commands.conf:" msgid "Output" msgstr "Výstup" msgid "What's your VDR hostname (e.g video.intra.net)?" msgstr "Jaké je VaÅ¡e VDR hostname?" msgid "On which port does VDR listen to SVDRP queries?" msgstr "Na jakém portu mám oÄekávat SVDRP příkazy?" msgid "On which address should VDRAdmin-AM listen (0.0.0.0 for any)?" msgstr "Na jaké adrese má Äekat VDRAdmin-AM (0.0.0.0 pro jakoukoli)?" msgid "On which port should VDRAdmin-AM listen?" msgstr "Na jakém portu má Äekat VDRAdmin-AM?" msgid "Username?" msgstr "Uživ. jméno?" msgid "Password?" msgstr "Heslo?" msgid "Where are your recordings stored?" msgstr "Kam ukládáte nahrávky z VDR?" msgid "Where are your VDR's configuration files located?" msgstr "Kde se nacházejí konfiguraÄní soubory VDR?" msgid "Config file written successfully." msgstr "KonfiguraÄní soubor uložen v pořádku." #, perl-format msgid "%s %s started with pid %d." msgstr "%s %s startuje s pidem %d." msgid "Not found" msgstr "Nefunguje" msgid "The requested URL was not found on this server!" msgstr "Požadovaná URL nebyla na tomto serveru nalezena!" msgid "Forbidden" msgstr "Zakázáno" msgid "You don't have permission to access this function!" msgstr "Nemáte práva pro využití této funkce!" #, fuzzy msgid "All channels" msgstr "Kanály" #, fuzzy msgid "Selected channels" msgstr "Vybrat vÅ¡e/Nic" #, fuzzy msgid "TV channels" msgstr "Kanály" #, fuzzy msgid "Radio channels" msgstr "Kanály" #, perl-format msgid "Access to file \"%s\" denied!" msgstr "Přístup k souboru \"%s\" odmítnut!" #, perl-format msgid "The URL \"%s\" was not found on this server!" msgstr "URL \"%s\" nebyla na tomto serveru nalezena!" msgid "Your favorites" msgstr "" #, fuzzy msgid "Search results" msgstr "Hledat v:" #, fuzzy msgid "Default" msgstr "Smazat" msgid "--- no timer ---" msgstr "" #, fuzzy msgid "unknown" msgstr "nyní" msgid "none" msgstr "" #, perl-format msgid "Can't open file \"%s\"!" msgstr "Nemohu otevřít soubor \"%s\"!" #, perl-format msgid "Can't connect to VDR at %s:%s: %s

Please check if VDR is running and if VDR's svdrphosts.conf is configured correctly." msgstr "Nemohu se připojit k VDR v %s:%s: %s

Prosím zkontrolujte, zda VDR běží a pokud je soubor soubor svdrphosts.conf řádnÄ› nastaven." #, perl-format msgid "Error while sending command to VDR at %s" msgstr "Chyba pÅ™i posílání příkazu k VDR v %s" #, fuzzy msgid "Internal error:" msgstr "Interval:" msgid "Lookup movie in the Internet-Movie-Database (IMDb)" msgstr "Hledat film v Internetové filmové databázi (IMDb)" msgid "Can't find EPG entry!" msgstr "Nemohu nalézt EPG vstup!" msgid "Playing Tomorrow" msgstr "Co poběží zítra?" #, perl-format msgid "Playing on the %s" msgstr "Poběží v %s" msgid "next" msgstr "další" msgid "What's on after" msgstr "Co běží pak" msgid "What's on at" msgstr "Co běží v" msgid "Suitable matches for:" msgstr "" msgid "short view" msgstr "struÄný pÅ™ehled" msgid "long view" msgstr "detailní pÅ™ehled" msgid "Schedule" msgstr "Plán" #, perl-format msgid "Can't write configuration file %s! Reason: %s" msgstr "" #, perl-format msgid "Configuration file %s not writable! Configuration won't be saved!" msgstr "" msgid "Timers" msgstr "ÄŒasovaÄe" msgid "System default" msgstr "Defaultní nastavení" vdradmin-am-3.6.13/po/de.po000066400000000000000000002210601443716113400153560ustar00rootroot00000000000000# Copyright (C) Andreas Mair # This file is distributed under the same license as the VDRAdmin-AM package. # # Andreas Mair , 2007 # msgid "" msgstr "" "Project-Id-Version: VDRAdmin-AM-3.6.10\n" "Report-Msgid-Bugs-To: Andreas Mair \n" "POT-Creation-Date: 2012-07-09 12:23+0200\n" "PO-Revision-Date: 2011-11-19 08:55+0100\n" "Last-Translator: Andreas Mair \n" "Language-Team: German \n" "Language: de\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" msgid "About" msgstr "Über" msgid "License" msgstr "Lizenz" msgid "Authors" msgstr "Autoren" msgid "Current author (VDRAdmin-AM branch):" msgstr "Derzeitiger Autor (VDRAdmin-AM):" msgid "Original author (VDRAdmin):" msgstr "Ursprünglicher Autor (VDRAdmin):" msgid "Translation Team" msgstr "Übersetzungsteam" msgid "English:" msgstr "Englisch:" msgid "German:" msgstr "Deutsch:" msgid "French:" msgstr "Französisch:" msgid "At the moment unmaintained, former translations by:" msgstr "Wird zurzeit nicht aktualisiert, ältere Übersetzungen von:" msgid "Spanish:" msgstr "Spanisch:" msgid "Finnish:" msgstr "Finnisch:" msgid "Dutch:" msgstr "Holländisch:" msgid "Russian:" msgstr "Russisch:" msgid "Czech:" msgstr "Tschechisch:" msgid "Italian:" msgstr "Italienisch:" msgid "Hungarian:" msgstr "Ungarisch" msgid "Information" msgstr "Informationen" msgid "VDRAdmin-AM version:" msgstr "VDRAdmin-AM Version:" msgid "VDR version:" msgstr "VDR Version:" msgid "Supported features in VDR:" msgstr "Unterstützte Funktionen im VDR:" msgid "EPGSearch" msgstr "EPGSearch" msgid "EPGSearch Plugin" msgstr "EPGSearch Plugin" msgid "LiveTV Streaming" msgstr "LiveTV Streaming" msgid "Streamdev Plugin" msgstr "Streamdev Plugin" msgid "Xineliboutput Plugin" msgstr "Xineliboutput Plugin" msgid "Rename Recordings (Liemikuutio Patch)" msgstr "Aufnahmen umbenennen (Liemikuutio Patch)" msgid "Getting Help and Reporting Bugs" msgstr "Hilfe bekommen und Fehler melden" msgid "If you need help please first try to use the online help you'll find on some pages. You can access it by clicking \"\"." msgstr "Wenn Sie Hilfe benötigen, dann werfen Sie bitte zuerst einen Blick in die Online-Hilfe, die für einige Seiten verfügbar ist. Sie können Sie aufrufen indem Sie \"\" anklicken." msgid "If this doesn't provide the information you need you can try to get help at VDR-Portal if you understand German language. Please use the announcement thread if possible, search for:" msgstr "Wenn dies nicht die benötigte Information liefert, dann können Sie versuchen Hilfe im VDR-Portal zu bekommen. Bitte verwenden Sie hierfür wenn möglich den Ankündigungsthread, suchen Sie dafür nach:" msgid "If you think you have found a bug please check that it's a new one and report it in the VDRAdmin-AM BugTracking system." msgstr "Wenn Sie meinen, dass Sie einen Fehler gefunden haben, dann überprüfen Sie im VDRAdmin-AM BugTracking System, ob es sich um einen neuen Fehler handelt und legen Sie gegebenenfalls einen neuen Fehlerbericht an." msgid "AutoTimer" msgstr "AutoTimer" msgid "Priority:" msgstr "Priorität:" msgid "Lifetime:" msgstr "Lebenszeit:" msgid "New AutoTimer" msgstr "Neuer AutoTimer" msgid "Help" msgstr "Hilfe" msgid "Active" msgstr "Aktiv" msgid "Channel" msgstr "Kanal" msgid "Start" msgstr "Beginn" msgid "Stop" msgstr "Ende" msgid "Name" msgstr "Name" msgid "Select all/none" msgstr "Alle/keine auswählen" msgid "Yes" msgstr "Ja" msgid "No" msgstr "Nein" msgid "Edit" msgstr "Bearbeiten" msgid "Delete timer?" msgstr "Timer löschen?" msgid "Delete" msgstr "Löschen" msgid "Force Update" msgstr "Manuelles Update" msgid "Delete Selected AutoTimers" msgstr "Ausgewählte AutoTimer löschen" msgid "Delete all selected timers?" msgstr "Ausgewählte Timer wirklich löschen?" msgid "No AutoTimers defined!" msgstr "Es wurden noch keine AutoTimer definiert!" msgid "Add New AutoTimer" msgstr "Neuen AutoTimer anlegen" msgid "Edit AutoTimer" msgstr "AutoTimer editieren" msgid "AutoTimer Active:" msgstr "AutoTimer aktiv:" msgid "oneshot" msgstr "einmal" msgid "Search Patterns:" msgstr "Suchbegriffe:" msgid "Search in:" msgstr "zu suchen in:" msgid "Title" msgstr "Titel" msgid "Subtitle" msgstr "Untertitel" msgid "Description" msgstr "Beschreibung" msgid "Search only on these days:" msgstr "Nur an diesen Tagen suchen:" msgid "Monday" msgstr "Montag" msgid "Tuesday" msgstr "Dienstag" msgid "Wednesday" msgstr "Mittwoch" msgid "Thursday" msgstr "Donnerstag" msgid "Friday" msgstr "Freitag" msgid "Saturday" msgstr "Samstag" msgid "Sunday" msgstr "Sonntag" msgid "Channel:" msgstr "Kanal:" msgid "all" msgstr "alle" msgid "Starts After:" msgstr "Beginnt frühestens:" msgid "o'clock" msgstr "Uhr" msgid "Ends Before:" msgstr "Endet spätestens:" msgid "Override Start/Stop Margins:" msgstr "Zeitpuffer für Anfang/Ende überschreiben:" msgid "Time Margin at Start:" msgstr "Zeitpuffer Anfang:" msgid "minutes" msgstr "Minuten" msgid "Time Margin at Stop:" msgstr "Zeitpuffer Ende:" msgid "Episode:" msgstr "Serie:" msgid "Remember programmed timers:" msgstr "Programmierte Timer merken:" msgid "Directory:" msgstr "Ordner:" msgid "Save" msgstr "Speichern" msgid "Test" msgstr "Testen" msgid "Cancel" msgstr "Abbrechen" msgid "Broadcasted" msgstr "Ausgestrahlt" msgid "Stored in" msgstr "Abgelegt in" msgid "No matches found!" msgstr "Nichts gefunden!" msgid "Configuration" msgstr "Konfiguration" msgid "General Settings" msgstr "Allgemeine Einstellungen" msgid "Template:" msgstr "Template:" msgid "Skin:" msgstr "Skin:" msgid "Login Page:" msgstr "Startseite:" msgid "Number of channels to use:" msgstr "Anzahl der zu verwendenden Kanäle:" msgid "Local net (no login required):" msgstr "Lokales Netz (kein Login notwendig):" msgid "Language:" msgstr "Sprache:" msgid "Save settings on exit:" msgstr "Einstellungen beim Beenden speichern:" msgid "VDR" msgstr "VDR" msgid "Number of DVB cards:" msgstr "Anzahl der DVB-Karten:" msgid "Path to recordings:" msgstr "Pfad der Aufnahmen:" msgid "Path to configuration files:" msgstr "Pfad zu den Konfigurationsdateien:" msgid "Path to EPG images:" msgstr "Pfad zu den EPG-Bildern:" msgid "Identification" msgstr "Identifikation" msgid "Username:" msgstr "Benutzername:" msgid "Password:" msgstr "Passwort:" msgid "Guest Account:" msgstr "Gast-Zugang:" msgid "Guest Username:" msgstr "Gast Benutzername:" msgid "Guest Password:" msgstr "Gast Passwort:" msgid "Timeline" msgstr "Zeitleiste" msgid "Hours:" msgstr "Stunden:" msgid "Times:" msgstr "Zeiten:" msgid "Also used for other EPG views!" msgstr "Wird auch für andere EPG-Ansichten verwendet!" msgid "Tooltips:" msgstr "Tooltips:" msgid "Electronic Program Guide (EPG)" msgstr "Elektronischer Programmführer (EPG)" msgid "Day begins at:" msgstr "Den Tag beginnen um:" msgid "Show Subtitle:" msgstr "Untertitel anzeigen:" msgid "Show Summary:" msgstr "Zusammenfassung anzeigen:" msgid "Active:" msgstr "Aktiv:" msgid "Send email after programming timer:" msgstr "Nach programmiertem Timer E-Mail verschicken:" msgid "Send email as:" msgstr "E-Mail verschicken als:" msgid "Send email to:" msgstr "E-Mail schicken an:" msgid "Mail server:" msgstr "Mail-Server:" msgid "SMTPAuth user:" msgstr "Benutzername für SMTPAuth:" msgid "SMTPAuth password:" msgstr "Passwort für SMTPAuth:" msgid "Track schedule changes by:" msgstr "Verfolge Ausstrahlungsänderungen anhand:" msgid "Broadcast time" msgstr "Ausstrahlungszeit" msgid "Event id" msgstr "Event-ID" msgid "Timer" msgstr "Timer" msgid "Tooltips in timeline:" msgstr "Tooltips in der Zeitleiste:" msgid "Tooltips in list:" msgstr "Tooltips in der Liste:" msgid "Streaming" msgstr "Streaming" msgid "Live Streaming:" msgstr "LiveTV streamen:" msgid "HTTP Port of Streamdev (also possible 3000/ts):" msgstr "HTTP-Port von Streamdev (auch möglich 3000/ts):" msgid "HTTP Port of Xineliboutput (e.g. 37890):" msgstr "HTTP-Port von Xineliboutput (z.B. 37890):" msgid "Recordings Streaming:" msgstr "Aufnahmen streamen:" msgid "Path to VDR Recordings on your workstation:" msgstr "Pfad zu den VDR-Aufnahmen auf Ihrem PC:" msgid "MIME type for live streaming:" msgstr "MIME-Typ für das Streamen von LiveTV:" msgid "Suffix for live streaming:" msgstr "Dateierweiterung für das Streamen von LiveTV:" msgid "MIME type for recordings streaming:" msgstr "MIME-Typ für das Streamen von Aufnahmen:" msgid "Suffix for recordings streaming:" msgstr "Dateierweiterung für das Streamen von Aufnahmen:" msgid "Bandwidth of Streams:" msgstr "Bandbreite des Streams:" msgid "External Search" msgstr "Externe Suche" msgid "URL:" msgstr "URL:" msgid "Title:" msgstr "Titel:" msgid "User-defined search:" msgstr "Benutzerdefinierte Suche:" msgid "Expert" msgstr "Expertenmodus" msgid "Update EPG data in background:" msgstr "EPG-Daten im Hintergrund aktualisieren:" msgid "Update EPG every:" msgstr "EPG aktualisieren alle:" msgid "Channel Selections" msgstr "Kanalauswahl" msgid "Show channels without EPG information:" msgstr "Kanäle ohne EPG Informationen anzeigen:" msgid "In \"AutoTimer\"?" msgstr "Bei \"AutoTimer\"?" msgid "Apply" msgstr "Anwenden" msgid "EPG Search Blacklists" msgstr "EPG Search Ausschlusslisten" msgid "New Blacklist" msgstr "Neue Ausschlussliste" msgid "Search pattern" msgstr "Suchbegriff" msgid "From" msgstr "Von" msgid "To" msgstr "Bis" msgid "Delete blacklist?" msgstr "Ausschlussliste löschen?" msgid "Delete Selected Blacklists" msgstr "Ausgewählte Ausschlusslisten löschen" msgid "Delete all selected blacklists?" msgstr "Alle ausgewählten Ausschlusslisten wirklich löschen?" msgid "EPG search" msgstr "EPG search" msgid "EPG Search" msgstr "EPG Search" msgid "Use template" msgstr "Von Vorlage" msgid "New Search" msgstr "Neue Suche" msgid "Edit Template" msgstr "Suchvorlage bearbeiten" msgid "Settings" msgstr "Einstellungen" msgid "Action" msgstr "Aktion" msgid "Find" msgstr "Suche starten" msgid "Show Favorites" msgstr "Favoriten anzeigen" msgid "Delete Selected Searches" msgstr "Ausgewählte Suchen löschen" msgid "Delete all selected searches?" msgstr "Alle ausgewählten Suchen wirklich löschen?" msgid "Execute Selected Searches" msgstr "Ausgewählte Suchen ausführen" msgid "Duration" msgstr "Dauer" msgid "More Information" msgstr "mehr Infos" msgid "Channels" msgstr "Programmübersicht" msgid "Record" msgstr "Sendung aufnehmen" msgid "Add New Blacklist" msgstr "Neue Ausschlussliste anlegen" msgid "Edit Blacklist" msgstr "Ausschlussliste bearbeiten" msgid "Add New Template" msgstr "Neue Suchvorlage anlegen" msgid "Add New Search" msgstr "Neuen Suche anlegen" msgid "Edit Search" msgstr "Suche bearbeiten" msgid "Small search pattern.\\nDo you really want to use it?" msgstr "Kurzes Suchmuster.\\nSoll es wirklich verwendet werden?" msgid "You didn't select at least one of\\ntitle, subtitle or description.\\nDo you really want to use this search?" msgstr "Sie haben zum Durchsuchen weder\\nTitel noch Untertitel noch Beschreibung ausgewählt.\\nSoll die Suche wirklich verwendet werden?" msgid "Hide results" msgstr "Ergebnis ausblenden" msgid "Name:" msgstr "Name:" msgid "Search Term:" msgstr "Suche:" msgid "Search Mode:" msgstr "Suchmodus:" msgid "phrase" msgstr "Ausdruck" msgid "all words" msgstr "alle Worte" msgid "at least one word" msgstr "ein Wort" msgid "match exactly" msgstr "exakt" msgid "regular expression" msgstr "regulärer Ausdruck" msgid "fuzzy" msgstr "unscharf" msgid "Tolerance for \"fuzzy\":" msgstr "Toleranz für \"unscharf\":" msgid "Match Case:" msgstr "Groß/klein:" msgid "Use extended EPG info:" msgstr "Verwende erweiterte EPG Info:" msgid "Ignore missing categories?" msgstr "Ignoriere fehlende Kategorien?" msgid "Use Channel:" msgstr "Verwende Kanal:" msgid "no" msgstr "nein" msgid "interval" msgstr "Bereich" msgid "channel group" msgstr "Kanalgruppe" msgid "only FTA" msgstr "ohne PayTV" msgid "Range:" msgstr "Bereich:" msgid "Channel Group:" msgstr "Kanalgruppe:" msgid "Use Time:" msgstr "Verwende Uhrzeit:" msgid "Start After:" msgstr "Start nach:" msgid "Start Before:" msgstr "Start vor:" msgid "Use Duration:" msgstr "Verwende Dauer:" msgid "Min. Duration:" msgstr "Minimale Dauer:" msgid "hh:mm" msgstr "hh:mm" msgid "Max. Duration:" msgstr "Maximale Dauer:" msgid "Use Day of Week:" msgstr "Verwende Wochentag:" msgid "Use Blacklists:" msgstr "Verwende Ausschlusslisten:" msgid "selection" msgstr "Auswahl" msgid "Use in Favorites Menu:" msgstr "In Favoritenmenü verwenden:" msgid "Use as Search Timer:" msgstr "Als Suchtimer verwenden:" msgid "yes" msgstr "Ja" msgid "user-defined" msgstr "benutzerdefiniert" msgid "record" msgstr "aufnehmen" msgid "announce by OSD" msgstr "per OSD ankündigen" msgid "switch only" msgstr "nur umschalten" msgid "announce and switch" msgstr "ankündigen und Umschalten" msgid "announce by mail" msgstr "per Mail ankündigen" msgid "First day:" msgstr "Erster Tag:" msgid "Last day:" msgstr "Letzter Tag:" msgid "Auto delete:" msgstr "Automatisch löschen:" msgid "count recordings" msgstr "Anzahl Aufnahmen" msgid "count days" msgstr "Anzahl Tage" msgid "After ... recordings:" msgstr "Nach ... Aufnahmen:" msgid "After ... days after first recording:" msgstr "Nach ... Tagen nach erster Aufnahme:" msgid "Settings for action \"record\"" msgstr "Einstellungen für \"aufnehmen\"" msgid "Series Recording:" msgstr "Serienaufnahme:" msgid "Delete Recordings After ... Days:" msgstr "Aufnahme nach ... Tagen löschen:" msgid "Keep ... Recordings:" msgstr "Behalte ... Aufnahmen:" msgid "Pause, when ... recordings exist:" msgstr "Pause, wenn ... Aufnahmen existieren:" msgid "Avoid Repeats:" msgstr "Vermeide Wiederholung:" msgid "Allowed Repeats:" msgstr "Erlaubte Wiederholungen:" msgid "Only Repeats Within ... Days:" msgstr "Nur Wiederholungen innerhalb ... Tagen:" msgid "Compare:" msgstr "Vergleiche:" msgid "Minimal match of description in %:" msgstr "Minimale Übereinstimmung der Beschreibung in %:" msgid "VPS:" msgstr "VPS:" msgid "Settings for action \"switch only\"" msgstr "Settings für \"nur umschalten\"" msgid "Switch ... Minutes Before Start:" msgstr "Umschalten ... Minuten vor Start:" msgid "Unmute sound:" msgstr "Ton anschalten:" msgid "Settings for action \"announce and switch\"" msgstr "Einstellungen für \"ankündigen und umschalten\"" msgid "Ask ... Minutes Before Start:" msgstr "Nachfrage ... Minuten vor Start:" msgid "Delete template" msgstr "Suchvorlage löschen" msgid "Delete this template?" msgstr "Diese Suchvorlage löschen?" msgid "Save as template" msgstr "Als Vorlage speichern" msgid "Run" msgstr "Ausführen" msgid "Error!" msgstr "Fehler!" msgid "

Here you will find a listing of automatic timers (AutoTimer) known to VDRAdmin-AM.

The list shows some information on AutoTimers. You can change the list's sorting by clicking the columns heading.

For each AutoTimer you have the following options:

Set its state
By clicking on \"Yes\" or \"No\" in the \"Active\" column to toggle the activity.
Quickly view its priority and lifetime
By pointing the mouse cursor to the AutoTimer's title.
Edit the AutoTimer
You can edit an AutoTimer by clicking \"edit\".
Delete the AutoTimer
To delete an AutoTimer you click \"delete\".

Each AutoTimer's state is indicated by differently coloured images:
\"on\" AutoTimer is OK and will automatically program matching broadcasts.
\"inactive\" AutoTimer is not active.

In addition to these functions you can add a new AutoTimer by clicking at the top and you can delete a number of AutoTimers at once by checking the box in the last column of those timers and clicking .

Click to force VDRAdmin-AM to reconnect to VDR, fetch the current EPG and check for matching AutoTimers.

" msgstr "

Hier finden Sie eine Liste aller AutoTimer, die VDRAdmin-AM kennt.

Die Liste zeigt Ihnen einige Informationen zu den AutoTimern. Sie können die Sortierung dieser Liste ändern indem Sie auf die Spaltenüberschriften klicken.

Für jeden AutoTimer haben Sie die folgenden Möglichkeiten:

Setzen seines Zustands
Durch klicken auf \"Ja\" oder \"Nein\" in der \"Aktiv\" Spalte können Sie den AutoTimer aktivieren bzw. deaktivieren.
Schnellanzeige seiner Priorität und Lebenszeit
Der Mauszeiger muss dazu über den Namen des AutoTimers bewegt werden.
Bearbeiten eines AutoTimers
Sie können einen AutoTimer bearbeiten indem Sie auf \"edit\" klicken.
Löschen eines AutoTimers
Um einen Timer zu löschen klicken Sie bitte auf \"delete\".

Der Status eines jeden AutoTimers wird durch eine bestimmte Farbe angezeigt:
\"on\" Der AutoTimer ist OK und wird automatisch übereinstimmende Sendungen programmieren.
\"inactive\" Der AutoTimer ist nicht aktiv.

Zusätzlich zu diesen Funktionen können Sie einen neuen AutoTimer anlegen indem Sie die Schaltfläche am oberen Rand anklicken. Am unteren Bildschirmrand finden Sie die Schaltfläche , mit der Sie alle AutoTimer, die Sie in der Liste in der letzten Spalte mit einem Haken versehen haben, auf einmal löschen können.

Mit der Schaltfläche können Sie VDRAdmin-AM veranlassen sich mit dem VDR zu verbinden, die aktuellen EPG Daten zu holen und anschliessend nach übereinstimmenden AutoTimern zu suchen.

" msgid "

Here you can edit an automatic timer's (AutoTimer) settings.

AutoTimer is a key feature of VDRAdmin-AM. An AutoTimer consists of one or more search terms and some other settings, that are looked for regularly in the Electronic Program Guide (EPG). On match AutoTimer adds a timer in VDR automatically for that broadcast. That's very comfortable for irregularly broadcasted series or movies you don't want to miss.

" msgstr "

Hier können Sie die Einstellungen der automatischen Timer (AutoTimer) bearbeiten.

Die AutoTimer sind eine Schlüsselfunktion des VDRAdmin-AM. Ein AutoTimer besteht aus einem oder mehreren Suchbegriffen und einigen anderen Einstellungen, die regelmäßig im Electronic Program Guide (EPG, elektronischer Programmführer) gesucht werden. Bei einer Übereinstimmung legt AutoTimer automatisch einen neuen Timer für diese Sendung im VDR an. Das ist sehr komfortable für unregelmäßig ausgestrahlte Serien oder Spielfilmen, die Sie nicht vermissen wollen.

" msgid "Activate or deactivate this AutoTimer. Deactivated AutoTimers are still stored in the AutoTimer list so that they can be activated again, but they do not record anything meanwhile. Above that you can set this to \"oneshot\" so this AutoTimer only programs the (one!) next matching broadcast." msgstr "Diesen AutoTimer aktivieren oder deaktivieren. Deaktivierte AutoTimer werden weiterhin in der Liste der verfügbaren AutoTimer geführt, so dass sie später wieder aktiviert werden können. In der Zwischenzeit nehmen Sie dann aber nichts auf. Darüberhinaus können Sie dies auch auf \"einmal\" setzen, so dass dieser AutoTimer nur die als nächstes übereinstimmende Sendung (eine einzige!) programmiert." msgid "Choosing the right search items decides whether only the wanted broadcasts or broadcasts having similar names or even nothing gets recorded.
Case doesn't matter, \"X-Files\" matches anything \"x-files\" will match. You can set multiple search items by separating them with spaces. Broadcasts will match only if they match all configured search items.
You'd better only use letters and numbers for search items, as the EPG often miss colons, brackets and other characters.
Experts can also use regular expressions, but you have to get needed information from the VDRAdmin-AM sources (undocumented feature).

You can exclude broadcasts so that they don't get recorded even if they would match an AutoTimer. Therefore you have to enter that titles into the file vdradmind.bl, one event a line. This file must be located in your VDRAdmin-AM's configuration folder. If this string is found either in the EPG's title or in title~subtitle, this event will not be programmed by AutoTimer. So you can disable complete episodes (for example when using \"Enterprise\" as blacklist string) or only one episode (when using \"Enterprise~Azati Prime\" as blacklist string)." msgstr "Die Auswahl der richtigen Suchbegriffe entscheidet darüber ob nur die gewünschten Sendungen oder Sendungen mit ähnlichen Namen oder überhaupt nichts aufgenommen wird.
Groß-/Kleinschreibung spielt keine Rolle, d.h. \"Akte X\" findet das gleiche wie \"akte x\". Sie können mehrere Suchbegriffe durch Leerzeichen getrennt angeben. Diese müssen dann alle in den gewünschten Feldern der Sendung enthalten sein, um gefunden zu werden.
Es empfiehlt sich nur Buchstaben und Zahlen in den Suchbegriffen zu verwenden, da im EPG oft Doppelpunkte, Klammern und andere Zeichen fehlen.
Experten können auch \"regular expressions\" verwenden. Zu deren Einsatz müssen Sie jedoch einen Blick in den Quelltext von VDRAdmin-AM werfen (nicht dokumentierte Funktion).

Sie können auch Sendungen, die eigentlich passen würden, ausschliessen indem Sie diese Titel der Datei vdradmind.bl hinzufügen, pro Zeile eine Sendung. Diese Datei muss sich im Konfigurationsverzeichnis von VDRAdmin-AM befinden. Wenn eine Zeile entweder auf title oder title~subtitle aus dem EPG der Sendung paßt, so wird diese Sendung nicht automatisch programmiert. Somit können Sie eine komplette Serie (z.B. mit \"Enterprise\" als Blacklist-Eintrag) oder nur eine bestimmte Episode (z.B. \"Enterprise~Azati Prime\") ausschliessen." msgid "Here you can define the EPG sections where VDRAdmin-AM should look for the search pattern." msgstr "Hier geben Sie die Abschnitte aus dem EPG an, den VDRAdmin-AM nach den Suchbegriffen durchsuchen soll." msgid "Use these checkboxes to limit searching for matching broadcasts to a set of weekdays." msgstr "Haken Sie die Tage an, an denen Sendungen gesucht werden sollen." msgid "The channel to look for matching broadcasts or \"all\" to search in all known or wanted channels. You can define the wanted channels for AutoTimer in \"Configuration\"." msgstr "Der Kanal, der auf übereinstimmende Sendungen durchsucht werden soll. Mit \"alle\" werden alle bekannten oder erwünschten Kanäle durchsucht. Die erwünschten Kanäle für den AutoTimer können auf der \"Konfiguration\" Seite eingestellt werden." msgid "A broadcast must start after the time entered here to match. The first text field is for \"hour\", the second for \"minute\"." msgstr "Eine Sendung darf frühestens zu der hier eingestellten Uhrzeit beginnen. Das erste Textfeld gibt die Stunden, das zweite die Minuten an." msgid "A broadcast must end before the time entered here to match. The first text field is for \"hour\", the second for \"minute\"." msgstr "Eine Sendung darf spätestens zu der hier eingestellten Uhrzeit aufhören. Das erste Textfeld gibt die Stunden, das zweite die Minuten an." msgid "Set this option to \"yes\" if all timers programed by this AutoTimer should have individual start/stop margins and enter the values in the next two text boxes." msgstr "Setzen Sie diese Option auf \"Ja\" wenn die von diesem AutoTimer programmierten Timer individuelle Zeitpuffer bekommen sollen. Die entsprechenden Werte können Sie in den zwei folgenden Textfeldern angeben." msgid "The number of minutes VDRAdmin-AM subtracts from the broadcast's start time found in the EPG." msgstr "Die Anzahl von Minuten, die VDRAdmin-AM von der Startzeit der Sendung im EPG abzieht." msgid "The number of minutes VDRAdmin-AM adds to the broadcast's stop time found in the EPG." msgstr "Die Anzahl von Minuten, die VDRAdmin-AM zur Stoppzeit der Sendung im EPG addiert." msgid "An integer in the range 0...99, defining the priority of this timer and of recordings created by this timer. 0 represents the lowest value, 99 the highest. The priority is used to decide which timer shall be started in case there are two or more timers with the exact same start time. The first timer in the list with the highest priority will be used.

This value is also stored with the recording and is later used to decide which recording to remove from disk in order to free space for a new recording. If the disk runs full and a new recording needs more space, an existing recording with the lowest priority (and which has exceeded its guaranteed lifetime) will be removed.

If all available DVB cards are currently occupied, a timer with a higher priority will interrupt the timer with the lowest priority in order to start recording." msgstr "Eine Zahl im Bereich 0...99, die die Priorität dieses Timers und der von ihm programmierten Aufnahmen angibt. 0 ist die geringste Priorität und 99 die höchste. Die Priorität wird verwendet um zu entscheiden, welcher Timer gestartet werden soll für den Fall, dass zwei oder mehr Timer mit exakt der gleichen Startzeit existieren. Der erste Timer in der Liste mit den höchsten Prioritäten wird verwendet.

Dieser Wert wird ebenso zusammen mit der Aufnahme gespeichert und wird später verwendet um zu entscheiden, welche Aufnahme gelöscht werden soll, für den Fall, dass kein Pattenplatz mehr für eine neue Aufnahme ist. Wenn die Platte voll läuft und eine Aufnahme mehr Plattenplatz benötigt, wird eine existierende Aufnahme mit der geringsten Priorität (und deren garantierte Lebenszeit überschritten wurde) gelöscht.

Wenn alle verfügbaren DVB-Karten belegt sind unterbricht ein Timer mit einer höheren Priorität den Timer mit der niedrigsten Priorität um die Aufnahme zu starten." msgid "The guaranteed lifetime (in days) of a recording created by this timer. 0 means that this recording may be automatically deleted at any time by a new recording with higher priority. 99 means that this recording will never be automatically deleted. Any number in the range 1...98 means that this recording may not be automatically deleted in favour of a new recording, until the given number of days since the start time of the recording has passed by." msgstr "Die garantierte Lebenszeit (in Tagen) einer Aufnahme, die von diesem Timer erstellt wurde. 0 bedeutet, dass diese Aufnahme jederzeit von einer Aufnahme mit höherer Priorität automatisch gelöscht werden kann. 99 heißt. dass diese Aufnahme nie automatisch gelöscht wird. Eine Zahl im Bereich 1...98 gibt an, dass die Aufnahme automatisch gelöscht werden kann, wenn die angegebene Anzahl von Tagen seit der Startzeit abgelaufen ist und Plattenplatz für eine neue Aufnahme benötigt wird." msgid "Check this box if you want VDRAdmin-AM to append the broadcast's EPG subtitle to the recording's file name." msgstr "Aktivieren Sie diese Option, wenn Sie wollen, dass VDRAdmin-AM den Untertitel der Sendung aus dem EPG an den Namen der Aufnahme anhängt." msgid "If you enable this VDRAdmin-AM will track timers it has already programmed automatically. This is useful if want to deactivate or delete timers that have been programmed automatically in the timers listing." msgstr "Wenn Sie diese Option aktivieren merkt sich VDRAdmin-AM die Timer, die er bereits automatisch programmiert hat. Dies ist nützlich, wenn automatisch programmierte Timer in der Timerliste deaktiviert oder gelöscht werden sollen." msgid "The directory this AutoTimer will place the recordings in. If the name shall contain subdirectories, these have to be delimited by '~' (since the '/' character may be part of a regular programme name).
VDRAdmin-AM will append the matching broadcast's title and subtitle (if the \"Episode\" checkbox is marked) to the directory given here.

You can also use the following keywords that are replaced in the final file name by the values supplied by for example tvm2vdr:
  • %Title% - will become the title of the event.
  • %Subtitle% - will become the subtitle of the event.
  • %Director% - will become the director of the event.
  • %Date% - will become the date of the recording.
  • %Category% - will become the category of the event (Spielfilm/Serie/...).
  • %Genre% - will become the genre of the event (Drama/Krimi/..).
  • %Year% - will become the year of production.
  • %Country% - will become the country of production.
  • %Originaltitle% - will become the original title of the event.
  • %FSK% - will become the FSK from the event.
  • %Episode% - will become the episode's title of the event.
  • %Rating% - will become the rating of the event from the EPG provider.

Note:

If you use the above keywords it's in your own responsibility to supply the complete file name for the recordings! VDRAdmin-AM will not append anything to the resulting string." msgstr "Hier geben Sie das Verzeichnis an, in dem dieser AutoTimer die Aufnahmen ablegen soll. Sollen Unterverzeichnisse angegeben werden, dann müssen diese mit '~' getrennt werden (da '/' auch Teil des Programmnamens sein kann).
VDRAdmin-AM wird automatisch den Titel un den Untertitel (wenn das Häkchen bei \"Serie\" gesetzt ist) anhängen.

Sie können auch die folgenden Schlüsselwörter verwenden, die dann im endgültigen Dateinamen mit den Werten ersetzt werden, die z.B. von tvm2vdr bereitgestellt wurden:
  • %Title% - der Titel der Sendung.
  • %Subtitle% - der Untertitel der Sendung.
  • %Director% - der Regisseur der Sendung.
  • %Date% - das Datum der Aufnahme.
  • %Category% - die Kategorie der Aufnahme (Spielfilm/Serie/...).
  • %Genre% - das Genre der Aufnahme (Drama/Krimi/..).
  • %Year% - das Produktionsjahr.
  • %Country% - das Produktionsland.
  • %Originaltitle% - der Originaltitel der Sendung.
  • %FSK% - die FSK-Freigabe der Sendung.
  • %Episode% - der Titel der Episode einer Serie.
  • %Rating% - die Bewertung der Sendung vom Bereitsteller des EPG.

Achtung:

Wenn Sie die oben genannten Schlüsselwörter verwenden, liegt es in Ihrer Verantwortung den kompletten Dateinamen der Aufnahme anzugeben! VDRAdmin-AM wird nichts mehr anhängen." msgid "

Here you can change general settings and base settings for timers, AutoTimers, channel selection and streaming parameters.

" msgstr "

Hier können Sie allgemeine Einstellungen und Grundeinstellungen für Timer und AutoTimer, sowie die Kanalauswahl und die Streaming Einstellungen vornehmen.

" msgid "The skin you want to use." msgstr "Der zu verwendende Skin (=grafische Oberflächenrepräsentation)." msgid "The page you want to see at first connect to VDRAdmin-AM." msgstr "Die Seite, die angezeigt werden soll, wenn Sie sich das erste Mal mit VDRAdmin-AM verbinden." msgid "VDRAdmin-AM will load the given number of channels from VDR and present only those in any fields where channels can be selected. This also limits the EPG information VDRAdmin-AM will read so that you can use this to reduce VDRAdmin-AM's memory consumption and increase its performance. 0 turns this feature off and VDRAdmin-AM will use all available channels." msgstr "VDRAdmin-AM wird nur die hier eingestellte Anzahl an Kanälen vom VDR laden und nur diese an allen Stellen, die die Kanäle anzeigen, anbieten. Dies beschränkt auch die EPG Informationen, die VDRAdmin-AM lesen wird und vermindert somit auch den Speicherbedarf von VDRAdmin-AM und erhöht seine Verarbeitungsgeschwindigkeit. 0 schaltet diese Funktion ab und VDRAdmin-AM wird alle verfügbaren Kanäle verwenden." msgid "Here you can specify subnets from which access to VDRAdmin-AM does not require logging in. For example: \"192.168.0.0/24\" will include any IP starting with \"192.168.0.\", \"192.168.0.123/32\" will only match \"192.168.0.123\". Multiple subnets can be specified by separating them with spaces or commas." msgstr "Hier geben Sie die IP-Adresse oder den IP-Bereich an von dem aus man sich anmelden kann, ohne dass Login-Informationen eingegeben werden müssen. Z.B. \"192.168.0.0/24\" beinhaltet jede IP, die mit \"192.168.0.\" beginnt. \"192.168.0.123/32\" beinhaltet nur die IP \"192.168.0.123\". Mehrere IP-Bereiche können mit Komma oder Leerzeichen getrennt eingegeben werden." msgid "Here you can set the localization VDRAdmin-AM should use." msgstr "Hier stellen Sie die Lokalisierung ein, die VDRAdmin-AM verwenden soll." msgid "With this option the settings will be saved if VDRAdmin-AM exits. This will also save settings not available on the \"Configuration\" menu like interval and size in TV, sorting in the lists and current view in \"What's on now\"." msgstr "Mit dieser Option werden die Einstellungen gespeichert, wenn VDRAdmin-AM beendet wird. Damit werden dann auch Einstellungen gespeichert, die nicht im \"Konfiguration\" Menü enthalten sind, wie z.B. Interfall und Größe im Fernseher, die Sortierung in den Listen und die aktuelle Ansicht bei \"Was läuft jetzt\"." msgid "Top" msgstr "nach oben" msgid "The number of DVB cards VDR can access. Depending on this value VDRAdmin-AM will calculate critical timers in the Timer menu." msgstr "Die Anzahl der DVB-Karten, die der VDR ansprechen kann. In Abhängigkeit von diesem Wert berechnet VDRAdmin-AM die kritischen Timer auf der Timer Seite" msgid "The path to VDR's recordings. It's used so that VDRAdmin-AM can locate the recordings when using Recordings Streaming and reccmds.conf in the Recordings menu." msgstr "Der Pfad zu den Aufnahmen des VDR. Dieser wird verwendet um die Aufnahmen zu finden, wenn die Funktionen Aufnahmen streamen und reccmds.conf auf der Aufnahmen Seite verwendet werden." msgid "The path where VDR's configuration files are located. If this directory contains the file reccmds.conf its content is shown in a selectbox in the Recordings menu." msgstr "Der Pfad zu den Konfigurationsdateien des VDR. Wenn dieses Verzeichnis die Datei reccmds.conf enthält wird der Inhalt dieser Datei auf der Aufnahmen Seite zur Auswahl angezeigt." msgid "The path where the EPG images are stored." msgstr "Der Pfad, wo die EPG Bilder abgelegt sind." msgid "The username for the main user, i.e. the user having the most privileges." msgstr "Der Benutzername für den Hauptbenutzer, d.h. dem Benutzer mit den meisten Rechten." msgid "The main user's password." msgstr "Das Passwort des Hauptbenutzers." msgid "If you want a user account having only limited privileges, this is for you. The guest user cannot modify anything, it's only allowed to view the EPG, timers, AutoTimers and recordings listings." msgstr "Wenn Sie einen Benutzer wünschen, der nur eingeschränkte Rechte besitzt, dann aktivieren Sie diese Option. Der Gastbenutzer kann nichts ändern, es ist nur erlaubt den EPG, die Timer, AutoTimer und Aufnahmen aufzulisten." msgid "The username for the guest user." msgstr "Der Benutzername für den Gastbenutzer." msgid "The guest user's password." msgstr "Das Passwort des Gastbenutzers." msgid "The number of hours to show in the timeline." msgstr "Die Anzahl der Stunden, die in der Zeitleiste angezeigt wird." msgid "A comma separated list of times in hh:mm format that appear in the selectbox placed at the top." msgstr "Eine durch Kommas getrennte Liste von Uhrzeiten im Format hh:mm, die in der Auswahlliste am Seitenanfang angezeigt wird." msgid "Here you can (de-)activate the tooltips." msgstr "Hier können Sie die Tooltips ein- oder ausschalten." msgid "The time after which events are shown on a new day. For example setting 03:00 means that today's schedule will include any event starting before 03:00 tomorrow. Applies only to the 'Playing Today?' list." msgstr "Die Uhrzeit, ab der Sendungen am nächsten Tag angezeigt werden. Ist dies z.B. auf 03:00 gestellt, dann zeigt der EPG des heutigen Tages alle Sendungen, die spätestens Morgen um 03:00 Uhr beginnen. Diese Einstellung wirkt sich nur im Menüpunkt 'Was läuft heute?' aus." msgid "Show the 'Subtitle' text for each event. Not all broadcasters use this field." msgstr "Zeigt den Untertitel einer Sendung, falls vorhanden." msgid "Show the 'Summary' text for each event." msgstr "Zeigt die Zusammenfassung einer Sendung, falls vorhanden." msgid "Activate or deactivate the AutoTimer function." msgstr "Die AutoTimer-Funktionalität aktivieren oder deaktivieren." msgid "VDRAdmin-AM will send an email whenever an event matches an AutoTimer and a timer has been programmed if you enable this feature." msgstr "Wenn Sie diese Funktion aktivieren, dann schickt Ihnen VDRAdmin-AM immer wenn ein AutoTimer eine passende Sendung findet eine E-Mail." msgid "Here you set the sending email address of the generated email." msgstr "Hier geben Sie die Absende-Adresse der erzeugten E-Mail an." msgid "The email address the email is sent to." msgstr "Die E-Mail-Adresse an die die E-Mail geschickt werden soll." msgid "The outgoing mail server." msgstr "Der Server für ausgehende E-Mails." msgid "If you need to authenticate yourself at the outgoing mail server, you have to supply the username and the password below. Leaving this field empty will disable SMTPAuth." msgstr "Wenn Sie sich am Server für ausgehende E-Mails anmelden müssen, dann geben Sie hier den Benutzernamen und unten das Passwort an. Lassen Sie dieses Feld leer um SMTPAuth nicht zu verwenden." msgid "The password for the SMTPAuth user." msgstr "Das Passwort für den SMTPAuth Benutzer." msgid "Here you can (de-)activate the tooltips in the timeline." msgstr "Hier können Sie die Tooltips in der Zeitleiste ein- oder ausschalten." msgid "Here you can (de-)activate the tooltips in the list." msgstr "Hier können Sie die Tooltips in der Liste ein- oder ausschalten." msgid "Add summary to new timers:" msgstr "Beschreibung aus dem EPG für neue Timer verwenden:" msgid "If you don't want VDRAdmin-AM to add the summary taken from EPG to new timers you can switch it off here." msgstr "Wenn Sie nicht wollen, dass VDRAdmin-AM die Beschreibung einer Sendung aus dem EPG für neue Timer setzt, dann können Sie dies hiermit unterbinden." msgid "Enable or disable live streaming using the streamdev plugin. You also have to set the correct HTTP Port for Streamdev below." msgstr "Aktivieren oder deaktivieren des Streamens vom LiveTV. Dazu benötigen Sie das streamdev plugin. Außerdem muss noch der HTTP-Port von Streamdev korrekt gesetzt sein." msgid "Here you have to set the port number your VDR's streamdev server listens for connections. Additionally you can also provide the stream type you like to use." msgstr "Hier geben Sie die Portnummer des Streamdev-Servers im VDR an. Sie können auch den zu verwendenden Streamtyp angeben." msgid "Enable or disable streaming of recordings.
Well actually this is no real \"streaming\", but you have to setup your workstation so that it can access VDR's recordings. You can use for example Samba or NFS for this. VDRAdmin-AM simply generates a playlist that contains all parts of the recording and sends this to your browser. If your browser and media player are configured correctly you will see the recording on your workstation's display." msgstr "Streamen von Aufnahmen aktivieren oder deaktivieren.
Es ist eigentlich kein richtiges \"Streamen\", Sie müssen nämlich Ihren PC so konfigurieren, dass dieser auf die Aufnahmen des VDR zugreifen kann. Sie können dies z.B. mit Samba oder NFS erreichen. VDRAdmin-AM erstellt eine Abspielliste (Playlist), die alle Teile der ausgewählten Aufnahme enthält, und sendet diese dann zum Browser. Wenn nun der Browser und das Medienabspielprogramm korrekt konfiguriert sind wird die Aufnahme am PC abgespielt." msgid "This is the path where your workstation can access VDR's recordings. This depends on your VDR and workstation setup, for example \"\\\\vdr\\videos\" or \"V:\\\" (on Windows) or \"/mnt/videos\" (on Linux)." msgstr "Der Pfad, über den Ihr PC auf die Aufnahmen des VDR zugreifen kann. Dieser ist abhängig von der Konfiguration des VDR und des PC und kann z.B. \"\\\\vdr\\videos\" oder \"V:\\\" (unter Windows) oder \"/mnt/videos\" (unter Linux) sein." msgid "The MIME type to send when using live streaming. Defaults to \"video/x-mpegurl\"." msgstr "Der zu sendende MIME-Type für das Streamen von LiveTV. Vorgabe ist \"video/x-mpegurl\"." msgid "The suffix to use for live streaming. Defaults to \"m3u\"." msgstr "Die zu verwendende Dateierweiterung für das Streamen von LiveTV. Vorgabe ist \"m3u\"." msgid "The MIME type to send when using recordings streaming. Defaults to \"video/x-mpegurl\"." msgstr "Der zu sendende MIME-Type für das Streamen von Aufnahmen. Vorgabe ist \"video/x-mpegurl\"." msgid "The suffix to use for recordings streaming. Defaults to \"m3u\"." msgstr "Dateierweiterung für das Streamen von Aufnahmen. Vorgabe ist \"m3u\"." msgid "

Here you can define two external searches that you can access in the EPG views. You simply have to find the required URL and where the search pattern has to be located. %TITLE% will be substituted by the broadcast's EPG title.

" msgstr "

Hier können Sie zwei externe Suchen angeben, die in den EPG-Ansichten zugreifbar sind. Dazu müssen Sie nur die erforderliche URL und die Position des Suchmusters wissen. %TITLE% wird mit dem EPG-Titel ersetzt." msgid "Some examples:" msgstr "Einige Beispiele:" msgid "Please change the hostname to your local needs!" msgstr "Bitte passen Sie den Rechnernamen an Ihre lokale Umgebung an!" msgid "

This section is for experts only, i.e. you know what you are doing!

" msgstr "

Dieser Bereich ist nur für Experten, d.h. Sie wissen was Sie tun!

" msgid "If set to \"yes\" VDRAdmin-AM will periodically refresh its local EPG cache. Else the EPG will be refreshed if the user accesses any EPG view at the web interface and the timeout set at \"Update EPG every\" has been reached." msgstr "Wenn dies aktiviert ist, dann aktualisiert VDRAdmin-AM seine lokalen EPG-Daten peridoisch im Hintergrund. Andernfalls werden die EPG-Daten aktualisiert wenn der Benutzer eine EPG-Ansicht auf der Web-Oberfläche öffnet und die bei \"EPG aktualisieren alle\" eingestellt Zeitspanne abgelaufen ist." msgid "The interval, the EPG data is refreshed from VDR and AutoTimer updates are performed (if AutoTimer feature is used)." msgstr "Das Intervall indem die EPG Daten aktualisiert werden und nach neuen AutoTimern gesucht wird, falls die AutoTimer-Funktion genutzt wird." msgid "

If you want to limit the number of channels used in some parts of VDRAdmin-AM, this is for you!

Use the radio buttons to activate or deactivate the wanted channels in the named menu.

To add channels to the list of wanted channels you have to select them in the left side selectbox and click . If you want to remove channels from the list of wanted channels you have to select them in the right side selectbox and click .

" msgstr "

Hiermit können Sie die Anzahl der Kanäle für einige Teilbereiche von VDRAdmin-AM einschränken.

Verwenden Sie die \"Ja\"/\"Nein\"-Knöpfe um die Kanalauswahl für das angegebene Menü zu aktivieren oder deaktivieren.

Zum Hinzufügen von Kanälen zu der Liste der ausgewählten Kanäle müssen Sie die gewünschten Kanäle im linken Auswahlfeld markieren und die Schaltfläche anklicken. Um Kanäle aus dieser Liste wieder zu entfernen müssen diese im rechten Auswahlfeld markiert werden und danach die Schaltfläche angeklickt werden.

" msgid "Usually channels that don't have EPG information are hidden in all EPG views. If you don't want them to be hidden you have to set this option to \"yes\"." msgstr "Normalerweise werden Kanäle, die keine EPG Information haben, in den EPG Ansichten ausgeblendet. Wenn diese Option auf \"ja\" steht, dann werden diese auch angezeigt." msgid "Edit Timer" msgstr "Timer editieren" msgid "Edit EPG" msgstr "EPG bearbeiten" msgid "

Here you can edit the descriptive fields of an existing EPG entry.

" msgstr "

Hier können Sie die Beschreibung eines existierenden EPG-Eintrags bearbeiten.

" msgid "Channel (readonly)" msgstr "Kanal (unveränderbar)" msgid "This is the channel of the EPG entry. It cannot be changed." msgstr "Der Kanal des EPG-Eintrags. Er kann nicht verändert werden." msgid "Time (readonly)" msgstr "Zeiten (unveränderbar)" msgid "This is the start and end time of the entry. It cannot be changed." msgstr "Die Start- und Stoppzeit des Eintrags. Diese können nicht verändert werden." msgid "Change this string to give this EPG Entry a new title. It must consist of only one line of text." msgstr "Der einzeilige, neue Titel des EPG-Eintrags." msgid "Change this string to give this EPG Entry a new subtitle. It must consist of only one line of text." msgstr "Der einzeilige, neue Untertitel des EPG-Eintrags." msgid "Change the text in this field to edit the description of this entry. The text can consist of one or more lines." msgstr "Hier können Sie die Beschreibung des EPG-Eintrags bearbeiten." msgid "VPS (readonly)" msgstr "VPS (unveränderbar)" msgid "If available this field shows the vps time of the EPG entry. It cannot be changed." msgstr "Die VPS-Zeit des EPG-Eintrags, falls vorhanden. Diese kann nicht verändert werden." msgid "Video tracks (readonly)" msgstr "Videospuren (unveränderbar)" msgid "If available this field shows the video track(s). It cannot be changed." msgstr "Die verfügbaren Videospuren. Das Feld kann nicht verändert werden." msgid "Audio tracks (readonly)" msgstr "Audiospuren (unveränderbar)" msgid "If available this field shows the audio track(s). It cannot be changed." msgstr "Die verfügbaren Audiospuren. Das Feld kann nicht verändert werden." msgid "No Help Available" msgstr "Keine Hilfe verfügbar" msgid "

No help available yet. For adding or changing text please contact amair.sob@googlemail.com.

" msgstr "Bisher keine Hilfe vorhanden. Zum Hinzufügen oder Ändern eines Textes bitte an amair.sob@googlemail.com wenden." msgid "Recordings" msgstr "Aufnahmen" msgid "

Here you will find a listing of recordings known to VDR. The headline will also show you VDR's total and free disk space.

The listing showing you some information on the recordings. You can change the list's sorting by clicking the columns heading. Above the list you'll see the navigation path. If you want to view the contents of previous folders you'll have to click on its name in that path.

Each row contains this information:

Date
The date when the recording has been done. In case of folders this will show the number of recordings the folder contains.
Time
The time when the recording has been done. In case of folders this will show the number of new recordings the folder contains.
Name
The recording's or folder's name. Click it to show the recording's summary or descend into the folder.
Rename (\"edit\")
Rename a recording.

Note:

This only works if VDR has the MOVR or RENR SVDRP command which is not a core VDR feature but provided by the Liemikuutio patch set.
Delete (\"delete\")
Delete a recording.
Stream (\"stream\")
This column is only shown if you activated and configured Recordings Streaming in the Configuration menu. You can watch the recording at your workstation.

In addition to these functions you can delete a number of recordings at once by checking the box in the last but one column of those recordings and clicking .

If you've set the path the VDR's configuration files and have entries in VDR's reccmds.conf you can run those commands for the selected recording by selecting the wanted command in the select box locate next to Commands: and pressing the button.

Use to force reloading of VDR's recordings listing.

" msgstr "

Hier sehen Sie eine Liste aller Aufnahmen, die auf dem VDR bereit stehen. In der Kopfzeile können Sie den gesamten und den freien Plattenplatz des VDR ablesen.

Dies Liste zeigt Ihnen einige Informationen zu den Aufnahmen. Sie können die Sortierung ändern indem Sie auf die Spaltenüberschriften klicken. Über der Liste sehen Sie den Navigationspfad. Wenn Sie den Inhalt eines zuvor besuchten Verzeichnisses sehen wollen, dann klicken Sie einfach auf den Namen des Verzeichnisses in diesem Pfad.

Jede Zeile enthält folgende Information:

Datum
Das Datum an dem die Aufnahme stattgefunden hat. Im Falle eines Verzeichnisses wird hier die Anzahl der enthaltenen Aufnahmen angezeigt.
Uhrzeit
Die Uhrzeit zu der die Aufnahme stattgefunden hat. Im Falle eines Verzeichnisses wird hier die Anzahl der neuen Aufnahmen in diesem Verzeichnis angezeigt.
Name
Der Name der Aufnahme oder des Verzeichnisses. Klicken Sie ihn an um die Zusammenfassung der Aufnahme anzuzeigen oder um in das Verzeichnis zu wechseln.
Umbenennen (\"edit\")
Umbenennen einer Aufnahme.

Achtung:

Dies funktioniert nur, wenn der VDR das RENR SVDRPort Kommando versteht. Dieses ist nicht im Standard-VDR enthalten sondern kann durch einen Patch hinzugefügt werden. vdr-aio21_svdrprename.patch und enAIO-v2.2+ bieten dieses Kommando.
Löschen (\"delete\")
Löschen einer Aufnahme.
Streamen (\"stream\")
Diese Spalte wird nur angezeigt, wenn Sie auf der Konfiguration Seite Aufnahmen streamen aktiviert und konfiguriert haben. Sie können dann die Aufnahme auf Ihrem PC anschauen.

Zusätzlich zu diesen Funktionen können Sie mehrere Aufnahmen auf einmal löschen, indem Sie ein Häkchen in der vorletzten Spalte dieser Aufnahmen setzen und dann die Schaltfläche anklicken.

Wenn Sie den Pfad zu den VDR Konfigurationsdateien eingestellt haben und es dort die Datei reccmds.conf gibt, können Sie die darin enthaltenen Befehle für die ausgewählten Aufnahmen ausführen. Dazu wählen Sie den gewünschten Befehl in der Schaltfläche neben Befehle: aus und klicken dann auf .

Mit der Schaltfläche können Sie das Neuladen der VDR-Aufnahmenliste forcieren.

" msgid "

Here you will find a listing of timers known to VDR.

On top you will find a chart showing a day's timers graphically. This provides an quick overview on what's going on at the specified day and helps you in finding conflicting timers. Moving the mouse cursor above any timer box will display a tooltip containing the timer's title, priority, lifetime and duration.

Below the chart you'll find the timers list showing you some information on the timers. You can change the list's sorting by clicking the columns heading.

For each timer you have the following options:

Set its state
By clicking on \"Yes\", \"No\", \"VPS\" or \"Auto\" in the \"Active\" column.
Quickly view its priority and lifetime
By pointing the mouse cursor to the timer's title.
View its EPG entry
Timers that have set AutoTimer Checking to \"Transmission Identification\" will show you the corresponding EPG entry if you click on the timer's title.
Edit the timer
You can edit a timer by clicking \"edit\".
Delete the timer
To delete a timer you click \"delete\".

Each timer's state is indicated by differently coloured boxes (in the chart view) or images (in the list view):
    / \"on\" Timer is OK and will record.
    / \"problem\" Timer conflicts with other timers. That's not critical, as long as you have enough DVB cards for the parallel recordings.
    / \"impossible\" Timer is critical and will most likely not record.
    / \"inactive\" Timer is not active.

In addition to these functions you can add a new timer by clicking at the top and you can delete a number of timers at once by checking the box in the last column of those timers and clicking .

You can and selected timers.

" msgstr "" "

Hier finden Sie eine Liste von allen Timern, die VDR kennt.

Im oberen Bereich finden Sie eine grafische Repräsentation der Timer für einen Tag. Dies vermittelt Ihnen einen schnellen Überblick darüber, was an einem Tag programmiert wurde und hilft Ihnen beim Erkennen von überschneidenden Timern. Wenn Sie den Mauszeiger über einen farbigen Bereich bewegen erfahren Sie seinen Namen, die Priorität und Lebenszeit sowie seine Dauer.

Unterhalb der grafischen Anzeige sehen Sie eine Liste der programmierten Timer. Sie können die Sortierung der Liste ändern indem Sie auf die gewünschte Spaltenüberschrift klicken.

Für jeden Timer haben Sie die folgenden Möglichkeiten:

Setzen seines Zustands
Dies erfolgt durch Anklicken von \"Ja\", \"Nein\", \"VPS\" oder \"Auto\" in der \"Aktiv\" Spalte.
Schnellanzeige seiner Priorität und Lebenszeit
Der Mauszeiger muss dazu über den Namen des Timers bewegt werden.
Anzeigen seinen EPG Eintrags
Bei Timern, bei denen die Option Automatische Timer-Überwachung auf \"Sendungskennung\" gesetzt ist, kann durch Anklicken des Timernamens der zugehörige EPG Eintrag angezeigt werden.
Bearbeiten eines Timers
Sie können einen Timer bearbeiten indem Sie auf \"edit\" klicken.
Löschen eines Timers
Um einen Timer zu löschen klicken Sie bitte auf \"delete\".

Der Status eines jeden Timers wird durch eine bestimmte Farbe angezeigt:
    / \"on\" Der Timer ist OK und wird aufnehmen.
    / \"problem\" Der Timer überschneidet sich mit anderen Timern. Das ist nicht kritisch, wenn genügend DVB-Karten für die parallelen Aufnahmen vorhanden sind.
    / \"impossible\" Der Timer ist kritisch und wird höchst wahrscheinlich nicht aufnehmen.
    / \"inactive\" Der Timer ist nicht aktiv.\n" "

Zusätzlich zu diesen Funktionen können Sie einen neuen Timer programmieren indem Sie die Schaltfläche am oberen Bildschirmrand anklicken. Am unteren Bildschirmrand finden Sie die Schaltfläche , mit der Sie alle Timer, die Sie in der Liste in der letzten Spalte mit einem Haken versehen haben, auf einmal löschen können.

Sie können alle ausgewählten Timer mit den entsprechenden Schaltflächen auch aktivieren bzw. deaktivieren.

" msgid "

Here you can edit a timer's settings.

" msgstr "

Hier können Sie die Einstellungen eines Timers bearbeiten.

" msgid "Timer Active:" msgstr "Timer aktiv:" msgid "Activate or deactivate this timer. Deactivated timers are still stored in the timer list so that they can be activated again, but they do not record anything meanwhile." msgstr "Aktivieren bzw. Deaktivieren des Timers. Deaktivierte Timer werden weiterhin in der Liste der verfügbaren Timer geführt, so dass sie später wieder aktiviert werden können. In der Zwischenzeit nehmen Sie dann aber nichts auf." msgid "AutoTimer Checking:" msgstr "Automatische Timer-Überwachung:" msgid "Depending on how this timer has been programmed you have up to three possible settings:" msgstr "Die möglichen Optionen sind abhängig davon, wie der Timer programmiert wurde:" msgid "Transmission Identification" msgstr "Sendungskennung" msgid "Monitor this timer using the identification provided in the EPG. Please note that this only works if the provided identification is a fix and unique value! This option is not available with timers programmed in VDR." msgstr "Der Timer wird anhand der Identifikation, die die zugehörige Sendung im EPG besitzt, überwacht. Bitte beachten Sie, dass dies nur funktioniert, wenn die Identifikation im EPG fest und eindeutig ist! Diese Option ist nicht verfügbar, wenn der Timer im VDR programmiert wurde." msgid "Time" msgstr "Uhrzeit" msgid "Monitor this timer using the start and stop time." msgstr "Der Timer wird anhand seiner Start- und Stoppzeit überwacht." msgid "off" msgstr "aus" msgid "Do not monitor this timer." msgstr "Der Timer wird nicht überwacht." msgid "The channel to record." msgstr "Der aufzunehmende Kanal." msgid "Day Of Recording:" msgstr "Tag der Aufnahme:" msgid "The day when the timer should get active. You can enter the day in two formats:
  • Two digits (DD). This will use the current month and year.
  • ISO norm (YYYY-MM-DD). Program your timers as far in the future as you like.
In case you want to program a repeating timer you can use the seven checkboxes below the text field. Check the box for each day you want the timer to get active." msgstr "Der Tag an dem der Timer aktiv werden soll. Der Tag kann in zwei Formaten eingegeben werden:
  • Zwei Ziffern (TT). Es wird der aktuelle Monat und das aktuelle Jahr verwendet.
  • ISO-Norm (JJJJ-MM-TT). Damit können Sie Timer soweit in der Zukunft programmieren wie Sie wollen.
Für den Fall, dass Sie wiederkehrende Timer programmieren wollen, können Sie die sieben Schaltflächen unterhalb des Textfeldes verwenden. Markieren Sie einfach das Feld des Tages an dem der Timer aktiv werden soll." msgid "Start Time:" msgstr "Startzeit:" msgid "This is the time when the timer should start recording. The first text field is for \"hour\", the second for \"minute\"." msgstr "Dies ist die Startzeit der Aufnahme. Das erste Textfeld ist für die Stunde, das zweite für die Minuten." msgid "End Time:" msgstr "Endzeit:" msgid "This is the time when the timer should stop recording. The first text field is for \"hour\", the second for \"minute\"." msgstr "Die Uhrzeit zu der die Aufnahme gestoppt werden soll. Das erste Textfeld ist für die Stunde, das zweite für die Minuten." msgid "Title of Recording:" msgstr "Titel der Aufnahme:" msgid "The file name this timer will give to a recording. If the name shall contain subdirectories, these have to be delimited by '~' (since the '/' character may be part of a regular programme name).

The special keywords TITLE and EPISODE, if present, will be replaced by the title and episode information from the EPG data at the time of recording (if that data is available). If at the time of recording either of these cannot be determined, TITLE will default to the channel name, and EPISODE will default to a blank." msgstr "Der Dateiname den dieser Timer der Aufnahme geben wird. Sollen Unterverzeichnisse angegeben werden, so müssen diese mit '~' getrennt werden, da '/' auch Teil eines regulären Programmnamens sein kann.

Die Schlüsselwörter TITLE und EPISODE werden, falls vorhanden, mit der Titel- bzw. Untertitel-Information aus dem EPG zur Zeit der Aufnahme ersetzt, wenn diese Daten im EPG vorhanden sind. Sollten diese Informationen nicht verfügbar sein, so wird für TITLE der Kanalname und für EPISODE ein Leerzeichen verwendet." msgid "Summary:" msgstr "Zusammenfassung:" msgid "Arbitrary text that describes the recording made by this timer. If this field is not empty, its contents will be written into the summary.vdr or info.vdr file of the recording." msgstr "Beliebiger Text, der die von diesem Timer erstellte Aufnahme beschreibt. Wenn dieses Feld nicht leer ist wird der Text in die summary.vdr bzw. info.vdr der Aufnahme geschrieben." msgid "Your Browser does not support frames!" msgstr "Ihr Browser unterstützt keine Frames!" msgid "What's On Now?" msgstr "Was läuft jetzt?" msgid "Playing Today?" msgstr "Was läuft heute?" msgid "Remote Control" msgstr "Fernbedienung" msgid "Watch TV" msgstr "Fernseher" msgid "Commands" msgstr "Befehle" msgid "Search" msgstr "Suchen" msgid "Authorization Required" msgstr "Autorisierung erforderlich" msgid "This server could not verify that you are authorized to access the document requested. Either you supplied the wrong credentials (e.g. bad password), or your browser doesn't understand how to supply the credentials required." msgstr "Dieser Server kann nicht bestätigen, dass Sie berechtigt sind, auf das angeforderte Dokument zuzugreifen. Entweder haben Sie falsche Anmeldedaten angegeben (z.B. falsches Passwort) oder Ihr Browser kann die Anmeldedaten nicht übermitteln." msgid "VPS" msgstr "VPS" msgid "close" msgstr "schließen" msgid "view" msgstr "umschalten" msgid "search" msgstr "Wiederholungen" msgid "edit" msgstr "Bearbeiten" msgid "Length" msgstr "Länge" msgid "Video tracks:" msgstr "Videospuren:" msgid "Audio tracks:" msgstr "Audiospuren:" msgid "Subtitles:" msgstr "Untertitel:" msgid "Video tracks" msgstr "Videospuren" msgid "Audio tracks" msgstr "Audiospuren" msgid "TV select" msgstr "TV umschalten" msgid "Stream" msgstr "Stream" msgid "Channel group:" msgstr "Kanalgruppe:" msgid "Go!" msgstr "Go!" msgid "Search for other show times" msgstr "Nach Wiederholungen suchen" msgid "No Information" msgstr "keine Infos" msgid "No EPG information available" msgstr "Es sind keine EPG Informationen vorhanden" msgid "Playing Today" msgstr "Was läuft heute" msgid "starting at" msgstr "ab" msgid "What's on:" msgstr "Was läuft:" msgid "at" msgstr "um" msgid "now" msgstr "jetzt" msgid "to" msgstr "bis" msgid "Duration:" msgstr "Dauer:" msgid "min" msgstr "min" msgid "at:" msgstr "um:" msgid "You need JavaScript to use the timeline!" msgstr "Für die Zeitleiste muss JavaScript aktiviert sein!" msgid "Rename Recording" msgstr "Aufnahme umbenennen" msgid "Original Name of Recording:" msgstr "Alter Titel der Aufnahme:" msgid "New Name of Recording:" msgstr "Neuer Titel der Aufnahme:" msgid "Subtitle:" msgstr "Untertitel:" msgid "Rename" msgstr "Umbenennen" msgid "Total:" msgstr "Total:" msgid "h" msgstr "h" msgid "Free:" msgstr "Frei:" msgid "Date" msgstr "Datum" msgid "Total" msgstr "Gesamt" msgid "New" msgstr "neu" msgid "Play" msgstr "Abspielen" msgid "Cut" msgstr "Schneiden" msgid "Delete recording?" msgstr "Aufnahme löschen?" msgid "Refresh" msgstr "Neu einlesen" msgid "Commands:" msgstr "Befehle:" msgid "Really run this command?" msgstr "Diesen Befehl wirklich ausführen?" msgid "stream all recordings" msgstr "Alle Aufnahmen streamen" msgid "Delete Selected Recordings" msgstr "Ausgewählte Aufnahmen löschen" msgid "Delete all selected recordings?" msgstr "Ausgewählte Aufnahmen wirklich löschen?" msgid "No recordings available" msgstr "Es sind keine Aufnahmen vorhanden" msgid "Transponder:" msgstr "Transponder:" msgid "CA-System:" msgstr "CA-System:" msgid "New Timer" msgstr "Neuer Timer" msgid "Edit timer status?" msgstr "Timerstatus ändern?" msgid "This timer is inactive!" msgstr "Diese Aufnahme ist deaktiviert!" msgid "This timer is impossible!" msgstr "Diese Aufnahme ist nicht möglich!" msgid "No more timers on other transponders possible!" msgstr "Keine weiteren Aufnahmen auf anderen Transpondern mehr möglich!" msgid "Timer OK." msgstr "Diese Aufnahme ist möglich." msgid "Auto" msgstr "Auto" msgid "activate" msgstr "Aktiviere" msgid "inactivate" msgstr "Deaktiviere" msgid "selected timers" msgstr "ausgewählte Timer" msgid "Delete Selected Timers" msgstr "Ausgewählte Timer löschen" msgid "No timers defined!" msgstr "Es wurden noch keine Timer angelegt!" msgid "Create New Timer" msgstr "Neuen Timer anlegen" msgid "Buffer:" msgstr "Puffer:" msgid "Use VPS:" msgstr "VPS verwenden:" msgid "readonly" msgstr "unveränderbar" msgid "Timer has been set by AutoTimer pattern:" msgstr "Timer wurde gesetzt vom AutoTimer Muster:" msgid "TV" msgstr "Fernseher" msgid "Interval:" msgstr "Intervall:" msgid "sec." msgstr "sek" msgid "G" msgstr "G" msgid "Grab the picture!" msgstr "Hole das Bild!" msgid "Size:" msgstr "Größe:" msgid "Open in separate window" msgstr "Öffne eigenes Fenster" msgid "VDR Commands" msgstr "VDR Befehle" msgid "Export channels as playlist:" msgstr "Kanäle als Playlist exportieren:" msgid "Number of lines to show:" msgstr "Anzahl der anzuzeigenden Zeilen:" msgid "unlimited" msgstr "alle" msgid "SVDRP commands:" msgstr "SVDRP Befehle:" msgid "Commands defined in commands.conf:" msgstr "In commands.conf definierte Befehle:" msgid "Output" msgstr "Ausgabe" msgid "What's your VDR hostname (e.g video.intra.net)?" msgstr "Wie lautet der Hostname des VDR (z.B. video.intra.net)?" msgid "On which port does VDR listen to SVDRP queries?" msgstr "Auf welchem Port hört der VDR auf SVDRP-Anfragen?" msgid "On which address should VDRAdmin-AM listen (0.0.0.0 for any)?" msgstr "An welcher Adresse soll VDRAdmin-AM auf Verbindungen warten (0.0.0.0 für alle)?" msgid "On which port should VDRAdmin-AM listen?" msgstr "Auf welchem Port soll VDRAdmin-AM hören?" msgid "Username?" msgstr "Benutzername?" msgid "Password?" msgstr "Passwort?" msgid "Where are your recordings stored?" msgstr "Wo befinden sich die Aufnahmen?" msgid "Where are your VDR's configuration files located?" msgstr "Wo befinden sich die Konfigurationsdateien des VDR?" msgid "Config file written successfully." msgstr "Konfigurationsdatei wurde erfolgreich geschrieben." #, perl-format msgid "%s %s started with pid %d." msgstr "%s %s wurde mit der Prozeß-ID %d gestartet." msgid "Not found" msgstr "Nicht gefunden" msgid "The requested URL was not found on this server!" msgstr "Die angeforderte URL konnte auf dem Server nicht gefunden werden!" msgid "Forbidden" msgstr "Verboten" msgid "You don't have permission to access this function!" msgstr "Sie haben nicht die Erlaubnis diese Funktion aufzurufen!" msgid "All channels" msgstr "Alle Kanäle" msgid "Selected channels" msgstr "Ausgewählte Kanäle" msgid "TV channels" msgstr "Fernsehkanäle" msgid "Radio channels" msgstr "Radiokanäle" #, perl-format msgid "Access to file \"%s\" denied!" msgstr "Zugriff auf Datei \"%s\" verweigert!" #, perl-format msgid "The URL \"%s\" was not found on this server!" msgstr "Die URL \"%s\" wurde auf dem Server nicht gefunden!" msgid "Your favorites" msgstr "Favoriten" msgid "Search results" msgstr "Suchergebnis" msgid "Default" msgstr "Standard" msgid "--- no timer ---" msgstr "--- kein Timer ---" msgid "unknown" msgstr "unbekannt" msgid "none" msgstr "keine" #, perl-format msgid "Can't open file \"%s\"!" msgstr "Kann Datei \"%s\" nicht öffnen!" #, perl-format msgid "Can't connect to VDR at %s:%s: %s

Please check if VDR is running and if VDR's svdrphosts.conf is configured correctly." msgstr "Konnte Verbindung zu %s:%s nicht aufbauen: %s

Bitte überprüfen Sie, dass VDR läuft und dass seine svdrphosts.conf richtig konfiguriert ist." #, perl-format msgid "Error while sending command to VDR at %s" msgstr "Fehler beim Senden eines Kommandos zu %s" msgid "Internal error:" msgstr "Interner Fehler:" msgid "Lookup movie in the Internet-Movie-Database (IMDb)" msgstr "Film in der Internet-Movie-Database (IMDb) suchen" msgid "Can't find EPG entry!" msgstr "EPG-Eintrag wurde nicht gefunden!" msgid "Playing Tomorrow" msgstr "Was läuft morgen" #, perl-format msgid "Playing on the %s" msgstr "Was läuft am %s" msgid "next" msgstr "als nächstes" msgid "What's on after" msgstr "Was läuft nach" msgid "What's on at" msgstr "Was läuft um" msgid "Suitable matches for:" msgstr "Suchergebnis für" msgid "short view" msgstr "Listenansicht" msgid "long view" msgstr "Ausführliche Ansicht" msgid "Schedule" msgstr "Übersicht" #, perl-format msgid "Can't write configuration file %s! Reason: %s" msgstr "Kann die Konfigurationsdatei %s nicht schreiben! Grund: %s" #, perl-format msgid "Configuration file %s not writable! Configuration won't be saved!" msgstr "Die Konfigurationsdatei %s ist schreibgeschützt! Die Konfiguration wird nicht gesichert!" msgid "Timers" msgstr "Timer" msgid "System default" msgstr "Systemstandard" vdradmin-am-3.6.13/po/es.po000066400000000000000000002162751443716113400154110ustar00rootroot00000000000000# Copyright (C) Andreas Mair # This file is distributed under the same license as the VDRAdmin-AM package. # # rudiberto , 2007 # msgid "" msgstr "" "Project-Id-Version: VDRAdmin-AM-3.6.6\n" "Report-Msgid-Bugs-To: Andreas Mair \n" "POT-Creation-Date: 2012-07-09 12:23+0200\n" "PO-Revision-Date: 2011-11-18 23:42+0200\n" "Last-Translator: Ville Skyttä \n" "Language-Team: Spanish \n" "Language: es\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Language: Spanish\n" "X-Poedit-Country: SPAIN\n" "X-Poedit-SourceCharset: UTF-8\n" "X-Poedit-Bookmarks: 210,-1,86,-1,-1,-1,-1,-1,-1,-1\n" msgid "About" msgstr "Acerca de" msgid "License" msgstr "Licencia" msgid "Authors" msgstr "Autores" msgid "Current author (VDRAdmin-AM branch):" msgstr "Autor actual (VDRAdmin-AM):" msgid "Original author (VDRAdmin):" msgstr "Autor original (VDRAdmin):" msgid "Translation Team" msgstr "Equipo de traducción" msgid "English:" msgstr "Inglés:" msgid "German:" msgstr "Alemán:" msgid "French:" msgstr "Francés:" msgid "At the moment unmaintained, former translations by:" msgstr "De momento no se actualiza, traducciones anteriores de:" msgid "Spanish:" msgstr "Español:" msgid "Finnish:" msgstr "Finlandés:" msgid "Dutch:" msgstr "Holandés:" msgid "Russian:" msgstr "Ruso:" msgid "Czech:" msgstr "Checo:" msgid "Italian:" msgstr "Italiano:" msgid "Hungarian:" msgstr "" msgid "Information" msgstr "Información" msgid "VDRAdmin-AM version:" msgstr "Versión de VDRAdmin-AM:" msgid "VDR version:" msgstr "Versión de VDR:" msgid "Supported features in VDR:" msgstr "Características respaldadas en VDR:" msgid "EPGSearch" msgstr "Búsqueda EPG" msgid "EPGSearch Plugin" msgstr "" msgid "LiveTV Streaming" msgstr "Flujo de LiveTV" msgid "Streamdev Plugin" msgstr "" msgid "Xineliboutput Plugin" msgstr "" msgid "Rename Recordings (Liemikuutio Patch)" msgstr "Renombrar grabaciones (Liemikuutio Patch)" msgid "Getting Help and Reporting Bugs" msgstr "Recibir ayuda y comentar \"Bugs\" (fallos)" msgid "If you need help please first try to use the online help you'll find on some pages. You can access it by clicking \"\"." msgstr "Si hace falta ayuda, intenta primero \"Online Help\" (Ayuda en linea) que encontraras en algunas páginas. Tienes acceso haciendo clic encima de \"\"." msgid "If this doesn't provide the information you need you can try to get help at VDR-Portal if you understand German language. Please use the announcement thread if possible, search for:" msgstr "Si no te sirve esta información puedes intentar conseguir ayuda en la página VDR-Portal si entiendes alemán (lo siento...). Por favor, usa la conversación del anuncio si es posible, busca por:" msgid "If you think you have found a bug please check that it's a new one and report it in the VDRAdmin-AM BugTracking system." msgstr "Si crees que has encontrado un fallo, asegúrate de que sea un fallo desconocido y entonces coméntalo en VDRAdmin-AM BugTracking system (sistema de seguimiento de fallos)." msgid "AutoTimer" msgstr "Autoprogramaciones" msgid "Priority:" msgstr "Prioridad:" msgid "Lifetime:" msgstr "Durabilidad:" msgid "New AutoTimer" msgstr "Añadir autoprogramación" msgid "Help" msgstr "Ayuda" msgid "Active" msgstr "Activa" msgid "Channel" msgstr "Canal" msgid "Start" msgstr "Inicio" msgid "Stop" msgstr "Fin" msgid "Name" msgstr "Título" msgid "Select all/none" msgstr "Seleccionar todas/ninguna" msgid "Yes" msgstr "Sí" msgid "No" msgstr "No" msgid "Edit" msgstr "Modificar" msgid "Delete timer?" msgstr "¿Borrar programación?" msgid "Delete" msgstr "Borrar" msgid "Force Update" msgstr "Actualizar ahora" msgid "Delete Selected AutoTimers" msgstr "Borrar autoprogramaciones elegidas" msgid "Delete all selected timers?" msgstr "¿Estas seguro de que deseas borrar las programaciones elegidas?" msgid "No AutoTimers defined!" msgstr "¡No hay autoprogramaciones!" msgid "Add New AutoTimer" msgstr "Añadir autoprogramación" msgid "Edit AutoTimer" msgstr "Modificar autoprogramación" msgid "AutoTimer Active:" msgstr "Autoprogramación activa:" msgid "oneshot" msgstr "una vez" msgid "Search Patterns:" msgstr "Patrones de búsqueda:" msgid "Search in:" msgstr "Buscar en:" msgid "Title" msgstr "Título" msgid "Subtitle" msgstr "Subtítulo" msgid "Description" msgstr "Descripción" msgid "Search only on these days:" msgstr "Los días para la búsqueda:" msgid "Monday" msgstr "Lunes" msgid "Tuesday" msgstr "Martes" msgid "Wednesday" msgstr "Miércoles" msgid "Thursday" msgstr "Jueves" msgid "Friday" msgstr "Viernes" msgid "Saturday" msgstr "Sábado" msgid "Sunday" msgstr "Domingo" msgid "Channel:" msgstr "Emisora:" msgid "all" msgstr "todos" msgid "Starts After:" msgstr "Empieza después de:" msgid "o'clock" msgstr "h." msgid "Ends Before:" msgstr "Acaba antes de:" msgid "Override Start/Stop Margins:" msgstr "Reemplazar los márgenes de tiempo para Inicio/Fin:" msgid "Time Margin at Start:" msgstr "Margen de tiempo al principio:" msgid "minutes" msgstr "minutos" msgid "Time Margin at Stop:" msgstr "Margen de tiempo al final:" msgid "Episode:" msgstr "Episodios:" msgid "Remember programmed timers:" msgstr "Recordar programaciones:" msgid "Directory:" msgstr "Carpeta:" msgid "Save" msgstr "Guardar" msgid "Test" msgstr "Prueba" msgid "Cancel" msgstr "Cancelar" msgid "Broadcasted" msgstr "Emitido" msgid "Stored in" msgstr "Guardado en" msgid "No matches found!" msgstr "¡Ninguna coincidencia encontrada!" msgid "Configuration" msgstr "Configuración" msgid "General Settings" msgstr "Ajustes generales" msgid "Template:" msgstr "Plantilla:" msgid "Skin:" msgstr "Piel:" msgid "Login Page:" msgstr "Página de inicio:" msgid "Number of channels to use:" msgstr "Cantidad de emisoras a usar:" msgid "Local net (no login required):" msgstr "Red local (no requiere contraseña)" msgid "Language:" msgstr "Idioma:" msgid "Save settings on exit:" msgstr "Guardar los ajustes al salir:" msgid "VDR" msgstr "VDR" msgid "Number of DVB cards:" msgstr "Cantidad de tarjetas DVB:" msgid "Path to recordings:" msgstr "Ruta de las grabaciones:" msgid "Path to configuration files:" msgstr "Ruta de los ficheros de configuración:" msgid "Path to EPG images:" msgstr "Ruta de las imágenes de EPG:" msgid "Identification" msgstr "Identificaciones" msgid "Username:" msgstr "Nombre del usuario:" msgid "Password:" msgstr "Contraseña:" msgid "Guest Account:" msgstr "Acceso como invitado:" msgid "Guest Username:" msgstr "Nombre como invitado:" msgid "Guest Password:" msgstr "Contraseña como invitado:" msgid "Timeline" msgstr "Tabla de tiempo" msgid "Hours:" msgstr "Rango de hora/s:" msgid "Times:" msgstr "Horas:" msgid "Also used for other EPG views!" msgstr "También se usa para otras vistas de la EPG" msgid "Tooltips:" msgstr "Notas flotantes:" msgid "Electronic Program Guide (EPG)" msgstr "Guía electrónica de programación (EPG)" msgid "Day begins at:" msgstr "Día comienza a las:" msgid "Show Subtitle:" msgstr "Mostrar subtítulo:" msgid "Show Summary:" msgstr "Mostrar resumen:" msgid "Active:" msgstr "Activa:" msgid "Send email after programming timer:" msgstr "Mandar mensaje después de crear programación:" msgid "Send email as:" msgstr "Mandar mensaje electrónico como:" msgid "Send email to:" msgstr "Mandar mensaje electrónico a:" msgid "Mail server:" msgstr "Servidor de correo:" msgid "SMTPAuth user:" msgstr "Usuario de SMPTAuth:" msgid "SMTPAuth password:" msgstr "Contraseña de SMPTAuth:" msgid "Track schedule changes by:" msgstr "Vigilar cambios de horario por:" msgid "Broadcast time" msgstr "Hora de emisión" msgid "Event id" msgstr "Id. de programa" msgid "Timer" msgstr "Programaciones" msgid "Tooltips in timeline:" msgstr "Notas flotantes en la tabla de tiempo:" msgid "Tooltips in list:" msgstr "Notas flotantes en la lista:" msgid "Streaming" msgstr "Flujo" msgid "Live Streaming:" msgstr "Flujo en vivo:" msgid "HTTP Port of Streamdev (also possible 3000/ts):" msgstr "Puerto HTTP para el flujo (3000/ts también posible):" msgid "HTTP Port of Xineliboutput (e.g. 37890):" msgstr "" msgid "Recordings Streaming:" msgstr "Flujo de grabaciones:" msgid "Path to VDR Recordings on your workstation:" msgstr "Ruta de las grabaciones de VDR en tu equipo:" msgid "MIME type for live streaming:" msgstr "Tipo MIME del flujo en vivo:" msgid "Suffix for live streaming:" msgstr "Extensión para flujo en vivo:" msgid "MIME type for recordings streaming:" msgstr "Tipo MIME para flujo de grabaciones:" msgid "Suffix for recordings streaming:" msgstr "Extensión para flujo de grabaciones:" msgid "Bandwidth of Streams:" msgstr "Ancho de banda del flujo:" msgid "External Search" msgstr "Búsqueda externa" msgid "URL:" msgstr "URL:" msgid "Title:" msgstr "Título:" msgid "User-defined search:" msgstr "Búsqueda personalizada:" msgid "Expert" msgstr "Experto" msgid "Update EPG data in background:" msgstr "Actualizar datos EPG en segundo plano:" msgid "Update EPG every:" msgstr "Actualizar datos EPG cada:" msgid "Channel Selections" msgstr "Emisoras preferidas" msgid "Show channels without EPG information:" msgstr "Mostrar emisoras sin información EPG:" msgid "In \"AutoTimer\"?" msgstr "¿Usar en \"Autoprogramaciones\"?" msgid "Apply" msgstr "Establecer" msgid "EPG Search Blacklists" msgstr "Utiliza lista negra en búsqueda de EPG:" msgid "New Blacklist" msgstr "Nueva lista negra" msgid "Search pattern" msgstr "Palabras claves" msgid "From" msgstr "De" msgid "To" msgstr "Para" msgid "Delete blacklist?" msgstr "¿Borrar lista negra?" msgid "Delete Selected Blacklists" msgstr "Borrar listas negras elegidas" msgid "Delete all selected blacklists?" msgstr "¿Estás seguro de que deseas borrar las listas negras elegidas?" msgid "EPG search" msgstr "Búsqueda EPG" msgid "EPG Search" msgstr "Búsqueda EPG" msgid "Use template" msgstr "Usar plantilla" msgid "New Search" msgstr "Búsqueda nueva" msgid "Edit Template" msgstr "Editar plantilla" msgid "Settings" msgstr "Ajustes" msgid "Action" msgstr "Acción" msgid "Find" msgstr "Buscar" msgid "Show Favorites" msgstr "Mostrar favoritas" msgid "Delete Selected Searches" msgstr "Borrar búsquedas elegidas" msgid "Delete all selected searches?" msgstr "¿Estás seguro de que deseas borrar las búsquedas elegidas?" msgid "Execute Selected Searches" msgstr "Ejecutar búsquedas elegidas" msgid "Duration" msgstr "Duración" msgid "More Information" msgstr "Más información" msgid "Channels" msgstr "EPG por emisoras" msgid "Record" msgstr "Grabar" msgid "Add New Blacklist" msgstr "Agregar lista negra" msgid "Edit Blacklist" msgstr "Editar lista negra" msgid "Add New Template" msgstr "Añadir plantilla" msgid "Add New Search" msgstr "Añadir búsqueda" msgid "Edit Search" msgstr "Editar búsqueda" msgid "Small search pattern.\\nDo you really want to use it?" msgstr "Patrón de búsqueda muy corto.\\n¿Estás seguro de que deseas utilizarlo?" msgid "You didn't select at least one of\\ntitle, subtitle or description.\\nDo you really want to use this search?" msgstr "No has elegido al menos uno de entre\\ntítulo, subtítulo, o descripción.\\n¿Quieres realizar esta búsqueda?" msgid "Hide results" msgstr "Ocultar resultados" msgid "Name:" msgstr "Nombre:" msgid "Search Term:" msgstr "Término de búsqueda:" msgid "Search Mode:" msgstr "Modo de búsqueda:" msgid "phrase" msgstr "frase" msgid "all words" msgstr "todas las palabras" msgid "at least one word" msgstr "una palabra por lo menos" msgid "match exactly" msgstr "coincidencia exacta" msgid "regular expression" msgstr "expresión regular" msgid "fuzzy" msgstr "difusa" msgid "Tolerance for \"fuzzy\":" msgstr "Tolerancia para \"difusa\":" msgid "Match Case:" msgstr "Coincidir mayús/minús:" msgid "Use extended EPG info:" msgstr "Utiliza información EPG extendida:" msgid "Ignore missing categories?" msgstr "¿Ignorar categorías ausentes?" msgid "Use Channel:" msgstr "Utiliza emisora:" msgid "no" msgstr "no" msgid "interval" msgstr "Intervalo" msgid "channel group" msgstr "Grupo de emisoras" msgid "only FTA" msgstr "sólo FTA" msgid "Range:" msgstr "Rango:" msgid "Channel Group:" msgstr "Grupo de emisoras:" msgid "Use Time:" msgstr "Utiliza hora:" msgid "Start After:" msgstr "Inicia después de:" msgid "Start Before:" msgstr "Inicia antes de:" msgid "Use Duration:" msgstr "Utiliza duración:" msgid "Min. Duration:" msgstr "Duración min.:" msgid "hh:mm" msgstr "hh:mm" msgid "Max. Duration:" msgstr "Duración max.:" msgid "Use Day of Week:" msgstr "Utiliza día de la semana:" msgid "Use Blacklists:" msgstr "Utiliza lista negra:" msgid "selection" msgstr "selección" msgid "Use in Favorites Menu:" msgstr "Utiliza menú de favoritas:" msgid "Use as Search Timer:" msgstr "Utiliza como programación de búsqueda:" msgid "yes" msgstr "Sí" msgid "user-defined" msgstr "personalizado" msgid "record" msgstr "grabar" msgid "announce by OSD" msgstr "anunciado por OSD" msgid "switch only" msgstr "sólo cambiar" msgid "announce and switch" msgstr "anunciar y cambiar" msgid "announce by mail" msgstr "anunciar por correo" msgid "First day:" msgstr "Primer día:" msgid "Last day:" msgstr "Último día:" msgid "Auto delete:" msgstr "Borrar automáticamente:" msgid "count recordings" msgstr "Cantidad de grabaciones" msgid "count days" msgstr "Cantidad de días" msgid "After ... recordings:" msgstr "Después ... grabaciones:" msgid "After ... days after first recording:" msgstr "Después de ... días después de la última grabación:" msgid "Settings for action \"record\"" msgstr "Ajustes para acción \"grabar\"" msgid "Series Recording:" msgstr "Grabación en serie:" msgid "Delete Recordings After ... Days:" msgstr "Borrar grabaciones después de ... días:" msgid "Keep ... Recordings:" msgstr "Guarda ... grabaciones:" msgid "Pause, when ... recordings exist:" msgstr "Pausa, si existen ... grabaciones:" msgid "Avoid Repeats:" msgstr "Evitar repeticiones:" msgid "Allowed Repeats:" msgstr "Permitir repeticiones:" msgid "Only Repeats Within ... Days:" msgstr "Sólo repeticiones dentro de ... días:" msgid "Compare:" msgstr "Comparar:" msgid "Minimal match of description in %:" msgstr "" msgid "VPS:" msgstr "VPS:" msgid "Settings for action \"switch only\"" msgstr "Ajustes para \"sólo cambiar\"" msgid "Switch ... Minutes Before Start:" msgstr "cambiar ... minutos antes del inicio:" msgid "Unmute sound:" msgstr "" msgid "Settings for action \"announce and switch\"" msgstr "" msgid "Ask ... Minutes Before Start:" msgstr "" msgid "Delete template" msgstr "Borrar plantilla:" msgid "Delete this template?" msgstr "¿Borrar esta plantilla?" msgid "Save as template" msgstr "Guardar como plantilla" msgid "Run" msgstr "Iniciar" msgid "Error!" msgstr "¡Error!" msgid "

Here you will find a listing of automatic timers (AutoTimer) known to VDRAdmin-AM.

The list shows some information on AutoTimers. You can change the list's sorting by clicking the columns heading.

For each AutoTimer you have the following options:

Set its state
By clicking on \"Yes\" or \"No\" in the \"Active\" column to toggle the activity.
Quickly view its priority and lifetime
By pointing the mouse cursor to the AutoTimer's title.
Edit the AutoTimer
You can edit an AutoTimer by clicking \"edit\".
Delete the AutoTimer
To delete an AutoTimer you click \"delete\".

Each AutoTimer's state is indicated by differently coloured images:
\"on\" AutoTimer is OK and will automatically program matching broadcasts.
\"inactive\" AutoTimer is not active.

In addition to these functions you can add a new AutoTimer by clicking at the top and you can delete a number of AutoTimers at once by checking the box in the last column of those timers and clicking .

Click to force VDRAdmin-AM to reconnect to VDR, fetch the current EPG and check for matching AutoTimers.

" msgstr "" "

Aquí se encuentra una lista de todas las autoprogramaciones conocidas por VDRAdmin-AM.

\n" "

La lista contiene informaciones de las autoprogramaciones. Se puede cambiar el orden de la lista haciendo clic en los títulos de las columnas.

\n" "\n" "

Para cada autoprogramación hay las siguientes opciones:

\n" "
Cambiar estado
\n" "
Haciendo clic en \"Sí\" o \"No\" en la columna \"Activa\" se puede activar y desactivar.
\n" "\n" "
Vista rápida de prioridad y durabilidad
\n" "
Tienes que mover la flecha del ratón encima del nombre de la autoprogramación.
\n" "\n" "
Modificar autoprogramación
\n" "
Se realiza una edición haciendo clic en \"editar\".
\n" "\n" "
Borrar autoprogramación
\n" "
Para borrar una autoprogramación hay que hacer clic en \"borrar\".
\n" "

\n" "

El estado de una autoprogramación está indicada por colores diferentes:
\n" "\"Activa\" La autoprogramación está bien y va a programar automáticamente emisiones coincidentes.
\n" "\"inactiva\" La autoprogramación está desactivada.

\n" "

Además se puede añadir otra autoprogramación más, haciendo clic en al tope. Más abajo se encuentra el botón , cuál hace posible borrar las autoprogramaciones marcadas en la lista por lotes.

\n" "

Con el botón arrancarás una búsqueda inmediatamente en los datos actuales de la EPG recién actualizados.

" msgid "

Here you can edit an automatic timer's (AutoTimer) settings.

AutoTimer is a key feature of VDRAdmin-AM. An AutoTimer consists of one or more search terms and some other settings, that are looked for regularly in the Electronic Program Guide (EPG). On match AutoTimer adds a timer in VDR automatically for that broadcast. That's very comfortable for irregularly broadcasted series or movies you don't want to miss.

" msgstr "" "

Aquí se encuentra los ajustes de las autoprogramaciones.

\n" "

Autoprogramaciones son la herramienta básica del VDRAdmin-AM. Una autoprogramación busca por una o más palabras claves y unos ajustes más, por los cuáles buscará regularmente en la \"Electronic Program Guide\" (EPG, guía electrónica de programación). Sí lo encuentra, aquellas variables ajustadas anteriormente crearán automáticamente una programación en el VDR para el programa encontrado. Bastante útil para emisiones irregulares, que te importan mucho.

" msgid "Activate or deactivate this AutoTimer. Deactivated AutoTimers are still stored in the AutoTimer list so that they can be activated again, but they do not record anything meanwhile. Above that you can set this to \"oneshot\" so this AutoTimer only programs the (one!) next matching broadcast." msgstr "Activar o desactivar ésta programación. Programaciones desactivadas se encuentran todavía en la lista de las programaciones. Así se puede activar más tarde. Pero significará que no grabará mientras está desactivada." msgid "Choosing the right search items decides whether only the wanted broadcasts or broadcasts having similar names or even nothing gets recorded.
Case doesn't matter, \"X-Files\" matches anything \"x-files\" will match. You can set multiple search items by separating them with spaces. Broadcasts will match only if they match all configured search items.
You'd better only use letters and numbers for search items, as the EPG often miss colons, brackets and other characters.
Experts can also use regular expressions, but you have to get needed information from the VDRAdmin-AM sources (undocumented feature).

You can exclude broadcasts so that they don't get recorded even if they would match an AutoTimer. Therefore you have to enter that titles into the file vdradmind.bl, one event a line. This file must be located in your VDRAdmin-AM's configuration folder. If this string is found either in the EPG's title or in title~subtitle, this event will not be programmed by AutoTimer. So you can disable complete episodes (for example when using \"Enterprise\" as blacklist string) or only one episode (when using \"Enterprise~Azati Prime\" as blacklist string)." msgstr "" "Las palabras claves bien elegidas importan mucho para grabar sólo el programa querido o por ejemplo también éstos con palabras parecidas o con mala suerte nada por falta de coincidencia.
\n" "Mayúsculas o minúsculas no importan para encontrar las palabras claves. Se puede usar varias palabras claves separadas por espacios. Todas tienen que encontrarse en los campos deseados del programa para un resultado exitoso.
\n" "Es muy recomendable, utilizar sólo caracteres normales o cifras como palabra clave, porque los caracteres especiales no son muy comunes en la EPG.
\n" "Para expertos hay la posibilidad de usar \"regular expressions\". Para esta función no documentada, tienes que investigar el código fuente del VDRAdmin-AM.
\n" "
Otra opción es, excluir un programa, que normalmente cumpliría los valores de búsqueda, agregando su título al fichero vdradmind.bl. Cada programa se pone en una fila. Este archivo tiene que estar en la carpeta de configuración del VDRAdmin-AM. Sí una fila coincide con título o título~subtítulo de la EPG del programa, no se va a autoprogramar ese programa. Así se puede bloquear una serie completa (p.e. con \"Stargate\" como registro negro) o un episodio solo (p.e. \"Stargate~Revisiones\")." msgid "Here you can define the EPG sections where VDRAdmin-AM should look for the search pattern." msgstr "Aquí se ajusta las secciones de la EPG (emisoras posibles) donde VDRAdmin-AM va a buscar por palabras claves." msgid "Use these checkboxes to limit searching for matching broadcasts to a set of weekdays." msgstr "Marca estas casillas para especificar los días de la semana que quieres incluir para la búsqueda." msgid "The channel to look for matching broadcasts or \"all\" to search in all known or wanted channels. You can define the wanted channels for AutoTimer in \"Configuration\"." msgstr "La emisora para la búsqueda o \"todas\" para buscar en todas las cadenas conocidas o deseadas. Se puede establecer las emisoras deseadas para autoprogramaciones en \"Configuraciones\"." msgid "A broadcast must start after the time entered here to match. The first text field is for \"hour\", the second for \"minute\"." msgstr "Un programa tiene que empezar después de la hora establecida aquí. El primer campo es para \"hora\", el segundo para \"minutos\"." msgid "A broadcast must end before the time entered here to match. The first text field is for \"hour\", the second for \"minute\"." msgstr "Un programa tiene que finalizar antes de la hora establecida aquí. El primer campo es para \"hora\", el segundo para \"minutos\"." msgid "Set this option to \"yes\" if all timers programed by this AutoTimer should have individual start/stop margins and enter the values in the next two text boxes." msgstr "Marca \"Sí\" para esta opción, si quieres que todas las programaciones de la autoprogramación tengan margenes individuales para inicio/terminar. Después puedes poner los valores en los 2 siguientes campos de texto." msgid "The number of minutes VDRAdmin-AM subtracts from the broadcast's start time found in the EPG." msgstr "La cantidad de minutos que VDRAdmin-AM va a quitar de la hora inicial del programa encontrado en la EPG" msgid "The number of minutes VDRAdmin-AM adds to the broadcast's stop time found in the EPG." msgstr "La cantidad de minutos que VDRAdmin-AM va a quitar de la hora final del programa encontrado en la EPG" msgid "An integer in the range 0...99, defining the priority of this timer and of recordings created by this timer. 0 represents the lowest value, 99 the highest. The priority is used to decide which timer shall be started in case there are two or more timers with the exact same start time. The first timer in the list with the highest priority will be used.

This value is also stored with the recording and is later used to decide which recording to remove from disk in order to free space for a new recording. If the disk runs full and a new recording needs more space, an existing recording with the lowest priority (and which has exceeded its guaranteed lifetime) will be removed.

If all available DVB cards are currently occupied, a timer with a higher priority will interrupt the timer with the lowest priority in order to start recording." msgstr "" "Un número en el rango 0...99, establece la prioridad de esta programación y la grabación creada de la programación. 0 representa el valor más bajo, 99 lo mayor. La prioridad se usa para decidir cuál de las programaciones se iniciaría en caso de que haya dos o más en la misma hora de inicio. La primera en la lista con la prioridad más alta va a ser elegida.
\n" "
El valor se guardará también junto con la grabación para utilizarlo más tarde para decidir cuál de las grabaciones guardadas se puede borrar del disco para liberar espacio para una nueva grabación, si hace falta. En éste caso una grabación existente con la prioridad más baja (y su duración garantizada ya caducada) removerá.
\n" "
Si todas las tarjetas DVB están ocupadas una programación va a interrumpir otra - si tiene una prioridad más baja - para iniciar su grabación." msgid "The guaranteed lifetime (in days) of a recording created by this timer. 0 means that this recording may be automatically deleted at any time by a new recording with higher priority. 99 means that this recording will never be automatically deleted. Any number in the range 1...98 means that this recording may not be automatically deleted in favour of a new recording, until the given number of days since the start time of the recording has passed by." msgstr "La duración garantizada (en días) de una grabación guardada de esta programación. 0 significa que se puede borrar automáticamente en cualquier momento por otra grabación con prioridad más alta. 99 significa que esta grabación automáticamente nunca va a ser borrada. Todos valores demás en el rango 1...98 significan que esta grabación solo va a ser borrada automáticamente por otra grabación nueva, cuando se han pasado los días ajustados y garantizados desde su día de grabación." msgid "Check this box if you want VDRAdmin-AM to append the broadcast's EPG subtitle to the recording's file name." msgstr "Marca este campo si VDRAdmin-AM debe añadir el subtítulo de la EPG del programa al nombre de la grabación." msgid "If you enable this VDRAdmin-AM will track timers it has already programmed automatically. This is useful if want to deactivate or delete timers that have been programmed automatically in the timers listing." msgstr "Habilitando esta función, VDRAdmin-AM va seguir programaciones programadas automáticamente. Así se puede borrar o desactivar estas programaciones agregadas automáticamente de la lista de programaciones." msgid "The directory this AutoTimer will place the recordings in. If the name shall contain subdirectories, these have to be delimited by '~' (since the '/' character may be part of a regular programme name).
VDRAdmin-AM will append the matching broadcast's title and subtitle (if the \"Episode\" checkbox is marked) to the directory given here.

You can also use the following keywords that are replaced in the final file name by the values supplied by for example tvm2vdr:
  • %Title% - will become the title of the event.
  • %Subtitle% - will become the subtitle of the event.
  • %Director% - will become the director of the event.
  • %Date% - will become the date of the recording.
  • %Category% - will become the category of the event (Spielfilm/Serie/...).
  • %Genre% - will become the genre of the event (Drama/Krimi/..).
  • %Year% - will become the year of production.
  • %Country% - will become the country of production.
  • %Originaltitle% - will become the original title of the event.
  • %FSK% - will become the FSK from the event.
  • %Episode% - will become the episode's title of the event.
  • %Rating% - will become the rating of the event from the EPG provider.

Note:

If you use the above keywords it's in your own responsibility to supply the complete file name for the recordings! VDRAdmin-AM will not append anything to the resulting string." msgstr "" "Aquí se establece la carpeta, donde la autoprogramación va a guardar su grabaciones. Si quieres crear subcarpetas hay que separarlas con '~' (eso por que '/' puede ser parte del título).
\n" "VDRAdmin-AM añadirá automáticamente el título y el subtítulo (a caso que está marcado \"Serie\").
\n" "
Además es posible usar las siguientes palabras claves, que se sustituirán en el título final que se va a encontrar en p.e. tvm2vdr:\n" "
  • %Title% - el título del programa.
  • \n" "
  • %Subtitle% - el subtítulo del programa.
  • \n" "
  • %Director% - el director del programa.
  • \n" "
  • %Date% - la fecha de la grabación.
  • \n" "
  • %Category% - la categoría de la grabación. (Película/serie/...).
  • \n" "
  • %Genre% - el género de la grabación. (Drama/suspense/..).
  • \n" "
  • %Year% - el año de la producción.
  • \n" "
  • %Country% - el país de la producción.
  • \n" "
  • %Originaltitle% - el título original del programa.
  • \n" "
  • %FSK% - el límite por edad del programa.
  • \n" "
  • %Episode% - el título del episodio de una serie.
  • \n" "
  • %Rating% - la valoración del programa de la redacción de la EPG.
  • \n" "
\n" "

Advertencia:

¡Si utilizas estas palabras claves queda a tu propia responsabilidad escribir el nombre completo de la grabación! VDRAdmin-AM no añadirá nada más." msgid "

Here you can change general settings and base settings for timers, AutoTimers, channel selection and streaming parameters.

" msgstr "

En esta página se ajusta las propiedades generales de las programaciones y de las autoprogramaciones, como las emisoras preferidas y además los ajustes del flujo

" msgid "The skin you want to use." msgstr "La piel deseada." msgid "The page you want to see at first connect to VDRAdmin-AM." msgstr "La página deseada al inicio del VDRAdmin-AM." msgid "VDRAdmin-AM will load the given number of channels from VDR and present only those in any fields where channels can be selected. This also limits the EPG information VDRAdmin-AM will read so that you can use this to reduce VDRAdmin-AM's memory consumption and increase its performance. 0 turns this feature off and VDRAdmin-AM will use all available channels." msgstr "VDRAdmin-AM solo utilizará tantas emisoras del VDR como se ajusten aquí y presentará esta cantidad en cada campo, donde se pueden elegir canales. Así también está limitada la información de la EPG que VDRAdmin-AM leerá, que va a reducir el consumo de memoria de VDRAdmin-AM y mejorar así su rendimiento. 0 desactivará esta función y VDRAdmin-AM utilizará todas las emisoras posibles." #, fuzzy msgid "Here you can specify subnets from which access to VDRAdmin-AM does not require logging in. For example: \"192.168.0.0/24\" will include any IP starting with \"192.168.0.\", \"192.168.0.123/32\" will only match \"192.168.0.123\". Multiple subnets can be specified by separating them with spaces or commas." msgstr "Aquí se especifica una dirección IP o rango para una conexión sin necesidad de iniciar una sesión con contraseña. Por ejemplo: \"192.168.0.0/24\" incluye cada IP empezando en \"192.168.0.\", \"192.168.0.123/32\" resultaría \"192.168.0.123\"." msgid "Here you can set the localization VDRAdmin-AM should use." msgstr "Aquí se ajusta el idioma y codificación de caracteres que VDRAdmin-AM utilizará." msgid "With this option the settings will be saved if VDRAdmin-AM exits. This will also save settings not available on the \"Configuration\" menu like interval and size in TV, sorting in the lists and current view in \"What's on now\"." msgstr "Con esta opción los ajustes se guardarán cuando VDRAdmin-AM se apague. Así guardará también las opciones invisibles del menú \"Configuración\" como intervalo y dimensiones del TV, orden de la lista y modo de vista en \"Programas ahora\"." msgid "Top" msgstr "Al principio" msgid "The number of DVB cards VDR can access. Depending on this value VDRAdmin-AM will calculate critical timers in the Timer menu." msgstr "La cantidad de tarjetas accesibles. Referiendose a este valor, VDRAdmin-AM calculará programaciones críticas en el menú Programaciones" msgid "The path to VDR's recordings. It's used so that VDRAdmin-AM can locate the recordings when using Recordings Streaming and reccmds.conf in the Recordings menu." msgstr "La ruta de las grabaciones. Necesario, para que VDRAdmin-AM pueda localizar las grabaciones para usar Flujo de grabaciones y reccmds.conf en el menú Grabaciones." msgid "The path where VDR's configuration files are located. If this directory contains the file reccmds.conf its content is shown in a selectbox in the Recordings menu." msgstr "La ruta de los ficheros de configuración del VDR. Si allí se encuentra el archivo reccmds.conf su contenido se mostrará en un campo de selección en el menú Grabaciones." msgid "The path where the EPG images are stored." msgstr "La ruta donde se guardan las imágenes de EPG" msgid "The username for the main user, i.e. the user having the most privileges." msgstr "El nombre del usuario, p.e. el usuario con todos los privilegios." msgid "The main user's password." msgstr "La contraseña del usuario principal." msgid "If you want a user account having only limited privileges, this is for you. The guest user cannot modify anything, it's only allowed to view the EPG, timers, AutoTimers and recordings listings." msgstr "Esta opción te permite crear una cuenta limitada. La cuenta del invitado no permite modificar nada. Además sólo se le permite ver EPG, programaciones, autoprogramaciones y grabaciones." msgid "The username for the guest user." msgstr "Nombre del invitado." msgid "The guest user's password." msgstr "Contraseña del invitado." msgid "The number of hours to show in the timeline." msgstr "Cantidad de horas visibles en la tabla de tiempo." msgid "A comma separated list of times in hh:mm format that appear in the selectbox placed at the top." msgstr "Una lista separada por coma con el formato hh:mm, que aparece en la lista de selección al principio de la página." msgid "Here you can (de-)activate the tooltips." msgstr "Aquí se pueden (des)activar las notas flotantes." msgid "The time after which events are shown on a new day. For example setting 03:00 means that today's schedule will include any event starting before 03:00 tomorrow. Applies only to the 'Playing Today?' list." msgstr "El tiempo después del que los eventos se muestran en un nuevo día. Por ejemplo, establecerlo a 03:00 significa que el horario de hoy incluirá cualquier evento que comience antes de las 03:00 mañana. Aplica sólo a la lista de \"Programas hoy\"." msgid "Show the 'Subtitle' text for each event. Not all broadcasters use this field." msgstr "Mostrar el texto de 'Subtítulo' para cada programa. No todas las emisoras utilizan este campo." msgid "Show the 'Summary' text for each event." msgstr "Mostrar el texto de 'Resumen' para cada programa." msgid "Activate or deactivate the AutoTimer function." msgstr "Activar o desactivar la función autoprogramación" msgid "VDRAdmin-AM will send an email whenever an event matches an AutoTimer and a timer has been programmed if you enable this feature." msgstr "VDRAdmin-AM mandará un email, siempre que un evento cumpla con una autoprogramación y se haya creado una programación para él si habilitas esta posibilidad." msgid "Here you set the sending email address of the generated email." msgstr "Aquí se pone el remitente del mensaje generado." msgid "The email address the email is sent to." msgstr "La dirección a donde se manda el mensaje." msgid "The outgoing mail server." msgstr "Servidor de correo saliente" msgid "If you need to authenticate yourself at the outgoing mail server, you have to supply the username and the password below. Leaving this field empty will disable SMTPAuth." msgstr "Si hace falta autentificarse al servidor de mensajes saliente, hay que agregar el nombre del usuario y la contraseña abajo. Dejandolo vacío deshabilitará SMPTAuth." msgid "The password for the SMTPAuth user." msgstr "Contraseña del usuario de SMPTAuth." msgid "Here you can (de-)activate the tooltips in the timeline." msgstr "Aquí se pueden (des)activar las notas flotantes en la tabla de tiempo" msgid "Here you can (de-)activate the tooltips in the list." msgstr "Aquí se pueden (des)activar las notas flotantes en la lista." msgid "Add summary to new timers:" msgstr "Añadir resumen a programaciones creadas:" msgid "If you don't want VDRAdmin-AM to add the summary taken from EPG to new timers you can switch it off here." msgstr "Si no quieres que VDR agregue el resumen creado automáticamente de la información de la EPG a las programaciones nuevas, se puede deshabilitar aquí." msgid "Enable or disable live streaming using the streamdev plugin. You also have to set the correct HTTP Port for Streamdev below." msgstr "Habilitar o inhabilitar flujo en vivo utilizando el streamdev plugin. Además tienes que ajustar correctamente el puerto HTTP para flujo más abajo." msgid "Here you have to set the port number your VDR's streamdev server listens for connections. Additionally you can also provide the stream type you like to use." msgstr "Aquí se ajusta el numero del puerto del servidor del streamdev de VDR. Además puedes elegir el tipo del flujo." msgid "Enable or disable streaming of recordings.
Well actually this is no real \"streaming\", but you have to setup your workstation so that it can access VDR's recordings. You can use for example Samba or NFS for this. VDRAdmin-AM simply generates a playlist that contains all parts of the recording and sends this to your browser. If your browser and media player are configured correctly you will see the recording on your workstation's display." msgstr "" "Habilitar o deshabilitar el flujo de grabaciones.
\n" "Pues realmente no es un \"flujo\" de verdad, por que tienes que configurar tu ordenador para que tenga acceso a las grabaciones del VDR. Se puede usar Samba o NFS. VDRAdmin-AM solo va a crear una lista de títulos incluyendo todas las grabaciones y mandarlas al navegador. Si está bien configurado el navegador y reproductor multimedia, verás las grabaciones en la pantalla del ordenador." msgid "This is the path where your workstation can access VDR's recordings. This depends on your VDR and workstation setup, for example \"\\\\vdr\\videos\" or \"V:\\\" (on Windows) or \"/mnt/videos\" (on Linux)." msgstr "Ésta es la ruta donde tu equipo puede acceder a las grabaciones de VDR. Depende de la configuración de los dos, p.e. \"\\\\vdr\\videos\" o \"V:\\\" (en Windows) o \"/mnt/videos\" (en Linux)." msgid "The MIME type to send when using live streaming. Defaults to \"video/x-mpegurl\"." msgstr "Tipo MIME para mandar utilizando flujo en vivo. Por defecto \"video/x-mpegurl\"." msgid "The suffix to use for live streaming. Defaults to \"m3u\"." msgstr "La extensión para el uso de flujo en vivo. Por defecto \"m3u\"." msgid "The MIME type to send when using recordings streaming. Defaults to \"video/x-mpegurl\"." msgstr "Tipo MIME para mandar mientras utilizando flujo de grabaciones. Por defecto \"video/x-mpegurl\"." msgid "The suffix to use for recordings streaming. Defaults to \"m3u\"." msgstr "La extensión utilizada para flujos de grabaciones. Por defecto \"m3u\"." msgid "

Here you can define two external searches that you can access in the EPG views. You simply have to find the required URL and where the search pattern has to be located. %TITLE% will be substituted by the broadcast's EPG title.

" msgstr "

Aquí se pueden definir dos búsquedas externas que serán accesibles en las vistas de EPG. Solo hay que encontrar la URL necesaria y dónde se ha de insertar el patrón de búsqueda. %TITLE% se va a sustituir con el título de la EPG.

" msgid "Some examples:" msgstr "Unos ejemplos:" msgid "Please change the hostname to your local needs!" msgstr "¡Adapta el nombre del host a tus necesidades locales!" msgid "

This section is for experts only, i.e. you know what you are doing!

" msgstr "

Esta sección es sólo para expertos, ¡es bastante importante saber que haces!

" msgid "If set to \"yes\" VDRAdmin-AM will periodically refresh its local EPG cache. Else the EPG will be refreshed if the user accesses any EPG view at the web interface and the timeout set at \"Update EPG every\" has been reached." msgstr "Si esta activado con \"sí\" VDRAdmin-AM actualizará periódicamente su datos EPG local en segundo plano. En el otro caso solo se actualiza, cuando el usuario abre la vista de EPG en la plantilla del VDRAdmin y el periodo ajustado en \"Actualizar EPG cada\" se ha caducado." msgid "The interval, the EPG data is refreshed from VDR and AutoTimer updates are performed (if AutoTimer feature is used)." msgstr "El intervalo de búsqueda que va a realizar VDRAdmin-AM para actualizar las autoprogramaciones (en caso de usar el autoprogramador)" msgid "

If you want to limit the number of channels used in some parts of VDRAdmin-AM, this is for you!

Use the radio buttons to activate or deactivate the wanted channels in the named menu.

To add channels to the list of wanted channels you have to select them in the left side selectbox and click . If you want to remove channels from the list of wanted channels you have to select them in the right side selectbox and click .

" msgstr "" "

Aquí se puede limitar la cantidad de emisoras visibles en diferentes partes del VDRAdmin-AM!

\n" "

Usa los botones para activar o desactivar en el menú las emisoras deseadas.

\n" "

Se pueden añadir emisoras seleccionando una o más en el campo de la izquierda (Elegir más de una se permite con el botón \"CTRL\" apretando mientras haces clic en las emisoras). Al final haces clic en el botón . Para desmarcar emisoras haz lo mismo pero con las emisoras de la lista de la derecha y pulsa .

" msgid "Usually channels that don't have EPG information are hidden in all EPG views. If you don't want them to be hidden you have to set this option to \"yes\"." msgstr "Normalmente no se muestran las emisoras sin información EPG. Si no quieres que se oculten pon esta opción a \"sí\"." msgid "Edit Timer" msgstr "Modificar programación" msgid "Edit EPG" msgstr "Modificar EPG" msgid "

Here you can edit the descriptive fields of an existing EPG entry.

" msgstr "

Aquí se puede modificar la descripción de una entrada EPG existente.

" msgid "Channel (readonly)" msgstr "Emisora (sólo lectura)" msgid "This is the channel of the EPG entry. It cannot be changed." msgstr "Eso es el canal de la entrada del EPG. ¡No se puede cambiar!" msgid "Time (readonly)" msgstr "Horas (sólo lectura)" msgid "This is the start and end time of the entry. It cannot be changed." msgstr "Eso es la hora de inicio y final de la entrada. No se puede cambiar!" msgid "Change this string to give this EPG Entry a new title. It must consist of only one line of text." msgstr "El nuevo título de solo una fila de la entrada de la EPG." msgid "Change this string to give this EPG Entry a new subtitle. It must consist of only one line of text." msgstr "El nuevo subtítulo de la entrada de la EPG. Sólo puede contener una línea." msgid "Change the text in this field to edit the description of this entry. The text can consist of one or more lines." msgstr "Aquí se puede manipular la descripción del EPG. Este texto puede tener varias líneas." msgid "VPS (readonly)" msgstr "VPS (sólo lectura)" msgid "If available this field shows the vps time of the EPG entry. It cannot be changed." msgstr "Si disponible, muestra la hora VPS de la entrada de EPG. No se puede modificar." msgid "Video tracks (readonly)" msgstr "Pistas de vídeo (sólo lectura)" msgid "If available this field shows the video track(s). It cannot be changed." msgstr "Si disponible, muestra las pistas de vídeo. No se puede modificar." msgid "Audio tracks (readonly)" msgstr "Pistas de audio (sólo lectura)" msgid "If available this field shows the audio track(s). It cannot be changed." msgstr "Si disponible, muestra las pistas de audio. No se puede modificar." msgid "No Help Available" msgstr "No hay ayuda" msgid "

No help available yet. For adding or changing text please contact amair.sob@googlemail.com.

" msgstr "" "

Para esta función no dispone ayuda hasta ahora. Para añadir o modificar un texto, escribe un e-mail a \n" "amair.sob@googlemail.com.

" msgid "Recordings" msgstr "Grabaciones" msgid "

Here you will find a listing of recordings known to VDR. The headline will also show you VDR's total and free disk space.

The listing showing you some information on the recordings. You can change the list's sorting by clicking the columns heading. Above the list you'll see the navigation path. If you want to view the contents of previous folders you'll have to click on its name in that path.

Each row contains this information:

Date
The date when the recording has been done. In case of folders this will show the number of recordings the folder contains.
Time
The time when the recording has been done. In case of folders this will show the number of new recordings the folder contains.
Name
The recording's or folder's name. Click it to show the recording's summary or descend into the folder.
Rename (\"edit\")
Rename a recording.

Note:

This only works if VDR has the MOVR or RENR SVDRP command which is not a core VDR feature but provided by the Liemikuutio patch set.
Delete (\"delete\")
Delete a recording.
Stream (\"stream\")
This column is only shown if you activated and configured Recordings Streaming in the Configuration menu. You can watch the recording at your workstation.

In addition to these functions you can delete a number of recordings at once by checking the box in the last but one column of those recordings and clicking .

If you've set the path the VDR's configuration files and have entries in VDR's reccmds.conf you can run those commands for the selected recording by selecting the wanted command in the select box locate next to Commands: and pressing the button.

Use to force reloading of VDR's recordings listing.

" msgstr "" "

Aquí se ve una lista de todas las grabaciones disponibles en el VDR. En la fila encabezada se puede ver el espacio total y libre del VDR.

\n" "

Esta lista contiene algunas informaciones de las grabaciones. Se puede cambiar el orden de la lista haciendo clic en los títulos de las columnas. Encima se ve la ruta de navegar. Si quieres ver el contenido de una carpeta visitado anteriormente, se puede hacer clic en el nombre de la carpeta en esa ruta.

\n" "

Cada fila contiene las informaciones siguientes:

\n" "\n" "
Fecha
\n" "
La fecha cuando se realizó la grabación. Si es una carpeta se ve la cantidad de grabaciones dentro.
\n" "\n" "
Hora
\n" "
La hora cuando se grabó. Si es una carpeta se ve la cantidad de grabaciones nuevas.
\n" "\n" "
Nombre
\n" "
El nombre de la carpeta o de la grabación. Se hace clic para ver el contenido o un resúmen de la grabación..
\n" "\n" "
Renombrar (\"edit\")
\n" "
Renombrar una grabación.

Advertencia:

Solo funccionará si tu VDR entiende el comando RENR del SVDRPuerto. Aúnque no es un orden estandar del VDR, se puede añadir un parche. vdr-aio21_svdrprename.patch y enAIO-v2.2+ te añadirá este orden.
\n" "\n" "
Borrar (\"delete\")
\n" "
Borrar una grabacion.
\n" "\n" "
Flujo (\"stream\")
\n" "
Esta columna solo se ve, si has activado y configurado Flujo de grabaciones en la página de Configuraciones. Así entonces es posible ver las grabaciones en tu ordenador.

\n" "

Además es posible borrar varias grabaciones por lotes, marcando la casilla de cada una deseada y haciendo clic en

\n" "

Si has ajustado la ruta de los archivos de configuración y además se encuntra ahi el fichero reccmds.conf, se puede utilizar los órdenes que contiene para las grabaciones elegidas. Hay que elegir el órden deseado con el botón a lado de Órdenes: y depués hacer clic en .

/n

Así se restaurará la lista de grabaciones de VDR

" msgid "

Here you will find a listing of timers known to VDR.

On top you will find a chart showing a day's timers graphically. This provides an quick overview on what's going on at the specified day and helps you in finding conflicting timers. Moving the mouse cursor above any timer box will display a tooltip containing the timer's title, priority, lifetime and duration.

Below the chart you'll find the timers list showing you some information on the timers. You can change the list's sorting by clicking the columns heading.

For each timer you have the following options:

Set its state
By clicking on \"Yes\", \"No\", \"VPS\" or \"Auto\" in the \"Active\" column.
Quickly view its priority and lifetime
By pointing the mouse cursor to the timer's title.
View its EPG entry
Timers that have set AutoTimer Checking to \"Transmission Identification\" will show you the corresponding EPG entry if you click on the timer's title.
Edit the timer
You can edit a timer by clicking \"edit\".
Delete the timer
To delete a timer you click \"delete\".

Each timer's state is indicated by differently coloured boxes (in the chart view) or images (in the list view):
    / \"on\" Timer is OK and will record.
    / \"problem\" Timer conflicts with other timers. That's not critical, as long as you have enough DVB cards for the parallel recordings.
    / \"impossible\" Timer is critical and will most likely not record.
    / \"inactive\" Timer is not active.

In addition to these functions you can add a new timer by clicking at the top and you can delete a number of timers at once by checking the box in the last column of those timers and clicking .

You can and selected timers.

" msgstr "" "

Aquí encontrarás una lista de programaciones conocidas para VDR.

\n" "

Arriba hay un diagrama mostrando gráficamente las programaciones del día. Te ofrece una vista rápida del día especificado y te ayuda encontrar programaciones conflictivas. Moviendo la flecha del ratón encima de cualquier programación verás el título, la prioridad, la durabilidad y la duración de la programación.

\n" "

Abajo del diagrama encuentras la lista de programaciones visualizando unas informaciones de las programaciones. Se puede cambiar el orden de la lista con un clic en el tope de la columna correspondiente.

\n" "

Para cada programación tienes las siguientes opciones:

\n" "
Establecer su estado
\n" "
Hacer clic en \"Sí\", \"No\", \"VPS\" o \"Auto\" en la columna \"Activa\".
\n" "
Vista rápida de la prioridad y durabilidad
\n" "
Moviendo la flecha del ratón encima del título de programación.
\n" "
Vista de la entrada del EPG
\n" "
Programaciones con Autotest programación para la \"Identificación de la transmisión\" enseñarán la entrada correspondiente del EPG si haces clic en el título.
\n" "\n" "
Modificar programación
\n" "
Se puede editar una programación haciendo clic en \"editar\".
\n" "\n" "
Borrar la programación
\n" "
Se puede borrar una programación haciendo clic en \"borrar\".

\n" "\n" "

El estado de cualquiera programación está indicado por iconos de diferentes colores (la vista como diagrama) o imagenes (la vista como lista):
\n" "    / \"activa\" OK para la programación y grabará.
    / \"problema\" Conflictos con otras programaciones. Ésto no produzca ningún problema, si hay bastantes tarjetas DVB para grabar en paralelo.
\n" "    / \"imposible\" Programación crítica que probablemente no grabará.
\n" "    / \"inactiva\" Programación inactiva.

\n" "

Además puedes añadir una programación nueva cliqueando encima de arriba y se puede borrar programaciones por lotes cliqueando encima al final de la columna.

\n" "

Se puede y programaciones seleccionadas.

" msgid "

Here you can edit a timer's settings.

" msgstr "

Aquí se pueden modificar los ajustes de las programaciones.

" msgid "Timer Active:" msgstr "Programación activa:" msgid "Activate or deactivate this timer. Deactivated timers are still stored in the timer list so that they can be activated again, but they do not record anything meanwhile." msgstr "Activar o desactivar esta programación. Programaciones desactivadas se encuentran todavía en la lista de las programaciones. Así se puede activarse más tarde. Pero significará que no grabará mientras están desactivadas." msgid "AutoTimer Checking:" msgstr "Comprobación de las auto programaciones:" msgid "Depending on how this timer has been programmed you have up to three possible settings:" msgstr "Dependiendo de como se haya creado la programación tienes tres ajustes posibles:" msgid "Transmission Identification" msgstr "Identificador de la emisora" msgid "Monitor this timer using the identification provided in the EPG. Please note that this only works if the provided identification is a fix and unique value! This option is not available with timers programmed in VDR." msgstr "Monitorizar esta programación utilizando la identificación del EPG. ¡Ten en cuenta, que éste sólo funcionará si el identificador es un valor fijo y único! Esta opción no es valido para programaciones creados en VDR." msgid "Time" msgstr "Hora" msgid "Monitor this timer using the start and stop time." msgstr "Monitorizar esta programación utilizando hora de inicio y fin." msgid "off" msgstr "apagado" msgid "Do not monitor this timer." msgstr "No monitorices esta programación." msgid "The channel to record." msgstr "La emisora para grabar:" msgid "Day Of Recording:" msgstr "Día de la grabación:" msgid "The day when the timer should get active. You can enter the day in two formats:
  • Two digits (DD). This will use the current month and year.
  • ISO norm (YYYY-MM-DD). Program your timers as far in the future as you like.
In case you want to program a repeating timer you can use the seven checkboxes below the text field. Check the box for each day you want the timer to get active." msgstr "" "El día de la activación de la programación. Se puede verificar en dos formatos:
    \n" "
  • Dos dígitos (DD). Así se usará mes y año actual.
  • \n" "
  • Norma ISO (YYYY-MM-DD). Esta forma te permite crear programaciones para cualquier momento en el futuro.
\n" "Para una programación repetitiva usa las 7 casillas abajo del texto. Cada una marcará el día activado para la programación." msgid "Start Time:" msgstr "Comienzo:" msgid "This is the time when the timer should start recording. The first text field is for \"hour\", the second for \"minute\"." msgstr "Esta es la hora cuando la programación iniciará la grabación. El primer campo de texto es para \"hora\", el segundo para \"minutos\"." msgid "End Time:" msgstr "Fin:" msgid "This is the time when the timer should stop recording. The first text field is for \"hour\", the second for \"minute\"." msgstr "Esta es la hora cuando la programación acabará la grabación. El primer campo de texto es para \"hora\", el segundo para \"minutos\"." msgid "Title of Recording:" msgstr "Título de la grabación:" msgid "The file name this timer will give to a recording. If the name shall contain subdirectories, these have to be delimited by '~' (since the '/' character may be part of a regular programme name).

The special keywords TITLE and EPISODE, if present, will be replaced by the title and episode information from the EPG data at the time of recording (if that data is available). If at the time of recording either of these cannot be determined, TITLE will default to the channel name, and EPISODE will default to a blank." msgstr "" "El titulo que esta programación va a dar a la grabación. Si la grabación la quieres agregar en una subcarpeta, tienes que seperar cada una con '~' (desde que el caracter '/' puede ser parte de programas regulares).
\n" "
Las palabras claves TÃTULO y EPISODIO, si existen, van a ser sustituidos con título y episodio de los datos de la EPG en la hora de grabación; si no puede verificar esos datos, porque no se encuentra la información en los datos\n" " TÃTULO se pone con el nombre del canal y EPISODIO se deja en blanco." msgid "Summary:" msgstr "Resumen:" msgid "Arbitrary text that describes the recording made by this timer. If this field is not empty, its contents will be written into the summary.vdr or info.vdr file of the recording." msgstr "Un texto a tu gusto para describir la grabación realizada de una programación. Si este campo contiene algo, el texto va a ser escrito al fichero summary.vdr o info.vdr de la grabación." msgid "Your Browser does not support frames!" msgstr "¡El navegador no respalda marcos!" msgid "What's On Now?" msgstr "Programas ahora" msgid "Playing Today?" msgstr "Programas hoy" msgid "Remote Control" msgstr "Mando a distancia" msgid "Watch TV" msgstr "Ver TV" msgid "Commands" msgstr "Órdenes" msgid "Search" msgstr "Buscar" msgid "Authorization Required" msgstr "Autorización requerida" msgid "This server could not verify that you are authorized to access the document requested. Either you supplied the wrong credentials (e.g. bad password), or your browser doesn't understand how to supply the credentials required." msgstr "" "Este servidor no pudo verificar, tú permiso de acceso al documento requerido.
\n" "Posiblemente por entregar datos incorrectos (nombre del usuario o contraseña p.e.) o por que tú navegador no soporta la forma de acceso." msgid "VPS" msgstr "VPS" msgid "close" msgstr "cerrar" msgid "view" msgstr "cambiar" msgid "search" msgstr "repeticiones" msgid "edit" msgstr "Modificar" msgid "Length" msgstr "" msgid "Video tracks:" msgstr "Pistas de vídeo:" msgid "Audio tracks:" msgstr "Pistas de audio:" msgid "Subtitles:" msgstr "Subtítulos:" msgid "Video tracks" msgstr "Pistas de vídeo:" msgid "Audio tracks" msgstr "Pistas de audio:" msgid "TV select" msgstr "cambiar canal" msgid "Stream" msgstr "Flujo" msgid "Channel group:" msgstr "Grupo de emisoras:" msgid "Go!" msgstr "¡Venga!" msgid "Search for other show times" msgstr "Buscar repeticiones" msgid "No Information" msgstr "No hay información" msgid "No EPG information available" msgstr "No hay información de la EPG" msgid "Playing Today" msgstr "Emisiones de hoy" msgid "starting at" msgstr "empezando a la/s" msgid "What's on:" msgstr "Se puede ver:" msgid "at" msgstr " a la/s:" msgid "now" msgstr "ahora" msgid "to" msgstr "hasta" msgid "Duration:" msgstr "Duración:" msgid "min" msgstr "min" msgid "at:" msgstr " a la/s:" msgid "You need JavaScript to use the timeline!" msgstr "¡Se necesita JavaScript para usar la barra de tiempo!" msgid "Rename Recording" msgstr "Renombrar grabación" msgid "Original Name of Recording:" msgstr "Título actual de la grabación:" msgid "New Name of Recording:" msgstr "Título nuevo de la grabación:" msgid "Subtitle:" msgstr "Subtítulo:" msgid "Rename" msgstr "Renombrar" msgid "Total:" msgstr "Espacio en el disco:" msgid "h" msgstr "h." msgid "Free:" msgstr "Espacio disponible:" msgid "Date" msgstr "Fecha" msgid "Total" msgstr "en total" msgid "New" msgstr "nueva" msgid "Play" msgstr "Reproducir" msgid "Cut" msgstr "Cortar" msgid "Delete recording?" msgstr "¿Borrar grabación?" msgid "Refresh" msgstr "Actualizar" msgid "Commands:" msgstr "Órdenes:" msgid "Really run this command?" msgstr "¿Ejecutar la orden de verdad?" msgid "stream all recordings" msgstr "" msgid "Delete Selected Recordings" msgstr "Borrar grabaciones elegidas" msgid "Delete all selected recordings?" msgstr "¿Estas seguro de que deseas borrar las grabaciones elegidas?" msgid "No recordings available" msgstr "No hay grabaciones." msgid "Transponder:" msgstr "Transpondedor" msgid "CA-System:" msgstr "Sistema CA:" msgid "New Timer" msgstr "Añadir programación" msgid "Edit timer status?" msgstr "¿Cambiar estado de la programación?" msgid "This timer is inactive!" msgstr "¡Esta programación está inactiva!" msgid "This timer is impossible!" msgstr "¡Esta programación es imposible!" msgid "No more timers on other transponders possible!" msgstr "¡No se pueden añadir más programaciones!" msgid "Timer OK." msgstr "Esta programación es válida." msgid "Auto" msgstr "Auto" msgid "activate" msgstr "Activar" msgid "inactivate" msgstr "Desactivar" msgid "selected timers" msgstr "programaciones elegidas" msgid "Delete Selected Timers" msgstr "Borrar programaciones elegidas" msgid "No timers defined!" msgstr "¡No hay programaciones!" msgid "Create New Timer" msgstr "Añadir programación" msgid "Buffer:" msgstr "Almacenador intermediario:" msgid "Use VPS:" msgstr "Utiliza VPS:" msgid "readonly" msgstr "sólo lectura" msgid "Timer has been set by AutoTimer pattern:" msgstr "Programación por cumplir ajustes de la autoprogramación:" msgid "TV" msgstr "TV" msgid "Interval:" msgstr "Intervalo:" msgid "sec." msgstr "seg" msgid "G" msgstr "C" msgid "Grab the picture!" msgstr "¡Captura la imagen!" msgid "Size:" msgstr "Dimensiones:" msgid "Open in separate window" msgstr "Abrir en una ventana separada" msgid "VDR Commands" msgstr "Órdenes de VDR" msgid "Export channels as playlist:" msgstr "Exportar los canales como lista de" msgid "Number of lines to show:" msgstr "Cantidad de líneas a mostrar:" msgid "unlimited" msgstr "sin límites" msgid "SVDRP commands:" msgstr "Órdenes de SVDRP:" msgid "Commands defined in commands.conf:" msgstr "Órdenes definidas en commands.conf:" msgid "Output" msgstr "Salida" msgid "What's your VDR hostname (e.g video.intra.net)?" msgstr "¿Cuál es el nombre del sitio del VDR (p.e. video.intra.net)?" msgid "On which port does VDR listen to SVDRP queries?" msgstr "¿Por qué puerto está escuchando VDR para peticiones de SVDRP?" msgid "On which address should VDRAdmin-AM listen (0.0.0.0 for any)?" msgstr "¿En qué dirección debe VDRAdmin-AM escuchar (0.0.0.0 para todas)?" msgid "On which port should VDRAdmin-AM listen?" msgstr "¿Por qué puerto debe VDRAdmin-AM esperar órdenes?" msgid "Username?" msgstr "¿Nombre del usuario?" msgid "Password?" msgstr "¿Contraseña?" msgid "Where are your recordings stored?" msgstr "Introduce la ruta de las grabaciones:" msgid "Where are your VDR's configuration files located?" msgstr "Introduce la ruta de los archivos de configuración:" msgid "Config file written successfully." msgstr "¡El archivo de configuración se ha escrito con éxito!" #, perl-format msgid "%s %s started with pid %d." msgstr "%s %s se ha iniciado con pid %d." msgid "Not found" msgstr "No encontrado" msgid "The requested URL was not found on this server!" msgstr "¡No se ha encontrado la URL requerida en este servidor!" msgid "Forbidden" msgstr "Prohibido" msgid "You don't have permission to access this function!" msgstr "¡No tienes permiso para esta función!" msgid "All channels" msgstr "Todas las emisoras" msgid "Selected channels" msgstr "Emisoras seleccionadas" msgid "TV channels" msgstr "Emisoras de TV" msgid "Radio channels" msgstr "Emisoras de radio" #, perl-format msgid "Access to file \"%s\" denied!" msgstr "¡Acceso al archivo \"%s\" denegado!" #, perl-format msgid "The URL \"%s\" was not found on this server!" msgstr "¡No encontrado la URL %s en el servidor!" msgid "Your favorites" msgstr "Tus favoritos" msgid "Search results" msgstr "Resultados de búsqueda" msgid "Default" msgstr "Por defecto" msgid "--- no timer ---" msgstr "--- sin programación ---" msgid "unknown" msgstr "desconocido" msgid "none" msgstr "nada" #, perl-format msgid "Can't open file \"%s\"!" msgstr "¡No se pudo abrir el archivo \"%s\" !" #, perl-format msgid "Can't connect to VDR at %s:%s: %s

Please check if VDR is running and if VDR's svdrphosts.conf is configured correctly." msgstr "No se puede conectar a VDR a %s:%s: %s

Compruebe si VDR está en marcha y su svdrhosts.conf bien configurado." #, perl-format msgid "Error while sending command to VDR at %s" msgstr "Error mientras mandó la orden a %s " msgid "Internal error:" msgstr "Error interno:" msgid "Lookup movie in the Internet-Movie-Database (IMDb)" msgstr "Buscar la película en la base de datos de películas en Internet (IMDb)" msgid "Can't find EPG entry!" msgstr "¡No se encuentra el registro en la EPG!" msgid "Playing Tomorrow" msgstr "Programas mañana" #, perl-format msgid "Playing on the %s" msgstr "Programas el %s" msgid "next" msgstr "después" msgid "What's on after" msgstr "Se puede ver después:" msgid "What's on at" msgstr "Se puede ver a la/s:" msgid "Suitable matches for:" msgstr "Coincidencias encontradas para:" msgid "short view" msgstr "Vista rápida" msgid "long view" msgstr "Vista detallada" msgid "Schedule" msgstr "Vista general" #, perl-format msgid "Can't write configuration file %s! Reason: %s" msgstr "¡No se puede escribir el archivo de configuración %s! Razón: %s" #, perl-format msgid "Configuration file %s not writable! Configuration won't be saved!" msgstr "¡El archivo de configuración %s no se puede escribir! ¡La configuración no se guardará!" msgid "Timers" msgstr "Programaciones" msgid "System default" msgstr "Predefinido del sistema" vdradmin-am-3.6.13/po/fi.po000066400000000000000000001570171443716113400153760ustar00rootroot00000000000000# Copyright (C) Andreas Mair # This file is distributed under the same license as the VDRAdmin-AM package. # # Rolf Ahrenberg, 2007 # Ville Skyttä, 2007-2011 # msgid "" msgstr "" "Project-Id-Version: VDRAdmin-AM-3.6.2\n" "Report-Msgid-Bugs-To: Andreas Mair \n" "POT-Creation-Date: 2012-07-09 12:23+0200\n" "PO-Revision-Date: 2012-08-18 10:31+0200\n" "Last-Translator: Ville Skyttä \n" "Language-Team: Finnish \n" "Language: fi\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" msgid "About" msgstr "Tietoja" msgid "License" msgstr "Lisenssi" msgid "Authors" msgstr "Tekijät" msgid "Current author (VDRAdmin-AM branch):" msgstr "Nykyinen tekijä (VDRAdmin-AM -haara):" msgid "Original author (VDRAdmin):" msgstr "Alkuperäinen tekijä (VDRAdmin):" msgid "Translation Team" msgstr "Lokalisointi" msgid "English:" msgstr "Englanti:" msgid "German:" msgstr "Saksa:" msgid "French:" msgstr "Ranska:" msgid "At the moment unmaintained, former translations by:" msgstr "Ei ylläpidetty - aiemmat lokalisoinnit:" msgid "Spanish:" msgstr "Espanja:" msgid "Finnish:" msgstr "Suomi:" msgid "Dutch:" msgstr "Hollanti:" msgid "Russian:" msgstr "Venäjä:" msgid "Czech:" msgstr "Tsekki:" msgid "Italian:" msgstr "Italia:" msgid "Hungarian:" msgstr "Unkari:" msgid "Information" msgstr "Lisätietoja" msgid "VDRAdmin-AM version:" msgstr "VDRAdmin-AM:n versio:" msgid "VDR version:" msgstr "VDR:n versio:" msgid "Supported features in VDR:" msgstr "VDR:n tuetut ominaisuudet:" msgid "EPGSearch" msgstr "Hakuajastimet" msgid "EPGSearch Plugin" msgstr "EPGSearch-laajennos" msgid "LiveTV Streaming" msgstr "Live-kuvan suoratoisto" msgid "Streamdev Plugin" msgstr "Streamdev-laajennos" msgid "Xineliboutput Plugin" msgstr "Xineliboutput-laajennos" msgid "Rename Recordings (Liemikuutio Patch)" msgstr "Tallenteiden uudelleennimeäminen (Liemikuutio-kokoelma)" msgid "Getting Help and Reporting Bugs" msgstr "Avunsaanti ja virheiden raportointi" msgid "If you need help please first try to use the online help you'll find on some pages. You can access it by clicking \"\"." msgstr "Saat opasteen näytille painamalla \"\" -kuvaketta." msgid "If this doesn't provide the information you need you can try to get help at VDR-Portal if you understand German language. Please use the announcement thread if possible, search for:" msgstr "Vaihtoehtoisesti voit etsiä apua saksankieliseltä VDR-Portal -foorumilta, missä ensisijaisesti kannattaa selata VDRAdminin julkistussäie läpi: " msgid "If you think you have found a bug please check that it's a new one and report it in the VDRAdmin-AM BugTracking system." msgstr "Löydettyäsi ohjelmistovirheen tarkista, ettei sitä ole jo raportoitu aiemmin ja raportoi se VDRAdmin-AM BugTracking -järjestelmään." msgid "AutoTimer" msgstr "Hakuajastimet" msgid "Priority:" msgstr "Prioriteetti:" msgid "Lifetime:" msgstr "Elinaika:" msgid "New AutoTimer" msgstr "Uusi hakuajastin" msgid "Help" msgstr "Opaste" msgid "Active" msgstr "Aktiivinen" msgid "Channel" msgstr "Kanava" msgid "Start" msgstr "Aloitus" msgid "Stop" msgstr "Lopetus" msgid "Name" msgstr "Nimi" msgid "Select all/none" msgstr "Valitse kaikki/ei yhtään" msgid "Yes" msgstr "Kyllä" msgid "No" msgstr "Ei" msgid "Edit" msgstr "Muokkaa" msgid "Delete timer?" msgstr "Poistetaanko ajastin?" msgid "Delete" msgstr "Poista" msgid "Force Update" msgstr "Päivitä" msgid "Delete Selected AutoTimers" msgstr "Poista valitut hakuajastimet" msgid "Delete all selected timers?" msgstr "Poistetaanko valitut ajastimet?" msgid "No AutoTimers defined!" msgstr "Hakuajastimia ei ole määritelty!" msgid "Add New AutoTimer" msgstr "Lisää uusi hakuajastin" msgid "Edit AutoTimer" msgstr "Muokkaa hakuajastinta" msgid "AutoTimer Active:" msgstr "Aktiivinen:" msgid "oneshot" msgstr "Kerran" msgid "Search Patterns:" msgstr "Hakuehdot:" msgid "Search in:" msgstr "Hakukentät:" msgid "Title" msgstr "Otsikko" msgid "Subtitle" msgstr "Lyhyt kuvaus" msgid "Description" msgstr "Kuvaus" msgid "Search only on these days:" msgstr "Etsi valittuina päivinä:" msgid "Monday" msgstr "Maanantai" msgid "Tuesday" msgstr "Tiistai" msgid "Wednesday" msgstr "Keskiviikko" msgid "Thursday" msgstr "Torstai" msgid "Friday" msgstr "Perjantai" msgid "Saturday" msgstr "Lauantai" msgid "Sunday" msgstr "Sunnuntai" msgid "Channel:" msgstr "Kanava:" msgid "all" msgstr "kaikki" msgid "Starts After:" msgstr "Alkaa jälkeen:" msgid "o'clock" msgstr " " msgid "Ends Before:" msgstr "Loppuu ennen:" msgid "Override Start/Stop Margins:" msgstr "Käytä yksilöllisiä aloitus- ja lopetusmarginaaleja" msgid "Time Margin at Start:" msgstr "Aloitusmarginaali:" msgid "minutes" msgstr "minuuttia" msgid "Time Margin at Stop:" msgstr "Lopetusmarginaali:" msgid "Episode:" msgstr "Sarjatallennus:" msgid "Remember programmed timers:" msgstr "Muista ohjelmoidut ajastimet:" msgid "Directory:" msgstr "Hakemisto:" msgid "Save" msgstr "Tallenna" msgid "Test" msgstr "Hae" msgid "Cancel" msgstr "Peru" msgid "Broadcasted" msgstr "Lähetysaika" msgid "Stored in" msgstr "Tallennehakemisto" msgid "No matches found!" msgstr "Ei löydy!" msgid "Configuration" msgstr "Asetukset" msgid "General Settings" msgstr "Yleiset" msgid "Template:" msgstr "Mallipohja:" msgid "Skin:" msgstr "Ulkoasu:" msgid "Login Page:" msgstr "Aloitussivu:" msgid "Number of channels to use:" msgstr "Kanavien lukumäärä:" msgid "Local net (no login required):" msgstr "Käyttäjätunnukseton osoiteavaruus:" msgid "Language:" msgstr "Kieli:" msgid "Save settings on exit:" msgstr "Tallenna asetukset suljettaessa:" msgid "VDR" msgstr "VDR" msgid "Number of DVB cards:" msgstr "DVB-korttien lukumäärä:" msgid "Path to recordings:" msgstr "VDR-tallenteiden polku:" msgid "Path to configuration files:" msgstr "Asetustiedostojen polku:" msgid "Path to EPG images:" msgstr "Ohjelmaoppaan kuvapolku:" msgid "Identification" msgstr "Käyttäjätunnistus" msgid "Username:" msgstr "Käyttäjätunnus:" msgid "Password:" msgstr "Salasana:" msgid "Guest Account:" msgstr "Sallitaanko vierailija:" msgid "Guest Username:" msgstr "Vierailijan käyttäjätunnus:" msgid "Guest Password:" msgstr "Vierailijan salasana:" msgid "Timeline" msgstr "Aikajana" msgid "Hours:" msgstr "Pituus tunteina:" msgid "Times:" msgstr "Ajankohdat:" msgid "Also used for other EPG views!" msgstr "Käytetään myös muihin ohjelmaoppaan näkymiin!" msgid "Tooltips:" msgstr "Lisätietolaatikot:" msgid "Electronic Program Guide (EPG)" msgstr "Ohjelmaopas" msgid "Day begins at:" msgstr "Päivä alkaa:" msgid "Show Subtitle:" msgstr "Näytä jakson nimi:" msgid "Show Summary:" msgstr "Näytä kuvaus:" msgid "Active:" msgstr "Käytössä:" msgid "Send email after programming timer:" msgstr "Lähetä sähköpostia ohjelmoidusta ajastimesta:" msgid "Send email as:" msgstr "Lähetä sähköposti nimellä:" msgid "Send email to:" msgstr "Lähetä sähköposti osoitteeseen:" msgid "Mail server:" msgstr "Sähköpostipalvelin:" msgid "SMTPAuth user:" msgstr "SMTP-käyttäjätunnus:" msgid "SMTPAuth password:" msgstr "SMTP-salasana:" msgid "Track schedule changes by:" msgstr "Ohjelmamuutosten seurantaperuste:" msgid "Broadcast time" msgstr "Lähetysaika" msgid "Event id" msgstr "Ohjelmatunniste" msgid "Timer" msgstr "Ajastimet" msgid "Tooltips in timeline:" msgstr "Lisätietolaatikot \"Aikajana\"-sivulla:" msgid "Tooltips in list:" msgstr "Lisätietolaatikot \"Ajastimet\"-sivulla:" msgid "Streaming" msgstr "Suoratoisto" msgid "Live Streaming:" msgstr "Live-kuvan suoratoisto:" msgid "HTTP Port of Streamdev (also possible 3000/ts):" msgstr "Streamdev-laajennoksen HTTP-portti (esim. 3000/ts):" msgid "HTTP Port of Xineliboutput (e.g. 37890):" msgstr "Xineliboutput-laajennoksen HTTP-portti (esim. 37890):" msgid "Recordings Streaming:" msgstr "Tallenteiden suoratoisto:" msgid "Path to VDR Recordings on your workstation:" msgstr "VDR-tallenteiden polku työasemallasi:" msgid "MIME type for live streaming:" msgstr "Live-kuvan suoratoiston MIME-tyyppi:" msgid "Suffix for live streaming:" msgstr "Live-kuvan suoratoiston tiedostopääte:" msgid "MIME type for recordings streaming:" msgstr "Tallenteiden suoratoiston MIME-tyyppi:" msgid "Suffix for recordings streaming:" msgstr "Tallenteiden suoratoiston tiedostopääte:" msgid "Bandwidth of Streams:" msgstr "Kaistanleveys:" msgid "External Search" msgstr "Ulkoinen haku" msgid "URL:" msgstr "URL:" msgid "Title:" msgstr "Otsikko:" msgid "User-defined search:" msgstr "Käyttäjän määrittelemä haku:" msgid "Expert" msgstr "Ekspertti" msgid "Update EPG data in background:" msgstr "Päivitä ohjelmaopasta taustalla:" msgid "Update EPG every:" msgstr "Ohjelmaoppaan päivitysväli:" msgid "Channel Selections" msgstr "Kanavavalinnat" msgid "Show channels without EPG information:" msgstr "Näytä ohjelmaoppaattomat kanavat:" msgid "In \"AutoTimer\"?" msgstr "Käytä kanavavalintoja \"Hakuajastimet\"-sivulla" msgid "Apply" msgstr "Käytä" msgid "EPG Search Blacklists" msgstr "Hakuajastimien mustat listat" msgid "New Blacklist" msgstr "Uusi musta lista" msgid "Search pattern" msgstr "Hakuehto" msgid "From" msgstr "Aikaisintaan" msgid "To" msgstr "Viimeistään" msgid "Delete blacklist?" msgstr "Poistetaanko musta lista?" msgid "Delete Selected Blacklists" msgstr "Poista valitut mustat listat" msgid "Delete all selected blacklists?" msgstr "Poistetaanko kaikki valitut mustat listat?" msgid "EPG search" msgstr "Hae ohjelmaoppaasta" msgid "EPG Search" msgstr "Hakuajastimet" msgid "Use template" msgstr "Käytä mallipohjaa" msgid "New Search" msgstr "Uusi haku" msgid "Edit Template" msgstr "Muokkaa mallipohjaa" msgid "Settings" msgstr "Asetukset" msgid "Action" msgstr "Toiminto" msgid "Find" msgstr "Etsi" msgid "Show Favorites" msgstr "Näytä suosikit" msgid "Delete Selected Searches" msgstr "Poista valitut haut" msgid "Delete all selected searches?" msgstr "Poistetaanko kaikki valitut haut?" msgid "Execute Selected Searches" msgstr "Suorita valitut haut" msgid "Duration" msgstr "Kesto" msgid "More Information" msgstr "Lisätietoja" msgid "Channels" msgstr "Kanavat" msgid "Record" msgstr "Tallenna" msgid "Add New Blacklist" msgstr "Lisää uusi musta lista" msgid "Edit Blacklist" msgstr "Muokkaa mustaa listaa" msgid "Add New Template" msgstr "Lisää uusi mallipohja" msgid "Add New Search" msgstr "Lisää uusi hakuajastin" msgid "Edit Search" msgstr "Muokkaa hakuajastinta" msgid "Small search pattern.\\nDo you really want to use it?" msgstr "Hakuehdot ovat hyvin suppeat.\\nHaetaanko silti?" msgid "You didn't select at least one of\\ntitle, subtitle or description.\\nDo you really want to use this search?" msgstr "Et valinnut otsikkoa, lyhyttä tai\\npitkää kuvausta hakuehdoksi.\\nHaluatko silti käyttää hakua?" msgid "Hide results" msgstr "Piilota hakutulokset" msgid "Name:" msgstr "Nimi:" msgid "Search Term:" msgstr "Hakutermi:" msgid "Search Mode:" msgstr "Hakutapa:" msgid "phrase" msgstr "fraasi" msgid "all words" msgstr "kaikki sanat" msgid "at least one word" msgstr "yksi sana" msgid "match exactly" msgstr "täsmällinen" msgid "regular expression" msgstr "säännöllinen lauseke" msgid "fuzzy" msgstr "sumea" msgid "Tolerance for \"fuzzy\":" msgstr "Toleranssi:" msgid "Match Case:" msgstr "Huomioi kirjainkoko:" msgid "Use extended EPG info:" msgstr "Käytä laajennettua ohjelmaopasta:" msgid "Ignore missing categories?" msgstr "Jätetäänkö puuttuvat kategoriat huomioimatta?" msgid "Use Channel:" msgstr "Käytä kanavaa:" msgid "no" msgstr "ei" msgid "interval" msgstr "kyllä" msgid "channel group" msgstr "kanavaryhmä" msgid "only FTA" msgstr "vapaat" msgid "Range:" msgstr "Kanavat:" msgid "Channel Group:" msgstr "Kanavaryhmä:" msgid "Use Time:" msgstr "Käytä aloitusaikaa:" msgid "Start After:" msgstr "Aikaisintaan:" msgid "Start Before:" msgstr "Viimeistään:" msgid "Use Duration:" msgstr "Käytä kestoaikaa:" msgid "Min. Duration:" msgstr "Kestoaika vähintään:" msgid "hh:mm" msgstr "hh:mm" msgid "Max. Duration:" msgstr "Kestoaika enintään:" msgid "Use Day of Week:" msgstr "Käytä viikonpäivää:" msgid "Use Blacklists:" msgstr "Käytä mustia listoja:" msgid "selection" msgstr "valitut" msgid "Use in Favorites Menu:" msgstr "Käytä suosikkina:" msgid "Use as Search Timer:" msgstr "Käytä hakuajastimena:" msgid "yes" msgstr "Kyllä" msgid "user-defined" msgstr "Määritellyt" msgid "record" msgstr "Tallenna" msgid "announce by OSD" msgstr "muistutus kuvaruutunäytölle" msgid "switch only" msgstr "Kanavanvaihto" msgid "announce and switch" msgstr "muistutus ja kanavanvaihto" msgid "announce by mail" msgstr "muistutus sähköpostitse" msgid "First day:" msgstr "Aloituspäivä:" msgid "Last day:" msgstr "Lopetuspäivä:" msgid "Auto delete:" msgstr "Poista automaattisesti:" msgid "count recordings" msgstr "Lukumäärän mukaan" msgid "count days" msgstr "Päivien mukaan" msgid "After ... recordings:" msgstr "... tallenteen jälkeen:" msgid "After ... days after first recording:" msgstr "... päivän jälkeen ensimmäisestä" msgid "Settings for action \"record\"" msgstr "Tallennustoiminnon asetukset" msgid "Series Recording:" msgstr "Sarjatallennus:" msgid "Delete Recordings After ... Days:" msgstr "Poista tallenteet ... päivän jälkeen:" msgid "Keep ... Recordings:" msgstr "Säilytä ... tallennetta:" msgid "Pause, when ... recordings exist:" msgstr "Keskeytä ... tallenteen jälkeen:" msgid "Avoid Repeats:" msgstr "Estä uusinnat:" msgid "Allowed Repeats:" msgstr "Sallittujen uusintojen lukumäärä:" msgid "Only Repeats Within ... Days:" msgstr "Vain uusinnat ... päivän sisällä:" msgid "Compare:" msgstr "Vertaa hakukenttiä:" msgid "Minimal match of description in %:" msgstr "Vaadittava kuvauksen yhdenmukaisuus [%]:" msgid "VPS:" msgstr "VPS-toiminto:" msgid "Settings for action \"switch only\"" msgstr "Kanavanvaihdon asetukset" msgid "Switch ... Minutes Before Start:" msgstr "Vaihda ... minuuttia ennen alkua:" msgid "Unmute sound:" msgstr "Ota mykistys pois päältä:" msgid "Settings for action \"announce and switch\"" msgstr "Asetukset muistutukselle ja kanavanvaihdolle:" msgid "Ask ... Minutes Before Start:" msgstr "Kysy ... minuuttia ennen alkua:" msgid "Delete template" msgstr "Poista mallipohja" msgid "Delete this template?" msgstr "Poistetaanko mallipohja?" msgid "Save as template" msgstr "Tallenna mallipohjaksi" msgid "Run" msgstr "Suorita" msgid "Error!" msgstr "Virhe!" msgid "

Here you will find a listing of automatic timers (AutoTimer) known to VDRAdmin-AM.

The list shows some information on AutoTimers. You can change the list's sorting by clicking the columns heading.

For each AutoTimer you have the following options:

Set its state
By clicking on \"Yes\" or \"No\" in the \"Active\" column to toggle the activity.
Quickly view its priority and lifetime
By pointing the mouse cursor to the AutoTimer's title.
Edit the AutoTimer
You can edit an AutoTimer by clicking \"edit\".
Delete the AutoTimer
To delete an AutoTimer you click \"delete\".

Each AutoTimer's state is indicated by differently coloured images:
\"on\" AutoTimer is OK and will automatically program matching broadcasts.
\"inactive\" AutoTimer is not active.

In addition to these functions you can add a new AutoTimer by clicking at the top and you can delete a number of AutoTimers at once by checking the box in the last column of those timers and clicking .

Click to force VDRAdmin-AM to reconnect to VDR, fetch the current EPG and check for matching AutoTimers.

" msgstr "" msgid "

Here you can edit an automatic timer's (AutoTimer) settings.

AutoTimer is a key feature of VDRAdmin-AM. An AutoTimer consists of one or more search terms and some other settings, that are looked for regularly in the Electronic Program Guide (EPG). On match AutoTimer adds a timer in VDR automatically for that broadcast. That's very comfortable for irregularly broadcasted series or movies you don't want to miss.

" msgstr "" msgid "Activate or deactivate this AutoTimer. Deactivated AutoTimers are still stored in the AutoTimer list so that they can be activated again, but they do not record anything meanwhile. Above that you can set this to \"oneshot\" so this AutoTimer only programs the (one!) next matching broadcast." msgstr "Aktivoi tai deaktivoi tämä hakuajastin. Deaktivoidut hakuajastimet eivät tallenna mitään, mutta ne näytetään ajastinlistauksessa josta ne voidaan aktivoida uudelleen. Voit myös määrittää hakuajastimen toimimaan vain kerran, jolloin se ajastaa vain (yhden) seuraavan hakuun osuvan ohjelman tallennuksen." msgid "Choosing the right search items decides whether only the wanted broadcasts or broadcasts having similar names or even nothing gets recorded.
Case doesn't matter, \"X-Files\" matches anything \"x-files\" will match. You can set multiple search items by separating them with spaces. Broadcasts will match only if they match all configured search items.
You'd better only use letters and numbers for search items, as the EPG often miss colons, brackets and other characters.
Experts can also use regular expressions, but you have to get needed information from the VDRAdmin-AM sources (undocumented feature).

You can exclude broadcasts so that they don't get recorded even if they would match an AutoTimer. Therefore you have to enter that titles into the file vdradmind.bl, one event a line. This file must be located in your VDRAdmin-AM's configuration folder. If this string is found either in the EPG's title or in title~subtitle, this event will not be programmed by AutoTimer. So you can disable complete episodes (for example when using \"Enterprise\" as blacklist string) or only one episode (when using \"Enterprise~Azati Prime\" as blacklist string)." msgstr "" msgid "Here you can define the EPG sections where VDRAdmin-AM should look for the search pattern." msgstr "" msgid "Use these checkboxes to limit searching for matching broadcasts to a set of weekdays." msgstr "" msgid "The channel to look for matching broadcasts or \"all\" to search in all known or wanted channels. You can define the wanted channels for AutoTimer in \"Configuration\"." msgstr "" msgid "A broadcast must start after the time entered here to match. The first text field is for \"hour\", the second for \"minute\"." msgstr "Ohjelman pitää alkaa tähän syötetyn ajan jälkeen osuakseen hakuehtoon. Ensimmäiseen kenttään syötetään tunnit, jälkimmäiseen minuutit." msgid "A broadcast must end before the time entered here to match. The first text field is for \"hour\", the second for \"minute\"." msgstr "Ohjelman pitää loppua ennen tähän syötettyä aikaa osuakseen hakuehtoon. Ensimmäiseen kenttään syötetään tunnit, jälkimmäiseen minuutit." msgid "Set this option to \"yes\" if all timers programed by this AutoTimer should have individual start/stop margins and enter the values in the next two text boxes." msgstr "" msgid "The number of minutes VDRAdmin-AM subtracts from the broadcast's start time found in the EPG." msgstr "Minuuttimäärä jonka verran ennen ohjelmaoppaan tietojen ohjelman alkuaikaa VDRAdmin-AM asettaa tallennuksen alkamaan." msgid "The number of minutes VDRAdmin-AM adds to the broadcast's stop time found in the EPG." msgstr "Minuuttimäärä jonka verran ohjelmaoppaan tietojen ohjelman loppuajan jälkeen VDRAdmin-AM asettaa tallennuksen loppumaan." msgid "An integer in the range 0...99, defining the priority of this timer and of recordings created by this timer. 0 represents the lowest value, 99 the highest. The priority is used to decide which timer shall be started in case there are two or more timers with the exact same start time. The first timer in the list with the highest priority will be used.

This value is also stored with the recording and is later used to decide which recording to remove from disk in order to free space for a new recording. If the disk runs full and a new recording needs more space, an existing recording with the lowest priority (and which has exceeded its guaranteed lifetime) will be removed.

If all available DVB cards are currently occupied, a timer with a higher priority will interrupt the timer with the lowest priority in order to start recording." msgstr "Kokonaisluku väliltä 0...99 joka määrittää tämän ajastimen ja sen tekemien tallennusten prioriteetin. 0 on alin prioriteetti, 99 ylin. Prioriteettiarvoa käytetään päättämään mikä ajastettu tallennus aloitetaan mikäli asetettuna on kaksi tai useampia samaan aikaan alkamaan asetettuja ajastimia. Valinta kohdistuu ensimmäiseen suurimmalla prioriteetilla olevista ajastimista.

Prioriteettiarvo säilytetään myös tallenteen mukana, ja sitä käytetään myöhemmin päättämään mikä tallenne poistetaan mikäli uutta varten pitää saada lisää levytilaa. Mikäli levy täyttyy ja uusi tallenne tarvitsee lisää tilaa, pienimmällä prioriteetilla merkitty tallenne (joka on ylittänyt taatun elinaikansa) poistetaan.

Mikäli kaikki DVB-kortit ovat käytössä, korkeamman prioriteetin ajastin keskeyttää tarvittaessa käynnissä olevan alimman prioriteetin tallennuksen." msgid "The guaranteed lifetime (in days) of a recording created by this timer. 0 means that this recording may be automatically deleted at any time by a new recording with higher priority. 99 means that this recording will never be automatically deleted. Any number in the range 1...98 means that this recording may not be automatically deleted in favour of a new recording, until the given number of days since the start time of the recording has passed by." msgstr "Tämän ajastimen tekemien tallenteiden taattu elinaika (päivinä). 0 tarkoittaa että tallenne saatetaan poistaa automaattisesti milloin tahansa korkeamman prioriteetin ajastimen tarvitessa lisää levytilaa. 99 tarkoittaa että tallennetta ei poisteta automaattisesti. Numero väliltä 1...98 tarkoittaa päivien määrää, jonka pitää olla kulunut ajastimen alkuajankohdasta ennen kuin tallenne saatetaan poistaa automaattisesti uuden tallenteen tarvitessa levytilaa." msgid "Check this box if you want VDRAdmin-AM to append the broadcast's EPG subtitle to the recording's file name." msgstr "Valitse mikäli haluat VDRAdmin-AM:n lisäävän ohjelman jakson nimen tallenteen tiedostonimeen." msgid "If you enable this VDRAdmin-AM will track timers it has already programmed automatically. This is useful if want to deactivate or delete timers that have been programmed automatically in the timers listing." msgstr "" msgid "The directory this AutoTimer will place the recordings in. If the name shall contain subdirectories, these have to be delimited by '~' (since the '/' character may be part of a regular programme name).
VDRAdmin-AM will append the matching broadcast's title and subtitle (if the \"Episode\" checkbox is marked) to the directory given here.

You can also use the following keywords that are replaced in the final file name by the values supplied by for example tvm2vdr:
  • %Title% - will become the title of the event.
  • %Subtitle% - will become the subtitle of the event.
  • %Director% - will become the director of the event.
  • %Date% - will become the date of the recording.
  • %Category% - will become the category of the event (Spielfilm/Serie/...).
  • %Genre% - will become the genre of the event (Drama/Krimi/..).
  • %Year% - will become the year of production.
  • %Country% - will become the country of production.
  • %Originaltitle% - will become the original title of the event.
  • %FSK% - will become the FSK from the event.
  • %Episode% - will become the episode's title of the event.
  • %Rating% - will become the rating of the event from the EPG provider.

Note:

If you use the above keywords it's in your own responsibility to supply the complete file name for the recordings! VDRAdmin-AM will not append anything to the resulting string." msgstr "" msgid "

Here you can change general settings and base settings for timers, AutoTimers, channel selection and streaming parameters.

" msgstr "" msgid "The skin you want to use." msgstr "Haluamasi käyttöliittymän ulkoasu." msgid "The page you want to see at first connect to VDRAdmin-AM." msgstr "" msgid "VDRAdmin-AM will load the given number of channels from VDR and present only those in any fields where channels can be selected. This also limits the EPG information VDRAdmin-AM will read so that you can use this to reduce VDRAdmin-AM's memory consumption and increase its performance. 0 turns this feature off and VDRAdmin-AM will use all available channels." msgstr "" msgid "Here you can specify subnets from which access to VDRAdmin-AM does not require logging in. For example: \"192.168.0.0/24\" will include any IP starting with \"192.168.0.\", \"192.168.0.123/32\" will only match \"192.168.0.123\". Multiple subnets can be specified by separating them with spaces or commas." msgstr "Tässä määritellyistä aliverkoista sallitaan sisäänkirjautumiset ilman käyttäjätunnusta ja salasanaa. Esimerkiksi \"192.168.0.0/24\" sallii mistä tahansa IP-osoitteesta joka alkaa \"192.168.0.\", \"192.168.0.123/32\" sallii vain IP-osoitteesta \"192.168.0.123\". Voit määritellä useampia aliverkkoja erottamalla ne välilyönneillä tai pilkuilla." msgid "Here you can set the localization VDRAdmin-AM should use." msgstr "" msgid "With this option the settings will be saved if VDRAdmin-AM exits. This will also save settings not available on the \"Configuration\" menu like interval and size in TV, sorting in the lists and current view in \"What's on now\"." msgstr "" msgid "Top" msgstr "Alkuun" msgid "The number of DVB cards VDR can access. Depending on this value VDRAdmin-AM will calculate critical timers in the Timer menu." msgstr "VDR:n käyttämien DVB-korttien lukumäärä. VDRAdmin-AM käyttää tätä lukua laskiessaan ajastimien toteutumisen mahdollisuutta Ajastimet-näkymässä." msgid "The path to VDR's recordings. It's used so that VDRAdmin-AM can locate the recordings when using Recordings Streaming and reccmds.conf in the Recordings menu." msgstr "Polku josta VDR:n tallenteet löytyvät. VDRAdmin-AM tarvitsee tätä polkua löytämään tallenteet tallenteiden suoratoistoa ja reccmds.conf:ia varten tallenteet-valikossa." msgid "The path where VDR's configuration files are located. If this directory contains the file reccmds.conf its content is shown in a selectbox in the Recordings menu." msgstr "Polku jossa VDR:n asetustiedostot sijaitsevat. Mikäli tämän polun osoittamassa hakemistossa on tiedosto reccmds.conf, sen sisältämät komennot näytetään alasvetovalikossa Tallenteet-näkymässä." msgid "The path where the EPG images are stored." msgstr "Polku josta ohjelmaopasnäkymän käyttämät kuvat löytyvät." msgid "The username for the main user, i.e. the user having the most privileges." msgstr "Pääkäyttäjän, ts. käyttäjän jolla on kaikki käyttöoikeudet, salasana." msgid "The main user's password." msgstr "Pääkäyttäjän salasana." msgid "If you want a user account having only limited privileges, this is for you. The guest user cannot modify anything, it's only allowed to view the EPG, timers, AutoTimers and recordings listings." msgstr "Jos haluat sallia rajoitetut käyttöoikeudet omaavan käyttäjän, tämä asetus on sinua varten. Vierailijakäyttäjän ei sallita muokkaavan mitään, vaan sillä on ainoastaan lukuoikeudet ohjelmaopas-, ajastin-, automaattiajastin- ja tallennenäkymiin." msgid "The username for the guest user." msgstr "Vierailijakäyttäjän käyttäjätunnus." msgid "The guest user's password." msgstr "Vierailijakäyttäjän salasana." msgid "The number of hours to show in the timeline." msgstr "Aikajanalla näytettävien tuntien lukumäärä." msgid "A comma separated list of times in hh:mm format that appear in the selectbox placed at the top." msgstr "Pilkulla erotettu lista ajoista hh:mm -muodossa jotka näytetään ylälaidan alasvetovalikossa." msgid "Here you can (de-)activate the tooltips." msgstr "" msgid "The time after which events are shown on a new day. For example setting 03:00 means that today's schedule will include any event starting before 03:00 tomorrow. Applies only to the 'Playing Today?' list." msgstr "Kellonaika jota edeltävät ohjelmat näytetään edellisen päivän tiedoissa. Esimerkiksi asetus 03:00 tarkoittaa että tämän päivän ohjelmistossa näytetään ohjelmat jotka alkavat ennen klo 03:00 huomenna. Vaikuttaa ainoastaan 'Tänään'-listaan." msgid "Show the 'Subtitle' text for each event. Not all broadcasters use this field." msgstr "" msgid "Show the 'Summary' text for each event." msgstr "" msgid "Activate or deactivate the AutoTimer function." msgstr "Aktivoi tai deaktivoi hakuajastintoiminto." msgid "VDRAdmin-AM will send an email whenever an event matches an AutoTimer and a timer has been programmed if you enable this feature." msgstr "Mikäli tämä ominaisuus on käytössä, VDRAdmin-AM lähettää sähköpostin aina kun automaattiajastinta vastaava ohjelma on löytynyt ja ajastettu." msgid "Here you set the sending email address of the generated email." msgstr "Sähköpostin lähettäjän osoite." msgid "The email address the email is sent to." msgstr "Sähköpostin vastaanottajan osoite." msgid "The outgoing mail server." msgstr "Sähköpostin lähetyspalvelimen osoite." msgid "If you need to authenticate yourself at the outgoing mail server, you have to supply the username and the password below. Leaving this field empty will disable SMTPAuth." msgstr "Mikäli sähköpostin lähetyspalvelin vaatii tunnistautumista, täytä SMTP-käyttäjätunnus ja -salasanakentät. Tämän kentän jättäminen tyhjäksi poistaa SMTP-tunnistautumisen käytöstä." msgid "The password for the SMTPAuth user." msgstr "SMTP-tunnistautumisessa käytetty salasana." msgid "Here you can (de-)activate the tooltips in the timeline." msgstr "" msgid "Here you can (de-)activate the tooltips in the list." msgstr "" msgid "Add summary to new timers:" msgstr "Lisää tallenteen kuvaus uusiin ajastimiin" msgid "If you don't want VDRAdmin-AM to add the summary taken from EPG to new timers you can switch it off here." msgstr "" msgid "Enable or disable live streaming using the streamdev plugin. You also have to set the correct HTTP Port for Streamdev below." msgstr "" msgid "Here you have to set the port number your VDR's streamdev server listens for connections. Additionally you can also provide the stream type you like to use." msgstr "" msgid "Enable or disable streaming of recordings.
Well actually this is no real \"streaming\", but you have to setup your workstation so that it can access VDR's recordings. You can use for example Samba or NFS for this. VDRAdmin-AM simply generates a playlist that contains all parts of the recording and sends this to your browser. If your browser and media player are configured correctly you will see the recording on your workstation's display." msgstr "" msgid "This is the path where your workstation can access VDR's recordings. This depends on your VDR and workstation setup, for example \"\\\\vdr\\videos\" or \"V:\\\" (on Windows) or \"/mnt/videos\" (on Linux)." msgstr "" msgid "The MIME type to send when using live streaming. Defaults to \"video/x-mpegurl\"." msgstr "Live-kuvan suoratoiston yhteydessä lähetettävä MIME-tyyppi, oletus \"video/x-mpegurl\"." msgid "The suffix to use for live streaming. Defaults to \"m3u\"." msgstr "Live-kuvan suoratoiston tiedostopääte, oletus \"m3u\"." msgid "The MIME type to send when using recordings streaming. Defaults to \"video/x-mpegurl\"." msgstr "Tallenteiden suoratoiston yhteydessä lähetettävä MIME-tyyppi, oletus \"video/x-mpegurl\"." msgid "The suffix to use for recordings streaming. Defaults to \"m3u\"." msgstr "Tallenteiden suoratoiston tiedostopääte, oletus \"m3u\"." msgid "

Here you can define two external searches that you can access in the EPG views. You simply have to find the required URL and where the search pattern has to be located. %TITLE% will be substituted by the broadcast's EPG title.

" msgstr "" msgid "Some examples:" msgstr "Esimerkkejä:" msgid "Please change the hostname to your local needs!" msgstr "" msgid "

This section is for experts only, i.e. you know what you are doing!

" msgstr "

Tämä osio on vain asiantuntijoille jotka tietävät mitä ovat tekemässä!

" msgid "If set to \"yes\" VDRAdmin-AM will periodically refresh its local EPG cache. Else the EPG will be refreshed if the user accesses any EPG view at the web interface and the timeout set at \"Update EPG every\" has been reached." msgstr "Mikäli kyllä, VDRAdmin-AM päivittää ohjelmaopasvälimuistiaan taustalla. Mikäli ei, ohjelmaoppaan tiedot päivitetään web-käyttöliittymän ohjelmaopasnäkymää avattaessa jos määritelty ohjelmaoppaan päivitysväli on kulunut edellisestä päivityksestä." msgid "The interval, the EPG data is refreshed from VDR and AutoTimer updates are performed (if AutoTimer feature is used)." msgstr "Aika jonka välein ohjelmaoppaan tiedot päivitetään VDR:stä ja hakuajastimien päivitykset tehdään (mikäli hakuajastintoiminto on käytössä)." msgid "

If you want to limit the number of channels used in some parts of VDRAdmin-AM, this is for you!

Use the radio buttons to activate or deactivate the wanted channels in the named menu.

To add channels to the list of wanted channels you have to select them in the left side selectbox and click . If you want to remove channels from the list of wanted channels you have to select them in the right side selectbox and click .

" msgstr "" msgid "Usually channels that don't have EPG information are hidden in all EPG views. If you don't want them to be hidden you have to set this option to \"yes\"." msgstr "" msgid "Edit Timer" msgstr "Muokkaa ajastinta" msgid "Edit EPG" msgstr "Muokkaa ohjelmatietoja" msgid "

Here you can edit the descriptive fields of an existing EPG entry.

" msgstr "

Tässä näkymässä voit muokata ohjelmaoppaan tietoja.

" msgid "Channel (readonly)" msgstr "Kanava (kirjoitussuojattu)" msgid "This is the channel of the EPG entry. It cannot be changed." msgstr "" msgid "Time (readonly)" msgstr "Aika (kirjoitussuojattu)" msgid "This is the start and end time of the entry. It cannot be changed." msgstr "" msgid "Change this string to give this EPG Entry a new title. It must consist of only one line of text." msgstr "" msgid "Change this string to give this EPG Entry a new subtitle. It must consist of only one line of text." msgstr "" msgid "Change the text in this field to edit the description of this entry. The text can consist of one or more lines." msgstr "" msgid "VPS (readonly)" msgstr "VPS (kirjoitussuojattu)" msgid "If available this field shows the vps time of the EPG entry. It cannot be changed." msgstr "" msgid "Video tracks (readonly)" msgstr "Kuvaraidat (kirjoitussuojattu)" msgid "If available this field shows the video track(s). It cannot be changed." msgstr "" msgid "Audio tracks (readonly)" msgstr "Ääniraidat (kirjoitussuojattu)" msgid "If available this field shows the audio track(s). It cannot be changed." msgstr "" msgid "No Help Available" msgstr "Ei opastetta" msgid "

No help available yet. For adding or changing text please contact amair.sob@googlemail.com.

" msgstr "

Valittua opastetta ei ole saatavilla. Jos haluat lisätä tai muokata opastetta, ota yhteyttä sähköpostitse: amair.sob@googlemail.com.

" msgid "Recordings" msgstr "Tallenteet" msgid "

Here you will find a listing of recordings known to VDR. The headline will also show you VDR's total and free disk space.

The listing showing you some information on the recordings. You can change the list's sorting by clicking the columns heading. Above the list you'll see the navigation path. If you want to view the contents of previous folders you'll have to click on its name in that path.

Each row contains this information:

Date
The date when the recording has been done. In case of folders this will show the number of recordings the folder contains.
Time
The time when the recording has been done. In case of folders this will show the number of new recordings the folder contains.
Name
The recording's or folder's name. Click it to show the recording's summary or descend into the folder.
Rename (\"edit\")
Rename a recording.

Note:

This only works if VDR has the MOVR or RENR SVDRP command which is not a core VDR feature but provided by the Liemikuutio patch set.
Delete (\"delete\")
Delete a recording.
Stream (\"stream\")
This column is only shown if you activated and configured Recordings Streaming in the Configuration menu. You can watch the recording at your workstation.

In addition to these functions you can delete a number of recordings at once by checking the box in the last but one column of those recordings and clicking .

If you've set the path the VDR's configuration files and have entries in VDR's reccmds.conf you can run those commands for the selected recording by selecting the wanted command in the select box locate next to Commands: and pressing the button.

Use to force reloading of VDR's recordings listing.

" msgstr "" msgid "

Here you will find a listing of timers known to VDR.

On top you will find a chart showing a day's timers graphically. This provides an quick overview on what's going on at the specified day and helps you in finding conflicting timers. Moving the mouse cursor above any timer box will display a tooltip containing the timer's title, priority, lifetime and duration.

Below the chart you'll find the timers list showing you some information on the timers. You can change the list's sorting by clicking the columns heading.

For each timer you have the following options:

Set its state
By clicking on \"Yes\", \"No\", \"VPS\" or \"Auto\" in the \"Active\" column.
Quickly view its priority and lifetime
By pointing the mouse cursor to the timer's title.
View its EPG entry
Timers that have set AutoTimer Checking to \"Transmission Identification\" will show you the corresponding EPG entry if you click on the timer's title.
Edit the timer
You can edit a timer by clicking \"edit\".
Delete the timer
To delete a timer you click \"delete\".

Each timer's state is indicated by differently coloured boxes (in the chart view) or images (in the list view):
    / \"on\" Timer is OK and will record.
    / \"problem\" Timer conflicts with other timers. That's not critical, as long as you have enough DVB cards for the parallel recordings.
    / \"impossible\" Timer is critical and will most likely not record.
    / \"inactive\" Timer is not active.

In addition to these functions you can add a new timer by clicking at the top and you can delete a number of timers at once by checking the box in the last column of those timers and clicking .

You can and selected timers.

" msgstr "" msgid "

Here you can edit a timer's settings.

" msgstr "

Tässä näkymässä voit muokata ajastimen asetuksia.

" msgid "Timer Active:" msgstr "Aktiivinen:" msgid "Activate or deactivate this timer. Deactivated timers are still stored in the timer list so that they can be activated again, but they do not record anything meanwhile." msgstr "Aktivoi tai deaktivoi tämä ajastin. Deaktivoidut ajastimet eivät tallenna mitään, mutta ne näytetään ajastinlistauksessa josta ne voidaan aktivoida uudelleen." msgid "AutoTimer Checking:" msgstr "Hakuajastimen tarkistus:" msgid "Depending on how this timer has been programmed you have up to three possible settings:" msgstr "Riippuen ajastimen tekotavasta, käytettävissäsi on useita asetuksia:" msgid "Transmission Identification" msgstr "Lähetteen tunniste" msgid "Monitor this timer using the identification provided in the EPG. Please note that this only works if the provided identification is a fix and unique value! This option is not available with timers programmed in VDR." msgstr "Tarkista ajastinta ohjelmaoppaan sisältämän ohjelmatunnisteen perusteella. Tämä tarkistustapa toimii vain mikäli ohjelmaoppaan ohjelmatunniste on vakio ja uniikki. Tämä valinta ei ole käytettävissä VDR:stä tehtyjen ajastimien kohdalla." msgid "Time" msgstr "Aika" msgid "Monitor this timer using the start and stop time." msgstr "Tarkista ajastin käyttäen alku- ja loppuaikoja." msgid "off" msgstr "Pois" msgid "Do not monitor this timer." msgstr "Älä tarkista tätä ajastinta." msgid "The channel to record." msgstr "Tallennettava kanava." msgid "Day Of Recording:" msgstr "Päivä:" msgid "The day when the timer should get active. You can enter the day in two formats:
  • Two digits (DD). This will use the current month and year.
  • ISO norm (YYYY-MM-DD). Program your timers as far in the future as you like.
In case you want to program a repeating timer you can use the seven checkboxes below the text field. Check the box for each day you want the timer to get active." msgstr "Ajastimen aktivoitumispäivä. Voit käyttää kahta eri muotoa päivän asettamiseen:
  • Kaksi numeroa (PP). Tämä täydennetään päivämääräksi kuluvalla kuukaudella ja vuodella.
  • ISO-standardi (VVVV-KK-PP). Voit tehdä ajastuksia niin kauas tulevaisuuteen kuin haluat.
Halutessasi asettaa toistuvan ajastuksen voit käyttää tekstikentän alla olevia seitsemää viikonpäiväkohtaista valintaruutua. Valitse jokainen viikonpäivä jolloin haluat ajastimen aktivoituvan." msgid "Start Time:" msgstr "Aloitusaika:" msgid "This is the time when the timer should start recording. The first text field is for \"hour\", the second for \"minute\"." msgstr "Aika jolloin ajastettu tallennus alkaa. Ensimmäiseen kenttään syötetään tunnit, jälkimmäiseen minuutit." msgid "End Time:" msgstr "Lopetusaika:" msgid "This is the time when the timer should stop recording. The first text field is for \"hour\", the second for \"minute\"." msgstr "Aika jolloin ajastettu tallennus päättyy. Ensimmäiseen kenttään syötetään tunnit, jälkimmäiseen minuutit." msgid "Title of Recording:" msgstr "Tallenteen nimi:" msgid "The file name this timer will give to a recording. If the name shall contain subdirectories, these have to be delimited by '~' (since the '/' character may be part of a regular programme name).

The special keywords TITLE and EPISODE, if present, will be replaced by the title and episode information from the EPG data at the time of recording (if that data is available). If at the time of recording either of these cannot be determined, TITLE will default to the channel name, and EPISODE will default to a blank." msgstr "Ajastimen tekemien tallenteiden tiedostonimi. Hakemistoerottimena käytetään '~':a (koska '/' saattaa esiintyä ohjelmien nimissä).

Avainsanat TITLE ja EPISODE korvataan ohjelmaoppaan otsikko- ja jaksotiedoilla mikäli ne ovat saatavilla tallennuksen alkaessa. Jos eivät, TITLE:n oletus on kanavan nimi ja EPISODE:n tyhjä." msgid "Summary:" msgstr "Lisätiedot:" msgid "Arbitrary text that describes the recording made by this timer. If this field is not empty, its contents will be written into the summary.vdr or info.vdr file of the recording." msgstr "Vapaavalintainen lisätietoteksti tämän ajastimen tekemille tallenteille. Jos tämä kenttä ei ole tyhjä, sen sisältö kirjoitetaan tallenteen summary.vdr- tai info.vdr-tiedostoon." msgid "Your Browser does not support frames!" msgstr "Selaimesi ei tue kehyksiä!" msgid "What's On Now?" msgstr "Menossa nyt" msgid "Playing Today?" msgstr "Tänään" msgid "Remote Control" msgstr "Kauko-ohjain" msgid "Watch TV" msgstr "Katso TV:tä" msgid "Commands" msgstr "Komennot" msgid "Search" msgstr "Etsi" msgid "Authorization Required" msgstr "Käyttäjätunnistus puutteellinen" msgid "This server could not verify that you are authorized to access the document requested. Either you supplied the wrong credentials (e.g. bad password), or your browser doesn't understand how to supply the credentials required." msgstr "Käyttäjätunnistus ei onnistu! Tarkista syöttämäsi käyttäjätunnus/salasana." msgid "VPS" msgstr "VPS" msgid "close" msgstr "Sulje" msgid "view" msgstr "Katso" msgid "search" msgstr "Etsi" msgid "edit" msgstr "Muokkaa" msgid "Length" msgstr "Kesto" msgid "Video tracks:" msgstr "Kuvaraidat:" msgid "Audio tracks:" msgstr "Ääniraidat:" msgid "Subtitles:" msgstr "Tekstitys:" msgid "Video tracks" msgstr "Kuvaraidat" msgid "Audio tracks" msgstr "Ääniraidat" msgid "TV select" msgstr "Valitse" msgid "Stream" msgstr "Suoratoisto" msgid "Channel group:" msgstr "Kanavaryhmä:" msgid "Go!" msgstr "Siirry" msgid "Search for other show times" msgstr "Etsi vaihtoehtoisia esitysaikoja" msgid "No Information" msgstr "Ei tietoja" msgid "No EPG information available" msgstr "Ohjelmaoppaan tietoja ei saatavilla" msgid "Playing Today" msgstr "Ohjelmisto tänään" msgid "starting at" msgstr "alkaen kello" msgid "What's on:" msgstr "Menossa" msgid "at" msgstr " " msgid "now" msgstr "nyt" msgid "to" msgstr "-" msgid "Duration:" msgstr "Kesto:" msgid "min" msgstr "min" msgid "at:" msgstr "kello:" msgid "You need JavaScript to use the timeline!" msgstr "Aikajanatoiminto tarvitsee JavaScript-tuen!" msgid "Rename Recording" msgstr "Nimeä tallenne" msgid "Original Name of Recording:" msgstr "Tallenteen alkuperäinen nimi:" msgid "New Name of Recording:" msgstr "Tallenteen uusi nimi:" msgid "Subtitle:" msgstr "Lyhyt kuvaus:" msgid "Rename" msgstr "Nimeä" msgid "Total:" msgstr "Käytössä:" msgid "h" msgstr "h" msgid "Free:" msgstr "Vapaana:" msgid "Date" msgstr "Päivä" msgid "Total" msgstr "kpl" msgid "New" msgstr "Uusi" msgid "Play" msgstr "Toista" msgid "Cut" msgstr "Leikkaa" msgid "Delete recording?" msgstr "Poistetaanko tallenne?" msgid "Refresh" msgstr "Päivitä" msgid "Commands:" msgstr "Komennot:" msgid "Really run this command?" msgstr "Suoritetaanko komento?" msgid "stream all recordings" msgstr "suoratoista kaikki tallenteet" msgid "Delete Selected Recordings" msgstr "Poista valitut tallenteet" msgid "Delete all selected recordings?" msgstr "Poistetaanko valitut tallenteet?" msgid "No recordings available" msgstr "Tallenteita ei saatavilla" msgid "Transponder:" msgstr "Transponderi:" msgid "CA-System:" msgstr "Salaus:" msgid "New Timer" msgstr "Uusi ajastin" msgid "Edit timer status?" msgstr "Muokataanko ajastinta?" msgid "This timer is inactive!" msgstr "Ajastin ei ole aktiivinen!" msgid "This timer is impossible!" msgstr "Ajastin ei ole mahdollinen!" msgid "No more timers on other transponders possible!" msgstr "Maksimimäärä ajastimia käytössä!" msgid "Timer OK." msgstr "Ajastin kunnossa." msgid "Auto" msgstr "Automaattinen" msgid "activate" msgstr "Aktivoi" msgid "inactivate" msgstr "Älä aktivoi" msgid "selected timers" msgstr "valittuja ajastimia" msgid "Delete Selected Timers" msgstr "Poista valitut ajastimet" msgid "No timers defined!" msgstr "Ajastimia ei määritelty!" msgid "Create New Timer" msgstr "Luo uusi ajastin" msgid "Buffer:" msgstr "Marginaali:" msgid "Use VPS:" msgstr "VPS-toiminto:" msgid "readonly" msgstr "kirjoitussuojattu" msgid "Timer has been set by AutoTimer pattern:" msgstr "Ajastin on luotu automaattisesti hakuehdolla:" msgid "TV" msgstr "TV" msgid "Interval:" msgstr "Päivitysväli:" msgid "sec." msgstr "s" msgid "G" msgstr "K" msgid "Grab the picture!" msgstr "Kuvankaappaus" msgid "Size:" msgstr "Koko:" msgid "Open in separate window" msgstr "Avaa omaan ikkunaan" msgid "VDR Commands" msgstr "Komennot" msgid "Export channels as playlist:" msgstr "Luo soittolista:" msgid "Number of lines to show:" msgstr "Näytettävien rivien lukumäärä:" msgid "unlimited" msgstr "ei rajoitusta" msgid "SVDRP commands:" msgstr "SVDRP-komennot:" msgid "Commands defined in commands.conf:" msgstr "Määritellyt komennot (commands.conf):" msgid "Output" msgstr "Vaste" msgid "What's your VDR hostname (e.g video.intra.net)?" msgstr "Anna VDR-koneesi nimi (esim. video.intra.net):" msgid "On which port does VDR listen to SVDRP queries?" msgstr "Anna VDR-koneesi käyttämä SVDRP-portti:" msgid "On which address should VDRAdmin-AM listen (0.0.0.0 for any)?" msgstr "Anna osoiteavaruus VDRAdmin-AM:lle (0.0.0.0 = ei rajoituksia):" msgid "On which port should VDRAdmin-AM listen?" msgstr "Anna portti VDRAdmin-AM:lle:" msgid "Username?" msgstr "Anna käyttäjätunnus VDRAdmin-AM:lle:" msgid "Password?" msgstr "Anna salasana VDRAdmin-AM:lle:" msgid "Where are your recordings stored?" msgstr "Anna VDR-koneesi tallennehakemiston polku:" msgid "Where are your VDR's configuration files located?" msgstr "Anna VDR-koneesi asetustiedostojen hakemiston polku:" msgid "Config file written successfully." msgstr "VDRAdmin-AM:n asetustiedosto muodostettu." #, perl-format msgid "%s %s started with pid %d." msgstr "%s %s käynnistetty prosessitunnisteella %d." msgid "Not found" msgstr "Ei löydy" msgid "The requested URL was not found on this server!" msgstr "Pyydettyä URL:ia ei löydy palvelimelta!" msgid "Forbidden" msgstr "Kielletty" msgid "You don't have permission to access this function!" msgstr "Puutteelliset käyttäjäoikeudet haluttuun toimintoon!" msgid "All channels" msgstr "Kaikki kanavat" msgid "Selected channels" msgstr "Valitut kanavat" msgid "TV channels" msgstr "TV-kanavat" msgid "Radio channels" msgstr "Radiokanavat" #, perl-format msgid "Access to file \"%s\" denied!" msgstr "Pääsy tiedostoon \"%s\" evätty!" #, perl-format msgid "The URL \"%s\" was not found on this server!" msgstr "URL:ia \"%s\" ei löydy palvelimelta!" msgid "Your favorites" msgstr "Suosikit" msgid "Search results" msgstr "Hakutulokset" msgid "Default" msgstr "Oletus" msgid "--- no timer ---" msgstr "-- ei ajastinta ---" msgid "unknown" msgstr "tuntematon" msgid "none" msgstr "-" #, perl-format msgid "Can't open file \"%s\"!" msgstr "Tiedoston \"%s\" avaus ei onnistu!" #, perl-format msgid "Can't connect to VDR at %s:%s: %s

Please check if VDR is running and if VDR's svdrphosts.conf is configured correctly." msgstr "Yhteydenotto VDR:ään (%s:%s) epäonnistui: %s

Varmista että VDR on käynnissä ja svdrphosts.conf-tiedoston oikeellisuus." #, perl-format msgid "Error while sending command to VDR at %s" msgstr "Komennon lähetys VDR:lle epäonnistui (%s)" msgid "Internal error:" msgstr "Sisäinen virhe:" msgid "Lookup movie in the Internet-Movie-Database (IMDb)" msgstr "Etsi IMDB:stä" msgid "Can't find EPG entry!" msgstr "Ohjelman tietoja ei löydy ohjelmaoppaasta!" msgid "Playing Tomorrow" msgstr "Ohjelmisto huomenna" #, perl-format msgid "Playing on the %s" msgstr "Ohjelmisto %s" msgid "next" msgstr "seuraavaksi" msgid "What's on after" msgstr "Menossa seuraavaksi" msgid "What's on at" msgstr "Menossa" msgid "Suitable matches for:" msgstr "Hakutulokset termille:" msgid "short view" msgstr "lyhyt näkymä" msgid "long view" msgstr "pitkä näkymä" msgid "Schedule" msgstr "Ohjelmisto" #, perl-format msgid "Can't write configuration file %s! Reason: %s" msgstr "Asetustiedoston %s kirjoittaminen ei onnistu: %s" #, perl-format msgid "Configuration file %s not writable! Configuration won't be saved!" msgstr "Ei kirjoitusoikeutta asetustiedostoon %s, asetukset eivät tallennu!" msgid "Timers" msgstr "Ajastimet" msgid "System default" msgstr "Oletus" vdradmin-am-3.6.13/po/fr.po000066400000000000000000002231631443716113400154030ustar00rootroot00000000000000# Copyright (C) Andreas Mair # This file is distributed under the same license as the VDRAdmin-AM package. # # Trois Six , 2007 # msgid "" msgstr "" "Project-Id-Version: VDRAdmin-AM-3.6.0\n" "Report-Msgid-Bugs-To: Andreas Mair \n" "POT-Creation-Date: 2012-07-09 12:23+0200\n" "PO-Revision-Date: 2011-11-18 23:42+0200\n" "Last-Translator: Ville Skyttä \n" "Language-Team: French \n" "Language: fr\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Language: French\n" "X-Poedit-Country: FRANCE\n" msgid "About" msgstr "A propos" msgid "License" msgstr "" msgid "Authors" msgstr "Auteurs" msgid "Current author (VDRAdmin-AM branch):" msgstr "Auteur Actuel (Branche VDRAdmin-AM) :" msgid "Original author (VDRAdmin):" msgstr "Auteur du programme (VDRAdmin) :" msgid "Translation Team" msgstr "Équipe de Traduction" msgid "English:" msgstr "Anglais :" msgid "German:" msgstr "Allemand :" msgid "French:" msgstr "Français" msgid "At the moment unmaintained, former translations by:" msgstr "Pour le moment non maintenu, précédente traductions par :" msgid "Spanish:" msgstr "Espagnol :" msgid "Finnish:" msgstr "Finlandais :" msgid "Dutch:" msgstr "Hollandais :" msgid "Russian:" msgstr "Russe" msgid "Czech:" msgstr "Tchèque :" msgid "Italian:" msgstr "Italien :" msgid "Hungarian:" msgstr "" msgid "Information" msgstr "Information" msgid "VDRAdmin-AM version:" msgstr "Version de VDRAdmin-AM :" msgid "VDR version:" msgstr "Version de VDR :" msgid "Supported features in VDR:" msgstr "Options supportées par VDR :" msgid "EPGSearch" msgstr "Plugin de Recherche dans les données EPG" msgid "EPGSearch Plugin" msgstr "EPGSearch" msgid "LiveTV Streaming" msgstr "Plugin de Streaming Live" msgid "Streamdev Plugin" msgstr "Streamdev" msgid "Xineliboutput Plugin" msgstr "" msgid "Rename Recordings (Liemikuutio Patch)" msgstr "Renommer les Enregistrements (Patch Liemikuutio)" msgid "Getting Help and Reporting Bugs" msgstr "Avoir de l'Aide et Rapporter les Bugs" msgid "If you need help please first try to use the online help you'll find on some pages. You can access it by clicking \"\"." msgstr "Si vous avez besoin d'aide, merci de regarder en priorité sur l'aide en ligne. Ici \"\"." msgid "If this doesn't provide the information you need you can try to get help at VDR-Portal if you understand German language. Please use the announcement thread if possible, search for:" msgstr "Si vous ne trouvez pas l'information recherchée, vous pouvez essayer d'obtenir de l'aide sur VDR-Portal si vous comprenez l'allemand. Merci d'utiliser le topic de l'annonce si possible, recherchez : " msgid "If you think you have found a bug please check that it's a new one and report it in the VDRAdmin-AM BugTracking system." msgstr "Si vous croyez avoir trouvé un bug, merci de vérifier si c'est un bug non identifié dans L'Outil de Gestion des Bugs VDRAdmin-AM." msgid "AutoTimer" msgstr "Auto-Programmation" msgid "Priority:" msgstr "Priorité :" msgid "Lifetime:" msgstr "Chronologie :" msgid "New AutoTimer" msgstr "Nouvelle Auto-Programmation" msgid "Help" msgstr "Aide" msgid "Active" msgstr "Actif" msgid "Channel" msgstr "Chaîne" msgid "Start" msgstr "Début" msgid "Stop" msgstr "Fin" msgid "Name" msgstr "Nom" msgid "Select all/none" msgstr "Selectionner tout/rien" msgid "Yes" msgstr "Oui" msgid "No" msgstr "Non" msgid "Edit" msgstr "Editer" msgid "Delete timer?" msgstr "Supprimer Programmation ?" msgid "Delete" msgstr "Supprimer" msgid "Force Update" msgstr "Forcer Mise à jour" msgid "Delete Selected AutoTimers" msgstr "Supprimer Auto-Programmations Sélectionnées" msgid "Delete all selected timers?" msgstr "Supprimer Programmations Sélectionnées ?" msgid "No AutoTimers defined!" msgstr "Aucune Auto-Programmation définie !" msgid "Add New AutoTimer" msgstr "Ajouter Nouvelle Auto-Programmation" msgid "Edit AutoTimer" msgstr "Editer Auto-Programmation" msgid "AutoTimer Active:" msgstr "Auto-Programmation Active :" msgid "oneshot" msgstr "une fois" msgid "Search Patterns:" msgstr "Rechercher Modèles :" msgid "Search in:" msgstr "Rechercher dans :" msgid "Title" msgstr "une fois" msgid "Subtitle" msgstr "Sous-titre" msgid "Description" msgstr "Description" msgid "Search only on these days:" msgstr "Rechercher uniquement sur ces jours :" msgid "Monday" msgstr "Lundi" msgid "Tuesday" msgstr "Mardi" msgid "Wednesday" msgstr "Mercredi" msgid "Thursday" msgstr "Jeudi" msgid "Friday" msgstr "Vendredi" msgid "Saturday" msgstr "Samedi" msgid "Sunday" msgstr "Dimanche" msgid "Channel:" msgstr "Chaîne :" msgid "all" msgstr "tout" msgid "Starts After:" msgstr "Début de recherche :" msgid "o'clock" msgstr "Heure" msgid "Ends Before:" msgstr "Fin de recherche :" msgid "Override Start/Stop Margins:" msgstr "Permettre de dépasser les Marges de Début/Fin :" msgid "Time Margin at Start:" msgstr "Marge avant :" msgid "minutes" msgstr "minutes" msgid "Time Margin at Stop:" msgstr "Marge après :" msgid "Episode:" msgstr "Episode :" msgid "Remember programmed timers:" msgstr "Se souvenir des programmations :" msgid "Directory:" msgstr "Chemin :" msgid "Save" msgstr "Enregistrer" msgid "Test" msgstr "Test" msgid "Cancel" msgstr "Annuler" msgid "Broadcasted" msgstr "Diffusé" msgid "Stored in" msgstr "Stockés dans" msgid "No matches found!" msgstr "Aucune correspondance trouvée !" msgid "Configuration" msgstr "Configuration" msgid "General Settings" msgstr "Paramètres Généraux" msgid "Template:" msgstr "Gabarit :" msgid "Skin:" msgstr "Thème :" msgid "Login Page:" msgstr "Page de Démarrage :" msgid "Number of channels to use:" msgstr "Nombre de chaînes à utiliser :" msgid "Local net (no login required):" msgstr "Réseau local (login non nécessaire) :" msgid "Language:" msgstr "Langue :" msgid "Save settings on exit:" msgstr "Enregistrer les paramètres en quittant :" msgid "VDR" msgstr "VDR" msgid "Number of DVB cards:" msgstr "Nbre de Cartes DVB :" msgid "Path to recordings:" msgstr "Chemin des Enregistrements VDR :" msgid "Path to configuration files:" msgstr "Chemin vers les fichiers de configuration :" msgid "Path to EPG images:" msgstr "Chemin vers les images EPG :" msgid "Identification" msgstr "Identification" msgid "Username:" msgstr "Identifiant :" msgid "Password:" msgstr "Mot de Passe :" msgid "Guest Account:" msgstr "Compte d'Invité :" msgid "Guest Username:" msgstr "Identifiant Invité :" msgid "Guest Password:" msgstr "Mot de Passe Invité :" msgid "Timeline" msgstr "Chronologie" msgid "Hours:" msgstr "Heures :" msgid "Times:" msgstr "Périodes :" msgid "Also used for other EPG views!" msgstr "Aussi utilisé pour d'autres vues EPG !" msgid "Tooltips:" msgstr "Bulles d'aide :" msgid "Electronic Program Guide (EPG)" msgstr "" msgid "Day begins at:" msgstr "" msgid "Show Subtitle:" msgstr "" msgid "Show Summary:" msgstr "" msgid "Active:" msgstr "Active :" msgid "Send email after programming timer:" msgstr "Envoyer email après création programmation :" msgid "Send email as:" msgstr "Envoyer mail en tant que :" msgid "Send email to:" msgstr "Envoyer mail à :" msgid "Mail server:" msgstr "Serveur smtp :" msgid "SMTPAuth user:" msgstr "Identifiant smtp :" msgid "SMTPAuth password:" msgstr "Mot de Passe smtp :" msgid "Track schedule changes by:" msgstr "" msgid "Broadcast time" msgstr "" msgid "Event id" msgstr "" msgid "Timer" msgstr "Programmation" msgid "Tooltips in timeline:" msgstr "Bulles d'aide dans la chronologie :" msgid "Tooltips in list:" msgstr "Bulles d'aide dans la liste :" msgid "Streaming" msgstr "Emission de Flux" msgid "Live Streaming:" msgstr "Emission de Flux en direct :" msgid "HTTP Port of Streamdev (also possible 3000/ts):" msgstr "Port HTTP Streamdev (aussi possible 3000/ts) :" msgid "HTTP Port of Xineliboutput (e.g. 37890):" msgstr "" msgid "Recordings Streaming:" msgstr "Emission d'Enregistrements" msgid "Path to VDR Recordings on your workstation:" msgstr "Chemin vers les Enregistrements VDR sur votre poste de travail :" msgid "MIME type for live streaming:" msgstr "Type MIME pour l'Emission de flux en direct :" msgid "Suffix for live streaming:" msgstr "Suffixe pour les flux en direct :" msgid "MIME type for recordings streaming:" msgstr "Type MIME pour l'Emission d'Enregistrements :" msgid "Suffix for recordings streaming:" msgstr "Suffixe pour les flux d'Enregistrements :" msgid "Bandwidth of Streams:" msgstr "Bande Passante Flux :" msgid "External Search" msgstr "Recherche Extenre" msgid "URL:" msgstr "URL :" msgid "Title:" msgstr "Titre :" msgid "User-defined search:" msgstr "Recherches définies par l'utilisateur :" msgid "Expert" msgstr "Expert" msgid "Update EPG data in background:" msgstr "Mettre à jour les données EPG en tâche de fond :" msgid "Update EPG every:" msgstr "Mettre à jour les données EPG toutes les :" msgid "Channel Selections" msgstr "Sélections Chaînes" msgid "Show channels without EPG information:" msgstr "Voir les chaînes sans les informations EPG :" msgid "In \"AutoTimer\"?" msgstr "Dans \"Auto-Programmations\" ?" msgid "Apply" msgstr "Appliquer" #, fuzzy msgid "EPG Search Blacklists" msgstr "Utiliser des \"listes noires\" :" #, fuzzy msgid "New Blacklist" msgstr "Utiliser des \"listes noires\" :" msgid "Search pattern" msgstr "Rechercher un motif" msgid "From" msgstr "De" msgid "To" msgstr "A" #, fuzzy msgid "Delete blacklist?" msgstr "Utiliser des \"listes noires\" :" #, fuzzy msgid "Delete Selected Blacklists" msgstr "Supprimer Recherches Sélectionnées" #, fuzzy msgid "Delete all selected blacklists?" msgstr "Supprimer toutes les Recherches Sélectionnées ?" msgid "EPG search" msgstr "recherche EPG" msgid "EPG Search" msgstr "Recherche EPG" msgid "Use template" msgstr "Utiliser un modèle" msgid "New Search" msgstr "Nouvelle Recherche" #, fuzzy msgid "Edit Template" msgstr "Gabarit :" msgid "Settings" msgstr "Paramètres" msgid "Action" msgstr "Action" msgid "Find" msgstr "Rechercher" msgid "Show Favorites" msgstr "Montrer les Favoris" msgid "Delete Selected Searches" msgstr "Supprimer Recherches Sélectionnées" msgid "Delete all selected searches?" msgstr "Supprimer toutes les Recherches Sélectionnées ?" msgid "Execute Selected Searches" msgstr "Executer les Recherches Sélectionnées" msgid "Duration" msgstr "Durée" msgid "More Information" msgstr "Plus d'Informations" msgid "Channels" msgstr "Chaînes" msgid "Record" msgstr "Enregistrer" #, fuzzy msgid "Add New Blacklist" msgstr "Utiliser des \"listes noires\" :" #, fuzzy msgid "Edit Blacklist" msgstr "Utiliser des \"listes noires\" :" #, fuzzy msgid "Add New Template" msgstr "Ajouter Nouvelle Auto-Programmation" msgid "Add New Search" msgstr "Ajouter une Nouvelle Recherche" msgid "Edit Search" msgstr "Editer la recherche" msgid "Small search pattern.\\nDo you really want to use it?" msgstr "Le motif de recherche est trop petit.\\nVoulez-vous vraiment l'utiliser ?" msgid "You didn't select at least one of\\ntitle, subtitle or description.\\nDo you really want to use this search?" msgstr "Vous n'avez ni sélectionné\\ntitre, ni sous-titre, ni description.\\nVoulez-vous vraiment utiliser cette recherche ?" msgid "Hide results" msgstr "Cacher les résultats" #, fuzzy msgid "Name:" msgstr "Nom" msgid "Search Term:" msgstr "Rechercher le Terme :" msgid "Search Mode:" msgstr "Mode de Recherche :" msgid "phrase" msgstr "phrase" msgid "all words" msgstr "tous les mots" msgid "at least one word" msgstr "au moins un mot" msgid "match exactly" msgstr "rechercher exactement" msgid "regular expression" msgstr "expression régulière" msgid "fuzzy" msgstr "fuzzy" msgid "Tolerance for \"fuzzy\":" msgstr "Tolérance pour \"fuzzy\":" msgid "Match Case:" msgstr "Respecter la Casse :" msgid "Use extended EPG info:" msgstr "Utiliser les informations EPG étendues :" msgid "Ignore missing categories?" msgstr "" msgid "Use Channel:" msgstr "Utiliser la Chaîne :" msgid "no" msgstr "non" msgid "interval" msgstr "intervalle" msgid "channel group" msgstr "groupe de la chaîne" msgid "only FTA" msgstr "Seulement les chaînes \"en clair\"" msgid "Range:" msgstr "Intervalle :" msgid "Channel Group:" msgstr "Groupe de la Chaîne :" msgid "Use Time:" msgstr "Utiliser l'Heure :" msgid "Start After:" msgstr "Démarrer après :" msgid "Start Before:" msgstr "Démarrer avant :" msgid "Use Duration:" msgstr "Utiliser Durée :" msgid "Min. Duration:" msgstr "Durée Min. :" msgid "hh:mm" msgstr "hh:mm" msgid "Max. Duration:" msgstr "Durée Max. :" msgid "Use Day of Week:" msgstr "Utiliser un jour de la Semaine :" msgid "Use Blacklists:" msgstr "Utiliser des \"listes noires\" :" msgid "selection" msgstr "Sélectionner" msgid "Use in Favorites Menu:" msgstr "Utiliser dans le Menu des Favoris :" msgid "Use as Search Timer:" msgstr "Utiliser en tant que Recherche de Programmation :" #, fuzzy msgid "yes" msgstr "Oui" #, fuzzy msgid "user-defined" msgstr "Recherches définies par l'utilisateur :" msgid "record" msgstr "enregistrer" msgid "announce by OSD" msgstr "" msgid "switch only" msgstr "zapper uniquement" msgid "announce and switch" msgstr "" msgid "announce by mail" msgstr "" #, fuzzy msgid "First day:" msgstr "Vendredi" #, fuzzy msgid "Last day:" msgstr "Vendredi" msgid "Auto delete:" msgstr "" #, fuzzy msgid "count recordings" msgstr "Enregistrements" #, fuzzy msgid "count days" msgstr "Lundi" #, fuzzy msgid "After ... recordings:" msgstr "Garder ... Enregistrements :" #, fuzzy msgid "After ... days after first recording:" msgstr "Garder ... Enregistrements :" msgid "Settings for action \"record\"" msgstr "Paramètres pour action \"enregistrement\"" msgid "Series Recording:" msgstr "Enregistrement des Séries :" msgid "Delete Recordings After ... Days:" msgstr "Supprimer les Enregistrement Après ... Jours :" msgid "Keep ... Recordings:" msgstr "Garder ... Enregistrements :" msgid "Pause, when ... recordings exist:" msgstr "Pause, quand ... Enregistrements existent :" msgid "Avoid Repeats:" msgstr "Eviter les répétitions :" msgid "Allowed Repeats:" msgstr "Autoriser les répétitions :" msgid "Only Repeats Within ... Days:" msgstr "Se répète uniquement dans ... Jours :" msgid "Compare:" msgstr "Comparer :" msgid "Minimal match of description in %:" msgstr "" msgid "VPS:" msgstr "VPS :" msgid "Settings for action \"switch only\"" msgstr "Paramètres pour action \"zapper uniquement\"" msgid "Switch ... Minutes Before Start:" msgstr "Zapper ... Minutes Avant le Début :" msgid "Unmute sound:" msgstr "" msgid "Settings for action \"announce and switch\"" msgstr "" msgid "Ask ... Minutes Before Start:" msgstr "" #, fuzzy msgid "Delete template" msgstr "Utiliser un modèle" #, fuzzy msgid "Delete this template?" msgstr "Supprimer Programmation ?" msgid "Save as template" msgstr "Enregistrer en tant que modèle" msgid "Run" msgstr "Exécuter" msgid "Error!" msgstr "Erreur !" msgid "

Here you will find a listing of automatic timers (AutoTimer) known to VDRAdmin-AM.

The list shows some information on AutoTimers. You can change the list's sorting by clicking the columns heading.

For each AutoTimer you have the following options:

Set its state
By clicking on \"Yes\" or \"No\" in the \"Active\" column to toggle the activity.
Quickly view its priority and lifetime
By pointing the mouse cursor to the AutoTimer's title.
Edit the AutoTimer
You can edit an AutoTimer by clicking \"edit\".
Delete the AutoTimer
To delete an AutoTimer you click \"delete\".

Each AutoTimer's state is indicated by differently coloured images:
\"on\" AutoTimer is OK and will automatically program matching broadcasts.
\"inactive\" AutoTimer is not active.

In addition to these functions you can add a new AutoTimer by clicking at the top and you can delete a number of AutoTimers at once by checking the box in the last column of those timers and clicking .

Click to force VDRAdmin-AM to reconnect to VDR, fetch the current EPG and check for matching AutoTimers.

" msgstr "

Ici vous trouverez une liste des programmations automatiques (ou AutoTimer) connues de VDRAdmin-AM.

Cette liste montre des informations sur ces Programmations Automatiques. Vous pouvez changer l'ordre de cette liste en cliquant les descriptions des colonnes.

Pour chaque Programmation Automatique vous avez les options suivantes :

Changer son état
En cliquant sur \"Oui\" ou \"Non\" dans la colonne \"Activé\".
Voir rapidement sa priorité et sa durée de vie
En survolant de la sourie le titre de la Programmation Automatique.
Editer la Programmation Automatique
Vous pouvez éditer une Programmation Automatique en cliquant sur\"editer\".
Supprimer une Programmation Automatique
Pour supprimer une Programmation Automatique vous devez cliquer sur \"supprimer\".

Les états de toutes les Programmations Automatiques sont indiqués par des images de couleurs différentes :
\"on\" La Programmation Automatique est OK and se programmera automatiquement.
\"inactivée\" La Programmation Automatique n'est pas activée.

En plus de ces fonctions vous pouvez ajouter une nouvelle Programmation Automatique en cliquant sur en haut et vous pouvez supprimer plusieurs Programmations Automatiques en cochant les case dans la dernière colonne de celles-ci et en cliquant sur .

Cliquez pour forcer VDRAdmin-AM à se reconnecter à VDR, récupérer les données EPG courantes et vérifier and les modèles de Programmations Automatiques.

" msgid "

Here you can edit an automatic timer's (AutoTimer) settings.

AutoTimer is a key feature of VDRAdmin-AM. An AutoTimer consists of one or more search terms and some other settings, that are looked for regularly in the Electronic Program Guide (EPG). On match AutoTimer adds a timer in VDR automatically for that broadcast. That's very comfortable for irregularly broadcasted series or movies you don't want to miss.

" msgstr "

Ici vous pouvez éditer les paramètres d'une programmation automatique (AutoTimer).

Les Programmations Automatiques sont une fonction clé de VDRAdmin-AM. Une Programmation Automatique consiste en un ou plusieurs motifs et d'autres paramètres, qui sont recherchés dans l'Electronic Program Guide (EPG). Quand ces motifs sont trouvés, une Programmation Automatique est ajouté à VDR automatiquement pour cette diffusion. Cette fonctionnalité est très confortable pour enregistrer des séries diffusées irrégulièrement ou des films que vous ne voulez par manquer.

" msgid "Activate or deactivate this AutoTimer. Deactivated AutoTimers are still stored in the AutoTimer list so that they can be activated again, but they do not record anything meanwhile. Above that you can set this to \"oneshot\" so this AutoTimer only programs the (one!) next matching broadcast." msgstr "Activer ou désactiver cette Auto-Programmation. Les Auto-Programmations désactivées sont toujours stockées dans la liste des Auto-programmation, aussi elles peuvent être activées à tout moment, mais cependant elles n'enregistre rien. Au dessus vous pouvez régler ceci à \"Une Fois\", donc cette Auto-Programmation programme seulement la prochaine (et unique!) occurrence de la diffusion." msgid "Choosing the right search items decides whether only the wanted broadcasts or broadcasts having similar names or even nothing gets recorded.
Case doesn't matter, \"X-Files\" matches anything \"x-files\" will match. You can set multiple search items by separating them with spaces. Broadcasts will match only if they match all configured search items.
You'd better only use letters and numbers for search items, as the EPG often miss colons, brackets and other characters.
Experts can also use regular expressions, but you have to get needed information from the VDRAdmin-AM sources (undocumented feature).

You can exclude broadcasts so that they don't get recorded even if they would match an AutoTimer. Therefore you have to enter that titles into the file vdradmind.bl, one event a line. This file must be located in your VDRAdmin-AM's configuration folder. If this string is found either in the EPG's title or in title~subtitle, this event will not be programmed by AutoTimer. So you can disable complete episodes (for example when using \"Enterprise\" as blacklist string) or only one episode (when using \"Enterprise~Azati Prime\" as blacklist string)." msgstr "Choisir les bons critères de recherches décidera soit que seules les diffusions recherchés ou les diffusions ayant un nom similaires voire même rien ne sera enregistré.
La Casse n'est pas importante, \"X-Files\" concorde avec tout ce que \"x-files\" fera concorder. Vous pouvez régler de multiples critères de recherche en les séparants par des espaces. Les diffusions concorderont seulement si elles contiennent tous les critères.
Utiliser de préférence uniquement des chiffres et des lettres, car l'EPG omet souvent les virgules, parenthèses, et autres caractères.
Les experts peuvent aussi utiliser les expressions régulières, mais vous devrez étudier les sources de VDRAdmin-AM (fonctionnalité non documentée).

Vous pouvez exclure des diffusions et donc elle ne seront pas enregistré même si elle concordent avec une Auto-Programmation. Néanmoins vous devez entrer ses titres dans le fichier vdradmind.bl, un évènement par ligne. Ce fichier doit être situé dans votre répertoire de configuration de VDRAdmin-AM. Si cette chaîne de caractères est trouvé soit dans titre ou dans titre~soustitrede l'EPG, cet évenement ne sera pas programmé. Donc sous pouvez désactivé des épisodes complets (par exemple en utilisant \"Enterprise\" comme chaîne de caractère) ou seulement un épisode (en utilisant \"Enterprise~Azati Prime\" comme chaîne de caractères)." msgid "Here you can define the EPG sections where VDRAdmin-AM should look for the search pattern." msgstr "Ici, vous pouvez définir les sections du guide électronique des programmes où VDRAdmin-AM recherchera le motif de recherche." msgid "Use these checkboxes to limit searching for matching broadcasts to a set of weekdays." msgstr "Utilisez ces cases à cocher pour limiter la recherche de diffusions concordantes à un jeu de jours." msgid "The channel to look for matching broadcasts or \"all\" to search in all known or wanted channels. You can define the wanted channels for AutoTimer in \"Configuration\"." msgstr "La chaîne à rechercher pour des diffusion concordantes ou \"toutes\" pour rechercher dans toutes les chaînes connues ou désirées. Vous pouvez définir les chaînes désirées pour l'Auto-programmation dans \"Configuration\"." msgid "A broadcast must start after the time entered here to match. The first text field is for \"hour\", the second for \"minute\"." msgstr "Une diffusion doit démarrer après l'horaire entrée pour être concordante. Le premier champ est pour \"heure\", le second pour \"minute\"." msgid "A broadcast must end before the time entered here to match. The first text field is for \"hour\", the second for \"minute\"." msgstr "Une diffusion doit s'arrêter avant l'horaire entrée pour être concordante. Le premier champ est pour \"heure\", le second pour \"minute\"." msgid "Set this option to \"yes\" if all timers programed by this AutoTimer should have individual start/stop margins and enter the values in the next two text boxes." msgstr "Sélectionnez cette option à \"oui\" si toutes les programmations programmées par cette Auto-Programmation devraient avoir des marges de début/fin individuelles et entrez les valeurs dans les deux prochains champs." msgid "The number of minutes VDRAdmin-AM subtracts from the broadcast's start time found in the EPG." msgstr "Le nombre de minutes que VDRAdmin-AM soustrait aux heures de début trouvées dans les données EPG." msgid "The number of minutes VDRAdmin-AM adds to the broadcast's stop time found in the EPG." msgstr "Le nombre de minutes que VDRAdmin-AM ajoute aux heures de fin trouvées dans les données EPG." msgid "An integer in the range 0...99, defining the priority of this timer and of recordings created by this timer. 0 represents the lowest value, 99 the highest. The priority is used to decide which timer shall be started in case there are two or more timers with the exact same start time. The first timer in the list with the highest priority will be used.

This value is also stored with the recording and is later used to decide which recording to remove from disk in order to free space for a new recording. If the disk runs full and a new recording needs more space, an existing recording with the lowest priority (and which has exceeded its guaranteed lifetime) will be removed.

If all available DVB cards are currently occupied, a timer with a higher priority will interrupt the timer with the lowest priority in order to start recording." msgstr "Un entier dans l'intervalle 0...99, définissant la priorité de cette programmation et de l'enregitrement créé par cette programmation. 0 représente la valeur la plus faible, 99 la plus haute. La priorité est utilisée pour décider quelle programmation devrait être démarrée dans le cas où deux ou plus de programmation possèdent la même heure début. La première programmation dans la liste avec la priorité la plus haute sera utilisée.

Cette valeur est aussi stockée avec l'enregistrement, et est utilisée plus tard pour décider quel enregistrement doit être supprimé du disque pour libérer de la place pour un nouvel enregistrement. Si le disque est plein et qu'un nouvel enregistrement nécessite plus de place, un enregistrement avec la plus faible priorité (et dont durée de vie garantie sera dépassée) sera enlevé.

Si toutes les cartes DVB disponibles sont actuellement occupés, une programmation avec une priorité plus élevée interrompra la programmation avec la priorité la plus faible pour démarrer l'enregistrement." msgid "The guaranteed lifetime (in days) of a recording created by this timer. 0 means that this recording may be automatically deleted at any time by a new recording with higher priority. 99 means that this recording will never be automatically deleted. Any number in the range 1...98 means that this recording may not be automatically deleted in favour of a new recording, until the given number of days since the start time of the recording has passed by." msgstr "La durée de vie garantie (en jours) d'un enregistrement créé pas cette programmation. 0 signifie que cet enregistrement peut être automatiquement supprimé à n'importe quelle moment par un enregistrement avec une priorité plus haute. 99 signifie que cet enregistrement ne sera jamais automatiquement supprimé. Tout nombre dans l'interval 1...98 signifie que cet enregistrement ne peut être automatiquement supprimé en faveur d'un nouvel enregistrement, jusqu'à ce que le nombre de jour donné depuis la date de démarrage de l'enregistrement soit dépassé." msgid "Check this box if you want VDRAdmin-AM to append the broadcast's EPG subtitle to the recording's file name." msgstr "Cochez cette case si vous voulez que VDRAdmin-AM ajoute le sous-titre EPG de la diffusion au nom du fichier de l'enregistrement." msgid "If you enable this VDRAdmin-AM will track timers it has already programmed automatically. This is useful if want to deactivate or delete timers that have been programmed automatically in the timers listing." msgstr "Si vous activez ceci, VDRAdmin-AM suivra les programmations qu'il aura automatiquement créées. Ceci est utile si vous voulez désactiver ou supprimer les programmations automatiquement créées dans la liste des programmations." msgid "The directory this AutoTimer will place the recordings in. If the name shall contain subdirectories, these have to be delimited by '~' (since the '/' character may be part of a regular programme name).
VDRAdmin-AM will append the matching broadcast's title and subtitle (if the \"Episode\" checkbox is marked) to the directory given here.

You can also use the following keywords that are replaced in the final file name by the values supplied by for example tvm2vdr:
  • %Title% - will become the title of the event.
  • %Subtitle% - will become the subtitle of the event.
  • %Director% - will become the director of the event.
  • %Date% - will become the date of the recording.
  • %Category% - will become the category of the event (Spielfilm/Serie/...).
  • %Genre% - will become the genre of the event (Drama/Krimi/..).
  • %Year% - will become the year of production.
  • %Country% - will become the country of production.
  • %Originaltitle% - will become the original title of the event.
  • %FSK% - will become the FSK from the event.
  • %Episode% - will become the episode's title of the event.
  • %Rating% - will become the rating of the event from the EPG provider.

Note:

If you use the above keywords it's in your own responsibility to supply the complete file name for the recordings! VDRAdmin-AM will not append anything to the resulting string." msgstr "Le répertoire où cette Programmation Automatique va placer les enregistrements. Si le nom devait contenir des sous répertoires, ceux-ci devraient être délimités par le caractère '~' (le caractère '/' peut faire partie du nom d'un exécutable).
VDRAdmin-AM ajoutera le titre et le sous-titre (si la case \"Episode\" est cochée) du programme diffusé à ce nom.

Vous pouvez aussi utiliser d'autres noms clé qui sont remplacés par les valeurs fournies par exemple par tvm2vdr:
  • %Title% - deviendra le titre de l'évènement.
  • %Subtitle% - deviendra le sous-titre de l'évènement.
  • %Director% - deviendra le metteur en scène de l'évènement.
  • %Date% - deviendra la date de l'enregistrement.
  • %Category% - deviendra la catégorie de l'évènement (Film/Série/...).
  • %Genre% - deviendra le genre de l'évènement (Drame/Tragédie/..).
  • %Year% - deviendra l'année de production.
  • %Country% - deviendra le pays de production.
  • %Originaltitle% - deviendra le titre original de l'évènement.
  • %FSK% - deviendra le FSK (??) de l'évènement.
  • %Episode% - deviendra le titre de l'épisode de l'évènement.
  • %Rating% - deviendra la note de l'évènement donnée par le fournisseur de l'EPG.

Remarque :

Si vous utilisez les noms clé ci-dessus, il est de votre responsabilité de fournir le nom complet du fichier de l'enregistrement ! VDRAdmin-AM n'ajoutera rien à la chaîne de caractères obtenue." msgid "

Here you can change general settings and base settings for timers, AutoTimers, channel selection and streaming parameters.

" msgstr "

Vous pouvez changer ici les réglages généraux et de base pour les programmations, les Auto-Programmations, la sélection des chaînes et les paramétrages de diffusion.

" msgid "The skin you want to use." msgstr "Le thème que vous désirez utiliser." msgid "The page you want to see at first connect to VDRAdmin-AM." msgstr "La page que vous désirez voir à la première connexion à VDRAdmin-AM." msgid "VDRAdmin-AM will load the given number of channels from VDR and present only those in any fields where channels can be selected. This also limits the EPG information VDRAdmin-AM will read so that you can use this to reduce VDRAdmin-AM's memory consumption and increase its performance. 0 turns this feature off and VDRAdmin-AM will use all available channels." msgstr "VDRAdmin-AM va charger le présent nombre de chaînes de VDR et ne montrer que celles qui ont les champs qui peuvent être sélectionnés. Cela limite aussi les Informations EPG. VDRAdmin-AM ne va lire que ce dont il a besoin, ce qui va réduire la consommation mémoire et augmenter la performance. 0 désactive cette option et VDRAdmin-AM va utiliser toutes les chaînes." #, fuzzy msgid "Here you can specify subnets from which access to VDRAdmin-AM does not require logging in. For example: \"192.168.0.0/24\" will include any IP starting with \"192.168.0.\", \"192.168.0.123/32\" will only match \"192.168.0.123\". Multiple subnets can be specified by separating them with spaces or commas." msgstr "Vous pouvez spécifier ici une adresse IP ou une plage pour laquelle aucune authentification ne sera demandée. Par exemple : \"192.168.0.0/24\" inclura toute adresse commençant par \"192.168.0.\", \"192.168.0.123/32\" inclura seulement \"192.168.0.123\"." msgid "Here you can set the localization VDRAdmin-AM should use." msgstr "Ici vous pouvez définir la langue de VDRAdmin-AM." msgid "With this option the settings will be saved if VDRAdmin-AM exits. This will also save settings not available on the \"Configuration\" menu like interval and size in TV, sorting in the lists and current view in \"What's on now\"." msgstr "Avec cette option, les paramètres seront sauvegardés si VDRAdmin-AM existe. Cela enregistrera aussi les paramètres non disponibles dans le menu \"Configuration\" comme l'intervalle et la taille sur la TV, tri des listes et la vue courante dans \"En ce Moment\"." msgid "Top" msgstr "Haut" msgid "The number of DVB cards VDR can access. Depending on this value VDRAdmin-AM will calculate critical timers in the Timer menu." msgstr "Le nombre de carte DVB auxquelles VDR peut accéder. Suivant cette valeur VDRAdmin-AM calculera les programmations critiques an le menu Programmation." msgid "The path to VDR's recordings. It's used so that VDRAdmin-AM can locate the recordings when using Recordings Streaming and reccmds.conf in the Recordings menu." msgstr "Le Chemin vers les enregistrements de VDR. Ceci est utilisé pour que VDR puisse situer les enregistrements lorsque l'on utilise Emission d'Enregistrements et reccmds.conf dans le menu Enregistrements." msgid "The path where VDR's configuration files are located. If this directory contains the file reccmds.conf its content is shown in a selectbox in the Recordings menu." msgstr "Le chemin où la configuration de VDR se situe. Si ce répertoire contient le fichier reccmds.conf son contenu est affiché dans une boite de sélection dans le menu Enregistrements." msgid "The path where the EPG images are stored." msgstr "Le chemin dans lequel les images EPG sont stockées." msgid "The username for the main user, i.e. the user having the most privileges." msgstr "Le nom d l'utilisateur principal, celui possédant le plus de privilèges." msgid "The main user's password." msgstr "Le mot de passe de l'utilisateur principal." msgid "If you want a user account having only limited privileges, this is for you. The guest user cannot modify anything, it's only allowed to view the EPG, timers, AutoTimers and recordings listings." msgstr "Si vous voulez un compte utilisateur possédant seulement des droits limités, ceci est pour vous. L'utilisateur invité ne peut rien modifier. Il est seulement autoriser à voir le guides électronique des programmes, les programmations, les Auto-Programmations et la liste des enregistrements." msgid "The username for the guest user." msgstr "Le nom de l'utilisateur invité." msgid "The guest user's password." msgstr "Le mot de passe de l'invité." msgid "The number of hours to show in the timeline." msgstr "Le nombre d'heures à afficher dans la chronologie." msgid "A comma separated list of times in hh:mm format that appear in the selectbox placed at the top." msgstr "Une liste d'horaires séparés par des virgules au format hh:mm qui apparaissent dans la boites de sélection placée en haut." msgid "Here you can (de-)activate the tooltips." msgstr "Ici vous (dés-)activer les bulles d'aide." msgid "The time after which events are shown on a new day. For example setting 03:00 means that today's schedule will include any event starting before 03:00 tomorrow. Applies only to the 'Playing Today?' list." msgstr "" msgid "Show the 'Subtitle' text for each event. Not all broadcasters use this field." msgstr "" msgid "Show the 'Summary' text for each event." msgstr "" msgid "Activate or deactivate the AutoTimer function." msgstr "Active ou désactive la fonction d'Auto-Programmation." msgid "VDRAdmin-AM will send an email whenever an event matches an AutoTimer and a timer has been programmed if you enable this feature." msgstr "VDRAdmin-AM va envoyer un email à chaque fois qu'un évènement va correspondre à une auto-programmation et qu'une programmation a été programmée si vous activez cette option." msgid "Here you set the sending email address of the generated email." msgstr "Ici vous allez définir le nom de domaine de provenance de l'email généré." msgid "The email address the email is sent to." msgstr "L'adresse email de destination." msgid "The outgoing mail server." msgstr "Le serveur smtp d'envoi des emails." msgid "If you need to authenticate yourself at the outgoing mail server, you have to supply the username and the password below. Leaving this field empty will disable SMTPAuth." msgstr "Si vous avez besoin de vous authentifier sur votre serveur smtp, vous devez fournir vos identifiants ci-dessous. Laissez ces champs vide implique qu'il n'y a pas d'authentification smtp." msgid "The password for the SMTPAuth user." msgstr "Le Mot de Passe pour le serveur SMTP." msgid "Here you can (de-)activate the tooltips in the timeline." msgstr "Ici vous pouvez (dés-)activer les bulles d'aide dans la chronologie." msgid "Here you can (de-)activate the tooltips in the list." msgstr "Ici vous pouvez (dés-)activer les bulles d'aide dans la liste." msgid "Add summary to new timers:" msgstr "Ajouter résumé dans les nouvelles programmations :" msgid "If you don't want VDRAdmin-AM to add the summary taken from EPG to new timers you can switch it off here." msgstr "Si vous ne voulez pas que VDRAdmin-AM ajoute le résumé de l'EPG dans les nouvelles programmations vous pouvez désactiver cette option." msgid "Enable or disable live streaming using the streamdev plugin. You also have to set the correct HTTP Port for Streamdev below." msgstr "Active ou Désactive la diffusion en directe en utilisant le plugin streamdev. Vous devez aussi définir le réglage correct du Port HTTP pour Streamdev ci-dessous." msgid "Here you have to set the port number your VDR's streamdev server listens for connections. Additionally you can also provide the stream type you like to use." msgstr "Vous pouvez ici régler le numéro de port sur lequel le serveur streamdev de VDR sera à l'écoute pour toute connexion. Additionnellement vous pouvez aussi fournir le type de flux que vous désirez utiliser." msgid "Enable or disable streaming of recordings.
Well actually this is no real \"streaming\", but you have to setup your workstation so that it can access VDR's recordings. You can use for example Samba or NFS for this. VDRAdmin-AM simply generates a playlist that contains all parts of the recording and sends this to your browser. If your browser and media player are configured correctly you will see the recording on your workstation's display." msgstr "Active ou désactive la diffusion des enregistrements.
Actuellement ceci n'est un réel \"streaming\", mais vous avez à parametrer votre station pour quelle puisse accéder aux enregistrements de VDR. Vous pouvez utiliser par exemple Samba or NFS pour cette tâche. VDRAdmin-AM générera simplement une liste de lecture qui contiendra tous les enregistrements et l'enverra à votre navigateur. Si votre navigateur et votre lecteur de média sont configurés correctement, vous pourrez voir les enregistrements sur votre station." msgid "This is the path where your workstation can access VDR's recordings. This depends on your VDR and workstation setup, for example \"\\\\vdr\\videos\" or \"V:\\\" (on Windows) or \"/mnt/videos\" (on Linux)." msgstr "Ceci est le chemin où votre station peut accéder au enregistrements de VDR. Cela dépend des réglages de votre VDR et de votre station, par exemple \"\\\\vdr\\videos\" ou \"V:\\\" (sur Windows) ou \"/mnt/videos\" (sur Linux)." msgid "The MIME type to send when using live streaming. Defaults to \"video/x-mpegurl\"." msgstr "Le Type MIME envoyé quand vous envoyez du flux en direct. Par défaut, le type MIME est \"video/x-mpegurl\"." msgid "The suffix to use for live streaming. Defaults to \"m3u\"." msgstr "L'extension à utiliser pour l'émission de flux en direct. Par défaut, l'extension est \"video/x-mpegurl\"." msgid "The MIME type to send when using recordings streaming. Defaults to \"video/x-mpegurl\"." msgstr "Le type MIME à envoyer lors de l'envoi de flux d'enregistrements. Par défaut \"video/x-mpegurl\"." msgid "The suffix to use for recordings streaming. Defaults to \"m3u\"." msgstr "L'extension à utiliser pour l'envoi de flux d'enregistrements. Par défaut \"m3u\"." msgid "

Here you can define two external searches that you can access in the EPG views. You simply have to find the required URL and where the search pattern has to be located. %TITLE% will be substituted by the broadcast's EPG title.

" msgstr "

Ici vous pouvez définir deux recherches externes auxquelles vous pouvez accéder dans les vues EPG. You avez seulement à trouver l'URL et où le paramètres de recherche doit être indiqué. %TITLE% sera substitué par titre de la diffusion trouvé dans le titre dans les données EPG.

" msgid "Some examples:" msgstr "Quelques exemples :" msgid "Please change the hostname to your local needs!" msgstr "" msgid "

This section is for experts only, i.e. you know what you are doing!

" msgstr "

Cette section est pour les experts seulement. Vous devez savoir ce que vous faites!

" msgid "If set to \"yes\" VDRAdmin-AM will periodically refresh its local EPG cache. Else the EPG will be refreshed if the user accesses any EPG view at the web interface and the timeout set at \"Update EPG every\" has been reached." msgstr "Si l'option est \"oui\" VDRAdmin-AM rafraichira périodiquement son cache local EPG. Sinon l'EPG sera rafraichit si l'utilisateur accède à n'importe quelle vue EPG dans l'interface web et que le timeout choisit dans \"Mise à jour EPG tous les\" aura été atteint." msgid "The interval, the EPG data is refreshed from VDR and AutoTimer updates are performed (if AutoTimer feature is used)." msgstr "L'intervalle durant lequel les données du guide éléctronique des programmes sont vérifiées pour mettre à jour les Auto-Programmations (si les Auto-Programmations sont activées)." msgid "

If you want to limit the number of channels used in some parts of VDRAdmin-AM, this is for you!

Use the radio buttons to activate or deactivate the wanted channels in the named menu.

To add channels to the list of wanted channels you have to select them in the left side selectbox and click . If you want to remove channels from the list of wanted channels you have to select them in the right side selectbox and click .

" msgstr "

Si vous voulez limiter le nombre de chaînes utilisées dans certaines parties de VDRAdmin-AM, cette option est faite pour vous !

Utilisez le radio bouton pour activer ou désactiver les chaînes désirées le menu.

Pour ajouter des chaînes dans la liste des chaînes désirées, vous devez les sélectionner sur le côté gauche de la liste de sélection et cliquez sur . Si vous voulez enlever des chaînes de la liste des chaînes désirées, vous devez les sélectionner dans la liste de sélection de droite et cliquez sur .

" msgid "Usually channels that don't have EPG information are hidden in all EPG views. If you don't want them to be hidden you have to set this option to \"yes\"." msgstr "De manière générale, les chaînes qui n'ont pas d'information EPG sont cachées dans toutes les vues EPG. Si vous ne voulez pas les cacher, activez (\"oui\") cette option." msgid "Edit Timer" msgstr "Editer Programmation" msgid "Edit EPG" msgstr "Editer EPG" msgid "

Here you can edit the descriptive fields of an existing EPG entry.

" msgstr "

Ici vous pouvez modifier les champs de description d'une entrée EPG.

" msgid "Channel (readonly)" msgstr "Chaîne (lecture seule)" msgid "This is the channel of the EPG entry. It cannot be changed." msgstr "Ceci est la chaîne diffusant les données EPG. Elle ne peut être changée." msgid "Time (readonly)" msgstr "Temps (lecture seule)" msgid "This is the start and end time of the entry. It cannot be changed." msgstr "Ceci est le début et la fin de cette entrée. Ceci ne peut être changé." msgid "Change this string to give this EPG Entry a new title. It must consist of only one line of text." msgstr "Changez cette chaîne de caractères pour donner à l'entrée EPG un nouveau titre. Il ne doit y avoir qu'une ligne de texte au maximum." msgid "Change this string to give this EPG Entry a new subtitle. It must consist of only one line of text." msgstr "Changez cette chaîne de caractères pour donner à l'entrée EPG un nouveau sous-titre. Il ne doit y avoir qu'une ligne de texte au maximum." msgid "Change the text in this field to edit the description of this entry. The text can consist of one or more lines." msgstr "Changez le texte de ce champ pour éditer la description de cette entrée. Le texte peut faire une ou plusieurs lignes." msgid "VPS (readonly)" msgstr "VPS (lecture seule)" msgid "If available this field shows the vps time of the EPG entry. It cannot be changed." msgstr "Si des temps VPN dans l'entrée EPG existe(nt), ce champ les montrera. Il ne peut pas être modifié." msgid "Video tracks (readonly)" msgstr "Pistes vidéo (lecture seule)" msgid "If available this field shows the video track(s). It cannot be changed." msgstr "Si des piste(s) vidéo existe(nt), ce champ les montrera. Il ne peut pas être modifié." msgid "Audio tracks (readonly)" msgstr "Pistes audio (lecture seule)" msgid "If available this field shows the audio track(s). It cannot be changed." msgstr "Si des piste(s) audio existe(nt), ce champ les montrera. Il ne peut pas être modifié." msgid "No Help Available" msgstr "Pas d'aide disponible" msgid "

No help available yet. For adding or changing text please contact amair.sob@googlemail.com.

" msgstr "

Aucune aide n'est disponible. Pour ajouter ou changer du texte contactez amair.sob@googlemail.com..

" msgid "Recordings" msgstr "Enregistrements" msgid "

Here you will find a listing of recordings known to VDR. The headline will also show you VDR's total and free disk space.

The listing showing you some information on the recordings. You can change the list's sorting by clicking the columns heading. Above the list you'll see the navigation path. If you want to view the contents of previous folders you'll have to click on its name in that path.

Each row contains this information:

Date
The date when the recording has been done. In case of folders this will show the number of recordings the folder contains.
Time
The time when the recording has been done. In case of folders this will show the number of new recordings the folder contains.
Name
The recording's or folder's name. Click it to show the recording's summary or descend into the folder.
Rename (\"edit\")
Rename a recording.

Note:

This only works if VDR has the MOVR or RENR SVDRP command which is not a core VDR feature but provided by the Liemikuutio patch set.
Delete (\"delete\")
Delete a recording.
Stream (\"stream\")
This column is only shown if you activated and configured Recordings Streaming in the Configuration menu. You can watch the recording at your workstation.

In addition to these functions you can delete a number of recordings at once by checking the box in the last but one column of those recordings and clicking .

If you've set the path the VDR's configuration files and have entries in VDR's reccmds.conf you can run those commands for the selected recording by selecting the wanted command in the select box locate next to Commands: and pressing the button.

Use to force reloading of VDR's recordings listing.

" msgstr "

Ici vous trouverez une liste des enregistrements connus de VDR. L'entête montrera aussi les espaces disques utilisés en libres selon VDR.

La liste vous montre certaines informations sur les enregistrements. Vous pouvez changer l'ordre ce cette liste en cliquant sur la description de la colonne. Au dessus de la liste vous verrez le chemin de navigation. Si vous voulez voir le contenu des répertoires précédents vous devrez cliquant sur leurs noms dans le chemin.

Chaque ligne contient ces informations :

Date
La Date de création de l'enregistrement. Dans le cas d'un répertoire, cela montrera le nombre d'enregistrements que ce répertoire contient.
Heure
L'heure de création de l'enregistrement.Dans le cas d'un répertoire, cela montrera le nombre de nouveaux enregistrements que ce répertoire contient.
Nom
Le nom de l'enregistrement ou du répertoire. Cliquez dessus pour voir le résumé de l'enregistrement ou naviguer dans le répertoire.
Renommer (\"editer\")
Renommer un enregistrement.

Remarque :

Cele ne marque que si VDR a la commande SVDRPort RENR qui ne fait pas partie de base de VDR mais qui peut être ajouter grâce à un patch. vdr-aio21_svdrprename.patch ou enAIO-v2.2+ permettent d'ajouter cette commande.
Supprimer (\"supprimer\")
Supprimer un enregistrement.
Emettre un flux (\"stream\")
Cette colonne n'est visible que si vous avez activé et configuré L'émission de Flux d'Enregistrement dans le menu de Configuration. Vous pouvez regarder l'enregistrement sur votre station de travail.

En plus de ces fonctions vous pouvez supprimer plusieurs enregistrements en même temps en cochant les cases de la dernière colonne de ceux-ci et en cliquant sur .

Si vous avez défini le chemin des fichiers de configuration de VDR et que vous avez des entrées dans le reccmds.conf de VDR vous pouvez exécuter ces commandes pour les enregistrements sélectionnées en sélectionnant la commande désirée dans la liste de sélection située près de Commandes : et en pressant sur le bouton .

Utilisez pour forcer VDR à rafraîchir sa liste d'enregistrements.

" msgid "

Here you will find a listing of timers known to VDR.

On top you will find a chart showing a day's timers graphically. This provides an quick overview on what's going on at the specified day and helps you in finding conflicting timers. Moving the mouse cursor above any timer box will display a tooltip containing the timer's title, priority, lifetime and duration.

Below the chart you'll find the timers list showing you some information on the timers. You can change the list's sorting by clicking the columns heading.

For each timer you have the following options:

Set its state
By clicking on \"Yes\", \"No\", \"VPS\" or \"Auto\" in the \"Active\" column.
Quickly view its priority and lifetime
By pointing the mouse cursor to the timer's title.
View its EPG entry
Timers that have set AutoTimer Checking to \"Transmission Identification\" will show you the corresponding EPG entry if you click on the timer's title.
Edit the timer
You can edit a timer by clicking \"edit\".
Delete the timer
To delete a timer you click \"delete\".

Each timer's state is indicated by differently coloured boxes (in the chart view) or images (in the list view):
    / \"on\" Timer is OK and will record.
    / \"problem\" Timer conflicts with other timers. That's not critical, as long as you have enough DVB cards for the parallel recordings.
    / \"impossible\" Timer is critical and will most likely not record.
    / \"inactive\" Timer is not active.

In addition to these functions you can add a new timer by clicking at the top and you can delete a number of timers at once by checking the box in the last column of those timers and clicking .

You can and selected timers.

" msgstr "

Ici vous trouverez une liste des programmations connues par VDR.

En haut vous trouverez un graphique montrant les programmations au jour le jour. Cela permet d'appréhender rapidement ce qu'il se passe sur une journée et vous aide à découvrir les programmations conflictuelles. Survoler avec la souris une programmation permet d'afficher une bulle d'aide contenant le titre, la priorité, la durée de vie, la durée de celle-ci.

En dessous du graphe, vous trouverez une liste des programmations montrant quelques informations sur les programmations. Vous pouvez changer l'ordre d'affichage en cliquant sur les descriptions des colonnes.

Pour chaque enregistrement, vous avez les options suivantes :

Changer son état
En cliquant sur \"Oui\", \"Non\", \"VPS\" or \"Auto\" dans la colonne \"Activé\" .
Voir rapidement sa priorité et sa durée de vie
En survolant de la souris le titre de la programmation.
Voir ses données EPG
Les programmations qui ont le paramètre Vérification de l'auto-programmation à \"Identification de Transmission\" montreront les données EPG si vous cliquez sur le titre de la programmation.
Editer la programmation
Vous pouvez éditer la programmation en cliquant sur \"éditer\".
Supprimer une programmation
Pour supprimer une programmation vous devez cliquer sur \"supprimer\".

Les états de programmation sont indiqués par des cases de couleurs différentes (dans le vue avec graphique) ou des images (dans la vue par liste) :
    / \"on\" La programmation est OK et enregistrera.
    / \"problem\" La programmation est conflictuelle avec une autre programmation. Cela n'est pas critique, tant que vous avez assez de cartes DVB que d'enregistrements.
    / \"impossible\" La programmation est critique et a beaucoup de chances de ne pas enregistrer.
    / \"inactive\" La programmation n'est pas active.

En plus de ces fonctions vous pouvez ajouter une nouvelle programmation en cliquant sur en haut et vous pouvez supprimer plusieurs programmations en cochant plusieurs programmations dans la dernière coloone de ces programmations et en cliquant sur .

Vous pouvez et les programmations sélectionnées.

" msgid "

Here you can edit a timer's settings.

" msgstr "

Ici vous pouvez modifier un programmation.

" msgid "Timer Active:" msgstr "Programmation Active :" msgid "Activate or deactivate this timer. Deactivated timers are still stored in the timer list so that they can be activated again, but they do not record anything meanwhile." msgstr "Active ou désactive une programmation. Les programmations désactivés sont toujours stockées dans la liste des programmations et peuvent être activées à nouveau, mais elles n'enregistrent néanmoins plus rien." msgid "AutoTimer Checking:" msgstr "Vérification Auto-Programmation :" msgid "Depending on how this timer has been programmed you have up to three possible settings:" msgstr "Suivant comment cette programmation à été définie,vous avez jusqu'à trois possibilités :" msgid "Transmission Identification" msgstr "Identification Transmission" msgid "Monitor this timer using the identification provided in the EPG. Please note that this only works if the provided identification is a fix and unique value! This option is not available with timers programmed in VDR." msgstr "Surveille cette programmation en utilisant l'identification fournie par le guide électronique des programmes. Notez que cela fonctionne seulement si l'identification est fixe et unique! Cette option n'est pas disponible avec les programmations créées dans VDR." msgid "Time" msgstr "Horaires" msgid "Monitor this timer using the start and stop time." msgstr "Surveille cette programmation en utilisant l'horaire de démarrage et d'arrêt." msgid "off" msgstr "off" msgid "Do not monitor this timer." msgstr "Ne surveille pas cette programmation." msgid "The channel to record." msgstr "La chaîne à enregistrer." msgid "Day Of Recording:" msgstr "Jour d'Enregistrement :" msgid "The day when the timer should get active. You can enter the day in two formats:
  • Two digits (DD). This will use the current month and year.
  • ISO norm (YYYY-MM-DD). Program your timers as far in the future as you like.
In case you want to program a repeating timer you can use the seven checkboxes below the text field. Check the box for each day you want the timer to get active." msgstr "Le jour où la programmation doit être active. Vous pouvez entrer le jour selon 2 formats :
  • 2 chiffres (JJ). Cela utilisera le mois et l'année courante.
  • ou la norme ISO (AAAA-MM-JJ). Vous pouvez programmer des programmations aussi loin dans le futur que vous le désirez.
Dans le cas où vous voulez programmer une programmation répétitive, vous pouvez utiliser les 7 cases à cocher en dessous du champ texte. Cochez les cases des jours pour lesquels vous désirez que la programmation soit active." msgid "Start Time:" msgstr "Heure De Début :" msgid "This is the time when the timer should start recording. The first text field is for \"hour\", the second for \"minute\"." msgstr "Ceci est l'heure de démarrage de la programmation. Le premier champ texte est pour \"heure\", le second pour \"minute\"." msgid "End Time:" msgstr "Heure De Fin :" msgid "This is the time when the timer should stop recording. The first text field is for \"hour\", the second for \"minute\"." msgstr "Ceci est l'heure de fin de la programmation. Le premier champ texte est pour \"heure\", le second pour \"minute\"." msgid "Title of Recording:" msgstr "Titre de l'Enregistrement :" msgid "The file name this timer will give to a recording. If the name shall contain subdirectories, these have to be delimited by '~' (since the '/' character may be part of a regular programme name).

The special keywords TITLE and EPISODE, if present, will be replaced by the title and episode information from the EPG data at the time of recording (if that data is available). If at the time of recording either of these cannot be determined, TITLE will default to the channel name, and EPISODE will default to a blank." msgstr "Le nom de fichier que cette programmation va donner à un enregistrement. Si ce nom devait contenir des sous-répertoires, ceux-ci devraient être délimités par '~' (le caractère '/' peut faire partie du nom d'un programme).

Si les mots clé TITLE et/ou EPISODE sont présents, ils seront remplacés par le titre et l'information sur l'épisode contenue dans les données EPG présentes au moment du lancement de l'enregistrement (si ces données existent). Si au moment de l'enregistrement ces variables ne peuvent être définies, TITLE sera remplacé par le nom de la chaîne, et EPISODE sera vide." msgid "Summary:" msgstr "Résumé :" msgid "Arbitrary text that describes the recording made by this timer. If this field is not empty, its contents will be written into the summary.vdr or info.vdr file of the recording." msgstr "Texte arbitraire qui décrit l'enregistrement fait par cette programmation. Si ce champ n'est pas vide, son contenu sera écrit dans le fichier summary.vdr ou info.vdr, le fichier de l'enregistrement." msgid "Your Browser does not support frames!" msgstr "Votre Navigateur ne supporte pas les cadres !" msgid "What's On Now?" msgstr "En ce Moment ?" msgid "Playing Today?" msgstr "Aujourd'hui ?" msgid "Remote Control" msgstr "Télécommande" msgid "Watch TV" msgstr "Regarder TV" msgid "Commands" msgstr "Commandes" msgid "Search" msgstr "Rechercher" msgid "Authorization Required" msgstr "Autorisation Requise" msgid "This server could not verify that you are authorized to access the document requested. Either you supplied the wrong credentials (e.g. bad password), or your browser doesn't understand how to supply the credentials required." msgstr "Le serveur n'a pas pu vérifier que vous êtes autorisé à accéder au document demandé. Ou vous avez fourni de mauvaises informations (par ex. mauvais mot de passe), ou votre navigateur n'a pu fournir les informations requises." msgid "VPS" msgstr "VPS" msgid "close" msgstr "fermer" msgid "view" msgstr "vue" msgid "search" msgstr "rechercher" msgid "edit" msgstr "éditer" msgid "Length" msgstr "" msgid "Video tracks:" msgstr "Piste vidéo :" msgid "Audio tracks:" msgstr "Piste audio :" msgid "Subtitles:" msgstr "Sous-titres:" msgid "Video tracks" msgstr "Pistes vidéo" msgid "Audio tracks" msgstr "Pistes audio" msgid "TV select" msgstr "Zapper" msgid "Stream" msgstr "Flux" msgid "Channel group:" msgstr "Groupe de la Chaîne :" msgid "Go!" msgstr "Ok !" msgid "Search for other show times" msgstr "Rechercher d'autres moments de diffusion" msgid "No Information" msgstr "Pas d'Information" msgid "No EPG information available" msgstr "Pas d'information EPG disponible" msgid "Playing Today" msgstr "Joué Aujourd'hui" msgid "starting at" msgstr "Commence à" msgid "What's on:" msgstr "En ce moment :" msgid "at" msgstr "à" msgid "now" msgstr "maintenant" msgid "to" msgstr "à" msgid "Duration:" msgstr "Durée :" msgid "min" msgstr "min" msgid "at:" msgstr "à :" msgid "You need JavaScript to use the timeline!" msgstr "Vous avez besoin de JavaScript pour utiliser la chronologie !" msgid "Rename Recording" msgstr "Nom Original d'Enregistrement :" msgid "Original Name of Recording:" msgstr "Nom Original d'Enregistrement :" msgid "New Name of Recording:" msgstr "Nouveau Nom d'Enregistrement :" msgid "Subtitle:" msgstr "Sous-titre :" msgid "Rename" msgstr "Renommer" msgid "Total:" msgstr "Total :" msgid "h" msgstr "h" msgid "Free:" msgstr "Libre :" msgid "Date" msgstr "Date" msgid "Total" msgstr "Total" msgid "New" msgstr "Nouveau" msgid "Play" msgstr "Lire" msgid "Cut" msgstr "Couper" msgid "Delete recording?" msgstr "Supprimer l'Enregistrement ?" msgid "Refresh" msgstr "Rafraîchir" msgid "Commands:" msgstr "Commandes :" msgid "Really run this command?" msgstr "Voulez-vous réellement exécuter cette commande ?" msgid "stream all recordings" msgstr "" msgid "Delete Selected Recordings" msgstr "Supprimer Enregistrements Sélectionnés" msgid "Delete all selected recordings?" msgstr "Supprimer Enregistrements Sélectionnés ?" msgid "No recordings available" msgstr "Aucun enregistrement disponible" msgid "Transponder:" msgstr "Transpondeur :" msgid "CA-System:" msgstr "Système CA :" msgid "New Timer" msgstr "Nouvelle Programmation" msgid "Edit timer status?" msgstr "Changer Statut Programmation ?" msgid "This timer is inactive!" msgstr "Cette Programmation est inactive !" msgid "This timer is impossible!" msgstr "Cette Programmation est impossible !" msgid "No more timers on other transponders possible!" msgstr "Pas plus de Programmations possibles sur d'autres transpondeurs !" msgid "Timer OK." msgstr "Programmation OK." msgid "Auto" msgstr "Auto" msgid "activate" msgstr "activer" msgid "inactivate" msgstr "désactiver" msgid "selected timers" msgstr "programmations sélectionnées" msgid "Delete Selected Timers" msgstr "Supprimer Programmations Sélectionnées" msgid "No timers defined!" msgstr "Aucune Programmation définie !" msgid "Create New Timer" msgstr "Créer Nouvelle Programmation" msgid "Buffer:" msgstr "Tampon :" msgid "Use VPS:" msgstr "Utiliser VPS :" msgid "readonly" msgstr "lecture seule" msgid "Timer has been set by AutoTimer pattern:" msgstr "La programmation a été auto-programmée avec le modèle :" msgid "TV" msgstr "TV" msgid "Interval:" msgstr "Intervalle :" msgid "sec." msgstr "sec." msgid "G" msgstr "R" msgid "Grab the picture!" msgstr "Rafraîchir!" msgid "Size:" msgstr "Taille :" msgid "Open in separate window" msgstr "Ouvrir dans une nouvelle fenêtre" msgid "VDR Commands" msgstr "Commandes VDR" msgid "Export channels as playlist:" msgstr "Exporter les chaînes en tant que playlist :" msgid "Number of lines to show:" msgstr "Nombre de lignes à montrer :" msgid "unlimited" msgstr "illimité" msgid "SVDRP commands:" msgstr "Commandes SVDRP :" msgid "Commands defined in commands.conf:" msgstr "Commandes définies dans commands.conf :" msgid "Output" msgstr "Sortie" msgid "What's your VDR hostname (e.g video.intra.net)?" msgstr "Quel est votre Nom d'hôte (ex video.intra.net) ?" msgid "On which port does VDR listen to SVDRP queries?" msgstr "Sur quel port VDR écoute les requêtes SVDRP ?" msgid "On which address should VDRAdmin-AM listen (0.0.0.0 for any)?" msgstr "Sur quelle adresse VDRAdmin-AM doit-il écouter (0.0.0.0 pour toutes) ?" msgid "On which port should VDRAdmin-AM listen?" msgstr "Sur quel port VDRAdmin-AM doit-il écouter ?" msgid "Username?" msgstr "Identifiant ?" msgid "Password?" msgstr "Mot de Passe ?" msgid "Where are your recordings stored?" msgstr "Où vos enregistrements sont-ils stockés ?" msgid "Where are your VDR's configuration files located?" msgstr "Où sont vos fichiers de configuration de VDR ?" msgid "Config file written successfully." msgstr "Fichier de configuration écrit avec succès." #, perl-format msgid "%s %s started with pid %d." msgstr "%s %s a démarré avec le pid %d." msgid "Not found" msgstr "Non trouvé" msgid "The requested URL was not found on this server!" msgstr "L'URL demandée n'a pas été trouvée sur le serveur !" msgid "Forbidden" msgstr "Interdit" msgid "You don't have permission to access this function!" msgstr "Vous n'avez pas la permission d'accéder à cette fonction !" msgid "All channels" msgstr "Toutes les Chaînes" msgid "Selected channels" msgstr "Chaînes Sélectionnées" msgid "TV channels" msgstr "Chaînes TV" msgid "Radio channels" msgstr "Chaînes Radio" #, perl-format msgid "Access to file \"%s\" denied!" msgstr "Accès au fichier \"%s\" interdit !" #, perl-format msgid "The URL \"%s\" was not found on this server!" msgstr "L'URL \"%s\" n'a pas été trouvée sur le serveur !" msgid "Your favorites" msgstr "Vos favoris" msgid "Search results" msgstr "Résultats de la Recherche" msgid "Default" msgstr "Par défaut" msgid "--- no timer ---" msgstr "--- pas de programmations ---" msgid "unknown" msgstr "inconnu" msgid "none" msgstr "aucun" #, perl-format msgid "Can't open file \"%s\"!" msgstr "Ne peut pas ouvrir le fichier \"%s\" !" #, perl-format msgid "Can't connect to VDR at %s:%s: %s

Please check if VDR is running and if VDR's svdrphosts.conf is configured correctly." msgstr "Connexion impossible vers VDR %s:%s: %s

Merci de vérifier que VDR est lancé et que le fichier svdrphosts.conf est configuré correctement." #, perl-format msgid "Error while sending command to VDR at %s" msgstr "Erreur en envoyant la commande à %s" msgid "Internal error:" msgstr "Erreur Interne :" msgid "Lookup movie in the Internet-Movie-Database (IMDb)" msgstr "Plus de détails sur Internet" msgid "Can't find EPG entry!" msgstr "Aucune entrée EPG trouvée !" msgid "Playing Tomorrow" msgstr "Joué demain" #, perl-format msgid "Playing on the %s" msgstr "Lecture en cours sur la %s" msgid "next" msgstr "suivant" msgid "What's on after" msgstr "Que se passe-t-il ensuite" msgid "What's on at" msgstr "Que se passe-t-il à telle heure" msgid "Suitable matches for:" msgstr "Correspondances trouvées pour :" msgid "short view" msgstr "Court aperçu" msgid "long view" msgstr "Long aperçu" msgid "Schedule" msgstr "Programmateur" #, perl-format msgid "Can't write configuration file %s! Reason: %s" msgstr "" #, perl-format msgid "Configuration file %s not writable! Configuration won't be saved!" msgstr "" msgid "Timers" msgstr "Programmations" msgid "System default" msgstr "Par défaut" vdradmin-am-3.6.13/po/hu.po000066400000000000000000001413601443716113400154060ustar00rootroot00000000000000# Copyright (C) Andreas Mair # This file is distributed under the same license as the VDRAdmin-AM package. # # TRANSLATOR , YEAR # # # Translators, if you are not familiar with the PO format, gettext # documentation is worth reading, especially sections dedicated to # this format, e.g. by running: # info -n '(gettext)PO Files' # info -n '(gettext)Header Entry' # # Some information specific to po-debconf are available at # /usr/share/doc/po-debconf/README-trans # or http://www.debian.org/intl/l10n/po-debconf/README-trans # # Developers do not need to manually edit POT or PO files. # msgid "" msgstr "" "Project-Id-Version: VDRAdmin-AM 3.6.8\n" "Report-Msgid-Bugs-To: Andreas Mair \n" "POT-Creation-Date: 2012-07-09 12:23+0200\n" "PO-Revision-Date: 2011-12-07 12:42+0200\n" "Last-Translator: Füley István \n" "Language-Team: Hungarian \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" msgid "About" msgstr "Névjegy" msgid "License" msgstr "Licensz" msgid "Authors" msgstr "SzerzÅ‘k" msgid "Current author (VDRAdmin-AM branch):" msgstr "Jelenlegi szerzÅ‘ (VDRAdmin-AM ág):" msgid "Original author (VDRAdmin):" msgstr "Eredeti szerzÅ‘ (VDRAdmin):" msgid "Translation Team" msgstr "Fordító csapat" msgid "English:" msgstr "Angol:" msgid "German:" msgstr "Német:" msgid "French:" msgstr "Francia:" msgid "At the moment unmaintained, former translations by:" msgstr "Jelenleg nincs karbantartva, korábbi fordító" msgid "Spanish:" msgstr "Spanyol:" msgid "Finnish:" msgstr "Finn:" msgid "Dutch:" msgstr "Holland:" msgid "Russian:" msgstr "Orosz:" msgid "Czech:" msgstr "Cseh:" msgid "Italian:" msgstr "Olasz:" msgid "Hungarian:" msgstr "" msgid "Information" msgstr "Infó" msgid "VDRAdmin-AM version:" msgstr "VDRAdmin-AM verzió:" msgid "VDR version:" msgstr "VDR verzió:" msgid "Supported features in VDR:" msgstr "VDR által támogatott szolgáltatások:" msgid "EPGSearch" msgstr "EPGSearch" msgid "EPGSearch Plugin" msgstr "EPGSearch Plugin" msgid "LiveTV Streaming" msgstr "ÉlÅ‘kép streaming" msgid "Streamdev Plugin" msgstr "Streamdev Plugin" msgid "Xineliboutput Plugin" msgstr "Xineliboutput Plugin" msgid "Rename Recordings (Liemikuutio Patch)" msgstr "Felvételek átnevezése (Liemikuutio Patch)" msgid "Getting Help and Reporting Bugs" msgstr "Segítség és hibák jelentése" msgid "If you need help please first try to use the online help you'll find on some pages. You can access it by clicking \"\"." msgstr "Ha segítségre van szükséged, elÅ‘ször nézd meg a helyenként elérhetÅ‘ online segítséget, erre a jelre kattintva \"\"." msgid "If this doesn't provide the information you need you can try to get help at VDR-Portal if you understand German language. Please use the announcement thread if possible, search for:" msgstr "Ha így nem találod meg a keresett információt, próbálkozhatsz itt VDR-Portal, ha értesz németül. Kérlek használd a bejelentés topikot, erre keress rá: " msgid "If you think you have found a bug please check that it's a new one and report it in the VDRAdmin-AM BugTracking system." msgstr "Amennyiben úgy gondolod, hogy egy hibát találtál, kérlek ellenÅ‘rizd, hogy ez egy új hiba, és kérlek jelentsd be a VDRAdmin-AM hibakövetÅ‘ rendszerén." msgid "AutoTimer" msgstr "AutoidÅ‘zítÅ‘" msgid "Priority:" msgstr "Prioritás:" msgid "Lifetime:" msgstr "Élettartam:" msgid "New AutoTimer" msgstr "Új autoidÅ‘zítÅ‘" msgid "Help" msgstr "Segítség" msgid "Active" msgstr "Aktív" msgid "Channel" msgstr "Csatorna" msgid "Start" msgstr "Kezdet" msgid "Stop" msgstr "Vég" msgid "Name" msgstr "Név" msgid "Select all/none" msgstr "Válaszd ki az összest/egyiket se" msgid "Yes" msgstr "Igen" msgid "No" msgstr "Nem" msgid "Edit" msgstr "Szerkesztés" msgid "Delete timer?" msgstr "IdÅ‘zítÅ‘ törlése?" msgid "Delete" msgstr "Törlés" msgid "Force Update" msgstr "Frissítés kényszerítése" msgid "Delete Selected AutoTimers" msgstr "A kiválasztott autoidÅ‘zítÅ‘k törlése" msgid "Delete all selected timers?" msgstr "Az összes kiválasztott idÅ‘zítÅ‘ törlése?" msgid "No AutoTimers defined!" msgstr "Nincs meghatározott autoidÅ‘zítÅ‘" msgid "Add New AutoTimer" msgstr "Új autoidÅ‘zítÅ‘ hozzaadása" msgid "Edit AutoTimer" msgstr "AutoidÅ‘zítÅ‘ szerkesztése" msgid "AutoTimer Active:" msgstr "AutoidÅ‘zítÅ‘ aktív:" msgid "oneshot" msgstr "egyszeri" msgid "Search Patterns:" msgstr "Keresési minta:" msgid "Search in:" msgstr "Keresés helye:" msgid "Title" msgstr "Cím" msgid "Subtitle" msgstr "Alcím" msgid "Description" msgstr "Leírás" msgid "Search only on these days:" msgstr "Csak ezeken a napokon keresse:" msgid "Monday" msgstr "HétfÅ‘" msgid "Tuesday" msgstr "Kedd" msgid "Wednesday" msgstr "Szerda" msgid "Thursday" msgstr "CSütörtök" msgid "Friday" msgstr "Péntek" msgid "Saturday" msgstr "Szombat" msgid "Sunday" msgstr "Vasárnap" msgid "Channel:" msgstr "Csatorna:" msgid "all" msgstr "mind" msgid "Starts After:" msgstr "Ezután kezdÅ‘dik:" msgid "o'clock" msgstr " " msgid "Ends Before:" msgstr "BefejezÅ‘dik ezelÅ‘tt:" msgid "Override Start/Stop Margins:" msgstr "A kezdési/lejárati határok felülírása:" msgid "Time Margin at Start:" msgstr "IdÅ‘eltolás a műsor kezdetnél:" msgid "minutes" msgstr "perc" msgid "Time Margin at Stop:" msgstr "IdÅ‘eltolás a műsor végénél:" msgid "Episode:" msgstr "Epizód:" msgid "Remember programmed timers:" msgstr "A beállított felvételek megjegyzése:" msgid "Directory:" msgstr "Könyvtár:" msgid "Save" msgstr "Mentés" msgid "Test" msgstr "Teszt" msgid "Cancel" msgstr "Mégsem" msgid "Broadcasted" msgstr "Adás idÅ‘pontja" msgid "Stored in" msgstr "Tárolva" msgid "No matches found!" msgstr "Nincs találat!" msgid "Configuration" msgstr "Beállítások" msgid "General Settings" msgstr "Ãltalános beállítások" msgid "Template:" msgstr "Sablon:" msgid "Skin:" msgstr "BÅ‘r:" msgid "Login Page:" msgstr "BejelentkezÅ‘ oldal:" msgid "Number of channels to use:" msgstr "Hány csatornát használjunk:" msgid "Local net (no login required):" msgstr "Helyi hálózat (bejelentkezés nem szükséges):" msgid "Language:" msgstr "Nyelv:" msgid "Save settings on exit:" msgstr "Kilépéskor a beállítások mentése:" msgid "VDR" msgstr "VDR" msgid "Number of DVB cards:" msgstr "DVB adapterek száma:" msgid "Path to recordings:" msgstr "Felvételek könyvtára:" msgid "Path to configuration files:" msgstr "konfigurációs fileok könyvtára:" msgid "Path to EPG images:" msgstr "EPG képek könyvtára:" msgid "Identification" msgstr "Azonosítás" msgid "Username:" msgstr "Felhasználónév:" msgid "Password:" msgstr "Jelszó:" msgid "Guest Account:" msgstr "Vendég azonosító:" msgid "Guest Username:" msgstr "Vendég felhasználónév:" msgid "Guest Password:" msgstr "Vendég jelszó:" msgid "Timeline" msgstr "IdÅ‘sáv" msgid "Hours:" msgstr "Óra:" msgid "Times:" msgstr "IdÅ‘pontok:" msgid "Also used for other EPG views!" msgstr "Egyéb EPG nézetekhez is használva lesz." msgid "Tooltips:" msgstr "Tippek a kurzornál:" msgid "Electronic Program Guide (EPG)" msgstr "Elektrnikus műsorfüzet (EPG)" msgid "Day begins at:" msgstr "Ekkor kezdÅ‘dik a nap:" msgid "Show Subtitle:" msgstr "Feliratok:" msgid "Show Summary:" msgstr "Leírás:" msgid "Active:" msgstr "Aktív:" msgid "Send email after programming timer:" msgstr "Email küldése az idÅ‘zítÅ‘ beállítása után:" msgid "Send email as:" msgstr "Email feladója:" msgid "Send email to:" msgstr "Email címzettje:" msgid "Mail server:" msgstr "Mail szerver:" msgid "SMTPAuth user:" msgstr "SMTPAuth felhasználónév:" msgid "SMTPAuth password:" msgstr "SMTPAuth jelszó:" msgid "Track schedule changes by:" msgstr "Programváltozás követése:" msgid "Broadcast time" msgstr "Adás idÅ‘pontja" msgid "Event id" msgstr "Esemény id" msgid "Timer" msgstr "IdÅ‘zítÅ‘" msgid "Tooltips in timeline:" msgstr "Tippek az idÅ‘sávban:" msgid "Tooltips in list:" msgstr "Tippek a listákban:" msgid "Streaming" msgstr "Streaming" msgid "Live Streaming:" msgstr "ÉlÅ‘kép streaming:" msgid "HTTP Port of Streamdev (also possible 3000/ts):" msgstr "A Streamdev HTTP Portja (3000/ts is lehetséges):" msgid "HTTP Port of Xineliboutput (e.g. 37890):" msgstr "A Xineliboutput HTTP portja (pl. 37890):" msgid "Recordings Streaming:" msgstr "Felvételek Streamingje:" msgid "Path to VDR Recordings on your workstation:" msgstr "A VDR felvételek könyvtára a helyi gépen:" msgid "MIME type for live streaming:" msgstr "Az élÅ‘ stream MIME tipusa:" msgid "Suffix for live streaming:" msgstr "Az élÅ‘ stream filekiterjesztése:" msgid "MIME type for recordings streaming:" msgstr "A felvétel streamek MIME tipusa:" msgid "Suffix for recordings streaming:" msgstr "Az felvétel stream filekiterjesztése:" msgid "Bandwidth of Streams:" msgstr "A streamek sávszélessége:" msgid "External Search" msgstr "KülsÅ‘ keresÅ‘" msgid "URL:" msgstr "URL:" msgid "Title:" msgstr "Cím:" msgid "User-defined search:" msgstr "Felhasználó által definiált keresések:" msgid "Expert" msgstr "Haladó" msgid "Update EPG data in background:" msgstr "Az EPG adatok frissítése a háttérben:" msgid "Update EPG every:" msgstr "Automatikus EPG frissítési intervallum:" msgid "Channel Selections" msgstr "Csatornák kiválasztása" msgid "Show channels without EPG information:" msgstr "EPG nélküli csatornák:" msgid "In \"AutoTimer\"?" msgstr " \"AutoTimer\" -ben/ban?" msgid "Apply" msgstr "Alkalmazd" msgid "EPG Search Blacklists" msgstr "EPG keresési tiltólista" msgid "New Blacklist" msgstr "Új tiltólista" msgid "Search pattern" msgstr "Keresési minta" msgid "From" msgstr "EttÅ‘l" msgid "To" msgstr "Eddig" msgid "Delete blacklist?" msgstr "Tiltólisták törlése?" msgid "Delete Selected Blacklists" msgstr "Kijelölt tiltóéisták törlése" msgid "Delete all selected blacklists?" msgstr "A kijelölt tiltólisták törlése?" msgid "EPG search" msgstr "Keresés az EPG-ben" msgid "EPG Search" msgstr "EPG Search" msgid "Use template" msgstr "Használd a sablont" msgid "New Search" msgstr "Új keresés" msgid "Edit Template" msgstr "Sablon szerkesztése" msgid "Settings" msgstr "Beállítások" msgid "Action" msgstr "Művelet" msgid "Find" msgstr "Keresd" msgid "Show Favorites" msgstr "Kedvencek" msgid "Delete Selected Searches" msgstr "A kijelölt keresések törlése" msgid "Delete all selected searches?" msgstr "A kijelölt keresések törlése?" msgid "Execute Selected Searches" msgstr "A kijelölt keresések végrehajtása" msgid "Duration" msgstr "IdÅ‘tartam" msgid "More Information" msgstr "További részletek" msgid "Channels" msgstr "Csatornák" msgid "Record" msgstr "Felvétel" msgid "Add New Blacklist" msgstr "Új tiltólista" msgid "Edit Blacklist" msgstr "Tiltólista szerkesztése" msgid "Add New Template" msgstr "Új sablon létrehozása" msgid "Add New Search" msgstr "Új keresés létrehozása" msgid "Edit Search" msgstr "Keresés szerkesztése" msgid "Small search pattern.\\nDo you really want to use it?" msgstr "Túl rövid minta.\\nBiztos ezt akarod használni?" msgid "You didn't select at least one of\\ntitle, subtitle or description.\\nDo you really want to use this search?" msgstr "Egyetlen címet, alcimet vagy\\nleírást sem választottál ki\\nBiztos ezt akarod használni?" msgid "Hide results" msgstr "Eredmények elrejtése" msgid "Name:" msgstr "Név:" msgid "Search Term:" msgstr "Keresési frázis:" msgid "Search Mode:" msgstr "Keresés módja:" msgid "phrase" msgstr "kifejezés" msgid "all words" msgstr "öszes szóra" msgid "at least one word" msgstr "legalább egy szóra" msgid "match exactly" msgstr "pontos találat" msgid "regular expression" msgstr "szabályos kifejezés" msgid "fuzzy" msgstr "fuzzy" msgid "Tolerance for \"fuzzy\":" msgstr "\"fuzzy\" toleranciája:" msgid "Match Case:" msgstr "Kis nagybetű számít:" msgid "Use extended EPG info:" msgstr "A kiterjesztett EPG infóban is:" msgid "Ignore missing categories?" msgstr "A hiányzó kategóriákat figyelmen kivül hagyjuk?" msgid "Use Channel:" msgstr "Csatorna használata:" msgid "no" msgstr "nem" msgid "interval" msgstr "intervallum" msgid "channel group" msgstr "csatornacsoport" msgid "only FTA" msgstr "csak FTA" msgid "Range:" msgstr "Tartomány:" msgid "Channel Group:" msgstr "Csatornacsoport:" msgid "Use Time:" msgstr "Műsor idÅ‘pontja:" msgid "Start After:" msgstr "Ezután kezdÅ‘dÅ‘ műsor:" msgid "Start Before:" msgstr "EzelÅ‘tt kezdÅ‘dÅ‘ műsor:" msgid "Use Duration:" msgstr "IdÅ‘tartam:" msgid "Min. Duration:" msgstr "Min. idÅ‘tartam:" msgid "hh:mm" msgstr "óó:pp" msgid "Max. Duration:" msgstr "Max. idÅ‘tartam:" msgid "Use Day of Week:" msgstr "Hét napja:" msgid "Use Blacklists:" msgstr "Tiltólista:" msgid "selection" msgstr "kiválasztás" msgid "Use in Favorites Menu:" msgstr "Felhasználni a kedvencek menüben:" msgid "Use as Search Timer:" msgstr "Felhasználni keresési idÅ‘zítÅ‘ként:" msgid "yes" msgstr "igen" msgid "user-defined" msgstr "felhasználó-programozott" msgid "record" msgstr "felvétel" msgid "announce by OSD" msgstr "OSD-n megjeleníteni" msgid "switch only" msgstr "csak átkapcsolni" msgid "announce and switch" msgstr "megjeleníteni és átkapcsolni" msgid "announce by mail" msgstr "emailt küldeni" msgid "First day:" msgstr "ElsÅ‘ nap:" msgid "Last day:" msgstr "Utolsó nap:" msgid "Auto delete:" msgstr "Automatikusan törölni:" msgid "count recordings" msgstr "felvételek számlálása" msgid "count days" msgstr "napok számlálása" msgid "After ... recordings:" msgstr "Ennyi felvétel után:" msgid "After ... days after first recording:" msgstr "Az elsÅ‘ felvétel után ennyi nappal:" msgid "Settings for action \"record\"" msgstr " \"felvétel\" beállításai" msgid "Series Recording:" msgstr "Sorozat felvétel:" msgid "Delete Recordings After ... Days:" msgstr "Felvételek törlése ... nap után:" msgid "Keep ... Recordings:" msgstr "... felvételek megtartása:" msgid "Pause, when ... recordings exist:" msgstr "Szünet, mikor a ... felvétel létezik:" msgid "Avoid Repeats:" msgstr "Ismétlések kerülése:" msgid "Allowed Repeats:" msgstr "Engedélyezett ismétlések:" msgid "Only Repeats Within ... Days:" msgstr "... napon belüli ismétlés:" msgid "Compare:" msgstr "Összehasonlítani:" msgid "Minimal match of description in %:" msgstr "A leírások minimális hasonlósága %-ban:" msgid "VPS:" msgstr "VPS:" msgid "Settings for action \"switch only\"" msgstr " \"csak átkapcsolni\" beállításai" msgid "Switch ... Minutes Before Start:" msgstr "Ãtkapcsolni ... perccel a kezdés elÅ‘tt:" msgid "Unmute sound:" msgstr "Némiítás:" msgid "Settings for action \"announce and switch\"" msgstr "\"megjeleníteni és átkapcsolni\" beállításai" msgid "Ask ... Minutes Before Start:" msgstr "Rákérdez ... perccel a kezdés elÅ‘tt:" msgid "Delete template" msgstr "Sablon törlése" msgid "Delete this template?" msgstr "Töröljük ezt a sablont?" msgid "Save as template" msgstr "Mentés sablonként" msgid "Run" msgstr "Futtat" msgid "Error!" msgstr "Hiba!" msgid "

Here you will find a listing of automatic timers (AutoTimer) known to VDRAdmin-AM.

The list shows some information on AutoTimers. You can change the list's sorting by clicking the columns heading.

For each AutoTimer you have the following options:

Set its state
By clicking on \"Yes\" or \"No\" in the \"Active\" column to toggle the activity.
Quickly view its priority and lifetime
By pointing the mouse cursor to the AutoTimer's title.
Edit the AutoTimer
You can edit an AutoTimer by clicking \"edit\".
Delete the AutoTimer
To delete an AutoTimer you click \"delete\".

Each AutoTimer's state is indicated by differently coloured images:
\"on\" AutoTimer is OK and will automatically program matching broadcasts.
\"inactive\" AutoTimer is not active.

In addition to these functions you can add a new AutoTimer by clicking at the top and you can delete a number of AutoTimers at once by checking the box in the last column of those timers and clicking .

Click to force VDRAdmin-AM to reconnect to VDR, fetch the current EPG and check for matching AutoTimers.

" msgstr "" msgid "

Here you can edit an automatic timer's (AutoTimer) settings.

AutoTimer is a key feature of VDRAdmin-AM. An AutoTimer consists of one or more search terms and some other settings, that are looked for regularly in the Electronic Program Guide (EPG). On match AutoTimer adds a timer in VDR automatically for that broadcast. That's very comfortable for irregularly broadcasted series or movies you don't want to miss.

" msgstr "" msgid "Activate or deactivate this AutoTimer. Deactivated AutoTimers are still stored in the AutoTimer list so that they can be activated again, but they do not record anything meanwhile. Above that you can set this to \"oneshot\" so this AutoTimer only programs the (one!) next matching broadcast." msgstr "" msgid "Choosing the right search items decides whether only the wanted broadcasts or broadcasts having similar names or even nothing gets recorded.
Case doesn't matter, \"X-Files\" matches anything \"x-files\" will match. You can set multiple search items by separating them with spaces. Broadcasts will match only if they match all configured search items.
You'd better only use letters and numbers for search items, as the EPG often miss colons, brackets and other characters.
Experts can also use regular expressions, but you have to get needed information from the VDRAdmin-AM sources (undocumented feature).

You can exclude broadcasts so that they don't get recorded even if they would match an AutoTimer. Therefore you have to enter that titles into the file vdradmind.bl, one event a line. This file must be located in your VDRAdmin-AM's configuration folder. If this string is found either in the EPG's title or in title~subtitle, this event will not be programmed by AutoTimer. So you can disable complete episodes (for example when using \"Enterprise\" as blacklist string) or only one episode (when using \"Enterprise~Azati Prime\" as blacklist string)." msgstr "" msgid "Here you can define the EPG sections where VDRAdmin-AM should look for the search pattern." msgstr "" msgid "Use these checkboxes to limit searching for matching broadcasts to a set of weekdays." msgstr "" msgid "The channel to look for matching broadcasts or \"all\" to search in all known or wanted channels. You can define the wanted channels for AutoTimer in \"Configuration\"." msgstr "" msgid "A broadcast must start after the time entered here to match. The first text field is for \"hour\", the second for \"minute\"." msgstr "" msgid "A broadcast must end before the time entered here to match. The first text field is for \"hour\", the second for \"minute\"." msgstr "" msgid "Set this option to \"yes\" if all timers programed by this AutoTimer should have individual start/stop margins and enter the values in the next two text boxes." msgstr "" msgid "The number of minutes VDRAdmin-AM subtracts from the broadcast's start time found in the EPG." msgstr "" msgid "The number of minutes VDRAdmin-AM adds to the broadcast's stop time found in the EPG." msgstr "" msgid "An integer in the range 0...99, defining the priority of this timer and of recordings created by this timer. 0 represents the lowest value, 99 the highest. The priority is used to decide which timer shall be started in case there are two or more timers with the exact same start time. The first timer in the list with the highest priority will be used.

This value is also stored with the recording and is later used to decide which recording to remove from disk in order to free space for a new recording. If the disk runs full and a new recording needs more space, an existing recording with the lowest priority (and which has exceeded its guaranteed lifetime) will be removed.

If all available DVB cards are currently occupied, a timer with a higher priority will interrupt the timer with the lowest priority in order to start recording." msgstr "" msgid "The guaranteed lifetime (in days) of a recording created by this timer. 0 means that this recording may be automatically deleted at any time by a new recording with higher priority. 99 means that this recording will never be automatically deleted. Any number in the range 1...98 means that this recording may not be automatically deleted in favour of a new recording, until the given number of days since the start time of the recording has passed by." msgstr "" msgid "Check this box if you want VDRAdmin-AM to append the broadcast's EPG subtitle to the recording's file name." msgstr "Pipáld be ezt az opciót, ha szeretnéd hogy a VDRAdmin-AM hozzaadja a felvétel filenevéhez az EPG alcímet." msgid "If you enable this VDRAdmin-AM will track timers it has already programmed automatically. This is useful if want to deactivate or delete timers that have been programmed automatically in the timers listing." msgstr "" msgid "The directory this AutoTimer will place the recordings in. If the name shall contain subdirectories, these have to be delimited by '~' (since the '/' character may be part of a regular programme name).
VDRAdmin-AM will append the matching broadcast's title and subtitle (if the \"Episode\" checkbox is marked) to the directory given here.

You can also use the following keywords that are replaced in the final file name by the values supplied by for example tvm2vdr:
  • %Title% - will become the title of the event.
  • %Subtitle% - will become the subtitle of the event.
  • %Director% - will become the director of the event.
  • %Date% - will become the date of the recording.
  • %Category% - will become the category of the event (Spielfilm/Serie/...).
  • %Genre% - will become the genre of the event (Drama/Krimi/..).
  • %Year% - will become the year of production.
  • %Country% - will become the country of production.
  • %Originaltitle% - will become the original title of the event.
  • %FSK% - will become the FSK from the event.
  • %Episode% - will become the episode's title of the event.
  • %Rating% - will become the rating of the event from the EPG provider.

Note:

If you use the above keywords it's in your own responsibility to supply the complete file name for the recordings! VDRAdmin-AM will not append anything to the resulting string." msgstr "" msgid "

Here you can change general settings and base settings for timers, AutoTimers, channel selection and streaming parameters.

" msgstr "" msgid "The skin you want to use." msgstr "A bőr (skin), amit használni szeretnél." msgid "The page you want to see at first connect to VDRAdmin-AM." msgstr "Bejelentkezés után ez az oldal lesz látható." msgid "VDRAdmin-AM will load the given number of channels from VDR and present only those in any fields where channels can be selected. This also limits the EPG information VDRAdmin-AM will read so that you can use this to reduce VDRAdmin-AM's memory consumption and increase its performance. 0 turns this feature off and VDRAdmin-AM will use all available channels." msgstr "" msgid "Here you can specify subnets from which access to VDRAdmin-AM does not require logging in. For example: \"192.168.0.0/24\" will include any IP starting with \"192.168.0.\", \"192.168.0.123/32\" will only match \"192.168.0.123\". Multiple subnets can be specified by separating them with spaces or commas." msgstr "" msgid "Here you can set the localization VDRAdmin-AM should use." msgstr "Beállíthatod a VDRAdmin-AM által használt nyelvet." msgid "With this option the settings will be saved if VDRAdmin-AM exits. This will also save settings not available on the \"Configuration\" menu like interval and size in TV, sorting in the lists and current view in \"What's on now\"." msgstr "" msgid "Top" msgstr "Fel" msgid "The number of DVB cards VDR can access. Depending on this value VDRAdmin-AM will calculate critical timers in the Timer menu." msgstr "" msgid "The path to VDR's recordings. It's used so that VDRAdmin-AM can locate the recordings when using Recordings Streaming and reccmds.conf in the Recordings menu." msgstr "" msgid "The path where VDR's configuration files are located. If this directory contains the file reccmds.conf its content is shown in a selectbox in the Recordings menu." msgstr "" msgid "The path where the EPG images are stored." msgstr "Az EPG képek elérési útja." msgid "The username for the main user, i.e. the user having the most privileges." msgstr "" msgid "The main user's password." msgstr "A fő felhasználó jelszava." msgid "If you want a user account having only limited privileges, this is for you. The guest user cannot modify anything, it's only allowed to view the EPG, timers, AutoTimers and recordings listings." msgstr "" msgid "The username for the guest user." msgstr "A vendégfelhasználó neve." msgid "The guest user's password." msgstr "A vendégfelhasználó jelszava." msgid "The number of hours to show in the timeline." msgstr "Az idősávban megjelenítendő időintervallum hossza órákban." msgid "A comma separated list of times in hh:mm format that appear in the selectbox placed at the top." msgstr "" msgid "Here you can (de-)activate the tooltips." msgstr "Itt tudod kikapcsolni a tippeket." msgid "The time after which events are shown on a new day. For example setting 03:00 means that today's schedule will include any event starting before 03:00 tomorrow. Applies only to the 'Playing Today?' list." msgstr "" msgid "Show the 'Subtitle' text for each event. Not all broadcasters use this field." msgstr "" msgid "Show the 'Summary' text for each event." msgstr "" msgid "Activate or deactivate the AutoTimer function." msgstr "" msgid "VDRAdmin-AM will send an email whenever an event matches an AutoTimer and a timer has been programmed if you enable this feature." msgstr "" msgid "Here you set the sending email address of the generated email." msgstr "" msgid "The email address the email is sent to." msgstr "" msgid "The outgoing mail server." msgstr "" msgid "If you need to authenticate yourself at the outgoing mail server, you have to supply the username and the password below. Leaving this field empty will disable SMTPAuth." msgstr "" msgid "The password for the SMTPAuth user." msgstr "" msgid "Here you can (de-)activate the tooltips in the timeline." msgstr "" msgid "Here you can (de-)activate the tooltips in the list." msgstr "" msgid "Add summary to new timers:" msgstr "" msgid "If you don't want VDRAdmin-AM to add the summary taken from EPG to new timers you can switch it off here." msgstr "" msgid "Enable or disable live streaming using the streamdev plugin. You also have to set the correct HTTP Port for Streamdev below." msgstr "" msgid "Here you have to set the port number your VDR's streamdev server listens for connections. Additionally you can also provide the stream type you like to use." msgstr "" msgid "Enable or disable streaming of recordings.
Well actually this is no real \"streaming\", but you have to setup your workstation so that it can access VDR's recordings. You can use for example Samba or NFS for this. VDRAdmin-AM simply generates a playlist that contains all parts of the recording and sends this to your browser. If your browser and media player are configured correctly you will see the recording on your workstation's display." msgstr "" msgid "This is the path where your workstation can access VDR's recordings. This depends on your VDR and workstation setup, for example \"\\\\vdr\\videos\" or \"V:\\\" (on Windows) or \"/mnt/videos\" (on Linux)." msgstr "" msgid "The MIME type to send when using live streaming. Defaults to \"video/x-mpegurl\"." msgstr "" msgid "The suffix to use for live streaming. Defaults to \"m3u\"." msgstr "" msgid "The MIME type to send when using recordings streaming. Defaults to \"video/x-mpegurl\"." msgstr "" msgid "The suffix to use for recordings streaming. Defaults to \"m3u\"." msgstr "" msgid "

Here you can define two external searches that you can access in the EPG views. You simply have to find the required URL and where the search pattern has to be located. %TITLE% will be substituted by the broadcast's EPG title.

" msgstr "" msgid "Some examples:" msgstr "Néhány példa:" msgid "Please change the hostname to your local needs!" msgstr "" msgid "

This section is for experts only, i.e. you know what you are doing!

" msgstr "" msgid "If set to \"yes\" VDRAdmin-AM will periodically refresh its local EPG cache. Else the EPG will be refreshed if the user accesses any EPG view at the web interface and the timeout set at \"Update EPG every\" has been reached." msgstr "" msgid "The interval, the EPG data is refreshed from VDR and AutoTimer updates are performed (if AutoTimer feature is used)." msgstr "" msgid "

If you want to limit the number of channels used in some parts of VDRAdmin-AM, this is for you!

Use the radio buttons to activate or deactivate the wanted channels in the named menu.

To add channels to the list of wanted channels you have to select them in the left side selectbox and click . If you want to remove channels from the list of wanted channels you have to select them in the right side selectbox and click .

" msgstr "" msgid "Usually channels that don't have EPG information are hidden in all EPG views. If you don't want them to be hidden you have to set this option to \"yes\"." msgstr "" msgid "Edit Timer" msgstr "Időzítő szerkesztése" msgid "Edit EPG" msgstr "EPG szerkesztése" msgid "

Here you can edit the descriptive fields of an existing EPG entry.

" msgstr "" msgid "Channel (readonly)" msgstr "Csatorna (csak olvasható)" msgid "This is the channel of the EPG entry. It cannot be changed." msgstr "" msgid "Time (readonly)" msgstr "Időpont (csak olvasható)" msgid "This is the start and end time of the entry. It cannot be changed." msgstr "" msgid "Change this string to give this EPG Entry a new title. It must consist of only one line of text." msgstr "" msgid "Change this string to give this EPG Entry a new subtitle. It must consist of only one line of text." msgstr "" msgid "Change the text in this field to edit the description of this entry. The text can consist of one or more lines." msgstr "" msgid "VPS (readonly)" msgstr "VPS (csak olvasható)" msgid "If available this field shows the vps time of the EPG entry. It cannot be changed." msgstr "" msgid "Video tracks (readonly)" msgstr "Videó sávok (csak olvasható)" msgid "If available this field shows the video track(s). It cannot be changed." msgstr "" msgid "Audio tracks (readonly)" msgstr "Hangsávok (csak olvasható)" msgid "If available this field shows the audio track(s). It cannot be changed." msgstr "" msgid "No Help Available" msgstr "Nincs elérhető help." msgid "

No help available yet. For adding or changing text please contact amair.sob@googlemail.com.

" msgstr "" msgid "Recordings" msgstr "Felvételek" msgid "

Here you will find a listing of recordings known to VDR. The headline will also show you VDR's total and free disk space.

The listing showing you some information on the recordings. You can change the list's sorting by clicking the columns heading. Above the list you'll see the navigation path. If you want to view the contents of previous folders you'll have to click on its name in that path.

Each row contains this information:

Date
The date when the recording has been done. In case of folders this will show the number of recordings the folder contains.
Time
The time when the recording has been done. In case of folders this will show the number of new recordings the folder contains.
Name
The recording's or folder's name. Click it to show the recording's summary or descend into the folder.
Rename (\"edit\")
Rename a recording.

Note:

This only works if VDR has the MOVR or RENR SVDRP command which is not a core VDR feature but provided by the Liemikuutio patch set.
Delete (\"delete\")
Delete a recording.
Stream (\"stream\")
This column is only shown if you activated and configured Recordings Streaming in the Configuration menu. You can watch the recording at your workstation.

In addition to these functions you can delete a number of recordings at once by checking the box in the last but one column of those recordings and clicking .

If you've set the path the VDR's configuration files and have entries in VDR's reccmds.conf you can run those commands for the selected recording by selecting the wanted command in the select box locate next to Commands: and pressing the button.

Use to force reloading of VDR's recordings listing.

" msgstr "" msgid "

Here you will find a listing of timers known to VDR.

On top you will find a chart showing a day's timers graphically. This provides an quick overview on what's going on at the specified day and helps you in finding conflicting timers. Moving the mouse cursor above any timer box will display a tooltip containing the timer's title, priority, lifetime and duration.

Below the chart you'll find the timers list showing you some information on the timers. You can change the list's sorting by clicking the columns heading.

For each timer you have the following options:

Set its state
By clicking on \"Yes\", \"No\", \"VPS\" or \"Auto\" in the \"Active\" column.
Quickly view its priority and lifetime
By pointing the mouse cursor to the timer's title.
View its EPG entry
Timers that have set AutoTimer Checking to \"Transmission Identification\" will show you the corresponding EPG entry if you click on the timer's title.
Edit the timer
You can edit a timer by clicking \"edit\".
Delete the timer
To delete a timer you click \"delete\".

Each timer's state is indicated by differently coloured boxes (in the chart view) or images (in the list view):
    / \"on\" Timer is OK and will record.
    / \"problem\" Timer conflicts with other timers. That's not critical, as long as you have enough DVB cards for the parallel recordings.
    / \"impossible\" Timer is critical and will most likely not record.
    / \"inactive\" Timer is not active.

In addition to these functions you can add a new timer by clicking at the top and you can delete a number of timers at once by checking the box in the last column of those timers and clicking .

You can and selected timers.

" msgstr "" msgid "

Here you can edit a timer's settings.

" msgstr "" msgid "Timer Active:" msgstr "Időzítő aktív:" msgid "Activate or deactivate this timer. Deactivated timers are still stored in the timer list so that they can be activated again, but they do not record anything meanwhile." msgstr "" msgid "AutoTimer Checking:" msgstr "Auto-időzítő ellenőrzés:" msgid "Depending on how this timer has been programmed you have up to three possible settings:" msgstr "" msgid "Transmission Identification" msgstr "" msgid "Monitor this timer using the identification provided in the EPG. Please note that this only works if the provided identification is a fix and unique value! This option is not available with timers programmed in VDR." msgstr "" msgid "Time" msgstr "Idő" msgid "Monitor this timer using the start and stop time." msgstr "" msgid "off" msgstr "ki" msgid "Do not monitor this timer." msgstr "" msgid "The channel to record." msgstr "A törlendő csatorna." msgid "Day Of Recording:" msgstr "Felvétel napja:" msgid "The day when the timer should get active. You can enter the day in two formats:
  • Two digits (DD). This will use the current month and year.
  • ISO norm (YYYY-MM-DD). Program your timers as far in the future as you like.
In case you want to program a repeating timer you can use the seven checkboxes below the text field. Check the box for each day you want the timer to get active." msgstr "" msgid "Start Time:" msgstr "Kezdet:" msgid "This is the time when the timer should start recording. The first text field is for \"hour\", the second for \"minute\"." msgstr "" msgid "End Time:" msgstr "Vég:" msgid "This is the time when the timer should stop recording. The first text field is for \"hour\", the second for \"minute\"." msgstr "" msgid "Title of Recording:" msgstr "Felvétel címe:" msgid "The file name this timer will give to a recording. If the name shall contain subdirectories, these have to be delimited by '~' (since the '/' character may be part of a regular programme name).

The special keywords TITLE and EPISODE, if present, will be replaced by the title and episode information from the EPG data at the time of recording (if that data is available). If at the time of recording either of these cannot be determined, TITLE will default to the channel name, and EPISODE will default to a blank." msgstr "" msgid "Summary:" msgstr "Leírás:" msgid "Arbitrary text that describes the recording made by this timer. If this field is not empty, its contents will be written into the summary.vdr or info.vdr file of the recording." msgstr "" msgid "Your Browser does not support frames!" msgstr "A böngészÅ‘d nem támogat kereteket!" msgid "What's On Now?" msgstr "Most adásban" msgid "Playing Today?" msgstr "Ma adásban" msgid "Remote Control" msgstr "Távirányító" msgid "Watch TV" msgstr "TV nézés" msgid "Commands" msgstr "Parancsok" msgid "Search" msgstr "Keresés" msgid "Authorization Required" msgstr "Azonosítás szükséges" msgid "This server could not verify that you are authorized to access the document requested. Either you supplied the wrong credentials (e.g. bad password), or your browser doesn't understand how to supply the credentials required." msgstr "" msgid "VPS" msgstr "VPS" msgid "close" msgstr "bezárni" msgid "view" msgstr "nézet" msgid "search" msgstr "keresés" msgid "edit" msgstr "szerkesztés" msgid "Length" msgstr "Hossz" msgid "Video tracks:" msgstr "Videó sávok:" msgid "Audio tracks:" msgstr "Hangsávok:" msgid "Subtitles:" msgstr "Feliratok:" msgid "Video tracks" msgstr "Videó sávok" msgid "Audio tracks" msgstr "Hangsávok" msgid "TV select" msgstr "Ãtkapcsolni erra az adóra" msgid "Stream" msgstr "Stream" msgid "Channel group:" msgstr "Csoport:" msgid "Go!" msgstr "Mehet!" msgid "Search for other show times" msgstr "Ismétlések keresése" msgid "No Information" msgstr "Nincs információ" msgid "No EPG information available" msgstr "Nincs elérhetÅ‘ EPG információ" msgid "Playing Today" msgstr "Ma adásban" msgid "starting at" msgstr "kezdés ekkor" msgid "What's on:" msgstr "Adásban:" msgid "at" msgstr " " msgid "now" msgstr "most" msgid "to" msgstr "-" msgid "Duration:" msgstr "IdÅ‘tartam:" msgid "min" msgstr "perc" msgid "at:" msgstr " " msgid "You need JavaScript to use the timeline!" msgstr "Az idÅ‘sáv használatához JavaScript telepítése szükséges" msgid "Rename Recording" msgstr "Felvétel átnevezése" msgid "Original Name of Recording:" msgstr "A felvétel eredeti neve:" msgid "New Name of Recording:" msgstr "A felvétel új neve:" msgid "Subtitle:" msgstr "Alcím:" msgid "Rename" msgstr "Ãtnevezés" msgid "Total:" msgstr "Összesen:" msgid "h" msgstr "óra" msgid "Free:" msgstr "Szabad:" msgid "Date" msgstr "Dátum" msgid "Total" msgstr "Összesen" msgid "New" msgstr "Új" msgid "Play" msgstr "Lejátszani" msgid "Cut" msgstr "Vágni" msgid "Delete recording?" msgstr "Felvétel törlése?" msgid "Refresh" msgstr "Frissíteni" msgid "Commands:" msgstr "Parancsok:" msgid "Really run this command?" msgstr "Biztos, hogy futtassuk ezt a parancsot?" msgid "stream all recordings" msgstr "" msgid "Delete Selected Recordings" msgstr "Kijelölt felvételek törlése" msgid "Delete all selected recordings?" msgstr "Az összes kijelölt felvétel törlése?" msgid "No recordings available" msgstr "Nincs elérhetÅ‘ felvétel" msgid "Transponder:" msgstr "Transponder:" msgid "CA-System:" msgstr "CA-rendszer:" msgid "New Timer" msgstr "Új idÅ‘zítÅ‘" msgid "Edit timer status?" msgstr "Az idÅ‘zítÅ‘ állapotának szerkesztése?" msgid "This timer is inactive!" msgstr "Ez az idÅ‘zítÅ‘ inaktív!" msgid "This timer is impossible!" msgstr "Ez az idÅ‘zítÅ‘ nem lehetséges!" msgid "No more timers on other transponders possible!" msgstr "Több felvétel más transzponderen nem lehetséges!" msgid "Timer OK." msgstr "IdÅ‘zítÅ‘ rendben." msgid "Auto" msgstr "Auto" msgid "activate" msgstr "engedélyezni" msgid "inactivate" msgstr "tiltani" msgid "selected timers" msgstr "kiválasztott idÅ‘zítÅ‘k" msgid "Delete Selected Timers" msgstr "Kiválasztott idÅ‘zítÅ‘k törlése" msgid "No timers defined!" msgstr "Nincs kiválasztott idÅ‘zítÅ‘!" msgid "Create New Timer" msgstr "Új idÅ‘zítÅ‘ létrehozása" msgid "Buffer:" msgstr "Puffer:" msgid "Use VPS:" msgstr "VPS használata:" msgid "readonly" msgstr "csak olvasható" msgid "Timer has been set by AutoTimer pattern:" msgstr "Az idÅ‘zítÅ‘t ez a keresési minta hozta létre:" msgid "TV" msgstr "TV" msgid "Interval:" msgstr "Intervallum:" msgid "sec." msgstr "mp" msgid "G" msgstr "G" msgid "Grab the picture!" msgstr "Pillanatfelvétel!" msgid "Size:" msgstr "Méret:" msgid "Open in separate window" msgstr "Új ablakban nyissad" msgid "VDR Commands" msgstr "VDR parancsok" msgid "Export channels as playlist:" msgstr "Csatornák exportálása lejátszási listába:" msgid "Number of lines to show:" msgstr "Hány sor kerüljön kijelzésre:" msgid "unlimited" msgstr "végtelen" msgid "SVDRP commands:" msgstr "SVDRP parancsok:" msgid "Commands defined in commands.conf:" msgstr "commands.conf-ban meghatározott parancsok" msgid "Output" msgstr "Kimenet" msgid "What's your VDR hostname (e.g video.intra.net)?" msgstr "A VDR számítógép neve (pl. video.intra.net)?" msgid "On which port does VDR listen to SVDRP queries?" msgstr "SVDRP port:" msgid "On which address should VDRAdmin-AM listen (0.0.0.0 for any)?" msgstr "IP cím, amelyen a VDRAdmin-AM figyel (0.0.0.0 az összeshez):" msgid "On which port should VDRAdmin-AM listen?" msgstr "Port, amelyen a VDRAdmin-AM figyel:" msgid "Username?" msgstr "Felhasználónév?" msgid "Password?" msgstr "Jelszó?" msgid "Where are your recordings stored?" msgstr "VDR felvételek mappája?" msgid "Where are your VDR's configuration files located?" msgstr "VDR konfigurációs fileok mappája?" msgid "Config file written successfully." msgstr "Konfig file sikeresen lementve." #, perl-format msgid "%s %s started with pid %d." msgstr "%s %s elindítva, pid: %d." msgid "Not found" msgstr "Nincs találat" msgid "The requested URL was not found on this server!" msgstr "A keresett URL nem található a kiszolgálón!" msgid "Forbidden" msgstr "Tiltott" msgid "You don't have permission to access this function!" msgstr "Nincs hozzaférésed ehhez a szolgáltatáshoz!" msgid "All channels" msgstr "Minden csatorna" msgid "Selected channels" msgstr "Kiválasztott csatornák" msgid "TV channels" msgstr "TV csatornák" msgid "Radio channels" msgstr "Rádiócsatornák" #, perl-format msgid "Access to file \"%s\" denied!" msgstr "Hozzaférés a \"%s\" file-hoz megtagadva!" #, perl-format msgid "The URL \"%s\" was not found on this server!" msgstr "\"%s\" URL nem található a szerveren!" msgid "Your favorites" msgstr "Kedvencek" msgid "Search results" msgstr "Találatok" msgid "Default" msgstr "Alapértelmezett" msgid "--- no timer ---" msgstr "--- nincs idÅ‘zítÅ‘ ---" msgid "unknown" msgstr "ismeretlen" msgid "none" msgstr "nincs" #, perl-format msgid "Can't open file \"%s\"!" msgstr "A \"%s\" file-t nem tudom megnyitni!" #, perl-format msgid "Can't connect to VDR at %s:%s: %s

Please check if VDR is running and if VDR's svdrphosts.conf is configured correctly." msgstr "Nem tudok csatlakozni a VDR-hez %s:%s: %s

Kérlek, ellenőrízd, hogy a VDR fut, és az svdrphosts.conf megfelelően van beállítva." #, perl-format msgid "Error while sending command to VDR at %s" msgstr "Hiba a parancsküldés folyamatában %s" msgid "Internal error:" msgstr "Belső hiba:" msgid "Lookup movie in the Internet-Movie-Database (IMDb)" msgstr "A film Internetes-Film-Adatbázis (IMDb) bejegyzése" msgid "Can't find EPG entry!" msgstr "Nem található EPG bejegyzés!" msgid "Playing Tomorrow" msgstr "Holnap adásban" #, perl-format msgid "Playing on the %s" msgstr "%s -n adásban" msgid "next" msgstr "következik" msgid "What's on after" msgstr "Mi következik ezután:" msgid "What's on at" msgstr "Adásban" msgid "Suitable matches for:" msgstr "Találatok erre:" msgid "short view" msgstr "rövidnézet" msgid "long view" msgstr "részletes nézet" msgid "Schedule" msgstr "Program" #, perl-format msgid "Can't write configuration file %s! Reason: %s" msgstr "Nem sikerült menteni a konfigurációs file-t %s! Ok: %s" #, perl-format msgid "Configuration file %s not writable! Configuration won't be saved!" msgstr "%s konfigurációs file nem menthető! A beállítások nem kerülnek lemetésre." msgid "Timers" msgstr "Időzítől" msgid "System default" msgstr "Rendszer alapértelmezett" vdradmin-am-3.6.13/po/it.po000066400000000000000000002165521443716113400154140ustar00rootroot00000000000000# Copyright (C) Andreas Mair # This file is distributed under the same license as the VDRAdmin-AM package. # # Diego Pierotto , 2007 # msgid "" msgstr "" "Project-Id-Version: VDRAdmin-AM-3.6.6\n" "Report-Msgid-Bugs-To: Andreas Mair \n" "POT-Creation-Date: 2012-07-09 12:23+0200\n" "PO-Revision-Date: 2012-05-03 20:19+0100\n" "Last-Translator: Diego Pierotto \n" "Language-Team: Italian \n" "Language: it\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Language: Italian\n" "X-Poedit-Country: ITALY\n" "X-Poedit-SourceCharset: UTF-8\n" msgid "About" msgstr "Info" msgid "License" msgstr "Licenza" msgid "Authors" msgstr "Autori" msgid "Current author (VDRAdmin-AM branch):" msgstr "Autore attuale (ramo VDRAdmin-AM):" msgid "Original author (VDRAdmin):" msgstr "Autore originale (VDRAdmin):" msgid "Translation Team" msgstr "Gruppo traduzione" msgid "English:" msgstr "Inglese:" msgid "German:" msgstr "Tedesco:" msgid "French:" msgstr "Francese:" msgid "At the moment unmaintained, former translations by:" msgstr "Al momento non mantenuto, vecchie traduzioni di:" msgid "Spanish:" msgstr "Spagnolo:" msgid "Finnish:" msgstr "Finlandese:" msgid "Dutch:" msgstr "Olandese:" msgid "Russian:" msgstr "Russo:" msgid "Czech:" msgstr "Ceco:" msgid "Italian:" msgstr "Italiano:" msgid "Hungarian:" msgstr "Ungherese:" msgid "Information" msgstr "Informazioni" msgid "VDRAdmin-AM version:" msgstr "Versione VDRAdmin-AM:" msgid "VDR version:" msgstr "Versione VDR:" msgid "Supported features in VDR:" msgstr "Funzioni supportate da VDR:" msgid "EPGSearch" msgstr "Ricerca EPG" msgid "EPGSearch Plugin" msgstr "Plugin EPGSearch" msgid "LiveTV Streaming" msgstr "Trasmissione TV dal vivo" msgid "Streamdev Plugin" msgstr "Plugin Streamdev" msgid "Xineliboutput Plugin" msgstr "Plugin Xineliboutput" msgid "Rename Recordings (Liemikuutio Patch)" msgstr "Rinomina registrazioni (Patch di Liemikuutio)" msgid "Getting Help and Reporting Bugs" msgstr "Chiedi aiuto e riporta errori" msgid "If you need help please first try to use the online help you'll find on some pages. You can access it by clicking \"\"." msgstr "Se hai bisogno di aiuto prova a usare l'aiuto in linea che troverai in alcune pagine. Puoi accedervi cliccando \"\"." msgid "If this doesn't provide the information you need you can try to get help at VDR-Portal if you understand German language. Please use the announcement thread if possible, search for:" msgstr "Se questo non ti fornisce le informazioni di cui hai bisogno puoi provare a chiedere aiuto nel Portale VDR se capisci il tedesco. Usa la sezione annunci se possibile, cerca:" msgid "If you think you have found a bug please check that it's a new one and report it in the VDRAdmin-AM BugTracking system." msgstr "Se pensi di aver trovato un errore verifica che sia uno nuovo e riportalo nel Sistema di raccolta errori di VDRAdmin-AM." msgid "AutoTimer" msgstr "Timer automatico" msgid "Priority:" msgstr "Priorità:" msgid "Lifetime:" msgstr "Scadenza:" msgid "New AutoTimer" msgstr "Nuovo timer automatico" msgid "Help" msgstr "Aiuto" msgid "Active" msgstr "Attivo" msgid "Channel" msgstr "Canale" msgid "Start" msgstr "Inizio" msgid "Stop" msgstr "Fine" msgid "Name" msgstr "Nome" msgid "Select all/none" msgstr "Seleziona tutti/nessuno" msgid "Yes" msgstr "Sì" msgid "No" msgstr "No" msgid "Edit" msgstr "Modifica" msgid "Delete timer?" msgstr "Eliminare timer?" msgid "Delete" msgstr "Elimina" msgid "Force Update" msgstr "Forza aggiornamento" msgid "Delete Selected AutoTimers" msgstr "Elimina timer automatici selezionati" msgid "Delete all selected timers?" msgstr "Eliminare tutti i timer selezionati?" msgid "No AutoTimers defined!" msgstr "Nessun timer automatico definito!" msgid "Add New AutoTimer" msgstr "Aggiungi nuovo timer automatico" msgid "Edit AutoTimer" msgstr "Modifica timer automatico" msgid "AutoTimer Active:" msgstr "Timer automatico attivo:" msgid "oneshot" msgstr "solo una volta" msgid "Search Patterns:" msgstr "Cerca valori:" msgid "Search in:" msgstr "Cerca in:" msgid "Title" msgstr "Titolo" msgid "Subtitle" msgstr "Sottotitolo" msgid "Description" msgstr "Descrizione" msgid "Search only on these days:" msgstr "Cerca solo in questi giorni:" msgid "Monday" msgstr "Lunedì" msgid "Tuesday" msgstr "Martedì" msgid "Wednesday" msgstr "Mercoledì" msgid "Thursday" msgstr "Giovedì" msgid "Friday" msgstr "Venerdì" msgid "Saturday" msgstr "Sabato" msgid "Sunday" msgstr "Domenica" msgid "Channel:" msgstr "Canale:" msgid "all" msgstr "tutti" msgid "Starts After:" msgstr "Inizia dopo:" msgid "o'clock" msgstr "in punto" msgid "Ends Before:" msgstr "Finisce prima:" msgid "Override Start/Stop Margins:" msgstr "Sovrascrivi margini Inizio/Fine:" msgid "Time Margin at Start:" msgstr "Margine tempo iniziale:" msgid "minutes" msgstr "minuti" msgid "Time Margin at Stop:" msgstr "Margine tempo finale:" msgid "Episode:" msgstr "Episodio:" msgid "Remember programmed timers:" msgstr "Ricorda timer programmati:" msgid "Directory:" msgstr "Directory:" msgid "Save" msgstr "Salva" msgid "Test" msgstr "Prova" msgid "Cancel" msgstr "Annulla" msgid "Broadcasted" msgstr "Trasmesso" msgid "Stored in" msgstr "Salvato in" msgid "No matches found!" msgstr "Nessun valore trovato!" msgid "Configuration" msgstr "Configurazione" msgid "General Settings" msgstr "Impostazioni generali" msgid "Template:" msgstr "Modello:" msgid "Skin:" msgstr "Stile interfaccia:" msgid "Login Page:" msgstr "Pagina di accesso:" msgid "Number of channels to use:" msgstr "Numero di canali da usare:" msgid "Local net (no login required):" msgstr "Rete locale (nessun accesso richiesto):" msgid "Language:" msgstr "Lingua:" msgid "Save settings on exit:" msgstr "Salva impostazioni all'uscita:" msgid "VDR" msgstr "VDR" msgid "Number of DVB cards:" msgstr "Numero di schede DVB:" msgid "Path to recordings:" msgstr "Percorso delle registrazioni:" msgid "Path to configuration files:" msgstr "Percorso files di configurazione:" msgid "Path to EPG images:" msgstr "Percorso immagini EPG:" msgid "Identification" msgstr "Identificazione" msgid "Username:" msgstr "Nome utente:" msgid "Password:" msgstr "Password:" msgid "Guest Account:" msgstr "Account Guest:" msgid "Guest Username:" msgstr "Nome utente Guest:" msgid "Guest Password:" msgstr "Password Guest:" msgid "Timeline" msgstr "Linea temporale" msgid "Hours:" msgstr "Ore:" msgid "Times:" msgstr "Periodi:" msgid "Also used for other EPG views!" msgstr "Usato anche per altre viste EPG!" msgid "Tooltips:" msgstr "Dettagli:" msgid "Electronic Program Guide (EPG)" msgstr "Guida Elettronica Programmi (EPG)" msgid "Day begins at:" msgstr "Inizio giornata alle:" msgid "Show Subtitle:" msgstr "Mostra sottotitoli:" msgid "Show Summary:" msgstr "Mostra sommario:" msgid "Active:" msgstr "Attivo:" msgid "Send email after programming timer:" msgstr "Invia email dopo la programmazione del timer:" msgid "Send email as:" msgstr "Invia email come:" msgid "Send email to:" msgstr "Invia email a:" msgid "Mail server:" msgstr "Server di posta:" msgid "SMTPAuth user:" msgstr "Utente autenticazione SMTP:" msgid "SMTPAuth password:" msgstr "Password autenticazione SMTP:" msgid "Track schedule changes by:" msgstr "Traccia modifiche pianificate da:" msgid "Broadcast time" msgstr "Ora trasmissione" msgid "Event id" msgstr "ID evento" msgid "Timer" msgstr "Timer" msgid "Tooltips in timeline:" msgstr "Dettagli nella linea temporale:" msgid "Tooltips in list:" msgstr "Dettagli nell'elenco:" msgid "Streaming" msgstr "Trasmissione" msgid "Live Streaming:" msgstr "Trasmissione dal vivo:" msgid "HTTP Port of Streamdev (also possible 3000/ts):" msgstr "Porta HTTP di Streamdev (possibile anche 3000/ts):" msgid "HTTP Port of Xineliboutput (e.g. 37890):" msgstr "Porta HTTP di Xineliboutput (es. 37890):" msgid "Recordings Streaming:" msgstr "Trasmissione registrazioni:" msgid "Path to VDR Recordings on your workstation:" msgstr "Percorso di registrazione VDR sul tuo pc:" msgid "MIME type for live streaming:" msgstr "Tipo MIME per trasmissione dal vivo:" msgid "Suffix for live streaming:" msgstr "Suffisso per trasmissione dal vivo:" msgid "MIME type for recordings streaming:" msgstr "Tipo MIME per trasmissione registrazioni:" msgid "Suffix for recordings streaming:" msgstr "Suffisso per trasmissione registrazioni:" msgid "Bandwidth of Streams:" msgstr "Ampiezza di banda delle trasmissioni:" msgid "External Search" msgstr "Ricerca esterna" msgid "URL:" msgstr "URL:" msgid "Title:" msgstr "Titolo:" msgid "User-defined search:" msgstr "Ricerca definita dall'utente:" msgid "Expert" msgstr "Esperto" msgid "Update EPG data in background:" msgstr "Aggiorna i dati EPG in sottofondo:" msgid "Update EPG every:" msgstr "Aggiorna EPG ogni:" msgid "Channel Selections" msgstr "Selezione canali" msgid "Show channels without EPG information:" msgstr "Mostra canali senza informazione EPG:" msgid "In \"AutoTimer\"?" msgstr "In \"Timer automatici\"?" msgid "Apply" msgstr "Applica" msgid "EPG Search Blacklists" msgstr "Lista esclusione ricerca EPG" msgid "New Blacklist" msgstr "Nuova lista esclusione" msgid "Search pattern" msgstr "Cerca valore" msgid "From" msgstr "Da" msgid "To" msgstr "A" msgid "Delete blacklist?" msgstr "Eliminare lista esclusione?" msgid "Delete Selected Blacklists" msgstr "Elimina liste esclusioni selezionate" msgid "Delete all selected blacklists?" msgstr "Eliminare tutte le liste esclusioni selezionate?" msgid "EPG search" msgstr "Ricerca EPG" msgid "EPG Search" msgstr "Ricerca EPG" msgid "Use template" msgstr "Utilizza modello" msgid "New Search" msgstr "Nuova ricerca" msgid "Edit Template" msgstr "Modifica modello" msgid "Settings" msgstr "Impostazioni" msgid "Action" msgstr "Azione" msgid "Find" msgstr "Trova" msgid "Show Favorites" msgstr "Mostra Preferiti" msgid "Delete Selected Searches" msgstr "Elimina ricerche selezionate" msgid "Delete all selected searches?" msgstr "Eliminare tutte le ricerche selezionate?" msgid "Execute Selected Searches" msgstr "Esegui ricerche selezionate" msgid "Duration" msgstr "Durata" msgid "More Information" msgstr "Altre informazioni" msgid "Channels" msgstr "Canali" msgid "Record" msgstr "Registra" msgid "Add New Blacklist" msgstr "Aggiungi nuova lista esclusione" msgid "Edit Blacklist" msgstr "Modifica lista esclusione" msgid "Add New Template" msgstr "Aggiungi nuovo modello" msgid "Add New Search" msgstr "Aggiungi nuova ricerca" msgid "Edit Search" msgstr "Modifica ricerca" msgid "Small search pattern.\\nDo you really want to use it?" msgstr "Valore piccola ricerca.\\nSei sicuro di usarla?" msgid "You didn't select at least one of\\ntitle, subtitle or description.\\nDo you really want to use this search?" msgstr "Non hai selezionato almeno uno tra\\ntitolo, sottotitolo o descrizione.\\nSei sicuro di usare questa ricerca?" msgid "Hide results" msgstr "Nascondi risultati" msgid "Name:" msgstr "Nome:" msgid "Search Term:" msgstr "Termine ricerca:" msgid "Search Mode:" msgstr "Modalità ricerca:" msgid "phrase" msgstr "frase" msgid "all words" msgstr "tutte le parole" msgid "at least one word" msgstr "almeno una parola" msgid "match exactly" msgstr "corrispondenza esatta" msgid "regular expression" msgstr "espressione regolare" msgid "fuzzy" msgstr "imprecisa" msgid "Tolerance for \"fuzzy\":" msgstr "Tolleranza per \"imprecisa\":" msgid "Match Case:" msgstr "Tipo corrispondenza:" msgid "Use extended EPG info:" msgstr "Utilizza info EPG estese:" msgid "Ignore missing categories?" msgstr "Ignorare categorie mancanti?" msgid "Use Channel:" msgstr "Utilizza canale:" msgid "no" msgstr "no" msgid "interval" msgstr "intervallo" msgid "channel group" msgstr "gruppo canali" msgid "only FTA" msgstr "solo gratuiti" msgid "Range:" msgstr "Range:" msgid "Channel Group:" msgstr "Gruppo canale:" msgid "Use Time:" msgstr "Utilizza ora:" msgid "Start After:" msgstr "Inizio dopo:" msgid "Start Before:" msgstr "Inizio prima:" msgid "Use Duration:" msgstr "Utilizza durata:" msgid "Min. Duration:" msgstr "Durata minima:" msgid "hh:mm" msgstr "hh:mm" msgid "Max. Duration:" msgstr "Durata massima:" msgid "Use Day of Week:" msgstr "Utilizza giorno della settimana:" msgid "Use Blacklists:" msgstr "Utilizza lista esclusioni:" msgid "selection" msgstr "selezione" msgid "Use in Favorites Menu:" msgstr "Utilizza nel menu Preferiti:" msgid "Use as Search Timer:" msgstr "Utilizza come timer di ricerca:" msgid "yes" msgstr "sì" msgid "user-defined" msgstr "definito dall'utente" msgid "record" msgstr "registra" msgid "announce by OSD" msgstr "notifica tramite OSD" msgid "switch only" msgstr "cambia soltanto" msgid "announce and switch" msgstr "notifica e cambia" msgid "announce by mail" msgstr "notifica tramite email" msgid "First day:" msgstr "Primo giorno:" msgid "Last day:" msgstr "Ultimo giorno:" msgid "Auto delete:" msgstr "Eliminazione automatica:" msgid "count recordings" msgstr "conta registrazioni" msgid "count days" msgstr "conta giorni" msgid "After ... recordings:" msgstr "Dopo ... registrazioni:" msgid "After ... days after first recording:" msgstr "Dopo ... giorni dopo la prima registrazione:" msgid "Settings for action \"record\"" msgstr "Impostazioni per azione \"registra\"" msgid "Series Recording:" msgstr "Registrazione di serie:" msgid "Delete Recordings After ... Days:" msgstr "Elimina registrazioni dopo ... giorni:" msgid "Keep ... Recordings:" msgstr "Mantieni ... registrazioni:" msgid "Pause, when ... recordings exist:" msgstr "Pausa, quando ... la registrazione esiste:" msgid "Avoid Repeats:" msgstr "Evita repliche:" msgid "Allowed Repeats:" msgstr "Repliche permesse:" msgid "Only Repeats Within ... Days:" msgstr "Ripeti solo entro ... giorni:" msgid "Compare:" msgstr "Confronta:" msgid "Minimal match of description in %:" msgstr "Corrispondenza minima della descrizione in %:" msgid "VPS:" msgstr "VPS:" msgid "Settings for action \"switch only\"" msgstr "Impostazioni per azione \"cambia soltanto\"" msgid "Switch ... Minutes Before Start:" msgstr "Cambia ... minuti prima dell'inizio:" msgid "Unmute sound:" msgstr "Togli suono muto:" msgid "Settings for action \"announce and switch\"" msgstr "Impostazioni per azione \"notifica e cambia\"" msgid "Ask ... Minutes Before Start:" msgstr "Chiedi ... minuti prima dell'inizio:" msgid "Delete template" msgstr "Elimina modello" msgid "Delete this template?" msgstr "Eliminare questo modello?" msgid "Save as template" msgstr "Salva come modello" msgid "Run" msgstr "Esegui" msgid "Error!" msgstr "Errore!" msgid "

Here you will find a listing of automatic timers (AutoTimer) known to VDRAdmin-AM.

The list shows some information on AutoTimers. You can change the list's sorting by clicking the columns heading.

For each AutoTimer you have the following options:

Set its state
By clicking on \"Yes\" or \"No\" in the \"Active\" column to toggle the activity.
Quickly view its priority and lifetime
By pointing the mouse cursor to the AutoTimer's title.
Edit the AutoTimer
You can edit an AutoTimer by clicking \"edit\".
Delete the AutoTimer
To delete an AutoTimer you click \"delete\".

Each AutoTimer's state is indicated by differently coloured images:
\"on\" AutoTimer is OK and will automatically program matching broadcasts.
\"inactive\" AutoTimer is not active.

In addition to these functions you can add a new AutoTimer by clicking at the top and you can delete a number of AutoTimers at once by checking the box in the last column of those timers and clicking .

Click to force VDRAdmin-AM to reconnect to VDR, fetch the current EPG and check for matching AutoTimers.

" msgstr "

Qui troverai un elenco dei timer automatici (AutoTimer) noti a VDRAdmin-AM.

Questa lista mostra alcune informazioni sui timer automatici. Puoi cambiare l'ordinamento dell'elenco cliccando sul titolo della colonna.

Per ciascun timer automatico hai le seguenti opzioni:

Imposta lo stato
Clicca su \"Sì\" o \"No\" nella colonna \"Attivo\" per vedere l'attività.
Vedi velocemente la priorità e la scadenza
Puntando il cursore del mouse nel titolo del timer automatico.
Modifica il timer automatico
Puoi modificare un timer automatico cliccando \"modifica\".
Elimina il timer automatico
Per eliminare un timer automatico fai click su \"elimina\".

Lo stato di ciascun timer automatico è indicato con diverse immagini colorate:
\"attivo\" Il timer automatico è OK e programmerà automaticamente le trasmissioni corrispondenti.
\"disattivo\" Il timer automatico non è attivo.

In aggiunta a queste funzionalità puoi aggiungere un nuovo timer automatico cliccando in cima e puoi eliminare un numero di timer automatici alla volta spuntando la casella nell'ultima colonna di quei timer e cliccando .

Clicca per forzare VDRAdmin-AM a riconnettersi a VDR, raccogliere l'EPG attuale e verificare la corrispondenza dei timer automatici.

" msgid "

Here you can edit an automatic timer's (AutoTimer) settings.

AutoTimer is a key feature of VDRAdmin-AM. An AutoTimer consists of one or more search terms and some other settings, that are looked for regularly in the Electronic Program Guide (EPG). On match AutoTimer adds a timer in VDR automatically for that broadcast. That's very comfortable for irregularly broadcasted series or movies you don't want to miss.

" msgstr "

Qui puoi modificare le impostazioni dei timer automatici (AutoTimer).

Il timer automatico è una funzione chiave di VDRAdmin-AM. Un timer automatico consiste in uno o più termini di ricerca e alcune altre impostazioni, che cercano regolarmente nella Guida Programmi Elettronici (EPG). Se un timer automatico corrisponde allora aggiunge un timer a VDR automaticamente per quella trasmissione. Questo è molto comodo per serie o film trasmessi irregolarmente che tu non vuoi perdere.

" msgid "Activate or deactivate this AutoTimer. Deactivated AutoTimers are still stored in the AutoTimer list so that they can be activated again, but they do not record anything meanwhile. Above that you can set this to \"oneshot\" so this AutoTimer only programs the (one!) next matching broadcast." msgstr "Attiva o disattiva questo timer automatico. I timer automatici disattivati sono ancora salvati nell'elenco dei timer automatici in modo che possano ancora essere attivati, ma non registreranno niente nel frattempo. Sopra quello puoi impostare questo come \"solo una volta\" in modo che questo timer automatico si programmi solo alla prossima (unica!) trasmissione corrispondente." msgid "Choosing the right search items decides whether only the wanted broadcasts or broadcasts having similar names or even nothing gets recorded.
Case doesn't matter, \"X-Files\" matches anything \"x-files\" will match. You can set multiple search items by separating them with spaces. Broadcasts will match only if they match all configured search items.
You'd better only use letters and numbers for search items, as the EPG often miss colons, brackets and other characters.
Experts can also use regular expressions, but you have to get needed information from the VDRAdmin-AM sources (undocumented feature).

You can exclude broadcasts so that they don't get recorded even if they would match an AutoTimer. Therefore you have to enter that titles into the file vdradmind.bl, one event a line. This file must be located in your VDRAdmin-AM's configuration folder. If this string is found either in the EPG's title or in title~subtitle, this event will not be programmed by AutoTimer. So you can disable complete episodes (for example when using \"Enterprise\" as blacklist string) or only one episode (when using \"Enterprise~Azati Prime\" as blacklist string)." msgstr "Scegliendo i valori corretti di ricerca decidi se solo le trasmissioni volute o le trasmissioni che hanno nomi simili o anche nessuna sarà registrata.
Il maiuscolo non importa, \"X-Files\" corrisponde a qualsiasi cosa \"x-files\" incontrerà. Puoi impostare valori di ricerca multipli separandoli con degli spazi. Le trasmissioni corrisponderanno solo se contengono tutti i valori.
Dovresti piuttosto usare lettere e numeri per la ricerca dei valori, visto che l'EPG spesso omette le virgole, parentesi e altri caratteri.
Gli esperti possono anche usare espressioni regolari, ma devi aver bisogno di più informazione dai sorgenti di VDRAdmin-AM (caratteristica non documentata).

Puoi escludere le trasmissioni in modo che non siano registrate se corrispondessero a un timer automatico. Perciò devi inserire quei titoli nel file vdradmind.bl, un evento per riga. Questo file deve essere posizionato nella tua directory di configurazione di VDRAdmin-AM. Se questa stringa viene trovata sia nel titolo dell'EPG che nel titolo~sottotitolo, questo evento non sarà programmato dai timer automatici. Puoi così disabilitare episodi completi (per esempio quando usi \"Enterprise\" come stringa della lista esclusioni) o solo un episodio (quando usi \"Enterprise~Azati Prime\" come stringa della lista nera)." msgid "Here you can define the EPG sections where VDRAdmin-AM should look for the search pattern." msgstr "Qui puoi definire le sezioni EPG dove VDRAdmin-AM dovrebbe guardare per la ricerca del valore." msgid "Use these checkboxes to limit searching for matching broadcasts to a set of weekdays." msgstr "Utilizza queste caselle di verifica per limitare la ricerca delle trasmissioni corrispondenti ad un insieme di giorni della settimana." msgid "The channel to look for matching broadcasts or \"all\" to search in all known or wanted channels. You can define the wanted channels for AutoTimer in \"Configuration\"." msgstr "Canale da cercare per le trasmissioni corrispondenti oppure \"tutti\" per cercare in tutti i canali noti e voluti. Puoi definire i canali voluti nei timer automatici nella \"Configurazione\"." msgid "A broadcast must start after the time entered here to match. The first text field is for \"hour\", the second for \"minute\"." msgstr "Una trasmissione deve iniziare dopo che l'ora qui inserita corrisponda. Il primo campo di testo è per l'\"ora\", il secondo per i \"minuti\"." msgid "A broadcast must end before the time entered here to match. The first text field is for \"hour\", the second for \"minute\"." msgstr "Una trasmissione deve finire prima che l'orario qui inserito corrisponda. Il primo campo di testo è per l' \"ora\", il secondo per i \"minuti\"." msgid "Set this option to \"yes\" if all timers programed by this AutoTimer should have individual start/stop margins and enter the values in the next two text boxes." msgstr "Imposta questa opzione come \"sì\" se tutti i timer programmati da questo timer automatico dovrebbero avere margini individuali di avvio/chiusura e inserisci i valori nelle prossime 2 caselle di testo." msgid "The number of minutes VDRAdmin-AM subtracts from the broadcast's start time found in the EPG." msgstr "Numero di minuti che VDRAdmin-AM sottrae dall'ora di avvio delle trasmissioni trovate nell'EPG." msgid "The number of minutes VDRAdmin-AM adds to the broadcast's stop time found in the EPG." msgstr "Numero di minuti che VDRAdmin-AM aggiunge all'ora di chiusura delle trasmissioni trovate nell'EPG." msgid "An integer in the range 0...99, defining the priority of this timer and of recordings created by this timer. 0 represents the lowest value, 99 the highest. The priority is used to decide which timer shall be started in case there are two or more timers with the exact same start time. The first timer in the list with the highest priority will be used.

This value is also stored with the recording and is later used to decide which recording to remove from disk in order to free space for a new recording. If the disk runs full and a new recording needs more space, an existing recording with the lowest priority (and which has exceeded its guaranteed lifetime) will be removed.

If all available DVB cards are currently occupied, a timer with a higher priority will interrupt the timer with the lowest priority in order to start recording." msgstr "Un valore integer nel range 0...99, definisce la priorità di questo timer e delle registrazioni create da questo timer. 0 rappresenta il valore più basso, 99 il più alto. La priorità è usata per decidere quale timer inizierà nel caso ci siano 2 o più timer con la stessa esatta ora di avvio. Verrà usato il primo timer nella lista con la priorità più alta.

Questo valore è salvato anche con la registrazione ed è usato più tardi per rimuoverla dal disco in modo da liberare spazio per nuove registrazioni. Se il disco è pieno e una nuova registrazione ha bisogno di spazio, una registrazione esistente con una priorità più bassa (e la cui scadenza è garantita) sarà rimossa.

Se tutte le schede DVB disponibili sono attualmente occupate, un timer con una priorità più alta interromperà il timer con la priorità più bassa per poter iniziare la registrazione." msgid "The guaranteed lifetime (in days) of a recording created by this timer. 0 means that this recording may be automatically deleted at any time by a new recording with higher priority. 99 means that this recording will never be automatically deleted. Any number in the range 1...98 means that this recording may not be automatically deleted in favour of a new recording, until the given number of days since the start time of the recording has passed by." msgstr "La scadenza garantita (in giorni) di una registrazione creata da questo timer. 0 significa che questa registrazione può essere automaticamente eliminata a qualsiasi ora da una nuova registrazione con priorità più alta. 99 significa che questa registrazione non sarà mai eliminata automaticamente. Qualsiasi numero nel range 1...98 significa che questa registrazione non può essere automaticamente eliminata in favore di una nuova registrazione, finché il numero di giorni impostato dall'ora di avvio della registrazione sarà passato." msgid "Check this box if you want VDRAdmin-AM to append the broadcast's EPG subtitle to the recording's file name." msgstr "Seleziona questa casella se vuoi che VDRAdmin-AM aggiunga il sottotitolo EPG della trasmissione al nome file della registrazione." msgid "If you enable this VDRAdmin-AM will track timers it has already programmed automatically. This is useful if want to deactivate or delete timers that have been programmed automatically in the timers listing." msgstr "Se abiliti questo VDRAdmin-AM traccerà i timer che ha programmato automaticamente. Questo è utile se vuoi disattivare o eliminare i timers che sono stati programmati automaticamente nella lista dei timers." msgid "The directory this AutoTimer will place the recordings in. If the name shall contain subdirectories, these have to be delimited by '~' (since the '/' character may be part of a regular programme name).
VDRAdmin-AM will append the matching broadcast's title and subtitle (if the \"Episode\" checkbox is marked) to the directory given here.

You can also use the following keywords that are replaced in the final file name by the values supplied by for example tvm2vdr:
  • %Title% - will become the title of the event.
  • %Subtitle% - will become the subtitle of the event.
  • %Director% - will become the director of the event.
  • %Date% - will become the date of the recording.
  • %Category% - will become the category of the event (Spielfilm/Serie/...).
  • %Genre% - will become the genre of the event (Drama/Krimi/..).
  • %Year% - will become the year of production.
  • %Country% - will become the country of production.
  • %Originaltitle% - will become the original title of the event.
  • %FSK% - will become the FSK from the event.
  • %Episode% - will become the episode's title of the event.
  • %Rating% - will become the rating of the event from the EPG provider.

Note:

If you use the above keywords it's in your own responsibility to supply the complete file name for the recordings! VDRAdmin-AM will not append anything to the resulting string." msgstr "La directory dove i timer automatici posizioneranno le registrazioni. Se il nome conterrà sottodirectory, queste devono essere delimitate da '~' (dal momento che il carattere '/' può essere parte di un normale nome programma).
VDRAdmin-AM metterà in coda il titolo e il sottotitolo della trasmissione corrispondente (se la spunta \"Episodio\" è segnata) nella directory qui specificata.

Puoi anche usare le seguenti parole chiave che sono sostituite nel finale del nome file dai valori forniti per esempio tvm2vdr:
  • %Title% - diventerà il titolo dell'evento.
  • %Subtitle% - diventerà il sottotitolo dell'evento.
  • %Director% - diventerà il direttore dell'evento.
  • %Date% - diventerà la data della registrazione.
  • %Category% - diventerà la categoria dell'evento (Spielfilm/Serie/...).
  • %Genre% - diventerà il genere dell'evento (Drama/Krimi/..).
  • %Year% - diventerà l'anno di produzione.
  • %Country% - diventerà il paese di produzione.
  • %Originaltitle% - diventerà il titolo originale dell'evento.
  • %FSK% - diventerà la FSK dell'evento.
  • %Episode% - diventerà il titolo dell'episodio dell'evento.
  • %Rating% - diventerà la valutazione dell'evento del fornitore dell'EPG.

Nota:

Se usi le parole chiave di sopra è tua responsabilità fornire il nome file completo per le registrazioni! VDRAdmin-AM non includerà niente alla stringa risultante." msgid "

Here you can change general settings and base settings for timers, AutoTimers, channel selection and streaming parameters.

" msgstr "

Qui puoi cambiare le impostazioni generali e di base per i timer, timer automatici, selezione canale e parametri di trasmissione.

" msgid "The skin you want to use." msgstr "Lo stile interfaccia che vuoi usare." msgid "The page you want to see at first connect to VDRAdmin-AM." msgstr "La pagina che vuoi vedere alla prima connessione a VDRAdmin-AM." msgid "VDRAdmin-AM will load the given number of channels from VDR and present only those in any fields where channels can be selected. This also limits the EPG information VDRAdmin-AM will read so that you can use this to reduce VDRAdmin-AM's memory consumption and increase its performance. 0 turns this feature off and VDRAdmin-AM will use all available channels." msgstr "VDRAdmin-AM caricherà il numero di canali fornito da VDR e mostrerà solo quelli in qualunque campo dove i canali possano essere selezionati. Questo limita anche l'informazione EPG che VDRAdmin-AM leggerà in modo che tu possa usarla per ridurre l'uso di memoria di VDRAdmin-AM ed incrementare le sue performance. 0 disattiva questa opzione e VDRAdmin-AM userà tutti i canali disponibili." msgid "Here you can specify subnets from which access to VDRAdmin-AM does not require logging in. For example: \"192.168.0.0/24\" will include any IP starting with \"192.168.0.\", \"192.168.0.123/32\" will only match \"192.168.0.123\". Multiple subnets can be specified by separating them with spaces or commas." msgstr "Qui puoi specificare le sotto reti per le quali VDRAdmin-AM non chiederà l'accesso. Per esempio: \"192.168.0.0/24\" includerà qualunque IP che comincia con \"192.168.0.\", \"192.168.0.123/32\" corrisponderà solo a \"192.168.0.123\". Possono essere specificate multiple sotto reti separate con spazi e virgole." msgid "Here you can set the localization VDRAdmin-AM should use." msgstr "Qui puoi impostare la lingua che VDRAdmin-AM dovrebbe usare." msgid "With this option the settings will be saved if VDRAdmin-AM exits. This will also save settings not available on the \"Configuration\" menu like interval and size in TV, sorting in the lists and current view in \"What's on now\"." msgstr "Con questa opzione le impostazioni saranno salvate se VDRAdmin-AM esiste. Questo salverà anche le impostazioni non disponibili nel menu \"Configurazione\" come l'intervallo e la dimensione nella TV, ordine nell'elenco e la vista corrente \"In programmazione adesso\"." msgid "Top" msgstr "In alto" msgid "The number of DVB cards VDR can access. Depending on this value VDRAdmin-AM will calculate critical timers in the Timer menu." msgstr "Numero di schede DVB a cui VDR può accedere. A seconda di questo valore VDRAdmin-AM calcolerà i timer critici nel menu Timer." msgid "The path to VDR's recordings. It's used so that VDRAdmin-AM can locate the recordings when using Recordings Streaming and reccmds.conf in the Recordings menu." msgstr "Percorso per le registrazioni di VDR. Viene usato in modo che VDRAdmin-AM possa trovare le registrazioni quando usa la Registrazione Trasmissione e reccmds.conf nel menu Registrazioni." msgid "The path where VDR's configuration files are located. If this directory contains the file reccmds.conf its content is shown in a selectbox in the Recordings menu." msgstr "Percorso dove i file di configurazione di VDR sono salvati. Se questa directory contiene il file reccmds.conf il suo contenuto è mostrato nella casella di selezione nel menu Registrazioni." msgid "The path where the EPG images are stored." msgstr "Percorso dove sono salvate le immagini EPG." msgid "The username for the main user, i.e. the user having the most privileges." msgstr "Nome utente per l'account principale, per esempio l'utente con più privilegi." msgid "The main user's password." msgstr "Password account principale." msgid "If you want a user account having only limited privileges, this is for you. The guest user cannot modify anything, it's only allowed to view the EPG, timers, AutoTimers and recordings listings." msgstr "Se vuoi un account utente che abbia solo permessi limitati, questo è per te. L'utente guest non può modificare niente, può solo vedere l'EPG, i timer, i timer automatici e l'elenco delle registrazioni." msgid "The username for the guest user." msgstr "Nome utente dell'account guest." msgid "The guest user's password." msgstr "Password account guest." msgid "The number of hours to show in the timeline." msgstr "Numero di ore da mostrare nella linea temporale." msgid "A comma separated list of times in hh:mm format that appear in the selectbox placed at the top." msgstr "Un elenco di orari nel formato comma separated hh:mm che compare nella casella di selezione posizionata in cima." msgid "Here you can (de-)activate the tooltips." msgstr "Qui puoi (dis)attivare i dettagli." msgid "The time after which events are shown on a new day. For example setting 03:00 means that today's schedule will include any event starting before 03:00 tomorrow. Applies only to the 'Playing Today?' list." msgstr "Il tempo dopo il quale gli eventi vengono mostrati nel nuovo giorno. Per esempio se si imposta 03:00 significa che la pianificazione di oggi includerà qualsiasi evento inizi prima delle 03:00 di domani. Si applica soltanto all'elenco 'In esecuzione oggi'." msgid "Show the 'Subtitle' text for each event. Not all broadcasters use this field." msgstr "Mostra il testo dei 'Sottotitoli' per ogni evento. Non tutte le emittenti usano questo campo." msgid "Show the 'Summary' text for each event." msgstr "Mostra il testo del 'Sommario' per ogni evento." msgid "Activate or deactivate the AutoTimer function." msgstr "Attiva o disattiva la funzione timer automatici." msgid "VDRAdmin-AM will send an email whenever an event matches an AutoTimer and a timer has been programmed if you enable this feature." msgstr "VDRAdmin-AM invierà un'email se un evento corrisponde ad un timer automatico e un timer è stato programmato abilitando questa opzione." msgid "Here you set the sending email address of the generated email." msgstr "Qui puoi impostare l'invio all'indirizzo email del messaggio generato." msgid "The email address the email is sent to." msgstr "L'indirizzo email a cui il messaggio viene inviato." msgid "The outgoing mail server." msgstr "Server di posta in uscita." msgid "If you need to authenticate yourself at the outgoing mail server, you have to supply the username and the password below. Leaving this field empty will disable SMTPAuth." msgstr "Se devi autenticarti per l'invio di email, allora devi fornire sotto il nome utente e la password. Lasciando questo campo vuoto si disattiverà l'autenticazione SMTP." msgid "The password for the SMTPAuth user." msgstr "Password per l'utente di autenticazione SMTP." msgid "Here you can (de-)activate the tooltips in the timeline." msgstr "Qui puoi (dis)attivare i dettagli nella linea temporale." msgid "Here you can (de-)activate the tooltips in the list." msgstr "Qui puoi (dis)attivare i dettagli nell'elenco." msgid "Add summary to new timers:" msgstr "Aggiungi sommario ai nuovi timer:" msgid "If you don't want VDRAdmin-AM to add the summary taken from EPG to new timers you can switch it off here." msgstr "Se non vuoi che VDRAdmin-AM aggiunga il sommario preso dall'EPG nei nuovi timer puoi disattivarlo qui." msgid "Enable or disable live streaming using the streamdev plugin. You also have to set the correct HTTP Port for Streamdev below." msgstr "Abilita o disabilita la trasmissione dal vivo usando il plugin streamdev. Devi anche impostare sotto la corretta porta HTTP per Streamdev." msgid "Here you have to set the port number your VDR's streamdev server listens for connections. Additionally you can also provide the stream type you like to use." msgstr "Qui devi impostare il numero di porta in cui il server streamdev di VDR ascolta per effettuare le connessioni. Puoi anche fornire il tipo di trasmissione che utilizzi." msgid "Enable or disable streaming of recordings.
Well actually this is no real \"streaming\", but you have to setup your workstation so that it can access VDR's recordings. You can use for example Samba or NFS for this. VDRAdmin-AM simply generates a playlist that contains all parts of the recording and sends this to your browser. If your browser and media player are configured correctly you will see the recording on your workstation's display." msgstr "Abilita o disabilita la trasmissione delle registrazioni.
Anche se attualmente questa non è una vera \"trasmissione\", ma devi impostare il tuo pc affinché possa accedere alle registrazioni di VDR. Puoi usare per esempio Samba o NFS per questo. VDRAdmin-AM semplicemente genera una lista di esecuzione che contiene tutte le parti della registrazione e invia questo al tuo browser. Se il tuo browser e media player sono configurati correttamente vedrai la registrazione visualizzata sul tuo pc." msgid "This is the path where your workstation can access VDR's recordings. This depends on your VDR and workstation setup, for example \"\\\\vdr\\videos\" or \"V:\\\" (on Windows) or \"/mnt/videos\" (on Linux)." msgstr "Questo è il percorso in cui il tuo computer può accedere alle registrazioni di VDR. Questo dipende dalle impostazioni di VDR e del tuo pc, per esempio \"\\\\vdr\\videos\" oppure \"V:\\\" (su Windows) o \"/mnt/videos\" (su GNU/Linux)." msgid "The MIME type to send when using live streaming. Defaults to \"video/x-mpegurl\"." msgstr "Tipo MIME da inviare quando si usa la trasmissione dal vivo. Il valore predefinito è \"video/x-mpegurl\"." msgid "The suffix to use for live streaming. Defaults to \"m3u\"." msgstr "Suffisso da usare per le trasmissioni dal vivo. Il valore predefinito è \"m3u\". " msgid "The MIME type to send when using recordings streaming. Defaults to \"video/x-mpegurl\"." msgstr "Il tipo MIME da inviare quando si utilizza la trasmissione delle registrazioni. Il valore predefinito è \"video/x-mpegurl\"." msgid "The suffix to use for recordings streaming. Defaults to \"m3u\"." msgstr "Suffisso da usare per trasmettere la registrazione. Il valore predefinito è \"m3u\"." msgid "

Here you can define two external searches that you can access in the EPG views. You simply have to find the required URL and where the search pattern has to be located. %TITLE% will be substituted by the broadcast's EPG title.

" msgstr "

Qui puoi definire due ricerche esterne che possono accedere alle viste EPG. Devi semplicemente trovare l'URL richiesto e dove il parametro di ricerca deve essere posizionato. %TITLE% sarà sostituito dal titolo EPG della trasmissione.

" msgid "Some examples:" msgstr "Alcuni esempi:" msgid "Please change the hostname to your local needs!" msgstr "Cambia il nome server per adattarlo alle tue impostazioni" msgid "

This section is for experts only, i.e. you know what you are doing!

" msgstr "

Questa sezione è per soli esperti, del tipo: sai cosa stai facendo!

" msgid "If set to \"yes\" VDRAdmin-AM will periodically refresh its local EPG cache. Else the EPG will be refreshed if the user accesses any EPG view at the web interface and the timeout set at \"Update EPG every\" has been reached." msgstr "Se imposti \"sì\" VDRAdmin-AM aggiornerà periodicamente la sua cache EPG locale. Inoltre l'EPG sarà aggiornato se l'utente accede a qualsiasi vista EPG nell'interfaccia web e la scadenza impostata in \"Aggiorna EPG ogni\" è stata raggiunta." msgid "The interval, the EPG data is refreshed from VDR and AutoTimer updates are performed (if AutoTimer feature is used)." msgstr "L'intervallo, i dati EPG sono aggiornati da VDR e gli aggiornamenti sono eseguiti dai timer automatici (se la funzione AutoTimer viene usata)." msgid "

If you want to limit the number of channels used in some parts of VDRAdmin-AM, this is for you!

Use the radio buttons to activate or deactivate the wanted channels in the named menu.

To add channels to the list of wanted channels you have to select them in the left side selectbox and click . If you want to remove channels from the list of wanted channels you have to select them in the right side selectbox and click .

" msgstr "

Se vuoi limitare il numero di canali usati in alcune parti di VDRAdmin-AM, questo è per te!

Utilizza i pulsanti radio per attivare o disattivare i canali preferiti nel menu indicato.

Per aggiungere canali alla lista dei canali preferiti devi selezionarli nella casella di selezione del lato sinistro e cliccare . Se vuoi rimuovere canali dalla lista dei canali preferiti devi selezionarli nella casella di selezione del lato destro e cliccare .

" msgid "Usually channels that don't have EPG information are hidden in all EPG views. If you don't want them to be hidden you have to set this option to \"yes\"." msgstr "Di solito i canali che non hanno informazione EPG sono nascosti nelle viste EPG. Se non vuoi che siano nascosti devi impostare questa opzione come \"sì\"." msgid "Edit Timer" msgstr "Modifica timer" msgid "Edit EPG" msgstr "Modifica EPG" msgid "

Here you can edit the descriptive fields of an existing EPG entry.

" msgstr "

Qui puoi modificare i campi descrittivi di un valore EPG esistente.

" msgid "Channel (readonly)" msgstr "Canale (sola lettura)" msgid "This is the channel of the EPG entry. It cannot be changed." msgstr "Questo è il canale del valore EPG. Non può essere modificato." msgid "Time (readonly)" msgstr "Ora (sola lettura)" msgid "This is the start and end time of the entry. It cannot be changed." msgstr "Questa è l'ora di inizio e fine del valore. Non può essere modificato." msgid "Change this string to give this EPG Entry a new title. It must consist of only one line of text." msgstr "Cambia questa stringa per assegnare un nuovo titolo al valore EPG. Deve essere composta da una sola riga di testo." msgid "Change this string to give this EPG Entry a new subtitle. It must consist of only one line of text." msgstr "Cambia questa stringa per assegnare un nuovo sottotitolo al valore EPG. Deve essere composta da una sola riga di testo." msgid "Change the text in this field to edit the description of this entry. The text can consist of one or more lines." msgstr "Cambia il testo in questo campo per modificare la descrizione di questo valore. Il testo deve essere composto da una o più righe." msgid "VPS (readonly)" msgstr "VPS (sola lettura)" msgid "If available this field shows the vps time of the EPG entry. It cannot be changed." msgstr "Se disponibile questo campo mostra l'ora VPS del valore EPG. Non può essere modificato." msgid "Video tracks (readonly)" msgstr "Tracce video (sola lettura)" msgid "If available this field shows the video track(s). It cannot be changed." msgstr "Se disponibile questo campo mostra le tracce video. Non può essere modificato." msgid "Audio tracks (readonly)" msgstr "Tracce audio (sola lettura)" msgid "If available this field shows the audio track(s). It cannot be changed." msgstr "Se disponibile questo campo mostra le tracce audio. Non può essere modificato." msgid "No Help Available" msgstr "Nessun aiuto disponibile" msgid "

No help available yet. For adding or changing text please contact amair.sob@googlemail.com.

" msgstr "

Nessun aiuto ancora disponibile. Per aggiungere o cambiare il testo contatta amair.sob@googlemail.com.

" msgid "Recordings" msgstr "Registrazioni" msgid "

Here you will find a listing of recordings known to VDR. The headline will also show you VDR's total and free disk space.

The listing showing you some information on the recordings. You can change the list's sorting by clicking the columns heading. Above the list you'll see the navigation path. If you want to view the contents of previous folders you'll have to click on its name in that path.

Each row contains this information:

Date
The date when the recording has been done. In case of folders this will show the number of recordings the folder contains.
Time
The time when the recording has been done. In case of folders this will show the number of new recordings the folder contains.
Name
The recording's or folder's name. Click it to show the recording's summary or descend into the folder.
Rename (\"edit\")
Rename a recording.

Note:

This only works if VDR has the MOVR or RENR SVDRP command which is not a core VDR feature but provided by the Liemikuutio patch set.
Delete (\"delete\")
Delete a recording.
Stream (\"stream\")
This column is only shown if you activated and configured Recordings Streaming in the Configuration menu. You can watch the recording at your workstation.

In addition to these functions you can delete a number of recordings at once by checking the box in the last but one column of those recordings and clicking .

If you've set the path the VDR's configuration files and have entries in VDR's reccmds.conf you can run those commands for the selected recording by selecting the wanted command in the select box locate next to Commands: and pressing the button.

Use to force reloading of VDR's recordings listing.

" msgstr "

Qui troverai un elenco dei timer noti a VDR. L'intestazione mostrerà anche lo spazio disco totale e disponibile di VDR.

L'elenco mostra alcune informazioni sulle registrazioni. Puoi cambiare l'ordine della lista cliccando sull'intestazione della colonna. Sopra la lista vedrai il percorso di navigazione. Se vuoi vedere i contenuti delle directory precedenti dovrai cliccare sul suo nome in quel percorso.

Ciascuna riga contiene queste informazioni:

Data
La data in cui la registrazione è stata effettuata. Nel caso di directory questo mostrerà il numero di registrazioni delle directory contenute.
Ora
L'ora in cui la registrazione è stata effettuata. Nel caso di directory questo mostrerà il numero di nuove registrazioni che la directory contiene.
Nome
Il nome registrazione o della directory. Fai click per mostrare il sommario delle registrazioni oppure aprire la directory.
Rinomina (\"edit\")
Rinomina una registrazione.

Nota:

Questo funziona soltanto se VDR ha il comando SVDRPort RENR che non è integrato ma disponibile attraverso una patch. vdr-aio21_svdrprename.patch o enAIO-v2.2+ che fornisce questo comando.
Elimina (\"delete\")
Elimina una registrazione.
Trasmetti (\"stream\")
Questa colonna è mostrata solo se hai attivato e configurato la Registrazione delle trasmissioni nel menu di Configurazione. Puoi guardare la registrazione nel tuo pc.

In aggiunta a queste funzioni puoi eliminare un numero di registrazioni alla volta cliccando l'ultima casella ma solo una colonna di quelle registrazioni e cliccando .

Se hai impostato il percorso dei files di configurazione di VDR e hai valori nel file reccmds.conf di VDR puoi eseguire questi comandi per la registrazione selezionando il comando voluto nella casella di selezione posizionata vicino a Comandi: e premendo il pulsante .

Utilizza per forzare a ricaricare l'elenco delle registrazioni di VDR.

" msgid "

Here you will find a listing of timers known to VDR.

On top you will find a chart showing a day's timers graphically. This provides an quick overview on what's going on at the specified day and helps you in finding conflicting timers. Moving the mouse cursor above any timer box will display a tooltip containing the timer's title, priority, lifetime and duration.

Below the chart you'll find the timers list showing you some information on the timers. You can change the list's sorting by clicking the columns heading.

For each timer you have the following options:

Set its state
By clicking on \"Yes\", \"No\", \"VPS\" or \"Auto\" in the \"Active\" column.
Quickly view its priority and lifetime
By pointing the mouse cursor to the timer's title.
View its EPG entry
Timers that have set AutoTimer Checking to \"Transmission Identification\" will show you the corresponding EPG entry if you click on the timer's title.
Edit the timer
You can edit a timer by clicking \"edit\".
Delete the timer
To delete a timer you click \"delete\".

Each timer's state is indicated by differently coloured boxes (in the chart view) or images (in the list view):
    / \"on\" Timer is OK and will record.
    / \"problem\" Timer conflicts with other timers. That's not critical, as long as you have enough DVB cards for the parallel recordings.
    / \"impossible\" Timer is critical and will most likely not record.
    / \"inactive\" Timer is not active.

In addition to these functions you can add a new timer by clicking at the top and you can delete a number of timers at once by checking the box in the last column of those timers and clicking .

You can and selected timers.

" msgstr "

Qui troverai un elenco dei timer noti a VDR.

In cima troverai un diagramma che mostra i timers giornalieri graficamente. Questo fornisce una vista veloce su cosa stia succedendo in un giorno specifico e ti aiuta a trovare i timers in conflitto. Spostando il cursore del mouse sopra ciascuna casella dei timer sarà visualizzato un dettaglio contenente il titolo del timer, la priorità, la scadenza e la durata.

Sotto il diagramma troverai l'elenco dei timer che ti mostrano alcune informazioni sui timers. Puoi modificare l'ordine della lista cliccando sull'intestazione delle colonne.

Per ciascun timer hai le seguenti opzioni:

Impostare lo stato
Cliccando su \"Sì\", \"No\", \"VPS\" o \"Auto\" nella colonna \"Attiva\".
Vedere velocemente la priorità e la durata
Puntando il cursore del mouse nel titolo del timer.
Vedere il valore EPG
I timers che hanno impostato Verifica timer automatici per \"Identificazione Trasmissione\" ti mostreranno il valore EPG corrispondente se fai click sul titolo del timer.
Modificare il timer
Puoi modificare il timer cliccando \"modifica\".
Eliminare il timer
Per eliminare un timer fai click su \"elimina\".

Lo stato di ciascun timer è indicato a seconda delle caselle colorate (vedi diagramma) o immagini (vedi elenco):
    / \"on\" Il timer è OK e registrerà.
    / \"problem\" Conflitti di timers con altri uguali. Questo non è critico, se tu hai abbastanza schede DVB per le registrazioni in parallelo.
    / \"impossible\" Il timer è critico e molto probabilmente non registrerà.
    / \"inactive\" Il timer non è attivo.

In aggiunta a queste funzioni puoi aggiungere un nuovo timer cliccando su in cima e puoi eliminare un numero di timers alla volta cliccando nella casella dell'ultima colonna di quei timers e cliccando .

Puoi e i timers selezionati.

" msgid "

Here you can edit a timer's settings.

" msgstr "

Qui puoi modificare le impostazioni dei timer.

" msgid "Timer Active:" msgstr "Timer attivo:" msgid "Activate or deactivate this timer. Deactivated timers are still stored in the timer list so that they can be activated again, but they do not record anything meanwhile." msgstr "Attiva o disattiva questo timer. I timer disattivati sono salvati sempre nell'elenco dei timer in modo che tu possa attivarli ancora, ma non registrano niente nel frattempo." msgid "AutoTimer Checking:" msgstr "Verifica timer automatici:" msgid "Depending on how this timer has been programmed you have up to three possible settings:" msgstr "A seconda di come questo timer è stato programmato hai fino a 3 possibili impostazioni:" msgid "Transmission Identification" msgstr "Identificazione trasmissione" msgid "Monitor this timer using the identification provided in the EPG. Please note that this only works if the provided identification is a fix and unique value! This option is not available with timers programmed in VDR." msgstr "Monitora questo timer utilizzando l'identificazione usata dall'EPG. Nota che questo funziona solo se l'identificazione fornita è un valore fisso ed unico! Questa opzione non è disponibile con i timer programmati in VDR." msgid "Time" msgstr "Ora" msgid "Monitor this timer using the start and stop time." msgstr "Monitora questo timer utilizzando l'ora di inizio e fine." msgid "off" msgstr "disattivo" msgid "Do not monitor this timer." msgstr "Non monitorare questo timer." msgid "The channel to record." msgstr "Canale da registrare." msgid "Day Of Recording:" msgstr "Giorno registrazione:" msgid "The day when the timer should get active. You can enter the day in two formats:
  • Two digits (DD). This will use the current month and year.
  • ISO norm (YYYY-MM-DD). Program your timers as far in the future as you like.
In case you want to program a repeating timer you can use the seven checkboxes below the text field. Check the box for each day you want the timer to get active." msgstr "Il giorno in cui il timer dovrebbe attivarsi. Puoi inserire il giorno in 2 formati:
  • Due caratteri (GG). Questo userà il mese e l'anno corrente.
  • Modo ISO (AAAA-MM-GG). Programma i tuoi timer per il futuro come vuoi.
Nel caso tu voglia programmare un timer ricorsivo puoi usare le 7 caselle sotto il campo di testo. Spunta la casella per ogni giorno in cui vuoi attivare il timer." msgid "Start Time:" msgstr "Ora inizio:" msgid "This is the time when the timer should start recording. The first text field is for \"hour\", the second for \"minute\"." msgstr "Questa è l'ora in cui il timer dovrebbe avviare la registrazione. Il primo campo di testo è per l'\"ora\", il secondo per i \"minuti\"." msgid "End Time:" msgstr "Ora fine:" msgid "This is the time when the timer should stop recording. The first text field is for \"hour\", the second for \"minute\"." msgstr "Questa è l'ora in cui il timer dovrebbe fermare la registrazione. Il primo campo di testo è per l'\"ora\", il secondo per i \"minuti\"." msgid "Title of Recording:" msgstr "Titolo registrazione:" msgid "The file name this timer will give to a recording. If the name shall contain subdirectories, these have to be delimited by '~' (since the '/' character may be part of a regular programme name).

The special keywords TITLE and EPISODE, if present, will be replaced by the title and episode information from the EPG data at the time of recording (if that data is available). If at the time of recording either of these cannot be determined, TITLE will default to the channel name, and EPISODE will default to a blank." msgstr "Il nome file che questo timer assegnerà alla registrazione. Se il nome conterrà sottodirectory, queste devono essere delimitate da '~' (dal momento che il carattere '/' può essere parte del nome di un programma).

Le parole chiave speciali TITOLO ed EPISODIO, se presenti, saranno sostituite dalle informazioni del titolo e dell'episodio dei dati EPG all'ora di registrazione (se questi dati sono disponibili). Se all'ora di registrazione questi non possono essere determinati, il TITOLO predefinito sarà il nome canale, e l'EPISODIO predefinito sarà lasciato vuoto." msgid "Summary:" msgstr "Sommario:" msgid "Arbitrary text that describes the recording made by this timer. If this field is not empty, its contents will be written into the summary.vdr or info.vdr file of the recording." msgstr "Testo arbitrario che descrive la registrazione fatta da questo timer. Se il campo non è vuoto, il suo contenuto sarà sovrascritto nel file di registrazione summary.vdr oppure info.vdr." msgid "Your Browser does not support frames!" msgstr "Il tuo browser non supporta i frames!" msgid "What's On Now?" msgstr "In programmazione adesso" msgid "Playing Today?" msgstr "In esecuzione oggi" msgid "Remote Control" msgstr "Telecomando" msgid "Watch TV" msgstr "Guarda TV" msgid "Commands" msgstr "Comandi" msgid "Search" msgstr "Cerca" msgid "Authorization Required" msgstr "Richiesta autorizzazione" msgid "This server could not verify that you are authorized to access the document requested. Either you supplied the wrong credentials (e.g. bad password), or your browser doesn't understand how to supply the credentials required." msgstr "Questo server non può verificare se tu sei autorizzato ad accedere al documento richiesto. Inoltre hai fornito le credenziali errate (esempio: password sbagliata), oppure il tuo browser non capisce come fornire le credenziali richieste." msgid "VPS" msgstr "VPS" msgid "close" msgstr "chiudi" msgid "view" msgstr "mostra" msgid "search" msgstr "cerca" msgid "edit" msgstr "modifica" msgid "Length" msgstr "Durata" msgid "Video tracks:" msgstr "Tracce video:" msgid "Audio tracks:" msgstr "Tracce audio:" msgid "Subtitles:" msgstr "Sottotitoli:" msgid "Video tracks" msgstr "Tracce video" msgid "Audio tracks" msgstr "Tracce audio" msgid "TV select" msgstr "Seleziona TV" msgid "Stream" msgstr "Trasmetti" msgid "Channel group:" msgstr "Gruppo canali:" msgid "Go!" msgstr "Vai!" msgid "Search for other show times" msgstr "Cerca altri spettacoli" msgid "No Information" msgstr "Nessuna informazione" msgid "No EPG information available" msgstr "Nessuna informazione EPG disponibile" msgid "Playing Today" msgstr "In esecuzione oggi" msgid "starting at" msgstr "inizio alle" msgid "What's on:" msgstr "In programmazione:" msgid "at" msgstr "alle" msgid "now" msgstr "adesso" msgid "to" msgstr "a" msgid "Duration:" msgstr "Durata:" msgid "min" msgstr "min" msgid "at:" msgstr "alle:" msgid "You need JavaScript to use the timeline!" msgstr "Serve Javascript per usare la linea temporale!" msgid "Rename Recording" msgstr "Rinomina registrazione" msgid "Original Name of Recording:" msgstr "Nome registrazione originale:" msgid "New Name of Recording:" msgstr "Nuovo nome registrazione:" msgid "Subtitle:" msgstr "Sottotitolo:" msgid "Rename" msgstr "Rinomina" msgid "Total:" msgstr "Totale:" msgid "h" msgstr "h" msgid "Free:" msgstr "Disponibile:" msgid "Date" msgstr "Data" msgid "Total" msgstr "Totale" msgid "New" msgstr "Nuovo" msgid "Play" msgstr "Esegui" msgid "Cut" msgstr "Taglia" msgid "Delete recording?" msgstr "Eliminare registrazione?" msgid "Refresh" msgstr "Aggiorna" msgid "Commands:" msgstr "Comandi:" msgid "Really run this command?" msgstr "Sicuro di eseguire questo comando?" msgid "stream all recordings" msgstr "" msgid "Delete Selected Recordings" msgstr "Elimina registrazioni selezionate" msgid "Delete all selected recordings?" msgstr "Eliminare tutte le registrazioni selezionate?" msgid "No recordings available" msgstr "Nessuna registrazione disponibile" msgid "Transponder:" msgstr "Transponder:" msgid "CA-System:" msgstr "Sistema CA:" msgid "New Timer" msgstr "Nuovo timer" msgid "Edit timer status?" msgstr "Modificare stato timer?" msgid "This timer is inactive!" msgstr "Questo timer è inattivo!" msgid "This timer is impossible!" msgstr "Questo timer è impossibile!" msgid "No more timers on other transponders possible!" msgstr "Nessun altro timer è possibile sugli altri transponder!" msgid "Timer OK." msgstr "Timer OK." msgid "Auto" msgstr "Auto" msgid "activate" msgstr "attiva" msgid "inactivate" msgstr "disattiva" msgid "selected timers" msgstr "timer selezionati" msgid "Delete Selected Timers" msgstr "Elimina timer selezionati" msgid "No timers defined!" msgstr "Nessun timer definito!" msgid "Create New Timer" msgstr "Crea nuovo timer" msgid "Buffer:" msgstr "Buffer:" msgid "Use VPS:" msgstr "Utilizza VPS:" msgid "readonly" msgstr "solo lettura" msgid "Timer has been set by AutoTimer pattern:" msgstr "Timer impostato dal valore timer automatico:" msgid "TV" msgstr "TV" msgid "Interval:" msgstr "Intervallo:" msgid "sec." msgstr "sec." msgid "G" msgstr "C" msgid "Grab the picture!" msgstr "Cattura immagine!" msgid "Size:" msgstr "Dimensione:" msgid "Open in separate window" msgstr "Apri in una nuova finestra" msgid "VDR Commands" msgstr "Comandi VDR" msgid "Export channels as playlist:" msgstr "Esporta i canali come lista esecuzione:" msgid "Number of lines to show:" msgstr "Numero di righe da mostrare:" msgid "unlimited" msgstr "illimitate" msgid "SVDRP commands:" msgstr "Comandi SVDR:" msgid "Commands defined in commands.conf:" msgstr "Comandi definiti in commands.conf:" msgid "Output" msgstr "Risultato" msgid "What's your VDR hostname (e.g video.intra.net)?" msgstr "Nome sistema di VDR (ad esempio video.intra.net)?" msgid "On which port does VDR listen to SVDRP queries?" msgstr "Su quale porta VDR riceve le richieste di SVDP?" msgid "On which address should VDRAdmin-AM listen (0.0.0.0 for any)?" msgstr "Su quale indirizzo dovrebbe essere in ascolto VDRAdmin-AM (0.0.0.0 per tutti)?" msgid "On which port should VDRAdmin-AM listen?" msgstr "Su quale porta dovrebbe essere in ascolto VDRAdmin-AM?" msgid "Username?" msgstr "Nome utente?" msgid "Password?" msgstr "Password?" msgid "Where are your recordings stored?" msgstr "Dove sono salvate le tue registrazioni?" msgid "Where are your VDR's configuration files located?" msgstr "Dove si trovano i files di configurazione di VDR?" msgid "Config file written successfully." msgstr "File Config scritto manualmente." #, perl-format msgid "%s %s started with pid %d." msgstr "%s %s avviato con pid %d." msgid "Not found" msgstr "Non trovato" msgid "The requested URL was not found on this server!" msgstr "L'URL richiesto non si trova su questo server!" msgid "Forbidden" msgstr "Vietato" msgid "You don't have permission to access this function!" msgstr "Non hai i permessi per accedere a questa funzione!" msgid "All channels" msgstr "Tutti i canali" msgid "Selected channels" msgstr "Canali selezionati" msgid "TV channels" msgstr "Canali TV" msgid "Radio channels" msgstr "Canali Radio" #, perl-format msgid "Access to file \"%s\" denied!" msgstr "Accesso al file \"%s\" negato!" #, perl-format msgid "The URL \"%s\" was not found on this server!" msgstr "URL \"%s\" non trovato su questo server!" msgid "Your favorites" msgstr "I tuoi preferiti" msgid "Search results" msgstr "Cerca risultati" msgid "Default" msgstr "Predefinito" msgid "--- no timer ---" msgstr "--- nessun timer ---" msgid "unknown" msgstr "sconosciuto" msgid "none" msgstr "nessuno" #, perl-format msgid "Can't open file \"%s\"!" msgstr "Non posso aprire il file \"%s\"!" #, perl-format msgid "Can't connect to VDR at %s:%s: %s

Please check if VDR is running and if VDR's svdrphosts.conf is configured correctly." msgstr "Impossibile collegarsi a VDR al %s:%s: %s

Controlla che VDR sia in esecuzione e che il file svdrphosts.conf di VDR sia configurato correttamente." #, perl-format msgid "Error while sending command to VDR at %s" msgstr "Errore durante l'invio del comando a VDR alle %s" msgid "Internal error:" msgstr "Errore interno:" msgid "Lookup movie in the Internet-Movie-Database (IMDb)" msgstr "Cerca film in Internet-Movie-Database (IMDb)" msgid "Can't find EPG entry!" msgstr "Impossibile trovare il valore EPG!" msgid "Playing Tomorrow" msgstr "In esecuzione domani" #, perl-format msgid "Playing on the %s" msgstr "In esecuzione il %s" msgid "next" msgstr "prossimi" msgid "What's on after" msgstr "In programmazione dopo" msgid "What's on at" msgstr "In programmazione alle" msgid "Suitable matches for:" msgstr "Corrispondenze adatte per:" msgid "short view" msgstr "vista breve" msgid "long view" msgstr "vista estesa" msgid "Schedule" msgstr "Programmi" #, perl-format msgid "Can't write configuration file %s! Reason: %s" msgstr "Impossibile scrivere il file di configurazione %s! Motivo: %s" #, perl-format msgid "Configuration file %s not writable! Configuration won't be saved!" msgstr "File di configurazione %s non modificabile! La configurazione non sarà salvata!" msgid "Timers" msgstr "Timer" msgid "System default" msgstr "Predefinita di sistema" vdradmin-am-3.6.13/po/nl.po000066400000000000000000002137211443716113400154040ustar00rootroot00000000000000# Vertaling van @VDRADMIN-AM@.po to @Nederlands@ # translation of nl.po to # Copyright (C) Andreas Mair # This file is distributed under the same license as the VDRAdmin-AM package. # # # Roel , 2005, 2006, 2007. # Roel Koelewijn , 2007, 2008, 2010. msgid "" msgstr "" "Project-Id-Version: VDRAdmin-AM-3.6.7\n" "Report-Msgid-Bugs-To: Andreas Mair \n" "POT-Creation-Date: 2012-07-09 12:23+0200\n" "PO-Revision-Date: 2011-11-18 23:41+0200\n" "Last-Translator: Ville Skyttä \n" "Language-Team: Dutch \n" "Language: nl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Generator: KBabel 1.11.4\n" msgid "About" msgstr "Over" msgid "License" msgstr "Licentie" msgid "Authors" msgstr "Auteurs" msgid "Current author (VDRAdmin-AM branch):" msgstr "Huidige auteur (VDRAdmin-AM branch):" msgid "Original author (VDRAdmin):" msgstr "Originele auteur van (VDRAdmin):" msgid "Translation Team" msgstr "Vertalers team" msgid "English:" msgstr "Engels:" msgid "German:" msgstr "Duits:" msgid "French:" msgstr "Frans:" msgid "At the moment unmaintained, former translations by:" msgstr "Op dit moment niet onderhouden, eerdere vertalingen door:" msgid "Spanish:" msgstr "Spaans:" msgid "Finnish:" msgstr "Fins:" msgid "Dutch:" msgstr "Nederlands:" msgid "Russian:" msgstr "Russies" msgid "Czech:" msgstr "Tjechies:" msgid "Italian:" msgstr "Italiaans:" msgid "Hungarian:" msgstr "" msgid "Information" msgstr "Informatie" msgid "VDRAdmin-AM version:" msgstr "VDRAdmin-AM versie:" msgid "VDR version:" msgstr "VDR versie:" msgid "Supported features in VDR:" msgstr "Ondersteunde elementen in VDR" msgid "EPGSearch" msgstr "EPG zoeken" msgid "EPGSearch Plugin" msgstr "" msgid "LiveTV Streaming" msgstr "" msgid "Streamdev Plugin" msgstr "" msgid "Xineliboutput Plugin" msgstr "" msgid "Rename Recordings (Liemikuutio Patch)" msgstr "Hernoem opnames (Liemikuutio Patch)" msgid "Getting Help and Reporting Bugs" msgstr "Voor het verkrijgen van hulp en melden van bugs" msgid "If you need help please first try to use the online help you'll find on some pages. You can access it by clicking \"\"." msgstr "Als u hulp nodig heeft probeer dan eerst de online hulp, u zult enige pagina's vinden. U kunt dit bezoeken door op \"\" te klikken." msgid "If this doesn't provide the information you need you can try to get help at VDR-Portal if you understand German language. Please use the announcement thread if possible, search for:" msgstr "Als dit niet de informatie verschaft die u zoekt dan kunt u het proberen op VDR-Portal als u de Duitse taal verstaat. Gebruik graag de bekendmakingen draad indien mogelijk, zoek naar:" msgid "If you think you have found a bug please check that it's a new one and report it in the VDRAdmin-AM BugTracking system." msgstr "Als u denkt een bug gevonden te hebben controleer dan graag eerst of dit een nieuwe is en meld het in de VDRAdmin-AM BugTracking systeem." msgid "AutoTimer" msgstr "AutoTimer" msgid "Priority:" msgstr "Prioriteit:" msgid "Lifetime:" msgstr "Levensduur:" msgid "New AutoTimer" msgstr "Nieuwe AutoTimer" msgid "Help" msgstr "Help" msgid "Active" msgstr "Aktief" msgid "Channel" msgstr "Kanaal" msgid "Start" msgstr "Start" msgid "Stop" msgstr "Stop" msgid "Name" msgstr "Naam" msgid "Select all/none" msgstr "Selecteer alles/niets" msgid "Yes" msgstr "Ja" msgid "No" msgstr "Nee" msgid "Edit" msgstr "Bewerken" msgid "Delete timer?" msgstr "Timer verwijderen? " msgid "Delete" msgstr "Verwijderen" msgid "Force Update" msgstr "Verversen forceren" msgid "Delete Selected AutoTimers" msgstr "Verwijder geselecteerde Auto Timers" msgid "Delete all selected timers?" msgstr "Verwijder alle geselecteerde timers?" msgid "No AutoTimers defined!" msgstr "Geen Auto timers ingesteld!" msgid "Add New AutoTimer" msgstr "Nieuwe auto timer toevoegen " msgid "Edit AutoTimer" msgstr "Auto timer bewerken" msgid "AutoTimer Active:" msgstr "Auto timer aktief:" msgid "oneshot" msgstr "eenmalig" msgid "Search Patterns:" msgstr "Zoek patronen:" msgid "Search in:" msgstr "Zoeken in: " msgid "Title" msgstr "Titel" msgid "Subtitle" msgstr "Ondertitel" msgid "Description" msgstr "Omschrijving" msgid "Search only on these days:" msgstr "Alleen zoeken op deze dagen:" msgid "Monday" msgstr "Maandag" msgid "Tuesday" msgstr "Dinsdag" msgid "Wednesday" msgstr "Woensdag" msgid "Thursday" msgstr "Donderdag" msgid "Friday" msgstr "Vrijdag" msgid "Saturday" msgstr "Zaterdag" msgid "Sunday" msgstr "Zondag" msgid "Channel:" msgstr "Kanaal" msgid "all" msgstr "Alle" msgid "Starts After:" msgstr "Start na: " msgid "o'clock" msgstr "Uur" msgid "Ends Before:" msgstr "Eindigd voor: " msgid "Override Start/Stop Margins:" msgstr "Start/stop marges overschrijden" msgid "Time Margin at Start:" msgstr "Tijd marge bij start:" msgid "minutes" msgstr "minuten" msgid "Time Margin at Stop:" msgstr "Tijd marge bij stop:" msgid "Episode:" msgstr "Aflevering:" msgid "Remember programmed timers:" msgstr "Herinner geprogrammeerde timer:" msgid "Directory:" msgstr "Map:" msgid "Save" msgstr "Opslaan" msgid "Test" msgstr "Test" msgid "Cancel" msgstr "Annuleren" msgid "Broadcasted" msgstr "Uitgezonden" msgid "Stored in" msgstr "Opgeslagen in" msgid "No matches found!" msgstr "Geen overeenkomsten gevonden!" msgid "Configuration" msgstr "Configuratie" msgid "General Settings" msgstr "Algemene instellingen" msgid "Template:" msgstr "Sjabloon:" msgid "Skin:" msgstr "Skin:" msgid "Login Page:" msgstr "Inlog pagina:" msgid "Number of channels to use:" msgstr "Aantal te tonen kanalen:" msgid "Local net (no login required):" msgstr "Lokaal netwerk (geen login benodigd):" msgid "Language:" msgstr "Taal:" msgid "Save settings on exit:" msgstr "Instellingen opslaan bij afsluiten:" msgid "VDR" msgstr "VDR" msgid "Number of DVB cards:" msgstr "Aantal DVB kaarten:" msgid "Path to recordings:" msgstr "Pad voor opnames:" msgid "Path to configuration files:" msgstr "Pad naar configuratie bestanden:" msgid "Path to EPG images:" msgstr "Pad naar EPG beelden:" msgid "Identification" msgstr "Identificatie" msgid "Username:" msgstr "Gebruikersnaam:" msgid "Password:" msgstr "Wachtwoord:" msgid "Guest Account:" msgstr "Gast Account:" msgid "Guest Username:" msgstr "Gebruikersnaam gast:" msgid "Guest Password:" msgstr "Wachtwoord gast" msgid "Timeline" msgstr "Tijdlijn" msgid "Hours:" msgstr "Uur:" msgid "Times:" msgstr "Tijden:" msgid "Also used for other EPG views!" msgstr "Word ook gebruikt voor andere EPG" msgid "Tooltips:" msgstr "Handigheden:" msgid "Electronic Program Guide (EPG)" msgstr "Electronische Programma Gids (EPG)" msgid "Day begins at:" msgstr "Dag begint om:" msgid "Show Subtitle:" msgstr "Toon ondertitel:" msgid "Show Summary:" msgstr "Toon samenvatting:" msgid "Active:" msgstr "Aktief:" msgid "Send email after programming timer:" msgstr "Stuur email na het programmeren van de timer:" msgid "Send email as:" msgstr "Stuur email als:" msgid "Send email to:" msgstr "Stuur email naar:" msgid "Mail server:" msgstr "Mail server:" msgid "SMTPAuth user:" msgstr "SMTPAuth gebruiker:" msgid "SMTPAuth password:" msgstr "SMTPAuth Wachtwoord:" msgid "Track schedule changes by:" msgstr "Track schema veranderd door :" msgid "Broadcast time" msgstr "Uitzendtijd" msgid "Event id" msgstr "Evenement id" msgid "Timer" msgstr "Timer" msgid "Tooltips in timeline:" msgstr "Handigheden in de tijdlijn:" msgid "Tooltips in list:" msgstr "Handigheden in lijst:" msgid "Streaming" msgstr "Streaming" msgid "Live Streaming:" msgstr "Live Streaming:" msgid "HTTP Port of Streamdev (also possible 3000/ts):" msgstr "HTTP Poort van Streamdev (ook mogelijk 3000/ts):" msgid "HTTP Port of Xineliboutput (e.g. 37890):" msgstr "" msgid "Recordings Streaming:" msgstr "Streaming opnames:" msgid "Path to VDR Recordings on your workstation:" msgstr "Pad naar VDR opnames op uw werkstation:" msgid "MIME type for live streaming:" msgstr "Mime type voor live streaming:" msgid "Suffix for live streaming:" msgstr "Extensie voor Live Streaming:" msgid "MIME type for recordings streaming:" msgstr "MIME type voor opgenomen Streaming:" msgid "Suffix for recordings streaming:" msgstr "Extensie voor opgenomen Streaming:" msgid "Bandwidth of Streams:" msgstr "Bandbreedte van streams:" msgid "External Search" msgstr "Extern zoeken" msgid "URL:" msgstr "URL:" msgid "Title:" msgstr "Titel:" msgid "User-defined search:" msgstr "Gebruikers definieert zoeken" msgid "Expert" msgstr "Expert" msgid "Update EPG data in background:" msgstr "Bijwerken van EPG gegevens in de achtergrond:" msgid "Update EPG every:" msgstr "Werk EPG bij iedere:" msgid "Channel Selections" msgstr "Kanaal selecties" msgid "Show channels without EPG information:" msgstr "Toon kanalen zonder EPG informatie:" msgid "In \"AutoTimer\"?" msgstr "In \"AutoTimer\"?" msgid "Apply" msgstr "Toepassen" msgid "EPG Search Blacklists" msgstr "EPG zoeken zwarte lijsten" msgid "New Blacklist" msgstr "Nieuwe zwarte lijst" msgid "Search pattern" msgstr "Zoek patroon" msgid "From" msgstr "van" msgid "To" msgstr "Naar" msgid "Delete blacklist?" msgstr "Verwijder zwarte lijst?" msgid "Delete Selected Blacklists" msgstr "Verwijder geselecteerde zwarte lijst" msgid "Delete all selected blacklists?" msgstr "Verwijder alle geselecteerde zwarte lijsten?" msgid "EPG search" msgstr "Auto timer" msgid "EPG Search" msgstr "Auto timer" msgid "Use template" msgstr "Gebruik sjabloon" msgid "New Search" msgstr "Nieuwe zoekopdracht" msgid "Edit Template" msgstr "Sjabloon bewerken" msgid "Settings" msgstr "Instellingen" msgid "Action" msgstr "Aktie" msgid "Find" msgstr "Vinden" msgid "Show Favorites" msgstr "Toon favorieten" msgid "Delete Selected Searches" msgstr "Verwijder geselecteerde zoek opdrachten" msgid "Delete all selected searches?" msgstr "Verwijder alle geselecteerde zoek opdrachten?" msgid "Execute Selected Searches" msgstr "Uitvoeren geselecteerde zoek opdrachten" msgid "Duration" msgstr "Duur" msgid "More Information" msgstr "Meer informatie" msgid "Channels" msgstr "Kanalen" msgid "Record" msgstr "Opnemen" msgid "Add New Blacklist" msgstr "Zwarte lijsten toevoegen" msgid "Edit Blacklist" msgstr "Bewerk zwarte lijst" msgid "Add New Template" msgstr "Nieuw sjabloon toevoegen " msgid "Add New Search" msgstr "Voeg nieuw zoekpatroon toe" msgid "Edit Search" msgstr "Bewerk zoeken" msgid "Small search pattern.\\nDo you really want to use it?" msgstr "Klein zoek patroon.\\nWilt u dit echt gebruiken?" msgid "You didn't select at least one of\\ntitle, subtitle or description.\\nDo you really want to use this search?" msgstr "U moet tenminste één \\ntitel, ondertitel of omschrijving selecteren. \\nWilt u deze zoek opdracht daadwerkelijk gebruiken?" msgid "Hide results" msgstr "Verberg resultaten" msgid "Name:" msgstr "Naam:" msgid "Search Term:" msgstr "Zoeken term: " msgid "Search Mode:" msgstr "Zoeken modus: " msgid "phrase" msgstr "Uitdrukking" msgid "all words" msgstr "alle woorden" msgid "at least one word" msgstr "tenminste één woord" msgid "match exactly" msgstr "exacte overeenkomst" msgid "regular expression" msgstr "reguliere expressie" msgid "fuzzy" msgstr "wazig" msgid "Tolerance for \"fuzzy\":" msgstr "Tolerantie voor \"wazig\":" msgid "Match Case:" msgstr "Hoofdletter gevoelig:" msgid "Use extended EPG info:" msgstr "Gebruik uitgebreide EPG info:" msgid "Ignore missing categories?" msgstr "Negeer missende catogerien" msgid "Use Channel:" msgstr "Gebruik kanaal:" msgid "no" msgstr "nee" msgid "interval" msgstr "Interval" msgid "channel group" msgstr "Kanaal groep" msgid "only FTA" msgstr "Alleen FTA" msgid "Range:" msgstr "Bereik:" msgid "Channel Group:" msgstr "Kanaal groep:" msgid "Use Time:" msgstr "Gebruik tijd:" msgid "Start After:" msgstr "Start na:" msgid "Start Before:" msgstr "Start voor: " msgid "Use Duration:" msgstr "Gebruik tijdsduur:" msgid "Min. Duration:" msgstr "minimale tijdsduur:" msgid "hh:mm" msgstr "uu:mm" msgid "Max. Duration:" msgstr "Maximale tijdsduur:" msgid "Use Day of Week:" msgstr "Gebruik dag van de week:" msgid "Use Blacklists:" msgstr "Gebruik zwarte lijsten:" msgid "selection" msgstr "Selectie" msgid "Use in Favorites Menu:" msgstr "Gebruik in favorieten menu:" msgid "Use as Search Timer:" msgstr "Gebruik als zoek timer:" msgid "yes" msgstr "Ja" msgid "user-defined" msgstr "Gebruikers gedefinieerd" msgid "record" msgstr "opnemen" msgid "announce by OSD" msgstr "Aangekondigd door OSD" msgid "switch only" msgstr "alleen wisselen" msgid "announce and switch" msgstr "aankondigen en wisselen" msgid "announce by mail" msgstr "aankondigen per mail" msgid "First day:" msgstr "Eerste dag:" msgid "Last day:" msgstr "Laatste dag:" msgid "Auto delete:" msgstr "Automatisch verwijderen:" msgid "count recordings" msgstr "opnames tellen" msgid "count days" msgstr "dagen tellen" msgid "After ... recordings:" msgstr "Na...opnames:" msgid "After ... days after first recording:" msgstr "Na...dagen na eerste opname:" msgid "Settings for action \"record\"" msgstr "Instellingen voor aktie \"opname\"" msgid "Series Recording:" msgstr "Opname series:" msgid "Delete Recordings After ... Days:" msgstr "Opnames verwijderen na ... dagen:" msgid "Keep ... Recordings:" msgstr "Opnames bewaren:" msgid "Pause, when ... recordings exist:" msgstr "Pauzeren, als ... opname bestaat:" msgid "Avoid Repeats:" msgstr "Voorkom herhalingen:" msgid "Allowed Repeats:" msgstr "Toegestane herhalingen:" msgid "Only Repeats Within ... Days:" msgstr "Alleen herhalingen binnen .. Dagen:" msgid "Compare:" msgstr "Vergelijken:" msgid "Minimal match of description in %:" msgstr "Minimale overeenkomsten in de omschrijving in %" msgid "VPS:" msgstr "VPS:" msgid "Settings for action \"switch only\"" msgstr "Instellingen voor aktie \"wissel alleen\"" msgid "Switch ... Minutes Before Start:" msgstr "Wissel ... minuten voor start:" msgid "Unmute sound:" msgstr "Geluid aan:" msgid "Settings for action \"announce and switch\"" msgstr "Instellingen voor de aktie \"bekend maken en wisselen\"" msgid "Ask ... Minutes Before Start:" msgstr "Vraag ... minuten voor aanvang:" msgid "Delete template" msgstr "Verwijder sjabloon" msgid "Delete this template?" msgstr "Dit sjabloon verwijderen? " msgid "Save as template" msgstr "Opslaan als sjabloon" msgid "Run" msgstr "Uitvoeren" msgid "Error!" msgstr "Fout!" msgid "

Here you will find a listing of automatic timers (AutoTimer) known to VDRAdmin-AM.

The list shows some information on AutoTimers. You can change the list's sorting by clicking the columns heading.

For each AutoTimer you have the following options:

Set its state
By clicking on \"Yes\" or \"No\" in the \"Active\" column to toggle the activity.
Quickly view its priority and lifetime
By pointing the mouse cursor to the AutoTimer's title.
Edit the AutoTimer
You can edit an AutoTimer by clicking \"edit\".
Delete the AutoTimer
To delete an AutoTimer you click \"delete\".

Each AutoTimer's state is indicated by differently coloured images:
\"on\" AutoTimer is OK and will automatically program matching broadcasts.
\"inactive\" AutoTimer is not active.

In addition to these functions you can add a new AutoTimer by clicking at the top and you can delete a number of AutoTimers at once by checking the box in the last column of those timers and clicking .

Click to force VDRAdmin-AM to reconnect to VDR, fetch the current EPG and check for matching AutoTimers.

" msgstr "

Hier vind u de lijst van automatische timers (AutoTimer) die bekend zijn bij VDRAdmin-AM.

De lijst toont enige informatie over auto timers. U kunt de lijst's sortering veranderen door op de kolom hoofden te klikken.

Voor iedere autotimer heeft u de volgende mogelijkheden:

De status instellen
door te klikken op \"Ja\" of \"Nee\" in de \"Actief\"kolom om de activiteit te wisselen.
Het snel bekijken van de prioriteit en levensduur
door de muiscursor over de auto timers titel te bewegen.
Bewerk de autotimer
U kunt een auto timer bewerken door te klikken op\"edit\".
Verwijder de auto timer
Om een auto timer te verwijderen klik op \"verwijderen\".

De status van iedere auto timer word aangeduid door verschillend gekleurde afbeeldingen
\"aan\" auto timer is OK en zal overeenkomstige programma's opnemen
\"uit\" auto timer is niet aktief.

Aanvullend bij deze functies kunt u een nieuwe auto timer toevoegen door te klikken op bovenin kunt u een aantal auto timers verwijderen door ze aan te vinken in de laatste kolom van deze timers en klik dan op .

Klik om VDRAdmin-AM te dwingen om her te verbinden met VDR, de laatste EPG data op te halen en te controleren voor overeenkomstige timers.

" msgid "

Here you can edit an automatic timer's (AutoTimer) settings.

AutoTimer is a key feature of VDRAdmin-AM. An AutoTimer consists of one or more search terms and some other settings, that are looked for regularly in the Electronic Program Guide (EPG). On match AutoTimer adds a timer in VDR automatically for that broadcast. That's very comfortable for irregularly broadcasted series or movies you don't want to miss.

" msgstr "

Hier kunt u de instellingen van de automatische timers (AutoTimer) bewerken.

De auto timer is een sleutel eigenschap van VDRAdmin-AM. Een auto timer bevat een of meer zoek termen en andere instellingen waarnaar regelmatig gezocht word in de Elektronische Programma Gids (EPG). Bij een overeenkomst word een timer toegevoegd. Dit is zeer gemakkelijk voor onregelmatig uitgezonden series of voor film die u niet wilt missen.

" msgid "Activate or deactivate this AutoTimer. Deactivated AutoTimers are still stored in the AutoTimer list so that they can be activated again, but they do not record anything meanwhile. Above that you can set this to \"oneshot\" so this AutoTimer only programs the (one!) next matching broadcast." msgstr "Activeer of deactiveer deze auto timer. Als ze zijn gedeactiveerd worden ze nog steeds bewaard in de auto timer lijst zodat ze weer opnieuw geactiveerd kunnen worden, maar ondertussen nemen ze niets op. Bovendien kunt u dit instellen op \"eenmalig\" zodat deze auto timer alleen de eerst volgende overeenkomstige programma zal opnemen." msgid "Choosing the right search items decides whether only the wanted broadcasts or broadcasts having similar names or even nothing gets recorded.
Case doesn't matter, \"X-Files\" matches anything \"x-files\" will match. You can set multiple search items by separating them with spaces. Broadcasts will match only if they match all configured search items.
You'd better only use letters and numbers for search items, as the EPG often miss colons, brackets and other characters.
Experts can also use regular expressions, but you have to get needed information from the VDRAdmin-AM sources (undocumented feature).

You can exclude broadcasts so that they don't get recorded even if they would match an AutoTimer. Therefore you have to enter that titles into the file vdradmind.bl, one event a line. This file must be located in your VDRAdmin-AM's configuration folder. If this string is found either in the EPG's title or in title~subtitle, this event will not be programmed by AutoTimer. So you can disable complete episodes (for example when using \"Enterprise\" as blacklist string) or only one episode (when using \"Enterprise~Azati Prime\" as blacklist string)." msgstr "Het kiezen van de juiste zoekpatronen maakt het verschil tussen het opnemen van gewenste uitzendingen, uitzendingen met gelijksoortige namen of dat er niets opgenomen word
hoofd of kleine letters maken niet uit, \"X-Files\" of \"x-files\" leidt tot hetzelfde resultaat. U kunt meerdere zoekpatronen gebruiken door ze te scheiden door spaties. Alleen programma's die alle zoektermen bevatten zullen leiden tot een opname .
U kunt beter alleen cijfers en letters gebruiken voor de zoekpatronen omdat het bij de EPG vaak de leestekens ontbreken.
Gevorderden kunnen ook standaard uitdrukkingen gebruiken, maar dan moet u de benodigde informatie halen van de VDRAdmin-AM broncode (ongedocumenteerd aspect).

U kunt bepaalde programma's uitsluiten zodat deze niet worden opgenomen ondanks dat deze overeenkomen met een auto timer. Hiervoor moet u vdradmind.bl bewerken en hier de titels in plaatsen, een gebeurtenis per regel. Dit bestand moet staan in de VDRAdmin-AM's configuratie map. Als de zoekterm word gevonden in de EPG titel of in titel~subtitel, dan zal dit programma niet worden opgenomen door de auto timer. Zodoende kunt u complete afleveringen uitsluiten (bijvoorbeeld \"Enterprise\" zwarte lijst zoekterm) of alleen een opname (door gebruikt te maken van \"Enterprise~Azati Prime\" als zwarte lijst zoekterm)." msgid "Here you can define the EPG sections where VDRAdmin-AM should look for the search pattern." msgstr "Hier kunt u aangeven de EPG delen aangeven waar VDRAdmin-AM moet zoeken naar zoekpatronen." msgid "Use these checkboxes to limit searching for matching broadcasts to a set of weekdays." msgstr "Gebruik deze hokjes om het zoeken te beperken op bepaalde dagen." msgid "The channel to look for matching broadcasts or \"all\" to search in all known or wanted channels. You can define the wanted channels for AutoTimer in \"Configuration\"." msgstr "Het kanaal waar naar gezocht moet worden voor overeenkomstige programma's of \"alle\" om te zoeken in alle bekende of gewenste kanalen. U kunt de gewenste kanalen voor de auto timer aangeven in \"Configuratie\"." msgid "A broadcast must start after the time entered here to match. The first text field is for \"hour\", the second for \"minute\"." msgstr "Een programma moet starten na de hier ingegeven tijd om in aanmerking te komen voor opname. Het eerste veld is voor \"Uur\", de tweede voor \"minuut\"." msgid "A broadcast must end before the time entered here to match. The first text field is for \"hour\", the second for \"minute\"." msgstr "Een programma moet stoppen na de hier ingegeven tijd om in aanmerking te komen voor opname. Het eerste veld is voor \"Uur\", de tweede voor \"minuut\"." msgid "Set this option to \"yes\" if all timers programed by this AutoTimer should have individual start/stop margins and enter the values in the next two text boxes." msgstr "Stel deze optie in op \"ja\" als alle timers die ingesteld zijn met deze autotimer individuele start/stop marges moeten hebben en vul de waarden in in de twee volgende vakken." msgid "The number of minutes VDRAdmin-AM subtracts from the broadcast's start time found in the EPG." msgstr "Het aantal minuten dat VDRAdmin-AM in mindering brengt van de uitzend start tijd die gevonden is in de EPG." msgid "The number of minutes VDRAdmin-AM adds to the broadcast's stop time found in the EPG." msgstr "Het aantal minuten dat VDRAdmin-AM in toevoegd aan de stop tijd die gevonden is in de EPG." msgid "An integer in the range 0...99, defining the priority of this timer and of recordings created by this timer. 0 represents the lowest value, 99 the highest. The priority is used to decide which timer shall be started in case there are two or more timers with the exact same start time. The first timer in the list with the highest priority will be used.

This value is also stored with the recording and is later used to decide which recording to remove from disk in order to free space for a new recording. If the disk runs full and a new recording needs more space, an existing recording with the lowest priority (and which has exceeded its guaranteed lifetime) will be removed.

If all available DVB cards are currently occupied, a timer with a higher priority will interrupt the timer with the lowest priority in order to start recording." msgstr "Een getal in het bereik0...99, bepaald de prioriteitvan deze timer en de opnames aangemaakt door deze timer 0 geeft de laagst mogelijke waarde aan, 99 de hoogste. De prioriteit wordt gebruikt als er twee of meer timers gelijktijdig starten, de timer met de hoogste prioriteit heeft voorrang en zal worden opgenomen

Deze waarde wordt ook opgeslagen bij de opname en word later gebruikt om een opname te verwijderen om ruimte vrij te maken voor een nieuwe opname. Als de schijf vol raakt en een nieuwe opname heeft meer ruimte nodig dan zal een bestaande opname met de laagste prioriteit ( en die zijn gegarandeerde levensduur al voorbij is) zal worden verwijderd.

Als alle DVB kaarten bezet zijn met een timer dan zal de timer met de laagste prioriteit onderbroken worden om de opname met een hogere prioriteit op te gaan nemen." msgid "The guaranteed lifetime (in days) of a recording created by this timer. 0 means that this recording may be automatically deleted at any time by a new recording with higher priority. 99 means that this recording will never be automatically deleted. Any number in the range 1...98 means that this recording may not be automatically deleted in favour of a new recording, until the given number of days since the start time of the recording has passed by." msgstr "De gegarandeerde levensduur (in dagen) van een opname gecreëerd door deze timer 0 betekend dat deze opname automatisch verwijderd zal worden door een nieuwe timer met een hogere prioriteit.99 betekend dat deze opname nooit automatisch verwijderd zal worden. Ieder nummer in het bereik van 1...98 betekend dat de opname niet automatisch verwijderd zal worden om plaats te maken voor een nieuwe opname, alleen als de levensduur van de opname voorbij is." msgid "Check this box if you want VDRAdmin-AM to append the broadcast's EPG subtitle to the recording's file name." msgstr "Vink dit vakje aan als u VDRAdmin-AM de titel wilt laten toevoegen die gevonden is in de EPG informatie aan de opname's bestandsnaam." msgid "If you enable this VDRAdmin-AM will track timers it has already programmed automatically. This is useful if want to deactivate or delete timers that have been programmed automatically in the timers listing." msgstr "Als u dit activeerd dan zal VDRAdmin-AM de timers volgen die ze al automatisch heeft geprogrammeerd. Dit handig als u timers wilt activeren of verwijderen die automatisch zijn geprogrammeerd in de timer lijst." msgid "The directory this AutoTimer will place the recordings in. If the name shall contain subdirectories, these have to be delimited by '~' (since the '/' character may be part of a regular programme name).
VDRAdmin-AM will append the matching broadcast's title and subtitle (if the \"Episode\" checkbox is marked) to the directory given here.

You can also use the following keywords that are replaced in the final file name by the values supplied by for example tvm2vdr:
  • %Title% - will become the title of the event.
  • %Subtitle% - will become the subtitle of the event.
  • %Director% - will become the director of the event.
  • %Date% - will become the date of the recording.
  • %Category% - will become the category of the event (Spielfilm/Serie/...).
  • %Genre% - will become the genre of the event (Drama/Krimi/..).
  • %Year% - will become the year of production.
  • %Country% - will become the country of production.
  • %Originaltitle% - will become the original title of the event.
  • %FSK% - will become the FSK from the event.
  • %Episode% - will become the episode's title of the event.
  • %Rating% - will become the rating of the event from the EPG provider.

Note:

If you use the above keywords it's in your own responsibility to supply the complete file name for the recordings! VDRAdmin-AM will not append anything to the resulting string." msgstr "De map waar deze auto timer zijn opnames in zal plaatsen. Als de naam submappen bevat dan zullen deze aangeven moeten worden door een '~' aangezien het '/' karakter een deel kan uitmaken van een programma naam. .
VDRAdmin-AM zal de overeenkomstige programma naam en titel gebruiken (als de \"aflevering\" aanvinkvak is gemarkeerd) naar de hier aangegeven map.

U kunt ook de volgende sleutelwoorden gebruiken die worden vervangen voor de uiteindelijke bestandsnaam door waarden opgegeven door bijvoorbeeld tvm2vdr:
  • %Titel% - zal de naam worden van de gebeurtenis .
  • %Subtitel% zal de subtitel worden van de gebeurtenis .
  • %Datum% - zal de datum worden van de opname .
  • %Categorie% zal de categorie worden van de gebeurtenis (speelfilm, serie,...) .
  • %Genre% - zal het genre worden van de gebeurtenis (Drama/Krimi/..).
  • %Jaar% - zal het jaar worden van de productie .
  • %Origineletitel% zal de originele titel worden van de gebeurtenis
  • %FSK% - zal de FSK worden van de gebeurtenis .
  • %Aflevering% - zal de afleverings titel worden van de gebeurtenis .
  • %Waardering% - zal de waardering worden van de gebeurtenis van de EPG informatie .

Let op:

Als u bovenstaande sleutelwoorden gebruikt dan is het uw eigen verantwoording om een volledige bestandsnaam te geven aan de opnames! VDRAdmin-AM zal niets toevoegen aan de resulterende reeks." msgid "

Here you can change general settings and base settings for timers, AutoTimers, channel selection and streaming parameters.

" msgstr "

Hier kunt u de algemene en basis instellingen veranderen voor de timers, auto timer, kanaal selectie en streaming parameters.

" msgid "The skin you want to use." msgstr "De skin die u wilt gebruiken." msgid "The page you want to see at first connect to VDRAdmin-AM." msgstr "De pagina die u als eerste wilt zien als VDRAdmin-AM start." msgid "VDRAdmin-AM will load the given number of channels from VDR and present only those in any fields where channels can be selected. This also limits the EPG information VDRAdmin-AM will read so that you can use this to reduce VDRAdmin-AM's memory consumption and increase its performance. 0 turns this feature off and VDRAdmin-AM will use all available channels." msgstr "VDRAdmin-AM zal de kanalen laden van de VDR en alleen aanwezig in deze ieder veld waar een kanaal kan worden geselecteerd. Dit beperkt ook de EPG informatie die VDRAdmin-AM zal lezen zodat het geheugen gebruikt van VDRAdmin-AM beperkt zal worden en de prestaties zal verbeteren. 0als deze functie is uitgeschakeld dan zal VDRAdmin-AM alle beschikbare kanalen gebruiken." #, fuzzy msgid "Here you can specify subnets from which access to VDRAdmin-AM does not require logging in. For example: \"192.168.0.0/24\" will include any IP starting with \"192.168.0.\", \"192.168.0.123/32\" will only match \"192.168.0.123\". Multiple subnets can be specified by separating them with spaces or commas." msgstr "Hier kunt u een IP adres opgeven of bereik die kan inloggen zonder login informatie. Bijvoorbeeld:\"192.168.0.0/24\" zal ieder IP adres toestaan dat begint met \"192.168.0.\", \"192.168.0.123/32\" zal alleen \"192.168.0.123\" toestaan." msgid "Here you can set the localization VDRAdmin-AM should use." msgstr "Hier kunt u de taal instellen die VDRAdmin-AM moet gebruiken." msgid "With this option the settings will be saved if VDRAdmin-AM exits. This will also save settings not available on the \"Configuration\" menu like interval and size in TV, sorting in the lists and current view in \"What's on now\"." msgstr "Met deze optie worden de instellingen bewaard als VDRAdmin-AM afgesloten word. Dit bewaard ook de instellingen van het niet beschikbare op het \"Configuratie\" menu zoals interval en formaat in TV, het sorteren van de lijsten en huidig beeld in \"Wat is er nu op\"." msgid "Top" msgstr "Boven" msgid "The number of DVB cards VDR can access. Depending on this value VDRAdmin-AM will calculate critical timers in the Timer menu." msgstr "Het aantal kaarten dat VDR kan benaderen. Afhankelijk van deze waarde zal VDRAdmin-AM de timers berekenen in het Timer menu." msgid "The path to VDR's recordings. It's used so that VDRAdmin-AM can locate the recordings when using Recordings Streaming and reccmds.conf in the Recordings menu." msgstr "Pad naar de VDR opnames. Deze word zo gebruikt dat VDRAdmin-AM de opnames kan lokaliseren wanneer Streaming opnames gebruikt word en reccmds.conf in de opnames menu." msgid "The path where VDR's configuration files are located. If this directory contains the file reccmds.conf its content is shown in a selectbox in the Recordings menu." msgstr "Het pad waar de VDR's configuratie bestanden staan. Als deze map het bestand reccmds.conf bevat dan zal de inhoud getoond worden in een selectie vak in de opnames menu." msgid "The path where the EPG images are stored." msgstr "Het pad waar de EPG beelden zijn opgeslagen." msgid "The username for the main user, i.e. the user having the most privileges." msgstr "De gebruikersnaam voor de hoofdgebruiker, met andere woorden, de gebruiker met de meeste rechten." msgid "The main user's password." msgstr "De hoofdgebruikers wachtwoord." msgid "If you want a user account having only limited privileges, this is for you. The guest user cannot modify anything, it's only allowed to view the EPG, timers, AutoTimers and recordings listings." msgstr "Als u een gebruikers account wilt hebben met alleen beperkte rechten, dat is dit iets voor u. De gast gebruiker kan niets veranderen, deze heeft alleen toestemming om de EPG timers, autotimer en opnames te bekijken. " msgid "The username for the guest user." msgstr "De gebruikersnaam van de gast gebruiker." msgid "The guest user's password." msgstr "Het wachtwoord van de gast gebruiker." msgid "The number of hours to show in the timeline." msgstr "Het aantal uren die getoond worden in de tijdlijn. " msgid "A comma separated list of times in hh:mm format that appear in the selectbox placed at the top." msgstr "Een komma gescheiden lijst van tijden in uu:mm formaat die verschijnt in het selectie vak die zich boven bevind." msgid "Here you can (de-)activate the tooltips." msgstr "Hier kunt u de handigheden (de)activeren." msgid "The time after which events are shown on a new day. For example setting 03:00 means that today's schedule will include any event starting before 03:00 tomorrow. Applies only to the 'Playing Today?' list." msgstr "De tijd waarna evenementen getoond worden op een nieuwe dag. Bijvoorbeeld, instelling 03:00 betekend dat het schema van vandaag bevat ieder evenement dat start voor morgen .03:00. Alleen van toepassing op de lijst 'Speelt vandaag?' " msgid "Show the 'Subtitle' text for each event. Not all broadcasters use this field." msgstr "Toon de 'ondertitel' tekst voor ieder evenement. Niet alle zenders gebruiken dit veld." msgid "Show the 'Summary' text for each event." msgstr "Toon de 'Omschrijving' tekst voor ieder evenement" msgid "Activate or deactivate the AutoTimer function." msgstr "Activeer of deactiveer de autotimer functie." msgid "VDRAdmin-AM will send an email whenever an event matches an AutoTimer and a timer has been programmed if you enable this feature." msgstr "VDRAdmin-AM zal een email sturen als een gebeurtenis overeenkomt met een autotimer en een timer is geprogrammeerd als u dit activeerd in de toekomst." msgid "Here you set the sending email address of the generated email." msgstr "Hier kunt u de afzender instellen van de aangemaakte email." msgid "The email address the email is sent to." msgstr "Het email adres, de email is gestuurd naar:" msgid "The outgoing mail server." msgstr "De uitgaande mail server." msgid "If you need to authenticate yourself at the outgoing mail server, you have to supply the username and the password below. Leaving this field empty will disable SMTPAuth." msgstr "Als u zich moet identificeren voor SMTPAuth de uitgaande mail server dan moet u uw gebruikersnaam en wachtwoord hieronder invoeren. Als dit veld leeg is dan zal SMTPAuth niet aktief zijn." msgid "The password for the SMTPAuth user." msgstr "Het wachtwoord voor de SMTPAuth gebruiker." msgid "Here you can (de-)activate the tooltips in the timeline." msgstr "Hier kunt u de handigheen (de)activeren in de tijdlijn." msgid "Here you can (de-)activate the tooltips in the list." msgstr "Hier kunt u de handigheen (de)activeren in de lijst." msgid "Add summary to new timers:" msgstr "Voeg beschrijving toe aan nieuwe timers:" msgid "If you don't want VDRAdmin-AM to add the summary taken from EPG to new timers you can switch it off here." msgstr "Als u niet wilt dat VDRAdmin-AM de programma informatie uit de EPG overneemt aan nieuwe timer dan kunt u dat hier uitzetten." msgid "Enable or disable live streaming using the streamdev plugin. You also have to set the correct HTTP Port for Streamdev below." msgstr "Activeer of deactiveer live streaming door gebruik te maken van de streamdev plugin. U moet ook de juiste HTTP Poort voor Streamdevinstellen hieronder." msgid "Here you have to set the port number your VDR's streamdev server listens for connections. Additionally you can also provide the stream type you like to use." msgstr "Hier moet u het poort nummer instellen waar uw VDR's streamdev server naar luistert voor verbindingen. Tevens is het mogelijk de stream type in te stellen die u wilt gebruiken." msgid "Enable or disable streaming of recordings.
Well actually this is no real \"streaming\", but you have to setup your workstation so that it can access VDR's recordings. You can use for example Samba or NFS for this. VDRAdmin-AM simply generates a playlist that contains all parts of the recording and sends this to your browser. If your browser and media player are configured correctly you will see the recording on your workstation's display." msgstr "Het aan of uitzetten van streaming van opnames
Het is eigenlijk wel geen echte \"streaming\", maar u moet u werkstation instellen zodat deze de VDR opnames kan benaderen. U kunt bijvoorbeeld Samba of NFS hiervoor gebruiken. VDRAdmin-AM maakt gewoon een afspeellijst aan die alle delen van de opname bevat en stuurt dit naar uw browser. Als uw browser en media speler juist zijn ingesteld dan kunt u de opname op uw werkstations beeldscherm bekijken." msgid "This is the path where your workstation can access VDR's recordings. This depends on your VDR and workstation setup, for example \"\\\\vdr\\videos\" or \"V:\\\" (on Windows) or \"/mnt/videos\" (on Linux)." msgstr "Dit is het pad waar uw werkstation de VDR opnames kan benaderen. Dit hangt af de instellingen van de VDR en werkstation. bijvoorbeeld \"\\\\vdr\\videos\" of \"V:\\\" (op Windows) of \"/mnt/videos\" (op Linux)." msgid "The MIME type to send when using live streaming. Defaults to \"video/x-mpegurl\"." msgstr "Het MIME type te gebruiken voor live streaming. standaard is \"video/x-mpegurl\"." msgid "The suffix to use for live streaming. Defaults to \"m3u\"." msgstr "De extensie voor live streaming. Standaard is \"m3u\"." msgid "The MIME type to send when using recordings streaming. Defaults to \"video/x-mpegurl\"." msgstr "Het MIME type te gebruiken voor opgenomen streaming. standaard is \"video/x-mpegurl\"." msgid "The suffix to use for recordings streaming. Defaults to \"m3u\"." msgstr "De extensie voor opgenomen streaming. Standaard is \"m3u\"." msgid "

Here you can define two external searches that you can access in the EPG views. You simply have to find the required URL and where the search pattern has to be located. %TITLE% will be substituted by the broadcast's EPG title.

" msgstr "

Hier kunt u twee externe zoekopdrachten definiëren die u kunt benaderen in de EPG. U moet alleen de benodigde URL zien te vinden en waar het zoekpatroon geplaatst moet worden . %TITLE% zal worden vervangen door uitzendings EPG titel.This section is for experts only, i.e. you know what you are doing!

" msgstr "

Deze afdeling is voor deskundigenalleen, met andere woorden, als goed weet waar u mee bezig bent!

" msgid "If set to \"yes\" VDRAdmin-AM will periodically refresh its local EPG cache. Else the EPG will be refreshed if the user accesses any EPG view at the web interface and the timeout set at \"Update EPG every\" has been reached." msgstr "Als het ingesteld staat op \"ja\" dan zal VDRAdmin-AM met intervallen zijn lokale EPG cache verversen. Anders word de EPG pas ververst als de gebruiker met een EPG bezoek op de web interface benadert en de timeout instelling \"Ververs EPG iedere\" bereikt is" msgid "The interval, the EPG data is refreshed from VDR and AutoTimer updates are performed (if AutoTimer feature is used)." msgstr "De interval dat EPG data wordt ververst van VDR en auto timer updates worden uitgevoerd. (Als de auto timer functie word gebruikt)." msgid "

If you want to limit the number of channels used in some parts of VDRAdmin-AM, this is for you!

Use the radio buttons to activate or deactivate the wanted channels in the named menu.

To add channels to the list of wanted channels you have to select them in the left side selectbox and click . If you want to remove channels from the list of wanted channels you have to select them in the right side selectbox and click .

" msgstr "

Als u het aantal kanalen wilt beperken die in sommige delen van VDRAdmin-AM gebruikt worden, dan is dit iets voor u!

Gebruik de selectie vakken om de gewenste kanalen de activeren of deactiveren in het genoemde menu.

Om kanalen toe te voegen in de lijst van gewenste kanalen dan moet u de gewenste kanalen selecteren in de linkerlijst van het selectie vak en klikken op . Als u kanalen van deze lijst wilt verwijderen selecteer dan uit deze lijst de te verwijderen kanalen en klik op.

" msgid "Usually channels that don't have EPG information are hidden in all EPG views. If you don't want them to be hidden you have to set this option to \"yes\"." msgstr "Normaal gesproken worden kanalen verborgen die geen EPG informatie hebben. Als u deze niet verborgen wilt hebben moet u deze optie op \"ja\" zetten." msgid "Edit Timer" msgstr "Timer bewerken" msgid "Edit EPG" msgstr "Bewerk EPG" msgid "

Here you can edit the descriptive fields of an existing EPG entry.

" msgstr "

Hier kunt u de omschrijving van een bestaande EPG bewerken.

" msgid "Channel (readonly)" msgstr "Kanaal (alleen lezen)" msgid "This is the channel of the EPG entry. It cannot be changed." msgstr "Dit is het kanaal van de EPG invoer. Dit kan niet veranderd worden." msgid "Time (readonly)" msgstr "Tijd (alleen lezen)" msgid "This is the start and end time of the entry. It cannot be changed." msgstr "Dit is de start en eindtijd van de invoer. Dit kan niet veranderd worden." msgid "Change this string to give this EPG Entry a new title. It must consist of only one line of text." msgstr "Verander deze reeks om deze EPG invoer een nieuwe titel te geven.Het mag alleen bestaan uit één regel tekst." msgid "Change this string to give this EPG Entry a new subtitle. It must consist of only one line of text." msgstr "Verander deze reeks om deze EPG invoer een nieuwe subtitel te geven.Het mag alleen bestaan uit één regel tekst." msgid "Change the text in this field to edit the description of this entry. The text can consist of one or more lines." msgstr "Verander de tekst in dit veld om de omschrijving te veranderen van deze invoer. De tekst mag bestaan uit één of meer regels,." msgid "VPS (readonly)" msgstr "VPS (alleen lezen)" msgid "If available this field shows the vps time of the EPG entry. It cannot be changed." msgstr "Als het beschikbaar is toont dit vel de vps tijd van de EPG invoer. Dit kan niet veranderd worden." msgid "Video tracks (readonly)" msgstr "Video tracks (alleen lezen)" msgid "If available this field shows the video track(s). It cannot be changed." msgstr "Indien beschikbaar toont dit veld de video spoor of sporen. Dit kan niet verandert worden." msgid "Audio tracks (readonly)" msgstr "Audio sporen (alleen lezen)" msgid "If available this field shows the audio track(s). It cannot be changed." msgstr "Indien beschikbaar toont dit veld de audio sporen. Dit kan niet veranderd worden." msgid "No Help Available" msgstr "Geen help beschikbaar" msgid "

No help available yet. For adding or changing text please contact amair.sob@googlemail.com.

" msgstr "

Nog geen hulp beschikbaar: Voor toevoegen of veranderen van tekst graag contact opnemen metamair.sob@googlemail.com.

" msgid "Recordings" msgstr "Opnames" msgid "

Here you will find a listing of recordings known to VDR. The headline will also show you VDR's total and free disk space.

The listing showing you some information on the recordings. You can change the list's sorting by clicking the columns heading. Above the list you'll see the navigation path. If you want to view the contents of previous folders you'll have to click on its name in that path.

Each row contains this information:

Date
The date when the recording has been done. In case of folders this will show the number of recordings the folder contains.
Time
The time when the recording has been done. In case of folders this will show the number of new recordings the folder contains.
Name
The recording's or folder's name. Click it to show the recording's summary or descend into the folder.
Rename (\"edit\")
Rename a recording.

Note:

This only works if VDR has the MOVR or RENR SVDRP command which is not a core VDR feature but provided by the Liemikuutio patch set.
Delete (\"delete\")
Delete a recording.
Stream (\"stream\")
This column is only shown if you activated and configured Recordings Streaming in the Configuration menu. You can watch the recording at your workstation.

In addition to these functions you can delete a number of recordings at once by checking the box in the last but one column of those recordings and clicking .

If you've set the path the VDR's configuration files and have entries in VDR's reccmds.conf you can run those commands for the selected recording by selecting the wanted command in the select box locate next to Commands: and pressing the button.

Use to force reloading of VDR's recordings listing.

" msgstr "

Hier zult u een lijst vinden van opnames die bekend zijn bij VDR: De hoofdlijn zal ook de totale en vrije ruimte tonen die VDR beschikbaar heeft .

De lijst zal u enige informatie tonen over de opnames. U kunt de lijst sorteren door op de kolom hoofden te klikken. Boven de lijst zult u het navigatie pad aantreffen. Als u de inhoud van vorige mappen wil bekijken dan zult u op de naam moeten klikken in het pad.

Elke rij bevat de volgende informatie:

Datum
De datum van opname. In het geval van mappen worden het aantal opnames die in de map staan worden getoond.
Tijd
Het tijdstip van opname. Als het een map is dan zal het aantal nieuweopnames getoond worden in de map.
Naam
De naam van opname of map naam. Klik erop om de beschrijving van de opname te tonen of de inhoud van de map te bekijken.
Hernoemen (\"edit\")
Hernoem een opname .

Let op:

Dit werkt alleen als VDR de RENR SVDRPoort commando bevat wat geen kern mogelijkheid is van VDR maar beschikbaar is via een patch . vdr-aio21_svdrprename.patch of enAIO-v2.2+ voorzien in dit commando.
Verwijder (\"verwijder\")
Verwijder een opname
Stream (\"stream\")
Deze kolom word alleen getoond als deze is geactiveerd en geconfigureerd Opnames Streaming in de Configuratie menu. U kunt de opname bekijken op uw werkstation.

Aanvullend bij deze functies kunt u een aantal opnames verwijderen door te klikken in het aanvink vak van de opnames en te klikken op .

Als u het pad van de VDR configuratie bestanden heeft ingesteld en ingangen heeft staan in reccmds.conf kunt u deze commando's uitvoeren voor de geselecteerde opnames door het gewenste commando aan te klikken in het aanvinkvak naast Commando's: en te klikken op knop.

" msgid "

Here you will find a listing of timers known to VDR.

On top you will find a chart showing a day's timers graphically. This provides an quick overview on what's going on at the specified day and helps you in finding conflicting timers. Moving the mouse cursor above any timer box will display a tooltip containing the timer's title, priority, lifetime and duration.

Below the chart you'll find the timers list showing you some information on the timers. You can change the list's sorting by clicking the columns heading.

For each timer you have the following options:

Set its state
By clicking on \"Yes\", \"No\", \"VPS\" or \"Auto\" in the \"Active\" column.
Quickly view its priority and lifetime
By pointing the mouse cursor to the timer's title.
View its EPG entry
Timers that have set AutoTimer Checking to \"Transmission Identification\" will show you the corresponding EPG entry if you click on the timer's title.
Edit the timer
You can edit a timer by clicking \"edit\".
Delete the timer
To delete a timer you click \"delete\".

Each timer's state is indicated by differently coloured boxes (in the chart view) or images (in the list view):
    / \"on\" Timer is OK and will record.
    / \"problem\" Timer conflicts with other timers. That's not critical, as long as you have enough DVB cards for the parallel recordings.
    / \"impossible\" Timer is critical and will most likely not record.
    / \"inactive\" Timer is not active.

In addition to these functions you can add a new timer by clicking at the top and you can delete a number of timers at once by checking the box in the last column of those timers and clicking .

You can and selected timers.

" msgstr "

Hier vind u een lijst van timer die bekend zijn bij VDR.

Boven in zult u een lijst vinden die de timers van een dag grafisch weergeven. Dit voorziet in een snel overzicht van wat er gaande is op een bepaalde dag en helpt in het vinden van overlappende timers. Door de muis cursor boven iedere timerbox te plaatsen zal er een tooltip weergegeven worden die de timers titel, prioriteit, levensduur en lengte van opname zal tonen

Onder de lijst kunt u de timer lijst vinden die u enige informatie toont van de timers. U kunt lijst opsomming veranderen door op het kopje van de kolom te klikken.

Voor iedere timer heeft u de volgende opties:

De activiteit instellen
door te klikken op \"Ja\", \"Nee\", \"VPS\" of \"Auto\" in de \"Aktief\" kolom.
Om snel de prioriteit en levensduur te tonen
Door de muis cursor over de timers titel te bewegen
kunt u de EPG informatie tonen .
Timers die zijn ingesteld op AutoTimer Controle tot \"Transmissie Identificatie\" zal de overeenkomstige EPG informatie tonen als u klikt op de timer titel.
Bewerken van een timer
U kunt een timer bewerken door te klikken op\"edit\".
Verwijder de timer
Om een timer te verwijderen klik op \"delete\".

Iedere timers activiteit wordt getoond door verschillend gekleurde vakjes (in de overzichtslijst) of beelden (in de lijst overzicht):
    / \"on\" Timer is OK en zal worden opgenomen.
    / \"problem\" Timers die elkaar overlappen. dit is geen probleem zolang er voldoende DVB kaarten aanwezig zijn om gelijktijdig te kunne opnemen.
    / \"impossible\" De timer overlapt en zal hoogstwaarschijnlijk niet worden opgenomen.
    / \"inactive\" Timer is niet aktief.

Naast deze functies kunt u een nieuwe timer toevoegen door op boven in te klikken en u kunt een aantal timers verwijderen door eenmaal op het selectie vakje in de laatste kolom te klikken en dan op .

te klikken." msgid "

Here you can edit a timer's settings.

" msgstr "

Hier kunt u de timer instellingen bewerken.

" msgid "Timer Active:" msgstr "Actieve timers:" msgid "Activate or deactivate this timer. Deactivated timers are still stored in the timer list so that they can be activated again, but they do not record anything meanwhile." msgstr "Activeer of deactiveer deze timer. Gedeactiveerde timers worden wel bewaard in de timer lijst zodat deze wel weer geactiveerd kunnen worden, maar ondertussen nemen ze niets op." msgid "AutoTimer Checking:" msgstr "Auto timer controle" msgid "Depending on how this timer has been programmed you have up to three possible settings:" msgstr "Afhankelijk van hoe deze timer is geprogrammeerd heeft u tot en met drie mogelijkheden:" msgid "Transmission Identification" msgstr "Verzend identificatie" msgid "Monitor this timer using the identification provided in the EPG. Please note that this only works if the provided identification is a fix and unique value! This option is not available with timers programmed in VDR." msgstr "Gebruik deze timer door de EPG informatie in de gaten te houden. Let op! dit werkt alleen als de informatie een vaste en unieke waarde heeft. Deze optie is niet beschikbaar met timers geprogrammeerd in VDR." msgid "Time" msgstr "Tijd" msgid "Monitor this timer using the start and stop time." msgstr "Gebruik deze timer door gebruikt te maken van de start en stop tijd." msgid "off" msgstr "Uit " msgid "Do not monitor this timer." msgstr "Houd deze timer niet in de gaten." msgid "The channel to record." msgstr "Het op te nemen kanaal." msgid "Day Of Recording:" msgstr "Dag van opname" msgid "The day when the timer should get active. You can enter the day in two formats:
  • Two digits (DD). This will use the current month and year.
  • ISO norm (YYYY-MM-DD). Program your timers as far in the future as you like.
In case you want to program a repeating timer you can use the seven checkboxes below the text field. Check the box for each day you want the timer to get active." msgstr "De dag dat de timer aktief word. U kunt de dag op twee manieren invoeren.
  • Met twee cijfers (DD). Deze zal gebruik maken van de huidige maand en jaar .
  • ISO norm (YYYY-MM-DD). Programmeer de timer zo ver in de toekomst als u wilt.
In het geval u een herhalende timer wilt programmeren kunt u gebruik maken van de zeven aanvink vakjes onder het tekstveld. Vink het vakje aan voor iedere dag dat u de timer aktief wilt hebben." msgid "Start Time:" msgstr "Start tijd:" msgid "This is the time when the timer should start recording. The first text field is for \"hour\", the second for \"minute\"." msgstr "Dit is de tijd dat de timer moet beginnen met opnemen. Het eerste veld is voor \"uur\", de tweede voor de \"minuten\"." msgid "End Time:" msgstr "Eind tijd" msgid "This is the time when the timer should stop recording. The first text field is for \"hour\", the second for \"minute\"." msgstr "Dit is de tijd dat de timer moet stoppen met opnemen. Het eerste veld is voor \"uur\", de tweede voor de \"minuten\"." msgid "Title of Recording:" msgstr "Titel van opname:" msgid "The file name this timer will give to a recording. If the name shall contain subdirectories, these have to be delimited by '~' (since the '/' character may be part of a regular programme name).

The special keywords TITLE and EPISODE, if present, will be replaced by the title and episode information from the EPG data at the time of recording (if that data is available). If at the time of recording either of these cannot be determined, TITLE will default to the channel name, and EPISODE will default to a blank." msgstr "De bestandsnaam die de timer aan de opname zal geven. Als de naam sub mappen zal bevatten dan zullen deze gescheiden worden door '~'(aangezien het '/' karakter een leesteken kan zijn in een programma naam).

Als de speciale sleutelwoordenTITEL en AFLEVERING aanwezig zijn zullen deze vervangen worden door de titel en aflevering informatie uit de EPG informatie op het tijdstip van opname (als de gegevens beschikbaar zijn). Als deze informatie niet beschikbaar is dan zal TITEL vervangen worden door de naam van het kanaal en AFLEVERING zal leeg blijven." msgid "Summary:" msgstr "Omschrijving:" msgid "Arbitrary text that describes the recording made by this timer. If this field is not empty, its contents will be written into the summary.vdr or info.vdr file of the recording." msgstr "Aanvullende informatie die een beschrijving geeft van de opname gemaakt door deze timer. Als dit veld niet leeg is dan zal de inhoud geschreven worden naar summary.vdr of info.vdr bestand behorende bij deze opname." msgid "Your Browser does not support frames!" msgstr "UW browser ondersteund geen frames!" msgid "What's On Now?" msgstr "Wat is er nu op?" msgid "Playing Today?" msgstr "Speelt vandaag?" msgid "Remote Control" msgstr "Afstands bediening " msgid "Watch TV" msgstr "TV bekijken" msgid "Commands" msgstr "Commando's" msgid "Search" msgstr "Zoeken" msgid "Authorization Required" msgstr "Toestemming benodigd" msgid "This server could not verify that you are authorized to access the document requested. Either you supplied the wrong credentials (e.g. bad password), or your browser doesn't understand how to supply the credentials required." msgstr "De server kon niet controleren of u toestemming heeft om dit document te lezen. Waarschijnlijk heeft u een foutief wachtwoord gegeven of uw browser kan niet met wachtwoorden overweg." msgid "VPS" msgstr "VPS" msgid "close" msgstr "sluiten" msgid "view" msgstr "bekijken" msgid "search" msgstr "zoeken" msgid "edit" msgstr "Bewerken" msgid "Length" msgstr "" msgid "Video tracks:" msgstr "Video tracks:" msgid "Audio tracks:" msgstr "Audio sporen:" msgid "Subtitles:" msgstr "Ondertiteling:" msgid "Video tracks" msgstr "Video sporen:" msgid "Audio tracks" msgstr "Audio sporen" msgid "TV select" msgstr "Selecteer programma" msgid "Stream" msgstr "Stream" msgid "Channel group:" msgstr "Kanaal groep:" msgid "Go!" msgstr "Ga!" msgid "Search for other show times" msgstr "Zoek naar andere programma tijden" msgid "No Information" msgstr "Geen informatie" msgid "No EPG information available" msgstr "Geen informatie EPG informatie beschikbaar" msgid "Playing Today" msgstr "Programma vandaag " msgid "starting at" msgstr "start om" msgid "What's on:" msgstr "Wat is er op:" msgid "at" msgstr "om" msgid "now" msgstr "nu" msgid "to" msgstr "naar " msgid "Duration:" msgstr "Duur:" msgid "min" msgstr "min" msgid "at:" msgstr "om:" msgid "You need JavaScript to use the timeline!" msgstr "U heeft Javascript nodig om de tijdlijn te gebruiken! " msgid "Rename Recording" msgstr "Hernoemen opname" msgid "Original Name of Recording:" msgstr "Originele naam van de opname: " msgid "New Name of Recording:" msgstr "Nieuwe naam van de opname:" msgid "Subtitle:" msgstr "Ondertitel:" msgid "Rename" msgstr "Hernoemen" msgid "Total:" msgstr "Totaal:" msgid "h" msgstr "u" msgid "Free:" msgstr "Vrij:" msgid "Date" msgstr "Datum" msgid "Total" msgstr "Totaal" msgid "New" msgstr "Nieuw" msgid "Play" msgstr "Afspelen" msgid "Cut" msgstr "Knippen" msgid "Delete recording?" msgstr "Opname verwijderen?" msgid "Refresh" msgstr "Verversen" msgid "Commands:" msgstr "Commando's:" msgid "Really run this command?" msgstr "Dit commando echt uitvoeren?" msgid "stream all recordings" msgstr "" msgid "Delete Selected Recordings" msgstr "Geselecteerde opnames verwijderen" msgid "Delete all selected recordings?" msgstr "Alle geselecteerde opnames verwijderen?" msgid "No recordings available" msgstr "Geen opnames beschikbaar" msgid "Transponder:" msgstr "Transponder:" msgid "CA-System:" msgstr "CA-Systeem:" msgid "New Timer" msgstr "Nieuwe timer" msgid "Edit timer status?" msgstr "Timer status bewerken?" msgid "This timer is inactive!" msgstr "Deze timer is niet aktief!" msgid "This timer is impossible!" msgstr "Deze timer is niet mogelijk!" msgid "No more timers on other transponders possible!" msgstr "Geen andere timers op andere transponders mogelijk!" msgid "Timer OK." msgstr "Timer OK." msgid "Auto" msgstr "Auto" msgid "activate" msgstr "Activeren" msgid "inactivate" msgstr "niet aktief" msgid "selected timers" msgstr "Geselecteerde timers" msgid "Delete Selected Timers" msgstr "Verwijder geselecteerde timers" msgid "No timers defined!" msgstr "Geen timers opgegeven!" msgid "Create New Timer" msgstr "Nieuwe timer instellen" msgid "Buffer:" msgstr "Buffer:" msgid "Use VPS:" msgstr "Gebruik VPS" msgid "readonly" msgstr "Alleen lezen" msgid "Timer has been set by AutoTimer pattern:" msgstr "De timer is ingesteld door de auto timer zoek opdracht:" msgid "TV" msgstr "TV" msgid "Interval:" msgstr "Interval:" msgid "sec." msgstr "sec." msgid "G" msgstr "G" msgid "Grab the picture!" msgstr "Snapshot maken!" msgid "Size:" msgstr "Grootte:" msgid "Open in separate window" msgstr "In apart venster openen" msgid "VDR Commands" msgstr "VDR Commando's:" msgid "Export channels as playlist:" msgstr "Exporteer de kanalen als afspeellijst" msgid "Number of lines to show:" msgstr "Aantal te tonen regels:" msgid "unlimited" msgstr "Onbeperkt" msgid "SVDRP commands:" msgstr "SVDRP commando's:" msgid "Commands defined in commands.conf:" msgstr "Commando's gedefinieerd in commands.conf:" msgid "Output" msgstr "Uitvoer" msgid "What's your VDR hostname (e.g video.intra.net)?" msgstr "Wat de de hostnaam van de VDR (b.v. video.intra.net)?" msgid "On which port does VDR listen to SVDRP queries?" msgstr "Op welke poort luister VDR naar SVDRP verzoeken?" msgid "On which address should VDRAdmin-AM listen (0.0.0.0 for any)?" msgstr "Naar welk adres moet VDRAdmin-AM luisteren (0.0.0.0 voor alles)?" msgid "On which port should VDRAdmin-AM listen?" msgstr "Naar welke poort moet VDRAdmin-AM luisteren?" msgid "Username?" msgstr "Gebruikersnaam?" msgid "Password?" msgstr "Wachtwoord?" msgid "Where are your recordings stored?" msgstr "Waar worden uw opnames opgeslagen?" msgid "Where are your VDR's configuration files located?" msgstr "Waar bevinden zicht de VDR's configuratie bestanden?" msgid "Config file written successfully." msgstr "Configuratie bestanden succesvol weggeschreven." #, perl-format msgid "%s %s started with pid %d." msgstr "%s %s gestart met pid %d." msgid "Not found" msgstr "Niet gevonden" msgid "The requested URL was not found on this server!" msgstr "De gevraagde URl is niet gevonden op deze server!" msgid "Forbidden" msgstr "Niet toegestaan" msgid "You don't have permission to access this function!" msgstr "U heeft geen toestemming om deze functie te gebruiken!" msgid "All channels" msgstr "alle kanalen" msgid "Selected channels" msgstr "Geselecteerde kanalen" msgid "TV channels" msgstr "TV kanalen" msgid "Radio channels" msgstr "Radio kanalen" #, perl-format msgid "Access to file \"%s\" denied!" msgstr "Toegang tot bestand \"%s\" geweigerd!" #, perl-format msgid "The URL \"%s\" was not found on this server!" msgstr "De URl \"%s\" is niet gevonden op deze server!" msgid "Your favorites" msgstr "Uw favorieten" msgid "Search results" msgstr "Zoek resultaten" msgid "Default" msgstr "Standaard" msgid "--- no timer ---" msgstr "--- geen timer ---" msgid "unknown" msgstr "onbekend" msgid "none" msgstr "geen" #, perl-format msgid "Can't open file \"%s\"!" msgstr "Kan bestand \"%s\" niet openen!" #, perl-format msgid "Can't connect to VDR at %s:%s: %s

Please check if VDR is running and if VDR's svdrphosts.conf is configured correctly." msgstr "Kan geen verbinding maken met VDR at %s:%s: %s

Controleer of VDR draait en of VDR's svdrphosts.conf op de juiste manier is geconfigureerd." #, perl-format msgid "Error while sending command to VDR at %s" msgstr "Fout tijdens verzenden van commando op %s" msgid "Internal error:" msgstr "Interne fout:" msgid "Lookup movie in the Internet-Movie-Database (IMDb)" msgstr "Zoek de film op bij de Internet-Movie-Database (IMDb)" msgid "Can't find EPG entry!" msgstr "Kan geen EPG gegevens vinden!" msgid "Playing Tomorrow" msgstr "Speelt morgen" #, perl-format msgid "Playing on the %s" msgstr "Speelt op de %s" msgid "next" msgstr "volgende" msgid "What's on after" msgstr "Wat is er op na" msgid "What's on at" msgstr "Wat is er op om:" msgid "Suitable matches for:" msgstr "Bruikbare overeenkomsten voor:" msgid "short view" msgstr "beknopt tonen" msgid "long view" msgstr "uitgebreid tonen" msgid "Schedule" msgstr "Schema" #, perl-format msgid "Can't write configuration file %s! Reason: %s" msgstr "Kan niet schrijven naar configuratie bestand %s! Reden: %s" #, perl-format msgid "Configuration file %s not writable! Configuration won't be saved!" msgstr "Configuratie bestand %s is niet schrijfbaar! Configuratie bestand word niet opgeslagen!" msgid "Timers" msgstr "Timers" msgid "System default" msgstr "Systeem standaard" vdradmin-am-3.6.13/po/ru.po000066400000000000000000002465111443716113400154240ustar00rootroot00000000000000# Copyright (C) Andreas Mair # This file is distributed under the same license as the VDRAdmin-AM package. # # Oleg Roitburd , 2007 # msgid "" msgstr "" "Project-Id-Version: ru\n" "Report-Msgid-Bugs-To: Andreas Mair \n" "POT-Creation-Date: 2012-07-09 12:23+0200\n" "PO-Revision-Date: 2011-11-18 23:41+0200\n" "Last-Translator: Ville Skyttä \n" "Language-Team: Russian \n" "Language: ru\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Country: RUSSIAN FEDERATION\n" msgid "About" msgstr "O" msgid "License" msgstr "" msgid "Authors" msgstr "Ðвторы" msgid "Current author (VDRAdmin-AM branch):" msgstr "Ðынешний автор (VDRAdmin-AM branch):" msgid "Original author (VDRAdmin):" msgstr "Первоначальный автор (VDRAdmin):" msgid "Translation Team" msgstr "Группа переводчиков" msgid "English:" msgstr "ÐнглийÑкий:" msgid "German:" msgstr "Ðемецкий:" msgid "French:" msgstr "ФранцузÑкий:" msgid "At the moment unmaintained, former translations by:" msgstr "Ð’ наÑтоÑщее Ð²Ñ€ÐµÐ¼Ñ Ð½Ðµ обновлÑетÑÑ, прежние переводы от:" msgid "Spanish:" msgstr "ИÑпанÑкий:" msgid "Finnish:" msgstr "ФинÑкий:" msgid "Dutch:" msgstr "ГолландÑкий:" msgid "Russian:" msgstr "РуÑÑкий" msgid "Czech:" msgstr "ЧешÑкий:" msgid "Italian:" msgstr "" msgid "Hungarian:" msgstr "" #, fuzzy msgid "Information" msgstr "ИнформациÑ" msgid "VDRAdmin-AM version:" msgstr "ВерÑÐ¸Ñ VDRAdmin-AM:" msgid "VDR version:" msgstr "ВерÑÐ¸Ñ VDR:" msgid "Supported features in VDR:" msgstr "Поддерживаемые ÑƒÐ»ÑƒÑ‡ÑˆÐµÐ½Ð¸Ñ Ð² VDR:" msgid "EPGSearch" msgstr "EPG ПоиÑк" msgid "EPGSearch Plugin" msgstr "" msgid "LiveTV Streaming" msgstr "" msgid "Streamdev Plugin" msgstr "" msgid "Xineliboutput Plugin" msgstr "" msgid "Rename Recordings (Liemikuutio Patch)" msgstr "Переименование запиÑей (Liemikuutio Patch)" msgid "Getting Help and Reporting Bugs" msgstr "Получить помощь и Ñообщить об ошибке" msgid "If you need help please first try to use the online help you'll find on some pages. You can access it by clicking \"\"." msgstr "ЕÑли Вам нужна помощь по данной программе, то обратитеÑÑŒ вначале к интерактивной помощи, ÐºÐ¾Ñ‚Ð¾Ñ€Ð°Ñ Ð´Ð¾Ñтупна на некоторых Ñтраницах. Ð’Ñ‹ можете вызывать ее Ð½Ð°Ð¶Ð¸Ð¼Ð°Ñ Ð½Ð° \"\"." msgid "If this doesn't provide the information you need you can try to get help at VDR-Portal if you understand German language. Please use the announcement thread if possible, search for:" msgstr "ЕÑли вÑÑ‚Ñ€Ð¾ÐµÐ½Ð½Ð°Ñ Ñправка не дала Вам необходимую информацию, тогда Ð’Ñ‹ можете попытатьÑÑ Ð¿Ð¾Ð»ÑƒÑ‡Ð¸Ñ‚ÑŒ помощь в Allrussian VDR форуме. Ищите Ð´Ð»Ñ Ñтого:" msgid "If you think you have found a bug please check that it's a new one and report it in the VDRAdmin-AM BugTracking system." msgstr "ЕÑли Ð’Ñ‹ думаете, что нашли ошибку, тогда первым делом проверьте в VDRAdmin-AM BugTracking ÑиÑтеме. ЕÑли ее там нет, тогда отправьте рапорт о ней." msgid "AutoTimer" msgstr "Ðвтотаймеры" msgid "Priority:" msgstr "Приоритет:" msgid "Lifetime:" msgstr "Как долго хранить:" msgid "New AutoTimer" msgstr "Ðовый Ðвтотаймер" msgid "Help" msgstr "Помощь" msgid "Active" msgstr "Ðктивировано" msgid "Channel" msgstr "Канал" msgid "Start" msgstr "Ðачало" msgid "Stop" msgstr "Конец" msgid "Name" msgstr "ИмÑ" msgid "Select all/none" msgstr "Выбрать вÑе или ничего" msgid "Yes" msgstr "Да" msgid "No" msgstr "Ðет" msgid "Edit" msgstr "Редактировать" msgid "Delete timer?" msgstr "Удалить таймер?" msgid "Delete" msgstr "Удалить" msgid "Force Update" msgstr "ПроизвеÑти обновление" msgid "Delete Selected AutoTimers" msgstr "Удалить выбранный Ðвтотаймер" msgid "Delete all selected timers?" msgstr "Удалить вÑе выбранные Ðвтотаймеры?" msgid "No AutoTimers defined!" msgstr "AutoTimer не уÑтановлен" msgid "Add New AutoTimer" msgstr "Создать новый Ðвтотаймер" msgid "Edit AutoTimer" msgstr "Редактирование Ðвтотаймера" msgid "AutoTimer Active:" msgstr "Ðвтотаймер активен:" msgid "oneshot" msgstr "однократно" msgid "Search Patterns:" msgstr "ПоиÑковые признаки:" msgid "Search in:" msgstr "иÑкать в:" msgid "Title" msgstr "Заголовок" msgid "Subtitle" msgstr "Подзаголовок" msgid "Description" msgstr "ОпиÑание" msgid "Search only on these days:" msgstr "ИÑкать только в Ñти дни:" msgid "Monday" msgstr "Понедельник" msgid "Tuesday" msgstr "Вторник" msgid "Wednesday" msgstr "Среда" msgid "Thursday" msgstr "Четверг" msgid "Friday" msgstr "ПÑтница" msgid "Saturday" msgstr "Суббота" msgid "Sunday" msgstr "ВоÑкреÑение" msgid "Channel:" msgstr "Канал:" msgid "all" msgstr "вÑе" msgid "Starts After:" msgstr "ÐачинаетÑÑ Ð½Ðµ раньше:" msgid "o'clock" msgstr "ЧаÑов" msgid "Ends Before:" msgstr "ЗаканчиваетÑÑ Ð½Ðµ позднее:" msgid "Override Start/Stop Margins:" msgstr "ПерепиÑывать Ñтарт/Ñтоп " msgid "Time Margin at Start:" msgstr "Опережение начала таймера (мин.):" msgid "minutes" msgstr "Минуты" msgid "Time Margin at Stop:" msgstr "Запаздывание оÑтановки таймера (мин.):" msgid "Episode:" msgstr "СериÑ:" msgid "Remember programmed timers:" msgstr "Запомнить запрограммированные таймеры:" msgid "Directory:" msgstr "Каталог:" msgid "Save" msgstr "Сохранить" msgid "Test" msgstr "ТеÑÑ‚" msgid "Cancel" msgstr "Отменить" msgid "Broadcasted" msgstr "ВещÑлоÑÑŒ" msgid "Stored in" msgstr "Сохраненно в" msgid "No matches found!" msgstr "Ðет результатов!" msgid "Configuration" msgstr "ÐаÑтройки" msgid "General Settings" msgstr "Общие наÑтройки" msgid "Template:" msgstr "Шаблон:" msgid "Skin:" msgstr "Стиль:" msgid "Login Page:" msgstr "ÐÐ°Ñ‡Ð°Ð»ÑŒÐ½Ð°Ñ Ñтраница:" msgid "Number of channels to use:" msgstr "КоличеÑтво иÑпользуемых каналов:" msgid "Local net (no login required):" msgstr "Ð›Ð¾ÐºÐ°Ð»ÑŒÐ½Ð°Ñ Ñеть (вход без авторизации):" msgid "Language:" msgstr "Язык:" msgid "Save settings on exit:" msgstr "СохранÑть уÑтановки при выходе>" msgid "VDR" msgstr "VDR" msgid "Number of DVB cards:" msgstr "КоличеÑтво DVB-карт:" msgid "Path to recordings:" msgstr "Путь к запиÑÑм:" msgid "Path to configuration files:" msgstr "Путь к наÑтройкам:" msgid "Path to EPG images:" msgstr "Путь к EPG-картинкам:" msgid "Identification" msgstr "ИдентификациÑ" msgid "Username:" msgstr "ИмÑ:" msgid "Password:" msgstr "Пароль:" msgid "Guest Account:" msgstr "ГоÑтевой вход:" msgid "Guest Username:" msgstr "Ð˜Ð¼Ñ Ð´Ð»Ñ Ð³Ð¾ÑÑ‚Ñ:" msgid "Guest Password:" msgstr "Пароль Ð´Ð»Ñ Ð³Ð¾ÑÑ‚Ñ:" msgid "Timeline" msgstr "График времени" msgid "Hours:" msgstr "ЧаÑÑ‹:" msgid "Times:" msgstr "ВремÑ:" msgid "Also used for other EPG views!" msgstr "Также иÑпользовать Ð´Ð»Ñ Ð´Ñ€ÑƒÐ³Ð¸Ñ… EPG" msgid "Tooltips:" msgstr "ПодÑказки:" msgid "Electronic Program Guide (EPG)" msgstr "" msgid "Day begins at:" msgstr "" msgid "Show Subtitle:" msgstr "" msgid "Show Summary:" msgstr "" msgid "Active:" msgstr "Ðктивировано:" msgid "Send email after programming timer:" msgstr "Отправить E-Mail поÑле запрограммированного таймера:" msgid "Send email as:" msgstr "E-Mail отправить как:" msgid "Send email to:" msgstr "Oтправить E-Mail к:" msgid "Mail server:" msgstr "Mail Ñервер:" msgid "SMTPAuth user:" msgstr "Ð˜Ð¼Ñ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ Ð´Ð»Ñ SMTPAuth:" msgid "SMTPAuth password:" msgstr "Пароль Ð´Ð»Ñ SMTPAuth:" msgid "Track schedule changes by:" msgstr "" msgid "Broadcast time" msgstr "" msgid "Event id" msgstr "" msgid "Timer" msgstr "Таймер" msgid "Tooltips in timeline:" msgstr "ПодÑказки в графике времени:" msgid "Tooltips in list:" msgstr "ПодÑказки в ÑпиÑке:" msgid "Streaming" msgstr "ТранÑлÑциÑ" msgid "Live Streaming:" msgstr "ТранÑлÑÑ†Ð¸Ñ LiveTV:" msgid "HTTP Port of Streamdev (also possible 3000/ts):" msgstr "Streamdev HTTP порт (также возможно 3000/ts):" msgid "HTTP Port of Xineliboutput (e.g. 37890):" msgstr "" msgid "Recordings Streaming:" msgstr "ТранÑлировать запиÑи (Streaming):" msgid "Path to VDR Recordings on your workstation:" msgstr "Путь к запиÑÑм VDR на вашем компьютере:" msgid "MIME type for live streaming:" msgstr "Тип MIME Ð´Ð»Ñ Ñ‚Ñ€Ð°Ð½ÑлÑции LiveTV:" msgid "Suffix for live streaming:" msgstr "РаÑширение файла Ð´Ð»Ñ LiveTV:" msgid "MIME type for recordings streaming:" msgstr "Тип MIME Ð´Ð»Ñ Ñ‚Ñ€Ð°Ð½ÑлÑции запиÑей:" msgid "Suffix for recordings streaming:" msgstr "РаÑширение файла Ð´Ð»Ñ Ñ‚Ñ€Ð°Ð½ÑлÑции запиÑей:" msgid "Bandwidth of Streams:" msgstr "ПропуÑÐºÐ½Ð°Ñ ÑпоÑобноÑть транÑлÑции :" #, fuzzy msgid "External Search" msgstr "Изменить поиÑк" msgid "URL:" msgstr "" #, fuzzy msgid "Title:" msgstr "Заголовок" #, fuzzy msgid "User-defined search:" msgstr "Ðет таймеров!" msgid "Expert" msgstr "ЭкÑперт" msgid "Update EPG data in background:" msgstr "" msgid "Update EPG every:" msgstr "" msgid "Channel Selections" msgstr "Выбор канала" msgid "Show channels without EPG information:" msgstr "" msgid "In \"AutoTimer\"?" msgstr "Ð’ \"Ðвтотаймеры\"?" msgid "Apply" msgstr "Применить" #, fuzzy msgid "EPG Search Blacklists" msgstr "ИÑпользовать ÑпиÑок запретов:" #, fuzzy msgid "New Blacklist" msgstr "ИÑпользовать ÑпиÑок запретов:" msgid "Search pattern" msgstr "ПоиÑковые признаки" msgid "From" msgstr "С" msgid "To" msgstr "К" #, fuzzy msgid "Delete blacklist?" msgstr "ИÑпользовать ÑпиÑок запретов:" #, fuzzy msgid "Delete Selected Blacklists" msgstr "Удалить выбранные поиÑки" #, fuzzy msgid "Delete all selected blacklists?" msgstr "Удалить вÑе выбранные поиÑки?" msgid "EPG search" msgstr "ЕПГ поиÑк" msgid "EPG Search" msgstr "ПоиÑк по ЕПГ" #, fuzzy msgid "Use template" msgstr "Запомнить шаблон" msgid "New Search" msgstr "Ðовый поиÑк" #, fuzzy msgid "Edit Template" msgstr "Шаблон:" msgid "Settings" msgstr "ÐаÑтройки" msgid "Action" msgstr "ДейÑтвие" msgid "Find" msgstr "ПоиÑк" msgid "Show Favorites" msgstr "Показать фавориты" msgid "Delete Selected Searches" msgstr "Удалить выбранные поиÑки" msgid "Delete all selected searches?" msgstr "Удалить вÑе выбранные поиÑки?" msgid "Execute Selected Searches" msgstr "Выполнить выбранные поиÑки" msgid "Duration" msgstr "ПродолжительноÑть" msgid "More Information" msgstr "Ð”Ð¾Ð¿Ð¾Ð»Ð½Ð¸Ñ‚ÐµÐ»ÑŒÐ½Ð°Ñ Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ" msgid "Channels" msgstr "Телегид" msgid "Record" msgstr "ЗапиÑать передачу" #, fuzzy msgid "Add New Blacklist" msgstr "ИÑпользовать ÑпиÑок запретов:" #, fuzzy msgid "Edit Blacklist" msgstr "ИÑпользовать ÑпиÑок запретов:" #, fuzzy msgid "Add New Template" msgstr "Создать новый Ðвтотаймер" msgid "Add New Search" msgstr "Создать новый поиÑк" msgid "Edit Search" msgstr "Изменить поиÑк" msgid "Small search pattern.\\nDo you really want to use it?" msgstr "ÐœÐ°Ð»ÐµÐ½ÑŒÐºÐ°Ñ Ð¼Ð°Ñка поиÑка.\\n ДейÑтвительно по ней иÑкать?" msgid "You didn't select at least one of\\ntitle, subtitle or description.\\nDo you really want to use this search?" msgstr "" msgid "Hide results" msgstr "СпрÑтать результаты" #, fuzzy msgid "Name:" msgstr "ИмÑ" msgid "Search Term:" msgstr "ПоиÑк по уÑловию:" msgid "Search Mode:" msgstr "Режим поиÑка:" msgid "phrase" msgstr "фразы" msgid "all words" msgstr "вÑе Ñлова" msgid "at least one word" msgstr "в конце одно Ñлово" msgid "match exactly" msgstr "точный поиÑк" msgid "regular expression" msgstr "регулÑрные выражениÑ" msgid "fuzzy" msgstr "неточно" msgid "Tolerance for \"fuzzy\":" msgstr "погрешноÑть Ð´Ð»Ñ \"неточно\"" msgid "Match Case:" msgstr "ПоиÑк уÑловиÑ:" msgid "Use extended EPG info:" msgstr "ИÑпользовать раÑширенную ЕПГ информацию" msgid "Ignore missing categories?" msgstr "" msgid "Use Channel:" msgstr "ИÑпользовать канал:" msgid "no" msgstr "нет" msgid "interval" msgstr "интервал" msgid "channel group" msgstr "группа каналов" msgid "only FTA" msgstr "только FTA" msgid "Range:" msgstr "ОблаÑть:" msgid "Channel Group:" msgstr "Группа каналов:" msgid "Use Time:" msgstr "ИÑпользовать времÑ:" msgid "Start After:" msgstr "Старт поÑле:" msgid "Start Before:" msgstr "Старт раньше:" msgid "Use Duration:" msgstr "ИÑпользовать продолжительноÑть:" msgid "Min. Duration:" msgstr "Мин. продолжительноÑть:" msgid "hh:mm" msgstr "чч:мм" msgid "Max. Duration:" msgstr "МакÑ. продолжительноÑть:" msgid "Use Day of Week:" msgstr "ИÑпользовать день недели:" msgid "Use Blacklists:" msgstr "ИÑпользовать ÑпиÑок запретов:" msgid "selection" msgstr "выбор" msgid "Use in Favorites Menu:" msgstr "ИÑпользовать фаворитное меню:" msgid "Use as Search Timer:" msgstr "ИÑпользовать как поиÑк таймера:" #, fuzzy msgid "yes" msgstr "Да" #, fuzzy msgid "user-defined" msgstr "Ðет таймеров!" msgid "record" msgstr "запиÑать" msgid "announce by OSD" msgstr "" msgid "switch only" msgstr "только переключитÑÑ" msgid "announce and switch" msgstr "" msgid "announce by mail" msgstr "" #, fuzzy msgid "First day:" msgstr "ПÑтница" #, fuzzy msgid "Last day:" msgstr "ПÑтница" msgid "Auto delete:" msgstr "" #, fuzzy msgid "count recordings" msgstr "ЗапиÑи" #, fuzzy msgid "count days" msgstr "Понедельник" #, fuzzy msgid "After ... recordings:" msgstr "Сохранить ... ЗапиÑей" #, fuzzy msgid "After ... days after first recording:" msgstr "Сохранить ... ЗапиÑей" msgid "Settings for action \"record\"" msgstr "ÐаÑтройки Ð´Ð»Ñ \"запиÑи\"" msgid "Series Recording:" msgstr "ЗапиÑÑŒ Ñерий:" msgid "Delete Recordings After ... Days:" msgstr "Удалить запиÑи поÑле ... дней" msgid "Keep ... Recordings:" msgstr "Сохранить ... ЗапиÑей" msgid "Pause, when ... recordings exist:" msgstr "Пауза, еÑли ... запиÑÑŒ ÑущеÑтвует:" msgid "Avoid Repeats:" msgstr "Избегать повторений:" msgid "Allowed Repeats:" msgstr "Разрешенные повторениÑ:" msgid "Only Repeats Within ... Days:" msgstr "ÐŸÐ¾Ð²Ñ‚Ð¾Ñ€ÐµÐ½Ð¸Ñ Ñ‚Ð¾Ð»ÑŒÐºÐ¾ в течение ... Дней" msgid "Compare:" msgstr "Сравнить:" msgid "Minimal match of description in %:" msgstr "" msgid "VPS:" msgstr "VPS:" msgid "Settings for action \"switch only\"" msgstr "ÐаÑтройки Ð´Ð»Ñ \"только переключитÑÑ\"" msgid "Switch ... Minutes Before Start:" msgstr "ПереключитÑÑ Ð·Ð° ... минут до Ñтарта\"" msgid "Unmute sound:" msgstr "" msgid "Settings for action \"announce and switch\"" msgstr "" msgid "Ask ... Minutes Before Start:" msgstr "" #, fuzzy msgid "Delete template" msgstr "Запомнить шаблон" #, fuzzy msgid "Delete this template?" msgstr "Удалить таймер?" msgid "Save as template" msgstr "Запомнить шаблон" msgid "Run" msgstr "Выполнить" msgid "Error!" msgstr "Ошибка!" msgid "

Here you will find a listing of automatic timers (AutoTimer) known to VDRAdmin-AM.

The list shows some information on AutoTimers. You can change the list's sorting by clicking the columns heading.

For each AutoTimer you have the following options:

Set its state
By clicking on \"Yes\" or \"No\" in the \"Active\" column to toggle the activity.
Quickly view its priority and lifetime
By pointing the mouse cursor to the AutoTimer's title.
Edit the AutoTimer
You can edit an AutoTimer by clicking \"edit\".
Delete the AutoTimer
To delete an AutoTimer you click \"delete\".

Each AutoTimer's state is indicated by differently coloured images:
\"on\" AutoTimer is OK and will automatically program matching broadcasts.
\"inactive\" AutoTimer is not active.

In addition to these functions you can add a new AutoTimer by clicking at the top and you can delete a number of AutoTimers at once by checking the box in the last column of those timers and clicking .

Click to force VDRAdmin-AM to reconnect to VDR, fetch the current EPG and check for matching AutoTimers.

" msgstr "

ЗдеÑÑŒ Ð’Ñ‹ найдeте ÑпиÑок вÑех автотаймеров, которые знает VDRAdmin-AM.

СпиÑок показывает Вам неÑколько Ñведений о Ðвтотаймерах. Ð’Ñ‹ можете изменить Ñортировку ÑпиÑка, нажав на желаемую надпиÑÑŒ колонки.

Ð”Ð»Ñ ÐºÐ°Ð¶Ð´Ð¾Ð³Ð¾ Ðвтотаймера Ð’Ñ‹ имеете Ñледующие возможноÑти:

Изменение ÑоÑтоÑниÑ
Ð’Ñ‹ можете активировать или деактивировать Ðвтотаймеры переключив кнопкой мыши \"Да\" или \"Ðет\" в Ñтолбце \"Ðктивный\".
БыÑтрое уведомление его приоритета и Ñрока хранениÑ
Ð”Ð»Ñ Ñтого нужно навеÑти курÑор мышки на название Ðвтотаймера.
Редактирование Ðвтотаймера
Ð’Ñ‹ можете редактировать Ðвтотаймер, щeлкнув курÑором на \"edit\".
Удаление Ðвтотаймера
Удалить Ðвтотаймер можно нажав на \"delete\".

Ð¡Ñ‚Ð°Ñ‚ÑƒÑ ÐºÐ°Ð¶Ð´Ð¾Ð³Ð¾ Ðвтотаймера показываетÑÑ Ð¾Ð¿Ñ€ÐµÐ´ÐµÐ»ÐµÐ½Ð½Ñ‹Ð¼ цветом:
\"on\" Ðвтотаймер в порÑдке и Ñовподающие передачи будут запрограммированы.
\"inactive\" Ðвтотаймер не активен.

Дополнительно к Ñтим функциÑм Ð’Ñ‹ можете Ñоздать новый Ðвтотаймер , нажав курÑором на .Ð’ нижнем крае Ñкрана Ð’Ñ‹ найдeте кнопку , тем Ñамым будут удалены вÑе выбранные Вами Ðвтотаймеры.

С помощью кнопки Ð’Ñ‹ можете заÑтавить VDRAdmin-AM ÑвÑзыватьÑÑ Ñ VDR Ð´Ð»Ñ Ð¾Ð±Ð½Ð¾Ð²Ð»ÐµÐ½Ð¸Ñ Ð´Ð°Ð½Ð½Ñ‹Ñ… EPG и поиÑка Ñовподающих Ðвтотаймеров.

" msgid "

Here you can edit an automatic timer's (AutoTimer) settings.

AutoTimer is a key feature of VDRAdmin-AM. An AutoTimer consists of one or more search terms and some other settings, that are looked for regularly in the Electronic Program Guide (EPG). On match AutoTimer adds a timer in VDR automatically for that broadcast. That's very comfortable for irregularly broadcasted series or movies you don't want to miss.

" msgstr "

ЗдеÑÑŒ Ð’Ñ‹ можете обрабатывать уÑтановки Ðвтотаймеров.

Ðвтотаймеры ÑвлÑÑŽÑ‚ÑÑ ÐºÐ»ÑŽÑ‡ÐµÐ²Ð¾Ð¹ функцией VDRAdmin-AM. Ðвтотаймер ÑоÑтоит из неÑкольких поиÑковых признаков и других уÑтановок, которые регулÑрно ищутÑÑ Ð² Electronic Program Guide (EPG). При ÑоответÑтвии Ðвтотаймер автоматичеÑки ÑоздаeÑ‚ новый таймер Ð´Ð»Ñ Ñтой передачи в VDR. Это очень комфортабельно Ð´Ð»Ñ Ð½ÐµÑ€ÐµÐ³ÑƒÐ»Ñрно транÑлируемых Ñериалов или художеÑтвенных фильмов, которые Ð’Ñ‹ не хотите пропуÑтить.

" msgid "Activate or deactivate this AutoTimer. Deactivated AutoTimers are still stored in the AutoTimer list so that they can be activated again, but they do not record anything meanwhile. Above that you can set this to \"oneshot\" so this AutoTimer only programs the (one!) next matching broadcast." msgstr "Ðктивировать или деактивировать Ñтот Ðвтотаймер. Деактивированные Ðвтотаймеры будут находитьÑÑ Ð¸ дальше в ÑпиÑке и запиÑи по нему производитÑÑ Ð½Ðµ будут, но их можно активировать Ñнова. Ð’Ñ‹ можете уÑтанавливать их также на \"однократно\", так чтобы Ñтот Ðвтотаймер Ñработал только единажды на Ñледущей передаче." msgid "Choosing the right search items decides whether only the wanted broadcasts or broadcasts having similar names or even nothing gets recorded.
Case doesn't matter, \"X-Files\" matches anything \"x-files\" will match. You can set multiple search items by separating them with spaces. Broadcasts will match only if they match all configured search items.
You'd better only use letters and numbers for search items, as the EPG often miss colons, brackets and other characters.
Experts can also use regular expressions, but you have to get needed information from the VDRAdmin-AM sources (undocumented feature).

You can exclude broadcasts so that they don't get recorded even if they would match an AutoTimer. Therefore you have to enter that titles into the file vdradmind.bl, one event a line. This file must be located in your VDRAdmin-AM's configuration folder. If this string is found either in the EPG's title or in title~subtitle, this event will not be programmed by AutoTimer. So you can disable complete episodes (for example when using \"Enterprise\" as blacklist string) or only one episode (when using \"Enterprise~Azati Prime\" as blacklist string)." msgstr "Выбор иÑкомых понÑтий решает будут ли запиÑаны желаемые, Ñ Ð¿Ð¾Ñ…Ð¾Ð¶Ð¼Ð¸ названиÑми передачи или будет ли запиÑыватьÑÑ Ñ‡Ñ‚Ð¾-нибудь вообще.
ÐапиÑание Ñ Ð±Ð¾Ð»ÑŒÑˆÐ¾Ð¹ или маленькой буквы не играет роли. Ð’Ñ‹ можете указывать неÑколько поиÑковых признаков раздельно через пробел.Чтобы они нашлиÑÑŒ, вÑе признаки должны ÑодержатьÑÑ Ð² желаемых полÑÑ… передачи.
ИÑпользовать рекомендуетÑÑ Ñ‚Ð¾Ð»ÑŒÐºÐ¾ буквы и чиÑла, так как в EPG отÑутÑтвуют чаÑто двоеточиÑ, Ñкобки и другие Ñимволы.
ЭкÑперты могут иÑпользовать также \"regular expressions\".Ð”Ð»Ñ Ð¸Ñ… иÑÐ¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ Ð’Ñ‹ должны броÑить взглÑд в иÑходники VDRAdmin-AM (не Ð´Ð¾ÐºÑƒÐ¼ÐµÐ½Ñ‚Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð½Ð°Ñ Ñ„ÑƒÐ½ÐºÑ†Ð¸Ñ).

Ð’Ñ‹ можете также иÑключать передачи, которые ÑобÑтвенно подошли бы, внеÑÑ Ð¸Ñ… название в vdradmind.bl, одна передача в Ñтрочке. Этот файл должен находитьÑÑ Ð² конфигурационном каталоге VDRAdmin-AM. ЕÑли Ñтрока либо на title, либо title~subtitle из EPG передачи подходит, то Ñта передача автоматичеÑки не программируетÑÑ.Таким образом Ð’Ñ‹ можете иÑключать полную Ñерию." msgid "Here you can define the EPG sections where VDRAdmin-AM should look for the search pattern." msgstr "ЗдеÑÑŒ Ð’Ñ‹ указываете разделы из EPG, которые VDRAdmin-AM должен оÑматривать на наличие признаков поиÑка." msgid "Use these checkboxes to limit searching for matching broadcasts to a set of weekdays." msgstr "Отметьте дни недели, в которые будет проводитьÑÑ Ð¿Ð¾Ð¸Ñк передач." msgid "The channel to look for matching broadcasts or \"all\" to search in all known or wanted channels. You can define the wanted channels for AutoTimer in \"Configuration\"." msgstr "Канал, который должен быть проÑмотрен на наличие Ñовпадающих передач. С \"вÑе\" будут проÑмотрены вÑе извеÑтные или желаемые каналы. Желаемые каналы Ð´Ð»Ñ Ð°Ð²Ñ‚Ð¾Ñ‚Ð°Ð¹Ð¼ÐµÑ€Ð¾Ð² уÑтанавливаютÑÑ Ð½Ð° Ñтранице \"Конфигурации\". " msgid "A broadcast must start after the time entered here to match. The first text field is for \"hour\", the second for \"minute\"." msgstr "Передача может начинатьÑÑ Ð½Ðµ раньше уÑтановленного здеÑÑŒ времени. Первое текÑтовое поле указывает чаÑÑ‹, второе минуты." msgid "A broadcast must end before the time entered here to match. The first text field is for \"hour\", the second for \"minute\"." msgstr "Передача должна заканчиватьÑÑ Ð½Ðµ позднее уÑтановленного здеÑÑŒ времени.ПервоетекÑтовое поле указывает чаÑÑ‹, второе минуты." msgid "Set this option to \"yes\" if all timers programed by this AutoTimer should have individual start/stop margins and enter the values in the next two text boxes." msgstr "Ответьте \"да\", еÑли вÑе таймеры выÑтавленные по AutoTimer должны иметь индивидуальные начало/конец и введите Ñ‹Ð½Ð°Ñ‡ÐµÐ½Ð¸Ñ Ð² Ñлед. два текÑтовых Ð¿Ð¾Ð»Ñ " msgid "The number of minutes VDRAdmin-AM subtracts from the broadcast's start time found in the EPG." msgstr "КоличеÑтво минут, которые должен VDRAdmin-AM вычеÑть от начального времени передаваемого по EPG." msgid "The number of minutes VDRAdmin-AM adds to the broadcast's stop time found in the EPG." msgstr "КоличеÑтво минут, которые должен VDRAdmin-AM прибавить к конечному времени передаваемого по EPG." msgid "An integer in the range 0...99, defining the priority of this timer and of recordings created by this timer. 0 represents the lowest value, 99 the highest. The priority is used to decide which timer shall be started in case there are two or more timers with the exact same start time. The first timer in the list with the highest priority will be used.

This value is also stored with the recording and is later used to decide which recording to remove from disk in order to free space for a new recording. If the disk runs full and a new recording needs more space, an existing recording with the lowest priority (and which has exceeded its guaranteed lifetime) will be removed.

If all available DVB cards are currently occupied, a timer with a higher priority will interrupt the timer with the lowest priority in order to start recording." msgstr "ЧиÑло от 0 до 99, которое указывает приоритет Ñтого таймера и запрограммированных им запиÑей. 0 имеет наименьший приоритет, а 99 наивыÑший.Приоритет иÑпользуетÑÑ, чтобы решать, какой таймер должен запуÑкатьÑÑ Ð² Ñлучае, еÑли 2 и более таймера имееют одинаковое Ð²Ñ€ÐµÐ¼Ñ Ð½Ð°Ñ‡Ð°Ð»Ð° запиÑи.ИÑпользуетÑÑ Ð¿ÐµÑ€Ð²Ñ‹Ð¹ таймер в ÑпиÑке Ñ Ð½Ð°Ð¸Ð²Ñ‹Ñшим приоритетом.

Это значение ÑохранÑетÑÑ Ñ‚Ð°ÐºÐ¶Ðµ вмеÑте Ñ Ð·Ð°Ð¿Ð¸Ñью и иÑпользуетÑÑ Ð¿Ð¾Ð·Ð¶Ðµ, чтобы решать, ÐºÐ°ÐºÐ°Ñ Ð·Ð°Ð¿Ð¸ÑÑŒ должна удалÑтьÑÑ, в Ñлучае, еÑли на жеÑтком диÑке нет больше меÑта Ð´Ð»Ñ Ð½Ð¾Ð²Ð¾Ð¹ запиÑи.

ЕÑли вÑе DVB-карты занÑты, таймер Ñ Ð±Ð¾Ð»ÐµÐµ выÑоким припритетом прерывает таймер Ñ Ñамым низким приоритетом Ð´Ð»Ñ Ð½Ð°Ñ‡Ð°Ð»Ð° запиÑи." msgid "The guaranteed lifetime (in days) of a recording created by this timer. 0 means that this recording may be automatically deleted at any time by a new recording with higher priority. 99 means that this recording will never be automatically deleted. Any number in the range 1...98 means that this recording may not be automatically deleted in favour of a new recording, until the given number of days since the start time of the recording has passed by." msgstr "Гарантируемое количеÑтво дней Ñ…Ñ€Ð°Ð½ÐµÐ½Ð¸Ñ Ð·Ð°Ð¿Ð¸Ñи, которое былo Ñозданo Ñтим таймером. 0 означает, что Ñта запиÑÑŒ автоматичеÑки удалÑетÑÑ Ð² любое Ð²Ñ€ÐµÐ¼Ñ Ð·Ð°Ð¿Ð¸Ñью Ñ Ð±Ð¾Ð»ÐµÐµ выÑоким приоритетом. 99 означает, что Ñта запиÑÑŒ никогда не будет удалена автоматичеÑки.ЧиÑла от 1 до 98 означают, что запиÑÑŒ удалитÑÑ Ð°Ð²Ñ‚Ð¾Ð¼Ð°Ñ‚Ð¸Ñ‡ÐµÑки, еÑли указанное количеÑтво дней иÑтекло Ñо Ð´Ð½Ñ Ð·Ð°Ð¿Ð¸Ñи и на жеÑтком диÑке нет больше меÑта Ð´Ð»Ñ Ð½Ð¾Ð²Ñ‹Ñ… запиÑей. " msgid "Check this box if you want VDRAdmin-AM to append the broadcast's EPG subtitle to the recording's file name." msgstr "Ðктивируйте Ñту опцию, еÑли Ð’Ñ‹ хотите, чтобы VDRAdmin-AM добавлÑл подзаголовок передачи из EPG к названию запиÑи." msgid "If you enable this VDRAdmin-AM will track timers it has already programmed automatically. This is useful if want to deactivate or delete timers that have been programmed automatically in the timers listing." msgstr "ЕÑли Ð’Ñ‹ активируете Ñту опцию, то VDRAdmin-AM запоминает таймеры, которые он уже программировал автоматичеÑки. Это полезно, еÑли автоматичеÑки запрограммированные таймеры должны удалÑтьÑÑ Ð¸Ð»Ð¸ деактивироватьÑÑ Ð² ÑпиÑке таймеров." msgid "The directory this AutoTimer will place the recordings in. If the name shall contain subdirectories, these have to be delimited by '~' (since the '/' character may be part of a regular programme name).
VDRAdmin-AM will append the matching broadcast's title and subtitle (if the \"Episode\" checkbox is marked) to the directory given here.

You can also use the following keywords that are replaced in the final file name by the values supplied by for example tvm2vdr:
  • %Title% - will become the title of the event.
  • %Subtitle% - will become the subtitle of the event.
  • %Director% - will become the director of the event.
  • %Date% - will become the date of the recording.
  • %Category% - will become the category of the event (Spielfilm/Serie/...).
  • %Genre% - will become the genre of the event (Drama/Krimi/..).
  • %Year% - will become the year of production.
  • %Country% - will become the country of production.
  • %Originaltitle% - will become the original title of the event.
  • %FSK% - will become the FSK from the event.
  • %Episode% - will become the episode's title of the event.
  • %Rating% - will become the rating of the event from the EPG provider.

Note:

If you use the above keywords it's in your own responsibility to supply the complete file name for the recordings! VDRAdmin-AM will not append anything to the resulting string." msgstr "ЗдеÑÑŒ Ð’Ñ‹ указываете каталог в котором Ñтот Aвтотаймер будет ÑохранÑть запиÑи.ЕÑли указываютÑÑ Ð¿Ð¾Ð´ÐºÐ°Ñ‚Ð°Ð»Ð¾Ð³Ð¸, то они должны разделÑтьÑÑ Ñ '~' (так как '/' может быть чаÑтью Ð½Ð°Ð·Ð²Ð°Ð½Ð¸Ñ Ð¿ÐµÑ€ÐµÐ´Ð°Ñ‡Ð¸).
VDRAdmin-AM внеÑeÑ‚ автоматичеÑки заголовок и подзаголовок (еÑли у \"СериÑ\" была уÑтановлена галочка) в название запиÑи.

Ð’Ñ‹ можете иÑпользовать также ключевые Ñлова, которые в окончательном названии файла заменÑÑŽÑ‚ÑÑ Ð½Ð° значениÑ, например от tvm2vdr:
  • %Title% - Заголовок передачи.
  • %Subtitle% - Подзаголовок передачи.
  • %Director% - РежиÑÑeÑ€ передачи.
  • %Date% - Дата запиÑи.
  • %Category% - ÐšÐ°Ñ‚ÐµÐ³Ð¾Ñ€Ð¸Ñ Ð·Ð°Ð¿Ð¸Ñи (художеÑтвенный фильм/Ñериал/...).
  • %Genre% - Жанр запиÑи(Драма/детектив/....).
  • %Year% - Год производÑтва.
  • %Country% - Страна производÑтва.
  • %Originaltitle% - Оригинальный заголовок.
  • %FSK% - Ограничение по возвраÑту.
  • %Episode% - Заголовок Ñпизода.
  • %Rating% - Оценка передачи от поÑтавщика EPG.

Внимание:

ЕÑли иÑпользуютÑÑ Ð²Ñ‹ÑˆÐµÐ½Ð°Ð·Ð²Ð°Ð½Ð½Ñ‹Ðµ ключевые Ñлова, то Ð’Ñ‹ должны Ñами указать полное название запиÑи! VDRAdmin-AM ничего указывать или дополнÑть не будет." msgid "

Here you can change general settings and base settings for timers, AutoTimers, channel selection and streaming parameters.

" msgstr "

ЗдеÑÑŒ Ð’Ñ‹ можете изменить общие и оÑновные параметры таймеров, автотаймеров, выбор канала и транÑлÑции (Streaming).

" msgid "The skin you want to use." msgstr "ИÑпользуемый Ñтиль." msgid "The page you want to see at first connect to VDRAdmin-AM." msgstr "Страница, которую Ð’Ñ‹ хотите увидеть при первом Ñоединении Ñ VDRAdmin-AM" msgid "VDRAdmin-AM will load the given number of channels from VDR and present only those in any fields where channels can be selected. This also limits the EPG information VDRAdmin-AM will read so that you can use this to reduce VDRAdmin-AM's memory consumption and increase its performance. 0 turns this feature off and VDRAdmin-AM will use all available channels." msgstr "VDRAdmin-AM загрузит из VDR только указанное здеÑÑŒ чиÑло каналов и покажет их во вÑех меÑтах выбора канала.Тем Ñамым ограничиваетÑÑ Ð¸ EPG информациÑ, которую будет читать VDRAdmin-AM, что значительно повышает ÑкороÑть обработки.0 выключает Ñту функцию и VDRAdmin-AM иÑпользует вÑе доÑтупные каналы." #, fuzzy msgid "Here you can specify subnets from which access to VDRAdmin-AM does not require logging in. For example: \"192.168.0.0/24\" will include any IP starting with \"192.168.0.\", \"192.168.0.123/32\" will only match \"192.168.0.123\". Multiple subnets can be specified by separating them with spaces or commas." msgstr "ЗдеÑÑŒ Ð’Ñ‹ можете определить IP Ð°Ð´Ñ€ÐµÑ Ð¸Ð»Ð¸ IP маÑку , откуда можно войти без ввода данных пользователÑ.Ðапример: \"192.168.0.0/24\" Ñодержит каждый IP, который начинаетÑÑ Ñ \"192.168.0.\".\"192.168.0.123/32\" Ñодержит только Ñтот IP \"192.168.0.123\"." msgid "Here you can set the localization VDRAdmin-AM should use." msgstr "ЗдеÑÑŒ Ð’Ñ‹ уÑтанавливаете локализацию, которую должен иÑпользовать VDRAdmin-AM." msgid "With this option the settings will be saved if VDRAdmin-AM exits. This will also save settings not available on the \"Configuration\" menu like interval and size in TV, sorting in the lists and current view in \"What's on now\"." msgstr "С Ñтой опцией уÑтановки будут запомнены. Они также будут Ñодержать некоторые другие опции не из меню \"КонфигурациÑ\"." msgid "Top" msgstr "вверх" msgid "The number of DVB cards VDR can access. Depending on this value VDRAdmin-AM will calculate critical timers in the Timer menu." msgstr "КоличеÑтво DVB карт, к которым может обращатьÑÑ VDR. Ð’ завиÑимоÑти от значениÑ, VDRAdmin-AM вычиÑлит конфликтующие таймеры в меню Таймеры " msgid "The path to VDR's recordings. It's used so that VDRAdmin-AM can locate the recordings when using Recordings Streaming and reccmds.conf in the Recordings menu." msgstr "Путь к запиÑÑм VDR. Это иÑпользуетÑÑ Ñ‡Ñ‚Ð¾Ð±Ñ‹ VDRAdmin-AM мог определить меÑтонахождение запиÑей, еÑли будут иÑпользоватьÑÑ Ñ„ÑƒÐ½ÐºÑ†Ð¸Ð¸ ТранÑлировать запиÑÑŒ и reccmds.conf в меню ЗапиÑи " msgid "The path where VDR's configuration files are located. If this directory contains the file reccmds.conf its content is shown in a selectbox in the Recordings menu." msgstr "Путь к конфигурационным файлам VDR. ЕÑли Ñтот каталог Ñодержит файл reccmds.conf ,то Ñодержимое Ñтого файла будет доÑтупным в меню ЗапиÑи " msgid "The path where the EPG images are stored." msgstr "Путь, где Ñохранены Ð¸Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ EPG." msgid "The username for the main user, i.e. the user having the most privileges." msgstr "Ð˜Ð¼Ñ Ð³Ð»Ð°Ð²Ð½Ð¾Ð³Ð¾ пользователÑ, имеющего права на любые изменениÑ." msgid "The main user's password." msgstr "Пароль главного пользователÑ." msgid "If you want a user account having only limited privileges, this is for you. The guest user cannot modify anything, it's only allowed to view the EPG, timers, AutoTimers and recordings listings." msgstr "ЕÑли Ð’Ñ‹ хотите Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ Ñ Ð¾Ð³Ñ€Ð°Ð½Ð¸Ñ‡ÐµÐ½Ñ‹Ð¼Ð¸ правами, тогда Ñто Ð´Ð»Ñ Ð’Ð°Ñ. ГоÑтевой пользователь не может ничего изменÑть, ему дозволен только проÑмотр ЗапиÑей, Таймеров, Ðвтотаймеров и EPG." msgid "The username for the guest user." msgstr "Ð˜Ð¼Ñ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ Ð´Ð»Ñ Ð³Ð¾Ñтевого Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ ." msgid "The guest user's password." msgstr "Пароль гоÑтевого пользователÑ." msgid "The number of hours to show in the timeline." msgstr "ЧиÑло чаÑов, которые будут отображатьÑÑ Ð² графике времени." msgid "A comma separated list of times in hh:mm format that appear in the selectbox placed at the top." msgstr "СпиÑок времЈн (через запÑтую еÑли неÑколько)в формате hh:mm, который доÑтупен вверху Ñтраницы." msgid "Here you can (de-)activate the tooltips." msgstr "ЗдеÑÑŒ Ð’Ñ‹ можете вкл. или выкл. подÑказки." msgid "The time after which events are shown on a new day. For example setting 03:00 means that today's schedule will include any event starting before 03:00 tomorrow. Applies only to the 'Playing Today?' list." msgstr "" msgid "Show the 'Subtitle' text for each event. Not all broadcasters use this field." msgstr "" msgid "Show the 'Summary' text for each event." msgstr "" msgid "Activate or deactivate the AutoTimer function." msgstr "Ðктивирует или деактивирует функцию Ðвтотаймера." msgid "VDRAdmin-AM will send an email whenever an event matches an AutoTimer and a timer has been programmed if you enable this feature." msgstr "ЕÑли Ð’Ñ‹ активируете Ñту функцию, то VDRAdmin-AM будет отправлÑть Вам каждый раз E-Mail, еÑли Ðвтотаймер нашeл подходÑщию передачу изапрограммировал таймер" msgid "Here you set the sending email address of the generated email." msgstr "ЗдеÑÑŒ Ð’Ñ‹ уÑтанавливаете E-mail адреÑÑ Ð´Ð»Ñ Ñгенерированных E-mail" msgid "The email address the email is sent to." msgstr "E-Mail Ð°Ð´Ñ€ÐµÑ ÐºÑƒÐ´Ð° будет отправлÑтьÑÑ E-Mail." msgid "The outgoing mail server." msgstr "Сервер Ð´Ð»Ñ Ð²Ñ‹Ñ…Ð¾Ð´Ñщих Ñлектронных пиÑем." msgid "If you need to authenticate yourself at the outgoing mail server, you have to supply the username and the password below. Leaving this field empty will disable SMTPAuth." msgstr "ЕÑли Ñервер отправки почты (SMTP) требует авторизации, тогда укажите здеÑÑŒ Ð¸Ð¼Ñ Ð¸ пароль пользователÑ.ОÑтавте поле SMTPAuth пуÑтым, еÑли авторизации не требуетÑÑ." msgid "The password for the SMTPAuth user." msgstr "Пароль Ð´Ð»Ñ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ SMTPAuth." msgid "Here you can (de-)activate the tooltips in the timeline." msgstr "ЗдеÑÑŒ Ð’Ñ‹ можете вкл. или выкл. подÑказки в графике времени." msgid "Here you can (de-)activate the tooltips in the list." msgstr "ЗдеÑÑŒ Ð’Ñ‹ можете вкл. или выкл. подÑказки в ÑпиÑке." msgid "Add summary to new timers:" msgstr "ИÑпользовать опиÑание из EPG Ð´Ð»Ñ Ð½Ð¾Ð²Ñ‹Ñ… таймеров:" msgid "If you don't want VDRAdmin-AM to add the summary taken from EPG to new timers you can switch it off here." msgstr "ЕÑли Ð’Ñ‹ не хотите, чтобы VDRAdmin-AM уÑтанавливал опиÑание передачи из EPG Ð´Ð»Ñ Ð½Ð¾Ð²Ð¾Ð³Ð¾ таймера, тогда выключите Ñто здеÑÑŒ." msgid "Enable or disable live streaming using the streamdev plugin. You also have to set the correct HTTP Port for Streamdev below." msgstr "Ðктивирование или деактивирование транÑлÑции LiveTV. Ð”Ð»Ñ Ñтого Вам нужен streamdev модуль. Кроме Ñтого нужно уÑтановить Streamdev HTTP-порт. " msgid "Here you have to set the port number your VDR's streamdev server listens for connections. Additionally you can also provide the stream type you like to use." msgstr "ЗдеÑÑŒ Ð’Ñ‹ указываете номер порта Streamdev Ñервера в VDR. Ð’Ñ‹ можете указывать также иÑпользуемый тип транÑлÑции." msgid "Enable or disable streaming of recordings.
Well actually this is no real \"streaming\", but you have to setup your workstation so that it can access VDR's recordings. You can use for example Samba or NFS for this. VDRAdmin-AM simply generates a playlist that contains all parts of the recording and sends this to your browser. If your browser and media player are configured correctly you will see the recording on your workstation's display." msgstr "Ðктивирование или деактивирование транÑлÑции запиÑей.
Пока Ñто не наÑтоÑÑ‰Ð°Ñ \"ТранÑлÑциÑ\", но вы можете Ñконфигурировать Ваш перÑональный компьютер так, чтобы он мог обращатьÑÑ Ðº запиÑÑм VDR.Это возможно Ñделать иÑÐ¿Ð¾Ð»ÑŒÐ·ÑƒÑ Samba или NFS.VDRAdmin-AM только Ñоздает ÑпиÑок воÑпроизведениÑ, который Ñодержит вÑе чаÑти выбранной запиÑи и поÑылает их затем к броузеру.ЕÑли браузер и программа воÑÐ¿Ñ€Ð¾Ð¸Ð·Ð²ÐµÐ´ÐµÐ½Ð¸Ñ Ñконфигурированы правильно, то запиÑÑŒ на перÑональном компьютере должна воÑпроизвеÑтиÑÑŒ." msgid "This is the path where your workstation can access VDR's recordings. This depends on your VDR and workstation setup, for example \"\\\\vdr\\videos\" or \"V:\\\" (on Windows) or \"/mnt/videos\" (on Linux)." msgstr "Путь, по которому ваш перÑональный компьютер Ñможет обращатьÑÑ Ðº запиÑÑм VDR.Он завиÑит от конфигурации VDR и перÑонального компьютера.Ðапример: \"\\\\vdr\\videos\" или \"V:\\\" (Ð´Ð»Ñ Windows)\" или \"/mnt/videos\" (Ð´Ð»Ñ Linux)." msgid "The MIME type to send when using live streaming. Defaults to \"video/x-mpegurl\"." msgstr "MIME-тип транÑлÑции LiveTV. По умолчанию \"video/x-mpegurl\"." msgid "The suffix to use for live streaming. Defaults to \"m3u\"." msgstr "РаÑширение файла транÑлÑции LiveTV. По умолчанию \"m3u\"." msgid "The MIME type to send when using recordings streaming. Defaults to \"video/x-mpegurl\"." msgstr "MIME-тип транÑлÑции запиÑей. По умолчанию \"video/x-mpegurl\"." msgid "The suffix to use for recordings streaming. Defaults to \"m3u\"." msgstr "РаÑширение файла транÑлÑции запиÑей. По умолчанию \"m3u\"." msgid "

Here you can define two external searches that you can access in the EPG views. You simply have to find the required URL and where the search pattern has to be located. %TITLE% will be substituted by the broadcast's EPG title.

" msgstr "" msgid "Some examples:" msgstr "" msgid "Please change the hostname to your local needs!" msgstr "" msgid "

This section is for experts only, i.e. you know what you are doing!

" msgstr "

Этот раздел только Ð´Ð»Ñ ÑкÑпертов, Ñ‚.е. Ð´Ð»Ñ Ñ‚ÐµÑ… кто знает что он делает!

" msgid "If set to \"yes\" VDRAdmin-AM will periodically refresh its local EPG cache. Else the EPG will be refreshed if the user accesses any EPG view at the web interface and the timeout set at \"Update EPG every\" has been reached." msgstr "" #, fuzzy msgid "The interval, the EPG data is refreshed from VDR and AutoTimer updates are performed (if AutoTimer feature is used)." msgstr "Интервал проверки EPG Ð´Ð»Ñ Ð¾Ð±Ð½Ð¾Ð²Ð»ÐµÐ½Ð¸Ñ Ðвтотаймеров." msgid "

If you want to limit the number of channels used in some parts of VDRAdmin-AM, this is for you!

Use the radio buttons to activate or deactivate the wanted channels in the named menu.

To add channels to the list of wanted channels you have to select them in the left side selectbox and click . If you want to remove channels from the list of wanted channels you have to select them in the right side selectbox and click .

" msgstr "

Этим Ð’Ñ‹ можете ограничивать количеÑтво каналов в неÑкольких подразделах VDRAdmin-AM.

ИÑпользуйте кнопки \"Да\"/\"Ðет\" Ð´Ð»Ñ Ð°ÐºÑ‚Ð¸Ð²Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñили Ð´ÐµÐ°ÐºÑ‚Ð¸Ð²Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ ÑƒÐºÐ°Ð·Ð°Ð½Ð½Ð¾Ð³Ð¾ количеÑтва каналов.

Ð”Ð»Ñ Ð´Ð¾Ð±Ð°Ð²Ð»ÐµÐ½Ð¸Ñ ÐºÐ°Ð½Ð°Ð»Ð¾Ð² в выборочный ÑпиÑок нужно выделить желаемые каналы в левом поле выбора и нажать на кнопку .Удалить каналы из Ñтого ÑпиÑка можно выделив " msgid "Usually channels that don't have EPG information are hidden in all EPG views. If you don't want them to be hidden you have to set this option to \"yes\"." msgstr "" msgid "Edit Timer" msgstr "Редактировать таймер" #, fuzzy msgid "Edit EPG" msgstr "Редактировать" #, fuzzy msgid "

Here you can edit the descriptive fields of an existing EPG entry.

" msgstr "

ЗдеÑÑŒ Ð’Ñ‹ можете редактировать уÑтановки таймера.

" #, fuzzy msgid "Channel (readonly)" msgstr "Группа каналов:" msgid "This is the channel of the EPG entry. It cannot be changed." msgstr "" #, fuzzy msgid "Time (readonly)" msgstr "не изменÑемо" msgid "This is the start and end time of the entry. It cannot be changed." msgstr "" msgid "Change this string to give this EPG Entry a new title. It must consist of only one line of text." msgstr "" msgid "Change this string to give this EPG Entry a new subtitle. It must consist of only one line of text." msgstr "" msgid "Change the text in this field to edit the description of this entry. The text can consist of one or more lines." msgstr "" #, fuzzy msgid "VPS (readonly)" msgstr "не изменÑемо" msgid "If available this field shows the vps time of the EPG entry. It cannot be changed." msgstr "" #, fuzzy msgid "Video tracks (readonly)" msgstr "Видео дорожки" msgid "If available this field shows the video track(s). It cannot be changed." msgstr "" #, fuzzy msgid "Audio tracks (readonly)" msgstr "Ðудио дорожки" msgid "If available this field shows the audio track(s). It cannot be changed." msgstr "" msgid "No Help Available" msgstr "Помощь недоÑтупна" msgid "

No help available yet. For adding or changing text please contact amair.sob@googlemail.com.

" msgstr "

До Ñих пор нет помощи. Ð”Ð»Ñ ÑÐ¾Ð·Ð´Ð°Ð½Ð¸Ñ Ð¸Ð»Ð¸ иÑÐ¿Ñ€Ð°Ð²Ð»ÐµÐ½Ð¸Ñ Ñ‚ÐµÐºÑта ÑвÑжитеÑÑŒ Ñfreex@free-x.de.

" msgid "Recordings" msgstr "ЗапиÑи" msgid "

Here you will find a listing of recordings known to VDR. The headline will also show you VDR's total and free disk space.

The listing showing you some information on the recordings. You can change the list's sorting by clicking the columns heading. Above the list you'll see the navigation path. If you want to view the contents of previous folders you'll have to click on its name in that path.

Each row contains this information:

Date
The date when the recording has been done. In case of folders this will show the number of recordings the folder contains.
Time
The time when the recording has been done. In case of folders this will show the number of new recordings the folder contains.
Name
The recording's or folder's name. Click it to show the recording's summary or descend into the folder.
Rename (\"edit\")
Rename a recording.

Note:

This only works if VDR has the MOVR or RENR SVDRP command which is not a core VDR feature but provided by the Liemikuutio patch set.
Delete (\"delete\")
Delete a recording.
Stream (\"stream\")
This column is only shown if you activated and configured Recordings Streaming in the Configuration menu. You can watch the recording at your workstation.

In addition to these functions you can delete a number of recordings at once by checking the box in the last but one column of those recordings and clicking .

If you've set the path the VDR's configuration files and have entries in VDR's reccmds.conf you can run those commands for the selected recording by selecting the wanted command in the select box locate next to Commands: and pressing the button.

Use to force reloading of VDR's recordings listing.

" msgstr "

ЗдеÑÑŒ Ð’Ñ‹ видите ÑпиÑок вÑех запиÑей, которые доÑтупны в VDR. Ð’ верхнем колонтитуле Ð’Ñ‹ можете увидеть общее и Ñвободное меÑто на жеÑтком диÑке VDR.

Этот ÑпиÑок показывает Вам неÑколько Ñведений о запиÑÑÑ…. Ð’Ñ‹ можете изменÑть Ñортировку, Ð½Ð°Ð¶Ð¸Ð¼Ð°Ñ Ð½Ð° заголовки Ñтолбцов. Ðад ÑпиÑком Ð’Ñ‹ видите путь навигации. ЕÑли Ð’Ñ‹ хотите увидеть Ñодержание ранее поÑещенного каталога, то нажмите проÑто на название каталога в Ñтом пути.

ÐšÐ°Ð¶Ð´Ð°Ñ Ñтрока Ñодержит Ñледущую информацию:

Дата
Дата когда была произведена запиÑÑŒ. Ð’ Ñлучае каталога здеÑÑŒ показываетÑÑ ÐºÐ¾Ð»Ð¸Ñ‡ÐµÑтво занеÑeнных запиÑей.
ВремÑ
Ð’Ñ€ÐµÐ¼Ñ ÐºÐ¾Ð³Ð´Ð° была произведена запиÑÑŒ. Ð’ Ñлучае каталога здеÑÑŒ показываетÑÑ ÐºÐ¾Ð»Ð¸Ñ‡ÐµÑтво новых запиÑей в Ñтом каталоге.
Ðазвание
Ðазвание запиÑи или каталога. Ðажмите на него, чтобы увидеть резюме запиÑи или, чтобы перейти в каталог.
Переименовывать ()
Переименовать запиÑÑŒ.

Внимание:

Это функционирует только, еÑли VDR понимает SVDRPort-команду RENR. Это не ÑодержитÑÑ Ð² Ñтандартном VDR, но может добавлÑтьÑÑ Ð¿Ð°Ñ‚Ñ‡ÐµÐ¼. vdr-aio21_svdrprename.patch и enAIO-v2.2+ предлагают Ñту команду.
УдалÑть (\"delete\")
Удаление запиÑи.
ТранÑлировать (\"stream\")
Эта колонка показываетÑÑ Ñ‚Ð¾Ð»ÑŒÐºÐ¾, еÑли Ð’Ñ‹ активировали и откoнфигурировали ТранÑлировать запиÑи на Ñтранице КонфигурациÑ. Потом Ð’Ñ‹ можете проÑматривать запиÑи на вашем компьютере.

Дополнительно к Ñтим функциÑм Ð’Ñ‹ можете удалÑть неÑколько запиÑей одновременно, уÑтановив галочку в предпоÑледнем Ñтолбце Ñтих запиÑей и щeлкнув затем на кнопку .

ЕÑли Ð’Ñ‹ указали путь к конфигурационным файлам VDR и там еÑть файл reccmds.conf, тогда Ð’Ñ‹ можете запуÑкать занеÑeнные там команды Ð´Ð»Ñ Ð²Ñ‹Ð±Ñ€Ð°Ð½Ð½Ñ‹Ñ… запиÑей. Ð”Ð»Ñ Ñтого выберете желаемую команду возле Команды: и нажмите на .

Кнопкой Ð’Ñ‹ можете перезагрузить ÑпиÑок запиÑей VDR.

" msgid "

Here you will find a listing of timers known to VDR.

On top you will find a chart showing a day's timers graphically. This provides an quick overview on what's going on at the specified day and helps you in finding conflicting timers. Moving the mouse cursor above any timer box will display a tooltip containing the timer's title, priority, lifetime and duration.

Below the chart you'll find the timers list showing you some information on the timers. You can change the list's sorting by clicking the columns heading.

For each timer you have the following options:

Set its state
By clicking on \"Yes\", \"No\", \"VPS\" or \"Auto\" in the \"Active\" column.
Quickly view its priority and lifetime
By pointing the mouse cursor to the timer's title.
View its EPG entry
Timers that have set AutoTimer Checking to \"Transmission Identification\" will show you the corresponding EPG entry if you click on the timer's title.
Edit the timer
You can edit a timer by clicking \"edit\".
Delete the timer
To delete a timer you click \"delete\".

Each timer's state is indicated by differently coloured boxes (in the chart view) or images (in the list view):
    / \"on\" Timer is OK and will record.
    / \"problem\" Timer conflicts with other timers. That's not critical, as long as you have enough DVB cards for the parallel recordings.
    / \"impossible\" Timer is critical and will most likely not record.
    / \"inactive\" Timer is not active.

In addition to these functions you can add a new timer by clicking at the top and you can delete a number of timers at once by checking the box in the last column of those timers and clicking .

You can and selected timers.

" msgstr "

ЗдеÑÑŒ Ð’Ñ‹ найдeте ÑпиÑок вÑех таймеров, которые знает VDR.

Ð’ верхней чаÑти Ð’Ñ‹ найдeте графичеÑкое предÑтавление таймеров на один день. Это ÑпоÑобÑтвует быÑтрому обзору того, что было запрограммировано в один день и помогает Вам в раÑпознавании конфликтующих таймеров. ЕÑли Ð’Ñ‹ наведЈте курÑором на цветную облаÑть, Ð’Ñ‹ узнаете его название, приоритет, Ñрок Ñ…Ñ€Ð°Ð½ÐµÐ½Ð¸Ñ Ð¸ продолжительноÑть.

Ðиже графичеÑкого ÑƒÐ²ÐµÐ´Ð¾Ð¼Ð»ÐµÐ½Ð¸Ñ Ð’Ñ‹ видите ÑпиÑок запрограммированных таймеров. Ð’Ñ‹ можете изменить Ñортировку ÑпиÑка, нажав на желаемую надпиÑÑŒ колонки.

Ð”Ð»Ñ ÐºÐ°Ð¶Ð´Ð¾Ð³Ð¾ таймера Ð’Ñ‹ имеете Ñледующие возможноÑти:

Изменение ÑоÑтоÑниÑ
Это проиÑходит щелканием кнопкой мыши на \"Да\", \"Ðет\", \"VPS\" или \"Ðвто\" в Ñтолбце \"Ðктивный\".
БыÑтрое уведомление его приоритета и Ñрока хранениÑ
Ð”Ð»Ñ Ñтого нужно навеÑти курÑор мышки на название таймера.
Показ его EPG-запиÑи
Таймеры у которых в опции \"Опознавание передачи\" можно увидеть EPG-запиÑÑŒ, щЈлкнув курÑором на название таймера.
Ð ÐµÐ´Ð°ÐºÑ‚Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ñ‚Ð°Ð¹Ð¼ÐµÑ€Ð°
Ð’Ñ‹ можете редактировать таймер, щЈлкнув курÑором на \"edit\".
Удаление таймера
Ð”Ð»Ñ ÑƒÐ´Ð°Ð»ÐµÐ½Ð¸Ñ Ñ‚Ð°Ð¹Ð¼ÐµÑ€Ð° нажмите на .

Ð¡Ñ‚Ð°Ñ‚ÑƒÑ ÐºÐ°Ð¶Ð´Ð¾Ð³Ð¾ таймера показываетÑÑ Ð¾Ð¿Ñ€ÐµÐ´ÐµÐ»ÐµÐ½Ð½Ñ‹Ð¼ цветом:
    / \"on\" Таймер в порÑдке и будет запиÑан.
    / \"problem\" Таймер ÐºÐ¾Ð½Ñ„Ð»Ð¸ÐºÑ‚ÑƒÐµÑ‚Ñ Ð´Ñ€ÑƒÐ³Ð¸Ð¼Ð¸ таймерами.Это не Ñтрашно, еÑли имеетÑÑ Ð´Ð¾Ñтаточно DVB-карт Ð´Ð»Ñ Ð¿Ð°Ñ€Ð°Ð»Ð»ÐµÐ»ÑŒÐ½Ñ‹Ñ… запиÑей.
    / \"impossible\" Таймер критичеÑкий и Ñкорее вÑего не будет запиÑан.
    / \"inactive\" Таймер не активен.

Дополнительно к Ñтим функциÑм Ð’Ñ‹ можете запрограммироватьновый таймер, нажав курÑором на .Ð’ нижнем крае Ñкрана Ð’Ñ‹ найдЈте кнопку , тем Ñамым будут удалены вÑе выбранные Вами таймеры.

Вы можете также активироватьили деактивировать выбранные Вами таймеры.

" msgid "

Here you can edit a timer's settings.

" msgstr "

ЗдеÑÑŒ Ð’Ñ‹ можете редактировать уÑтановки таймера.

" msgid "Timer Active:" msgstr "Ðктивный таймер:" msgid "Activate or deactivate this timer. Deactivated timers are still stored in the timer list so that they can be activated again, but they do not record anything meanwhile." msgstr "Ðктивирование и деактивирование таймера. Деактивированные таймеры будут веÑтиÑÑŒ дальше в ÑпиÑке имеющийхÑÑ Ð² раÑпорÑжении таймеров так, что их можно активировать Ñнова.Между тем Ð’Ñ‹ ничто не запиÑываете." msgid "AutoTimer Checking:" msgstr "ÐвтоматичеÑÐºÐ°Ñ Ð¿Ñ€Ð¾Ð²ÐµÑ€ÐºÐ° таймера:" msgid "Depending on how this timer has been programmed you have up to three possible settings:" msgstr "Ð’ завиÑимоÑти от того как таймер программировалÑÑ Ð’Ñ‹ имеете на выбор 3 варианта:" msgid "Transmission Identification" msgstr "Идентификатор передачи" msgid "Monitor this timer using the identification provided in the EPG. Please note that this only works if the provided identification is a fix and unique value! This option is not available with timers programmed in VDR." msgstr "Таймер контролируетÑÑ Ð¿Ð¾ÑредÑтвом идентификации, ÐºÐ¾Ñ‚Ð¾Ñ€Ð°Ñ ÑодержитÑÑ Ð² EPG. ПожалуйÑта, обратите внимание, что Ñто работает только в Ñлучае, еÑли идентификации в EPG Ñ‚Ð²ÐµÑ€Ð´Ð°Ñ Ð¸ однозначнаÑ! Эта Ð¾Ð¿Ñ†Ð¸Ñ Ð½ÐµÐ´Ð¾Ñтупна, еÑли таймер программировалÑÑ Ð² VDR." msgid "Time" msgstr "ВремÑ" msgid "Monitor this timer using the start and stop time." msgstr "Таймер контролируетÑÑ Ð¿Ð¾ÑредÑтвом его времени запуÑка и оÑтановки." msgid "off" msgstr "выкл." msgid "Do not monitor this timer." msgstr "Таймер не контролируетÑÑ." msgid "The channel to record." msgstr "ЗапиÑываемый канал." msgid "Day Of Recording:" msgstr "День запиÑи:" msgid "The day when the timer should get active. You can enter the day in two formats:
  • Two digits (DD). This will use the current month and year.
  • ISO norm (YYYY-MM-DD). Program your timers as far in the future as you like.
In case you want to program a repeating timer you can use the seven checkboxes below the text field. Check the box for each day you want the timer to get active." msgstr "День, в который таймер должен Ñработать. День может вводитьÑÑ Ð² 2 форматах:
  • 2 цифры (TT)(при Ñтом иÑпользуетÑÑ Ñ‚ÐµÐºÑƒÑ‰Ð¸Ðµ меÑÑц и год) или
  • ISO-norm (JJJJ-MM-TT)(в Ñтом варианте Ð’Ñ‹ можете запрограммировать таймер на любой день в будущем).
ЕÑли Ð’Ñ‹ хотите запрограммировать повторÑющиеÑÑ Ñ‚Ð°Ð¹Ð¼ÐµÑ€Ñ‹, тогда Ð’Ñ‹ можете применить 7 кнопок, которые находÑÑ‚ÑÑ Ð¿Ð¾Ð´ текÑтовым полем. ПроÑто выделите поле Ñ Ð½Ð°Ð·Ð²Ð°Ð½Ð¸ÐµÐ¼ Ð´Ð½Ñ Ð½ÐµÐ´ÐµÐ»Ð¸, по которым таймер должен Ñрабатывать." msgid "Start Time:" msgstr "Ðачало:" msgid "This is the time when the timer should start recording. The first text field is for \"hour\", the second for \"minute\"." msgstr "Это - Ð²Ñ€ÐµÐ¼Ñ Ð½Ð°Ñ‡Ð°Ð»Ð° запиÑи. Первое текÑтовое поле Ð´Ð»Ñ Ñ‡Ð°Ñов, второе Ð´Ð»Ñ Ð¼Ð¸Ð½ÑƒÑ‚." msgid "End Time:" msgstr "Конец:" msgid "This is the time when the timer should stop recording. The first text field is for \"hour\", the second for \"minute\"." msgstr "Ð’Ñ€ÐµÐ¼Ñ ÐºÐ¾Ð½Ñ†Ð° запиÑи. Первое текÑтовое поле Ð´Ð»Ñ Ñ‡Ð°Ñов, второе Ð´Ð»Ñ Ð¼Ð¸Ð½ÑƒÑ‚." msgid "Title of Recording:" msgstr "Ðазвание запиÑи:" msgid "The file name this timer will give to a recording. If the name shall contain subdirectories, these have to be delimited by '~' (since the '/' character may be part of a regular programme name).

The special keywords TITLE and EPISODE, if present, will be replaced by the title and episode information from the EPG data at the time of recording (if that data is available). If at the time of recording either of these cannot be determined, TITLE will default to the channel name, and EPISODE will default to a blank." msgstr "Ð˜Ð¼Ñ Ñ„Ð°Ð¹Ð»Ð°, которое даÑÑ‚ Ñтот таймер запиÑи. ЕÑли указываютÑÑ Ð¿Ð¾Ð´ÐºÐ°Ñ‚Ð°Ð»Ð¾Ð³Ð¸, тогда они должны быть разделены Ñ '~', так как '/' может быть чаÑтью Ð½Ð°Ð·Ð²Ð°Ð½Ð¸Ñ Ñ€ÐµÐ³ÑƒÐ»Ñрной передачи.

Ключевые Ñлова TITLE и EPISODE заменÑÑŽÑ‚ÑÑ, еÑли такие еÑть в наличии, информацией заголовка или подзаголовка взÑтой из EPG во Ð²Ñ€ÐµÐ¼Ñ Ð·Ð°Ð¿Ð¸Ñи, еÑли Ñти данные еÑть в EPG. ЕÑли Ñти ÑÐ²ÐµÐ´ÐµÐ½Ð¸Ñ Ð±ÑƒÐ´ÑƒÑ‚ недоÑтупны, то Ð´Ð»Ñ TITLE будет иÑползоватьÑÑ Ð½Ð°Ð·Ð²Ð°Ð½Ð¸Ðµ канала, а Ð´Ð»Ñ EPISODE иÑпользуетÑÑ Ð¿Ñ€Ð¾Ð±ÐµÐ»." msgid "Summary:" msgstr "Ð¡Ð²Ð¾Ð´Ð½Ð°Ñ Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ:" msgid "Arbitrary text that describes the recording made by this timer. If this field is not empty, its contents will be written into the summary.vdr or info.vdr file of the recording." msgstr "Любой текÑÑ‚, который опиÑывает Ñоздаваемую Ñтим таймером запиÑÑŒ. ЕÑли Ñто поле заполнено, то текÑÑ‚ будет запиÑан в summary.vdr или в info.vdr запиÑи." msgid "Your Browser does not support frames!" msgstr "Ваш Броузер не поддерживает фреймы!" msgid "What's On Now?" msgstr "Что идет ÑейчаÑ?" msgid "Playing Today?" msgstr "Что будет ÑегоднÑ?" msgid "Remote Control" msgstr "Пульт ДУ" msgid "Watch TV" msgstr "Телевизор" msgid "Commands" msgstr "Команды" msgid "Search" msgstr "ПоиÑк" msgid "Authorization Required" msgstr "ТребуетÑÑ Ð°Ð²Ñ‚Ð¾Ñ€Ð¸Ð·Ð°Ñ†Ð¸Ñ" msgid "This server could not verify that you are authorized to access the document requested. Either you supplied the wrong credentials (e.g. bad password), or your browser doesn't understand how to supply the credentials required." msgstr "Сервер не может подтвердить, что Ð’Ñ‹ имеете право проÑмотра данного документа.Ð’Ñ‹ или ввели неправильные данные или ваш броузер не может их передать" msgid "VPS" msgstr "VPS" msgid "close" msgstr "закрыть" msgid "view" msgstr "переключить" msgid "search" msgstr "ПовторениÑ" #, fuzzy msgid "edit" msgstr "Редактировать" msgid "Length" msgstr "" msgid "Video tracks:" msgstr "Видео дорожки" msgid "Audio tracks:" msgstr "Ðудио дорожки" msgid "Subtitles:" msgstr "Субтитры:" #, fuzzy msgid "Video tracks" msgstr "Видео дорожки" #, fuzzy msgid "Audio tracks" msgstr "Ðудио дорожки" msgid "TV select" msgstr "TV переключить" msgid "Stream" msgstr "Stream" #, fuzzy msgid "Channel group:" msgstr "Группа каналов:" msgid "Go!" msgstr "Стартовать!" msgid "Search for other show times" msgstr "ИÑкать повторениÑ" msgid "No Information" msgstr "Ðет информации" msgid "No EPG information available" msgstr "Ðет EPG информации" msgid "Playing Today" msgstr "Что будет ÑегоднÑ?" msgid "starting at" msgstr "Ðачать в" msgid "What's on:" msgstr "Что ÑейчаÑ:" msgid "at" msgstr "в" msgid "now" msgstr "ÑейчаÑ" msgid "to" msgstr "до" msgid "Duration:" msgstr "ПродолжительноÑть:" msgid "min" msgstr "мин" msgid "at:" msgstr "в:" msgid "You need JavaScript to use the timeline!" msgstr "Вам нужен JavaScript Ð´Ð»Ñ Ð¸ÑÐ¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ timeline!" msgid "Rename Recording" msgstr "Переименовать запиÑÑŒ" msgid "Original Name of Recording:" msgstr "Старое название запиÑи:" msgid "New Name of Recording:" msgstr "Ðовое название запиÑи:" msgid "Subtitle:" msgstr "Подзаголовок:" msgid "Rename" msgstr "Переименовать" msgid "Total:" msgstr "Ð’Ñего:" msgid "h" msgstr "h" msgid "Free:" msgstr "Свободно:" msgid "Date" msgstr "Дата" msgid "Total" msgstr "Ð’Ñего" msgid "New" msgstr "Ðовый" msgid "Play" msgstr "ВоÑпроизведение" msgid "Cut" msgstr "Срез" msgid "Delete recording?" msgstr "Удалить запиÑÑŒ?" msgid "Refresh" msgstr "Обновить" msgid "Commands:" msgstr "Команды:" msgid "Really run this command?" msgstr "ДейÑтвительно выполнить команду?" msgid "stream all recordings" msgstr "" msgid "Delete Selected Recordings" msgstr "Удалить выбранные запиÑи" msgid "Delete all selected recordings?" msgstr "Удалить вÑе выбранные запиÑи?" msgid "No recordings available" msgstr "Ðет запиÑей" msgid "Transponder:" msgstr "ТранÑпондер:" msgid "CA-System:" msgstr "CA-System:" msgid "New Timer" msgstr "Ðовый таймер" msgid "Edit timer status?" msgstr "Изменить ÑÑ‚Ð°Ñ‚ÑƒÑ Ñ‚Ð°Ð¹Ð¼ÐµÑ€Ð°?" msgid "This timer is inactive!" msgstr "Эта запиÑÑŒ деактивирована!" msgid "This timer is impossible!" msgstr "ЗапиÑÑŒ по Ñтому таймеру невозможна!" msgid "No more timers on other transponders possible!" msgstr "Дальнейшие запиÑи на других транÑпондерах невозможны!" msgid "Timer OK." msgstr "ЗапиÑÑŒ по Ñтому таймеру возможна." msgid "Auto" msgstr "Ðвто" msgid "activate" msgstr "Ðктивирует" msgid "inactivate" msgstr "Деактивирует" msgid "selected timers" msgstr "выбранные таймеры" msgid "Delete Selected Timers" msgstr "Удалить выбранные таймеры" msgid "No timers defined!" msgstr "Ðет таймеров!" msgid "Create New Timer" msgstr "Создать новый таймер" msgid "Buffer:" msgstr "Буфер:" msgid "Use VPS:" msgstr "ИÑпользовать VPS:" msgid "readonly" msgstr "не изменÑемо" msgid "Timer has been set by AutoTimer pattern:" msgstr "Таймер выÑтавлен Ðвтотаймером:" msgid "TV" msgstr "TV" msgid "Interval:" msgstr "Интервал:" msgid "sec." msgstr "Ñек." msgid "G" msgstr "G" msgid "Grab the picture!" msgstr "Создать Ñкриншот!" msgid "Size:" msgstr "Размер:" msgid "Open in separate window" msgstr "Открыть в отдельном окне" msgid "VDR Commands" msgstr "VDR Команды:" msgid "Export channels as playlist:" msgstr "" msgid "Number of lines to show:" msgstr "КоличеÑтво показываемых Ñтрок:" msgid "unlimited" msgstr "без ограничений" msgid "SVDRP commands:" msgstr "SVDRP Команды:" msgid "Commands defined in commands.conf:" msgstr "Комманды из commands.conf:" msgid "Output" msgstr "Вывод" msgid "What's your VDR hostname (e.g video.intra.net)?" msgstr "Ð˜Ð¼Ñ Ñ…Ð¾Ñта VDR (например, video.intra.net)?" msgid "On which port does VDR listen to SVDRP queries?" msgstr "Какой порт иÑпользует VDR Ð´Ð»Ñ Ð·Ð°Ð¿Ñ€Ð¾Ñов SVDRP?" msgid "On which address should VDRAdmin-AM listen (0.0.0.0 for any)?" msgstr "По какому адреÑу VDRAdmin-AM должен ждать ÑÐ¾ÐµÐ´Ð¸Ð½ÐµÐ½Ð¸Ñ (0.0.0.0 повÑем)? " msgid "On which port should VDRAdmin-AM listen?" msgstr "Какой номер порта должен иÑпользовать VDRAdmin-AM?" msgid "Username?" msgstr "Ð˜Ð¼Ñ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ?" msgid "Password?" msgstr "Пароль?" msgid "Where are your recordings stored?" msgstr "По какому адреÑу находÑÑ‚ÑÑ Ð·Ð°Ð¿Ð¸Ñи?" msgid "Where are your VDR's configuration files located?" msgstr "По какому адреÑу находÑÑ‚ÑÑ ÐºÐ¾Ð½Ñ„Ð¸Ð³ÑƒÑ€Ð°Ñ†Ð¸Ð¾Ð½Ð½Ñ‹Ðµ файлы VDR?" msgid "Config file written successfully." msgstr "Файл конфигурации уÑпешно запиÑан." #, perl-format msgid "%s %s started with pid %d." msgstr "%s %s был запущен Ñ PID-ом %d." msgid "Not found" msgstr "Ðе найдено" msgid "The requested URL was not found on this server!" msgstr "Затребованный URL не был найден на Ñтом Ñервере!" msgid "Forbidden" msgstr "Запрещено" msgid "You don't have permission to access this function!" msgstr "У Ð²Ð°Ñ Ð½ÐµÐ´Ð¾Ñтаточно прав Ð´Ð»Ñ Ð²Ñ‹Ð·Ð¾Ð²Ð° Ñтой функции!" #, fuzzy msgid "All channels" msgstr "Телегид" #, fuzzy msgid "Selected channels" msgstr "Выбрать вÑе или ничего" #, fuzzy msgid "TV channels" msgstr "Телегид" #, fuzzy msgid "Radio channels" msgstr "Телегид" #, perl-format msgid "Access to file \"%s\" denied!" msgstr "Ð’ доÑтупе к файлу \"%s\" отказанно!" #, perl-format msgid "The URL \"%s\" was not found on this server!" msgstr "URL \"%s\" не был найден на Ñтом Ñервере!" #, fuzzy msgid "Your favorites" msgstr "Показать фавориты" #, fuzzy msgid "Search results" msgstr "СпрÑтать результаты" #, fuzzy msgid "Default" msgstr "Удалить" msgid "--- no timer ---" msgstr "--- нет таймера ---" msgid "unknown" msgstr "неизвеÑтно" msgid "none" msgstr "нет" #, perl-format msgid "Can't open file \"%s\"!" msgstr "Ðе может открыть файл \"%s\"!" #, perl-format msgid "Can't connect to VDR at %s:%s: %s

Please check if VDR is running and if VDR's svdrphosts.conf is configured correctly." msgstr "Ðе могу ÑоединитьÑÑ Ñ VDR %s:%s: %s

Проконтролируйте VDR и svdrphosts.conf" #, perl-format msgid "Error while sending command to VDR at %s" msgstr "Ошибка при отправлении команды к %s" msgid "Internal error:" msgstr "ВнутреннÑÑ Ð¾ÑˆÐ¸Ð±ÐºÐ°:" msgid "Lookup movie in the Internet-Movie-Database (IMDb)" msgstr "ИÑкать фильм в Internet-Movie-Database (IMDb)" msgid "Can't find EPG entry!" msgstr "Ðет EPG запиÑей!" msgid "Playing Tomorrow" msgstr "Программа на завтра" #, perl-format msgid "Playing on the %s" msgstr "ВоÑпроизвеÑти %s." msgid "next" msgstr "Ñлед." msgid "What's on after" msgstr "Что потом" msgid "What's on at" msgstr "Что в:" msgid "Suitable matches for:" msgstr "Результаты поиÑка длÑ" msgid "short view" msgstr "ÑÐ¾ÐºÑ€Ð°Ñ‰ÐµÐ½Ð½Ð°Ñ Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ" msgid "long view" msgstr "РаÑÑˆÐ¸Ñ€ÐµÐ½Ð½Ð°Ñ Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ" msgid "Schedule" msgstr "РаÑпиÑание" #, perl-format msgid "Can't write configuration file %s! Reason: %s" msgstr "" #, perl-format msgid "Configuration file %s not writable! Configuration won't be saved!" msgstr "" msgid "Timers" msgstr "Таймеры" msgid "System default" msgstr "СиÑтемный Ñтандарт" vdradmin-am-3.6.13/po/vdradmin.pot000066400000000000000000001172451443716113400167670ustar00rootroot00000000000000# Copyright (C) Andreas Mair # This file is distributed under the same license as the VDRAdmin-AM package. # # TRANSLATOR , YEAR # # # Translators, if you are not familiar with the PO format, gettext # documentation is worth reading, especially sections dedicated to # this format, e.g. by running: # info -n '(gettext)PO Files' # info -n '(gettext)Header Entry' # # Some information specific to po-debconf are available at # /usr/share/doc/po-debconf/README-trans # or http://www.debian.org/intl/l10n/po-debconf/README-trans # # Developers do not need to manually edit POT or PO files. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: VDRAdmin-AM 3.6.9\n" "Report-Msgid-Bugs-To: Andreas Mair \n" "POT-Creation-Date: 2012-07-09 12:23+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" msgid "About" msgstr "" msgid "License" msgstr "" msgid "Authors" msgstr "" msgid "Current author (VDRAdmin-AM branch):" msgstr "" msgid "Original author (VDRAdmin):" msgstr "" msgid "Translation Team" msgstr "" msgid "English:" msgstr "" msgid "German:" msgstr "" msgid "French:" msgstr "" msgid "At the moment unmaintained, former translations by:" msgstr "" msgid "Spanish:" msgstr "" msgid "Finnish:" msgstr "" msgid "Dutch:" msgstr "" msgid "Russian:" msgstr "" msgid "Czech:" msgstr "" msgid "Italian:" msgstr "" msgid "Hungarian:" msgstr "" msgid "Information" msgstr "" msgid "VDRAdmin-AM version:" msgstr "" msgid "VDR version:" msgstr "" msgid "Supported features in VDR:" msgstr "" msgid "EPGSearch" msgstr "" msgid "EPGSearch Plugin" msgstr "" msgid "LiveTV Streaming" msgstr "" msgid "Streamdev Plugin" msgstr "" msgid "Xineliboutput Plugin" msgstr "" msgid "Rename Recordings (Liemikuutio Patch)" msgstr "" msgid "Getting Help and Reporting Bugs" msgstr "" msgid "If you need help please first try to use the online help you'll find on some pages. You can access it by clicking \"\"." msgstr "" msgid "If this doesn't provide the information you need you can try to get help at VDR-Portal if you understand German language. Please use the announcement thread if possible, search for:" msgstr "" msgid "If you think you have found a bug please check that it's a new one and report it in the VDRAdmin-AM BugTracking system." msgstr "" msgid "AutoTimer" msgstr "" msgid "Priority:" msgstr "" msgid "Lifetime:" msgstr "" msgid "New AutoTimer" msgstr "" msgid "Help" msgstr "" msgid "Active" msgstr "" msgid "Channel" msgstr "" msgid "Start" msgstr "" msgid "Stop" msgstr "" msgid "Name" msgstr "" msgid "Select all/none" msgstr "" msgid "Yes" msgstr "" msgid "No" msgstr "" msgid "Edit" msgstr "" msgid "Delete timer?" msgstr "" msgid "Delete" msgstr "" msgid "Force Update" msgstr "" msgid "Delete Selected AutoTimers" msgstr "" msgid "Delete all selected timers?" msgstr "" msgid "No AutoTimers defined!" msgstr "" msgid "Add New AutoTimer" msgstr "" msgid "Edit AutoTimer" msgstr "" msgid "AutoTimer Active:" msgstr "" msgid "oneshot" msgstr "" msgid "Search Patterns:" msgstr "" msgid "Search in:" msgstr "" msgid "Title" msgstr "" msgid "Subtitle" msgstr "" msgid "Description" msgstr "" msgid "Search only on these days:" msgstr "" msgid "Monday" msgstr "" msgid "Tuesday" msgstr "" msgid "Wednesday" msgstr "" msgid "Thursday" msgstr "" msgid "Friday" msgstr "" msgid "Saturday" msgstr "" msgid "Sunday" msgstr "" msgid "Channel:" msgstr "" msgid "all" msgstr "" msgid "Starts After:" msgstr "" msgid "o'clock" msgstr "" msgid "Ends Before:" msgstr "" msgid "Override Start/Stop Margins:" msgstr "" msgid "Time Margin at Start:" msgstr "" msgid "minutes" msgstr "" msgid "Time Margin at Stop:" msgstr "" msgid "Episode:" msgstr "" msgid "Remember programmed timers:" msgstr "" msgid "Directory:" msgstr "" msgid "Save" msgstr "" msgid "Test" msgstr "" msgid "Cancel" msgstr "" msgid "Broadcasted" msgstr "" msgid "Stored in" msgstr "" msgid "No matches found!" msgstr "" msgid "Configuration" msgstr "" msgid "General Settings" msgstr "" msgid "Template:" msgstr "" msgid "Skin:" msgstr "" msgid "Login Page:" msgstr "" msgid "Number of channels to use:" msgstr "" msgid "Local net (no login required):" msgstr "" msgid "Language:" msgstr "" msgid "Save settings on exit:" msgstr "" msgid "VDR" msgstr "" msgid "Number of DVB cards:" msgstr "" msgid "Path to recordings:" msgstr "" msgid "Path to configuration files:" msgstr "" msgid "Path to EPG images:" msgstr "" msgid "Identification" msgstr "" msgid "Username:" msgstr "" msgid "Password:" msgstr "" msgid "Guest Account:" msgstr "" msgid "Guest Username:" msgstr "" msgid "Guest Password:" msgstr "" msgid "Timeline" msgstr "" msgid "Hours:" msgstr "" msgid "Times:" msgstr "" msgid "Also used for other EPG views!" msgstr "" msgid "Tooltips:" msgstr "" msgid "Electronic Program Guide (EPG)" msgstr "" msgid "Day begins at:" msgstr "" msgid "Show Subtitle:" msgstr "" msgid "Show Summary:" msgstr "" msgid "Active:" msgstr "" msgid "Send email after programming timer:" msgstr "" msgid "Send email as:" msgstr "" msgid "Send email to:" msgstr "" msgid "Mail server:" msgstr "" msgid "SMTPAuth user:" msgstr "" msgid "SMTPAuth password:" msgstr "" msgid "Track schedule changes by:" msgstr "" msgid "Broadcast time" msgstr "" msgid "Event id" msgstr "" msgid "Timer" msgstr "" msgid "Tooltips in timeline:" msgstr "" msgid "Tooltips in list:" msgstr "" msgid "Streaming" msgstr "" msgid "Live Streaming:" msgstr "" msgid "HTTP Port of Streamdev (also possible 3000/ts):" msgstr "" msgid "HTTP Port of Xineliboutput (e.g. 37890):" msgstr "" msgid "Recordings Streaming:" msgstr "" msgid "Path to VDR Recordings on your workstation:" msgstr "" msgid "MIME type for live streaming:" msgstr "" msgid "Suffix for live streaming:" msgstr "" msgid "MIME type for recordings streaming:" msgstr "" msgid "Suffix for recordings streaming:" msgstr "" msgid "Bandwidth of Streams:" msgstr "" msgid "External Search" msgstr "" msgid "URL:" msgstr "" msgid "Title:" msgstr "" msgid "User-defined search:" msgstr "" msgid "Expert" msgstr "" msgid "Update EPG data in background:" msgstr "" msgid "Update EPG every:" msgstr "" msgid "Channel Selections" msgstr "" msgid "Show channels without EPG information:" msgstr "" msgid "In \"AutoTimer\"?" msgstr "" msgid "Apply" msgstr "" msgid "EPG Search Blacklists" msgstr "" msgid "New Blacklist" msgstr "" msgid "Search pattern" msgstr "" msgid "From" msgstr "" msgid "To" msgstr "" msgid "Delete blacklist?" msgstr "" msgid "Delete Selected Blacklists" msgstr "" msgid "Delete all selected blacklists?" msgstr "" msgid "EPG search" msgstr "" msgid "EPG Search" msgstr "" msgid "Use template" msgstr "" msgid "New Search" msgstr "" msgid "Edit Template" msgstr "" msgid "Settings" msgstr "" msgid "Action" msgstr "" msgid "Find" msgstr "" msgid "Show Favorites" msgstr "" msgid "Delete Selected Searches" msgstr "" msgid "Delete all selected searches?" msgstr "" msgid "Execute Selected Searches" msgstr "" msgid "Duration" msgstr "" msgid "More Information" msgstr "" msgid "Channels" msgstr "" msgid "Record" msgstr "" msgid "Add New Blacklist" msgstr "" msgid "Edit Blacklist" msgstr "" msgid "Add New Template" msgstr "" msgid "Add New Search" msgstr "" msgid "Edit Search" msgstr "" msgid "Small search pattern.\\nDo you really want to use it?" msgstr "" msgid "You didn't select at least one of\\ntitle, subtitle or description.\\nDo you really want to use this search?" msgstr "" msgid "Hide results" msgstr "" msgid "Name:" msgstr "" msgid "Search Term:" msgstr "" msgid "Search Mode:" msgstr "" msgid "phrase" msgstr "" msgid "all words" msgstr "" msgid "at least one word" msgstr "" msgid "match exactly" msgstr "" msgid "regular expression" msgstr "" msgid "fuzzy" msgstr "" msgid "Tolerance for \"fuzzy\":" msgstr "" msgid "Match Case:" msgstr "" msgid "Use extended EPG info:" msgstr "" msgid "Ignore missing categories?" msgstr "" msgid "Use Channel:" msgstr "" msgid "no" msgstr "" msgid "interval" msgstr "" msgid "channel group" msgstr "" msgid "only FTA" msgstr "" msgid "Range:" msgstr "" msgid "Channel Group:" msgstr "" msgid "Use Time:" msgstr "" msgid "Start After:" msgstr "" msgid "Start Before:" msgstr "" msgid "Use Duration:" msgstr "" msgid "Min. Duration:" msgstr "" msgid "hh:mm" msgstr "" msgid "Max. Duration:" msgstr "" msgid "Use Day of Week:" msgstr "" msgid "Use Blacklists:" msgstr "" msgid "selection" msgstr "" msgid "Use in Favorites Menu:" msgstr "" msgid "Use as Search Timer:" msgstr "" msgid "yes" msgstr "" msgid "user-defined" msgstr "" msgid "record" msgstr "" msgid "announce by OSD" msgstr "" msgid "switch only" msgstr "" msgid "announce and switch" msgstr "" msgid "announce by mail" msgstr "" msgid "First day:" msgstr "" msgid "Last day:" msgstr "" msgid "Auto delete:" msgstr "" msgid "count recordings" msgstr "" msgid "count days" msgstr "" msgid "After ... recordings:" msgstr "" msgid "After ... days after first recording:" msgstr "" msgid "Settings for action \"record\"" msgstr "" msgid "Series Recording:" msgstr "" msgid "Delete Recordings After ... Days:" msgstr "" msgid "Keep ... Recordings:" msgstr "" msgid "Pause, when ... recordings exist:" msgstr "" msgid "Avoid Repeats:" msgstr "" msgid "Allowed Repeats:" msgstr "" msgid "Only Repeats Within ... Days:" msgstr "" msgid "Compare:" msgstr "" msgid "Minimal match of description in %:" msgstr "" msgid "VPS:" msgstr "" msgid "Settings for action \"switch only\"" msgstr "" msgid "Switch ... Minutes Before Start:" msgstr "" msgid "Unmute sound:" msgstr "" msgid "Settings for action \"announce and switch\"" msgstr "" msgid "Ask ... Minutes Before Start:" msgstr "" msgid "Delete template" msgstr "" msgid "Delete this template?" msgstr "" msgid "Save as template" msgstr "" msgid "Run" msgstr "" msgid "Error!" msgstr "" msgid "

Here you will find a listing of automatic timers (AutoTimer) known to VDRAdmin-AM.

The list shows some information on AutoTimers. You can change the list's sorting by clicking the columns heading.

For each AutoTimer you have the following options:

Set its state
By clicking on \"Yes\" or \"No\" in the \"Active\" column to toggle the activity.
Quickly view its priority and lifetime
By pointing the mouse cursor to the AutoTimer's title.
Edit the AutoTimer
You can edit an AutoTimer by clicking \"edit\".
Delete the AutoTimer
To delete an AutoTimer you click \"delete\".

Each AutoTimer's state is indicated by differently coloured images:
\"on\" AutoTimer is OK and will automatically program matching broadcasts.
\"inactive\" AutoTimer is not active.

In addition to these functions you can add a new AutoTimer by clicking at the top and you can delete a number of AutoTimers at once by checking the box in the last column of those timers and clicking .

Click to force VDRAdmin-AM to reconnect to VDR, fetch the current EPG and check for matching AutoTimers.

" msgstr "" msgid "

Here you can edit an automatic timer's (AutoTimer) settings.

AutoTimer is a key feature of VDRAdmin-AM. An AutoTimer consists of one or more search terms and some other settings, that are looked for regularly in the Electronic Program Guide (EPG). On match AutoTimer adds a timer in VDR automatically for that broadcast. That's very comfortable for irregularly broadcasted series or movies you don't want to miss.

" msgstr "" msgid "Activate or deactivate this AutoTimer. Deactivated AutoTimers are still stored in the AutoTimer list so that they can be activated again, but they do not record anything meanwhile. Above that you can set this to \"oneshot\" so this AutoTimer only programs the (one!) next matching broadcast." msgstr "" msgid "Choosing the right search items decides whether only the wanted broadcasts or broadcasts having similar names or even nothing gets recorded.
Case doesn't matter, \"X-Files\" matches anything \"x-files\" will match. You can set multiple search items by separating them with spaces. Broadcasts will match only if they match all configured search items.
You'd better only use letters and numbers for search items, as the EPG often miss colons, brackets and other characters.
Experts can also use regular expressions, but you have to get needed information from the VDRAdmin-AM sources (undocumented feature).

You can exclude broadcasts so that they don't get recorded even if they would match an AutoTimer. Therefore you have to enter that titles into the file vdradmind.bl, one event a line. This file must be located in your VDRAdmin-AM's configuration folder. If this string is found either in the EPG's title or in title~subtitle, this event will not be programmed by AutoTimer. So you can disable complete episodes (for example when using \"Enterprise\" as blacklist string) or only one episode (when using \"Enterprise~Azati Prime\" as blacklist string)." msgstr "" msgid "Here you can define the EPG sections where VDRAdmin-AM should look for the search pattern." msgstr "" msgid "Use these checkboxes to limit searching for matching broadcasts to a set of weekdays." msgstr "" msgid "The channel to look for matching broadcasts or \"all\" to search in all known or wanted channels. You can define the wanted channels for AutoTimer in \"Configuration\"." msgstr "" msgid "A broadcast must start after the time entered here to match. The first text field is for \"hour\", the second for \"minute\"." msgstr "" msgid "A broadcast must end before the time entered here to match. The first text field is for \"hour\", the second for \"minute\"." msgstr "" msgid "Set this option to \"yes\" if all timers programed by this AutoTimer should have individual start/stop margins and enter the values in the next two text boxes." msgstr "" msgid "The number of minutes VDRAdmin-AM subtracts from the broadcast's start time found in the EPG." msgstr "" msgid "The number of minutes VDRAdmin-AM adds to the broadcast's stop time found in the EPG." msgstr "" msgid "An integer in the range 0...99, defining the priority of this timer and of recordings created by this timer. 0 represents the lowest value, 99 the highest. The priority is used to decide which timer shall be started in case there are two or more timers with the exact same start time. The first timer in the list with the highest priority will be used.

This value is also stored with the recording and is later used to decide which recording to remove from disk in order to free space for a new recording. If the disk runs full and a new recording needs more space, an existing recording with the lowest priority (and which has exceeded its guaranteed lifetime) will be removed.

If all available DVB cards are currently occupied, a timer with a higher priority will interrupt the timer with the lowest priority in order to start recording." msgstr "" msgid "The guaranteed lifetime (in days) of a recording created by this timer. 0 means that this recording may be automatically deleted at any time by a new recording with higher priority. 99 means that this recording will never be automatically deleted. Any number in the range 1...98 means that this recording may not be automatically deleted in favour of a new recording, until the given number of days since the start time of the recording has passed by." msgstr "" msgid "Check this box if you want VDRAdmin-AM to append the broadcast's EPG subtitle to the recording's file name." msgstr "" msgid "If you enable this VDRAdmin-AM will track timers it has already programmed automatically. This is useful if want to deactivate or delete timers that have been programmed automatically in the timers listing." msgstr "" msgid "The directory this AutoTimer will place the recordings in. If the name shall contain subdirectories, these have to be delimited by '~' (since the '/' character may be part of a regular programme name).
VDRAdmin-AM will append the matching broadcast's title and subtitle (if the \"Episode\" checkbox is marked) to the directory given here.

You can also use the following keywords that are replaced in the final file name by the values supplied by for example tvm2vdr:
  • %Title% - will become the title of the event.
  • %Subtitle% - will become the subtitle of the event.
  • %Director% - will become the director of the event.
  • %Date% - will become the date of the recording.
  • %Category% - will become the category of the event (Spielfilm/Serie/...).
  • %Genre% - will become the genre of the event (Drama/Krimi/..).
  • %Year% - will become the year of production.
  • %Country% - will become the country of production.
  • %Originaltitle% - will become the original title of the event.
  • %FSK% - will become the FSK from the event.
  • %Episode% - will become the episode's title of the event.
  • %Rating% - will become the rating of the event from the EPG provider.

Note:

If you use the above keywords it's in your own responsibility to supply the complete file name for the recordings! VDRAdmin-AM will not append anything to the resulting string." msgstr "" msgid "

Here you can change general settings and base settings for timers, AutoTimers, channel selection and streaming parameters.

" msgstr "" msgid "The skin you want to use." msgstr "" msgid "The page you want to see at first connect to VDRAdmin-AM." msgstr "" msgid "VDRAdmin-AM will load the given number of channels from VDR and present only those in any fields where channels can be selected. This also limits the EPG information VDRAdmin-AM will read so that you can use this to reduce VDRAdmin-AM's memory consumption and increase its performance. 0 turns this feature off and VDRAdmin-AM will use all available channels." msgstr "" msgid "Here you can specify subnets from which access to VDRAdmin-AM does not require logging in. For example: \"192.168.0.0/24\" will include any IP starting with \"192.168.0.\", \"192.168.0.123/32\" will only match \"192.168.0.123\". Multiple subnets can be specified by separating them with spaces or commas." msgstr "" msgid "Here you can set the localization VDRAdmin-AM should use." msgstr "" msgid "With this option the settings will be saved if VDRAdmin-AM exits. This will also save settings not available on the \"Configuration\" menu like interval and size in TV, sorting in the lists and current view in \"What's on now\"." msgstr "" msgid "Top" msgstr "" msgid "The number of DVB cards VDR can access. Depending on this value VDRAdmin-AM will calculate critical timers in the Timer menu." msgstr "" msgid "The path to VDR's recordings. It's used so that VDRAdmin-AM can locate the recordings when using Recordings Streaming and reccmds.conf in the Recordings menu." msgstr "" msgid "The path where VDR's configuration files are located. If this directory contains the file reccmds.conf its content is shown in a selectbox in the Recordings menu." msgstr "" msgid "The path where the EPG images are stored." msgstr "" msgid "The username for the main user, i.e. the user having the most privileges." msgstr "" msgid "The main user's password." msgstr "" msgid "If you want a user account having only limited privileges, this is for you. The guest user cannot modify anything, it's only allowed to view the EPG, timers, AutoTimers and recordings listings." msgstr "" msgid "The username for the guest user." msgstr "" msgid "The guest user's password." msgstr "" msgid "The number of hours to show in the timeline." msgstr "" msgid "A comma separated list of times in hh:mm format that appear in the selectbox placed at the top." msgstr "" msgid "Here you can (de-)activate the tooltips." msgstr "" msgid "The time after which events are shown on a new day. For example setting 03:00 means that today's schedule will include any event starting before 03:00 tomorrow. Applies only to the 'Playing Today?' list." msgstr "" msgid "Show the 'Subtitle' text for each event. Not all broadcasters use this field." msgstr "" msgid "Show the 'Summary' text for each event." msgstr "" msgid "Activate or deactivate the AutoTimer function." msgstr "" msgid "VDRAdmin-AM will send an email whenever an event matches an AutoTimer and a timer has been programmed if you enable this feature." msgstr "" msgid "Here you set the sending email address of the generated email." msgstr "" msgid "The email address the email is sent to." msgstr "" msgid "The outgoing mail server." msgstr "" msgid "If you need to authenticate yourself at the outgoing mail server, you have to supply the username and the password below. Leaving this field empty will disable SMTPAuth." msgstr "" msgid "The password for the SMTPAuth user." msgstr "" msgid "Here you can (de-)activate the tooltips in the timeline." msgstr "" msgid "Here you can (de-)activate the tooltips in the list." msgstr "" msgid "Add summary to new timers:" msgstr "" msgid "If you don't want VDRAdmin-AM to add the summary taken from EPG to new timers you can switch it off here." msgstr "" msgid "Enable or disable live streaming using the streamdev plugin. You also have to set the correct HTTP Port for Streamdev below." msgstr "" msgid "Here you have to set the port number your VDR's streamdev server listens for connections. Additionally you can also provide the stream type you like to use." msgstr "" msgid "Enable or disable streaming of recordings.
Well actually this is no real \"streaming\", but you have to setup your workstation so that it can access VDR's recordings. You can use for example Samba or NFS for this. VDRAdmin-AM simply generates a playlist that contains all parts of the recording and sends this to your browser. If your browser and media player are configured correctly you will see the recording on your workstation's display." msgstr "" msgid "This is the path where your workstation can access VDR's recordings. This depends on your VDR and workstation setup, for example \"\\\\vdr\\videos\" or \"V:\\\" (on Windows) or \"/mnt/videos\" (on Linux)." msgstr "" msgid "The MIME type to send when using live streaming. Defaults to \"video/x-mpegurl\"." msgstr "" msgid "The suffix to use for live streaming. Defaults to \"m3u\"." msgstr "" msgid "The MIME type to send when using recordings streaming. Defaults to \"video/x-mpegurl\"." msgstr "" msgid "The suffix to use for recordings streaming. Defaults to \"m3u\"." msgstr "" msgid "

Here you can define two external searches that you can access in the EPG views. You simply have to find the required URL and where the search pattern has to be located. %TITLE% will be substituted by the broadcast's EPG title.

" msgstr "" msgid "Some examples:" msgstr "" msgid "Please change the hostname to your local needs!" msgstr "" msgid "

This section is for experts only, i.e. you know what you are doing!

" msgstr "" msgid "If set to \"yes\" VDRAdmin-AM will periodically refresh its local EPG cache. Else the EPG will be refreshed if the user accesses any EPG view at the web interface and the timeout set at \"Update EPG every\" has been reached." msgstr "" msgid "The interval, the EPG data is refreshed from VDR and AutoTimer updates are performed (if AutoTimer feature is used)." msgstr "" msgid "

If you want to limit the number of channels used in some parts of VDRAdmin-AM, this is for you!

Use the radio buttons to activate or deactivate the wanted channels in the named menu.

To add channels to the list of wanted channels you have to select them in the left side selectbox and click . If you want to remove channels from the list of wanted channels you have to select them in the right side selectbox and click .

" msgstr "" msgid "Usually channels that don't have EPG information are hidden in all EPG views. If you don't want them to be hidden you have to set this option to \"yes\"." msgstr "" msgid "Edit Timer" msgstr "" msgid "Edit EPG" msgstr "" msgid "

Here you can edit the descriptive fields of an existing EPG entry.

" msgstr "" msgid "Channel (readonly)" msgstr "" msgid "This is the channel of the EPG entry. It cannot be changed." msgstr "" msgid "Time (readonly)" msgstr "" msgid "This is the start and end time of the entry. It cannot be changed." msgstr "" msgid "Change this string to give this EPG Entry a new title. It must consist of only one line of text." msgstr "" msgid "Change this string to give this EPG Entry a new subtitle. It must consist of only one line of text." msgstr "" msgid "Change the text in this field to edit the description of this entry. The text can consist of one or more lines." msgstr "" msgid "VPS (readonly)" msgstr "" msgid "If available this field shows the vps time of the EPG entry. It cannot be changed." msgstr "" msgid "Video tracks (readonly)" msgstr "" msgid "If available this field shows the video track(s). It cannot be changed." msgstr "" msgid "Audio tracks (readonly)" msgstr "" msgid "If available this field shows the audio track(s). It cannot be changed." msgstr "" msgid "No Help Available" msgstr "" msgid "

No help available yet. For adding or changing text please contact amair.sob@googlemail.com.

" msgstr "" msgid "Recordings" msgstr "" msgid "

Here you will find a listing of recordings known to VDR. The headline will also show you VDR's total and free disk space.

The listing showing you some information on the recordings. You can change the list's sorting by clicking the columns heading. Above the list you'll see the navigation path. If you want to view the contents of previous folders you'll have to click on its name in that path.

Each row contains this information:

Date
The date when the recording has been done. In case of folders this will show the number of recordings the folder contains.
Time
The time when the recording has been done. In case of folders this will show the number of new recordings the folder contains.
Name
The recording's or folder's name. Click it to show the recording's summary or descend into the folder.
Rename (\"edit\")
Rename a recording.

Note:

This only works if VDR has the MOVR or RENR SVDRP command which is not a core VDR feature but provided by the Liemikuutio patch set.
Delete (\"delete\")
Delete a recording.
Stream (\"stream\")
This column is only shown if you activated and configured Recordings Streaming in the Configuration menu. You can watch the recording at your workstation.

In addition to these functions you can delete a number of recordings at once by checking the box in the last but one column of those recordings and clicking .

If you've set the path the VDR's configuration files and have entries in VDR's reccmds.conf you can run those commands for the selected recording by selecting the wanted command in the select box locate next to Commands: and pressing the button.

Use to force reloading of VDR's recordings listing.

" msgstr "" msgid "

Here you will find a listing of timers known to VDR.

On top you will find a chart showing a day's timers graphically. This provides an quick overview on what's going on at the specified day and helps you in finding conflicting timers. Moving the mouse cursor above any timer box will display a tooltip containing the timer's title, priority, lifetime and duration.

Below the chart you'll find the timers list showing you some information on the timers. You can change the list's sorting by clicking the columns heading.

For each timer you have the following options:

Set its state
By clicking on \"Yes\", \"No\", \"VPS\" or \"Auto\" in the \"Active\" column.
Quickly view its priority and lifetime
By pointing the mouse cursor to the timer's title.
View its EPG entry
Timers that have set AutoTimer Checking to \"Transmission Identification\" will show you the corresponding EPG entry if you click on the timer's title.
Edit the timer
You can edit a timer by clicking \"edit\".
Delete the timer
To delete a timer you click \"delete\".

Each timer's state is indicated by differently coloured boxes (in the chart view) or images (in the list view):
    / \"on\" Timer is OK and will record.
    / \"problem\" Timer conflicts with other timers. That's not critical, as long as you have enough DVB cards for the parallel recordings.
    / \"impossible\" Timer is critical and will most likely not record.
    / \"inactive\" Timer is not active.

In addition to these functions you can add a new timer by clicking at the top and you can delete a number of timers at once by checking the box in the last column of those timers and clicking .

You can and selected timers.

" msgstr "" msgid "

Here you can edit a timer's settings.

" msgstr "" msgid "Timer Active:" msgstr "" msgid "Activate or deactivate this timer. Deactivated timers are still stored in the timer list so that they can be activated again, but they do not record anything meanwhile." msgstr "" msgid "AutoTimer Checking:" msgstr "" msgid "Depending on how this timer has been programmed you have up to three possible settings:" msgstr "" msgid "Transmission Identification" msgstr "" msgid "Monitor this timer using the identification provided in the EPG. Please note that this only works if the provided identification is a fix and unique value! This option is not available with timers programmed in VDR." msgstr "" msgid "Time" msgstr "" msgid "Monitor this timer using the start and stop time." msgstr "" msgid "off" msgstr "" msgid "Do not monitor this timer." msgstr "" msgid "The channel to record." msgstr "" msgid "Day Of Recording:" msgstr "" msgid "The day when the timer should get active. You can enter the day in two formats:
  • Two digits (DD). This will use the current month and year.
  • ISO norm (YYYY-MM-DD). Program your timers as far in the future as you like.
In case you want to program a repeating timer you can use the seven checkboxes below the text field. Check the box for each day you want the timer to get active." msgstr "" msgid "Start Time:" msgstr "" msgid "This is the time when the timer should start recording. The first text field is for \"hour\", the second for \"minute\"." msgstr "" msgid "End Time:" msgstr "" msgid "This is the time when the timer should stop recording. The first text field is for \"hour\", the second for \"minute\"." msgstr "" msgid "Title of Recording:" msgstr "" msgid "The file name this timer will give to a recording. If the name shall contain subdirectories, these have to be delimited by '~' (since the '/' character may be part of a regular programme name).

The special keywords TITLE and EPISODE, if present, will be replaced by the title and episode information from the EPG data at the time of recording (if that data is available). If at the time of recording either of these cannot be determined, TITLE will default to the channel name, and EPISODE will default to a blank." msgstr "" msgid "Summary:" msgstr "" msgid "Arbitrary text that describes the recording made by this timer. If this field is not empty, its contents will be written into the summary.vdr or info.vdr file of the recording." msgstr "" msgid "Your Browser does not support frames!" msgstr "" msgid "What's On Now?" msgstr "" msgid "Playing Today?" msgstr "" msgid "Remote Control" msgstr "" msgid "Watch TV" msgstr "" msgid "Commands" msgstr "" msgid "Search" msgstr "" msgid "Authorization Required" msgstr "" msgid "This server could not verify that you are authorized to access the document requested. Either you supplied the wrong credentials (e.g. bad password), or your browser doesn't understand how to supply the credentials required." msgstr "" msgid "VPS" msgstr "" msgid "close" msgstr "" msgid "view" msgstr "" msgid "search" msgstr "" msgid "edit" msgstr "" msgid "Length" msgstr "" msgid "Video tracks:" msgstr "" msgid "Audio tracks:" msgstr "" msgid "Subtitles:" msgstr "" msgid "Video tracks" msgstr "" msgid "Audio tracks" msgstr "" msgid "TV select" msgstr "" msgid "Stream" msgstr "" msgid "Channel group:" msgstr "" msgid "Go!" msgstr "" msgid "Search for other show times" msgstr "" msgid "No Information" msgstr "" msgid "No EPG information available" msgstr "" msgid "Playing Today" msgstr "" msgid "starting at" msgstr "" msgid "What's on:" msgstr "" msgid "at" msgstr "" msgid "now" msgstr "" msgid "to" msgstr "" msgid "Duration:" msgstr "" msgid "min" msgstr "" msgid "at:" msgstr "" msgid "You need JavaScript to use the timeline!" msgstr "" msgid "Rename Recording" msgstr "" msgid "Original Name of Recording:" msgstr "" msgid "New Name of Recording:" msgstr "" msgid "Subtitle:" msgstr "" msgid "Rename" msgstr "" msgid "Total:" msgstr "" msgid "h" msgstr "" msgid "Free:" msgstr "" msgid "Date" msgstr "" msgid "Total" msgstr "" msgid "New" msgstr "" msgid "Play" msgstr "" msgid "Cut" msgstr "" msgid "Delete recording?" msgstr "" msgid "Refresh" msgstr "" msgid "Commands:" msgstr "" msgid "Really run this command?" msgstr "" msgid "stream all recordings" msgstr "" msgid "Delete Selected Recordings" msgstr "" msgid "Delete all selected recordings?" msgstr "" msgid "No recordings available" msgstr "" msgid "Transponder:" msgstr "" msgid "CA-System:" msgstr "" msgid "New Timer" msgstr "" msgid "Edit timer status?" msgstr "" msgid "This timer is inactive!" msgstr "" msgid "This timer is impossible!" msgstr "" msgid "No more timers on other transponders possible!" msgstr "" msgid "Timer OK." msgstr "" msgid "Auto" msgstr "" msgid "activate" msgstr "" msgid "inactivate" msgstr "" msgid "selected timers" msgstr "" msgid "Delete Selected Timers" msgstr "" msgid "No timers defined!" msgstr "" msgid "Create New Timer" msgstr "" msgid "Buffer:" msgstr "" msgid "Use VPS:" msgstr "" msgid "readonly" msgstr "" msgid "Timer has been set by AutoTimer pattern:" msgstr "" msgid "TV" msgstr "" msgid "Interval:" msgstr "" msgid "sec." msgstr "" msgid "G" msgstr "" msgid "Grab the picture!" msgstr "" msgid "Size:" msgstr "" msgid "Open in separate window" msgstr "" msgid "VDR Commands" msgstr "" msgid "Export channels as playlist:" msgstr "" msgid "Number of lines to show:" msgstr "" msgid "unlimited" msgstr "" msgid "SVDRP commands:" msgstr "" msgid "Commands defined in commands.conf:" msgstr "" msgid "Output" msgstr "" msgid "What's your VDR hostname (e.g video.intra.net)?" msgstr "" msgid "On which port does VDR listen to SVDRP queries?" msgstr "" msgid "On which address should VDRAdmin-AM listen (0.0.0.0 for any)?" msgstr "" msgid "On which port should VDRAdmin-AM listen?" msgstr "" msgid "Username?" msgstr "" msgid "Password?" msgstr "" msgid "Where are your recordings stored?" msgstr "" msgid "Where are your VDR's configuration files located?" msgstr "" msgid "Config file written successfully." msgstr "" #, perl-format msgid "%s %s started with pid %d." msgstr "" msgid "Not found" msgstr "" msgid "The requested URL was not found on this server!" msgstr "" msgid "Forbidden" msgstr "" msgid "You don't have permission to access this function!" msgstr "" msgid "All channels" msgstr "" msgid "Selected channels" msgstr "" msgid "TV channels" msgstr "" msgid "Radio channels" msgstr "" #, perl-format msgid "Access to file \"%s\" denied!" msgstr "" #, perl-format msgid "The URL \"%s\" was not found on this server!" msgstr "" msgid "Your favorites" msgstr "" msgid "Search results" msgstr "" msgid "Default" msgstr "" msgid "--- no timer ---" msgstr "" msgid "unknown" msgstr "" msgid "none" msgstr "" #, perl-format msgid "Can't open file \"%s\"!" msgstr "" #, perl-format msgid "Can't connect to VDR at %s:%s: %s

Please check if VDR is running and if VDR's svdrphosts.conf is configured correctly." msgstr "" #, perl-format msgid "Error while sending command to VDR at %s" msgstr "" msgid "Internal error:" msgstr "" msgid "Lookup movie in the Internet-Movie-Database (IMDb)" msgstr "" msgid "Can't find EPG entry!" msgstr "" msgid "Playing Tomorrow" msgstr "" #, perl-format msgid "Playing on the %s" msgstr "" msgid "next" msgstr "" msgid "What's on after" msgstr "" msgid "What's on at" msgstr "" msgid "Suitable matches for:" msgstr "" msgid "short view" msgstr "" msgid "long view" msgstr "" msgid "Schedule" msgstr "" #, perl-format msgid "Can't write configuration file %s! Reason: %s" msgstr "" #, perl-format msgid "Configuration file %s not writable! Configuration won't be saved!" msgstr "" msgid "Timers" msgstr "" msgid "System default" msgstr "" vdradmin-am-3.6.13/template/000077500000000000000000000000001443716113400156225ustar00rootroot00000000000000vdradmin-am-3.6.13/template/default/000077500000000000000000000000001443716113400172465ustar00rootroot00000000000000vdradmin-am-3.6.13/template/default/about.html000066400000000000000000000201171443716113400212470ustar00rootroot00000000000000 <?% gettext('About') %?>

VDRAdmin-AM © 2005-2014 Andreas Mair.

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.

Bubblehelp infoboxes (templates/default/infobox.js) is licensed under GNU GENERAL PUBLIC LICENSE Version 2 (GPLv2).

Crystal Theme Icons are licensed under GNU LESSER GENERAL PUBLIC LICENSE v2.1 (LGPLv2.1).

Andreas Mair (Homepage)
  Ville Skyttä
Thomas Koch (Homepage)

Andreas Mair
Andreas Mair
Trois Six (also at vdrportal.de), map, lobotomise, bads, Mickaël Nival
Rüdiger Jung, Manuel Gomez
Rolf Ahrenberg, Ville Skyttä
Roel Koelewijn
Oleg Roitburd and Allrussian-forum translation team
Karel Borkovec
Diego Pierotto
István Füley

  (EPGSearch Plugin') %?> v)
  (Streamdev Plugin') %?> v / Xineliboutput Plugin') %?> v)
 Liemikuutio Patch)') %?>

  • .') %?>
  • VDR-Portal if you understand German language. Please use the announcement thread if possible, search for:') %?> "[ANNOUNCE] VDRAdmin-AM-"
  • VDRAdmin-AM BugTracking system.') %?>
vdradmin-am-3.6.13/template/default/at_timer_list.html000066400000000000000000000161661443716113400230050ustar00rootroot00000000000000 VDRAdmin-AM - <?% gettext('AutoTimer') %?>

help
0 %?>

-
-
-
onmouseover="tip('VDR-'); return true;" onmouseout="untip(); return true;">
edit
delete
vdradmin-am-3.6.13/template/default/at_timer_new.html000066400000000000000000000255141443716113400226200ustar00rootroot00000000000000 VDRAdmin-AM - <?% IF newtimer %?><?% gettext('Add New AutoTimer') %?><?% ELSE %?><?% gettext('Edit AutoTimer') %?><?% END %?>

help
checked="checked" /> checked="checked" />
checked="checked" /> checked="checked" /> checked="checked" />
checked="checked" /> checked="checked" /> checked="checked" /> checked="checked" /> checked="checked" /> checked="checked" /> checked="checked" />
 :   
 :   
checked="checked" /> checked="checked" />
checked="checked" />
checked="checked" /> checked="checked" />

, - ()
vdradmin-am-3.6.13/template/default/config.html000066400000000000000000000663511443716113400214140ustar00rootroot00000000000000 VDRAdmin-AM - <?% gettext('Configuration') %?>

help
1 %?> 1 %?>

0 %?>
checked="checked" /> checked="checked" />

checked="checked" /> checked="checked" />
checked="checked" /> checked="checked" />

   
checked="checked" /> checked="checked" />

checked="checked" /> checked="checked" />
checked="checked" /> checked="checked" />

checked="checked" /> checked="checked" />
checked="checked" /> checked="checked" />
checked="checked" /> checked="checked" />
checked="checked" /> checked="checked" />

checked="checked" /> checked="checked" />
checked="checked" /> checked="checked" />

checked="checked" /> checked="checked" />
checked="checked" /> checked="checked" />
checked="checked" /> checked="checked" />
checked="checked" /> checked="checked" />

Internet Movie Database (IMDb):
checked="checked" /> checked="checked" />

checked="checked" /> checked="checked" />

checked="checked" /> checked="checked" />

checked="checked" /> checked="checked" />
checked="checked" /> checked="checked" />
 
 

vdradmin-am-3.6.13/template/default/default/000077500000000000000000000000001443716113400206725ustar00rootroot00000000000000vdradmin-am-3.6.13/template/default/default/aktion.png000066400000000000000000000010441443716113400226640ustar00rootroot00000000000000‰PNG  IHDRóÿaëIDATx¥ÓŒX†áíÝØggÝÆsÕîØ¶mÛ¶mÛ¶m{æíôÖÖ—{âó\KÜÜÜø˜@zz:qqqxyyáääÄüÁ÷ßÏ'Ÿ|‚D"y©€çµµ5–——™ŸŸgaa±±1†‡‡™šš588HOOÝÝÝtvv>¼)±±±XZX°¹¹ ÀÑч‡‡ïxzzrîÿÿ¹'§ÀíÛ·˜áääD`olmmøí×_ŽNcbbS³¹rõ }}}ìïï¿ËÓ×ÓCJJ }csr+;_‡­S¨ª­GVV–ææ¦WÛÛÛ¨««‹SÖ5µeqÊjÛ©nîei]‚ƒƒ_VVV¸sç?þô—®ÞÄÞ=ˆÙÎÝC´´¶cddˆ··7{{{/vvvüøã”U„‹Í}3¤gå"'{ððpqˆ¯¦§§¹u릦æl쳄'åð÷?ÿò÷_‘ššÊññ1âͼœžž²ººŠ¼œ,º&Ô´ £¨¢ÎùsÿSZZ*î?>>þ¹z888Èî:HKKsAF†¶¶6Ö××EÓãˆf‰äëG€xa¢ÎqÏ)))âÎÇç1ð¸ù3Ƀàíû²ìgóÞß÷…ÜiÓ¡?³(ñIEND®B`‚vdradmin-am-3.6.13/template/default/default/close.png000066400000000000000000000014611443716113400225070ustar00rootroot00000000000000‰PNG  IHDRóÿaøIDATxmScƒåHÍX³mÛ׿sÛ¶m;«6×öضmÛ¶}æVÆøpãêpÒ×ç##_^_ßK ùVOÏó[‰ §'ጼ? á ½8q^››É |Vøø$#/¯ µµ½¨«ëEaaÓ¡£Ã¯Ð×—ÈÞF@àà"kkåÖÖo±jÕ.\»v>£GpçÎlÙr‚ðlmÕ7ôôø¢WHYje¥¸×Ýý'¶m;‚]»Žbóæ4ûÅÙ´i?¶o?‚ݻ㧟¦}«£ã.eLù]ʼ27· sælÀòåÛpëÖmíÃÔ©+0}ú*L˜°'NœÇéÓÉÝn46޲8+uuùw9?ÞÅ% ÝÝÿ௿àúõÛÌ6‘Ü%Âõøá‡i8pà{&ÎÌAuõ EQBKË™çŒý©4_~ù':;%’ù¸yóû˜Î·qäÈ™çàžž?/¯ØØ(È…›À™š|+“å ¢¢ŸÚþÙÙ]øW¯Þzde~õÕ¯pq‰…D’oïTºŽEø–33 øÖÛ;115ˆŒ¬„JUD$öï?þœ€‘•–vÃÉ)ŠÔ“áã“J×ÌÁ·¬ÁÉ)œ¬eŠÖââj±sç‘gÊÏ\¹r ee=ps‹…¿¬­åÐÔt¨_žÝ0V¦~èÐóÌTìï­—.ÝïY7lµ˜ _hh8°}h½Wzy%‰fÍZCÊ166AA9¤–‰ÖÖï˜öÂ!¤¤4çã™úJ Çw¹'{ÛCji)½^F[ø+´µýˆÄÄFš$%5Šý´·ÿˆ¢¢n„†–ÀÈÈëÞgŸÙI‰€ ØÐ/²²’ß +W£¶vX\™ÊÊ~ºŸ©Õ… În|þ¹}¿L@.<9]]w­ps‹„R™‡ÔÔf$'7A.Ï¡ÖCɶó R–1à[ ÌÑò}Èkk» ôì[}}þ[ 'áÓOíx|ð2˜ÍcÍy›Þ6ÝIEND®B`‚vdradmin-am-3.6.13/template/default/default/configure.png000066400000000000000000000014511443716113400233620ustar00rootroot00000000000000‰PNG  IHDRóÿaðIDATx…’C $GÇÿÕî×k=®mÛ޽Ĺ_b۸ĜäûÛYÛ~6Û¬©® bþºËUŸÉSO½ŽÊÊø UUvO™2¶2Mïíµ;ÚÚºžwÝðJs>!ø(¢X°`*–. )Š44´¢¼|¨Ç9 ÃGgÏžDŒ¯«kyá§ŸO§”^Oˆ@Ž&䑃 B}}+õ<ÿñ~8tÓŽ‡]ÆÆŽ­Âœ9¯tÝàbËò`Ûòs˜¦Ï J¼®ëãĉóhmíÈîßre¹(PSS²2}KEb’$Š¢ ¢bxI@UÕˆ‹««G¼—$tFA«¦©÷.[6g¹adÇ$I¬68ãû!Ûƒaè˜>}léLQÄ`ÆcòA{·££ç‡uë^=iÒhضŸ(¡¯ÏBs›Ù>8wÆYg| 'Œ¡ùÓ\^pæLcÃÒ¥³¦nÛ¶bjwwßÔñã«ó>ÚR"¢»Û„¤#¶èßL"XÇS’ƒ÷÷ æý~þ‹/våýÔPxìû1’$‡(Ê¡¶¶=Ãê)Áº!Cé§!—¯g\D.M@ ‰“'/9pútëê2—r©‘®®^„aE±g'Ê[ŸGyÔ:ƒÔ-n xNgç.»ã4'’ÎÉ¥—ÞÏóòâmº®­2Œ~“óVt ^>ç²ÕçWueQAë0@ Ëh"F®öœx«ïGY7`( ðý”ÒbÔãzJ„p²Ñ¸èÂ)g>]5Õl¨"Šp €³Ý:;~·$1²ð§ªÕ°¼Ÿƒ­•ÇöX=ôÁºÞ E¹Tf€!YÄ´¡8e\ú\ \%à_à H˜ðâöýä®}ûÁ1PB 4x õf òÈÐAìaÿ(Œá™o·ã¦íD ùšÐBL‘Ø` þOçÈ~¹ˆÛø3ë–J"T³8Þ$ý_¥Ø)É 9«£®3z`pÔ:S=Õ ×ý vÀÒDÐ|IEND®B`‚vdradmin-am-3.6.13/template/default/default/cut.png000066400000000000000000000013011443716113400221660ustar00rootroot00000000000000‰PNG  IHDRóÿaˆIDATxP%IÛúêþc{wkÛ¶­±mÛ¶mÛ¶mÛ®µÕ±/X•™OCyy󳪪¶™ÂÂ1‚ACC÷PGÇ ÈʪúB’Rº;3³ò "‚––^P_ߢ¢òÄ,-ƒ‰ƒƒÓ÷ÖÖv¶·¶ö›""(+k……õÀÕ5VÊÃ#þlEEKûôôüZ~~*"‚ôô ”T ôô¼ÞÖµŽNƒììê/¯^D!!™ 00 DDä,¾ëc3$$£ÜÊ*„ÏÙ9Šð§ålUˆ¶@–ªÐ‡ÿ¯3†ÑïÿŒ ½€¿ Èɩ޲± Í}óÆJRZÚúçãxˆ½ÊŠ˜Íeo]jàéŽæJm³Æßöqv¾¾É@MÍ¥éÆ -Ñ›7uˆ~:ö¸ÃW³ÕOE¢fú| ‚¹4Άõf^°Ò"²ãng{ÀKñйF3˜©Á þ™ ê«Âˆ#í|ªÆ"Eb ÆŸ\©àÛü`º€Ìð‚Ù\ž²±®àfü¡ ýHŠäi,úŒ)í.a®yÞÁ2ÔZa]–3q[ÝìM“Yœ`«w{«‘gq½g­?‚£¥Ê F}Gó€^{Ôˆx½D‰¦§L›¡¢Ï…y©Ù’®‰ŽÅB`&îêrÄßôÃûÌ%AÅÐÝïÌN£„“ÓÅתS®UëÐN橳ÚÄJc¹"_BD½ž(0ì‡òÍP†é³Õ¡“ãál“YXÅï´` MO¡i“žÒ³E?eayƒâó¬Æˆ¥¯Õœ¡Æã&zg†‹j¿ýZ¼4ú%R$¾f±ê1¦Ü¬Q§în×§\¬Ñ¤ }‚âGLàvÅó˜1²F‰b#OšfØÿË « XÒÏó·ì EJj+ÕzIEND®B`‚vdradmin-am-3.6.13/template/default/default/delete.png000066400000000000000000000012611443716113400226420ustar00rootroot00000000000000‰PNG  IHDRóÿaxIDATx…ÒllKÆñ}¶mÛ¶m+|¶mÔÍ ®­Ú¶mcQwQŸÝb²;g2gæ»§v›äŸ‰æ74”U›£ÅFZÌÖ¹šLVRUßNJ+$1½Ü›TêØšy}pd®!4:ßðÏv€© µTJ‰… !঄£¡¹]Èْ̫ñpÈzÀl”q7C“±Äáª%•&_üú_Þëí@OÕÆÓJ“_…²ª&”Ôc×þdüñßÖïÖ×À5¡O4"-·ñIÅØ} "2ñÍO¾t½#LM¦”a‚ (ã*,Žq”×XPÓØÏ¿ùk@ãÆJHs 4)A¹Ñ$úÍpýñ9º‚ö£ÆhG“ÉŽ¯¾ÿw ×¹ç_Èß‚gEAq Œ˜Ì Ÿ¾yÅ1 Ý K­í¶1|ýÃJS!s" yòó§A}¿{ïYÈË{ð:ô'$¡£WA¯Ý¥ÿ-š¦×@‡štâ»!ºòš“Á^¼µ°:Ut[Ø&ðÍ^ó@ý 0¡j B‚¦DB>x©¾òñgvÛÕ¬n‚Xm ú'v@ˆìÀFÈû/ÖW> üÍÇ¡]z¤Á~晊J„uă!²` šyÇ9S+«^?ÃEÆõs‹OšBØùÀnìF¿‹­|âƒúË' ›ÿÇ8ÕàôhP4 gV!èM7CÙ¶K?‚ýCîÙ#¬ü‘„ž¦Ç¸„ªçãR‡˜€â¢›ÐðíO vW\¯øøo$~[§ò Ü<=l&>þ›‰·ÿ&½ÍÄËoñòÝH¼ý6“?ùI™X>bgxl…IEND®B`‚vdradmin-am-3.6.13/template/default/default/edit.png000066400000000000000000000011441443716113400223250ustar00rootroot00000000000000‰PNG  IHDRóÿa+IDATx…“Þ[€¿ShTרçÚ¶í{7×ÞÎ&Z…o1ÙÄ/s[ëØ¶“v—ëœÆØß㧮*ËJ2? üˆÒý¼qsnðiù޹Š+;·Îí:ÞaFãò«/=EJ)¼ " $åGxâƒ+ˆÂ³-'³ÓîЈ<À0„º†tnÒnmBÜwàâœ3m¡ÿÄ;—áƒÑ …(ì$™8tdÎäBê»V·«»{þ’U¯Lø^­º­âCœäáCç?P2ú¶XxôíÄTŽa„^†¨ÜJñÙ_èxç ZZ,\·Ê¸(@Þ\†nÙÚT§p_ú‰LöqLÓ`\#Ê'Ñ3W lƒgRJ¼†õÎ÷èɆ¡¢÷nd þY….2·ÃLƒ¯T5ŠOÿN¶óIâ8¥(•Jiàñ^é«@,e½*Táz"Ž îçÿÿIG8Ž[¯•r% ô‰bJ‚Œ*ŽÑãÇŸJ¾Lùñ¯0ü tˆÂÙ”b¨¹ G:"þœH½ÎµÛ‡‘ï}Q„’ !D³jš&¯¯yàQÞåê± d…D½ý7æãÏ¡‹$SIÚ:Úª@òªÏ}R5ã¿pý>æû¿`=ÿzý’ÞtmgÈf;°,‹t:7.q£4ë/¾JÇä9ËFIˆb‰aH©êU6UŽqûÎ=vïÞ;$€…¢YzÇ•J•áÔjTíC¾pøIEND®B`‚vdradmin-am-3.6.13/template/default/default/fern_03.jpg000066400000000000000000000025331443716113400226330ustar00rootroot00000000000000ÿØÿàJFIFddÿìDucky<ÿî&AdobedÀ M_ZYÿÛ„       ÿÂDÿĹP! A#2C  !1aÑB¢3DAQ±"2ð‘¡Rbr#CcsÃP!1A0Qaqð‘ñ ±á@ÁÿÚ éw‡@B” óF8¹vËǬÕ0‡Í±R’Á±“Ÿ 7ãÿÚŒÑÈòäŒrF9#‘ŽHÇ$}5eë°xÚ…ÞjI7nì¯Ò´¾ð• ÍÉ/¸­ÆÞºóáÆëe’®sM-rRíL'^b#,IãÂGW?.ßÿÚÑ?ÿÚÑ?ÿÚ?ÿÚ?ÿÚ?2½ÄEé…M &Î…Å“gBâɳ¡qdÙи²lè\i>š{kO­Rÿ#ù2æ$¤¾vþS>c–h7“;Çe§öEèÕR œµ&?ÒÇV î­0tvCs0 Dõ÷‘[PÉÙ{#„`sœFGk«WËFaìÎêQÜY Fqïn®#÷i\US÷?¹LÏ#•3Q´"ŒÚ lâM™ÓröþK –>>œ”Dñ$Ö»“¹z{½UÁD#ñbøÍ<ļ/{‰ÖìÎÕGºw„òâ,¯ŠÅ]«}þÚù/ÓË®ºeÓ.™të§]:n‚ÖøeÿÚ?!]k™šèw“i÷‘ûýô~ú?}·‹U–wYúK~k¶çÅÆ­Ô&x=Ù]9TÙ¯Y„3ßÿ`DkZŠU4xaè¦TçCP ÖôÀ—ʹ͹µÙÀÐÀßh¡ÓÝá³-P Ö ùSZõ‘cIe:0¢Z» —k‰B±é¡U;_•ö"¶ÙÐÖ5ÕSÝ2ž júT¬¿”>í+_ö×ÜxŒN=Yȩ̀›çí3Üöþ*ÿÚ?!æ\¹|ŠçÿÚ?!æ×ùÿÿÚ û% ŸÄ•È¥éËÔ’/ÿÚ?]}ô ^ót;·»¯w]!ˆù`( EqŒ`”…L'(]&Òæ®’µ@Õz€D³2aWœ2™ß»‘în‡±2.·RÀÛE»ñº¥¾$7M¬"g‹fÞб¸8`–#œ·.ìeQŠ:"žZâiƒt E§ØôÒPtF~6bCZ€ëÀRì­öö¿Oææ=ÕSÓ˜õzt¤T$¢¸â­ŒÔžÇÿÚe‡r#×uóòÞñÒ_½G´ÿÚ?!ôOÿÚ?!ôOÿÚ ‘%¶k$RÛåŠIHYÿÚ?¨ô­°fDóZj³ßÈßc!²ÂÁZˆ–¨–×óÈ´9?ÿÚðŸÿÚðŸÿÚ?ÿÚ?ÿÚ?ŒžLj¡fY<ñL¤/Še!|S) â™H_”ÊBü¦RëRrh…8˜úcܵÿy䔲×Û.ô°ÊèÁðm_#¶*È%„!üÁ¥­Ë8ò¾¤Þê²~cs Ä@ÊÚdzÚ×¢Ä"ʦ$íÓx8c×gâ:øÃ¯Œ:øÃ¸ÆÆ0î1‡ªÖ¤>y†ÿÚ?!Qnǵ;÷·ßñßÛJ †F½÷ŸÑ8ü¹…9¡8³Aínó)v6 6â+ÞÆpgÖiÛ›²°™s|;CA`.ÚS6Nf tõ{Çhƒ1YÇz5Ðs•„°ÚäŸ;îŸ/®SÿÚ?!þ'ÿÚ?!þ'ÿÚ ùþÒ«-R]¥ªJÔŸûïÿÚ?F…R’eVfå;ÚýÛV.-ŸWÇE3nº0ËW¾ç÷–¬”)M'cFˆP‹:½[¾ áïó*¼pÊÆv4ìhÈO[4&:»œôÎ*ݨ 9ƒ:¥4„ÀÁS€X¨¯ TÑV#w)¤öE¬€-YùðgÂqgõ>¸5̽ûvZÝ'D0}nöÑéÔÿÚ?©R¥J•*Wˆ|&ÖyßÿÚ?—.\¹råø“È"ßÿÙvdradmin-am-3.6.13/template/default/default/fern_07.jpg000066400000000000000000000021271443716113400226360ustar00rootroot00000000000000ÿØÿàJFIFddÿìDucky<ÿî&AdobedÀ >í™UÿÛ„       ÿÂCÿĸ#P!4A"1!’3£AaáCD¡Ábâq‘"R²Â„P!1Q 0Aa‘Áðq¡Ññ±@PáÿÚ Òï¯$§n:JqÍ™NZħLd Ææ‹ãÿÚe‡ÞOó€ùÀ|à±iÕz¥±¬#¥/­í[uy¬&°ŒiiuŸ‰I!l‚ß§³·¹Öžó×+g3™¹HÿÚðŸÿÚðŸÿÚ?ÿÚ?ÿÚ?yµäÖ´Ò /ŠÅ"ü¬R/ÊÅ"ü¬R/ŠÅ"ø¬R/›b©³öTA7ò‚Éé“McI\b|©l¹mk_(µ‘ß!¹1òñâž‚Êl˜Òs-8ÿD¦UsÈŠ©"lýˆó×Ӊꕗb²îŽ~(ç⎣u£¨ÅF(ïã'Ÿ¯·tÿÚ?!=f¹·èÅÊýó×Ü]M„Êw™=Þæó´Še- L‡˜x"4ÐæU~ÄCH )dÈy™2¢Ò󱤄½ö5=¶ÀH¨VC0`»­@µ@b®à°§÷»!Írõ¾Ý¤ý·Ìtœ®TŸÿÚ?!ôOÿÚ?!ôOÿÚ ƒ$²k%RËäŠK[_ÿÚ?¬«&ª‘ŠÈ²a$‚ öν’",2’#ĸ< 4¡”m-ÔÃ:9™hh;¶&ŸPœ$L$ËJÙ‘44ÐÑ•"¥ÈF¥d-iÞ w¡rI©7™ÑeH¶“ÀZ¢(œÓ‰„艄Nj7_¨UÏÒñÏ'8 ~01ÀcñÚÄÒ~?ûn²×à©çÖÿÚ?ß[Àð@ãÿÚ?â‘Á|oÿÙvdradmin-am-3.6.13/template/default/default/fern_09.jpg000066400000000000000000000021251443716113400226360ustar00rootroot00000000000000ÿØÿàJFIFddÿìDucky<ÿî&AdobedÀ 7æ“SÿÛ„       ÿÂBÿÄ·P!" 4  !1A’â3£DQaq‘¡Á"Bbr‚²ÂC„P!1Q Aaq‘ñ0ð±ÑP¡ÁÿÚ éî)€òBlše’àJqgZZ䆘â3Ø !ãÿÚ³jýäá¸1˜ŽLG&#“À¦®S ”˱4››­ØõO–êI4—8 >J  ¿kLúÛm£AAÂ¥GïëËÆçÿÚÑ?ÿÚÑ?ÿÚ?ÿÚ?ÿÚ?ŒžLm”-^a¬W1 b¹ˆkÌCX®bÅsÖmÌ@ݘ×%§¬ÇÓ7Åÿyô¬M ‰óZ¶µ¥*!32d·9ˆP±¯a·æ'ŠÅa0iw¹oSdn–¾û @˜òs¦Mœ‡2cÍLҮΪb®:‡1mË‹ñÑÈÝÑÈÞÑû÷‡·›Ç™¦`ÿÚ?!~¥¯mO)åÑäÑäÛƒ®è U|}sÿ —7(Sšï;Û“˜_|£Ù¼Êã§!Þræ¹» ™ß7ô _D¤ZðQ8c„O8KCPe†Ñb³œèqÒô:ýöv¹ŽÅ5ý:_/¿ÔÿÚ?!ü'ÿÚ?!ü'ÿÚ m7Ò+&R]¤šJ—ùý¿ÿÚ?h@õ°7 fåÛË—ûÑæÑçŒ&mR.Œ2ÇC¡ßÖ^µ’…)¢„ðhÜýz8¬¸1Dó)2D\V ðiàÑžöhJéÛž‘ÖèºfPŸ°gt¦‘´™¢p Àe’ö=Ì6©ÒtE¬€-YöCÍ9ÈëýÕ­›*-ð“¦n‰aûÒužýÇÿÚ?•*T©R¥n¬ÓkÑÇwÿÚ?—.\¹r÷ˆžŠúßÿÙvdradmin-am-3.6.13/template/default/default/fern_10.jpg000066400000000000000000000021201443716113400226210ustar00rootroot00000000000000ÿØÿàJFIFddÿìDucky<ÿî&AdobedÀ Aí‘NÿÛ„       ÿÂCÿĸ"P!#4A 1á’3£D!Qa¡Á"2Aq‘b²ÂCc„P !1QAaq‘ 0ð¡±ÁÑñPáÿÚ Óï €€r*]Å ±Bü‚¦DÓŽP\³ €ÙÑPìÿÚe©'g ØÈ6›ÏžùóÞôÓ6Î?Ôì]'%90¡qS×&—ItŽ*ôýê``J„Ô¨ñ8Öã/©¥)НÚúÍf³ÈyO1¬ÖÿÚèŸÿÚèŸÿÚ?ÿÚ?ÿÚ?œžLjòð¬=Ã8®Z3Êå£8®Z3Êå£<®Z3Êå ÝŠNOD©Þa?'²!¾·üçÂ"§ì$æß+zLÍU*Ïf-4™kØm^™ùˆˆ„!üÁ¥Öå¼|_B¯‘ñHŠ•'uZµRzEð ÅLCj€äŸ¯¤}ýQ¸ÕQ¸ÕQ¸Õ4<Ìå묔)M'ᡘªR‘)xb¼!bìt`U4°SðÓðÑž¶hJ}?9eº,o(0gT¦“ÈTE^h$€8]Ï4ð³¾SIÉj²µgÀýÜ'<æï‹iÌtMÓDpâÙë³mâxy ¼Dù®]*A#¦K'Œý4™îˆˆˆFÝýòßz}Å·«ˆº–§I¹Îu.3=çÐß^Îx‡rs¯±WãHÔf FhÔfFhÔfFh¦ý8Þ ôù~#ÿÚ?!rÅ»­ÒÎ ÇëÞûÏ~ú2>Ø{Þu;‹Ú¹ñ‡É)´Õ °õY|¹T¨Ñ͆u[ªl=fÃÖdjqgéÊ®qù9=»kÀT•J³r온V{T ~¡¥þÿÉÕoyè}\ANhçÞþeâkñ‰ÿÚ?!û'ÿÚ?!û'ÿÚ ’%²{-RÛäºI@2IÿÚ?%1њ܅æÒü‘ñØÝ¢‹è:zéMc4h»RIÃ4|QÒu[¨½9ºàÑbÿ'*æ•mAKÉ rü0b„ø4ø4³$±Á ¥¸fC0éñ¨<ÊôÕr¼YÑuC8JÀ°Ü`T 5Ò˜.´ NS¢S”òaÞXÍÏÇ/­}EëˆsÄù¿ŽÂsDçì¡üNöÝgˆ+³ÿÚ?ïE¾ä+¾ÿÚ?ïS¹^ûÿÙvdradmin-am-3.6.13/template/default/default/fern_12.jpg000066400000000000000000000021351443716113400226310ustar00rootroot00000000000000ÿØÿàJFIFddÿìDucky<ÿî&AdobedÀ <ì›[ÿÛ„       ÿÂBÿĸP! 4" 1!’3£DAaá"âq‘¡Áb‚²ÂC„P!AQa1‘ñ 0ðqÁ¡±Ñ@PáÿÚ ÓÜH rA.K*ˆ&Œ¦,Ö“@‚y`#Y€ B9%·ÿÚ³iÅäá¸0Ü˜Ž G&#“ȦÎS ”šÿ—¢i6ŽÖÑŽ£eqäf’i.*p5ÿ%Æ6Øi­¶ÝtL! ~'߯~;?ÿÚá?ÿÚá?ÿÚ?ÿÚ?ÿÚ?®O&·wJÃÐc6Ç1ŒÛÆ3lsͱÜ1›c¸c6Çp7^5ɺª{Ì|µüƒ|_õžÈ‰¿±(‰ïdgÄO'› ²Œ‰¯jµT©V9LDD!æ ..[G´äÌRiÒ­ ÈÈL™]Ó&ÍKÉEé„¶©ˆ~uo8ÝÖûF£4j3F£4j3F£4j3G]í_Žò¯¶¸ÿÚ?!uw qmNy¼m—ÙET4ª¼ýoðNÇ&P§šaÖ #.WCu^þ¸À‹L-ç”Øu›³NÞlÿa9s~%çÈÑb8ç9|¥J ¸ˆ0›Œ¿]!¨½÷àqŽ1Æ8ðë_uù’ü›z©ÿÚ?!óOãÿÿÚ?!þ“ÿÚ yöö+"R]¥ªH×é¬ÿÚ?Rný,i`›ËeŸîg¼#¼#¹!˜z¤]f7½mûËÛY(Rš(NÆ‚&ø(‰J°¡·‘'Çq½(¯$ìiØÑž¶hKvùºD[¢õÔÕ)¤Oè„ø ÄZxQC &Vs”Ò{"€ W V~«{ÛMúü_Š \?ÏÃnˆº%ë]öÞü?ÿÚ?•*T©R¥xV¢¿ Å.‘‹ÿÚ?—.\¹rüAȾwÿÙvdradmin-am-3.6.13/template/default/default/fern_13.jpg000066400000000000000000000021231443716113400226270ustar00rootroot00000000000000ÿØÿàJFIFddÿìDucky<ÿî&AdobedÀ @ï–QÿÛ„       ÿÂCÿĸ#P!A"4  1!á’3£D¡aÁ"AQq‘2Bb²ÂC„P!1Q 0Aa‘ðq¡±ÁñPÑÿÚ Óïâ#‚!yT L‰§&àE,@F@”09Ð"dÿÚe¬‡“¥h¾h¾h>h>h>+!)­òv&“•ÍVÉ+%Ù¤šG8yãþJ ˜ýÃã™Å…SB•O´î ¥Òétö=ÏÿÚèŸÿÚèŸÿÚ?ÿÚ?ÿÚ?¾O&5jð¬=ƒX°Z5‹£X°Z5‹£\°Z5Ë Ï4œžK©Þañæz¢éÖtD>|²'¹¨D°¬ÑMìI{¥¼äRt¯qÄò_9ÀDD!äî .×.#¥Ì'âlz¨uÅsæ̘úÜt©ˆqS ;™¹w¾ÑÈÝÑÈÝÑÈÝÑãÍ»óæ]ëUÿÚ?!wfâÚž|Ûç¿yòâAª¾rºýüBBá sBtã Z•s .b+ÔÚ-ÆtçAÞiÛ›²,.g¾¾£²æ°é*ic¯d(ºƒ 6ˆ0š—ÙÉ Qà?ï|Ù~kæKÑ~=ªÿÚ?!þ'ÿÚ?!þ'ÿÚ {,$ #RY¥ºIœ¶oÿÚ?hæÜi@7(¾sÕÙº«³SRz„’üºèÂ1…‰å9±eŸIiÖJ¦ŠðÑPÒK×MÍ{KU¹lgŒü4ü4d'½šŸoÖRæÔXPgt¦òøepêZ¦Ö„rx IM'’(ÕdjϨºuõþ¨t÷æ5öì¿RøÎžs'W¥ÕËÿÚ?à^âÔÓp+‹„ÿÚ?àVàDà¯ÿÙvdradmin-am-3.6.13/template/default/default/fern_15.jpg000066400000000000000000000021321443716113400226310ustar00rootroot00000000000000ÿØÿàJFIFddÿìDucky<ÿî&AdobedÀ =ë“XÿÛ„       ÿÂBÿĸ!P4"  1Aá"’3£D!Qaq¡ÁÑ2Bâb²Âƒ„P!1 AQa‘ðqÁñP0¡±ÑÿÚ é·‹@0J扤A\ß©ÌK½eð)`#—–[$„#B_ÿÚÁ‰Œôi²j2j2j2j2j2T«4Ãõ ë}9Òv¯i¥×ºÆF9¤æ“%\Àë½+ ÒÄÒéõ¸Õ…„i„!mD,&OædÉsÿÚðŸÿÚðŸÿÚ?ÿÚ?ÿÚ?ˆO šË|†9\¤c¦å#7)ɹHÇ+Ÿ!ŽW>B´RS=µYâcõÅìëWÜ{% |‚%/q ŽF¨Ù¼s<¯5R//VÛ¶Õ2Y6q(”0‡ñíSoÕ8{è_ CÅÖõëÖDxðÚfÉ8mi‰4l"tïøFpÔg FpÔg FpÔf‹qjýq*÷îP?ÿÚ?!¸( rÓO>n!ã,µ¾å pkÉzïðOvs&Sº°ó‘®¶†h»™Êï’Ã[9ÎÃÌì<λ²™m]ŸÊ?§P÷pZ¨#b=DpP”´0 Úˆ0Vw7IõïP3Àü×÷¾ièÇ¡?ÿÚ?!ü'ÿÚ?!ü'ÿÚ «¶ò«#R[¤šKTí/ïÿÚ?ÉAèZè@wiDsTûgìP®ñ„kSU"èÆXïúŸ2÷Þá¡JtPŸF”—ú‰¢ÃpVõXÞ•ïª'Me>> ógB| p(N¢È~àÏ)N‘|ÈQU^hǾ Ÿ˜¦¢'²(ÕljÏòî|¿ÎÛmëƒ|´#ÓS=¶ˆÿÿÚ?•*T©R¥hjµ„Õ. ®xq?ÿÚ?—.\¹råð„NQ‹ú¹ŸÿÙvdradmin-am-3.6.13/template/default/default/fern_18.jpg000066400000000000000000000024521443716113400226410ustar00rootroot00000000000000ÿØÿàJFIFddÿìDucky<ÿî&AdobedÀ N@4(ÿÛ„       ÿÂCÿļP !"2#$ !1Ñ¢3a2DQ±"Bb‚#ð¡RsƒÃ4P!1AðQa‘0q±ñ Á@¡áÑÿÚ èwÄ H Í×ÈÀ×c³Ð˜Ò72˜ JÆe‚1Ed,:ÿÚ¹Ä jµ\‘®H×ìr¼*‹ê3I 73#ÚD¿˜«¿pÚ9!/Gq\Œ=iúq†Â:jü ªi«Ý&ØCmšH†hø_ãÆw˜ÿÚèŸÿÚèŸÿÚ?ÿÚ?ÿÚ?{‹Ë@t(Y³0سfa±fÌÃbÍ™†Å3 ‹:fsðدQôù¯ÝŠ›÷OPäÞ¥æní —%M{"Ý4T–Î}êa™ª Ãàiê^žëH÷uÂ0"­ ×eÄ7t÷`Æ¿ _5*v®Ñ}Úá¿/îS™Þ3 ¡£àrMœÖú“®í=Úk6p %Ì!ÎWLb§­,É=§j+Ò˜+-›&öœ;ÔSe°AŒ­¥CÇ´òmcrëïEpë‡\:á׸d?Ÿ¡t/ÿÚ?!´õ‰[ç¸ì›O´ÝGìã÷ñûýäR,·­Œÿ–…1<‡´ð‹ÅE\è¶fa&Ʀí]è}wŸ$Ó]¦Žst©ªÛ%m\*/h`©t]\PéîÏБ-PmÖû¯ IõšáÑZ(åg´ÍDŒ¹\ÇÖV¢¹ ¹Y׬¶A…À4)ë5– 4Û¡UAªÍë:|&&Mëò¾æ83YŽ,ÇÈî>¯i«ürøŸÿÚ?!òî\¹yÿÿÚ?!ó*WñÿÿÚ Y%’»i®Å%IÊ[/ÿÚ?ÇÿÿHË^éy€éá•J*žV q‘~à,=æçZÆÝë~k^±EjǨ"Úž@¿ï {µ ²¡§¡JDÂCC­̱HµÍÙ«²f¨¨læ/;bÖ=3Ñp8GÔé/QöT‡"`‚¼ z[×Ë/ë÷‹ÔH¿hôzàé(Xí ©×…UÔ\2 ®·fN|4uá( [PÖ ªÎ?ŽË\Ô7/›X’mP~¨"+‹o—êSÖïîÞwfÿÿÚ?òÜ¡âÆ¥%J<ßÿÚ?òÃð+ó¹rüßÿÙvdradmin-am-3.6.13/template/default/default/fern_19.jpg000066400000000000000000000023601443716113400226400ustar00rootroot00000000000000ÿØÿàJFIFddÿìDucky<ÿî&AdobedÀ H; îÿÛ„       ÿÂCÿĸP !A3$4 1!AÑ¢3DQq2B‚C±Á"R²#„P!Að1Q0aq¡ñ ‘±PÁÑáÿÚ ÓïŒ! "qvX™)C6– d!dWŒv-fPˆ)# Hì^ÇÿÚóã×²× × × ÖŠÖ‚*öò‚¬þ.B®¦ÊÅ' î`€‡ «®2ÎB²;’ù®ÉÅJ­‰)ôµÜJ’¹Ùª`±qGÄÅ“¾nÞ¼?gºÿÚèŸÿÚèŸÿÚ?ÿÚ?ÿÚ?Þ:G6µ m4fÓUÆ“gRãI³©qdÙÔ¸²lê\Y6u.,›:‘"WT~Ô§Ð,>-âg{¿‘ÉÉÅ˽ío/±¯q´(¡{ì›™7‰ù5Õf‹C]žž 6rœ¾ñÆ!3î}´¯§U'(ïìÏ.rhpÑŸ»%4/ò}“Yêiuü×# ì¸Ç[s›Jãå!1¢+Du¶ÒáæÆ¤ŸÁº¦í¶6Žp6öt#£›!˜»ÎìN:{2;0 žß!Á÷®™t˧]:øÀ‡ ÛŠõb¿ÿÚ?!Y¡àf— çcäcçãçãå£ä¢xÑ0îDï-—U’1 NXvZ Fo+Ò–B&æetª,UHkè F¼ô@SìóŸØÀˆ)]êPìpåZ :µ *‹*ÑË´cÂÂþ¨ë´-ÂåbWG,-ª$ÌßÊæþÒ™˜VFS3‹LÌËþGðßîÿÚ?!á˜ãà(¸ßÿÚ?!ü'ÿÚ k%²[d¶Ù®i[õ¶€oÿÚ?RæP¤Ü„€¤'õ)Z¯vžô+¢¥eË·æ€Ü¡¼+~„ê×DBb =„&(ОÔ(‹Öy–M¬ý„BQD$T\€¬Ïþû]ÜÇì{Èà" ÑVQ ‹´ÐIVh)ƒ¬%%^„]DÔB~BI…I¡˜¢JhX@\Âíº’À¼Ü3½r¢TÛ«¾ x0`+3 ¿Åþ¡‰¨Vò&QÞNJÿÚ?‰Mô q"EÅÿÚ?à,@Š(G à qÇÅÿÙvdradmin-am-3.6.13/template/default/default/fern_22.jpg000066400000000000000000000020771443716113400226370ustar00rootroot00000000000000ÿØÿàJFIFddÿìDucky<ÿî&AdobedÀ LÊ}=ÿÛ„       ÿÂ2ÿļ !2#0$ 1¡±bÒ3£ !Cƒ“DAQ‘"r‚’¢„ 0@!ð1AQa q¡±Áñ0‘ÑáÿÚ è¶â˜¬Â­´9u»1Vë€ç^Ëþ]ÖìskõÀ™i¶ÿ–¯-ŒÖ egÿÚ}eŽJ(d´ÉhÛˆ»÷iU<Î +‚¿H @¶Oè‘Ng÷=SÓNOÿÚW@œœœœŸJ›SJ›SãÿÚ§I\b¸ÅqŠãÂÛ¹4´ÛS©i¶§_‡ÿÚ?ÙÿÚ?6.ºÿÚ?&8]ˆ€ÀÙ<»Ö+ܱib½Ë–#ܱmb=ôÐòIYÿÙvdradmin-am-3.6.13/template/default/default/fern_23.jpg000066400000000000000000000017461443716113400226420ustar00rootroot00000000000000ÿØÿàJFIFddÿìDucky<ÿî&AdobedÀ 2š+äÿÛ„       ÿÂ1ÿı! 1"03C£ !a’²â31r‚CDQÁ¢Â@  ð!1AQaqñ0‘¡±ÑÁÿÚ ×ä,`K×til\˜ù ¨V¾‡fÜ|˜ëÆ ÒµÜÙ¶Ÿy0“-qÿÚÈó"™TÊã3„÷¹ ©ùرbÅk£¾q"DˆÆè”¯c±Ø¸‘•ÏÿÚWP™2dÄvžÍ¬ä~ÖsàÿÚWP™2dÄvÚÞGío>ÿÚ?gÿÚ?gÿÚ?­i#áb®õ!ºx5 ÓÁ¨nž Cv^¡ZÔEi’Sîls«;Ô^å{)³óêÎõ¹Êl4ľ¾£Èš<‰£¿8wçTK¢D«åc?ÿÚ?!’¤Ae6Ý©ž*|4ø©Ü{HƽÃÓÚ…®Ô+™“­­­‰`dÚ D²Hý寧‡Á{h_,ƒT¬_î­«sû–õÿÚ?!P‰$D·F*æ?XÿÚ?!@‰$D·F:ö?ZÿÚ ¹,VI@¶Ì“ü¿ÿÚ?HK­[58˜îÙàB5$:¢-–ma-©¿HÜ>Ç»üÛ“kƒmÑ=<Ò<Ò”üÈœ+ùh¡¯Ãôȧ³[E{®ê„ ã%Á¡Þêÿ/ò ŠV²Wo.6§ÿÚ?iM·nͶm³m‘å3FR岡nðI$’`[*îÿÚ?y ÛvìÛvìÛvìÛvì…)£é©x·(Ãà’I$ÂôÿÙvdradmin-am-3.6.13/template/default/default/fern_24.jpg000066400000000000000000000020071443716113400226320ustar00rootroot00000000000000ÿØÿàJFIFddÿìDucky<ÿî&AdobedÀ =ªMÿÛ„       ÿÂ3ÿĸ!" 02#34 1¢â3£D !Aa’qá"2B‚²Âƒ@q!1Qañ 0ðA‘±¡ÁÑáÿÚ é9ÖC‘ežÂ=”Sè¯FØÅêùvQÏm~à“ÖrÀAiÿÚEê·XµXµXµXµX¸¹q¿ Àœ ÀZ†ü¸ÿÎÑ£F&›{'©©¸Þn>gÿÚ]X$ÉI’“%&JL”ôäûwr}¼¿ÿÚÑ£Fèžôù¿ÿÚ?gÿÚ?gÿÚ?šyaÝáWsa}B±}B±}B±}B±|ÎŽñSg—ܨCÛͺUÇŠÿÚ?!e11118M–|&Ë?ÃÿÚ ë,€ oß¶²OÿÚ?1¢H¶…è²E!'ž=vV¦™}#ÀŦºÞJºß”W#R:?ˆ‘Võ°ím;F€Ü±T.‚ÄrX–=®_) Â…Á¼€&U¹>m+p…¡±ÔØÆïÙ.¤µõŠÿÚ?á–à×…¸5áo x[Ã^øÉÔÎ}dtqê«Ò™Ïð&L™2›ª¯YŽÿÚ?1ËTa“f† >¤éÓ§RþÿÙvdradmin-am-3.6.13/template/default/default/fern_28.jpg000066400000000000000000000020141443716113400226340ustar00rootroot00000000000000ÿØÿàJFIFddÿìDucky<ÿî&AdobedÀ 1¸Z ÿÛ„       ÿÂBÿÄ·P! 3$4 Ñ3D1A¢!Qaqƒ ±"BR‚²4„Pð!AQa 1q¡Ñá0P‘ñ±ÿÚ Óï <‹BÄFR^ÊÀŒfe½²È™œ–5‘†ŽÆ‚_ÿÚëuÕ>] €¡( ](¥<©-Ÿ‰É’ïv„’ÏxpäŽI21Vèühi£Eµ â˜OÃco >ÃÿÚÉ?ÿÚÉ?ÿÚ?ÿÚ?ÿÚ?â*"’Ö°’˳^Ñ:& Ñ0¸N‰…ÂtL.¢ap ™F[KÜÆxäñ‚6«ìyN )·ž€]?P~k!¯N£×•—â G©&­âÚmíš•˜ˆYI»Þ O0RŠQH)(¥ùþ6‹íÿÚ?!ŒÙÓ0Ja‰¶0óŒ<ã]Œ<ã8¼=R“;s†u4Ÿ7 „iq&¿F$nï‚ñzä©£^Ï×ø<øëôf¿F$‚No0.§G·N¸›y@®›f¶œžf.…ªÊnQrÔ{·üËþGÿÚ?!öOÿÚ?!öOÿÚ ëe¶»l¶É¤²Y^ùlïÿÚ?Wu¢N+3"JÛÁ‡ŽÛ:óÀh$¥$ˆz ¹Ý%p3…ë$ßñû°Ñ²×sò;B§$t4èPWìûûbæÎÏȸ/T.Õ“K#‘„ÐÐqˆä@º¶É(Jq(?9«x¹…l~…’ÕcŠ3 u âSÅ_ÿÚ?‚ ‚#u±=Õ¶õ¿ÿÚ?$’I$䆷^äúßÿÙvdradmin-am-3.6.13/template/default/default/fern_31.jpg000066400000000000000000000020661443716113400226350ustar00rootroot00000000000000ÿØÿàJFIFddÿìDucky<ÿî&AdobedÀ 8Î{4ÿÛ„       ÿÂCÿĺP 2#1Ñ3C!‘¡"B‚D ðAa±2¢²csƒ£4P!1a0ðAQq‘¡±Ñ @PÁáñÿÚ è7àIYh¬f8 Êq²÷–xÜ^0t[X€‰Ñü¿ÿÚ¶¶úMc c k†”õÍ5Í5èIñÅ'©U¨I¥Íg2†áõ²Ri&•Ü«©‘"3I—‘"+Q ³ó¯ÖÏ#ÿÚá?ÿÚá?ÿÚ?ÿÚ?ÿÚ?qfµ$‰PÍ®c*«˜ÊjæJM»•§„S@¶sP-œîÐ-œé…¶ êkVªõO¨¥R›I­e2H8ã‡6ÏÄRÀ‡¿<#pÕn%ÀWÙFj–“JÓÈg8ä—‡´Ô¯ƒìO¥0¸à\ Ünà¿<ŸÿÚ?!xHÂï<Á#+]»þÚè·4a2ÛÅšÿ¢’0áÊŒx,ñ•*''P¸!*¿b„¹^hì¸Ç¨ "Š¿b«ö( eælHN›S~¥ðð2˜ØNm|Ù€$˜ ’³ÈÉÂA5ësàT1?.u §Â‹ñM™ØñŸ‡äÿÚá?ÿÚá?ÿÚ?ÿÚ?ÿÚ?æJ¤¢ä°‹XZ×]j™n]j™n]j™n]j™n]j™n]j™nDƬÜ}ÌÞÁps7(úÏó:{ØÒî?^˜F,D‡y=Š•Jù½´LhlÓS ½ Z¥hÅþd!lLœzÈ<Ê´Þd4ˆ&.>¬C£Š×O’ÚÛ.!²!…¾ú ¥¨³àý|®ÐvÄ0Ë-2™±¥ð&¿è—í½âÊâ51²\L”,gÙ^¼%%q± ¯â(Ï< T§€sðG\K¨Ú••á(]U€ ½óùŒyúíÖÖÃÏè¹Xß×\ÎîùŸß¾ÓÿÚ?©R¥J•*W¦ßPÒ„£ÞÿÚ?—.\¹råûgMË÷¿ÿÙvdradmin-am-3.6.13/template/default/default/fern_33.jpg000066400000000000000000000021071443716113400226330ustar00rootroot00000000000000ÿØÿàJFIFddÿìDucky<ÿî&AdobedÀ 9ÖEÿÛ„       ÿÂCÿĵ PA34 AÑ3C1q‘D!±ÁR‚¢Qar²„P!1Q0ðAaq¡ ‘ѱá@PñÿÚ Óï„s +êö'€­3²í,Dc$iKÀIÌÊ " ÐR;—ÑÿÚ·µ¬Á®®v1ë‚«Z X±ÔåüŽáYG{9' p©+R_8úÓÖjj¸·æ†ÞÒ+xZš {.¨«4\“GÝí—_Ã:þ% Š‘{Õ€xvã£+º¥]a3·¥{„æ»{@b•œ?Ò•³¿ŸÆÕô'øLk¿¦¿™ÿÚ?!ÞŸÇÿÚ?!þ“ÿÚ ûl–n¶Û¤ªYÕ–/ÿÚ?fàlg"óMPa´®A((ðb© ‚FLLä®pMô *¡é¿!ÑòKµм1š ø'èŒ"ë_ÑNæÓ)ĺ(+*O蜢_·7V[Á"CœÅ1 ¢l®’ºD¥&æ*1-Wus‘‚ ¦¬¶EJé+¤¡uV‚ùÍsï™>;ùðïý/bߥFÿHð!–;ã3…µñt©ÿÚ?Ü_¡‹Òm`VûÿÚ?Þ7]÷ÿÙvdradmin-am-3.6.13/template/default/default/fern_36.jpg000066400000000000000000000021041443716113400226330ustar00rootroot00000000000000ÿØÿàJFIFddÿìDucky<ÿî&AdobedÀ 3ÊtBÿÛ„       ÿÂBÿij P3$41Ñ¢3D!AqBa‘±2R‚²C4„P!ð1 AQaq¡ñ0P‘Ñá±ÿÚ Óïl‡-¥–"‰cšû1™–öË 99³7,k# šÿÚÆÇuõè! † h;-ö°ã?šI§)•ŸŒ¼fw#—dšI¥Š®éÇ/Ô‰kEJèeuĈø±¾§—wÓòÿÚðŸÿÚðŸÿÚ?ÿÚ?ÿÚ?ê:c›À6¶oŠÎ™†Å3 ‹:ftÌ6,é˜lYÓ0؉_î„<‚«ðõ“8»ìiêJºé°Å¼TMÖÈo­ð>mtÃrþ$Ös4ºðâcIDÁM—-·XÚ…%ÎØ«Iw½ ŸšÒ­*Ò­*Ò­*¯ñ­sV¿ÿÚ?!2YŽ µÓ˜Ÿ1›?¼iýãOï™Ã‚ÂßU'¼Õ6éHȵs¿ìËÕ†\‡«g“éç˜÷›'¾ÿïû3¿ìÁ(TT“wÌ £Ùñϰ¨#¸0–¹¾= 2•šï¦Wòsûq2ž{¯ñð?ÿÚ?!û'ÿÚ?!û'ÿÚ ém–[e¶Ù¥’[^é®ïÿÚ?få0ÝN¤U<=·Õδ»«¹ä¡`*ÑÞyúX/%ðÌè/øMÑ1ì ¼Ð"»&ùf˜Å¡™Py°kþ‰¯ú%ûsz²ý¹7‡P.i½"Êô•é;ޤ0‰„g+&|n¹µU´Êå̯I^’…ÕX ç;­?\ËL÷yÝs³³1­Y_ ¶e ¼æ>}õé?ÿÚ?©R¥J•*W °^€>·ÿÚ?ð¹råË—ÂDáxëÿÙvdradmin-am-3.6.13/template/default/default/fern_39.jpg000066400000000000000000000025521443716113400226450ustar00rootroot00000000000000ÿØÿàJFIFddÿìDucky<ÿî&AdobedÀ Qj]hÿÛ„       ÿÂCÿļP !2#$ 1!3AQÑ"¢Dða‘±2BR#$q¡‚sƒÃ4P!1AQq0ða‘¡ñ @±ÁÑáÿÚ è·‹ô@€åã›—H€œŒq¯e2É`„pÓPÄ1ꘊJt2ÿÿÚä-p­p­p­p­x­{-{.O¥S~Gi8Ho9ËÛ #¼vÙ ñ_ŽI8¦„‘ëüõ®Ü=|W–Õ0[9ÔÁ°3.ªãÔóª÷„%rˆ5ØpNko­cãµL܃,.± û¥ˆ!ì w´"¥™  €4€ˆ@2ÙJ‘­eF#È@iõ0‚iEJ¨øÄV‹@ .a èRq…¡¨QÊ6‹‚ {¡óxÚâ㙆;¤Wy)ABiŸ„2K8Cï§0ã0ve§;Vo€¨3(rg±Óü;åæºŸÅI4Ó«xCÁ^¢ ¿hJß‹ý¬ÍÇÿÚ?å¢Ýx}È«õ‰Þç»Ô˜i^òÓFXïºÆQ™¢ÕÍcC-ÉQ¼¸·bž£*p¬ðÇ ¤1DXå…… Ê7bÅì_ä÷/Ǩ1Dâ!ú—PÓeµ*eé€H ïõNŸÃJy°´÷÷“·µgå}Ìy¯Š]ýììºwUϼõ7Þ¥LÒøe<Ói|gh.áN€Ó¨øÞR$â°ÚK¯–Åw—ÃÚÈt~µå—–^]yuà/ÓzþWúÿÚ?!0A“65³?#˜ËGç£ó‘]LÀoä‰ç7OgDnG H$F! OQ(ÀA<`m#0©²2­ ?múúÔ£çªÎQª·]ã*®@h›<)ëD¸TÁP†dÆáHZ5„TpÅŠ9˜!hH’‰RÎ\Apr+¼e{¡6à uY½\K$wùþXí-©ql׊@*E†Xw„HÐfnýp–xšü¾‹}¾¢_Q?"ÛúÌ:ë?ÿÚ?!å>8ãû_ÿÚ?!樾ÛÿÚ K,’#•xÖ}{•’A/ÿÚ?$Z›"MØH „¹™Ý4¤Ùà»dðd’gY)  0ã´]ä=?²`4,fã‰BðIE© qر…Ï542µÚlÈB˜ÅkvÔõσ(Å…¬!´ûò2¤:¼#„U  4CãyröÏDDXÌ0diYŒpe9n àdáb3>lÐØ t\{œ.i: ÷TÂlG€$XP#´ Æ›a쥵M +Ô3CÆuÏßÌEòñwºz_øPÚþØz¼f*Ø{¥N©ŸGe?ÿÚ?ä8Oú (¢D"â9?ÿÚ?äQq#ƒŽ8ãŽ>gÿÙvdradmin-am-3.6.13/template/default/default/fern_41.jpg000066400000000000000000000042031443716113400226310ustar00rootroot00000000000000ÿØÿàJFIFHHÿÛCÿÛCÿÀCÿÄ  ÿÄI !A 12a#3QSUX‘'CDb–¡¥±Õ×áð"$%&6BFRWe•ñÿÄ ÿÄ,!a"A¡ð QáÿÚ ?½¬¹å}ã0ð3®¬¶ö]¨zW‰$Ý¡†Û«‡¥ý͘8CÞ,[1‡Ì+¢‘·:5òccêMÞ<±úßÇs¤¾h¿ßÙÿ°ì*z^ÇTkÒ?4_­Øþ¡i>B­´AÒG(Ídؘ V±ÝÝÒog› @›ôÅ'9)Yh54©“ ”,‚  ŽPp€A 0Óüf0›ˆ®`³ÆZD ˆIºÈR‘wJ1¡*ZÖµY(M®¥^ÖµïU1böMë8ØÖn¤$d7bÁƒåvõó×eCv¬Ùµn‚˧' ÂݸF²˜«@Æ…-IMÅ Ù7ËíÒ9Á=ºÎ­ð¸4„ç@Å.’¤·!­-¿”jÑjÖÖ ½wQâ,ÁÑ1‚ ;ŠPU‰„¼L®ï¥ÉÇÉlmïð¶y³»¯kwŽRmîm“F¾Úö×§¾›öï²L5ÃxWËñ £õO§þ䀕ƒçðö9|/ThוÅå5äÜ›néÞ­€gœ/Ò/4]µçe«ù=§þŽÜv5‹Öœð3)ß³ š-•Ûû[jþ]O®¸R˜e¼ìq(ÛìŽ/¯bÇævÕn ¨î´ Ò­RTzâ4oãVþùÉîù.MÛJtW P Z8ñ ''E'…Å&Óš¯¾–`ÀÝ(NI»|!D»€øA®(ßöû´©³ÁæŸÊ|=W—ŸæAÝ=¼ù£Ò¥¢É$]*T×.úNôé*í÷›~Ý”ÓÙ‡ÛóÚ•‡ÎÈ—œ¾gwú¿ Uð¾æMÏxÅŠi´r…G§ï)ÈzH®Rð'ù;crgáª%9cga%·5 )») ³ê§uÌÑtñ=Öi©[?gÜ1„` ôÑÔíØ†‡ Õó·Sk"çUÊmÒ ·íôëéÎ\k!꼓 ½Íe8Œ;·WI›AÅ ó§1-ì ñ¥eo8å‹ù"®G°à¶}4™j¤³â[`®E˶r3I@¥(èrcÖ5¼4¸TîŒOmƆ…/jq"½É…é)Z%E¤viVÜöÜÚäQAÌËãÒ ”Œ2„à7ì¤-ZÀä7RnFÎ…e§u¹t§R{¥hRP`¬GŠ~u3§˜W1 +5`§±/ô˜A}™HY1 ˆg7ñm‹Â•c¼[·[¹nW1Ò-žÅ>~Åϵ"¥QÀHV® 8‚¨€7:) Pioxé)gÖÑr¢NtÞ 0ëˆüÞá’69éÙÓ£n8¼Þ÷÷íío—¿×Íï¯?›ÞŠ˜ÜÓ+È×÷ãšž—4ÊòõýøR£~frmo³=2+($†WÄ%žt"rKQ ]aÏj˜ÐQU9½BæWBЇø¹ŽF¡X…V¼äÈ£¯,ØÎa‹Çåq×dï°œ‹RØ?l£±2¼)I·{n€šR—M¤ŒéJ{,.ÝÈ77Bzá–ô/.E*ÏâžÜ-²œYÙÖ(Ì’0JR’"­(7U–é‹ 6 Äc‚™ è§ÒÑ2Qw-|òÅÏAqe“ÝǦA [H² TAª0ð”ð¯ç2ÄLdµ{Yiȧ×Ó'ap£“ˆÈPúŽ:­‰ôµ–7$™Y·™;m `23⣤®ýÜÜWpåNL;Ù7jEíˆîá#)¶ ×u×ã‹)ê®"¼/ÆÓ¸¹Kœ9C–¹ ç%'#„!¡x˜hOJ‹sÜö›FåÌÀ.Õºm©f2ögX ZˆEPBkQ ¢ÓZÖµÓZÖµšÖµÛZ×mk¯^®9¦W¯ï”+0¤^x–Ë\›XXXS+prrqV"mU*=sߘRªžÞ·/`¶–©‰Õ8Q:2Ú[TÒäŒß ‘{u½#X˜Ý¾…˜Pþ+…QLS Kkߨ¥Sý¿ˆ?œ‰Iú_£í¯`IÇ­ïú±.‰Õ’Gî¼Q`ã?ºÄô 6È`lõ°OV ¦ý›)»Tô+ù³ŸÚkgñ-õV¡UÖŠÒƒ©jí z:°( ~†ŠaJiShí@+ù–ÆÞ§« ~Í”ÝøÓ…)]¨µ ê[XzÝXlt>?u1E)j-nßkXïäØïoøì)G‹onãÏí®lP([C’e5ÕÜâìiV‘´^QHBy]ê 8R¦|@bq"\ººÒµF¸œ¡AÔ Ì4Á9¬Ò!V´ÙJS@BRh!iJOJÿÙvdradmin-am-3.6.13/template/default/default/fern_42.jpg000066400000000000000000000033261443716113400226370ustar00rootroot00000000000000ÿØÿàJFIFHHÿÛCÿÛCÿÀCÿÄ  ÿÄI A !12#3Sa‘ "CDQUXb–¥Õ×áð%&'6BFRWe•¡±ñÿÄÿÄ/!Aa1Q2q¡ÁÑ"‘±á3BR²ðÿÚ ?Ý­\õ_˜Ö†¶U¶æÌµOk1d»ÄCÀãwtö¿±· |ÃÇn4û€ì ÊܘE÷22ó&ïìŸ/[ºã/­ùü?ö œ^·Ukã­Î,Aö? 6_Õ×UŒ1hæ{òæ1^ÁÏT…gvËx*²þe³5Ð3õ°–Å)ªí¬rîLÉÇ6pp0ˆSPÅÃisõ2“|½ uþ'h¦à¼)6eP8+Éló€“P¼‚Ê7WjgÅàp⪒…ìû!/¼b‰L8ÏO_'ìoÙb:}ž«¨$¾V n”Íj5³Ôìñm& ,·|Lú.^-úE]£ÆNÄ&MTULÀ=LÀtÕ!!ÈÇe81èj†ÖZ.éý-ÅïfÛéa¶ðsÁÔ«s¶:¾~Í'¡ã]ÈF³ÈÔ9Jk·MYóÆlæÖ±ý>s¹òû—fó€u€@¨NØÉÐèÓŒQY»+=.©pfÝW~·ëCtUéñ‰#.Båt£·ÛËògƒÍ¿+ª}=×—¿ë±n¾­d3ãÿ6i8 G–J»WÕY/ Žöí:óûŽ?§ 6ù´y¶¾Ê—Â_CËý_ ¢ú¤ÙØ—-RŽÕñ\µŒÀ"cGK$¶G vÑÆ ^1رÀ(”Ç.)Ã¥ÃWÂWqR›7×ðUÃ)Ãô¥?C™Ä]D– L‚DQE!Ê4Á%D€B¶dª‡kÇÒ]D™&åÒO7¼ðÖ™i†ôí¨r¯¦fžÙR›ÍS‘÷HðÖþ–½,¾Š\¶Šº:‰jŽ’Ò³'+ó1ž¯ÆÍ‘§.÷Ãóde»E[Ûy$ÉÊ~ÿIÁs°: ‡±zû4JÀoÙº07iA9ü‹aÏé63ù‡Vú«@"¯±%'cãBõvhUBÿȀЗ8}†1Ç…ëìÒ«Eß³t`nümÐx£“±híviµÒûþôpi@x£ôþ­h¿ƒk¾íÚ8¬c|w^Ÿ“‚¡Râ$›9o!Wƒjõ“x—I1*éu`åÐ> sH×™>|<éÛ¥dVpá`¨ª†“y´Æ€ØR” BHB”¥ ÁÿÙvdradmin-am-3.6.13/template/default/default/fern_43.jpg000066400000000000000000000037741443716113400226470ustar00rootroot00000000000000ÿØÿàJFIFHHÿÛCÿÛCÿÀCÿÄ  ÿÄA !1 A"#$2Q%&37Sa‘á'5BCRUbq¥ÕðÿÄÿÄ+!1QqÁAa¡ð"#R‘±ÿÚ ?;NY㹉¿å(ÉuÇðØþN­«|~ò ­’fn×H®dW²ßÚ!mpåƒe o…A²M«Š? $wfLè&—Ù½ùÈ>#Ôù:¯—NßàÅ õ&aæš?†Cù«”ÂC”!”þ‡S1Ž¡ U:”E M&éB,‚{4iDÑC˜Žhˆ _6b± }ÿ¡ý{µØ7Û‚*^{9(Q”xë™>gÛ7Gó‹)lÅ€TÿÔ:ÃÂ#û¶!¯wH„y:ÁJ¥^!Î70e Š.8‘‡††>ô3.mhW– EÕ2œÅz5ÜÜyc–YUãš¹zš"‚J)Á–³¦° €—˜þhôa9ÄFɈ”1Îc ©ðÿZ…!„S)Íߤ€î®þÚñ{™Nhˆºó ßú_öÛO²¦"¶ãÙãV®>-æ[™RÈH,Ô–•Äï¢> $t‘xÙ–$‚‘ð–2@GGa1ãà"äÏ`.¬±ß€‡KžR‚Zn²2ì^/N¶ÝhïÝ>vd×q+G·ÍÔ¥Ö"kCʨVŠJC<4xA×Ô¶”éÑJVˆG.c1|ÎÖ¢ªu ”©mœ&?˜]ùgåìâ—oï6¡‡Ó]"P÷pYѺ@:lU¤L¬[³ÒµUƒç]úJ"¢j5jºeLÆcÀJc @¦(‰o›*_æ_ðòÿõüF'ÛéΦs¤¼‚å–¡[²cÌ=’jc3/–¼?€6ÌqCõ;Ÿ$Éû ‹€”!äËv—øð åð Ok.aë1C@$Ô“kÌÅ Â 00säO÷òNˆpû;9žÈÃÚÈ|~J´ÍW Ջбµm›iDà+uª† œ¬™ëHa+·„±Ù›ÀE=¶Í¿LW‘]œSF/®ÇWêõ)ÃÄÍÔ¹¿‹O£š=ñÞ߇— ÏÔ8~Á:ûÞŠržl©‡a•ê1@ ?Š%ÇB/oêÿph›êlE;ƧBWž.íø è[jAÒa’8M°Ô\ªIï·©Ôð€{wê÷k}µÄ/Ô¦oð9$Ef &íÒ>=h§Î#¿¡@Jn‘ ˆ‚ 7 ÓŸvÝmçÞlƒ›„ž1Ü˧îÖ~ɸ")ª'âÕœkÞ0BÅ%z¢ÝcâvÍ'ÒU ‡ªHJ¶A_¬¨Ø©68Ð9>Œ\ƹ)~q Á[î6ä®ÐN¦Ÿ†Ab”ý!ØKÖ`(÷ÐŽ„eì;ÿ~ ~SKõþ?Ï‚&k˜^S±5x~Ãóml&éVí›æ Ñ¥–hn“ÔarYt]) i¯•ò«¨³VÇJY³ea¬$›®Øå+®3u8?1ôÝÁ£(“R)Ä  šI¤ õÃêƒLÍ-ZI‘§ò¢ë“k^ÊÜ9]È<˜f†O>.Í\«ãº®,·Zak±ì£³õV‚—Å.UöÒ_‹­°ŽK-dIý‚Y¤1$ésÉÎÅÆU^€pñþ$Ap æÌØû‚H‘Pr’Ó@a¤×f‰8yvˆ¨±ÓÈ­fƈ‹ùMÐva.„ÿ0¢U:þgâJ¯‰ÐMuø]!áìw¾ÿçð}V6XïÀ^òš_¨/ñþ|Bµy$šÔu6íÛHÈöMÌâAË×-Ú°+4ST\ꪈ˜H“s*ᆋâ"nûâ 7¨Ü «,wà(àÎÅ –ë”­QFtæÝš3m¾ífª/kvÜ·t±×$¦þzo äãݰzúñ”LVýà@¤ÆÒwVœ¬Ÿ o:±v¸Hk,tu‚a,çâc¥Ðh¼;7Z…ÞÍ#öJ¯@ôâÑkƒâïäÚƒ¡Øy:»¡Ø›{‹µî·Hb\UØ>L±è€÷]l@{ë¸ oþýÜr}ÆÜ”[tñ&%¸Ü@CcÕE«cÔ!êh¡@!©žÃÊ$&>'Æb=Zߪ¡Û¤£î‰õïëÁ†;áUˆ&Wc#ˆ(% Ñ*þ€h"À?´>ïì•q8+ #"š­ñ&7h»T~ÙÓ:Uu“ÆÎ’\ž†ïÇ"éSÖÓ:kÄ6ÌQˆò}ÆÜ•Õ–;ðíP¬=–†€Îº=B".V1„Laß­ÿÙvdradmin-am-3.6.13/template/default/default/fern_44.jpg000066400000000000000000000021071443716113400226350ustar00rootroot00000000000000ÿØÿàJFIFddÿìDucky<ÿî&AdobedÀ 9ÖEÿÛ„       ÿÂCÿĵ PA34 AÑ3C1q‘D!±ÁR‚¢Qar²„P!1Q0ðAaq¡ ‘ѱá@PñÿÚ Óï„s +êö'€­3²í,Dc$iKÀIÌÊ " ÐR;—ÑÿÚ·µ¬Á®®v1ë‚«Z X±ÔåüŽáYG{9' p©+R_8úÓÖjj¸·æ†ÞÒ+xZš {.¨«4\“GÝí—_Ã:þ% Š‘{Õ€xvã£+º¥]a3·¥{„æ»{@b•œ?Ò•³¿ŸÆÕô'øLk¿¦¿™ÿÚ?!ÞŸÇÿÚ?!þ“ÿÚ ûl–n¶Û¤ªYÕ–/ÿÚ?fàlg"óMPa´®A((ðb© ‚FLLä®pMô *¡é¿!ÑòKµм1š ø'èŒ"ë_ÑNæÓ)ĺ(+*O蜢_·7V[Á"CœÅ1 ¢l®’ºD¥&æ*1-Wus‘‚ ¦¬¶EJé+¤¡uV‚ùÍsï™>;ùðïý/bߥFÿHð!–;ã3…µñt©ÿÚ?Ü_¡‹Òm`VûÿÚ?Þ7]÷ÿÙvdradmin-am-3.6.13/template/default/default/fern_45.jpg000066400000000000000000000034061443716113400226410ustar00rootroot00000000000000ÿØÿàJFIFHHÿÛCÿÛCÿÀCÿÄ  ÿÄJA!12 #3Sa‘"CDQUXb–¥±Õ×áð %&'67BFRWe•¡ñÿÄÿÄ,!QAa1‘¡ð"qÁÑ2’¢áÿÚ ?½­9é|Æ¡àw²¬·6e¨{SI¸€àq»¸{_ÔÙy‡Ìaó ðPäl÷0`?È›½¿`yó|z]À=òú¢ÿ?‡þ£¶‹Òê{ãõEñ‹}OìD“Cx¢(ú6"GªÝFˆ)40øXcéÎdBDIˆ×²B#‡³¿‡×Wk$kòWš0³zõ¦,œº¸”زµÐaš Å'ŒŸ Õn¤Ê™Š>j*H5¼×_|“ÐA¤í”µk/ŠÍ¯ÛÇ|áûx;â 4ð0w’d"§^‰ôÄ`»>1&ñ•‡/A}{(=0%ÅÛŒ <% tA»—irÓÛÿM4Òk ¢Ú±–Éa*J’H†QÓ&½ç?qË•‘/t¾G/ô~Ù54žD8RX߸̹f×·9uMÞNŸ.ÀV¦ MÄaœ"ŸåÂi;·c(­7óîØ — ƒiŒ>:´I·(áó|ÇIH~6˺9S˜2Â7ÇûžB+$O‡›§ƒŸlp[}ë²ùo®[}qŒnÝÆä¯Ÿ?Û¶IÅÉ;^!>·`"6­ô‹õ ;E2ËÒ¶1ö:Ë£2L–2Ò˜8È#Äeb-Á]²õ£èÀcd ‹{ p"É‹`àîBzÜËN\ä>,t\i¥yÊ©§„“ºÒú¯™%Õµ·--óvëø¿Ï£ð11WcËc Pe[0Ž q“fBà°Ü`Á¼x¨®Ÿñ´ Â1bã`#{CRY#8㫯ŒHGƒXk` Ëò5Ë'|®‰ÆmRáÅB7©7%9]ªÔ¢›MJš”eª/J·Ú|„Zwm¶ëè’Íåï³ÝáLJŪ©U°ŠUKZ¸)è}Mª©)R“DRâÒšÒ—/zVúè«ÊBº¦—7~Iy$¾Äí¶Ûb䯟?Û¶+0¤^1-–’ÎÈ$EÛ6¸«V|sÙ›TøôsðÓ*Ý,Šĸ¨I&w|+Gã±ìi›Æ×yü%‡nZ_ÂEv S K‹ÏQË£øþ ~ó'7øOGÆ›CNÞ÷¿ñk%»³c·zïj¶ŽÙûþ‹iÀças'côõ`‘ŠoàÜ2›¶ œüKaÏé63ø‡ú+`_b,Jަ+ƉèêÀ¢‰ù„S`\âNëË©oôbàM¨ó Í _†…ƒæ½+Jº´)Ïèuµ)N!AÀ§ee @ „„(Â+„{40¤}‘ÌG4I¸O›4¬·ûhþßOËq± pDÇ<—h 5#äú9Çסª¿PÓխn:íJn¤Å¯^ Ó«êÞ¸¥M‹ð‹¢ìáªJL„)dO6}8ÀltóÍÊ+^þdÒ'RÖ¥(W£ýn% %¤­k¥>‰Uý¸ò{#™Nh=vóÏçýJ?ü㟄z¨Šœgj"È5¼Ës*›¥ †åµ¦”N¨÷€óKi™±¡i‡„òÚ’¸²=ÈÉGd€Z³#ÏA8™ž©Q=wŒ›x3òÜן*tµ6ü‹\/»Ä­ÞCoSÚ¸˜ŽZSLUxU„¯Ô mœéÙ)+D#—CqQžë¾AT—ê5K !¢~åöË?/k-ôswOmºJGΈ~iA*2^±.ÕËQûØ®À+¿JIqEŠûaµR¥…‚…(¤%I$Š÷͘—ö—ù=¿ü@S\õR×O=¯‘¨zm§ù>³eø§³BæçÓ<6±òLÊ»Q×!uuÂÑ0ZË› mשׂâË®Æ1|Ã#“UŠ\äâ‰"@¹H°}Ž¢ÐÊê`« Oüöó~û 9¡Ï9˜ö çúÍ­ùI¶É/´PâÃŒÌkWh±Š&òüêÌWªJg»GŽWH™6CQ&½ñi–Óî-oe^_O³Êoù¿LÿSì[òõ§ø´Äãÿ gG“Ö±ºÛ·Í˜˜ìm:ŠBAþH¸;”žžõÿ@GÔúñú2r"ÚÆæö'ïÂໞ‚ï͸’vQ²sd«¶Õv­7¿cÝnWø}]½}¶úmį©ÍÜì™/Ay¹l>Êö ú%eµ¾Ì°R®’“±I J½þeÊ-mïæÚƒ­ŒŠ \Çs,‚ÿÚý©¸")ª7O#+×b|È dvYÖ ›WÔ;.Slñ ÑìI‹Xì<}áqG„äU¡iû³"¶JGÚJø+~cŽÊÍñ&ü4ÂRR¾ŸB€°{€HÇbúïÁB÷å6ÿpƒëê׿ûÿwæE‰qù*Š×<­óžÞpôgËÓzœ¬p'Ýç¯8VQç–²¤d¨’ê¡Wo Êv(êB9—ÞjG8:§D8Á¥µA"›I¦–’óçX¦%¢†(l2õf6¹:çð`òe2“Ù룘9VÜèéü$áY®w§yv!ªx%E\)fYfE}‡äljl!ȈŒw(z¾žÞ§2¾ÍŒ¶bá_ØFƒ”y–ç!Ç ÐÅqˆMU)õ`8 ~Ò¡" ¶ÅÄ­€mư|ZA¦Skf?”ÙìÈ;% ¨§b½Ò \ëÙ7Š‚—CØ/Âéû½Ïsó±Ÿër"Û{®Fdyè.yM¯Ü'üïˆV«4Ô\E®åˉY_ …HŸ&t¨ñ "(tÉ\×]=E ÇS²HÙ># î <\†fsÒÐm~µZ³#ÏAk…{Uæ\×T²ª³.M._­:Û˜ãòÙ÷'Y›åº·šdxäöœïÖÜê;:ùh;þ‡‚bùëñ&8“ʵ%j…-&\ãÕY]%.K][\3õMu»LÇÝJDøÒiCެ£§n€B²”ŽÖdyè.uKÒ=)i@7¦xB¥æ~€Ôˆó"×3)—šÛvÖÓÉRêI’r~cŽÊÕ™z v¨Ä1„W²”Ò@Ø*AîÏQ$Éx’T¢T¢I$’I$’NüBµÿÙvdradmin-am-3.6.13/template/default/default/fern_47.jpg000066400000000000000000000030501443716113400226360ustar00rootroot00000000000000ÿØÿàJFIFHHÿÛCÿÛCÿÀCÿÄ  ÿÄM A!1 2QS‘"%3Ua¥Õá#'CXbq–±Á×$&6BDFHWe•¡ðñÿÄÿÄ'!1QAa"q¡±RáðÿÚ ?Ý«¹Ý}bðì9ÕUÛ[*Ó<ªÃ‘MͳÊþ†¼ëx3Þj`—£ûɇO°<ù<{È {Ñ£ÿqÖ‹Øêm|#ïEôŠ}ÏØç…Äé{ ¶²íy^¢ò ¶º cj ËËz>––’–WòÇN£ù‰ò>] ©Ýzëé-º~ñY¿Mg$Óªª É4ÕÂ~©Qi oe5xxéd['b¤âY\Éø;¢ÒIÇ6)¡ÍÀ vg›,?ˆ»ÑHƒ²•ü»=Çþ¯-€ã™ÁŽÃ˜g^ô[oçm+ÿ9(þ^Ñû, ·ƒ ¤Û]qµ«õl8¼ŽšmA4@Vaª3Mš*O<&M`›jŸ³—4z†:-Í“p€nÃ8AM†Æ\%*ibNv[MàL¼ã`dx·ÓäÍÛá%IW‚þ4#j<þß°]®2ü­ÓÙæº÷õàòNߺòƒýÿ™-8-¡Ç+\¡ŒÖj—¶ÉĹC†²ãûvÝ—ÉgÇ÷`qëcKÆ^gWô}€¤ü#n–¼ÛÞ¢T¥.ZlúSyô¬nÔ7oÑû<‚8ŽëcYÌJkŽü6uðù^Ëé˜ó\ÖÑ?øsÉ\iuúèS#‚0‚[dÔŒé`F!ãñ¡ˆlpAÉA*_uˆFÜÝIéЯéuÌ»&Ý8»I%•e)»¶æŠiJßå·Ž‰®aõŽOKÚØÒñ—™Õýn¤BÖÆ—Œ¼Î¯èû ÔUÅGa} @™’H¾ý“A‡@|ùljÑø&ÃF(Œ9x´BC€î¦MPÇnå\Q8ÕØÑéÔ¥"ÚÆÏ{Ö0t£ç„´¡Mi¬àÛÏ ø½AªäLS˳~M£lh+¶ûÇeé›MÛ}mkrÝÆÕ9]D=¾»dœZ§+¨‡·×`!ûÀ]Üx¢uRÍXÕYU9€ìcÉrè)«Æ µrk ¤Àþaž ž‹Ò=±®çlmnÓ~íUÎvŒ¨mecG+Ýý%åÁ EåC®EFcª1'…Ïj~Íp@Ä”fmF/I› ž¦=,$·¦»ÌMŽ|&$Y6BaY„¢”Y1i_˜¨¥UDlu©n¤OSl%³vÛnumÛ UC®—¸Þ­EC«w\COœvåÝ,¨4[TåuöúíÐÔZ§+¨‡·×`^×a¶–®Õ$ÔÇ””M“([5*Lo9öØ §§©§Ð)¥*BU/ %DZKJ’T‰Íð¥¦ÓÖÑ3…¦mð’ I™*?ØP1<)-/^&WéûAÁ8‘™ù˜¯7ÓVà)ËöüÚJ¡srdrÞûÉKƒ”ý~5§š D Ù¦†Þk±90L -A8+ø£ŸÊjgô ­è«*z‘RX9”®šC»šÂjCõ$€i3HéDÜS yþk)µ90L ,ºQK`æSVîk9»OBpZ€)t¢–í÷5`aûšÝòÿN° ŠoN۫ɪhL&ZB‘c#›¨'µÊ‘¶/jQgÊÜÈá°Iß&é#çÀ œ55Fqƒ€#™6dJ‡rňla„!‚†!†@pÿÙvdradmin-am-3.6.13/template/default/default/fern_48.jpg000066400000000000000000000033341443716113400226440ustar00rootroot00000000000000ÿØÿàJFIFHHÿÛCÿÛCÿÀCÿÄ  ÿÄI !A 12a#3QSU‘ÕáCDXb–¥×ð"%&'56BFRWe•¡±ñÿÄÿÄ*!A1Qa¡"q‘±ð2rÁáÿÚ ?½¬¹å}ã0ð3®¬¶ö]¨zW‰$Ý¡†Û«‡¥ýM˜8CÞ,[1‡Ì+¢‘·:5òccâMÞ?°>|ï÷sÊ_4_ßìÿØvæ{ÝQ¯”~h¾‘Z±ü.ÈŪƒ7$s—æ¯1Ñæ÷)Da§YÅžm-kì•Ù+k jªÏÔ¬qyX‘µ¥± Vµaå’AC°Dÿ%–*×Dž\Ìãf Nj$çJ%—ϳ3§=Å@ $Õë-iÀjÅ”åÔt† k\`Ÿƒ~à‘*ô9’Ìê´K“­"´òûRi R©,§<ƒAh* 8¡€ÂÆ Ô#¨*l­0ƒ81àfS¿f4[+·ò¶ÕÿO¦¸[ÁÎǾÈâ÷úö,~gmVàÚŽà;@Ý!ªÕ%G®#FðŽ5oáῒäÝ´§Ep Z8ñ ''E'…Å&Óš¯¾–`ÀÝ(NI»|!D»€ùÁ®(ý~Þ?Ð;<iøÜ§ÃÕyyþ`ôÓÑ™ Á÷ÿš18E’HºU©®]ôéÒ,UÛñ6ý»)§³§ÎÈ—œ¾§wõ~¨þI$iW%â%;€O4É%¡(6×rB"Ãs"ôp›„ƒ¶”©• h V¢¨kJh¯TëNnš¨IÓ­£'³þÎþ™[®ª+ë‚‹;ë™lÈBïDnU$d´R‹#aÌRâF©¶Zà}É‹* Z°k]#¹l­Fõkë J28'6|öß-xn]It5ô–2Ÿ:Í>yçœt½ö(z| y]ß<ð}Båq@âa–4ÅAS’ö iiZ~Ý\YKá}ˆ§ûåü¥÷a/;"^rúßÕøÓÉÄî#㤱?# F¥/ÃnRª›»:{pjZ˜ 3dCü6BÍvëe¦ý»°—FåYcg·E9&ç>oxé)gÖÑr¢NtÞ 0ëˆüÞá’69éÙÓ£n3Ae·Þ»/mï–ÞøÆ:·@ãsL¯ O·Ng4ÊòôûpÓ›|œÆs{d^¬D¦Hí ŒÊä¶õÅíù¹"‡ÒZ"Óxì¥Ù½—^8„mŽŒMMíî })K™N&²¹–@’Ǫ\ppTø£(»uÍMlžøxÆyµO};á’o­ý)öÙó2¼–òôd½VKma­¶ß#MM l©*H¢H´¹šhpm1ýˆr'é@ÉrLòþäè|‰ÅÖ«¤J^Ÿ SN0Ñz0ઊjå.$ÛNQur«Q¦ý®2âRig®®ºR¹r­³Ÿ ñ*Àæ·ARµ·¡l °˜Cr4¨I2¥ñ5IrÇRjzš•ݰ‹Šªƒê^žãŽ7Gv*¤®®•Óµušt­w¥ðŽO-¾­›œÓ+ÈÓíÆ˜ Ì)ÆÞ%²×&ÖÊÜœœU£H›UJ\øæª{zܽ‚ÚZ¦'TáDèËimSK’3|*EíÖö4bcvøBaCùÀ®ÂÒÚ÷ê)Tÿoâç"R~§WèûkØqë{þ¬K¢ud‘Ç|/X8ÏÛî±8Øk ³ÖÀ==X$b›ônl¦ìPN û‹YÏå5³úõV]h­(:–®Ú£«Šý4SD©´v ü coÓÕ…Fƒ¿FæÊnûéÀ íE­RÚÀÖêÃc¡ñø›©Š…Ú‹[·ókÝû›íþ€#ÞÝÇŸÛ\Ø P¶‡$Êk«¸7ÅØÒ­#h¼ ¢„òº)ÔpŸœcÈ—.®´­Q®'(Pu(3 0Nk4ˆU­6R”І” @BR“ƒÿÙvdradmin-am-3.6.13/template/default/default/fern_back.jpg000066400000000000000000000031701443716113400233070ustar00rootroot00000000000000ÿØÿàJFIFHHÿÛCÿÛCÿÂÈÿÄÿÄÿÚ ýSïxÿ<ÝiÆ [·Ï\TIÙì)‚ …N@w£q/´æ†º£…q‹5Ú'¬4¤«ñYÁ…3¤ÌgïDE;cYæÚ›%8ÍÑæ€¹ÓÂOOo” Ë 2´É8Í+ÞÉ>?ÿÄ$!1A#234ÿÚâ2Ïä,„Þ¤­ÇLœT,=ÔR%èNFަ¢£ÈÆÑV‡•ÍÍ›JÄlj ¶Œ/æÏ?O²Æ.ÆìŒ”Å6Lådª¢%ö¦Œ©c‚±ŽØúƒT9ͯO6˜YøŸê^qAó>íx¡•ý«’/—¯UõÅûÿÿÄPÿÚ?(¿ÿÄPQÿÚ?ŒÆÅÿÄD1!2¢ÑÒÓAB‘’“¡"#CQRqs‚ƒ£²³áã3@abr±ÁÃÔâðñóÿÚ?lPÁª5"òoK5`, ~˜Iêl„:~1 HV3:ÂK\=¢CLáÍ's…F}(Z,ÇñÑPaåš‘±ÅEare`äótád;YYu6AÝM¿ÆeXHVV[æè’×8sYá‘j‘´Ai Ûfö‹¸­¾àqΠFžq$e˪ÜDk˸rò½àÒèÏŽÒhŒ¦¢ žn¨“9€û»±s»»!ž–!êÅ]{È8ð@-»–U¸qåÕn/‹–‡æ‰xâJ°c¸Êñ‘_ú©¾5éù©øØï‰éÿÄ&!1qQA‘¡±Ñð aÁáÿÚ?!I¶‚‰‚Nú:‰aÛÏ2}E!¦&ʆø-"9*˜ŠÏL‘=ë™ÿŸ¦J ¶å5®Œ¢NÈ»Œ•íž'Ø;“§8ÿïŽùäFê…‚µÓI%sÞ ‡QJä²[ƒÏrÍŒÅëF“¿GbÙïNç•h%uÆ`Ù>Sê£÷ ’ìT7>×I3þÌw› RÐÉ߀±œÚÝ#]Ê“Ÿ1(vÖ«–ølÿZ/-kP´zé¢ç«ë¯ËPôå ßÿÚ „:'ÿößpAá¿}²‡}Ѽ×À“¿–ý÷#4ÿÿÄ 0Q@aÿÚ?á©5#•1²ð1G Æ÷?ÿÄQ 0PaÿÚ?bàÅÚÅÍ‹±‹Çƒ¥ÿÄ%!1AQaq±Áð¡Ñ‘áÿÚ?„zt™…aB-lH#‡–8 ê(|£Ž]tÎi'zPzR£eˆ ™ÑÜAÙà`a¢ý%¨³“Ó,À[™ÐNzQƒ€ ›3Ž’¬'öfÐ ‰4Íà+ë4Š3q£A ͉°ÞÜpe CÌe ÁiNÛ&ùÞ<•Û)u䪲)Žcp·|N%^¼-¾‰ZU§+Úñ-I§ëÂùð}Ü­þBŸÚ'EzÿÙvdradmin-am-3.6.13/template/default/default/fern_mute.jpg000066400000000000000000000025151443716113400233630ustar00rootroot00000000000000ÿØÿàJFIFHHÿÛC  !"$"$ÿÛCÿÀC"ÿÄÿÄ; !1"“ÑA”Ó2BEUaq35FQVbtƒ¡¤ÿÄÿÄ+!1Q¡"2Aaq‘ð3ÁáÿÚ ?OÙ›oë|™;Ö2·é׆Û@«Xª³z°#ŽÖ_³Ÿß®ògû7âÃøZ«¡‘„Í¡õLÌȈŠ!£î»ïœ¯J:ûˆäo[Âç6ýŠÕ©´­$5òpŽè˜)$ pUOÉžuÒ\ RéóâAøZôtÖþðgþ$?…¢TêýØøeÚkÇËÛ»PgrvwÍf|„ÌÌÏmíT…SÊ$@ _Èõ'*B»»ñÕîý3ŽôeY%­æ“Û”)8V^çb¾é‘ÈÒ:F·©JlÆÒO!T¬:sTzn,øÿ’ÂÔüžV›“p|H? Fï×|Ý–°q´±2Š{ëŽåîVO,£™ˆ¼(G ëÝÞÄñØÜ–[©I³&NkÒ`®Ä›Z=Õ^´¢ÂAg>ýWH¤OmÈñ̽ÀG¸’¾íwGëû¢¿Åk?+Àä6Ž›>\•a¿€ÀQ¶ôŸyn îGÁ’¥OgfxÁ†h¢…W‚=â8÷‡Ÿ#šñÛ2ý™žI.ît*‡†»n¬’3ò?B4+ÙÁüïiÏ#ŽÞ8:=ÜfÜ8ìž7ol]­Œ¨·`Í ²U^Éž_xƼMŽ1Ë {¿GíÓ6?5>wnSº´ž· Êñ´Šäñܤƒþ<ƒçZÛDÞ~ýè•î…­£^dê¥:]sâñ¶åž§t’È$I'ödîG(xþju5o,V”KöÇþ‰55UÍUºévJ¾;¸â¥öŸKÉ8Š^i&ŠUo!¹à8óé­žgotà ¶–&:ðÊ%‰ó©·‚Uç‰Ë)ðx íQ‡$ñÀǹj•f½:M^)T–‰0îäyóüN¬}‰ý™Oà/ËJæÅZ)[ÜæxvÃÍAË£äúi‚Ïäiå7uxwÚL$ªÖkÆ‘ÖnCŠ „îÈÒx§’Nê¶ÒÛÕ§ië`10LÕC$tãV0,bä{ 1%} 'ƆÓŠ/ÁÅÐãý²|µ TÐûºüµ­¼Kêe”Ys®ËØ ‡„•C§û3“¥£·ê­ŠÏVa:@ç–‰¸_(O’§Á:Ê}Ÿ¶ß»¿ob¾ˆÇ·4£óTzW>?ªÿGæþíý…çû"‡Ý×åªþ‚ÂþÈ¡÷tùi”FgaíÍj•²Û[z H#«Š:À€p_u@ƒ­²Ó­Nªª¤5ë¡T@àö4L˜ ýOCîëòÕQa0Ñ3I&‚º7ºEuäÖ„+õúL«:MrÄѰñÜ3²æ¤jk*kvð$ M[EÿÙvdradmin-am-3.6.13/template/default/default/find.png000066400000000000000000000012701443716113400223200ustar00rootroot00000000000000‰PNG  IHDRóÿaIDATx}x4W†omÛ¶Û‡µmû·ÛÖzcÛ¶íͬm;¶Î¢n'}¯ñ!uW•5}[U×Õ4woÕ·vCc[Ï\]SgUIyÝSyyu£½ ÓK¯ÎÌ©.«k··ô@ï8ú'1èŸÀ olÚº¹…E•Ÿ9ÿ]€ð R ¿)¨h²wOÂ4O© 1Œ`góa‚ÍÛ­ihÃÒ2 îßÃ@þpc× Lr… 4Ád·G"Rl§1¾B #S p8‰o€–»Ö=:,±ŒN±m~ ¨Œ&ëõ 0A¢Ñ•žY‹ð ¤çAßÄ Œ1¹0#”_®µÉì6f°ÙÀôûšB t"<¢iË®¢b\wRöO¡}aæ——Á`±@tLR%ÂÃÃ'ª·¥w†,wñÄNZ§À:?K««°¾±c“àçyáñÍ÷'_M$gé†gX€‰$ Rk@ó7jç9%…'O†~†ðxë­ý—ï;è}œHÏ530ª4 2™Ü)°ù| ’Ò!!!2SÝ=>w´¹ý^ôoî¡=t“Wï;(,*œC—H0…G&pÏž ÷òŠý:!4²¢6ìÃ-!ùÉ^Ï›ë‹öÝz ú;—!ä2àx¤}wÛQvÙK+¬`Pf½õÇo®ÿä6W$n!îø;„Ïo»¡øì“IÛXaˆòÄFÁ7”¼yëÿkàÇ5ôƒO8g–—þÀ'?µÿÉ­h_ÖK®ñ§Ðµ¿Œ€®B8xþ–b¿~$žÝxv]Xw"~~«A.^ ðÙ÷ì-×}òH{äÁáÀ§øZÇŠéß$IEND®B`‚vdradmin-am-3.6.13/template/default/default/folder_video.png000066400000000000000000000010521443716113400240370ustar00rootroot00000000000000‰PNG  IHDRóÿañIDATx…ÒÌdWÀñߦùXÛ¶'EÔ°Am3¨Û°¶mÛ¶mÛ¶ÆóÞ›Ó¬½û¿æaØñò_B)!À{/–Ì‹.ù1zED/©ã”6áÌ\¨láwqñîKèæ€„˜:Xgè'.ü6"‘$!¦žßt಩¢Èu ³AJì¶ÍF 0Õ²D Н¢2(r­ÌœIrÑwfOY%Š\3ŸA{iŠØyÿ3uÞ½ÌFmdhhÈðð° c³ÙtËã«Ä Ðì#qÒ5³Jz÷öÃì¼óÎö=üdK,±¤¡Cuê¥Ü9Õê Íœ³¯ùÊÖ[¬àÀÍÌ@é(RJºÝ¾¬ WPÊh4þ€ d}ò^îçÿ8ö1@P©T¼ûÚSþù}%c#CÆG‡•˜lBFÖéû¥$`‚Ík®»‘Õ×\W¥D¹Ä›Ï?4Eƒ\+§ßéû³cÆÇ”ËeÕJU)|øá‡S>(´3zíž{v6 iW^xaï¼ñ¢Ï>~O§ÓÑh¶œqÂñSLÈA¿Õ7'_|q«­³‰WYSVÐ͹â‚Ó4  üÕc‚¯¾ú¹Ù±Øb‹YxÁ1óÕHE022*÷ºUŠÁѵsÛýéÔ” !I`™e–QŠ\·õ¯F«ï—?þ¶üòËûè£$ó&Ì…ÿ´èüÆqIDIEND®B`‚vdradmin-am-3.6.13/template/default/default/help.png000066400000000000000000000011341443716113400223270ustar00rootroot00000000000000‰PNG  IHDRóÿa#IDATx“Œ&AF7ÖÆ8Û¶mÛ¶mÛ¶mÛXÛ¶õú]÷a­JÞ¸ü]AÖj%[.¥c‹%tl²ˆ’vŵ6+ÓvÖÀˆ=:#%òžÆ‹p¨?Ÿ1:¶[‰½t¾ß»àêG‹àw¨ Ï`~Ï5í0¨=‡û5faŸ_æûS™8¾ykø†ÛøoñÉ&®6ÜC‹Ï¤R}&÷ó”Ý{‹à…³à•³A\²@tÇ‚i€ƒ¿É;wA¯Í&U¦gkGõ¼ù–Åoðø§@b¨{ÅgþQpí“`ÕeÊÓqÈœvÇÕpà±àØ 8óZà !ï%Oe;¡é\ûh1h—`ÀN¥Üd¹µªn-6Ü"›ndàž€W˜Åð½ÊYÑ| ”ž$:Ú5[LÇ.ë3N’ƒ™’®Éx„XŒ>`1p™4["(=QP"i· Fí—êÌÈ}Èl“`Ã¦ÃøC‚a{ÉA9¥'˜Öh!#ö Æ ~šÜøLžçÃöÊL42· ÖuƒÉ¬Sd2ó„ÉkÇT¾xêÌ9MŽwíWè2»žS•Ja£÷¤³â –ž×°l¹Cæó¡;R•óý»H`8­¶ ~EÄ,½È<ÉìßóøÝôôg“ŽuŠù ‹/8 “¬^ã’ŸA’B¾¨’>ñ9:ðÝÇQlb`òÉ—m¼ôn†¡´Æ´HŽ5ÂØ¸GÝ×Üþè»|ýí7,6ï Ì8íH0Ôn¤KsmpðQW?8>Ö;‰',S0 È(›sŽX¯~âŠÛ^ EÍ×Y†”j䢳wßËÒÞP[¤¦[µ¦sÓþÐÕ‡£2ä2ŠBÎ¥˜'eóê{mIø SL1ßtÕx÷Ý—¿)w>u„ABe§Yiž}$+«R‚mZ¨d e› ?"?Ôè8Æ  ¯ .yÃŽ„}·üÂ-ͱÍlKìxÕ,3Íœ-f-ÛÀ²~>F8ù3ÈÑjÄWß|«Ûß¿ù8]ýöLþÊ͵,³èJû¼¼÷Q÷Ç'_øšœ}Å»rVŽ9ûÙvÿÛdÞ¥wÿÐI·lÌÿPÅÆ©W]`‘5O[f¥ínYvåínw¡5ÎɧÚ(ñ?Ö=‹:PLS¸IEND®B`‚vdradmin-am-3.6.13/template/default/default/info_button.png000066400000000000000000000014171443716113400237310ustar00rootroot00000000000000‰PNG  IHDRóÿaÖIDATxu’Ô#KF¿îQœü~¶m›kÛ¶mÛ¶mÛ¶mÛÆ k{f­{Î Êž¤ß˜E…s×=¤r›)7Ê4›@®å[M¦¼µGë5bn6<Ã=Ž<÷B¥¶ÓF~öáÛdû÷sÇģܲFÍÜŒƒ‡ ß±P܃{ͧÎ'•o3kFÁ¬ý‘ãß½fCSñjJ¡€ŸF(–é üûû÷ù3W¼’­Ê…ý¦î¢Y+ÓÌGhúòÃtáÊ-r1-‡f,?èÅ]ç¬:B ú­£"u‡/„„µï?+ËÖlÀ¯Ÿ¿¸ áÝW"øáã$l?pëvŸƒ¢¨\Î0aÑü3ñ%–¾ê¨.ï½óNùÁ)ƒ#@S8„àœÃŶœ:»Ž\ÂÅk&·Vc¹L¢`4‚„ìå^ã&`^@À§Bå Uú¬Ã©‹Ÿº KáDÞ¢/ÞPw³ŸËŒ pôæ]àm³õç—Q*õ[¸e:ø¶ÒlؤÜýB€Ü åë^S š`8~Ù8“Í`Ìs÷Ép!WE‘iýn³$¦Ëø )á}–¦Âኧp¿,U*›\˜TÓU¨º¦¹ªà2O††âá Üž"&ƒtM}:¢Ò¡Âƒ1ù]D25†~oð²AÓy¡¿ßkøvÄFXÄ‚âdQL¾ÞÀä{ÞGä° _ÃG‰t½Rîï›3Hêu›SmÛõp[ÀŸ¦à(ð[2b! `ωkè;÷8n9 Ì›aàÌc;þœÐ«ò"†{4ï¿dÌþkþì‘pÂàd{Û‰àý/0h†ÎÂõKWÿß<õ"H¡ãà…éŽ_æS_|éU(šÕû" ¶-`Ù·qîô ˜WNýÙ±vöEx|gÈÄU-›öZ´¾Ó°5äÚªÿҥæ¬jtìÈ¡$<ÁøÂ:·Î³¹SIEND®B`‚vdradmin-am-3.6.13/template/default/default/info_button_disabled.png000066400000000000000000000006271443716113400255620ustar00rootroot00000000000000‰PNG  IHDRµú7ê^IDATxMŠC¢œAûYÆÙæ 9@6±õlÛ¶9¶­ulÛ¶mÕëñTý«>‘ı¯ÆÔÿ½“Nz¨µX6ŠL^,/; àw‰{ƒQJM鼤ôü‘X~ÄWžs—{<ÀKɧì@€cÒ#|þp$v;‚†2«×·} ày–_\ÇKü¤œÈ Q:5… µT)Õ B#UÐKÛØX-è§/ö‡xÁ>ÓK5ÛÙ,ÝBãM‘M•´šZª¿ØÃnv±“íl£±½d‘M¹Ì?ÙG{cc;iAÔßÉ"‹ò(@ü"|rÈb{é|$ZGe¤r*1¿¨ Š2 É%‡Ñ9q|QÔÒD+à-´Ñjùúj•b²¦zÑó„¼ç2ôÐL+ykD•kyf¤³Ì0Å$ z¨‹ç8úµc8ðz°3IO2'y°Ú×?w΄ õ‘@Çã%"ÁeHîûû’ìIEND®B`‚vdradmin-am-3.6.13/template/default/default/logo.png000066400000000000000000000063501443716113400223440ustar00rootroot00000000000000‰PNG  IHDR–2¾Œ" ¯IDATxÝÝ”ÔÖÇñÌ«¸Ë{xêî^¤îîÞ"UxXÝqw÷ºã.‹S7\ZV ë2¿÷=§3çL·¹Ùͳó?çS,¹¹›üN’¹¹™Zå©g†Íü%V˜}‰ÂeèEø û‘‹"£^ÈÇ‹¡98€Ýøëñ Æ£Ú¡nÇ(lC&â²}r‹<䣅>E>…(@>r‘ƒlÄ_ÈB&2ðÒ°Ûñ36àk ÃãhUYŠÎ¾Ì “>^‹o¡ÈÇ7¸õð,öAa` z¡VeÖ‰ðB6rQý(ö- S £dîCMŒ‡ÂD® áZ |½†r—UÑîO4¸[-=pûš>}z`°ÚÑçÞÁd4Ãe¸WàJ\vhޏ7ávÜð(:£'à#l‡‚P€ó­ÊVtúMÈàär´»²q­‹ÁŠ«l¬/­³¤õuùÕ#mh¬ì%ñê×).0X=ƒèóKÁ—x ¡bÜcUÆ¢ã­á…l¼{„m¶1´™†8ƒeÑÜ“¾ãÃh,Ĩ(µ®Öª¦u#-륄„U«VM,º¼œ#ðsC¬¿pƒU™‹`©›s€X§/d£¯E¹,®…{‡<‘–ðhãKëGYJûûL[¶lQII‰üÅP„XÎÏ‹ðë—ƒåÅ/‹»ŒS¡# \£!é¨rí| ÙxÚå`õå¡ÒÒÒD©¨¨H999òz½ ,B§æÍ›†k?Á§Â)xó°+ŠuØˆÍøßáäA²p‹éÅy.dp]m4@TJj»¬«Qr×]w‰ É®ø{åååéСCêÑ£‡X>ÐxL÷†}à…ÜAl"R"9XüXžïx`¹ç!³-Ê¥`Åc+Ô³gOíß¿_”²²²”žžî•víÚ¥9sæhòäÉš?¾¸ÏRRRR`¸¶éÇTÈà¹#ܯM±r° "9\/8ÌK¯D0¿‡ltp1X1„ Ö­[û‚d.¦ŒŒ qŸ%>*%%EÉÉÉþ`íCJ©~¤VÄ<5ÖÃlÈÁü'RƒU…ûÊX÷lÈÆĺ,>Ý¥Ö®][Œª+ØâþK+W®ÁŸ"ÅÙË®çcvÃ1UÎp-†ü‚z‘®O sÊXo„Óke.ëÆ£tòÉ'‹›rnwÜqâAµ5jäÖïˆòõáÈ Ñ.ìÛÚø r°ñ‘¬k!…hàðhdãxƒ5‚Ë z÷î­Ò•››«²êæ›omˆO“âW¿Ó}}x2øÊåÙ»ùƒá‘¬8ì…lt2¬sd#Õ¢\ V3&îå1+T ,ø×½ãW*«:uê$Ú ¼ |‡ ºº¼»BJpN$†ëÈÆjÃò_A6w1Xý–š4i¢íÛ·+°a*X]ºtm¨~ýúÁzÓ7CA^4¯€Oàß@6 &Ò‚u,¼†Ü2Èþ\Ôt+X±1V¿‹O³tLËÿ Vvv¶¶mÛ¦²ê™gžQãÆÅ¥Pœùþ~Ìãñ<^ÆpÀò ÚÇÿA&äàéH§îµôσ§uúI ½/¼öhŸ2î½GqŽûÈzÔãüFîð,·²Ñέ`mjÝé]W۫ͧI[êƒw<ºñÆĨú?.‡¦ÊÞ󘣥wO›kiíäzZ7ïF§» ñ<(ýä`H¤+Þ°áצ†ww#¦<ÁznÈhÍœ|«ÖNkš–5Ï*&P"X8UZ_Mw^e‰—%ô믿ʩ8³iñGo©8ÕRê K·žeéò,}ØÇ’Ö%ëÇg9Ô'CôE-!ƒ"´‰´pƒl¼WÆ#œw-ª<Áš:ñT]ÚÐDÚØL §›Ž×¾9Qª‘b‰OýôÓOŽÁúlB/Zd©`…¥]XÚû‰¥â5õD[òn:Y“gt1MÍŽ Ñ~~r0žH Öù“û£°Öo=«a¯^¡9oUÓOã-(ý8ÎÒ'ÿKÒÓ/=­ÇúŽ×ÓC¦ÿkÝß©÷»ž¦eïXÔÒæ‘–>{¹ººõ}Ë¿ÌZœfûû5È ­#éÁtä`/bÝ –Y§¡ÓÔëínÐû* ìq‰^èÛ¯Ìuº­w{\«ÁÝÏÓ{½®#¨Ã½¾' 7!* ÷w<~† >ޤ³Ö{ûßm`–Ër±=pl%Øß£ÄáÁø%‘¬ÖØé³»KiS޶/ÇŸøû°×¦ý]ü}¶c~Ãf¬ÆR|ŠèŠó‘P ÷ù ìñÙ듆Xa•³þÞRÙeÐx‹IEND®B`‚vdradmin-am-3.6.13/template/default/default/noise.gif000066400000000000000000000270601443716113400225030ustar00rootroot00000000000000GIF89a´¢333fffÌÌÌ™™™ÿÿÿÿÿÿ!ÿ NETSCAPE2.0!ù,´ÿXªTíL@×Þrá(›Ep´ULW°}Œ¥½£93Z½»LU®A‰7Ò :°Ë§1ðñtaŽS •/’fû\ Ù»Ñΰñ3¦eØ8ª%D].šcû­Ñ‰ÿˆ\^|M Ba)ao_U1``Ja(X—&8i —›@sU\y "‡¦ ”™Žb‹"#¸3–=ƒš'i P »ÀDs:+Å¿I•‹É‚!‹f¦yÀtp~¢ˆu]xzÆ.Ž šw.ÑDW|Ï‘{% ¸ã^ÐÈ÷>ûáJ9+c‰WcàŠ¡8gÁ^65{Þh2$ &[£ÞÜ€f#ÿSD•èt§ŽAÉ©èÏ/ÃÛá|¯å fþJïÔéé’ϯö%ó)åè×X§å1EùBx¸•ÄŽ:Šž§ÃÒÇn4îÿ²qÂÖLKa¡Hh`7Â;r¨KjÅÀ&ÍqgiN‚©@°BI ÄÖ9¸R“+òðÒ6¥øAuîÇEvN£w¸Þk¢õ "ŠƒŸpz€sï!Fž2K<' €©×7fMS,#xÑ(bÈ`%:Ôâ9uA{ýÅ–6(4ƒÌ­d$˜ ¼Ñ>§<’ºx Ñ"ÏAàWšÞT³´öÏéÑÚy¾ôQX²5ZBHv˜V7k (—¡b'öÄ×R|cÑË$VHE'a¢™Ú#€—`éñ†Í5¡‹q°I‰L+.#F3Õ=£©4ùÄéÀ+ÿÂò1ÉßUÈ›e/lHÖ¡}ÂÀ+ÿ„ÉFt!ùpWXg… bÆP¢T ÎSH¶ÃK˜YeRXíŽhÂ[¯ÊÕáO ei^)†¸<‚ dôéJU@JC>ɪ›Ú\†¡ ¢-dàÐu 9ÁC=9óF:u¶Ô"~%è—2‚þw …w¶{ã’ ã– Aa0Šƒ,@XK0îuÄ$r½Õ¢E‰™ù´—*I˜ry§%– ¼†©å¦ ää„VŸ“â©BÈ$]liÖL‚ÇEˆY${‡éÉêžÕI妨ÜrttÊ@W]çq„ kE+²›[EäéI ¶)™ÿíyªd*zͱqû™P,¢qÕ®+|G}ËÞZÝÎI^|Ø*Ÿ dœjŠÄ¤²ô©ž°DÓV¦(b"Ëpk‹·? ¬Úã*² ¡“Ç”?‘!â’ –Ânïy?²Åî¯ßÓÌ;ªkC x™]YÕ¦A‘ÙfˆÊSùN'hD”Ä- Im)<ªç. FËRða/é$ {ªBÜǽHDóÛÑ•"„¨üDå×Wh5Z&"0„àŽsÁ'¬a~*ÌIPVÁ}à³_,S¾u m0á84@Nr;ú•„$ʼn[ãˆx?è ‰YP"ÿ9q9àq‘‡Ééœf‚dƒÐ4:˦”в/: TVh•@Ju,j‘ —øÑêL—ôŒ@V´zÁç~ˆ«hèêh®ÉÞÖܦ"Ç|LQVIÙˆ®…AR=i‰!ŸÈ•ý=€P9㜄•'á49´YVnã’Üt>»Ѐƒ1 …rëÇ{2tŒåDJ;ÐG,9’ ɤ £º%EŠ@ÜÈM…ÈÀžª4ìGK$=ÅÙYN;!#/C ¦çÉ‚’B¿r)º¹ð(`w!Š`5 ì°2g ˜ƒ’FBPÏÛ"@WJÎ] uËš"„%+¹-Ä’$qØÐì«YAãC0{°¡+H­…H‹Âö‚g•r!óDãˆúW tjYC\…5–Ü2Ø£GSɃ––šq4Fg¡Ó¼4äŠXC#³bÕ,Km!i'ì‘9:( NqäâÁtŠ#+~`xcE<äƒÌ"‡†xò`£$±%c|–˜„R¿¯tô:åÐßî‡*t-$oªô[ã¤;®ï3ª†î¶’Õ\^H£#•нué\fšß™ðwàZã&VÉÖm1:Âi p®éE7-«DÕ÷Á›º AÁ6ã%JWa^ƒl#óWBE C“^,4ŠÓZÓfz·ÔwA\÷A%Øà`‘€e’u]aa%†a…¢aÀa»ãa!!¦‚GÃ)ò·Bv`F=7iÄ(Xj…Ç„3‡5Qs³`öPq[ó`oƒ¼!ƒ×?@„A:Ñ kk7mÇ?‡³z$„`J£WÐ Rx—@z M&HQ×r D36V<þw_2w'´P‡²0‡ÙwØu×RÙôK³æ2Å×f¢×‚RzÆrz€ÑKª×bïVp´{mÿ€ÈuºB 3…VÓ;žÖ7Ó‘cÉ2ISÐcê*ö~óCEvúGU`e=Ä#hAzÚ‰{åM¯5#65†¸CY°D!sšE-¿ÕYræ'ov<å&KÀ »WA–†€ÆÁ§uêG|û×~dVŽÊ§"e×Og÷J&}t q†%P#p…SjÍsjÍÖŽ±4·ópÖö_F¢dëUA;–f–ktÂ5BA²±¤s¿!4c¸qFƒiBè(Oò—XX.%ŠÃ„zžhJ«§_Òòv³±)yð>û0M8KŸT%ó!)Ò9¡ÔWÆâ8iõ.†W\µU€U"±9Àÿ0vOA_"`#N%ØHd#M3o’nTèOéñ>\)t@ÀŒ­g”ðv9•NÓÈ;XÙ³˜&ÛH¿â!8fèæJ´mò1ž(ròV‡3XDH†ß#^EÐ?`8TÖ2/ 3'}@¸TC…™}|Aòâp÷aÒD}û=,ÁD²DW;˜r"S†RÂ0c–‰3³<ˆA1Û%)°rru .·O&f‘õ[“#VÆn" Zv|BrD²“/‚Ib;?(7ÿÔ’;ŽGG ÛA•Ž$]D%IЊ’°kÀ]¾ö](¨n›0*ŲfúÐpCH…ˆåÿ2„¦cJ1ŸÑRk0ŽqóbAך6¥a?&'ŠØ&—0&UÉ^È ì“;™>‰Ö-¼eGeP˜Ûq˜^)ž‹™@éc *#¸Ä+]d|žX’ªAz(iÄ”^®ƒ"†Ep›©¤¸ ÖprlÓ¡>Á›w°PVp³°åö çFeYpœ.X ˉ£äœ^öO÷¹/Ó9õbŒg@\iuý„”¼xFÿRÌuR×dy׃yÙy ú@·|_[‡¡RíVܶ|óÈpÖš„£ùª¦=§YrMdp¬é '¡,4ŽÉØqùf~Š´€êè’>À~xÚCawp|Ú™~j.Ðÿgš0¨T*žRêŒÜ”vèh¡;eYÕè4qI§\åY~Ö¢õ:· Óf`©e—¬¡M—óõŸt„‰ú'1 ¦}ÿ×/Þw@F€]©Šoˆ¤ šÖoçä’F§¦9A "6’ÔF«ê"Å:Gø§Éš¡Td{€”Èõ†JG–jF¬V§õ4þ© ¼¨†£;n/g6‘ya›úž{I@Ù°/™œÄ©~ÀºnOên[ÖœˆZ$1Z§bVziÈK¢%„Hvº€™cÚ DfIŒ„:ŒÈjþy£úb—^ÇEm}­•øý‡µómQ÷v¶á¦œ§þÿÔgäi&Ú [ÜiVÄTJ½SsfH5‚›ØçTÌ‚LÏò'4hU`-“Ò•ð2'<{Ni¸Ñ“ŸEâ´·ÅDY»stc™{x†Î&Bˆ 4@„ÈLŠÕ4qR $@ž¡KoBìÃt%ã…׆^W?ÛAŸ ?àõž† ˆtK¶Re¶Ò‚¶ñãeØÒ¶²×z̳§ð—!uË?Õ3³i©€ßúŽM¯Ñ~uè‘#’Ÿµâ°!{5{tkuOžë«žiµʳ›à<ÝðȼyŒS¤Œ±î2±z”Æ-W·P1Ïo&ây+¢Cæ2“ÅžyÿÈ5îÒµZ“)Íq µX ‚º,0U„ K蘶´¥¾Ù±˜³kr†ÖŠÅHc3øÏæœI½W¾ÚjÿŠK&hU:y5»FäxYicf¸‰Åõ•Ö–7jÝYŠx'–žÝ’^ÂG>š¯ª›Á‘;EöG­hFÀ^’U2/„ Ô‚™$!u7FÃlݵÅ´¿b,C‹@1¢ñI°nÇS3`‘à€‘#é8¶•3Omü¡þ¢N'J옊™,4™.Q™1¦‚RKWŒAYÜ;´C ªCói:© X©›v©uš©wz`yj b÷©;ª›ÿ2ªFRª¾W¨5tÜ8-~ËG`Ä4÷£ìE!g¼ÀÖ™œø•¸ƒRw‡@‡hRth‡ň,uQ¹Jk|Z5i=5˜hvXDÌ3F,¢I |< TÇûÅqÃG9:l›7ÐìòÃóu²Þ†sL†|G*±Q¶¤ëž;’±QúMY;%æY²£žlƒ"¡Dl3`l¨aؤ‚4Tx¿Ð‚û„à Gk¬I—ˆÆ考¶Ïš[Ñj¯ˆ#(Éç¨,ègÉxâ¡ðWˆyÄß§ÇÖly!Êã±€Ü0‚¼YTœIµpȌ̊ Œ¼d‚"Æ^°rìv‹Êÿ¬›;=NÖ2røÜ a7+”Hé” Â¸¿˜†vaä¸xåny4p„–„VvJqf’kÑ$a¤`‹¥‚4À‚ãð¤i)ctùŠq‹[´Q‹<Æš » ÑÚ[½Ø²º»0ëœ2‹’ã©.å ¾gÕ€›äìŒ9l9¯ù,¹È槃…Âêl|»TIömël¤’nï,Lz±ôCÏ껪¿Ò±Ðé•B î7¿½ˆ …ÕÂÄk‘ÙæóÈyÍ{/¦Õ&Í–<Ƽkcr»X¸CÖA~ŽÝi£ßÙ3Óµ­–”]÷!ÜéÙÏ^$ªÙ®ÌÙ’={÷•l;ø^t¢W/ÿ“k%À7ç5–€³ŽýH8¤vÁ&—Á¶¯‰§k\ý.ñ©^¯åO ºjŸsK²Cü5ÙKµ3`¼‚4 µ“µ;Ÿ}ÇHÜW*òÙ-µÛmÀá¬èÞØ51ã]Þ• —ýÏ™}ë 6žÞ£¾4ÒÇfÐ¥TÀ=Ú |Ûùk)IÕÖâ„,VXä,•óà‚•9>à”°vWƒ4„žÁWf­ÖÆ „~¥fcTÁ ×;ÀX5ùh©†¾2§…6÷’ vJ7è­œh <¨Ø>HbwÑŸhÃ9'<=)ÛQæ;I‚w…q¢ÅæeËoŽ“ô,)9I’ÝêVm®øÿáj á Náü0N.âa÷¥¼lkŒÿ¹c΋Gº|«þ¢Š½Z8Áf¾Rš?¾ƒ£Žz¥náöISÙ&ûÙáz©Ò‚U´ùµ¡œ@A¥ÀÁÊž  Ëv²Œ†¥[LˆûQcmw…ÈË%%’ÊA©™å'I]60£çÎ’ ¸±9úz•{¦8°‹RªÈ¬x‚äš Ó-d2=^ÜçÝa¦œZŒËûµ…+–Ê7çè‰>{^îŒp"4¹‚ Ç\"2b©™Q³w.? Ë!!”'A”­è|.”x7U^Ž^b %Ç=ÆÕ’&Ì,š›5ßO´ÒwÌ.O]Ó·> *´¢`ÿ‚^Ql™2$êAêÿ9LÅžßÓÒ¬.  /lëŠ ãûaÐÇA¨ƒ­íXZ½Ú¯išàO.®¥y«÷Œ¡]WÀþôÂõ2:õ#oxõIßD+Ø'鿆ve2¡ºÔ)¬Ÿ8ß•‚¹ó@ÚóÑÜTÓœÇaË’Cü‘Ï.Aº·FÕº`ع¤v$¿ñ£Û¤Ý޾îE(s“O¿ª¦ìŦ«¤´>Ç´Ö‰·N‰ sݼ…áKìÑKp ‘ûEGâkÔû"þû•ÔݨÚâ¯Þ0®ëš$ã4®ã1fܡ׼ÀפM‹Mbuòb¢ºd 9ð9SðA,ŒC]Æ\ þk•=•ßS¡•º£iÄç2¼4ŒDŬ ßx´(°œµyáV ×d¤tšm„°‘ßXÅ“é( ž‡…€sM¢B fÂT°˜ •*ñ6Í çѽ>ZZ'!ù,´ÿHµ¬¤¡Áò*m`½FäÛ¶ ¢cŠZyu—¦JGæXÛQíûƒ×®¥Á­$X¬ !;¯Tˆè?,a`“2¹®¸ØU7½MY Y&Œ—€šJe2_l®[hzm-€Qs78ŠwK,6[…IC$e)?K¡FGo\^ƒ{¥_£;$}R,!VJW2¨‚¦(`l«fQg5©m„S‡rtU% EŽ s§ x×I0S9ŸV¥€ŠÐ_k³e ¨NÝnŽªàySÒ¾“®.{­šÓÔ¸m—ÅY¥'2ØÅ#.U°Oçø`0³ \?…¿©Õ„ÿ[2è@Qà"2Ö 1C†¹ðAj9Š=v©Í^*Cô±Z2î4‰æøÁÈG™]fÜÈz3éÜŒC; šµ¤ÓJ«'RTóa©€Í¼˜3ôS©§>«}e²$%`Y+Q+1›Ž-F­´ƒ`âV$¤!_6ÓõòØ$™Ž,¡+ŽƒU¢B±£TH9ÙX”ä;н$†œRºEL9‹Å®÷P1•WN…¸u–ŸÑg°Óƒ1Lå8*KB!Wn{úa ?ÁFA•GGuàÂ×—›*‚%õè "¸NTm$äa |Ðc<€\òÄá>âC rZR,$0§Ï:@ÿ¼…Tç7Šó‡(ø½æq]ÀÒ–ÄÉ>ÞònZáÆ—þéà˜c8KŒ±ZÆ/—ÅŽž‡:Ù"«>…lè ©Ó21Ó(;^±*G34P©¿"GÁ…/Þ*7ü¦}ºÂ67¥4jBÚâYPR…aJI, V©`»©m§Rxbñlñ7`úà:‰Þº2eâ‰Dû1„±Ïˆ#KÂÕâÌ‚Nlq19ÒÕ)KEZ¢Çž},EkR©tm_Õù$0qv8¡¨¾"— «TŠDf„¢nYÃ`9ik$èzû@¬Ã’†h9=ô¡m¾3$=¬ZGÈÃÒÿ^K–ÍZIæÕüÙë„È£¡¹¶j1(²§pˆ*Êz¨iK€&Î\0F‹Nó8¨AA$L n„¦·Z1‰\ˆ«à<`îÆ³òð¡ïèhˆˆ¢QÌB†z¦¢0X,‰˜ÆÒǘØ#iàÔü¢—'o1”¦`ÃÙô"ÄV¡'¡$uã6EMØC’;J OéYÒ‰½Œ’¯¬é_S«ý‚NƒÖð[/e–ê.Pî˜eNRÓcXÕ4ôìi‹È&R—@1H®Â#ôÊÛ:o ¨%¦i‚¯z^ rŽ“$S† ®QTswÞÉ/MV"Ía‰Ç%@ñç~+À‰Òÿ‚„;G‹ ¶ÂÃjˆyÕ«LF•´žqɶÅ2rÄÓLNùbÓÖXN ¶èdжu¿z¤K%5_U y VkWIŒ~ÈR¢ª*‹Í{Ît=_ŠiuÇQF„ñyCb\Ñ 2¦p¶ D[åu&ŒÏoxÐü´¶;ÂáúåE >ƒJVeÊ„·…\f$uÚ£’:ôz[bÌVþ¬Ô§¸qÔy&g•š?ÿ’¾×…¶m/ã„fÛ3¸pm–f\¥®Žjå­Ôã¢Ø9ì²jì=“&èì:} ‹•u82B?Ê8Ûɉ*BJÅ.XÖR[ FxTÕDÆ®-Lz ²÷DQ 8sÎÿHhjåâ¦qúÂQí’_uvÛ'Ð’úãÜ„xùñ‘1&Eêv“ºý²Ñ±b€× C)ëëÕ]àæn|WèY‹ àÄ—m7å-ì©’´Ëu›»GbvÿØ;`×0ÓÿÓ>F„…N51!lÿ³kL'"W6u¹‡ U ¦„€0BaÚ(367¬2~Ú…D*Ã;„‚zâ…*ƒCš;ç'=g›@÷*B'*{—"p~hñ(f‚6›/¤[hWåa'ïÁ2( *lpz¤Ê(Õu€ä0´ [€…`uá’¿ñBD¨#ÜIˆdUræ#dz)H45 ed¡“x‚¹£ÉG@v…9Lø]ša÷Q(SmÙµ€´Žþ奧¤‡E €Q¤Qc’¢ä]g"F̱h7U‰cs“±v\k“|Ñ’Tâð‚Ó'‰5»ðM´ãs«§fŒÿ\@:,‰9|é$ŒÉŠ‹WáHrªˆ>0}©xG{u²ŠªhÂ0à˜ž2¶§| ä@.´;²Â.Í!x)µsxøj¹SžA4o~ u¸ÁužÄ›E›Kp,‚¡]ÛbðäŠ jœ[QhÖ·žašF2_Ÿ"0,ºFÈyfÊ„6 QxÒ6¡%ž†Z)6S”!(<ßTgþ*í–@¸OáwŸ¼æ9(Ak‚ÆÇ¦_ä*˜1›pІãˆvz 5IVÆ(A½Ð¶Ð²µ•bH°°¢[¼S®Jy(ÀVª™c€H×JçTpjm8 M«¡‡¹U@kà?< ÿG´0Ç femq¯KS “²fȦ+»”s¨ ¬w²I0XûIȲuH™8 + Á¥vÍõrp70OdLBÐ(ãz=*Ó“Y#Ò™™Iò®jÀO‘¹RóJô…5ä_à(i•&¢:(<¦äÁÖW!f X;G"Ëç9Y9¡ ´k…Ô «¦–7ЦG¦4ïñ'eâ6äh.øœj"52¯ÑÁ1è§€|«4ä~Uç<5DJ@ö¸|çm–Syæf¤Ž;v®I“ÛÑŸSë µ§xâRGN®yLmú­qŒ%ùTâ¢ÅptùTqu¤|º[i€çF4PX)ö#~ÿR #”Ywa¥»}ƒ¨,˜Ñ‡³Lô½‘‹‡û£3•´•êjB¤g{ù6òUKùµr "½íÒ ¼J)çÑ þ×x`œ5{0HÃm¨ )Œ8Š” £š[{.°·pš \m¡61к-L-¯FV*”k׉yõ2¿§PÏD6ï)&´;¹8eö©øc8->¬# ¬›z@fᕬ` £.0˼AJQ,+e p¾WdsÚÄ]綯2K®¢fjX-êˆcÛtŠAC_d‹W½ÑrAˆ"©WG©ŠJKª×Ô{§A¤¶&gȨFåh±ßš«ýÖ'2£kG;âúDÿH¬¨£ÝrJ*bm¢»V’Dà)IŸx•DÁ43 >ŒÃÃÅS<·ê@]Ê“Áš<Š6ªlØ1üârwµ`™·P¼Ãm¬ÂÈ¢TzýQªBÂ=!ʳvëGéKG4›Žr2x «ºåÄÜ[½¿²Tç5³ht³Ðy´@ˆ@'@?2œÃˆ‘}K(ñÁSƒžÁ@!o52)⤰Ö]趤²l\C¿—å™1£ —ëUT•Ôû!Ü'LW³?“¦5ÌePÓ4NÝb‰!+7÷r±["9¦Âʉ¶Ï£õJ ‚¦¤zýÍR¼Îº§‰‘×­3Û‘Þ³ õª«.E¤Ê6^%F»JÚ¢”ûVšh­rµ£ë › ×5$è’­ Òçt_ôljàÌ¡v~ÇÛÄà¸q“:>+n±õTno‹{!b €}š¦X…hûêvLP¹Žx’•­ª:³×\š $«Sd¶ ª«öQ=Ëð¼OúÅÚ]ûزäcSL•—\i wÊfÈÿÌw6Ùt,vĵW齃*lÓÔ{QB·–-Éê <Š_¼Û‡øT)l‚%Uç3[¼'€ÛËvþ3¥²¶Îûs‹¯R1^›ÝaG˜Êb |ÁyUú gj†‹mÑ/jMl4öAÂ¿Š‹¸‡$äìyL}!YŒu)Iíª8| ËÆì) *¨z±øžðcMc÷Ì&7J-wA­Ÿ“Ö¿âLÐð’œ.Ò<¢+‡îÕ; þÎUÞjÁ'`_g²gZ[m˜W,T«€ xhwmàKª•T£pÛE¬l­c]ö‰#À[2][ÈqË—Õæ%2Œ¾0Ѽ^: ‚šÿþVÌò³¡‡ˆB«eì?ÑhãÚ6pD„!"F…×z#wXŽE–CœW¬·r¬`;lrr¥üqøèiÄ8r™mvçwòTs;ÂŒvŽ)ãÚx•9ÄF…kw¢rG(·"©s1b[Ì(Za[ .¿·¡Áx¬Ü/ò#=óüËåÐjn<ûÚƒ ¾· ÞÝbjË…zW¤ÕÓÆ^ž ô €Î &8 ÁÐéÛ±ú«ú²ûÑ´œ )=æ”X£»¦ú\îÓwuæ 7ðÂsbáøP‡”°e«õ†.@¿oG-Óm¿V ˜m‹Àr1І™I«BpN­ œ6ïâäì˜zÿ‰= £?¹ë·GšÖóq4¿ ØÉümÙ ¨à¢Õ@ÕăÃñraù…&Ñ[|}[ÝÔêôJAÀµl»õaõ#«–¡Ÿ½1 _¹´Ýh/Õ þI([YæŽôoÔ»¤¶Ã…ã$ãÞáB«X°†óS¿^õp|ÏB1Ç=Nqÿ%-jÝŽx_Dç3¿½r=R9/âUõ4Ø•&£¿a˜ãÏ?] "ãQ)u(w‹E«ãnZ`B$4F­üøC,=WHã|s’ÉŸž=rÝyÏENq.„I¦í._HWÒѦ`A;r˜sÚ‹E S‚qºêÆjdÛ|Ýÿ#¯K½ÞÛ–4Œxaç„TE½$Öª–±[ïŠæ™-0K±"3wFaþ¾0(VÄAfõË’›\Ϋõï{Õ'î"³øMÜ–€{?ò—Z„œüR©Y%xï–…ÙûE#³Gê`Û5Ä^meŸ Ý©4øEå!:¹äÃïi¤ô–P€õWãi’6Ls»kÏCìüË/î!y )ü>Ku×à\Ì; …ñ×y½^ß\/©%ÏwìyÞ¹eÕÄé9%¬I|ë’³/ã 7w‚Ó±>4:`e®HÆÍO)ÕĉŬI<ý<÷að6@±<ƒt/çÑÀiÒÖz/‰‚G$@ÕšT 6¼ÝB͘MñpœOÂ{<4C¶jÑ`ˆáÍ6!QŠs·§ ¤WTEµn—¿U§ý:0b'Àl Õ=Ò L/qÂÞ2LØ÷—ÞÑ’ lר‘¢ Œa®)^bÞt§]rvdÒ¶8ÎdH Š+‘LªÖI®U¾ÜÇø7 b<;),na¶SQØr3AbDbY­Æ5 ³kì4ÍžÁ̦Áú—ý•·pý‘P~”ˆ#“ª‘5~Sš]b§êŽLÅí…š`<™°aË=síó‡ãtH>[æ™Çm³³$® ÜÆpÎo›Æ3WÝ6ñ p`]ÆèuxIEND®B`‚vdradmin-am-3.6.13/template/default/default/pfeile_nachlinks_soft.png000066400000000000000000000005741443716113400257370ustar00rootroot00000000000000‰PNG  IHDRµú7êCIDATxe3`%Q†o³vµv_½n]oß,gæb­jÛ¶»X]Œ.¬ÒĶë?gÿßàâ˜íKž–O…!¸xnœeG%ÏËøîoE4¾A¹E~çàõ55„n¬!@¸ÑOfr¿ØóV#i˜Æ ÑE˜ÿEAnh×mƒä a”è‚©.k=‚ðu’‰ÓÊ]~¾öÐʤP>íO¿£­Îõ&­Lêø ý5ÆTÑõQM’Á/ðP&øä`Çõß4gâù7„ÓŽ_»C1Bð ºdÆYåŽ@$a›‘g0ÂÈ%ʯ¹¨M‘„ ‹yì5^¡ÌIèWÔD:Ê,–{•9¯?¦9˜2ªÉDê¥Ú†V‰tÍ_ª‹lWÚu^ðÍm…ŽÆW?¯ oº> uR»§¿æ¡<\—šK]§à–vbž5R©ìã!IEND®B`‚vdradmin-am-3.6.13/template/default/default/pfeile_nachrechts.png000066400000000000000000000011541443716113400250470ustar00rootroot00000000000000‰PNG  IHDRóÿa3IDATxRQœBìRì²kÛN!Öš±mÛ¶mÛ:Û¶oíÎçÙ躪g¾ž›ûºÐú]po6P&ÐÈÚ}%ª× ¹ÿ€  taÛÆèÑ‚LŒß˜‚©Û Z!¢D¨ýq\ªzÞáoÆ­úð˜áë²píƒù˜¬nóK\xP‚‰Û™#]P~Oõ“~~Æ!ú°å¡D¤XšëÑîô‚h<Ð>!ˆåg3ÉIAùåÖ5ï¢ÈŸ"Jg©b%LV9¡3üŒ5cÊŽtˆ4ŸŽ«TªºkR}ªoßý< (âñ{Œ •(4¹È žþ(Âч`嚇Éöu"½»-LÁù¹xPŒÐD ÙENT‚ú2|«=×¢ùéè¡|8…ÈF¬Mî[™¨ N¿9€dI>zªŸ®áh΃VebÎñÖ$'þ*£×z@ÊôR?YÇ‘HÄlÎC¶xª8˜qàf/=DP2߸÷ ßF6Ð[yKɑ¨‰Ã¶z0l[5ûmâϽàà @ïY-ce›„)lψuP)â±»î™xçôVª~s•±\ Lž-Dú€ã¡¬¹˜UÅ3/ ˆ¼3z#ÒýL#ßÒ³L•è©zØU¬HTí‰Çî[ÙØs;‡G:£;±îGúhåž̸)ç’')¬Ïü`óŒm‘˜s8Z÷™l¡´)²¿1”)ŒDBs¦QQ·©aT3/m†_,8]ç@ DIEND®B`‚vdradmin-am-3.6.13/template/default/default/pfeile_nachrechts_soft.png000066400000000000000000000005761443716113400261110ustar00rootroot00000000000000‰PNG  IHDRµú7êEIDATxe3¼œA·‰]Åî«ëâ:}®cU±m›]¬*Vt±ýl£š·û;ßÍ|\ý!²¸žn²ÕÖØ©º·(Äõu»ç5,a#ÛY‚o°gÔ¨Üé!þË:^PEk°7lÇU›i™ÝþË!~Sì ž ïRÎájäÐä‚ýëxÇ×(‘VÎ…¯/ìÀœñÝ…íénó&å'"œãwñÍrŒ°“—ò LýHYK¤Š-¬a1j¦°z-×(æ kXÙ(¬YÅ J)äkã‚ÍÂN]Âf¢›ØÈZ~¦¦×±%('toß°…­D7¤¦/°‰ÍlÁ·ÈD(Ó\Ç‘”‘›©ïu˜+>vB ò?s‰èý`òë0úÑãýϽ\ãzÊkì Ófºï/ÒÈ¡æÌ’æíñh¶³¸Å\Q“Ó|w9FÍ4ÍfådÂM.ºÿZ4,d²•IEND®B`‚vdradmin-am-3.6.13/template/default/default/play.png000066400000000000000000000003471443716113400223510ustar00rootroot00000000000000‰PNG  IHDR‘h6tRNSn¦‘œIDATx•ÏWƒP`¾ê+€€òN TÃÙIºs;w„×üç’]öŸ®;eÞÌ`mÛ¦¥iš ë: 4«êf 3”eýü$(ZEh¥ô‚by¾÷ù­ Ó T‡® rG þß½`Ĩö&PëÙ„»íÔU0¿íýã0Ì»ž óÛþ ƒnoåÑÎÕø¶Ò¾FIEND®B`‚vdradmin-am-3.6.13/template/default/default/poempl_gelb.png000066400000000000000000000007331443716113400236700ustar00rootroot00000000000000‰PNG  IHDRóÿa¢IDATxÅ“CŸÄ;¶žëÛÉ-ùqrŽmÛ¶mÛÆÚ¶íßôV¯mjXõïêbæ:©î€÷»Ù_¾ÖÒ{ºtÅD§ÎXèØq«œéÂ%]¹f¢ë7tï>Ö“x‘éóíG×m?wy,þ=y¦›QM€þ5oÞi‚ /€†àç‡Oš˜¦U°€å¡-=R3ˆúÙ ¡/V¸;¹vFh\qddá—o]=²Ug« ?»uÇ`Ak8iŸD™ŠÚŸñÐïÈ1Ëp¨-´æéYÄŠ:˜nÆ€ÝB£®²n!ààa³Æ¿ŠÚ7wùÀøuY¦J8(¤5÷ú@¥tà ù¸LÖ:àºg.ŸOö¾ýæ]ðµµÊöî3ÑÎ]†ÙøJ4@¨+¤¤ìËÛwê—ˆ+Q¹€­Ût¢¨)-$˜œF súæ-ºy€TØ´YK[·ëßÉÞþA­+Å­ß ™%ïví©°a“†`&L[ƒ—ŽÂýty^m@¾FCŽOÙª hòcO|zìhЩIEND®B`‚vdradmin-am-3.6.13/template/default/default/poempl_grau.png000066400000000000000000000005271443716113400237160ustar00rootroot00000000000000‰PNG  IHDRµú7êIDATx¥ÑLoðóü¦gcxlÊvÓß¶uo¶mÛÍfsš²kÊòœëd»¦ï7~€7ìÍÀë§èA í¾ 4 à^¿}ÓýªÁ£›¤]¾yÄzNyy™€G›÷‚Öí4P¿7D„Ä"ÑHüðІ¤bà´Âî(>«<}ò0‰:Ý7vÜ9j­É1©¹ô¥Ô“hÃrLDU¥æöøÑU„™¨Qµ…cÞn†âùk U$b¦bìï a¶ø‰ޏz¿ÍLÌÀ,LA9¡Â)À–‘|6q7ŒAÅ “ä‚ð<`»>CQ´DÓ±€wÐÌX ŠæhT:\ vךÞGs£ÃeàámîdNȉL·z IEND®B`‚vdradmin-am-3.6.13/template/default/default/poempl_gruen.png000066400000000000000000000006731443716113400241020ustar00rootroot00000000000000‰PNG  IHDRóÿa‚IDATxÅÓ¨ EÑ»¶m#­mÛ¶mÛ¶í´¶mÛö†µ­ùïÛVuzinÌ,X‚`&i˜ Œ’Ò]:»l_$ÃdŒL©2›LQ1!ÆRvÀ4.3‘ÊþFË8R*0Œé<—ûf““ˆ“#ž‹23Ê[†RÚÇÀ@&‘㯊7Åš¦ÐI&Zˆ04Bßäû’[ôÅÑ_ЃÂâèA2úÑ)òìÈwS]Ne饳Hc"íf8)™ ])u[Ô_ÑßE7&ò˜Žä‘èÒ‰ œp4‚ÅüÓbŽeŠ­g ñ îv$e,—ø‚ñH†ñ¾œcÆ+ù/›¥ 3éF<ƒç@iÉBÎc|’rKÞ»æò‡æL¡‘è ÞM¥®2ËøËŒûòT®ÈX©M?šÁç@ ©JvºñŠó.‡‡¥?¨L{ê-ü T•JR‹ÃlÇØ(­xOZS hà_ ‚”“Ê cFK^SZÉò@õ€D È5ÅJk‘ÂÿâQ`EìSØIEND®B`‚vdradmin-am-3.6.13/template/default/default/poempl_rot.png000066400000000000000000000007411443716113400235620ustar00rootroot00000000000000‰PNG  IHDRóÿa¨IDATxÅ“CÀpÄ7wúl›Ï6³mû–mÛ¶mÛv²/ù˜k›Í6Ïþvæ˜ù·Æï&Ùlñã­Vi4ÒŽªÕÔ_©”•kµ4 wÃõze2Ñh³™D‹šÔ©Nç€i.×Z¹81Öl.ùƒ€è»M°Ù®cœH-€Ã“íö»y¿À}()rv]‘" Ð>Œ8Hèmw–,ɳ<ž(²~Àˆ¤Å‡ãì¡J•x_™2R¼a„Á×$ R¹V)òøxõêŒËË}•JFaŒÚ€Ž§êÔá­E‹2`Kà(Hâ¾ôR(" <~¬Z5–ptÂðËÒUŠúý ÝH4 ”HŸ¨WNÎDé ‰³«T)>R¥ ŸÏÓ99C Ë'±>tÏΦΙ™ð•<{0ö—-Ë;J”¼Ü13³h‰¾hŸž.# ön‰ )\û?l—–Öp‚ƒoÚ¤¥Q‡ŒŒ’{>ò"ÒýV)) å­KVÖ·­SS bB·nx”âÛ8—û¼&ŒÓ(öÊù‡ÿýßøq}¹ã´¤6 IEND®B`‚vdradmin-am-3.6.13/template/default/default/rec.gif000066400000000000000000000006341443716113400221350ustar00rootroot00000000000000GIF89a„ì¿ÁõßàÏ_c·ñÏÐÅ?D⟡篱ÔorÝ’ÊOSá›úïïÀ/4Öwz娪»$Ø‚²ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ!ÿ NETSCAPE2.0!ù d,cà'Ždižhª®lKÑ‘,$#!D„HÀH|DIàó“@@` yH‡¡ñ§`&I¡ô‹|Aad!®EheU` N‰9ÎlD (R9.ŒŽ!!ù È,à'Ždižhª®lë¾p,Ïtmßx®«!!ùÈ,cà'Ždižhª®lKÑ‘,$#!D„HÀH|DIàó“@@` yH‡¡ñ§`&I¡ô‹|Aad!®EheU` N‰9ÎlD (R9.ŒŽ!;vdradmin-am-3.6.13/template/default/default/rec_button.png000066400000000000000000000011051443716113400235410ustar00rootroot00000000000000‰PNG  IHDRóÿa IDATx•ÒÌA@áó°µmÛ jDµ§¶mÛm\ÛîÔ¶mÛ¶Í󪧮M¾‡ÅYòèÑ#´Ö>öüœÓ:û­«Öº¦ùÎVk÷­Ùlh?ÇŽÃ燬Fo£ÛÝxZÑ¢÷öéó÷Êœ9reÞ<90dˆÌ(]úN#Çé–¾£”ò ¤úB¬±)S®½nvøq÷®üzòD~=~ìËüþqÿ¾Ü_»VzeÏ~,$sùvhMw`BÚ´«ßìÛ'ß/_ŽÐ§“'¥_þü§ˆå¸¬5ƒ\®úwfÏ–ÏFÉóuë¤D¬X#3sä8óqýzy¿fM”|0—2«\¹ ”Šg™Ö+ö÷õ´i{«V•nJUã’Ö•W¥N-χ “gC†DÙŽ¼ye„Rƒm úb+UªÈÃ-¢äv½z²Òã‘ÑJ¶‚6°5fL¹V¢„Ü©P!B7Ê”‘ñãËJÞJu¶÷À=îÙãvË©)äJæÌr-kÖ`®dÉ"gR¥’½^¯ØmgÀŸ&J²gÀ0|äx§Lì´ÙØ:åñ[w̨ ‡”Rë´¦Ä ׯ‚Dæš1¾Ä2¯r, 1äœOƒ<ÀøšÚî€€ßØPº&°ñ0üy òÝÏã$ükâCUÀc>®xP$? ¯+*ÚB0)!Ôð=ÑÀ±ÿv4@²iIEND®B`‚vdradmin-am-3.6.13/template/default/default/sortiert_asc.gif000066400000000000000000000000701443716113400240570ustar00rootroot00000000000000GIF89a €ÿÿÿ!ù, Œ©Ë bŠôЮn­;vdradmin-am-3.6.13/template/default/default/sortiert_desc.gif000066400000000000000000000000671443716113400242350ustar00rootroot00000000000000GIF89a €ÿÿÿ!ù, Œ©ËàÿŒf&z™N;vdradmin-am-3.6.13/template/default/default/spacer.gif000066400000000000000000000000531443716113400226340ustar00rootroot00000000000000GIF89a€!ù,D;vdradmin-am-3.6.13/template/default/default/stream.png000066400000000000000000000010031443716113400226650ustar00rootroot00000000000000‰PNG  IHDRµú7êÊIDATxEQø•q­  kÛnPŹŒ:kûŒ5gÎærޠƺƟèFߟ6ï}ö÷%õõltœÒ¹‰y‚Á $m|ѺmiÅ¢"ßm'RÇ¡Þo²½äZÆ9˵5ߎW#Ø' Ñq"|5z/r×ÂuSK!5ÓÕ¡g£¶ûäx¹” ¼*été>¦÷£%ÛÙÁq ©[ˆÈ%:=^ÎÎ@ª08ÇUÖöSD–ôË:7;N$Ããe6ÎÛ34 ­éôÀçè V<[1¯÷‡¯¼ÏÎð¶L7ÌçFóV¾w¢œôyn¢Óy@0&[ôÞPRrt~ñÿÏéÁ=ó6•j?ƒ ºG/½‘»ƒÅ 4çFþ{ÿ9ëZ§?&í—°†k€¤Éÿ :=Ç ­yëñV‘·@j¤–@Oºm/0¾@Ë®›qd¨šžc=ÏÏ0ÚÉ"5<¡`swh݆sZªûXB;riaO‹x“ZØI¿ŒÜ°?C«Úê&-ךÎܳqaýÂf›ø"´°±Ü»0žh½³z ãõ–í •ó‹F¿B€ÜçÞ¸r åÝ‘ŸBGÄ ¿)7Ö^^œUšOâîꞇ>ËIEND®B`‚vdradmin-am-3.6.13/template/default/default/sum_find.png000066400000000000000000000012701443716113400232040ustar00rootroot00000000000000‰PNG  IHDRóÿaIDATx}x4W†omÛ¶Û‡µmû·ÛÖzcÛ¶íͬm;¶Î¢n'}¯ñ!uW•5}[U×Õ4woÕ·vCc[Ï\]SgUIyÝSyyu£½ ÓK¯ÎÌ©.«k··ô@ï8ú'1èŸÀ olÚº¹…E•Ÿ9ÿ]€ð R ¿)¨h²wOÂ4O© 1Œ`góa‚ÍÛ­ihÃÒ2 îßÃ@þpc× Lr… 4Ád·G"Rl§1¾B #S p8‰o€–»Ö=:,±ŒN±m~ ¨Œ&ëõ 0A¢Ñ•žY‹ð ¤çAßÄ Œ1¹0#”_®µÉì6f°ÙÀôûšB t"<¢iË®¢b\wRöO¡}aæ——Á`±@tLR%ÂÃÃ'ª·¥w†,wñÄNZ§À:?K««°¾±c“àçyáñÍ÷'_M$gé†gX€‰$ Rk@ó7jç9%…'O†~†ðxë­ý—ï;è}œHÏ530ª4 2™Ü)°ù| ’Ò!!!2SÝ=>w´¹ý^ôoî¡=t“Wï;(,*œC—H0…G&pÏž ÷òŠý:!4²¢6ìÃ-!ùÉ^Ï›ë‹öÝz ú;—!ä2àx¤}wÛQvÙK+¬`Pf½õÇo®ÿä6W$n!îø;„Ïo»¡øì“IÛXaˆòÄFÁ7”¼yëÿkàÇ5ôƒO8g–—þÀ'?µÿÉ­h_ÖK®ñ§Ðµ¿Œ€®B8xþ–b¿~$žÝxv]Xw"~~«A.^ ðÙ÷ì-×}òH{äÁáÀ§øZÇŠéß$IEND®B`‚vdradmin-am-3.6.13/template/default/default/tv_bottom.gif000066400000000000000000000265521443716113400234100ustar00rootroot00000000000000GIF89a€(÷´¼Å½ÆÐÂÈзÀɪ´¾ÃÊÒ£¬·ª²¼´½Æ¬´¾ÂÊÒž¨³«µ¿²ºÃ°¸Á²»Ä ªµ§±¦±¼£­¸¨°º°ºÄ¶¾ÈºÂÌÇÎÖÅÌÔ·ÀËÁÈÏÄÌÓ³¼ÆºÄή¸ÄºÀȦ®¸ÆÎÖÉÐØ¤­·°¸À¶¾Ê¬¶Â¼ÅÏ®¶¿¨²¾ÃÊоÆÍ¸¾Æ¹ÂÊÊÐØÃÌÒ½Ä˰ºÆ´¾Ç¶½Ä°ºÃ´¾É°¸Ä²ºÇ¸ÂÌ®¶Â«´½›¥¯ÇÎÕÀÆÑ´»Å¬´¼¯¹Å¢ªµ¹ÀÊ®¸ÁÀÈÒ¨²»©´¾¬¶¿³½È¸¿Ç¤­¸ÉÐ×½ÆÎ¶½Å´½Çª³½¡ªµ¥°»¦®ºÂÉѬµ¿ª²ºÄËÓÀÆÍ¨±»´ºÄ¸À̱¹Â ©´¾ÅÏ­¸Â¸ÀÇÈÏ×»ÃÍÆÍÕËÒÚ§°¹ºÃ΢«¶ÃËÔºÂÉ ¨³°·À¨°¹ÁÊÓ»Áɵ¿Ê¹ÂͽÂɨ´½©±»ÀÅÌ­µ¾ÂÇϪ¶À­´½¼Ã˾ÆÎ¯·À»Âʧ°º¼Ä̹ÀÈ¥®¸¾ÅÌÀÇλÃË©²¼¾ÅÍÀÇϽÄ̺ÂÊ®¸Â¯¹ÃÂÉпÆÍ¸ÀȺÂË·¾Æ½ÅÍ¥®¹ºÁɨ³½ÁÈЭ·Â¦°»ÁÇοÇ϶¾Æ¯¸Â¼Ãʶ¾Ç¿ÅÍ®·Á¬¶À¬·Á¶¿È®¶À·¾Ç¯·Á¼Âʦ°º¾ÄÌÀÈÐÀÆÎ½Ã˨²¼·¿Ç£®¹ÁÉѼÄÍ­¶À©³½¦¯¹¿Å̤®¸®¸Ã½ÅÌ¿ÆÏ¬¶Á§±¼¸ÁÊ¿ÇιÀÉ®·À©²½§°»¾ÆÏ¤¯¹¸ÀɺÃ˧²½¼ÅͰ¹Â¯¸Ã»ÂËÁÇÏÁÈÑ®¹Ã¾ÇЦ±»³»Ä½ÃÊ­·ÀÀÈѽÄͱ»Ç­¶Â¬µÁºÁÈÅÍÕ¦¯¸¼ÂËÀÉÒ«³½¸¿Æ¾Äͪ³¼ÃËÒ¨±ºÇÏש³¿¤¬µ»ÃÊ·Àȱ¹Áµ½Æ§¯¹¨±½¤¯¸®¶Á¬·ÀÀÉкÃÊÀÅÏÁÊѧ²¼¼Å̾ÇÎÇÐ×°·¿°¹Ä¶¿Æ¸Áȱ»Å®¹ÂËÓÛ¨³¼¿ÈÐÊÑÙÊÒÙ!ù,€(ÿAUªô!H…|öŽ Xë .âb9"g’ÅX±eY51(ûô‘ER¤É,³ˆÌB($It}²d¡@8™4±édCÈ›p¶mófeNËæ(µH{¢jr@Õœ9.X±6hà €×®NF±RB–l£FþUûèQZk|òÈÍs(#F êtW%*T\¹j£ €aß¾]YÌ8Ø1"Kv<¦‡å+‹xŒ92ãÏŒ9ˆæpíÚc "®}3 X™2J” ¢ ¶`Û®¢Elè–!TÀQES¦­M›Ü˜0ݺ¬I11ŽtI×U.”õPœÎ›1C;g[iÿ"E*ª(Q)zñ+ÁŽUªìÐn¥Jt$I† aàL”(ðw†žÑÅ"A<,¸à]@ !]Tha‚ ^¸`Qœá_Z’ 1$’¨‚ YÏŠ%ªÅ/²˜’Ë*!eá  0€#.•$¢H>Ó$aƒ oiCOYä’Ej tXÇ¡ `¥•[d© f\p]zyt.”é2bHƒB0“0¼òJ1( ðŠȸ ‹$|òò/’ 3"|ò™VYJ´…(7ܤõ\|DêÆ¤|lÃ¥§œ¢Š¥1¨¢Ê¥—>óÌ&›”2i)¨ž2˪X´Úꪫÿ’©]©Ôz×,ŒbÈ®‚²Ë.µîºÁ»‡Š X0È!‡tÃWr˜è¡G^ÔV ‰Øf+ƶb ãmtÓé"Œ0¬d¢Ý9œd纡Xðİ2€.. &˜x`ÒåàoNJ°.¼1Ct€d 3œÄà O#ÃÄ,SËŵcÏÄ8Lãñ4öÔÊÈ àR âH`ÉÊ–È2Á‘ä׊ÁÀ8ëˆã¸ôœ#(_€’c5ÔTòÅÑ#3´Ì2Š4ˆ' Uõ'TË—,°T¡ó{ÞxóRÞl“€(½ôâ‰'ä9`ÌV[u€@ ^Opw](å\9o½rÞÿ9Œždº趃 ’­s ŠÈ\tRÈãz$÷+p°ÁFÅ7¢­˜`€-²ˆa‰-fØèWLYf¨Cæ˜eeÚPQ@bµ±˜`®À†{î•·+#…0 ‰Ë)ƒÜr…@Ò3ý í<Ì0§œÅPk§Õ¿r#Ü{; ¸‡ke»Ú=ÑÁäÓUX9À,ŸÈ·ÍG-)uï@ÀGÛÀWÅü Å'rÄÜH9:B,Ä¡?Läf#{ˆ8T\ü ‘2HŒ–‘¤C¢…2ˆ¢¥ˆ¹ÈEJxŒHD«IRHí↓ðÈG p¿∀ñ©Cÿâ“€ÄçDÜÆZB¤¨Ä¦ ^F ýñ‡þÂþPè@²Ð…â áeøÄ§ƒxÀÿÏ~.¨Ÿ Š„*´A(žQ€–ÀPYÔF-ÁÈ¡àCÀâlgÓ„"*P4 øÁªt¥,mA:í¢½¼.q+Mu²Ó¶ü §—ŠáÈ@†÷¸gËAð¡P|B„P%‘–BY’ˆŸ¬)>É…T1†¤¥‡]ýj‚Ø€l0¬®vµ`ëz%ÉKl@0€d$/œ^¥¢™z¨:•‡H‘ŠT?õÓ¡Õʶ8Á+p‚΀8<æ¨Jû¢¢E«$v QÄÃ…HÅ*j1<ÊL&UšIž³I“<ÎtfÓìa¦ÃhXÄò„Z Ä ãhH;1Šÿµ¶$»ÃÐt‹¨€T™,"±|Ò‚À€&Њ—-Áˆn~DD#_ø"‰E¡`]üågw šÔŽ¡1ÒÚƒ£¤mÃd[ô¡+©ÍG>T붸!ÀnÂæ•°“ N°"fr÷Õ'`žq\gQÂ(þ:ÆLdÂ+NˆeY•–¶TØÂ|" RA7”ª1ÈÔ\mV¹J’­*+T|F`a§°‹²Ac¸zŠV©hq‹×ÉNt"/¶²-Jy¹˜2È0Qg™('8X°bù+­Ã‰Árç\XF'̵®s<_9¬3†>ú2ì èX¦рÒ*"ÿ™ŠHÖ<‘ˆJ|b ìÐ-¿›³=ëÌ“°à/l„Nb¿¸`$”ÏtvÁÍhÆWFZТ˜ž™‡ ðÜüÄÈ&1Ëb”B‘$z%7Œ¡ •Ò²D#YPŠMzÂ5o€-lLìR„bkû‰-”…ʨâ.på°bt21«'ø—¯gùƒ$Á=dyxz¸Ëãîb«\¢‘µ©Í"dSIE¦‹Li2Èňæu‹Iä!?»E «WÚ.ïò»e•2•«*" ‡­[’/”L*§+]^¶W ëÞh¥šÍâȳ‡^`MŠCdÀGt”,Ø$?}ÿ°IdqN¸Üåéü† Š¡I¨BöT§È ¢ QH¹’P<~1…âN` ²h-^†iZ,¡@Ë…9§‹K —/!fž&n$FY¸Z$³Æßºöµm¶Äï9{…x*’‚ØQ!ÏÛ­güÀ°bcºö~N¼’`H  —CxÁ ·ÀDó\AÜ&Ü Èä_€DŽf4§ƒDÐ „a ƒèGz˜þ¨7½?˜Àz&Œžô èe¤ÆÝ~&wG e؆r4„´’³ªN+[Ô*F]—܈;xïÞϱ-nl‹kÑi#64X‡"~¼ûîÙÿ©¶Äd¤>`ËC `C"®,~Áu§/Áå]—-ÔAââ³Á0\—–iÍUNS÷2––t°ié´\Ø R@CéÀB“p D@Õ@4t–>"_ÓÐD2/ÿ’f/ûbk¢/^â-þÒR-5‚.È/åÐïb3fP73pÏgÀ”dÄ~'ÁTe‚åLcQ´4mB5p·Ä8ØÂ,vÅ)rá)s……1@*ªp >¦o™†1Fcšò)¡hø ž¢ ¢b"àc°oŒ`cÙ€*‘ÂTŽ"m’ ‡Ž²€T|€KO8TÀ €" °„ ®ÿÔpØá_ & VRÖQ‰–HRz£ -à1Sl ŠmRŠ]9%Wb$6ð.ïÒPgÔ@ ð³?õ@:â Ü”"¹ Ñ – ‘`iÍå¢NAùÄP Õ ¥Œg0!íTNÏuNIiÍ@C*0Qññ5 à HÀñA Mã D` 5ÐLÆ0_ tcöx7øpct.N /V. Ú’SÝâ §W’ˆ|’S‘¢TG|2ˆÙâ8Œ0G±!;´#;–„W ¦q’!¯W’©wz¨÷¯{,"™c€c žÑ‘’qyhÿ y»ò……`|PduE`…".Âà(½´`ûXXG}Õ—lclèÃQ[Q`´·õ޽ gcM°°8MfwÆ á ä…1ñ ûË„àBÝåC^¼Õ[ñÐ2ÄÅPùô2ЗA€[$S µ2$s˜31ö° GS µX‹A¾0C*„~#çè@2!è}@¡™rÜÔMÐ5LôkE$l—å^ôXà_ÀôJ£p7ÿe( ¹p|UTIÕ¨âF~0+4Fc$-w!+Äy>–Uiuo‚€ ®PH‡4H[En…1Hžƒ‘ôF:hP;óÿ–4™™£ˆ4†±hОáÙx»ç Ú  Ê`˜ =À°Ì£ ®PÑ=À u"'C””Ø.`†qÆ€}mW;€fGv A4šèç!€¡úrã4H€`i´3+Nà$R €Ð%(*€xtÄÈPŸ€‘¶A%\+ó (¦ŒÁH /÷\–¦¡Ù¸6âøsgø>XÕè#ìÅQòUfuCRîR%ÖÁ‰º 7QR%iD&ÃÐ7sÒ&þÉ Îq'6%ƒ@‘R8Ùò päö‰ ¿ÑH³sy“áð§á “"éy,I{„:)ùª7­ÿçzŸçd@þÀ’ª·¨²7z€¨!)æÉžhàG äwzŸÓ”r‘So'nZ8/%”»T.ç`_ÅFZ‘>ê3}O‰Zàçcq™Õ4Mƒ^Âê4TÊQ “ÆPа gI H4‚ 4Kƒ1†91A4  @¿U"•**O2 Ð8 þaÐ%Œ–€² ¢A N,1CC,á5 ± -k„@À& šÀ¬Š  ¢P5š°¬uÅÆ QoÆÉôEå^°‡µfbÆ”\¡w¯ä`b¾Y&CET{è(I• ~ dª€*PUJs•)›"*žÿò† ’)¸Â¬‚,«âc°¢)¦2)D‹*nP)|ÀTLåÖ“Âa‹Â Gè4@S X…„XF Ç ¯ÔO&X™ðJÄ„Ä$FW&›oÃ0‡u±;±OY}ÉÔLD@ÐÐ sÇQ z·R#D°°òñ±phe™4i,c A:\÷]´P QPsÕ¨Œø2Ò!É8äJ®µõÄNBOÇi$qNÄØ~]DZM24²Pš&a"Áj¨Ù?EÄDN”½EO±èášÃYOñ»ÅöEZpwv×`Ž8 JÀ wmÆ—Ò † wT,¨°+•óÿ§Hë)1 •q¢w˜‘:ê[’jz.Énî—$y‚ÑVÓé– ¾² rØ … OU*¥P…Œ§·Tˆ„¢_ûJ ½ÄeJÙ`éBLë°\´ŒµQ”LlBTÁu°š$×âWD$'6{¦?àXXC–Ÿ3;P™2á åg äB)"Q¸“°"&t"&ò­À5®%PåZNÌÕ (–0hÚE ôCñC8B5 8ƒMĸhY^›Z ³ƒ¡°¶fÖ0qÃ`7wì‚o7ú¸éb÷0¶Ñ(w8r À°¿Á-ÙV‘† c½|^䦑ñF™Ñ¢'“©“¥q ®3Òò¶ö¦U9Hcÿå+,€)=©$+1dòPWq‘J·pKµˆ_+q‚åJ£À >LÝ!Xé y¦À$%;xƒ÷e>õõ«`ÄQw‡>wG_3 ³e^7p P³–w@2´]1h¾àB„ð‹Ñ53ŒV¢ÅX€œ 4i,£¢/P1,ÃuØ\WG(¤ª ó3 Æ…úC?Ý$vñ1ÅŸMÐ 5¤°6 …Ïb6ÚW«øÌ0qÓl‚uG¸l« a– «ÍÚGè`Š"mn yp8ÌdùFcÓœuØ ï ¼òȔTöFV[u ½ÝX@°—Rb«’)¢B*¨²É†ÿâ(ÜÐIÝäÍ(|¥|ȳ]XlCÚ_ä”˱£ XnKl+¼çwo÷°š€Qì~ï‘DZÃï‘? $~U@5Ǭ[Î]ÖÅ‹/"®*º¢Á˜y ¢g ÿ1ELPÝ, Å3~)²@âpâ±p"Q ß$jÔ¿ +©–jk=DN°Ì$ZŠPB^õ¾Úö¨\jL. f2 ~ð7ßÒ=}ƒ-Ü" Mån‚ À0|¡ŒgŸºÒ+½y›÷§›÷+9•jzô¬Gz•Zz¦w©+‰z­'z¨¿ªCëÆnæI×À±s9‰±–ÿD®qIàŽÞT-ÑB-~0º(|dAõ-bÂ=â2/Ôq‰¡@Lë± gšëAŽœ}êÈQ{6x6Q“ !5õì ES ìÑ3H˜ó—"#Òz3ìP2ÁÌ3=ƒ #£[6A&#¸°Ö•p¸P4Ç­µ¥˜Ó£0Ià1Kã4i}1þM šPgò¼DHqšHaà@øƒËñAEE“r¹¼ STEÉ›±'FSæµR’p´ƒHpuº+ÇÑ:¶œÅ©…œz` 9{ —Â…Xh½âUÃ"Ð-Io+¸"e5÷6Ü>vœ[¸ oÇúÿdCv=Ò@-Ò’ˆ÷Ÿ˜ \ާjšŸ>àÑÐJßÿ À=lÂ&25&Ó%Lî.Zí«ù° Í´ñ¡Mfײ è÷™ Æu3úr ÈáÞl! ª\P·sz-£ì'á´tÄ8BÄÀB ÄÕ@@„h%»2rC)$CÌœ¯8¤CQàð e“Q;ç! o×^ýŒÚ÷¥ÏV7›.{B/¦K{RKP®Æj A¿;WIæ¥1#}˜“{¤±©f>ûŒ!¾éè-Í…„;!ÏUc5cu(†žÂñ™Ì,×ío¨D# 9%| TÖVéPøSµÿ´-ß‚ É-IF¨LXqèS•ûãÍt6äQ6 ZëžDƒùf¹yægü 9BÀàA‚c© FlÒC¹~Y²$ABÆ*Tˆ‡ ¨;!'p$\_¾€4YZ%•AìÙ R«–¢ %òä©R­eŠvV"Z)Μò-Ö A9q4Xú`Z‡'3, ØÒް<ˆ!+F, ´(@ñÊí+iÒ »u 3L>ôbbÖ&`z{ñÉKݺz :$Xð_ȘP¡J•J N…X°\¨P§ÌŸ;Í C•ªT«ftY,–]¢]û’ÿ€E¹]¹Ú ˆ‘êÁUŸ:<8ñÕ§NçÉC$[Ñmù¡î‡9ìƒü@\תví&Oüüí+²¯P4iRLŒ#øð‡Í;ÌÅýùº„âß?ÔŒð Ÿ@§y ‚„šI(Mޱ'©«LÂ’Ð0‰¦ñ°Â=”¦e–9æÄ™‚øàƒ Z<†¨>ºc #ĉ(Wü ¨J‚áG eXæ ›*ñ¨jª©—Oªp &žt€–O> (vØ¡ XñòËž¾LD¤rZÊÌð@6ÛDЙâ|À™~pÆ™àNÎÉ„NXae'0Ô D8ÿçD5ôQ¥†DTRy„N9UIJ)»MJÝ$µYfadUVí6.• hÃ-7rÝm·Zi« V 1d6]]¡¢€o’-€ f]™ÌXfvZj™µÖZiÛpEn ù«Ÿ"Â-¢Ÿ~˜æ¹bü˜o˜ tbaøF˜ö Å f@ð¸ð—ªåä·A¡ф̂…"¨/yŒ+M" Br±ÄSúèC–H"‘E–`Z1à –&äVhYâŒ( pÙå.y"˜àæ›—ðØ’\,–¥™x&!Æ’e¡…Éœ>²ðK, É¢gª³`ÿú—,²ÎzŽ Dj­¿þz›-«H *ªÐ²Qzé%…D‘;<І¥—=H!e¾ð÷o.œúÎ~€tÑQFa¥œF榑F$‘¤%*—>˜Ó<ê˜+•9Æ<ÛL°VwÙeƒ Q Ö—=¶€r{½€Er½57ÜsßuÔiCe—U…½ÌôÊ:醱Í@óLXC;¤FÓiS%>ÑEÉ·ßòFxBD\Ð%|ïYQôuÔðEEÐ)¨Œ1Æ=äæ{Ê:Ø¥Ž`ÉÞèÚ׸mxík˂ز ±E‚0 –pÁ%P¤`)Èÿ²(°¬ QYBH²âlœÀÄAŽ0ภa U‚ ‰%ä 5(ø""¿ø³°Š‡ÄB‰YÚÁA¶Ô "Œ a³ßÁpE,òLö³ŸS¼ØˆO{rÀ‰ÄJ ¬è+”9Ìeg|œä°ƒDØ‘ŽuÄÎu2—Q¡†1Ù(E©D%ªRç4§D«VÒ´f·ËM®pÉ+|£u¬«˜Å:L^2c ¥Â `@«)3ðÊ \C–W(€ÐK4´AýÀbÈ ÂLÏ0À{šðö¸Èp„÷ôS¯y±b™pÔžøÅÿ¬oz;ˆÐ½ASòÄQ ¦ /y¢r«CÚÔ¦%Šemó¤Z.´f1Š`Ìó-&@‹`HaŸ‘ÁÇZqÐV\°cEûX$n….ĬfYE'Z³táe. á?QPžÝ3óœg• ƒ`‰‡ ØÁ±Ô5—b‰Kž€Eÿî–7R\Ñ~5#ú4þª^õÒ…#Äð–b$5©ç)Ëù°LD¤Ar÷Á£äàƒ씂sÕ‘Ž-žó™Ê´Ê”Ö'[wɳ¾Ò•jÅ@˜ðÖ·†á”aC*ÛJW¹ö ¡ü†´X-g¹&¬¬RMtªã‡R B±ƒ†#xñPÝÇÿ’øÃ3;ÝÉ_ìK°‡ì¡%Xƒ6ù¶˜p_ä¢1 ¤ oö¤'SšR“v°¨-kà‡7 [#AkS«!¼ƒ˜¤‡ÉõÈÃb„Ã;DˆÄC#ÑŠ›µ(9QQ%@Aß$B%8щdð¡))ðΫ! qh@6xC}58ä àï}s›ÏÔº²=8\ º¸× f@ Ãe‚š‹’ð„ÀŠðñBð1/ g ÉÍ«Ž’«lå”ð—xÄÌ1N ¾ªÎè¡t¦„+@Û+”WåDpWº2aLÀë ^à$@ÉKÿVr’G€d$¿õ”vU%+IYJÈ’”²üñ)³Ì4„9ÌÔjCʪ ¾°‡.Ål1Qð/s-kA zæS1\À b¹@Ÿ Ü•-lO¿ø%‹Ü_A/Ø{0‡ Ô¡|$¨‰ ÒŒà ­ùÂR£Ú/j ª!q‚ÑêON@–h†E\-"æ"h%a€8”˜$&÷?©’¨&E,EØùÈÉLŒ=×âŒi XN˜Ý0{):š u û‡?ÔäD(&ì§L8PÝnãâ×8aloÄ$N1ýˆà0&t0Þ… P·¿¶.Y<•àd#ÓõÈ/¨kÿ ÞƒpàõßJ®ë`©Ö1\#›%d qpà•˜D\‘,g‘Ç1æ±N»Øø4³{º¸Yšé=a°1õ*ÇtqŸgòÇæúuæ,°(©i)tRSòáÚbÛã ûDQX²Ü*—±X…¬'‘‹¢,GC(BSýu¬°ƒg ; Éö“©  'û˜Ú´,±@.P%\üº'Ǩ€Ò·é<=Á6× ðÕ <á *zžp'8˜M›]öœ4믰)~˜­“U)M-rFÆQ¹ã˜[Bð–˜ÑÀºW†Y㯜e-WçºM¢5w¸kÝîqÿ•+ÝíŠɨ m˜— Ð(ç£ÂªÜÀîÊj ŕӔ‰•PTGà±|.ÀŽù GýL PÔÿ4åÇ&Rš-£@ =+ê¾?s]èw&ÀУ`tò! µ©‚O˜‘‘ˆЏ˜}☚­S™!*»3p ü @5œY‚›éºƒ:š“Q‡£9Ñ'ŒùSh†U@®ø\ø‰ò²5<¸¯0±ðµ€¾øÁ\‹"І"`†:ëÁ$L‹´@—óÊQ [7Ó0í›*À#¬âƒAÈÆyë*‹A*ÔøSè„Tÿ{ã{ÛJÒ=KÒ=Üáßh× èaC¬U‘žÍ„SCCÒ*ê€Fø‹é9æðƒ¤ò§*ŸóŸ5Ò6@q°sX¿1‚“8ñ¢ø)›EÁ—'ØŠ¡´¯ØA±ÈA3@ VdÅýÚ3CÓ€úzÛ ù÷ú‘ ¨„‘P"¡©.Y """šHÀ Ž¡ìš€Š’™‹Š˜Fj¼¨ŒÚ(ÊF’ц’¸#„,I›þi§¦ó„ÿI-ÙX˜  t@yGp ˜òÚ†€›r›=0†Î:-,ò›/Ò¬~Hq‚Gx#ðùIÈH„„[ða©‹g±1ÈÿJÈHJÈ•ÙI–oà7RJ¥p¸½Ú1~ëS8¼š«0ÉÀ«Tú·$«+*s8Zº–]q…á« ò0Å0¹Å¢,ò¹B% ”õÙD;ñ"l:-¸Á¸©‡Ñ:-¦„Q …5¸¢ƒÑ›€üÁ¹"¨¨M¨„´Á­, Y´ JË Ú ´ì˜% ´T(Ž™ ‘ÉÀ±#;ˆª¨j ô ¢…ˆ‚€°ÃËT;šb̘„‚`€%‰Á¢¨…œø‘a;“¤8¶¤Ë EÐ/©"M˜Ë̇gy¿ùË6mcÇ¡¹šax£›»€erpÅr„a iè/Ðfè‡ñ@ÿ|›–á,«×I–|K–Œã2 É»j2(ó†kΗ¤+ƒ£«æ„%ZÒŒ¤$ ?¼ŒUQ AdÏX•®:,æ8¹Æ¢¬é+ÊQÐ Ã0V?D©°û$?Å)þ$»žË¹Ÿ;‡y5Y¡¨cÐO@EX1ᑞð®* ‘P.5ˆ#€ârް‘ža‹Èˆx¡#@5 òÀ 8(±;¡°Cš ú§¢yK…ÒoÌš>#ÈŒáQYxG† @Ø l(Rt €ÂÇèš-¹­¨¸¾¹ÊÀ)H.0sØÊÎ2Îj¿Îƒ3]D9”DyÿDa0SD©œh³kÀç•=-7ÀS>8•MÔx†g@•Y€ EY Øx$ØOÕÕ( ãP¾RQ!•M¨£S‰GôƒÓÅÒ¾8ÊžËÑžÇB±F”mÛÄG¡<§ “(È/òcø,¿á­$ýy³i):€Ýbš$•K$„)ƒ2àQe5…$UVŽIK´”…„Ö¹¼Ë³™Á„€ˆŠ¨–̘™™hŒ€Q†"‰ê!”ºP \P’%¡{M%¡¡)±WïŠ×c¸€‰c0†õr6«ð©5©¬p°ªzáû³K7ÿgr£zÜôƒWPªbxièØ6#&ê‰ ·POÍY¦9²£Ô„ó+JÎŒDE jÙ$åì±U:¸ê8#3²!£«p‡{8“TKBi¥XºÐ$×QTø Ó D=`D=HŒ«í%» = ŒÂ@£r 1X&1 Žfra û0Ÿw—y±—‰Åö‰¿…¶:¼MiÀ @º¾³‡ø× ™4£@Š¡X !z} ùˆZ¨ \ÐЇ¡¡ˆ.”˜ÜZÓu»qÕ¨¿¡o×²ó  œQm´À³“K)¸óч,àvtÒÙÞÚš9øš9˜ƒ>(ÿ6`ƒwdVpà(M ®9(=›À+ÅR€ œ;ñ¢H”Qø>k†¬#Ìñ#;Ò?è*ÏÊHJÈÉ|û«NBÛ¹9œCZê=ÝCÛ˜Œd°ƒ\AA¨Œ7LóYTž?œž’££?hD‘OûÌOMYŸDyB!£œ^¥ÄŸ©ÔÇqÌ` ¶©šz'xb¢˜ƒ¬iGt(š8a@ð'ÑU5 ™Î(ê‚ráΨˆ¢™X˜!!0!—Á!”…/`‘ ø‘eˆÜñ‘©€ (‘±‰^»WÍ "y"©Iˆ,Q"š-q'¶qÍ ¶¨3 ô 'ØÿùãûsÍíÁ¹7v£r›“^(ª;s¹S_ILÕ÷üÇiþ,‡A±0E9?a…¡R÷©ÛXŦ+Ú›¦\§:@G-9›Â-(ˆB`šAa¶lË *ÝR] ”(Š]‹ÊarFhŒ€q•"¯!ºš€ ÚV Z‚”V~b(‚ ÞŠìw¤®Q ¬zT Þí]Þ ÞݵGªRè-]Õö;f®Ä¦Ñ*/m€ö34M i;uƒ¤ÔCŽ[•ÿË@Œ¼–ÜØÿ$»¤Œã“´¸‹Û8¦un“d²²äTjû —-„çCê˜7GT¬ebŽQ)Ÿ¢”OX–¹ËʬXݬ¿é—Ï’JùÎЪèqL›³IÇÐìvÌìµÞYpk´ŒkòÖPƒ]pÍÆL Š‚g”Fj¬Ær ì›ÙV ;ºü­ëFŒ¡¬!®}Ö“èâb"-I.E‚»ûîŸ^ð„qêJÇ|œJ¾¹RÔúî“óöqD…„œ•Ó0ªÊ#÷\7‡¤Ž{±ÑÑJm$F èÙCH¨C;\„Ü˸øå¤ÝÛ™åÉ–ʨnÿS&ÄðÓç“BdkxÏÊä:*±Ä i kÕLHœB‘íFI”ó#P”Îò¢;¹¦ÀÁ&½!·©­&q'ø`,aBPë:K»\ËŽQ D¡ê(2]¹vQºKžÁ XÀÅÄ:„:š b¡ º ÅNÒÅÖVâÆhÅj=á¡…»`72pGl¨l mÎÞÝÍîÝ®±+ð `^ç ­‹^­2:47’BòßG„È[èÉN‹ ³KRN‹ë7»rÎÄ«éT8&C2‚SÉ&#ƒ} ƒèÜwéd²P¸vOîäÞ«àe`ð–¿Hi=pÄMȹxŽÿÃ:,G¨#ÜtVå„i¢&2¢`Áñ öÕ >qL²1›Òl#pGv—‡ v"l–€²Û˼ž( á¿á™!O?ì ¨RˇÀº±®4zx~XÞÍ_ ;ƒäª’‘;¨qì’D Šžp›fF ¡h­ Ř~颮ì®HŸE!·r+DÞ0HÛ[˜ àÜ•c¹%X’%.û±*[¥T:¥·Š2·²'ó‡À÷}ø~N¸"²‘ì7’Œ¥µÚ8¨sjÙf>Jà–2÷–ÈÀ„è„Wè <,$·cKL ‹Û”q㹺Gö‰<ú«¶´ç§¨€8a¨X惊eà Qˆf›ÂÐ*˜BX…xˆ‡žéƒdtK´tõ¶¬gW™%ÁfÄQ£¡)È…tH‡€;vdradmin-am-3.6.13/template/default/default/udef_search.png000066400000000000000000000002561443716113400236530ustar00rootroot00000000000000‰PNG  IHDR‘h6uIDATx’…Ä0 ÅÒ =Þ5íçaOì¹ÈCGIEND®B`‚vdradmin-am-3.6.13/template/default/default/view.png000066400000000000000000000011331443716113400223500ustar00rootroot00000000000000‰PNG  IHDRóÿa"IDATx•’Ó¶-GFg©±¼bÛ¶í\çòZy–à*Þ¸Œí¶«Nclζ>ü£5Çäé§ŸþØZ»º²²ò-\àØþ㿺®ûàñÇ_!>Z]]ýäØRJÛ{zè¡ÀŸ¿í·•%†Ácbÿá þü{_å×ó^õ†Ðã:ö!ºÚ¹èzàeà+/žý¶×~øáwÜy×ÿolµZ©³‘€Ãy0ÖZ†A£½çuŸb],æãéÿ–æ³µÈÜvÓµÌÆ!‹YÄt!… /[’¼bc·ÂÕšwŸ›5>¯;_ag{×5Bƒ˜SµŠ T§B‚P·’ºó¶6 P† A\(ŠœFMHËɤA+ÎRÕú´@×TMÏnRºŠ,Ë.ý²<.jø» ×_=¡íŒV4mÏænÁ/'ÜcK~Z ½ ¦iІq| 8¼s€V’ÁZвe7­{z&IšÐ¶\ØÛKÄ5“î´ó( ˜MâÐ ¤`è-eÜùk!*ŒéI“ÔI)íy²,–Ë%“XsÕ|Äl ”<]%Í”Î)[í ÊíÂÝyëÀv)×ÍþÄH;ƒ¨ Hƒ#:–¦CÏ;‚!a¯s—Që€ÿúýï8ë@ÀéSsî´‹šKôíÏý¥ÀïÖºkZKo­%ŽcF£gñKª¦‚Ü2üÜ(ít.•jN ¾²„§€IEND®B`‚vdradmin-am-3.6.13/template/default/epgsearch_config.html000066400000000000000000000133751443716113400234330ustar00rootroot00000000000000 VDRAdmin-AM - <?% gettext('EPG Search Blacklists') %?>

help

- -
--:--
--:--
edit delete
vdradmin-am-3.6.13/template/default/epgsearch_list.html000066400000000000000000000246561443716113400231450ustar00rootroot00000000000000 VDRAdmin-AM - <?% gettext('EPG search') %?>

0 %?> settings help

- -
--:--
--:--
find edit delete

0 %?>
-
 
record
vdradmin-am-3.6.13/template/default/epgsearch_new.html000066400000000000000000001054071443716113400227550ustar00rootroot00000000000000 VDRAdmin-AM - <?% IF newtimer %?><?% gettext('Add New Blacklist') %?><?% ELSE %?><?% gettext('Edit Blacklist') %?><?% END %?> VDRAdmin-AM - <?% IF newtimer %?><?% gettext('Add New Template') %?><?% ELSE %?><?% gettext('Edit Template') %?><?% END %?> VDRAdmin-AM - <?% IF newtimer %?><?% gettext('Add New Search') %?><?% ELSE %?><?% gettext('Edit Search') %?><?% END %?>

help
-
 
record

0 %?>
checked="checked" />
checked="checked" /> checked="checked" /> checked="checked" />
checked="checked" onclick="javascript:changedUseExtEpg(this)" />
checked="checked">

-
checked="checked" onclick="javascript:changedUseTime(this)" id="use_time" />
 
 
checked="checked" onclick="javascript:changedUseDuration(this)" id="use_duration" />
 ()
 ()
checked="checked" onclick="javascript:changedUseDays(this)" />
checked="checked" /> checked="checked" /> checked="checked" /> checked="checked" /> checked="checked" /> checked="checked" /> checked="checked" />
checked="checked" />
 
 

checked="checked" />
  
checked="checked" onclick="javascript:changedAvoidRepeats(this)" id="avoid_repeats" />
  
checked="checked" /> checked="checked" /> checked="checked" onclick="javascript:changedCompDescr(this)" /> = 925 %?>
checked="checked" />
checked="checked" />
= 925 %?>

checked="checked" />
= 925 %?>

checked="checked" />
vdradmin-am-3.6.13/template/default/error.html000066400000000000000000000011761443716113400212720ustar00rootroot00000000000000 <?% gettext('Error!') %?>
vdradmin-am-3.6.13/template/default/favicon.ico000066400000000000000000000263261443716113400214000ustar00rootroot00000000000000 °–(Fhn 0Ö è ¨î 000–00hÆ00¨.( €ÿÿÿÿÿç¬ÿÿÿÿÿÿù䪔ÛKª±aJZÖ’(ÿÿÿÿÿÿÿÿÿÿÿÿç¬ÿÿÿÿÿÿù䈈€ ÿÿÿÿÿÿÿÿÿÿ( Àÿÿÿ{{{{{{{{{½½½{{{ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿðÿð÷ˆ÷W·w‡÷ˆ÷(…xˆø¸p‡‚¸‡‡w‹ux‹‡x…‡ˆˆu‡‡xw‡‡wøw€ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿç¬ÿÿÿÿÿÿù䈈€ ÿÿÿÿÿÿÿÿÿÿ( @ÿÿÿ3ÿ!¥3Ìf3ÿ3™f3Ì™fÿfÿfÌ3f™3ÿf3™™fÌÌ™ÿ™ÿf™™3ÌÌfÿ“Ö™ÌÌ3ÿÌÿÿÿÌÌ™™€€ff33ÿ3ÿÌ3Ì™3™ÿfÿÌfÌf3fÿ™ÿ™f™Ì™ÌÿÌÿÿÌÌ™ÿ3Ì™fÌ3™ÿfÌÿ™ÿ€Ìff3ÿ3™™3fÌf™ÿ™Ìÿf™3Ì3fÿf™Ì3ÿ3fÿÌ™€f3ÿ33Ì33™33ÿffÌfff33ÿ™™™ffÌ™™ÿÌ̤  Ì3ÿf3™3Ìf3ÿ™fÿfÌff3ÿ™3™f3Ì™fÿÌ™ðʦÿ™ÿìÌ™fÌ™3ÿÌfÌ™ÿÌ3ÿÌÿÿÌÌ™™€€ff33ÿÿ3ÌÌ3™™3ÿÿfÌÌfff3ÿÿ™™™fÌÌ™ÿÿÌÌÿ™ÌÌÿ3f™™Ì3Ìÿf™ÿfÌ3f™ÿ3f™3™ÌfÌÿ™fÿ3™fÌ3™ÿf3Ìfÿ3ÿÌ™€f33ÿ33Ì33™3fÿffÌf3f3™ÿ™f™f™Ì™ÌÿÌÌ33ÿf™33Ìffÿ™ÿfÌff33ÿ™3™ffÌ™™ÿÌÿ™™f3Ì™fÿÌÌ™3ÿÌÿÌÿÿÌÌ™™€€ff333ÿÿ3ÌÌ3™™fÿÿfÌÌ3ff™ÿÿf™™™ÌÌÌÿÿÖçç©­Ìÿ™Ì3Ìÿf™3™ÌfÌÿ™ÿfÌ3f3™ÿ3f™f™Ì™ÌÿfÿÆÖï3™3fÌf™ÿ3Ì3fÿ3ÿÿÌ™€f333ÿ33ÌPPÿ33™ffÿffÌ33f™™ÿff™™™ÌÌÌÿ€|ÿþþþøøøñññêêêãããÝÝÝ×××ÌÌÌËËËÀÀÀ²²²™™™–––†††€€€wwwfff___UUUMMMBBB999333)))"""ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿããÿÿÿÿããÿ&ãÿåóIÿçlënçåñnKlJÿçlHÿoFI$låUíIëÿÿnF’JçlënóIñHoåÿpñðIëçlIílKHnKlåêFnðHKFKHH“lðIF’ênçIëoëêoåÿëIçë¶ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿç¬ÿÿÿÿÿÿù䈈€ ÿÿÿÿÿÿÿÿÿÿ( @ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿðàxêêINíô«•úîR©ÎukÔêTÇú <?% gettext('AutoTimer') %?>

Here you will find a listing of automatic timers (AutoTimer) known to VDRAdmin-AM.

The list shows some information on AutoTimers. You can change the list\'s sorting by clicking the columns heading.

For each AutoTimer you have the following options:

Set its state
By clicking on "Yes" or "No" in the "Active" column to toggle the activity.
Quickly view its priority and lifetime
By pointing the mouse cursor to the AutoTimer\'s title.
Edit the AutoTimer
You can edit an AutoTimer by clicking edit.
Delete the AutoTimer
To delete an AutoTimer you click delete.

Each AutoTimer\'s state is indicated by differently coloured images:
on AutoTimer is OK and will automatically program matching broadcasts.
inactive AutoTimer is not active.

In addition to these functions you can add a new AutoTimer by clicking at the top and you can delete a number of AutoTimers at once by checking the box in the last column of those timers and clicking .

Click to force VDRAdmin-AM to reconnect to VDR, fetch the current EPG and check for matching AutoTimers.

') %?>
vdradmin-am-3.6.13/template/default/help_at_timer_new.html000066400000000000000000000206771443716113400236350ustar00rootroot00000000000000 <?% gettext('Edit AutoTimer') %?>

Here you can edit an automatic timer\'s (AutoTimer) settings.

AutoTimer is a key feature of VDRAdmin-AM. An AutoTimer consists of one or more search terms and some other settings, that are looked for regularly in the Electronic Program Guide (EPG). On match AutoTimer adds a timer in VDR automatically for that broadcast. That\'s very comfortable for irregularly broadcasted series or movies you don\'t want to miss.

') %?>
Case doesn\'t matter, "X-Files" matches anything "x-files" will match. You can set multiple search items by separating them with spaces. Broadcasts will match only if they match all configured search items.
You\'d better only use letters and numbers for search items, as the EPG often miss colons, brackets and other characters.
Experts can also use regular expressions, but you have to get needed information from the VDRAdmin-AM sources (undocumented feature).

You can exclude broadcasts so that they don\'t get recorded even if they would match an AutoTimer. Therefore you have to enter that titles into the file vdradmind.bl, one event a line. This file must be located in your VDRAdmin-AM\'s configuration folder. If this string is found either in the EPG\'s title or in title~subtitle, this event will not be programmed by AutoTimer. So you can disable complete episodes (for example when using "Enterprise" as blacklist string) or only one episode (when using "Enterprise~Azati Prime" as blacklist string).') %?>
0...99, defining the priority of this timer and of recordings created by this timer. 0 represents the lowest value, 99 the highest. The priority is used to decide which timer shall be started in case there are two or more timers with the exact same start time. The first timer in the list with the highest priority will be used.

This value is also stored with the recording and is later used to decide which recording to remove from disk in order to free space for a new recording. If the disk runs full and a new recording needs more space, an existing recording with the lowest priority (and which has exceeded its guaranteed lifetime) will be removed.

If all available DVB cards are currently occupied, a timer with a higher priority will interrupt the timer with the lowest priority in order to start recording.') %?>
guaranteed lifetime (in days) of a recording created by this timer. 0 means that this recording may be automatically deleted at any time by a new recording with higher priority. 99 means that this recording will never be automatically deleted. Any number in the range 1...98 means that this recording may not be automatically deleted in favour of a new recording, until the given number of days since the start time of the recording has passed by.') %?>
VDRAdmin-AM will append the matching broadcast\'s title and subtitle (if the "Episode" checkbox is marked) to the directory given here.

You can also use the following keywords that are replaced in the final file name by the values supplied by for example tvm2vdr:
  • %Title% - will become the title of the event.
  • %Subtitle% - will become the subtitle of the event.
  • %Director% - will become the director of the event.
  • %Date% - will become the date of the recording.
  • %Category% - will become the category of the event (Spielfilm/Serie/...).
  • %Genre% - will become the genre of the event (Drama/Krimi/..).
  • %Year% - will become the year of production.
  • %Country% - will become the country of production.
  • %Originaltitle% - will become the original title of the event.
  • %FSK% - will become the FSK from the event.
  • %Episode% - will become the episode\'s title of the event.
  • %Rating% - will become the rating of the event from the EPG provider.

Note:

If you use the above keywords it\'s in your own responsibility to supply the complete file name for the recordings! VDRAdmin-AM will not append anything to the resulting string.') %?>
vdradmin-am-3.6.13/template/default/help_config.html000066400000000000000000000450141443716113400224150ustar00rootroot00000000000000 <?% gettext('Configuration') %?>

Here you can change general settings and base settings for timers, AutoTimers, channel selection and streaming parameters.

') %?>

0 turns this feature off and VDRAdmin-AM will use all available channels.') %?>

Timer menu.') %?>
Recordings Streaming and reccmds.conf in the Recordings menu.') %?>
reccmds.conf its content is shown in a selectbox in the Recordings menu.') %?>

hh:mm format that appear in the selectbox placed at the top.') %?>

0...99, defining the priority of this timer and of recordings created by this timer. 0 represents the lowest value, 99 the highest. The priority is used to decide which timer shall be started in case there are two or more timers with the exact same start time. The first timer in the list with the highest priority will be used.

This value is also stored with the recording and is later used to decide which recording to remove from disk in order to free space for a new recording. If the disk runs full and a new recording needs more space, an existing recording with the lowest priority (and which has exceeded its guaranteed lifetime) will be removed.

If all available DVB cards are currently occupied, a timer with a higher priority will interrupt the timer with the lowest priority in order to start recording.') %?>
guaranteed lifetime (in days) of a recording created by this timer. 0 means that this recording may be automatically deleted at any time by a new recording with higher priority. 99 means that this recording will never be automatically deleted. Any number in the range 1...98 means that this recording may not be automatically deleted in favour of a new recording, until the given number of days since the start time of the recording has passed by.') %?>

0...99, defining the priority of this timer and of recordings created by this timer. 0 represents the lowest value, 99 the highest. The priority is used to decide which timer shall be started in case there are two or more timers with the exact same start time. The first timer in the list with the highest priority will be used.

This value is also stored with the recording and is later used to decide which recording to remove from disk in order to free space for a new recording. If the disk runs full and a new recording needs more space, an existing recording with the lowest priority (and which has exceeded its guaranteed lifetime) will be removed.

If all available DVB cards are currently occupied, a timer with a higher priority will interrupt the timer with the lowest priority in order to start recording.') %?>
guaranteed lifetime (in days) of a recording created by this timer. 0 means that this recording may be automatically deleted at any time by a new recording with higher priority. 99 means that this recording will never be automatically deleted. Any number in the range 1...98 means that this recording may not be automatically deleted in favour of a new recording, until the given number of days since the start time of the recording has passed by.') %?>

streamdev plugin. You also have to set the correct HTTP Port for Streamdev below.') %?>
If disabled or streamdev plugin is not running, there is no real "streaming", but you have to setup your workstation so that it can access VDR\'s recordings. You can use for example Samba or NFS for this.
VDRAdmin-AM simply generates a playlist that contains all parts of the recording and sends this to your browser. If your browser and media player are configured correctly you will see the recording on your workstation\'s display.') %?>

Here you can define two external searches that you can access in the EPG views. You simply have to find the required URL and where the search pattern has to be located. %TITLE% will be substituted by the broadcast\'s EPG title.

') %?>
Internet Movie Database (IMDb): (http://www.imdb.com/)
http://akas.imdb.com/Tsearch?title=%TITLE%
VideoDB: (videodb.sf.net)
http://www.videodb.net/videodb/search.php?q=%TITLE%&engine=videodb&owner=Guest&fields%5B%5D=title

This section is for experts only, i.e. you know what you are doing!

') %?>

If you want to limit the number of channels used in some parts of VDRAdmin-AM, this is for you!

Use the radio buttons to activate or deactivate the wanted channels in the named menu.

To add channels to the list of wanted channels you have to select them in the left side selectbox and click . If you want to remove channels from the list of wanted channels you have to select them in the right side selectbox and click .

') %?>
vdradmin-am-3.6.13/template/default/help_edit_epg.html000066400000000000000000000045271443716113400227340ustar00rootroot00000000000000 <?% gettext('Edit Timer') %?>

Here you can edit the descriptive fields of an existing EPG entry.

') %?>
:
:
:
:
:
:
:
:
vdradmin-am-3.6.13/template/default/help_no.html000066400000000000000000000017741443716113400215710ustar00rootroot00000000000000 <?% gettext('No Help Available') %?>

No help available yet. For adding or changing text please contact amair.sob@googlemail.com.

') %?>
vdradmin-am-3.6.13/template/default/help_rec_list.html000066400000000000000000000062631443716113400227570ustar00rootroot00000000000000 <?% gettext('Recordings') %?>

Here you will find a listing of recordings known to VDR. The headline will also show you VDR\'s total and free disk space.

The listing showing you some information on the recordings. You can change the list\'s sorting by clicking the columns heading. Above the list you\'ll see the navigation path. If you want to view the contents of previous folders you\'ll have to click on its name in that path.

Each row contains this information:

Date
The date when the recording has been done. In case of folders this will show the number of recordings the folder contains.
Time
The time when the recording has been done. In case of folders this will show the number of new recordings the folder contains.
Name
The recording\'s or folder\'s name. Click it to show the recording\'s summary or descend into the folder.
Rename (edit)
Rename a recording.

Note:

This only works if VDR has the MOVR or RENR SVDRP command which is not a core VDR feature but provided by the Liemikuutio patch set.
Delete (delete)
Delete a recording.
Stream (stream)
This column is only shown if you activated and configured Recordings Streaming in the Configuration menu. You can watch the recording at your workstation.

In addition to these functions you can delete a number of recordings at once by checking the box in the last but one column of those recordings and clicking .

If you\'ve set the path the VDR\'s configuration files and have entries in VDR\'s reccmds.conf you can run those commands for the selected recording by selecting the wanted command in the select box locate next to Commands: and pressing the button.

Use to force reloading of VDR\'s recordings listing.

') %?>
vdradmin-am-3.6.13/template/default/help_timer_list.html000066400000000000000000000073061443716113400233250ustar00rootroot00000000000000 <?% gettext('Timer') %?>

Here you will find a listing of timers known to VDR.

On top you will find a chart showing a day\'s timers graphically. This provides an quick overview on what\'s going on at the specified day and helps you in finding conflicting timers. Moving the mouse cursor above any timer box will display a tooltip containing the timer\'s title, priority, lifetime and duration.

Below the chart you\'ll find the timers list showing you some information on the timers. You can change the list\'s sorting by clicking the columns heading.

For each timer you have the following options:

Set its state
By clicking on "Yes", "No", "VPS" or "Auto" in the "Active" column.
Quickly view its priority and lifetime
By pointing the mouse cursor to the timer\'s title.
View its EPG entry
Timers that have set AutoTimer Checking to "Transmission Identification" will show you the corresponding EPG entry if you click on the timer\'s title.
Edit the timer
You can edit a timer by clicking edit.
Delete the timer
To delete a timer you click delete.

Each timer\'s state is indicated by differently coloured boxes (in the chart view) or images (in the list view):
    / on Timer is OK and will record.
    / problem Timer conflicts with other timers. That\'s not critical, as long as you have enough DVB cards for the parallel recordings.
    / impossible Timer is critical and will most likely not record.
    / inactive Timer is not active.

In addition to these functions you can add a new timer by clicking at the top and you can delete a number of timers at once by checking the box in the last column of those timers and clicking .

You can and selected timers.

') %?>
vdradmin-am-3.6.13/template/default/help_timer_new.html000066400000000000000000000131211443716113400231330ustar00rootroot00000000000000 <?% gettext('Edit Timer') %?>

Here you can edit a timer\'s settings.

') %?>
  • Two digits (DD). This will use the current month and year.
  • ISO norm (YYYY-MM-DD). Program your timers as far in the future as you like.
  • In case you want to program a repeating timer you can use the seven checkboxes below the text field. Check the box for each day you want the timer to get active.') %?>
    0...99, defining the priority of this timer and of recordings created by this timer. 0 represents the lowest value, 99 the highest. The priority is used to decide which timer shall be started in case there are two or more timers with the exact same start time. The first timer in the list with the highest priority will be used.

    This value is also stored with the recording and is later used to decide which recording to remove from disk in order to free space for a new recording. If the disk runs full and a new recording needs more space, an existing recording with the lowest priority (and which has exceeded its guaranteed lifetime) will be removed.

    If all available DVB cards are currently occupied, a timer with a higher priority will interrupt the timer with the lowest priority in order to start recording.') %?>
    guaranteed lifetime (in days) of a recording created by this timer. 0 means that this recording may be automatically deleted at any time by a new recording with higher priority. 99 means that this recording will never be automatically deleted. Any number in the range 1...98 means that this recording may not be automatically deleted in favour of a new recording, until the given number of days since the start time of the recording has passed by.') %?>
    file name this timer will give to a recording. If the name shall contain subdirectories, these have to be delimited by \'~\' (since the \'/\' character may be part of a regular programme name).

    The special keywords TITLE and EPISODE, if present, will be replaced by the title and episode information from the EPG data at the time of recording (if that data is available). If at the time of recording either of these cannot be determined, TITLE will default to the channel name, and EPISODE will default to a blank.') %?>
    summary.vdr or info.vdr file of the recording.') %?>
    vdradmin-am-3.6.13/template/default/index.html000066400000000000000000000016361443716113400212510ustar00rootroot00000000000000 VDRAdmin-AM <?% version %?> (<?% host %?>) <body> <p><?% gettext('Your Browser does not support frames!') %?></p> </body> vdradmin-am-3.6.13/template/default/infobox.js000066400000000000000000000073101443716113400212510ustar00rootroot00000000000000// // Bubblehelp infoboxes, (C) 2007 Klaus Knopper // You can copy/modify and distribute this code under the conditions // of the GNU GENERAL PUBLIC LICENSE Version 2. // var IWIDTH=250 // Tip box width var ns4 // Are we using Netscape4? var ie4 // Are we using Internet Explorer Version 4? var ie5 // Are we using Internet Explorer Version 5 and up? var kon // Are we using KDE Konqueror? var x,y,winW,winH // Current help position and main window size var idiv=null // Pointer to infodiv container var px="px" // position suffix with "px" in some cases function nsfix(){setTimeout("window.onresize = rebrowse", 2000);} function rebrowse(){window.location.reload();} function hascss(){ return gettip('infodiv')?true:false } function infoinit(){ ns4=(document.layers)?true:false, ie4=(document.all)?true:false; ie5=((ie4)&&((navigator.userAgent.indexOf('MSIE 5')>0)||(navigator.userAgent.indexOf('MSIE 6')>0)))?true:false; kon=(navigator.userAgent.indexOf('konqueror')>0)?true:false; x=0;y=0;winW=800;winH=600; idiv=null; document.onmousemove = mousemove; if(ns4&&document.captureEvents) document.captureEvents(Event.MOUSEMOVE); // Workaround for just another netscape bug: Fix browser confusion on resize // obviously conqueror has a similar problem :-( if(ns4||kon){ nsfix() } if(ns4) { px=""; } } function untip(){ if(idiv) idiv.visibility=ns4?"hide":"hidden"; idiv=null; } function gettip(name){return (document.layers&&document.layers[name])?document.layers[name]:(document.all&&document.all[name]&&document.all[name].style)?document.all[name].style:document[name]?document[name]:(document.getElementById(name)?document.getElementById(name).style:0);} // Prepare tip boxes, but don't show them yet function maketip(name,title,text){ if(hascss()) document.write(''+"\n"); } function tip(name){ if(hascss()){ if(idiv) untip(); idiv=gettip(name); if(idiv){ // winW=(window.innerWidth)? window.innerWidth+window.pageXOffset-16:document.body.offsetWidth-20; // winH=(window.innerHeight)?window.innerHeight+window.pageYOffset :document.body.offsetHeight; // IE standards compliant mode compatibility partly contributed by Stefan Neufeind winW=(window.innerWidth)? window.innerWidth+window.pageXOffset-16:(document.documentElement&&document.documentElement.clientWidth)?document.documentElement.clientWidth-20:document.body.offsetWidth-20; winH=(window.innerHeight)?window.innerHeight+window.pageYOffset :(document.documentElement&&document.documentElement.clientHeight)?document.documentElement.clientHeight:document.body.offsetHeight; if(x<=0||y<=0){ // konqueror can't get mouse position x=(winW-IWIDTH)/2+(window.pageXOffset?window.pageXOffset:0); y=(winH-50)/2+(window.pageYOffset?window.pageYOffset:0); // middle of window } showtip(); } } } function showtip(){ idiv.left=(((x+260) VDRAdmin-AM vdradmin-am-3.6.13/template/default/noauth.html000066400000000000000000000015721443716113400214370ustar00rootroot00000000000000 <?% gettext('Authorization Required') %?>

    vdradmin-am-3.6.13/template/default/noperm.html000066400000000000000000000011561443716113400214370ustar00rootroot00000000000000 <?% title %?>

    vdradmin-am-3.6.13/template/default/prog_detail.html000066400000000000000000000113221443716113400224240ustar00rootroot00000000000000 <?% title %?>
    -
    <?% gettext('close') %?> <?% gettext('view') %?> <?% gettext('record') %?> <?% gettext('search') %?> <?% gettext('edit') %?> IMDb Search

    :

     

     

     

     
    vdradmin-am-3.6.13/template/default/prog_detail_form.html000066400000000000000000000077541443716113400234650ustar00rootroot00000000000000 <?% title %?>

    help
    :
    :
    :
    :
    :
    :
    :
    :
    vdradmin-am-3.6.13/template/default/prog_list.html000066400000000000000000000147621443716113400221500ustar00rootroot00000000000000 VDRAdmin-AM - <?% gettext('Channels') %?>

    <?% gettext('Stream') %?>

     
    0 %?>  
    0 %?>
    -

    <?% gettext('Search for other show times') %?> info noinfo edit record IMDb Search
    vdradmin-am-3.6.13/template/default/prog_list2.html000066400000000000000000000150631443716113400222250ustar00rootroot00000000000000 VDRAdmin-AM - <?% gettext('Playing Today') %?>

     
    0 %?>  
    0 %?>
    <?% gettext('Stream') %?> <?% gettext('TV select') %?>
    -
     
    <?% gettext('Search for other show times') %?> info noinfo edit record IMDb Search
    vdradmin-am-3.6.13/template/default/prog_summary.html000066400000000000000000000164101443716113400226620ustar00rootroot00000000000000 VDRAdmin-AM - <?% gettext('What\'s On Now?') %?>
    0 %?>

    []   
    0 %?>
    <?% gettext('Stream') %?> <?% gettext('TV select') %?> <?% gettext('Search for other show times') %?> <?% gettext('More Information') %?> noinfo <?% gettext('Edit') %?> <?% gettext('Record') %?> IMDb Search
    - 
     
    vdradmin-am-3.6.13/template/default/prog_summary2.html000066400000000000000000000165211443716113400227470ustar00rootroot00000000000000 VDRAdmin-AM - <?% gettext('What\'s On Now?') %?>
    0 %?>

    []     
    0 %?>
    -
    <?% gettext('Stream') %?> <?% gettext('TV select') %?> <?% gettext('Search for other show times') %?> <?% gettext('More Information') %?> noinfo <?% gettext('Edit') %?> <?% gettext('Record') %?> IMDb Search
    vdradmin-am-3.6.13/template/default/prog_timeline.html000066400000000000000000000156041443716113400227770ustar00rootroot00000000000000 VDRAdmin-AM - <?% gettext('Timeline') %?>

      

             
    0 %?>

    vdradmin-am-3.6.13/template/default/rc.html000066400000000000000000000214511443716113400205430ustar00rootroot00000000000000 VDRAdmin-AM - <?% gettext('Remote Control') %?> (<?% host %?>)
    vdradmin-am-3.6.13/template/default/rec_edit.html000066400000000000000000000042171443716113400217160ustar00rootroot00000000000000 VDRAdmin-AM - <?% gettext('Rename Recording') %?>

    vdradmin-am-3.6.13/template/default/rec_list.html000066400000000000000000000203111443716113400217350ustar00rootroot00000000000000 VDRAdmin-AM - <?% gettext('Recordings') %?>

       ()  |    () help
    >> 
    0 %?>
    = 10721 %?> = 10721 %?>

          play cut rename delete stream stream
    0 %?>
    stream
    vdradmin-am-3.6.13/template/default/style.css000066400000000000000000000307111443716113400211220ustar00rootroot00000000000000/* ugly MSIE6/7 hacks */ /* always show vertical scroller to avoid horizontal scrolling on some pages */ * html#scroller { overflow-y: scroll; } /* avoid too small inputs/selects */ * + html #epgsearch_new #use_extepg_settings table { width: 30%; } * html #epgsearch_new #use_extepg_settings table { width: 30%; } /* END OF ugly MSIE hacks */ * { font-family: Verdana, "Bitstream Vera Sans", Arial, Geneva, Helvetica, sans-serif; } #rc, #tv { margin: 0px; } body { background-color: #ffffff; margin: 3px; padding: 0; } form { margin: 0px; padding: 0; } td, div { color: black; font-weight: normal; font-size: 11px; } input { color: black; font-weight: normal; font-size: 11px; } textarea { color: black; font-weight: normal; font-size: 11px; } select { color: black; font-weight: normal; font-size: 11px; } img { border: 0; vertical-align: middle; display: inline; } /* .submit { height: 20px; }*/ h1 { margin-right: 5px; margin-left: 5px; font-size: 13px; font-weight: bold; color: black; display: inline; } h2 { margin: 0px; font-size: 11px; font-weight: bold; color: black; display: inline; } h3, .epg_title { margin: 0px; font-size: 11px; font-weight: bold; color: black; } #prog_list .epg_title a { margin: 0; padding: 0; } .col_label { width: 100px; text-align: right; } .col_label h5 { margin: 1px 5px; font-size: 11px; font-weight: normal; color: black; text-align: right; white-space: nowrap; } .col_value h5 { display: inline; font-size: 11px; font-weight: normal; color: black; } h6 { margin: 1px 5px; font-size: 10px; font-weight: normal; color: black; text-align: right; } label { cursor: default; } a, a:visited, a:active, a:hover { color: black; text-decoration: none; } label + input { margin-left: 1em; } #tv input, #tv select, #tv h5 { font-weight: normal; font-size: 9px; display: inline; } #tv #content { vertical-align: top; border-spacing: 10px; } #rc .rc, #tv #sect_rc { background-image: url("default/fern_back.jpg"); } #tv #sect_channels { vertical-align: top; } #rec_list .col_name { font-weight: bold; } #error h2 { font-size: 11px; color: red; } body.help .heading { display: table-row; } .row_odd td, .row_even td, .heading { height: 17px; } .list.hilight .row_even:hover, .list.hilight .row_odd:hover { background-color: #8cc1da; } .heading td { background-color: #6d96a9; height: 17px; } .heading h2, .heading .channel_name, .heading a { font-weight: bold; color: white; margin-top: 0px; white-space: normal; } #prog_summary .row_even .col_epg, .row_even { background-color: #ffffff; } .row_odd { background-color: #dee6ee; } .col_label, .col_value, .col_active, .col_channel, .col_start, .col_stop, .col_date, .col_time, .col_length { padding-left: 3px; padding-right: 3px; white-space: nowrap; } .col_channels { text-align: right; padding: 10px; width: 40%; } .col_wanted_channels { text-align: left; padding: 10px; width: 40%; } .col_navi img, .col_navi a { padding: 0; margin: 0; } .col_navi { text-align: right; vertical-align: middle; white-space: nowrap; height: 17px; } .list, .group { border: 1px solid #6d96a9; } .group td { padding: 2px; } #prog_list .list { margin-bottom: 0.5em; } #prog_summary .action, #prog_detail .action { display: block; margin: 5px 0 0 0; } .action a, .action img, .heading img, .heading .action { margin: 0; padding: 0; } .action { margin: 0; padding: 0; text-align: center; width: 20px; } .heading .action { background-color: white; } /* Summary */ #prog_summary .group { margin: 0 3px 3px 0; display: inline; float: left; } #prog_summary .heading td.col_content { height: 17px; width: 246px; color: white; background-color: #6d96a9; white-space: nowrap; overflow: hidden; } #prog_summary .row_even td.col_content { width: 246px; height: 200px; background-color: #dee6ee; vertical-align: top; } #prog_summary table.content td.col_buttons { height: 200px; } #prog_summary .col_epg { vertical-align: top; } #prog_summary .date_long { text-align: right; margin-top: 3px; float: left; } #prog_summary .time_duration { text-align: right; margin-top: 3px; } #prog_summary .epg_title { margin-top: 1em; width: 216px; overflow: hidden; white-space: nowrap; } #prog_summary .epg_subtitle { width: 216px; overflow: hidden; white-space: nowrap; } #prog_summary .epg_summary { margin-top: 1em; margin-bottom: 3px; width: 210px; height: 120px; overflow: auto; white-space: normal; } #prog_summary .heading a { font-weight: bold; color: white; padding: 2px 2px; } #action_record_settings, #action_switch_settings { margin-top: 1em; } .newday { height: 17px; background-color: #6d96a9; } .newday td { padding-left: 3px; font-weight: bold; color: white; } #prog_summary2 .epg_title, #prog_summary2 .channel_name { display: block; } #prog_summary2 .epg_subtitle { font-size: 11px; font-weight: normal; color: black; display: block; } #prog_list .col_buttons, #rec_list .col_buttons, #epgsearch_list .col_buttons, #epgsearch_config .col_buttons, #prog_summary2 .col_buttons { width: 120px; text-align: right; padding-right: 3px; white-space: nowrap; } #prog_summary2 table.percent td { height: 8px; } #prog_summary2 table.percent { height: 8px; width: 80px; border: 1px solid #6d96a9; } #prog_summary2 table.percent .elapsed { background-color: #6d96a9; } #prog_summary2 table.percent .remaining { background-color: transparent; } #prog_detail .heading .col_content * { color: white; font-weight: bold; } #prog_detail .channel_name { white-space: nowrap; } #prog_detail .date_long { margin-left: 2em; white-space: nowrap; } #prog_detail .time_vps, #prog_detail .time_duration { margin-left: 2em; white-space: nowrap; } #prog_detail .epg_title { display: block; } #prog_detail .epg_subtitle { font-size: 11px; font-weight: normal; color: black; display: block; } #prog_detail .epg_summary { margin: 2em 0; display: block; } #prog_detail .epg_video h4, #prog_detail .epg_audio h4, #prog_detail .epg_length h4, #prog_detail .epg_subs h4 { margin: 0; font-size: 10px; font-weight: bold; display: inline; } #prog_detail .epg_video h5, #prog_detail .epg_audio h5, #prog_detail .epg_length h5, #prog_detail .epg_subs h5 { margin-left: 1em; display: inline; font-size: 10px; font-weight: normal; font-style: italic; } #prog_detail .col_epg { padding: 1em; } #prog_summary .row_even td.col_content, #prog_detail .row_even td.col_content { padding: 0; } #prog_summary table.content td.col_buttons, #prog_detail table.content td.col_buttons { padding-top: 1em; vertical-align: top; width: 20px; text-align: center; background-color: #dee6ee; border-right: 1px solid #6d96a9; } .heading, #prog_list .heading td span, #prog_list .heading td { vertical-align: middle; } #prog_list .date_long { color: white; font-weight: bold; padding: 0 2em; } .col_duration { padding-left: 3px; padding-right: 3px; width: 100px; vertical-align: top; } .col_name, #content .col_title * { padding-left: 3px; padding-right: 3px; min-width: 50px; white-space: normal; } .col_info, .col_record { width: 16px; text-align: center; } .col_active { width: 90px; } .col_channel { width: 120px; } .col_start, .col_stop, .col_date, .col_time { width: 76px; text-align: left; } .col_length { width: 76px; text-align: right; } .col_edit, .col_delete, .col_stream, .col_checkbox { text-align: center; width: 16px; } #heading { height: 29px; border: 1px solid #6d96a9; } #heading tr { vertical-align: middle; background-color: #dee6ee; } #heading td { vertical-align: middle; padding: 0px 10px; } #heading .col_other { text-align: right; } #heading .col_other table { display: inline; } #heading .col_help { text-align: center; width: 45px; } #prog_timeline #content { position: absolute; top: 32px; left: 3px; } #prog_timeline .timertable, #prog_timeline .prgtable { border-color: #6d96a9; } #prog_timeline #timeline { background: red; } #prog_timeline .color_current { background-color: #b4e29c; } #prog_timeline .color_summary { background-color: #dee6ee; } #prog_timeline .color_broadcast { background-color: #ffffff; } #prog_timeline .color_timer { background-color: #ffb2b4; } #prog_timeline .color_spacer { background-color: #e0e0e0; } #rec_list #path { margin: 1em 10px 0px 10px; } #rec_edit .col_value { white-space: normal; } #timer_list .list { margin-top: 0.6em; } #timer_list .timers { border-top: 1px solid black; } #timer_list .color_ok { background-color: #00a317; } #timer_list .color_conflict { background-color: #a11917; } #timer_list .color_collision { background-color: #ffde62; } #timer_list .color_inactive { background-color: #858585; } #timer_list .prgtable { border-left-color: #000000; border-right-color: #000000; } #prog_timeline .row_even table td.color1, #timer_list .row_even table td.color1 { background-color: #ffffff; } #prog_timeline .row_even table td.color2, #timer_list .row_even table td.color2 { background-color: #dee6ee; } #prog_timeline table.timestable td.color1 { background-color: #ffffff; } #prog_timeline table.timestable td.color2 { background-color: #dee6ee; } #vdr_cmds pre { margin: 0px; padding: 0px; } #epgsearch_new #use_extepg_settings { white-space: normal; vertical-align: top; } #epgsearch_new #use_extepg_settings table { padding: 0 5px 5px 0; display: inline; float: left; vertical-align: top; height: 100%; } #epgsearch_new #use_extepg_settings table select, #epgsearch_new #use_extepg_settings table input { width: 100%; } #epgsearch_new #avoid_repeats_settings div { white-space: normal; } #epgsearch_new #avoid_repeats_settings span { float: left; padding-right: 1em; } #content { margin-top: 0.6em; } #buttons { border: 1px solid #6d96a9; padding: 3px; margin-top: 1em; margin-bottom: 1em; background-color: #dee6ee; text-align: right; } #config .heading { background-color: #dee6ee; border: none; } #config .heading a { color: black; font-weight: normal; } #about .group, #config .group { margin-top: 0.5em; width: 100%; } #config .col_label { width: 50%; } #about .col_label { width: 20%; } #about .col_label h5 { white-space: nowrap; } select.channels { min-width: 100px; } /* Tooltips */ .tt_border { border: 2px solid white; } .tt_table { width: 250px; border: 2px solid #6d96a9; background-color: #dee6ee; } .tt_table th { background-color: #6d96a9; font-weight: bold; color: white; padding-left: 2px; padding-right: 2px; } .tt_table td { color: black; padding-left: 5px; padding-right: 5px; } /* Help */ #help dt { margin-top: 0.6em; font-weight: bold; font-style: italic; } #help dd dl dt { margin-top: 0.3em; font-weight: normal; font-style: italic; } #help dl { padding: 5px; } #help h3 { font-weight: bold; font-style: italic; letter-spacing: 0.5em; background-color: #6d96a9; color: white; padding: 2px 5px; } #help h4 { text-decoration: underline; font-style: normal; } #help strong { font-weight: bold; } #help .ref_menu { font-style: italic; } #help .ref_file { text-decoration: underline; } #help .ref_label { font-style: italic; } #help .links { padding: 5px; background-color: #dee6ee; text-align: justify; } #help .links a { white-space: nowrap; } #about a, #about a:visited, #about a:active, #help a, #help a:visited, #help a:active { color: blue; } #help .group { margin-top: 0.6em; border: 1px solid #6d96a9; white-space: normal; } #help .group p { padding: 5px; } #help .top_link { text-align: right; font-size: 0.8em; background-color: #dee6ee; padding: 1px 5px; margin: 0px; } /* Navigation */ #navigation { margin: 0px 3px; } #navigation .nav_bar { border: 1px solid #6d96a9; padding: 1em 0px; } #navigation .logo { padding-top: 1em; padding-bottom: 2em; width: 150px; } #navigation .navi { font-size: 12px; padding-top: 6px; padding-bottom: 6px; text-align: center; } #navigation .navi:hover { background-color: #dee6ee; } #navigation .search { padding-top: 6px; font-size: 12px; text-align: center; } #navigation a, #navigation a:visited, #navigation a:active { color: #6d96a9; font-weight: bold; text-decoration: none; border: 0px; } #navigation input { width: 140px; box-sizing: border-box; } /* message boxes */ .warning h1 { display: block; font-weight: bold; font-size: 14px; } .warning { margin: 2em; padding: 1em; border: 1px solid #6d96a9; background-color: #dee6ee; text-align: center; vertical-align: middle; } .error h1 { display: block; color: red; font-weight: bold; font-size: 14px; } .error { margin: 2em; padding: 1em; border: 2px solid red; background-color: #dee6ee; text-align: center; vertical-align: middle; } vdradmin-am-3.6.13/template/default/timeline.js000066400000000000000000000341151443716113400214160ustar00rootroot00000000000000/*jslint browser: true, evil: true, laxbreak: true */ /*##########################################################################*/ /* Browser independent size detection */ /*##########################################################################*/ function GetWindowW() { if (window.innerWidth) { return window.innerWidth; } else if (document.body && document.body.offsetWidth) { return document.body.offsetWidth; } else { return 0; } } function GetWindowH() { if (window.innerHeight) { return window.innerHeight; } else if (document.body && document.body.offsetHeight) { return document.body.offsetHeight; } else { return 0; } } /*##########################################################################*/ /* Utility functions */ /*##########################################################################*/ function W(s) { document.write(s); } function Div(x, y) { return (x - x % y) / y; } function Translation(_now, _o_clock, _to) { this.now = _now; this.o_clock = _o_clock; this.to = _to; } function ChannelInfo(vdr_id, name, url, events) { this.vdr_id = vdr_id; this.name = name; this.url = url; this.events = events; } function format_date(fmt, time) { if (fmt == "%H:%M") { var date = new Date(time * 1000); var h = '0' + date.getHours(); var m = '0' + date.getMinutes(); return h.substr(h.length-2, 2) + ':' + m.substr(m.length-2, 2); } return "[WRONG_FMT:" + fmt + "]"; } function EPGEvent(epg_id, start_sec, stop_sec, title, timer, summary) { this.epg_id = epg_id; this.start_sec = start_sec; this.stop_sec = stop_sec; this.start_str = format_date('%H:%M', start_sec); this.stop_str = format_date('%H:%M', stop_sec); this.title = title; this.timer = timer; this.summary = summary; } function SetTimeLine(_this, _table_w, _px_per_min, _end_min) { _this.name_w = 100; _this.table_w = _table_w; _this.px_per_min = _px_per_min; _this.end_min = Div(_this.table_w - _this.name_w, _this.px_per_min); if (_this.end_min > _end_min) { _this.px_per_min = Div(_this.table_w - _this.name_w, _end_min); _this.end_min = _end_min; } _this.end_min -= _this.end_min % 30; _this.event_w = _this.end_min * _this.px_per_min; _this.name_w = _this.table_w - _this.event_w; _this.end_sec = _this.start_sec + _this.end_min * 60; _this.first_sec = _this.now_sec + 1799 - _this.end_min * 60; _this.first_sec -= _this.first_sec % 1800; _this.last_sec = _this.first_sec + 86400; } function TimeLine(_req_sec, _now_url, _px_per_min, _end_min) { this.now_url = _now_url; this.org_px_per_min = _px_per_min; this.org_end_min = _end_min; this.req_sec = _req_sec; this.start_sec = _req_sec - _req_sec % 1800; this.min5_h = 10; var d = new Date(); this.now_sec = Div(d.getTime(), 1000); var table_w = GetWindowW(); if (!document.all) { table_w -= 8; } SetTimeLine(this, table_w, _px_per_min, _end_min); } /*##########################################################################*/ /* Build the HTML code */ /*##########################################################################*/ function BuildOption(time, selected, text) { W(''); } function BuildHiddenFrameInput() { W(''); } function BuildHeader() { W(''); W(''); W('

    '); W(format_date('%H:%M', tl.start_sec) + ' ' + trans.o_clock + ' ' + trans.to + ' ' + format_date('%H:%M', tl.end_sec) + ' ' + trans.o_clock); W('

    '); W('
    '); W(''); W(''); var diff_sec; if (tl.start_sec < tl.first_sec + 1800) { W(''); } else { diff_sec = tl.start_sec - tl.end_min * 60; if (diff_sec < tl.first_sec) { diff_sec = tl.first_sec; } W(''); W(''); W(''); } if (tl.end_sec >= tl.last_sec) { W(''); } else { diff_sec = tl.end_sec; W(''); W(''); W(''); } W(''); W(''); } function DrawTimeLine() { var tab = document.getElementById("row_timeline"); if (tab && (tl.start_sec <= tl.now_sec) && (tl.now_sec < tl.end_sec)) { var x = tl.name_w + tl.px_per_min * Div(tl.now_sec - tl.start_sec, 60) + 1; var y = tab.offsetTop; var h = tab.offsetHeight; var style = "position:absolute; " + "top:" + y + "px; " + "left:" + x + "px; " + "width:1px; " + "height:" + h + "px; " + "z-index:2; "; if (document.all) { style = style + "filter:Alpha(opacity=50); "; } W(''); W(' '); W(''); } } function BuildTimeScale() { W(''); W(''); W(''); var c; var w; for (var min = 0; min < tl.end_min; min += 30) { c = min % 60 ? 'color1' : 'color2'; w = tl.px_per_min * (tl.end_min - min < 30) ? tl.end_min - min : 30; var t = tl.start_sec + min * 60; W(''); } W(''); W(''); W(''); for (min = 0; min < tl.end_min; min += 5) { c = min % 10 ? 'color1' : 'color2'; w = tl.px_per_min * 5; W(''); } W(''); W('
    '); W('
    '); W('' + format_date('%H:%M', t) + ''); W('
    '); W('
    '); W('
    '); } function BuildSpacer(width) { W(''); W(''); W(''); W(''); W('
    '); W('
    '); W(''); W(' '); W(''); W('
    '); } function BuildNoEPG(event, width) { W(''); W(''); W(''); W(''); W('
    '); W('
    '); W(''); W(event.title); W(''); W('
    '); } function BuildEvent(vdr_id, counter, event, td_class, px_w) { var table_class = event.timer ? "timertable" : "prgtable"; W(''); W(''); W(''); W(''); W('
    '); W('
    '); W(''); var anchor_start = ""; var anchor_end = ""; if (event.summary) { anchor_start = ''; anchor_end = ''; } W(anchor_start); W(event.title); W(anchor_end); W(''); W('
    '); } function BuildChannel(channel, td_class) { W(''); /* Channel name */ W(''); W('
    '); W(''); W(''); W(channel.name); W(''); W(''); W(''); /* Events */ W(''); W(''); var old_stop_min = 0; if (channel.events[0].start_sec > 0) { for (var i = 0; i < channel.events.length; i++) { var event = channel.events[i]; /* Calculate event start and stop time in minutes from table begin. */ var start_min = Div(event.start_sec - tl.start_sec, 60); var stop_min = Div(event.stop_sec - tl.start_sec, 60); if (start_min >= tl.end_min) { break; } /* Adjust times to regard end of last event and end of table. */ td_class = ""; if (start_min < old_stop_min) { start_min = old_stop_min; if (start_min > 0 && !event.timer) { td_class = "color_spacer"; /* overlapped event */ } } if (stop_min > tl.end_min) { stop_min = tl.end_min; } /* Ignore completely overlapped events. */ if (start_min >= stop_min) { continue; } if (!td_class) { if (event.timer) { td_class = "color_timer"; } else if ((event.start_sec <= tl.now_sec) && (tl.now_sec < event.stop_sec)) { td_class = "color_current"; } else if (event.summary) { td_class = "color_summary"; } else { td_class = "color_broadcast"; } } if (start_min > old_stop_min + 1) { BuildSpacer((start_min - old_stop_min) * tl.px_per_min); } var px_w = (stop_min - start_min) * tl.px_per_min; BuildEvent(channel.vdr_id, i, event, td_class, px_w); old_stop_min = stop_min; } if (old_stop_min < tl.end_min) { BuildSpacer((tl.end_min - old_stop_min) * tl.px_per_min); } } else { BuildNoEPG(channel.events[0], tl.end_min * tl.px_per_min); } W(''); W(''); W(''); } function BuildProgTable() { W(''); for (var i = 0; i < channels.length; i++) { var c = "prgname " + (i % 2 ? "color1" : "color2"); BuildChannel(channels[i], c); } W('
    '); } function BuildTable() { W(''); W(''); BuildTimeScale(); BuildProgTable(); W(''); W(''); } function BuildContentDiv() { W('
    '); W(''); BuildHeader(); BuildTable(); W('
    '); DrawTimeLine(); W('
    '); } function BuildContent() { /* Write content div */ BuildContentDiv(); /* Check if the width has changed due to vertical scrollbar */ var tab = document.getElementById("heading"); var table_w; if (tab) { table_w = tab.clientWidth; } else { table_w = this.innerWidth; } if (tl.table_w > table_w) { /* Recalculate all data for new table width */ SetTimeLine(tl, table_w, tl.org_px_per_min, tl.org_end_min); /* Delete first content div */ tab = document.getElementById("content"); tab.innerHTML = null; /* Write second content div */ BuildContentDiv(); } } vdradmin-am-3.6.13/template/default/timer_list.html000066400000000000000000000340501443716113400223110ustar00rootroot00000000000000 VDRAdmin-AM - <?% gettext('Timer') %?>

    help
    0 %?>


     

    = current; sender=timer.cdesc; %?> = current; IF sendung.active == 0 || sendung.active == 32768; td_class="color_inactive"; ELSE; IF sendung.critical == 1; td_class="color_conflict"; ELSE; IF sendung.collision == 1; td_class="color_collision"; ELSE; td_class="color_ok"; END; END; END; IF sendung.starttime < current; start=0; ELSE; start=((sendung.startlong / faktor) + 0.5 ) | format('%i'); END; IF sendung.stoptime > current; ende=tablaenge; ELSE; ende=(((sendung.stoplong + 1) / faktor) + 0.5 ) | format('%i'); END; NEXT IF ende <= start; IF start>pos; %?>


    onmouseover="tip('VDR-'); return true;" onmouseout="untip(); return true;"> onmouseover="tip('VDR-'); return true;" onmouseout="untip(); return true;">

    onmouseover="tip('VDR-'); return true;" onmouseout="untip(); return true;">  
    edit
    delete
     
    vdradmin-am-3.6.13/template/default/timer_new.html000066400000000000000000000225211443716113400221270ustar00rootroot00000000000000 VDRAdmin-AM - <?% IF newtimer %?><?% gettext('Create New Timer') %?><?% ELSE %?><?% gettext('Edit Timer') %?><?% END %?>

    help
    checked="checked" /> checked="checked" />
    checked="checked" /> checked="checked" /> checked="checked" />

     :    (  )
     :    (  )
    checked="checked" />
    ()
    vdradmin-am-3.6.13/template/default/tv.html000066400000000000000000000331061443716113400205700ustar00rootroot00000000000000 VDRAdmin-AM - <?% gettext('TV') %?> (<?% host %?>)

    ' title="" onclick="WebcamUpdate()" />   
    ' title="" onclick="WebcamUpdate()" />
    []  
    vdradmin-am-3.6.13/template/default/vdr_cmds.html000066400000000000000000000067711443716113400217500ustar00rootroot00000000000000 VDRAdmin-AM - <?% gettext('VDR Commands') %?>

    help
    0 %?>
    []
    0 %?>

    vdradmin-am-3.6.13/tools/000077500000000000000000000000001443716113400151475ustar00rootroot00000000000000vdradmin-am-3.6.13/tools/lib/000077500000000000000000000000001443716113400157155ustar00rootroot00000000000000vdradmin-am-3.6.13/tools/lib/String/000077500000000000000000000000001443716113400171635ustar00rootroot00000000000000vdradmin-am-3.6.13/tools/lib/String/Escape.pm000066400000000000000000000425671443716113400207370ustar00rootroot00000000000000### String::Escape - Backslash escaping, word splitting, and elision functions ### Copyright 2002 Matthew Simon Cavalletto. # You may use this software under the same terms as Perl. ######################################################################## package String::Escape; require 5; use strict; use Carp; use Exporter; use vars qw( $VERSION @ISA @EXPORT_OK ); $VERSION = 2002.001; push @ISA, qw( Exporter ); push @EXPORT_OK, qw( escape printable unprintable elide quote unquote quote_non_words qprintable unqprintable string2list string2hash list2string list2hash hash2string hash2list ); ######################################################################## ### Call by-name interface # %Escapes - escaper function references by name use vars qw( %Escapes ); %Escapes = ( %Escapes, 'none' => sub ($) { $_[0]; }, 'uppercase' => sub ($) { uc $_[0] }, 'lowercase' => sub ($) { lc $_[0] }, 'initialcase' => sub ($) { ucfirst lc $_[0] }, 'quote' => \"e, 'unquote' => \&unquote, 'quote_non_words' => \"e_non_words, 'printable' => \&printable, 'unprintable' => \&unprintable, 'qprintable' => 'printable quote_non_words', 'unqprintable' => 'unquote unprintable', 'elide' => \&elide, ); # String::Escape::add( $name, $subroutine ); sub add ($$) { $Escapes{ shift(@_) } = shift(@_); } # @defined_names = String::Escape::names(); sub names () { keys(%Escapes); } # $escaped = escape($escape_spec, $value); # @escaped = escape($escape_spec, @values); sub escape ($@) { my ($escape_spec, @values) = @_; croak "escape called with multiple values but in scalar context" if ($#values > 0 && ! wantarray); my @escapes = expand_escape_spec($escape_spec); # warn "Escaping: ". join(' ', @escapes) . "\n"; my ($value, $escaper); foreach $value ( @values ) { foreach $escaper ( @escapes ) { $value = &$escaper( $value ); } } return wantarray ? @values : $values[0]; } # @escape_functions = expand_escape_spec($escape_spec); sub expand_escape_spec { my $escape_spec = shift; if ( ref($escape_spec) eq 'CODE' ) { return $escape_spec; } elsif ( ref($escape_spec) eq 'ARRAY' ) { return map { expand_escape_spec($_) } @$escape_spec; } elsif ( ! ref($escape_spec) ) { return map { expand_escape_spec($_) } map { $Escapes{$_} or croak "unsupported escape specification '$_'; " . "should be one of " . join(', ', names()) } split(/\s+/, $escape_spec); } else { croak "unsupported escape specification '$escape_spec'"; } } ######################################################################## ### Double Quoting # $with_surrounding_quotes = quote( $string_value ); sub quote ($) { '"' . $_[0] . '"' } # $remove_surrounding_quotes = quote( $string_value ); sub unquote ($) { local $_ = $_[0]; s/\A\"(.*)\"\Z/$1/s; $_; } # $word_or_phrase_with_surrounding_quotes = quote( $string_value ); sub quote_non_words ($) { ( ! length $_[0] or $_[0] =~ /[^\w\_\-\/\.\:\#]/ ) ? '"'.$_[0].'"' : $_[0] } ### Backslash Escaping use vars qw( %Printable %Unprintable ); %Printable = ( ( map { chr($_), unpack('H2', chr($_)) } (0..255) ), "\\"=>'\\', "\r"=>'r', "\n"=>'n', "\t"=>'t', "\""=>'"' ); %Unprintable = ( reverse %Printable ); # $special_characters_escaped = printable( $source_string ); sub printable ($) { local $_ = ( defined $_[0] ? $_[0] : '' ); s/([\r\n\t\"\\\x00-\x1f\x7F-\xFF])/\\$Printable{$1}/sg; return $_; } # $original_string = unprintable( $special_characters_escaped ); sub unprintable ($) { local $_ = ( defined $_[0] ? $_[0] : '' ); s/((?:\A|\G|[^\\]))\\([rRnNtT\"\\]|[\da-fA-F]{2})/$1.$Unprintable{lc($2)}/gse; return $_; } # quoted_and_escaped = qprintable( $source_string ); sub qprintable ($) { quote_non_words printable $_[0] } # $original_string = unqprintable( quoted_and_escaped ); sub unqprintable ($) { unprintable unquote $_[0] } ######################################################################## ### Elision use vars qw( $Elipses $DefaultLength $DefaultStrictness ); $Elipses = '...'; $DefaultLength = 60; $DefaultStrictness = 10; # $elided_string = elide($string); # $elided_string = elide($string, $length); # $elided_string = elide($string, $length, $word_boundary_strictness); # Return a single-quoted, shortened version of the string, with ellipsis sub elide ($;$$) { my $source = shift; my $length = scalar(@_) ? shift() : $DefaultLength; my $word_limit = scalar(@_) ? shift() : $DefaultStrictness; # If the source is already short, we don't need to do anything return $source if (length($source) < $length); # Leave room for the elipses and make sure we include at least one character. $length -= length( $Elipses ); $length = 1 if ( $length < 1 ); my $excerpt; # Try matching $length characters or less at a word boundary. $excerpt = ( $source =~ /^(.{0,$length})(?:\s|\Z)/ )[0] if ( $word_limit ); # Ignore boundaries if that fails or returns much less than we wanted. $excerpt = substr($source, 0, $length) if ( ! defined $excerpt or length($excerpt) < length($source) and ! length($excerpt) || abs($length - length($excerpt)) > $word_limit); return $excerpt . $Elipses; } ######################################################################## # @words = string2list( $space_separated_phrases ); sub string2list { my $text = shift; carp "string2list called with a non-text argument, '$text'" if (ref $text); my @words; my $word = ''; while ( defined $text and length $text ) { if ($text =~ s/\A(?: ([^\"\s\\]+) | \\(.) )//mx) { $word .= $1; } elsif ($text =~ s/\A"((?:[^\"\\]|\\.)*)"//mx) { $word .= $1; } elsif ($text =~ s/\A\s+//m){ push(@words, unprintable($word)); $word = ''; } elsif ($text =~ s/\A"//) { carp "string2list found an unmatched quote at '$text'"; return; } else { carp "string2list parse exception at '$text'"; return; } } push(@words, unprintable($word)); return @words; } # $space_sparated_string = list2string( @words ); sub list2string { join ( ' ', map qprintable($_), @_ ); } # %hash = list2hash( @words ); sub list2hash { my @pairs; foreach (@_) { my ($key, $val) = m/\A(.*?)(?:\=(.*))?\Z/s; push @pairs, $key, $val; } return @pairs; } # @words = hash2list( %hash ); sub hash2list { my @words; while ( scalar @_ ) { my ($key, $value) = ( shift, shift ); push @words, qprintable($key) . '=' . qprintable($value) } return @words; } # %hash = string2hash( $string ); sub string2hash { return list2hash( string2list( shift ) ); } # $string = hash2string( %hash ); sub hash2string { join ( ' ', hash2list( @_ ) ); } ######################################################################## 1; __END__ =pod =head1 NAME String::Escape - Registry of string functions, including backslash escapes =head1 SYNOPSIS use String::Escape qw( printable unprintable ); # Convert control, high-bit chars to \n or \xxx escapes $output = printable($value); # Convert escape sequences back to original chars $value = unprintable($input); use String::Escape qw( elide ); # Shorten strings to fit, if necessary foreach (@_) { print elide( $_, 79 ) . "\n"; } use String::Escape qw( string2list list2string ); # Pack and unpack simple lists by quoting each item $list = list2string( @list ); @list = string2list( $list ); use String::Escape qw( string2hash hash2string ); # Pack and unpack simple hashes by quoting each item $hash = hash2string( %hash ); %hash = string2hash( $hash ); use String::Escape qw( escape ); # Defer selection of escaping routines until runtime $escape_name = $use_quotes ? 'qprintable' : 'printable'; @escaped = escape($escape_name, @values); =head1 DESCRIPTION This module provides a flexible calling interface to some frequently-performed string conversion functions, including applying and removing C/Unix-style backslash escapes like \n and \t, wrapping and removing double-quotes, and truncating to fit within a desired length. Furthermore, the escape() function provides for dynamic selection of operations by using a package hash variable to map escape specification strings to the functions which implement them. The lookup imposes a bit of a performance penalty, but allows for some useful late-binding behaviour. Compound specifications (ex. 'quoted uppercase') are expanded to a list of functions to be applied in order. Other modules may also register their functions here for later general use. (See the "CALLING BY NAME" section below for more.) =head1 FUNCTION REFERENCE =head2 Escaping And Unescaping Functions Each of these functions takes a single simple scalar argument and returns its escaped (or unescaped) equivalent. =over 4 =item quote($value) : $escaped Add double quote characters to each end of the string. =item quote_non_words($value) : $escaped As above, but only quotes empty, punctuated, and multiword values; simple values consisting of alphanumerics without special characters are not quoted. =item unquote($value) : $escaped If the string both begins and ends with double quote characters, they are removed, otherwise the string is returned unchanged. =item printable($value) : $escaped =item unprintable($value) : $escaped These functions convert return, newline, tab, backslash and unprintable characters to their backslash-escaped equivalents and back again. =item qprintable($value) : $escaped =item unqprintable($value) : $escaped The qprintable function applies printable escaping and then wraps the results with quote_non_words, while unqprintable applies unquote and then unprintable. (Note that this is I MIME quoted-printable encoding.) =back =head2 Simple Arrays and Hashes =over 4 =item @words = string2list( $space_separated_phrases ); Converts a space separated string of words and quoted phrases to an array; =item $space_sparated_string = list2string( @words ); Joins an array of strings into a space separated string of words and quoted phrases; =item %hash = string2hash( $string ); Converts a space separated string of equal-sign-associated key=value pairs into a simple hash. =item $string = hash2string( %hash ); Converts a simple hash into a space separated string of equal-sign-associated key=value pairs. =item %hash = list2hash( @words ); Converts an array of equal-sign-associated key=value strings into a simple hash. =item @words = hash2list( %hash ); Converts a hash to an array of equal-sign-associated key=value strings. =back =head2 String Elision Function This function extracts the leading portion of a provided string and appends ellipsis if it's longer than the desired maximum excerpt length. =over 4 =item elide($string) : $elided_string =item elide($string, $length) : $elided_string =item elide($string, $length, $word_boundary_strictness) : $elided_string If the original string is shorter than $length, it is returned unchanged. At most $length characters are returned; if called with a single argument, $length defaults to $DefaultLength. Up to $word_boundary_strictness additional characters may be ommited in order to make the elided portion end on a word boundary; you can pass 0 to ignore word boundaries. If not provided, $word_boundary_strictness defaults to $DefaultStrictness. =item $Elipses The string of characters used to indicate the end of the excerpt. Initialized to '...'. =item $DefaultLength The default target excerpt length, used when the elide function is called with a single argument. Initialized to 60. =item $DefaultStrictness The default word-boundary flexibility, used when the elide function is called without the third argument. Initialized to 10. =back =head1 CALLING BY NAME These functions provide for the registration of string-escape specification names and corresponding functions, and then allow the invocation of one or several of these functions on one or several source string values. =over 4 =item escape($escapes, $value) : $escaped_value =item escape($escapes, @values) : @escaped_values Returns an altered copy of the provided values by looking up the escapes string in a registry of string-modification functions. If called in a scalar context, operates on the single value passed in; if called in a list contact, operates identically on each of the provided values. Valid escape specifications are: =over 4 =item one of the keys defined in %Escapes The coresponding specification will be looked up and used. =item a sequence of names separated by whitespace, Each name will be looked up, and each of the associated functions will be applied successively, from left to right. =item a reference to a function The provided function will be called on with each value in turn. =item a reference to an array Each item in the array will be expanded as provided above. =back A fatal error will be generated if you pass an unsupported escape specification, or if the function is called with multiple values in a scalar context. =item String::Escape::names() : @defined_escapes Returns a list of defined escape specification strings. =item String::Escape::add( $escape_name, \&escape_function ); Add a new escape specification and corresponding function. =item %Escapes : $name, $operation, ... By default, the %Escapes hash is initialized to contain the following mappings: =over 4 =item quote, unquote, or quote_non_words =item printable, unprintable, qprintable, or unqprintable, =item elide Run the above-described functions of the same names. =item uppercase, lowercase, or initialcase Alters the case of letters in the string to upper or lower case, or for initialcase, sets the first letter to upper case and all others to lower. =item none Return an unchanged copy of the original value. =back =back =head1 EXAMPLES Here are a few example uses of these functions, along with their output. =head2 Backslash Escaping C \tNow is the time\nfor all good folks\n C Now is the time for all good folks =head2 Escape By Name C "\tNow is the time\nfor all good folks\n" C "\tNOW IS THE TIME\nFOR ALL GOOD FOLKS\n" C \tNow is the time\n--for all good folks\n =head2 String Elision Function C<$string = 'foo bar baz this that the other';> C foo bar baz this that the other C foo bar... C foo bar b... =head2 Simple Arrays and Hashes C hello "I move next march" C<@list = string2list('one "second item" 3 "four\nlines\nof\ntext"');> C second item C 'Animal Cities', 'bar' =E 'Cheap' );> foo="Animal Cities" bar=Cheap C<%hash = string2hash('key=value "undefined key" words="the cat in the hat"');> C the cat in the hat C 1 =head1 PREREQUISITES AND INSTALLATION This package should run on any standard Perl 5 installation. To install this package, download and unpack the distribution archive from http://www.evoscript.com/dist/ or your favorite CPAN mirror, and execute the standard "perl Makefile.PL", "make test", "make install" sequence. =head1 STATUS AND SUPPORT This release of String::Escape is intended for public review and feedback. It has been tested in several environments and no major problems have been discovered, but it should be considered "beta" pending that feedback. Name DSLI Description -------------- ---- --------------------------------------------- String:: ::Escape bdpf Registry of useful string escaping functions Further information and support for this module is available at Ewww.evoscript.orgE. Please report bugs or other problems to Csimonm@cavalletto.orgE>. The following changes are in progress or under consideration: =over 4 =item * Use word-boundary test in elide's regular expression rather than \s|\Z. =item * Check for possible problems in the use of printable escaping functions and list2hash. For example, are the encoded strings for hashes with high-bit characters in their keys properly unquoted and unescaped? =item * Update string2list; among other things, embedded quotes (eg: a@"!a) shouldn't cause phrase breaks. =back =head1 SEE ALSO Numerous modules provide collections of string manipulation functions; see L for an example. The string2list function is similar to to the quotewords function in the standard distribution; see L. Use other packages to stringify more complex data structures; see L, L, or other similar package. =head1 CREDITS AND COPYRIGHT =head2 Developed By M. Simon Cavalletto, simonm@cavalletto.org Evolution Softworks, www.evoscript.org =head2 Contributors Eleanor J. Evans piglet@piglet.org Jeremy G. Bishop =head2 Copyright Copyright 2002 Matthew Simon Cavalletto. Portions copyright 1996, 1997, 1998, 2001 Evolution Online Systems, Inc. =head2 License You may use, modify, and distribute this software under the same terms as Perl. =cut vdradmin-am-3.6.13/tools/tmplgettext000077500000000000000000000100571443716113400174610ustar00rootroot00000000000000#!/usr/bin/perl # # tmplgettext # # Creates a gettext pot-template from any text template specified by # in (recursivly) # # Any text matching /<%! (.*) !%>/ (even across multiple lines) will be # interpreted as a translatable strings like in gettext("foo") or _("foo"). # # e.g.: tmplgettext "^.*\.html$" ./templates >templates.pot # # Output goes to stdout. # # 04/2005 - Tobias Grimm # 09/2006 - Andres Mair # my $BASENAME; BEGIN { $BASENAME = $1; unshift(@INC, $BASENAME . "../tools/lib/"); } use String::Escape qw(printable); use File::Find; use Env qw(VERSION MY_EMAIL PACKAGE); my $START_TAG = ""; my $filePattern = ""; sub WritePotHeader { my ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = localtime(time); print "# Copyright (C) $MY_EMAIL # This file is distributed under the same license as the VDRAdmin-AM package. # # TRANSLATOR , YEAR # # # Translators, if you are not familiar with the PO format, gettext # documentation is worth reading, especially sections dedicated to # this format, e.g. by running: # info -n '(gettext)PO Files' # info -n '(gettext)Header Entry' # # Some information specific to po-debconf are available at # /usr/share/doc/po-debconf/README-trans # or http://www.debian.org/intl/l10n/po-debconf/README-trans # # Developers do not need to manually edit POT or PO files. # #, fuzzy msgid \"\" msgstr \"\" \"Project-Id-Version: $PACKAGE $VERSION\\n\" \"Report-Msgid-Bugs-To: $MY_EMAIL\\n\"\n"; # FIXME: Correctly set timezone printf "\"POT-Creation-Date: %4d-%02d-%02d %02d:%02d+0100\"\n", $year + 1900, $mon + 1, $mday, $hour, $min; print "\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\" \"Last-Translator: FULL NAME \\n\" \"Language-Team: LANGUAGE \\n\" \"MIME-Version: 1.0\\n\" \"Content-Type: text/plain; charset=CHARSET\\n\" \"Content-Transfer-Encoding: 8bit\\n\"\n\n"; } sub my_normalize { my $text = shift; $text =~ s/[\t\n]//g; $text =~ s/\\'/\'/g; $text =~ s/\\\\/\\/g; return printable($text); } sub WritePotEntry { my ($fileName, $lineNumber, $msgid) = @_; my $escapedMsgid = my_normalize($msgid); # print "#: $fileName:$lineNumber\n"; print "msgid \"$escapedMsgid\"\n"; print "msgstr \"\"\n\n"; } sub ExtractMsgids { my ($fileName, @fileContent) = @_; my $text = ""; my $isTextStarted = 0; my $lineCounter = 0; my $textStartLine; foreach my $line (@fileContent) { my $lookAhead; $lineCounter++; if ($isTextStarted) { $text = $text . "\n"; } for (my $index=0; $index < length($line); $index++) { $lookAhead = substr($line, $index, length($START_TAG)); if ($lookAhead eq $START_TAG) { $index = $index + length($START_TAG); # skip whole tag $isTextStarted = 1; $textStartLine = $lineCounter; $text = ""; } if ($isTextStarted) { $lookAhead = substr($line, $index, length($END_TAG)); if ($lookAhead eq $END_TAG) { $index = $index + length($END_TAG); # skip whole tag if (length($text) > 0) { WritePotEntry($fileName, $textStartLine, $text); } $isTextStarted = 0; } else { $text = $text . substr($line, $index, 1); } } } } } sub ProcessFile { my $file = shift; open(HTML, "< $file"); my @fileContent = ; close(HTML); ExtractMsgids($file, @fileContent); } # # main() # $filePattern = shift(@ARGV); my @files = (); find({no_chdir => 1, wanted => sub {push (@files, $_) if ($_ =~ /$filePattern/);}}, @ARGV); WritePotHeader; ProcessFile $_ foreach (sort(@files)); vdradmin-am-3.6.13/tools/update-po000077500000000000000000000026121443716113400167740ustar00rootroot00000000000000#!/bin/sh -e if [ "$1" = "--check-only" ]; then for LANG in cs de es fi fr hu it nl ru; do echo "$LANG: untranslated=$(msgattrib --untranslated po/$LANG.po | grep ^msgid | wc -l) fuzzy=$(msgattrib --fuzzy po/$LANG.po | grep ^msgid | wc -l)" done exit 0 fi export MY_EMAIL="Andreas Mair " export VERSION="$(grep "^my \$VERSION = " vdradmind.pl | sed -e 's#.*\"\(.*\)\".*#\1#')" export PACKAGE="VDRAdmin-AM" pushd po/ ../tools/tmplgettext "^.*\.html$" ../template >tmp-html-x.pot msguniq --no-wrap tmp-html-x.pot >tmp-pl-x.pot xgettext --from-code=ISO-8859-1 --no-location --no-wrap -L Perl ../vdradmind.pl --copyright-holder "$MY_EMAIL" --package-name="$PACKAGE" --package-version="$VERSION" --msgid-bugs-address="$MY_EMAIL" -j -o tmp-pl-x.pot # Create vdradmin.pot # (don't know how to include our own introduction comment smarter) sed -n '0,/^#, fuzzy$/p' vdradmin.pot sed -e '0,/^#, fuzzy$/d' >vdradmin.pot rm tmp-*.pot popd for LANG in cs de es fi fr hu it nl ru; do echo -n "$LANG: " if msgmerge --no-fuzzy-matching --no-wrap po/$LANG.po po/vdradmin.pot >temp.po ; then mv -f temp.po po/$LANG.po echo " untranslated=$(msgattrib --untranslated po/$LANG.po | grep ^msgid | wc -l) fuzzy=$(msgattrib --fuzzy po/$LANG.po | grep ^msgid | wc -l)" else echo "error merging po/$LANG.po and po/vdradmin.pot" fi done vdradmin-am-3.6.13/uninstall.sh000077700000000000000000000000001443716113400203512install.shustar00rootroot00000000000000vdradmin-am-3.6.13/vdradmind000077700000000000000000000000001443716113400202022vdradmind.plustar00rootroot00000000000000vdradmin-am-3.6.13/vdradmind.pl000077500000000000000000010632241443716113400163270ustar00rootroot00000000000000#!/usr/bin/perl # vim:et:sw=4:ts=4: # # VDRAdmin-AM 2005 - 2014 by Andreas Mair # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. # Or, point your browser to http://www.gnu.org/copyleft/gpl.html # # 08.10.2001 # # require 5.004; use vars qw($PROCNAME); use constant { EV_CHANNEL_NAME => 0, EV_START => 1, EV_STOP => 2, EV_TITLE => 3, EV_SUBTITLE => 4, EV_SUMMARY => 5, EV_VPS => 6, EV_ID => 7, EV_VDR_ID => 8, EV_EVENT_ID => 9, EV_STREAM_INFO => 10, }; my $VERSION = "3.6.13"; my $BASENAME; my $EXENAME; BEGIN { $PROCNAME = "vdradmind"; $0 =~ /(^.*\/)/; $EXENAME = $0; $BASENAME = $1; $0 = $PROCNAME; unshift(@INC, "/usr/share/vdradmin/lib"); unshift(@INC, $BASENAME . "lib/"); } my $localemod; if (eval { require Locale::gettext }) { $localemod = 'Locale::gettext'; } elsif (eval { require Locale::Messages }) { $localemod = 'Locale::Messages'; } else { die("Locale::gettext or Locale::Messages is required: $@"); } my $can_use_bind_textdomain_codeset = 1; eval { $localemod->import(qw(gettext bindtextdomain textdomain bind_textdomain_codeset)); }; if ($@) { $localemod->import(qw(gettext bindtextdomain textdomain)); print("Not using bind_textdomain_codeset(). Please update your Locale::gettext perl module!\n"); $can_use_bind_textdomain_codeset = undef; } require File::Temp; use locale; use CGI qw(:no_debug); use HTTP::Date qw(time2str); use IO::Socket; use Template; use Time::Local qw(timelocal); use POSIX qw(:sys_wait_h strftime mktime locale_h); use MIME::Base64 (); use File::Temp (); use File::Find (); use URI (); use URI::Escape qw(uri_escape uri_unescape); use HTTP::Tiny; use IO::Select; my $can_use_encode = 1; $can_use_encode = undef unless (eval { require Encode }); my $InetSocketModule = 'IO::Socket::INET'; my $VdrSocketModule = 'IO::Socket::INET'; my $can_use_net_smtp = 1; $can_use_net_smtp = undef unless (eval { require Net::SMTP }); my $can_use_smtpauth = 1; $can_use_smtpauth = undef unless (eval { require Authen::SASL }); #Authen::SASL->import(qw(Perl)) if($can_use_smtpauth); # Some users have problems if the LANGUAGE env variable is set # so it's cleared here. $ENV{LANGUAGE} = ""; $SIG{CHLD} = sub { wait }; use strict; #use warnings; my $SEARCH_FILES_IN_SYSTEM = 0; my $VDR_MAX_SVDRP_LENGTH = 10000; # validate this value my $SUPPORTED_LOCALE_PREFIXES = "^(cs|de|en|es|fi|fr|hu|it|nl|ru)_"; my $TOOL_AUTOTIMER = 0; my $TOOL_EPGSEARCH = 1; my $AT_BY_EVENT_ID = 2; my $AT_BY_TIME = 1; my $AT_OFF = 0; my $CHAN_FULL = 0; my $CHAN_WANTED = 1; my $CHAN_TV = 2; my $CHAN_RADIO = 3; # Channel groups start with this number (to be sorted like strings) my $CHAN_GROUPS = 40; sub true () { 1 } sub false () { 0 } sub CRLF () { "\r\n" } # [ internal log level, syslog priority ] sub LOG_FATALERROR () { [ 2, "crit" ] } sub LOG_ERROR () { [ 3, "err" ] } sub LOG_WARNING () { [ 4, "warning" ] } sub LOG_NOTICE () { [ 5, "notice" ] } sub LOG_INFO () { [ 6, "info" ] } sub LOG_DEBUG () { [ 7, "debug" ] } my (%CONFIG, %CONFIG_TEMP); $CONFIG{LOGLEVEL} = 5; #LOG_NOTICE $CONFIG{LOGGING} = 0; $CONFIG{LOGFILE} = "syslog"; $CONFIG{MOD_GZIP} = 0; $CONFIG{CACHE_BG_UPDATE} = 1; $CONFIG{CACHE_TIMEOUT} = 60; $CONFIG{CACHE_LASTUPDATE} = 0; $CONFIG{CACHE_REC_TIMEOUT} = 60; $CONFIG{CACHE_REC_LASTUPDATE} = 0; $CONFIG{CACHE_REC_ENABLED} = 0; $CONFIG{AUTO_SAVE_CONFIG} = 1; $CONFIG{HTTP_KEEPALIVE_TIMEOUT} = 10; # $CONFIG{VDR_HOST} = "localhost"; $CONFIG{VDR_PORT} = 2001; # will be set to 6419 in initial --config if locally installed VDR is >= 1.7.15 $CONFIG{SERVERHOST} = "0.0.0.0"; $CONFIG{SERVERPORT} = 8001; $CONFIG{LOCAL_NET} = "0.0.0.0/32"; $CONFIG{VIDEODIR} = "/video"; $CONFIG{VDRCONFDIR} = "$CONFIG{VIDEODIR}"; $CONFIG{EPGIMAGES} = "$CONFIG{VIDEODIR}/epgimages"; # $CONFIG{TEMPLATE} = "default"; $CONFIG{SKIN} = "default"; $CONFIG{LOGINPAGE} = 0; { my @a =
    ; $CONFIG{RECORDINGS} = scalar(@a) || 1; } $CONFIG{LANG} = ""; # $CONFIG{USERNAME} = "linvdr"; $CONFIG{PASSWORD} = "linvdr"; $CONFIG{GUEST_ACCOUNT} = 0; $CONFIG{USERNAME_GUEST} = "guest"; $CONFIG{PASSWORD_GUEST} = "guest"; $CONFIG{LOCAL_NET_ONLY} = 0; # $CONFIG{ZEITRAHMEN} = 1; $CONFIG{TIMES} = "18:00, 20:00, 21:00, 22:00"; $CONFIG{TL_TOOLTIP} = 1; # $CONFIG{EPG_SUMMARY} = 0; $CONFIG{EPG_SUBTITLE} = 1; $CONFIG{EPG_START_TIME} = "00:00"; # $CONFIG{AT_OFFER} = 0; $CONFIG{AT_FUNC} = 1; $CONFIG{AT_LIFETIME} = 99; $CONFIG{AT_PRIORITY} = 99; $CONFIG{AT_MARGIN_BEGIN} = 10; $CONFIG{AT_MARGIN_END} = 10; $CONFIG{AT_TOOLTIP} = 1; $CONFIG{AT_SORTBY} = "pattern"; $CONFIG{AT_DESC} = 0; # $CONFIG{ES_SORTBY} = "pattern"; $CONFIG{ES_DESC} = 0; $CONFIG{TM_LIFETIME} = 99; $CONFIG{TM_PRIORITY} = 99; $CONFIG{TM_MARGIN_BEGIN} = 10; $CONFIG{TM_MARGIN_END} = 10; $CONFIG{TM_TT_TIMELINE} = 1; $CONFIG{TM_TT_LIST} = 1; $CONFIG{TM_SORTBY} = "day"; $CONFIG{TM_DESC} = 0; # $CONFIG{ST_FUNC} = 1; $CONFIG{ST_REC_ON} = 0; $CONFIG{ST_LIVE_ON} = 1; $CONFIG{ST_URL} = ""; $CONFIG{ST_STREAMDEV_HOST} = ""; # streamdev/xineliboutput host $CONFIG{ST_STREAMDEV_PORT} = 3000; $CONFIG{ST_XINELIB_PORT} = 37890; $CONFIG{ST_VIDEODIR} = ""; $CONFIG{ST_DIRECT_LINKS_ON} = 0; $CONFIG{ST_REC_STREAMDEV} = 1; # $CONFIG{EPG_PRUNE} = 0; $CONFIG{NO_EVENTID} = 0; $CONFIG{NO_EVENTID_ON} = ""; # $CONFIG{AT_SENDMAIL} = 0; # set to 1 and set all the "MAIL_" things if you want email notification on new autotimers. chomp($CONFIG{MAIL_FROM} = 'autotimer@' . (`hostname -f 2>/dev/null` || "localhost.localdomain")); $CONFIG{MAIL_TO} = "you\@example.org"; $CONFIG{MAIL_SERVER} = "localhost"; $CONFIG{MAIL_AUTH_USER} = ""; $CONFIG{MAIL_AUTH_PASS} = ""; # $CONFIG{CHANNELS_WANTED} = ""; $CONFIG{CHANNELS_WANTED_AUTOTIMER} = 0; $CONFIG{CHANNELS_WANTED_PRG} = 0; $CONFIG{CHANNELS_WANTED_PRG2} = 0; $CONFIG{CHANNELS_WANTED_TIMELINE} = 0; $CONFIG{CHANNELS_WANTED_SUMMARY} = 0; $CONFIG{CHANNELS_WANTED_WATCHTV} = 0; $CONFIG{CHANNELS_WITHOUT_EPG} = 0; # $CONFIG{PROG_SUMMARY_COLS} = 3; # $CONFIG{TV_MIMETYPE} = "video/x-mpegurl"; $CONFIG{TV_EXT} = "m3u"; $CONFIG{TV_INTERVAL} = "5"; $CONFIG{TV_SIZE} = "half"; $CONFIG{REC_MIMETYPE} = "video/x-mpegurl"; $CONFIG{REC_EXT} = "m3u"; $CONFIG{REC_SORTBY} = "name"; $CONFIG{REC_DESC} = 0; # $CONFIG{PS_VIEW} = "ext"; # $CONFIG{CMD_LINES} = 20; # $CONFIG{GUI_POPUP_WIDTH} = 550; $CONFIG{GUI_POPUP_HEIGHT} = 550; # my %FEATURES; $FEATURES{STREAMDEV} = 0; # streamdev plugin available? $FEATURES{XINELIB} = 0; # xineliboutput plugin available? $FEATURES{REC_RENAME} = 0; # RENR/MOVR patch available? $FEATURES{AUTOTIMER} = 0; # use autotimer feature? $FEATURES{MYVERSION_HR} = "$VERSION"; # Human readable VDRAdmin-AM version, e.g. 3.6.5 $FEATURES{VDRVERSION} = 0; # Numeric VDR version, e.g. 10344 $FEATURES{VDRVERSION_HR} = ''; # Human readable VDR version, e.g. 1.3.44 $FEATURES{EPGSEARCH_VERSION} = 0; # Numeric epgsearch plugin version, e.g. 924 $FEATURES{EPGSEARCH_VERSION_HR} = ''; # Human readable epgsearch plugin version, e.g. 0.9.24 my %EPGSEARCH_SETTINGS; my $SERVERVERSION = "vdradmind/$VERSION"; my %ERROR_MESSAGE; my $MY_ENCODING = ''; my ($TEMPLATEDIR, $TEMPLATECACHE, $CONFFILE, $LOGGING, $LOGDIR, $LOGFILE, $LOGLEVEL, $PIDFILE, $AT_FILENAME, $DONE_FILENAME, $BL_FILENAME, $ETCDIR, $CERTSDIR, $USER_CSS); if (!$SEARCH_FILES_IN_SYSTEM) { $ETCDIR = "${BASENAME}"; $CERTSDIR = "${ETCDIR}/certs"; $TEMPLATEDIR = "${BASENAME}template"; $TEMPLATECACHE = "${BASENAME}cache"; $CONFFILE = "${BASENAME}vdradmind.conf"; $LOGDIR = "${BASENAME}"; $PIDFILE = "${BASENAME}vdradmind.pid"; $AT_FILENAME = "${BASENAME}vdradmind.at"; $DONE_FILENAME = "${BASENAME}vdradmind.done"; $BL_FILENAME = "${BASENAME}vdradmind.bl"; $USER_CSS = "${BASENAME}user.css"; bindtextdomain("vdradmin", "${BASENAME}locale"); } else { $ETCDIR = "/etc/vdradmin"; $CERTSDIR = "${ETCDIR}/certs"; $TEMPLATEDIR = "/usr/share/vdradmin/template"; $TEMPLATECACHE = "/var/cache/vdradmin"; $LOGDIR = "/var/log/vdradmin"; $PIDFILE = "/var/run/vdradmin/vdradmind.pid"; $CONFFILE = "${ETCDIR}/vdradmind.conf"; $AT_FILENAME = "${ETCDIR}/vdradmind.at"; $DONE_FILENAME = "${ETCDIR}/vdradmind.done"; $BL_FILENAME = "${ETCDIR}/vdradmind.bl"; $USER_CSS = "${ETCDIR}/user.css"; bindtextdomain("vdradmin", "/usr/share/locale"); } my $DONE = &DONE_Read || {}; textdomain("vdradmin"); my $UserCSS; $UserCSS = "user.css" if (-e "$USER_CSS"); my $USE_SHELL_GZIP = false; # set on false to use the gzip library my (%EPG, %CHAN, %CHAN_TABLES, $q, $ACCEPT_GZIP, $SVDRP, $low_time, @RECORDINGS); my (%RECORDING_FOLDERS, %RECORDING_BY_ID); my (%mimehash) = (html => "text/html", png => "image/png", gif => "image/gif", jpg => "image/jpeg", css => "text/css", ico => "image/x-icon", js => "text/javascript", swf => "application/x-shockwave-flash" ); my @LOGINPAGES = qw(prog_summary prog_list2 prog_timeline prog_list timer_list rec_list); $SIG{INT} = \&Shutdown; $SIG{TERM} = \&Shutdown; $SIG{HUP} = \&HupSignal; $SIG{PIPE} = 'IGNORE'; # my ($UseSSL, $UseIPv6); my $DAEMON = 1; for (my $i = 0 ; $i < scalar(@ARGV) ; $i++) { $_ = $ARGV[$i]; if (/^(-h|--help)$/) { $DAEMON = 0; print("Usage $EXENAME [OPTION]...\n"); print("A perl client for the Linux Video Disk Recorder.\n\n"); print(" -n --nofork don't fork\n"); print(" -c --config run configuration dialog\n"); print(" -d [dir] --cfgdir [dir] use [dir] for configuration files\n"); print(" -k --kill kill a forked vdradmind[.pl]\n"); print(" -p [name] --pid [name] name of pidfile (ignored with -n)\n"); print(" -6 --ipv6 use IPv6\n"); print(" -s --ssl only accept https:// connections\n"); print(" -l [level] --log [level] set log level for this session [0 - 7]\n"); print(" -L [file] --logfile [file] set log file for this session\n"); print(" -h --help this message\n"); exit(0); } if (/^(--nofork|-n)$/) { $DAEMON = 0; next; } if (/^(--cfgdir|-d)$/) { $ETCDIR = $ARGV[ ++$i ]; $CONFFILE = "${ETCDIR}/vdradmind.conf"; $AT_FILENAME = "${ETCDIR}/vdradmind.at"; $DONE_FILENAME = "${ETCDIR}/vdradmind.done"; $BL_FILENAME = "${ETCDIR}/vdradmind.bl"; $USER_CSS = "${ETCDIR}/user.css"; next; } if (/^(--config|-c)$/) { $DAEMON = 0; if (-e $CONFFILE) { ReadConfig(); } elsif ($CONFIG{VDR_PORT} == 2001 && `vdr --version 2>/dev/null` =~ /^vdr\s+.*?(\d+)\.(\d+)\.(\d+)/mi) { my $vdrversion = $1 * 10000 + $2 * 100 + $3; $CONFIG{VDR_PORT} = 6419 if ($vdrversion >= 10715); } LoadTranslation(); $CONFIG{VDR_HOST} = Question(gettext("What's your VDR hostname (e.g video.intra.net)?"), $CONFIG{VDR_HOST}); $CONFIG{VDR_PORT} = Question(gettext("On which port does VDR listen to SVDRP queries?"), $CONFIG{VDR_PORT}); $CONFIG{SERVERHOST} = Question(gettext("On which address should VDRAdmin-AM listen (0.0.0.0 for any)?"), $CONFIG{SERVERHOST}); $CONFIG{SERVERPORT} = Question(gettext("On which port should VDRAdmin-AM listen?"), $CONFIG{SERVERPORT}); $CONFIG{USERNAME} = Question(gettext("Username?"), $CONFIG{USERNAME}); $CONFIG{PASSWORD} = Question(gettext("Password?"), $CONFIG{PASSWORD}); $CONFIG{VIDEODIR} = Question(gettext("Where are your recordings stored?"), $CONFIG{VIDEODIR}); $CONFIG{VDRCONFDIR} = Question(gettext("Where are your VDR's configuration files located?"), $CONFIG{VDRCONFDIR}); (my $err = WriteConfig()) =~ s|$||gi; if ($err) { Log(LOG_ERROR, $err); exit(1); } print(gettext("Config file written successfully.") . "\n"); exit(0); } if (/^(--kill|-k)$/) { $DAEMON = 0; exit(1) unless (-e $PIDFILE); my $pid = getPID($PIDFILE); my $killed = defined($pid) ? kill(2, $pid) : -1; sleep(1); if ($killed > 0 && -e $PIDFILE) { # Not deleted by kill/Shutdown()? unlink($PIDFILE) or Log(LOG_WARNING, "Can't delete pid file '$PIDFILE': $!"); } exit($killed > 0 ? 0 : 1); } if (/^(--pid|-p)$/) { $PIDFILE = $ARGV[ ++$i ]; next; } if (/^(--ipv6-all)$/) { $UseIPv6 = 2; next; } if (/^(--ipv6|-6)$/) { $UseIPv6 = 1; next; } if (/^(--ssl|-s)$/) { $UseSSL = 1; next; } if (/^(--log|-l)$/) { $LOGLEVEL = $ARGV[ ++$i ]; $LOGGING = 1; next; } if (/^(--logfile|-L)$/) { $LOGFILE = $ARGV[ ++$i ]; if ($LOGFILE =~ m|/|) { ($LOGDIR, $LOGFILE) = $LOGFILE =~ m|^(.+)/([^/]*)$|; } else { $LOGDIR = "."; } $LOGGING = 1; next; } if (/^(--displaycall|-i)$/) { $DAEMON = 0; for (my $z = 0 ; $z < 5 ; $z++) { DisplayMessage($ARGV[ $i + 1 ]); sleep(3); } CloseSocket(); exit(0); } if (/^(--message|-m)$/) { $DAEMON = 0; DisplayMessage($ARGV[ $i + 1 ]); CloseSocket(); exit(0); } if (/^-u$/) { # Don't use user.css $UserCSS = undef; } } check_permissions() or exit 1; if ($UseIPv6) { if (eval { require IO::Socket::INET6 }) { $InetSocketModule = 'IO::Socket::INET6'; $VdrSocketModule = 'IO::Socket::INET6' if ($UseIPv6 == 2); } else { die("ERROR: Can't load module IO::Socket::INET6: $@"); } } ReadConfig(); $LOGGING ||= $CONFIG{LOGGING}; $LOGFILE ||= $CONFIG{LOGFILE}; LoadTranslation(); #use Template::Constants qw( :debug ); # IMHO a better Template Modul ;-) # some useful options (see below for full list) my $Xtemplate_vars = { usercss => $UserCSS, charset => $MY_ENCODING, gettext => sub{ $_[0] =~ s/\n\s+//g; return gettext($_[0]); }, config => \%CONFIG, features => \%FEATURES }; my $Xconfig = { START_TAG => '\<\?\%', # tag style END_TAG => '\%\?\>', # tag style INCLUDE_PATH => $TEMPLATEDIR, # or list ref INTERPOLATE => 0, # expand "$var" in plain text PRE_CHOMP => 1, # cleanup whitespace POST_CHOMP => 1, # cleanup whitespace EVAL_PERL => 1, # evaluate Perl code blocks COMPILE_EXT => 'cache', # tuning for templates COMPILE_DIR => $TEMPLATECACHE, # tuning for templates STAT_TTL => 3600, # tuning for templates VARIABLES => $Xtemplate_vars, # Developer options: #CACHE_SIZE => 0, #STAT_TTL => 1, #DEBUG => DEBUG_ALL, }; # create Template object my $Xtemplate; eval { $Xtemplate = Template->new($Xconfig); }; if ($@) { # Perhaps a cache dir problem, try without it chomp(my $err = $@); delete @$Xconfig{qw(COMPILE_DIR COMPILE_EXT)}; $Xtemplate = Template->new($Xconfig); Log(LOG_WARNING, "Problem setting up dir for compiled templates, expect degraded performance: $err"); } # ---- End new template section ---- my $LOG_TO_SYSLOG = 0; if ($LOGGING && $LOGFILE eq "syslog") { eval { require Sys::Syslog; Sys::Syslog->import(qw(:standard)); openlog($PROCNAME, "cons,pid", "daemon"); } and $LOG_TO_SYSLOG = 1; if ($@) { Log(LOG_WARNING, "Error setting up syslog logging, falling back to stderr: $@"); } } if (!$LOG_TO_SYSLOG) { *closelog = sub {}; # for Shutdown() } if ($CONFIG{MOD_GZIP}) { # lib gzipping require Compress::Zlib; } if (-e "$PIDFILE") { my $pid = getPID($PIDFILE); if ($pid) { Log(LOG_ERROR, "There's already a copy of this program running! (pid: $pid)\n"); chomp(my $pidproc = `ps -p $pid -o comm=` || ""); if ($pidproc eq $PROCNAME) { Log(LOG_ERROR, "If you feel this is an error, remove $PIDFILE!\n"); exit(1); } Log(LOG_ERROR, "The pid $pid is not a running $PROCNAME process, so I'll start anyway.\n"); } else { Log(LOG_ERROR, "$PIDFILE exists, but is empty or contains bogus data, so I'll start anyway.\n"); } } if ($DAEMON) { open(STDIN, "
    new( LocalPort => $CONFIG{SERVERPORT}, LocalAddr => $CONFIG{SERVERHOST}, Listen => 10, ReuseAddr => 1, ReusePort => 1, Reuse => 1, SSL_cert_file => "$CERT_FILE", SSL_key_file => "$KEY_FILE", SSL_ca_file => "$CA_FILE", SSL_ca_path => "$CA_PATH" ); *{HTTP::Daemon::SSL::product_tokens} = sub {return $SERVERVERSION;}; } else { die("ERROR: Can't load module HTTP::Daemon::SSL: $@"); } } else { if (eval { require HTTP::Daemon; }) { $Daemon = HTTP::Daemon->new( LocalPort => $CONFIG{SERVERPORT}, LocalAddr => $CONFIG{SERVERHOST}, Listen => 10, ReuseAddr => 1, ReusePort => 1, Reuse => 1 ); *{HTTP::Daemon::product_tokens} = sub {return $SERVERVERSION;}; } else { die("ERROR: Can't load module HTTP::Daemon: $@"); } } if (!$Daemon) { my $host = $CONFIG{SERVERHOST} || '(SERVERHOST missing)'; my $port = $CONFIG{SERVERPORT} || '(SERVERPORT missing)'; die("Can't start server at $host:$port: $@\n"); } $SIG{__DIE__} = \&SigDieHandler; my @reccmds = loadCommandsConf("$CONFIG{VDRCONFDIR}/reccmds.conf"); my @vdrcmds = loadCommandsConf("$CONFIG{VDRCONFDIR}/commands.conf"); ## # Mainloop ## my ($MyURL, $Referer, $Query, $Guest); my @GUEST_USER = qw(prog_detail prog_list prog_list2 prog_timeline timer_list at_timer_list epgsearch_list prog_summary rec_list rec_detail show_top toolbar show_help about); my @TRUSTED_USER = ( @GUEST_USER, qw(prog_detail_form prog_detail_aktion at_timer_edit at_timer_new at_timer_save at_timer_test at_timer_delete epgsearch_upds epgsearch_edit epgsearch_save epgsearch_save_template epgsearch_delete_template epgsearch_delete epgsearch_toggle timer_new_form timer_add timer_delete timer_toggle rec_delete rec_rename rec_edit config prog_switch rc_show rc_hitk grab_picture at_timer_toggle tv_show tv_switch live_stream rec_stream rec_stream_folder rec_play rec_cut force_update vdr_cmds export_channels_m3u epgsearch_config epgsearch_bl_edit epgsearch_bl_save epgsearch_bl_delete) ); my $MyStreamBase = "./vdradmin."; $MyURL = "./vdradmin.pl"; my @Connections = (); $CONFIG{CACHE_LASTUPDATE} = 0; while (true) { @Connections = grep {$_->{socket}->connected} @Connections; my $fd_set = ''; vec($fd_set, $Daemon->fileno, 1) = 1; foreach my $c (@Connections) { vec($fd_set, $c->{socket}->fileno, 1) = 1; } my $n_ready = select($fd_set, undef, undef, 2); Log(LOG_DEBUG, sprintf("[DAEMON] select() -> %s", printVec($fd_set))) if $n_ready > 0; my $now = time(); # update EPG if ($n_ready == 0 && ($CONFIG{CACHE_BG_UPDATE} == 1 || $CONFIG{AT_FUNC} && $FEATURES{AUTOTIMER} )) { if (UptoDate() != 0) { Log(LOG_DEBUG, "[EPG] Updating EPG data in the background FAILED, trying again in 60secs."); $CONFIG{CACHE_LASTUPDATE} = $now + 60 - $CONFIG{CACHE_TIMEOUT} * 60; } } if (vec($fd_set, $Daemon->fileno, 1)) { my $con = $Daemon->accept(); if ($con) { Log(LOG_DEBUG, sprintf("[DAEMON] accepted fd=%d, peer=%s", $con->fileno, $con->peerhost)); push(@Connections, {socket => $con, ttl => undef}); } next; } my @new = (); my $found = undef; foreach my $c (@Connections) { if (vec($fd_set, $c->{socket}->fileno, 1)) { $c->{ttl} = undef; if (!$found) { $found = $c; # don't copy } else { push(@new, $c); } } else { # no incoming data if ($c->{ttl} && $now >= $c->{ttl}) { Log(LOG_DEBUG, sprintf("[CLIENT(%d)] keep-alive timeout\n", $c->{socket}->fileno)); close($c->{socket}); } else { $c->{ttl} = $now + $CONFIG{HTTP_KEEPALIVE_TIMEOUT} unless $c->{ttl}; push(@new, $c); } } } @Connections = @new; next unless $found; # move to the end push(@Connections, $found); $Client = $found->{socket}; undef $found; if ($CONFIG{LOCAL_NET_ONLY} && !subnetcheck($Client->peerhost, $CONFIG{LOCAL_NET})) { closeClient(); next; } $Client->timeout(2); my $req = $Client->get_request(); if ($req) { processRequest($req); } else { Log(LOG_DEBUG, sprintf("[CLIENT(%d)] get_request() failed: %s", $Client->fileno, $Client->reason)); closeClient(); } } ############################################################################# ############################################################################# sub printVec { my $vec = shift; my @fdarr = (); for (my $i = 0; $i < length($vec) * 8; $i++) { push(@fdarr, $i) if (vec($vec, $i, 1)); } return join(',', @fdarr); } sub closeClient { if ($Client) { Log(LOG_DEBUG, sprintf("CLIENT(%d)] close()", $Client->fileno)); @Connections = grep {$_->{socket} != $Client} @Connections; close($Client); undef $Client; } } sub processRequest { my $req = shift; $ACCEPT_GZIP = 0; #print("REQUEST: $raw_request\n"); my $raw_request = $1 if ($req->as_string =~ /^([^\r\n]++)\r*\n/); Log(LOG_DEBUG, sprintf("[CLIENT(%d)] $raw_request\n", $Client->fileno)); if ($req->uri =~ /(\/[\w\.\/-\:]*)(?:\?([\w=&\.\+\%-\:\!\@\~\#]+))?$/) { ($Request, $Query) = ($1, $2); } else { Error("404", gettext("Not found"), gettext("The requested URL was not found on this server!")); return; } $Request =~ s|^/+|/|; local $ENV{HTTP_HOST}; # parse header my ($username, $password, $http_useragent); $Referer = $req->header("Referer"); $ENV{HTTP_HOST} = $req->header("Host"); ($username, $password) = split(":", MIME::Base64::decode_base64($1), 2) if ($req->header("Authorization") =~ /basic (.*)/i); $http_useragent = $req->header("User-Agent"); $ACCEPT_GZIP = 1 if ($req->header("Accept-Encoding") =~ /gzip/); my ($http_status, $bytes_transfered); # authenticate #print("Username: $username / Password: $password\n"); my $checkpass = defined($username) && defined($password); if (($checkpass && $CONFIG{USERNAME} eq $username && $CONFIG{PASSWORD} eq $password) || subnetcheck($Client->peerhost, $CONFIG{LOCAL_NET})) { $Guest = 0; } elsif (($checkpass && $CONFIG{USERNAME_GUEST} eq $username && $CONFIG{PASSWORD_GUEST} eq $password) && $CONFIG{GUEST_ACCOUNT}) { $Guest = 1; } else { ($http_status, $bytes_transfered) = headerNoAuth(); Log(LOG_INFO, "[ACCESS] " . access_log($Client->peerhost, $username, $raw_request, $http_status, $bytes_transfered, $Request, $http_useragent)); return; } # serve request $SVDRP = SVDRP->new; $MyURL = "." . $Request; if ($Request eq "/vdradmin.pl" || $Request eq "/vdradmin." . $CONFIG{TV_EXT} || $Request eq "/vdradmin." . $CONFIG{REC_EXT}) { $q = CGI->new($Query); my $aktion; my ($real_aktion, $dummy) = split("#", $q->param("aktion"), 2); if ($real_aktion eq "at_timer_aktion") { $real_aktion = "at_timer_save"; $real_aktion = "at_timer_delete" if ($q->param("at_delete")); $real_aktion = "force_update" if ($q->param("at_force")); $real_aktion = "at_timer_test" if ($q->param("test")); } elsif ($real_aktion eq "timer_aktion") { $real_aktion = "timer_delete" if ($q->param("timer_delete")); $real_aktion = "timer_toggle" if ($q->param("timer_active") || $q->param("timer_inactive")); } elsif ($real_aktion eq "epgsearch_aktion") { $real_aktion = "epgsearch_save"; $real_aktion = "epgsearch_save_template" if ($q->param("save_template")); $real_aktion = "epgsearch_delete_template" if ($q->param("delete_template")); $real_aktion = "epgsearch_delete" if ($q->param("delete")); $real_aktion = "epgsearch_edit" if ($q->param("single_test")); $real_aktion = "epgsearch_list" if ($q->param("execute")); $real_aktion = "epgsearch_list" if ($q->param("favorites")); $real_aktion = "epgsearch_list" if ($q->param("exit")); $real_aktion = "epgsearch_upds" if ($q->param("upds")); } elsif ($real_aktion eq "epgsearch_config_aktion") { $real_aktion = "epgsearch_config"; $real_aktion = "epgsearch_bl_delete" if ($q->param("delete")); } elsif ($real_aktion eq "epgsearch_bl_aktion") { $real_aktion = "epgsearch_bl_save"; $real_aktion = "epgsearch_config" if ($q->param("exit")); } my @ALLOWED_FUNCTIONS; $Guest ? (@ALLOWED_FUNCTIONS = @GUEST_USER) : (@ALLOWED_FUNCTIONS = @TRUSTED_USER); for (@ALLOWED_FUNCTIONS) { ($aktion = $real_aktion) if ($real_aktion eq $_); } if ($aktion) { eval("(\$http_status, \$bytes_transfered) = $aktion();"); } else { # XXX redirect to no access template Error("403", gettext("Forbidden"), gettext("You don't have permission to access this function!")); next; } } elsif ($Request eq "/") { $MyURL = "./vdradmin.pl"; ($http_status, $bytes_transfered) = show_index(); } elsif ($Request eq "/navigation.html") { ($http_status, $bytes_transfered) = show_navi(); } else { ($http_status, $bytes_transfered) = SendFile($Request); } Log(LOG_INFO, "[ACCESS] " . access_log($Client->peerhost, $username, $raw_request, $http_status, $bytes_transfered, $Request, $http_useragent)); $SVDRP->close; } sub check_permissions { my $rc = 1; check_rw_dir($ETCDIR) or $rc = 0; check_rw_dir($CERTSDIR) if ($UseSSL); check_rw_dir($TEMPLATECACHE) or $rc = 0; # Don't check permissions when logging to syslog or stderr !$LOGFILE or $LOGFILE eq "syslog" or $LOGFILE eq "stderr" or check_rw_dir($LOGDIR) or $rc = 0; check_rw_file($PIDFILE) or $rc = 0 if $DAEMON; check_rw_file($CONFFILE) or $rc = 0; if ($CONFIG{AT_FUNC} || $FEATURES{AUTOTIMER}) { check_rw_file($AT_FILENAME) or $rc = 0; check_rw_file($DONE_FILENAME) or $rc = 0; check_rw_file($BL_FILENAME) or $rc = 0; } return $rc; } sub check_rw_dir { my $dir = shift; # print "Checking directory '$dir':\n"; if (-e "$dir") { if (! -d _) { print "ERROR: '$dir' is NOT a directory!\n"; return 0; } if (-r _) { # print "directory '$dir' is readable!\n"; } else { print "ERROR: directory '$dir' is NOT readable!\n"; return 0; } if (-w _) { # print "directory '$dir' is writable!\n"; } else { print "ERROR: directory '$dir' is NOT writable!\n"; return 0; } } else { print "ERROR: directory '$dir' is missing!\n"; return 0; } return 1; } sub check_rw_file { my $file = shift; # print "Checking file '$file':\n"; if (-e "$file") { if (-d _) { print "ERROR: '$file' is a directory!\n"; return 0; } if (-r _) { # print "file '$file' is readable!\n"; } else { print "ERROR: file '$file' is NOT readable!\n"; return 0; } if (-w _) { # print "file '$file' is writable!\n"; } else { print "ERROR: file '$file' is NOT writable!\n"; return 0; } } else { $file =~ /(^.*)\/[^\/]*$/; return check_rw_dir($1); } return 1; } sub GetChannelDesc { #TODO: unused my (%hash); for (@{$CHAN{$CHAN_FULL}->{channels}}) { $hash{ $_->{id} } = $_->{name}; } return (%hash); } sub GetChannelDescByNumber { my $vdr_id = shift; if ($vdr_id) { for (@{$CHAN{$CHAN_FULL}->{channels}}) { if ($_->{vdr_id} == $vdr_id) { return ($_->{name}); } } } else { return (0); } } sub GetChannelUniqIdByNumber { my $vdr_id = shift; if ($vdr_id) { for (@{$CHAN{$CHAN_FULL}->{channels}}) { if ($_->{vdr_id} == $vdr_id) { return ($_->{uniq_id}); } } } else { return (0); } } sub include { my $file = shift; if ($file) { eval(ReadFile($file)); } } sub ReadFile { my $file = shift; return if (!$file); open(I18N, $file) || HTMLError(sprintf($ERROR_MESSAGE{cant_open}, $file)); my $buf = join("", ); close(I18N); return ($buf); } sub GetChannelID { #TODO: unused my ($sid) = $_[0]; for (@{$CHAN{$CHAN_FULL}->{channels}}) { if ($_->{id} == $sid) { return ($_->{number}); } } } sub EURL { #TODO: unused my ($text) = @_; $text =~ s/([^0-9a-zA-Z])/sprintf("%%%2.2x", ord($1))/ge; return ($text); } sub HTMLError { my $error = join("", @_); $CONFIG{CACHE_LASTUPDATE} = 0; my $vars = { error => $error }; return showTemplate("error.html", $vars); } sub FillInZero { #TODO: unused my ($str, $length) = @_; while (length($str) < $length) { $str = "0$str"; } return ($str); } sub MHz { my $frequency = shift; while ($frequency > 20000) { $frequency /= 1000; } return (int($frequency)); } sub ChanTree { undef(%CHAN); undef(%CHAN_TABLES); my (@CHANNELS_FULL, @CHANNELS_WANTED, @CHANNELS_TV, @CHANNELS_RADIO); my $group_name = ""; my $group_number = $CHAN_GROUPS - 1; if (!$FEATURES{VDRVERSION}) { # first connection - have to get version $SVDRP->command("help"); $SVDRP->readresponse; } my $use_groups = ($FEATURES{VDRVERSION} >= 10600); if ($use_groups) { $SVDRP->command("lstc :groups"); } else { $SVDRP->command("lstc"); } my ($DATA) = $SVDRP->readresponse; while ($_ = shift @$DATA) { chomp; my ($vdr_id, $temp) = split(/ /, $_, 2); if ($use_groups && $temp =~ /^:(.*)/) { # :group_name $group_name = $1; $group_number += 1; $CHAN{$group_number}->{title} = $group_name; $CHAN{$group_number}->{channels} = []; next; } my ($name, $frequency, $polarization, $source, $symbolrate, $vpid, $apid, $tpid, $ca, $service_id, $nid, $tid, $rid) = split(/\:/, $temp); $name =~ /(^[^,;]*).*/; #TODO? $name = $1; my $uniq_id = $source . "-" . $nid . "-" . ($nid || $tid ? $tid : $frequency) . "-" . $service_id; $uniq_id .= "-" . $rid if ($rid != 0); my $chan_ref = { vdr_id => $vdr_id, name => $name, frequency => MHz($frequency), polarization => $polarization, source => $source, symbolrate => $symbolrate, vpid => $vpid, apid => $apid, tpid => $tpid, ca => $ca, service_id => $service_id, nid => $nid, tid => $tid, rid => $rid, uniq_id => $uniq_id }; push(@CHANNELS_FULL, $chan_ref); $CHAN_TABLES{by_channel_id}->{$uniq_id} = $chan_ref; if ($CONFIG{CHANNELS_WANTED}) { for my $n (split(",", $CONFIG{CHANNELS_WANTED})) { if ($n eq $vdr_id) { push(@CHANNELS_WANTED, $chan_ref); last; } } } if ($vpid) { push(@CHANNELS_TV, $chan_ref); } elsif ($apid) { push(@CHANNELS_RADIO, $chan_ref); } if ($use_groups && $group_name) { push(@{$CHAN{$group_number}->{channels}}, $chan_ref); } } $CHAN{$CHAN_FULL}->{title} = gettext('All channels'); $CHAN{$CHAN_FULL}->{channels} = \@CHANNELS_FULL; if (@CHANNELS_WANTED) { $CHAN{$CHAN_WANTED}->{title} = gettext('Selected channels'); $CHAN{$CHAN_WANTED}->{channels} = \@CHANNELS_WANTED; } if (@CHANNELS_TV) { $CHAN{$CHAN_TV}->{title} = gettext('TV channels'); $CHAN{$CHAN_TV}->{channels} = \@CHANNELS_TV; } if (@CHANNELS_RADIO) { $CHAN{$CHAN_RADIO}->{title} = gettext('Radio channels'); $CHAN{$CHAN_RADIO}->{channels} = \@CHANNELS_RADIO; } # Temporarly disabled, because channellist also gets sorted by names. This causes duplicate channels appear side-by-side # Sort channel lists by channel name #foreach my $idx (keys(%CHAN)) { # @{$CHAN{$idx}->{channels}} = sort {$a->{name} cmp $b->{name}} @{$CHAN{$idx}->{channels}} #} } sub getChannelGroups { my $url = shift; my $cur = shift; my @ch_grps; foreach (sort(keys(%CHAN))) { push(@ch_grps, { id => $_, title => $CHAN{$_}->{title}, url => $url . "&wanted_channels=$_", selected => $_ eq $cur ? 1 : undef } ); } return \@ch_grps; } sub get_vdrid_from_channelid { my $channel_id = shift; if ($channel_id =~ /^(\d*)$/) { # vdr 1.0.x & >= vdr 1.1.15 for my $channel (@{$CHAN{$CHAN_FULL}->{channels}}) { if ($channel->{service_id} == $1) { return ($channel->{vdr_id}); } } } elsif (my $channel = $CHAN_TABLES{by_channel_id}->{$channel_id}) { return ($channel->{vdr_id}); } else { print "Can't find channel_id $channel_id\n"; } } # # Used to store channelid (instead of channel number) into auto timer entries. # Allows channels to be moved around without auto timer channels being messed up. # Use at your own risk... tvr@iki.fi # sub get_channelid_from_vdrid { my $vdr_id = shift; if ($vdr_id) { my @C = grep($_->{vdr_id} == $vdr_id, @{$CHAN{$CHAN_FULL}->{channels}}); if (scalar(@C) == 1) { my $ch = $C[0]; return $ch->{source} . "-" . $ch->{nid} . "-" . ($ch->{nid} || $ch->{tid} ? $ch->{tid} : $ch->{frequency}) . "-" . $ch->{service_id}; } } } sub get_name_from_uniqid { my $uniq_id = shift; if ($uniq_id) { # Kanalliste nach identischer vdr_id durchsuchen my @C = grep($_->{uniq_id} eq $uniq_id, @{$CHAN{$CHAN_FULL}->{channels}}); # foreach (@{$CHAN{$CHAN_FULL}->{channels}}) { # printf("(%s) ($uniq_id)\n", $_->{uniq_id}); # return $_->{name} if ($_->{uniq_id} eq $uniq_id); # } # Es darf nach Spec nur eine Übereinstimmung geben if (scalar(@C) == 1) { return $C[0]->{name}; } } } sub get_name_from_vdrid { my $vdr_id = shift; if ($vdr_id) { # Kanalliste nach identischer vdr_id durchsuchen my @C = grep($_->{vdr_id} == $vdr_id, @{$CHAN{$CHAN_FULL}->{channels}}); # Es darf nach Spec nur eine Übereinstimmung geben if (scalar(@C) == 1) { return $C[0]->{name}; } } } sub get_channel_from_vdrid { my $vdr_id = shift; if ($vdr_id) { # Kanalliste nach identischer vdr_id durchsuchen my @C = grep($_->{vdr_id} == $vdr_id, @{$CHAN{$CHAN_FULL}->{channels}}); # Es darf nach Spec nur eine Übereinstimmung geben if (scalar(@C) == 1) { return $C[0]; } } } sub get_transponder_from_vdrid { my $vdr_id = shift; if ($vdr_id) { # Kanalliste nach identischer vdr_id durchsuchen my @C = grep($_->{vdr_id} == $vdr_id, @{$CHAN{$CHAN_FULL}->{channels}}); # Es darf nach Spec nur eine Übereinstimmung geben if (scalar(@C) == 1) { return ("$C[0]->{source}-$C[0]->{frequency}-$C[0]->{polarization}"); } } } sub get_ca_from_vdrid { my $vdr_id = shift; if ($vdr_id) { # Kanalliste nach identischer vdr_id durchsuchen my @C = grep($_->{vdr_id} == $vdr_id, @{$CHAN{$CHAN_FULL}->{channels}}); # Es darf nach Spec nur eine Übereinstimmung geben if (scalar(@C) == 1) { return ($C[0]->{ca}); } } } ############################################################################# # common helpers ############################################################################# # remove spaces around string sub trim($) { my $string = shift; $string =~ s/^\s+//; $string =~ s/\s+$//; return $string; } # remove leading whitespaces from string sub ltrim($) { my $string = shift; $string =~ s/^\s+//; return $string; } # remove trailing whitespaces from string sub rtrim($) { my $string = shift; $string =~ s/\s+$//; return $string; } # quotemeta() for $MY_ENCODING byte strings (with zero utf8 flag) sub my_quotemeta { my $str = shift; if ($can_use_encode) { $str = Encode::decode($MY_ENCODING, $str); return Encode::encode($MY_ENCODING, quotemeta($str)); } else { return quotemeta($str); } } # case-insensitive compare on byte strings sub ciCmp { my ($a, $b) = @_; if (utf8::is_utf8($a)) { $a = lc($a); } elsif ($can_use_encode) { $a = lc(Encode::decode($MY_ENCODING, $a)); } if (utf8::is_utf8($b)) { $b = lc($b); } elsif ($can_use_encode) { $b = lc(Encode::decode($MY_ENCODING, $b)); } return $a cmp $b; } sub my_truncate { my ($text, $len) = @_; my $decode = !utf8::is_utf8($text) && $can_use_encode; $text = Encode::decode($MY_ENCODING, $text) if ($decode); $text = substr($text, 0, $len - 3) . "..." if (length($text) >= $len); $text = Encode::encode($MY_ENCODING, $text) if ($decode); return $text; } ############################################################################# # EPG functions ############################################################################# sub EPG_getEntry { my $vdr_id = shift; my $epg_id = shift; if ($vdr_id && $epg_id) { for (@{ $EPG{$vdr_id} }) { #if($_->{id} == $epg_id) { if ($_->[EV_EVENT_ID] == $epg_id) { return ($_); } } } } sub getNumberOfElements { #TODO: unused my $ref = shift; if ($ref) { return (@{$ref}); } else { return (0); } } sub getElement { my $ref = shift; my $index = shift; if ($ref) { return ($ref->[$index]); } else { return; } } sub EPG_buildTree { $SVDRP->command("lste"); my ($i, @events); my ($id, $bc) = (1, 0); $low_time = time; undef(%EPG); my $to_charset = $MY_ENCODING; my $from_charset = $SVDRP->encoding; my $recode = ($can_use_encode && $from_charset && $to_charset && ($from_charset ne $to_charset))? 1 : 0; my $SOCK = $SVDRP->socket; while($_ = <$SOCK>) { chomp; Encode::from_to($_, $from_charset, $to_charset) if ($recode); if (/^... /) { last; } if (/^...-C ([^ ]+) *(.*)/) { undef(@events); my ($channel_id, $channel_name) = ($1, $2); my $vdr_id = get_vdrid_from_channelid($channel_id); if ($CONFIG{EPG_PRUNE} > 0 && $vdr_id > $CONFIG{EPG_PRUNE}) { # diesen channel nicht einlesen while($_ = <$SOCK>) { Encode::from_to($_, $from_charset, $to_charset) if ($recode); last if (/^...-c/); last if (/^... /); } } else { $bc++; while($_ = <$SOCK>) { Encode::from_to($_, $from_charset, $to_charset) if ($recode); my $tok = substr($_, 3, 2); my $rest = substr($_, 6); if ($tok eq "-E") { # no need for chomp here - split() will take care my ($event_id, $time, $duration) = split(/ /, $rest, 4); my ($title, $subtitle, $summary, $vps); my @stream_info = (); while($_ = <$SOCK>) { chomp; Encode::from_to($_, $from_charset, $to_charset) if ($recode); $tok = substr($_, 3, 2); $rest = substr($_, 6); if ($tok eq "-T") { $title = $rest } elsif ($tok eq "-S") { $subtitle = $rest; } elsif ($tok eq "-D") { $summary = $rest; } elsif ($tok eq "-X") { push(@stream_info, $rest); } elsif ($tok eq "-V") { $vps = $rest; } elsif ($tok eq "-e") { # $low_time = $time if ($time < $low_time); push(@events, [ $channel_name, # EV_CHANNEL_NAME $time, # EV_START $time + $duration, # EV_STOP $title, # EV_TITLE $subtitle, # EV_SUBTITLE $summary, # EV_SUMMARY $vps, # EV_VPS $id, # EV_ID $vdr_id, # EV_VDR_ID $event_id, # EV_EVENT_ID join("\n", @stream_info), # EV_STREAM_INFO ] ); $id++; last; } elsif ($tok =~ /^ /) { last; } } } elsif ($tok eq "-c") { if ($FEATURES{VDRVERSION} < 10305) { # EPG is sorted by date since VDR 1.3.5 my ($last) = 0; my (@temp); for (sort({ $a->[EV_START] <=> $b->[EV_START] } @events)) { next if ($last == $_->[EV_START]); push(@temp, $_); $last = $_->[EV_START]; } $EPG{$vdr_id} = [@temp]; } else { $EPG{$vdr_id} = [@events]; } last; } elsif ($tok =~ /^ /) { last; } } } } } Log(LOG_INFO, "[EPG] EPGTree: $id events, $bc broadcasters (lowtime $low_time)"); } sub getEventStreamInfo { my ($event, $type, $raw) = @_; my $type_re = qr/^$type/; my @streams = grep { /$type_re/ } split("\n", $event->[EV_STREAM_INFO]); if ($raw) { if (wantarray) { return map { "X " . $_ } @streams; } else { return join("\n", map { "X " . $_ } @streams); } } else { my @out = (); for my $s (@streams) { my ($what, $garbage, $lang, $descr) = split(/ /, $s, 4); if ($what eq "1") { $what = "MPEG2: "; } elsif ($what eq "2") { $what = "MP2: "; } elsif ($what eq "4") { $what = "AC3: "; } elsif ($what eq "5") { $what = "H.264: "; } elsif ($what eq "6") { $what = "HEAAC: "; } else { $what = "" }; push(@out, $what . ($descr ? $descr . " (" . $lang . ")" : $lang)); } return wantarray? @out : join(", ", @out); } } sub getEventVideo { my ($event, $raw) = @_; return getEventStreamInfo($event, "[15]", $raw); } sub getEventAudio { my ($event, $raw) = @_; return getEventStreamInfo($event, "[246]", $raw); } sub getEventSubs { my ($event, $raw) = @_; return getEventStreamInfo($event, "3", $raw); } ############################################################################# # Socket functions ############################################################################# sub PrintToClient { my $string = join("", @_); return if (!defined($string)); print($Client $string) if ($Client && $Client->connected()); } sub ParseRequest { my $Socket = shift; my (@Request, $Line); do { $Line = <$Socket>; $Line =~ s/\r\n//g; push(@Request, $Line); } while ($Line); return (@Request); } sub CloseSocket { $SVDRP->close() if (defined $SVDRP); } sub OpenSocket { $SVDRP = SVDRP->new; } sub SendCMD { my $cmd = join("", @_); if (($FEATURES{VDRVERSION} < 10336) && (length($cmd) > $VDR_MAX_SVDRP_LENGTH)) { Log(LOG_FATALERROR, "[INT] SendCMD(): command is too long(" . length($cmd) . "): " . substr($cmd, 0, 10)); return; } OpenSocket() if (!$SVDRP); my @output; Log(LOG_DEBUG, "[SendCMD] send: $cmd"); $SVDRP->command($cmd); while ($_ = $SVDRP->readoneline) { push(@output, $_); } Log(LOG_DEBUG, "[SendCMD] all data received of: $cmd"); return (@output); } sub GZip { my $content = shift; my $filename = new File::Temp("vdradmin-XXXXX", UNLINK => 1); open(PIPE, "| gzip -9 - > $filename") || die "Can't open pipe to gzip ($!)"; print PIPE $$content; close(PIPE); open(FILE, $filename) || die "Can't open $filename ($!)"; my $result = join("", ); close(FILE); unlink($filename); #my $pid = open2(*RDFH, *WTFH, "gzip -1 -c -"); #print "Write\n"; #print WTFH $$content; #print "Done\n"; #close(WTFH); #my $result = join("", ); #close(RDFH); #waitpid($pid, 0); return ($result); } sub LibGZip { my $content = shift; return (Compress::Zlib::memGzip($$content)); } sub header { my ($status, $ContentType, $data, $filename, $caching, $lastmod) = @_; Log(LOG_FATALERROR, "[INT] Template Error: " . $Xtemplate->error()) if ($status >= 500); if ($ACCEPT_GZIP && $CONFIG{MOD_GZIP}) { if ($USE_SHELL_GZIP) { $data = GZip(\$data); } else { $data = LibGZip(\$data); } } my $status_text = "OK" if ($status eq "200"); my $now = time(); my $resp = HTTP::Response->new($status, $status_text); $resp->header('Date' => time2str($now)); if (!$caching || $ContentType =~ /text\/html/) { $resp->header('Cache-Control' => "max-age=0"); $resp->header('Cache-Control' => "private"); $resp->header('Pragma' => "no-cache"); $resp->header('Expires' => "Thu, 01 Jan 1970 00:00:00 GMT"); } else { $resp->header('Expires' => time2str($now + 3600)); $resp->header('Cache-Control' => "public, max-age=3600"); } if ($lastmod) { $lastmod = $now if ($lastmod > $now); # HTTP 1.1, 14.29 $resp->header('Last-Modified' => time2str($lastmod)); } $resp->header('Content-encoding' => "gzip") if ($CONFIG{MOD_GZIP} && $ACCEPT_GZIP); $resp->header('Content-type' => $ContentType) if ($ContentType); $resp->header('Content-Disposition' => "attachment; filename=$filename") if ($filename); $resp->content($data) if ($data); $Client->send_response($resp); return ($status, length($data)); } sub headerForward { my $url = shift; Log(LOG_DEBUG, "[FORWARD] " . $url); my $resp = HTTP::Response->new(302, "Found"); $resp->header('Date' => time2str()); $resp->header('Location' => $url); $resp->header('Content-type' => 'text/plain'); my $data = "302 Found"; $resp->content($data); $Client->send_response($resp); return (302, length($data)); } sub headerNoAuth { my $resp = HTTP::Response->new(401, "Authorization Required"); $resp->header('Date' => time2str()); $resp->header('WWW-Authenticate' => "Basic realm=\"vdradmind\""); $resp->header('Content-type' => "text/plain"); my $data = "401 Authorization Required"; $resp->content($data); $Client->send_response($resp); return (401, length($data)); } sub Error { my $vars = { title => $_[0] . " - " . $_[1], h1 => $_[1], error => $_[2], }; return showTemplate("noperm.html", $vars, $_[0], $_[1]); } sub SendFile { my ($File) = @_; my ($buf, $temp); $File =~ s/^\///; $File =~ s/^bilder/$CONFIG{SKIN}/i if (defined $CONFIG{SKIN}); my $FileWithPath = sprintf( "%s/%s/%s", #my $FileWithPath = sprintf("%s/%s/%s/%s", #$BASENAME, $TEMPLATEDIR, $CONFIG{TEMPLATE}, $File ); # Skin css file if ($File eq "style.css" and -e sprintf('%s/%s/%s/%s', $TEMPLATEDIR, $CONFIG{TEMPLATE}, $CONFIG{SKIN}, $File)) { $FileWithPath = sprintf('%s/%s/%s/%s', $TEMPLATEDIR, $CONFIG{TEMPLATE}, $CONFIG{SKIN}, $File); } elsif ($File eq "user.css" and -e "$USER_CSS") { $FileWithPath = "$USER_CSS"; } elsif ($File =~ "^epg/") { $File =~ s/^epg\///; $File =~ tr/:/-/; $FileWithPath = $CONFIG{EPGIMAGES} . "/" . $File; } if (-e $FileWithPath) { if (-r _) { my $lastmod = (stat(_))[9]; $buf = ReadFile($FileWithPath); $temp = $File; $temp =~ /([A-Za-z0-9]+)\.([A-Za-z0-9]+)$/; if (!$mimehash{$2}) { die("can't find mime-type \'$2\'\n"); } return (header("200", $mimehash{$2}, $buf, undef, 1, $lastmod)); } else { Log(LOG_FATALERROR, "[ACCESS] Access denied: $File"); Error("403", gettext("Forbidden"), sprintf(gettext("Access to file \"%s\" denied!"), $File)); } } else { Log(LOG_FATALERROR, "[ACCESS] File not found: $File"); Error("404", gettext("Not found"), sprintf(gettext("The URL \"%s\" was not found on this server!"), $File)); } } ############################################################################# # autotimer functions ############################################################################# sub can_do_eventid_autotimer { # check if we may use Event-IDs in general or not return 0 if ($CONFIG{NO_EVENTID} == 1); my $vdr_id = shift; # check if the current channel is on the Event-ID-blacklist for my $n (split(",", $CONFIG{NO_EVENTID_ON})) { return 0 if ($n == $vdr_id); } return 1; } sub AT_Read { my (@at); if (-e $AT_FILENAME) { open(AT_FILE, $AT_FILENAME) || HTMLError(sprintf($ERROR_MESSAGE{cant_open}, $AT_FILENAME)); while () { chomp; next if ($_ eq ""); my ($active, $pattern, $section, $start, $stop, $episode, $prio, $lft, $channel, $directory, $done, $weekday, $buffers, $bstart, $bstop) = split(/\:/, $_); $pattern =~ s/\|/\:/g; $pattern =~ s/\\:/\|/g; $directory =~ s/\|/\:/g; my ($usechannel) = ($channel =~ /^\d+$/) ? $channel : get_vdrid_from_channelid($channel); push( @at, { active => $active, pattern => $pattern, section => $section, start => $start, stop => $stop, buffers => $buffers, bstart => $bstart, bstop => $bstop, episode => $episode, prio => $prio, lft => $lft, channel => $usechannel, directory => $directory, done => $done, # Be compatible with older formats, so search on weekdays default to yes (weekdays => { map { $_->[0] => defined $weekday ? substr($weekday, $_->[1], 1) : 1 } ([ 'wday_mon', 0 ], [ 'wday_tue', 1 ], [ 'wday_wed', 2 ], [ 'wday_thu', 3 ], [ 'wday_fri', 4 ], [ 'wday_sat', 5 ], [ 'wday_sun', 6 ]) }) } ); } close(AT_FILE); } return (@at); } sub AT_Write { my @at = @_; open(AT_FILE, ">" . $AT_FILENAME) || HTMLError(sprintf($ERROR_MESSAGE{cant_open}, $AT_FILENAME)); foreach my $auto_timer (@at) { my $temp; for my $item (qw(active pattern section start stop episode prio lft channel directory done weekdays buffers bstart bstop)) { my $tempitem = $auto_timer->{$item}; if ($item eq 'channel') { my $channelnumber = get_channelid_from_vdrid($tempitem); if ($channelnumber) { $tempitem = $channelnumber; } } elsif ($item eq 'pattern') { $tempitem =~ s/\|/\\|/g; $tempitem =~ s/\:/\|/g; } elsif ($item eq 'weekdays') { # Create weekday string, starting with monday, 1=yes=search this day, e.g. 0011001 my $search_weekday = ''; map { $search_weekday .= $auto_timer->{$item}->{$_} } (qw (wday_mon wday_tue wday_wed wday_thu wday_fri wday_sat wday_sun)); $tempitem = $search_weekday; } else { $auto_timer->{$item} =~ s/\:/\|/g; } if (length($temp) == 0) { $temp = $tempitem; } else { $temp .= ":" . $tempitem; } } # Finally write the auto timer entry print AT_FILE $temp, "\n"; } close(AT_FILE); } sub DONE_Write { my $done = shift || return; open(DONE_FILE, ">" . $DONE_FILENAME) || HTMLError(sprintf($ERROR_MESSAGE{cant_open}, $DONE_FILENAME)); foreach my $n (sort keys %$done) { printf DONE_FILE "%s::%d::%s\n", $n, $done->{$n}, scalar localtime($done->{$n}); } close(DONE_FILE); } sub DONE_Read { my $done; if (-e $DONE_FILENAME) { open(DONE_FILE, $DONE_FILENAME) || HTMLError(sprintf($ERROR_MESSAGE{cant_open}, $DONE_FILENAME)); while () { chomp; next if ($_ eq ""); my @line = split('\:\:', $_); $done->{ $line[0] } = $line[1]; } close(DONE_FILE); } return $done; } sub BlackList_Read { my %blacklist; if (-e $BL_FILENAME) { open(BL_FILE, $BL_FILENAME) || HTMLError(sprintf($ERROR_MESSAGE{cant_open}, $BL_FILENAME)); while () { chomp; next if ($_ eq ""); $blacklist{$_} = 1; } close(BL_FILE); } return %blacklist; } sub AutoTimer { return if (!$CONFIG{AT_FUNC} || !$FEATURES{AUTOTIMER}); Log(LOG_INFO, "[AUTOTIMER] Scanning for events..."); my ($search, $start, $stop) = @_; my @at_matches; my @at; my $dry_run = shift; if ($dry_run) { @at = shift; } else { @at = AT_Read(); } my $oneshots = 0; $DONE = &DONE_Read unless ($DONE); my %blacklist = &BlackList_Read; # Merken der wanted Channels (geht schneller # bevor das immer wieder in der unteren Schleife gemacht wird). my $wanted; for my $n (split(",", $CONFIG{CHANNELS_WANTED})) { $wanted->{$n} = 1; } # Die Timerliste holen #TODO: is this really needed? Timers will be checked in AT_ProgTimer... # my $timer; # foreach my $t (ParseTimer(0)){ ##TODO: what's the 2nd "%s" for? # my $key = sprintf('%d:%s:%s', # $t->{vdr_id}, # $t->{title}, # "" # ); # $timer->{$key} = $t; #printf("Timer: %s / %s / %s\n", $key, $timer->{event_id}, $t); # } #print("TIMER\n") if($timer); #/TODO my $date_now = time(); for my $sender (keys(%EPG)) { for my $event (@{ $EPG{$sender} }) { # Event in the past? next if ($event->[EV_STOP] < $date_now); # Ein Timer der schon programmmiert wurde kann # ignoriert werden #TODO: $timer not initialized # next if($event->[EV_EVENT_ID] == $timer->{event_id}); # Wenn CHANNELS_WANTED_AUTOTIMER dann next wenn der Kanal # nicht in der WantedList steht if ($CONFIG{CHANNELS_WANTED_AUTOTIMER}) { next unless defined $wanted->{ $event->[EV_VDR_ID] }; } # Hamwa schon gehabt? my $DoneStr; unless ($dry_run) { $DoneStr = sprintf('%s~%d~%s', $event->[EV_TITLE], $event->[EV_EVENT_ID], ($event->[EV_SUBTITLE] ? $event->[EV_SUBTITLE] : ''),); if (exists $DONE->{$DoneStr}) { Log(LOG_DEBUG, sprintf("[AUTOTIMER] already done \"%s\"", $DoneStr)); next; } } if (%blacklist) { # Wollen wir nicht haben. my $BLStr = $event->[EV_TITLE]; $BLStr .= "~" . $event->[EV_SUBTITLE] if $event->[EV_SUBTITLE]; if ($blacklist{$BLStr} || $blacklist{ $event->[EV_TITLE] }) { Log(LOG_DEBUG, sprintf("[AUTOTIMER] blacklisted \"%s\"", $event->[EV_TITLE])); next; } } for my $at (@at) { next if (!$at->{active} && !$dry_run); next if (($at->{channel}) && ($at->{channel} != $event->[EV_VDR_ID])); #print("AT: " . $at->{channel} . " - " . $at->{pattern} . " --- " . $event->[EV_VDR_ID] . " - " . $event->[EV_TITLE] . "\n"); my $SearchStr; if ($at->{section} & 1) { $SearchStr = $event->[EV_TITLE]; } if (($at->{section} & 2) && defined($event->[EV_SUBTITLE])) { $SearchStr .= "~" . $event->[EV_SUBTITLE]; } if ($at->{section} & 4) { $SearchStr .= "~" . $event->[EV_SUMMARY]; } # Regular Expressions are surrounded by slashes -- everything else # are search patterns if ($at->{pattern} =~ /^\/(.*)\/(i?)$/) { # We have a RegExp Log(LOG_DEBUG, sprintf("[AUTOTIMER] Checking RegExp \"%s\"", $at->{pattern})); if ((!length($SearchStr)) || (!length($1))) { Log(LOG_DEBUG, "[AUTOTIMER] No search string or RegExp, skipping!"); next; } next if (!defined($1)); # Shall we search case insensitive? if (($2 eq "i") && ($SearchStr !~ /$1/i)) { next; } elsif (($2 ne "i") && ($SearchStr !~ /$1/)) { next; } else { Log(LOG_DEBUG, sprintf("[AUTOTIMER] RegExp \"%s\" matches \"%s\"", $at->{pattern}, $SearchStr)); } } else { # We have a search pattern Log(LOG_DEBUG, sprintf("[AUTOTIMER] Checking pattern \"%s\"", $at->{pattern})); # Escape special characters within the search pattern my $atpattern = $at->{pattern}; $atpattern =~ s/([\+\?\.\*\^\$\(\)\[\]\{\}\|\\])/\\$1/g; Log(LOG_DEBUG, sprintf("[AUTOTIMER] Escaped pattern: \"%s\"", $atpattern)); if ((!length($SearchStr)) || (!length($atpattern))) { Log(LOG_DEBUG, "[AUTOTIMER] No search string or pattern, skipping!"); next; } # split search pattern at spaces into single sub-patterns, and # test for all of them (logical "and") my $fp = 1; for my $pattern (split(/ +/, $atpattern)) { # search for each sub-pattern, case insensitive if ($SearchStr !~ /$pattern/i) { $fp = 0; } else { Log(LOG_DEBUG, sprintf("[AUTOTIMER] Found matching pattern: \"%s\"", $pattern)); } } next if (!$fp); } my $event_start = my_strftime("%H%M", $event->[EV_START]); my $event_stop = my_strftime("%H%M", $event->[EV_STOP]); Log(LOG_DEBUG, sprintf("[AUTOTIMER] Comparing pattern \"%s\" (%s - %s) with event \"%s\" (%s - %s)", $at->{pattern}, $at->{start}, $at->{stop}, $event->[EV_TITLE], $event_start, $event_stop)); # Do we have a time slot? if ($at->{start}) { # We have a start time and possibly a stop time for the auto timer # Do we have midnight between AT start and stop time? if (($at->{stop}) && ($at->{stop} < $at->{start})) { # The AT includes midnight Log(LOG_DEBUG, "[AUTOTIMER] AT includes midnight"); # Do we have midnight between event start and stop? if ($event_stop < $event_start) { # The event includes midnight Log(LOG_DEBUG, "[AUTOTIMER] Event includes midnight"); if ($event_start < $at->{start}) { Log(LOG_DEBUG, "[AUTOTIMER] Event starts before AT start"); next; } if ($event_stop > $at->{stop}) { Log(LOG_DEBUG, "[AUTOTIMER] Event ends after AT stop"); next; } } else { # Normal event not spreading over midnight Log(LOG_DEBUG, "[AUTOTIMER] Event does not include midnight"); if ($event_start < $at->{start}) { if ($event_start > $at->{stop}) { # The event starts before AT start and after AT stop Log(LOG_DEBUG, "[AUTOTIMER] Event starts before AT start and after AT stop"); next; } if ($event_stop > $at->{stop}) { # The event ends after AT stop Log(LOG_DEBUG, "[AUTOTIMER] Event ends after AT stop"); next; } } } } else { # Normal auto timer, not spreading over midnight Log(LOG_DEBUG, "[AUTOTIMER] AT does not include midnight"); # Is the event spreading over midnight? if ($event_stop < $event_start) { # Event spreads midnight if ($at->{stop}) { # We have a AT stop time defined before midnight -- no match Log(LOG_DEBUG, "[AUTOTIMER] Event includes midnight, AT not"); next; } } else { # We have a normal event, nothing special # Event must not start before AT start if ($event_start < $at->{start}) { Log(LOG_DEBUG, "[AUTOTIMER] Event starts before AT start"); next; } # Event must not end after AT stop if (($at->{stop}) && ($event_stop > $at->{stop})) { Log(LOG_DEBUG, "[AUTOTIMER] Event ends after AT stop"); next; } } } } else { # We have no AT start time if ($at->{stop}) { if ($event_stop > $at->{stop}) { Log(LOG_DEBUG, "[AUTOTIMER] Only AT stop time, event stops after AT stop"); next; } } } # Check if we should schedule any timers on this weekday my %weekdays_map = (1 => 'wday_mon', 2 => 'wday_tue', 3 => 'wday_wed', 4 => 'wday_thu', 5 => 'wday_fri', 6 => 'wday_sat', 7 => 'wday_sun'); unless ($at->{weekdays}->{ $weekdays_map{ my_strftime("%u", $event->[EV_START]) } }) { Log(LOG_DEBUG, "[AUTOTIMER] Event not valid for this weekday"); next; } Log(LOG_DEBUG, sprintf("[AUTOTIMER] Found \"%s\"", $at->{pattern})); ######################################################################################### # 20050130: patch by macfly: parse extended EPG information provided by tvm2vdr.pl ######################################################################################### my $title; my $directory = $at->{directory}; my %at_details; if ($directory) { $directory =~ s#/#~#g; } if ($directory && $directory =~ /\%.*\%/) { $title = $directory; $at_details{'title'} = $event->[EV_TITLE]; $at_details{'subtitle'} = $event->[EV_SUBTITLE] ? $event->[EV_SUBTITLE] : my_strftime("%Y-%m-%d", $event->[EV_START]); $at_details{'date'} = my_strftime("%Y-%m-%d", $event->[EV_START]); $at_details{'regie'} = $1 if $event->[EV_SUMMARY] =~ m/\|Director: (.*?)\|/; $at_details{'category'} = $1 if $event->[EV_SUMMARY] =~ m/\|Category: (.*?)\|/; $at_details{'genre'} = $1 if $event->[EV_SUMMARY] =~ m/\|Genre: (.*?)\|/; $at_details{'year'} = $1 if $event->[EV_SUMMARY] =~ m/\|Year: (.*?)\|/; $at_details{'country'} = $1 if $event->[EV_SUMMARY] =~ m/\|Country: (.*?)\|/; $at_details{'originaltitle'} = $1 if $event->[EV_SUMMARY] =~ m/\|Originaltitle: (.*?)\|/; $at_details{'fsk'} = $1 if $event->[EV_SUMMARY] =~ m/\|FSK: (.*?)\|/; $at_details{'episode'} = $1 if $event->[EV_SUMMARY] =~ m/\|Episode: (.*?)\|/; $at_details{'rating'} = $1 if $event->[EV_SUMMARY] =~ m/\|Rating: (.*?)\|/; $title =~ s/%([\w_-]+)%/$at_details{lc($1)}/sieg; #$title .= "~" . $event->[EV_TITLE]; } else { $title = $event->[EV_TITLE]; if ($directory) { $title = $directory . "~" . $title; } if ($at->{episode}) { if ($event->[EV_SUBTITLE]) { $title .= "~" . $event->[EV_SUBTITLE]; } else { $title .= "~" . my_strftime("%Y-%m-%d", $event->[EV_START]); } } } # gemaess vdr.5 alle : durch | ersetzen. $title =~ s#:#|#g; # sind irgendwelche Tags verwendet worden, die leer waren und die doppelte Verzeichnisse erzeugten? $title =~ s#~+#~#g; $title =~ s#^~##; ######################################################################################### # 20050130: patch by macfly: parse extended EPG information provided by tvm2vdr.pl ######################################################################################### if ($dry_run) { #printf("AT found: (%s) (%s) (%s) (%s) (%s) (%s)\n", $event->[EV_TITLE], $title, $event->[EV_SUBTITLE], $directory, $event->[EV_START], $event->[EV_STOP]); push(@at_matches, { otitle => $event->[EV_TITLE], title => $title, subtitle => $event->[EV_SUBTITLE] ? $event->[EV_SUBTITLE] : "", directory => $directory, start => my_strftime("%H:%M", $event->[EV_START]), stop => my_strftime("%H:%M", $event->[EV_STOP]), date => my_strftime("%A, %x", $event->[EV_START]), channel => GetChannelDescByNumber($event->[EV_VDR_ID]) }); } else { Log(LOG_INFO, sprintf("[AUTOTIMER] Programming Timer \"%s\" (Event-ID %s, %s - %s)", $title, $event->[EV_EVENT_ID], strftime("%Y%m%d-%H%M", localtime($event->[EV_START])), strftime("%Y%m%d-%H%M", localtime($event->[EV_STOP])))); AT_ProgTimer(1, $event->[EV_EVENT_ID], $event->[EV_VDR_ID], $event->[EV_START], $event->[EV_STOP], $title, $event->[EV_SUMMARY], $at); if ($at->{active} == 2) { Log(LOG_INFO, "[AUTOTIMER] Disabling one-shot Timer"); $at->{active} = 0; $oneshots = 1; } $DONE->{$DoneStr} = $event->[EV_STOP] if ($at->{done}); } } } } if ($oneshots) { Log(LOG_DEBUG, "[AUTOTIMER] Saving because of one-shots triggered"); AT_Write(@at); } unless ($dry_run) { Log(LOG_DEBUG, "[AUTOTIMER] Purging done list... (lowtime $low_time)"); for (keys %$DONE) { delete $DONE->{$_} if ($low_time > $DONE->{$_}) } Log(LOG_DEBUG, "[AUTOTIMER] Save done list..."); &DONE_Write($DONE) if ($DONE); } Log(LOG_INFO, "[AUTOTIMER] Done."); if ($dry_run) { return @at_matches; } } sub AT_ProgTimer { my ($active, $event_id, $channel, $start, $stop, $title, $summary, $at) = @_; $start -= (($at->{buffers} ? ($at->{bstart} eq "" ? $CONFIG{AT_MARGIN_BEGIN} : $at->{bstart}) : $CONFIG{TM_MARGIN_BEGIN}) * 60); $stop += (($at->{buffers} ? ($at->{bstop} eq "" ? $CONFIG{AT_MARGIN_END} : $at->{bstop}) : $CONFIG{TM_MARGIN_END}) * 60); my $start_fmt = my_strftime("%H%M", $start); my $found = 0; for (ParseTimer(1)) { if ($_->{vdr_id} == $channel) { if ($_->{autotimer} == $AT_BY_EVENT_ID && $event_id && $_->{event_id}) { if ($_->{event_id} == $event_id) { $found = 1; last; } } # event_ids didn't match, try matching using starting time if ($_->{start} eq $start) { $found = 1; last; } if ($start_fmt eq my_strftime("%H%M", $_->{start})) { if ($FEATURES{VDRVERSION} < 10323) { if ($_->{dor} == my_strftime("%d", $start)) { $found = 1; last; } } else { if ($_->{dor} eq my_strftime("%Y-%m-%d", $start)) { $found = 1; last; } } } } } # we will only programm new timers, CheckTimers is responsible for # updating existing timers if (!$found) { $title =~ s/\|/\:/g; my $autotimer = $AT_BY_EVENT_ID; unless (can_do_eventid_autotimer($channel)) { $event_id = 0; $autotimer = $AT_BY_TIME; } Log(LOG_DEBUG, sprintf("[AUTOTIMER] AT_ProgTimer: Programming Timer \"%s\" (Event-ID %s, %s - %s)", $title, $event_id, strftime("%Y%m%d-%H%M", localtime($start)), strftime("%Y%m%d-%H%M", localtime($stop)))); ProgTimer(0, $active, $event_id, $channel, $start, $stop, $at->{prio} ne "" ? $at->{prio} : $CONFIG{AT_PRIORITY}, $at->{lft} ne "" ? $at->{lft} : $CONFIG{AT_LIFETIME}, $title, append_timer_metadata($FEATURES{VDRVERSION} < 10344 ? $summary : undef, $event_id, $autotimer, $at->{buffers} ? ($at->{bstart} eq "" ? $CONFIG{AT_MARGIN_BEGIN} : $at->{bstart}) : $CONFIG{TM_MARGIN_BEGIN}, $at->{buffers} ? ($at->{bstop} eq "" ? $CONFIG{AT_MARGIN_END} : $at->{bstop}) : $CONFIG{TM_MARGIN_END}, $at->{pattern}, $TOOL_AUTOTIMER ) ); if ($CONFIG{AT_SENDMAIL} == 1 && $can_use_net_smtp && ($CONFIG{MAIL_AUTH_USER} eq "" || $can_use_smtpauth)) { my $sum = $summary; # remove all HTML-Tags from text $sum =~ s/\<[^\>]+\>/ /g; # linefeeds $sum =~ s/\|/\n/g; my $dat = strftime("%A, %x", localtime($start)); my $strt = strftime("%H:%M", localtime($start)); my $end = strftime("%H:%M", localtime($stop)); eval { local $SIG{__DIE__}; my $smtp = Net::SMTP->new($CONFIG{MAIL_SERVER}, Timeout => 30); if ($smtp) { if ($CONFIG{MAIL_AUTH_USER} ne "") { $smtp->auth($CONFIG{MAIL_AUTH_USER}, $CONFIG{MAIL_AUTH_PASS}) || return; } $smtp->mail("$CONFIG{MAIL_FROM}"); $smtp->to($CONFIG{MAIL_TO}); $smtp->data(); $smtp->datasend("To: $CONFIG{MAIL_TO}\n"); my $qptitle = my_encode_qp($title); $smtp->datasend("Subject: AUTOTIMER: New timer created for $qptitle\n"); $smtp->datasend("From: VDRAdmin-AM AutoTimer <$CONFIG{MAIL_FROM}>\n"); $smtp->datasend("Auto-Submitted: auto-generated\n"); # RFC 3834 $smtp->datasend("MIME-Version: 1.0\n"); $smtp->datasend("Content-Type: text/plain; charset=iso-8859-1\n"); $smtp->datasend("Content-Transfer-Encoding: 8bit\n"); $smtp->datasend("\n"); $smtp->datasend("Created AUTOTIMER for $title\n"); $smtp->datasend("===========================================================================\n\n"); $smtp->datasend("Channel: $channel\n\n"); $smtp->datasend("$title\n"); $smtp->datasend("$dat, $strt - $end\n\n"); $smtp->datasend("Summary:\n"); $smtp->datasend("--------\n"); $smtp->datasend("$sum\n"); $smtp->dataend(); $smtp->quit(); } else { Log(LOG_FATALERROR, "[MAIL] SMTP failed! Please check your email settings."); } }; if ($@) { Log(LOG_FATALERROR, "[MAIL] Failed to send email! Please contact the author."); } } elsif ($CONFIG{AT_SENDMAIL} == 1) { if (!$can_use_net_smtp) { Log(LOG_FATALERROR, "[MAIL] Missing Perl module Net::SMTP. AutoTimer email notification disabled."); } if ($CONFIG{MAIL_AUTH_USER} ne "" && !$can_use_smtpauth) { Log(LOG_FATALERROR, "[MAIL] Missing Perl module Authen::SASL and/or Digest::HMAC_MD5. AutoTimer email notification disabled."); } } } } sub my_encode_qp { my $title = shift; if ($title =~ /[\001-\037\200-\377]/) { my $qptitle = $title; $qptitle = "=?iso-8859-1?b?" . MIME::Base64::encode_base64($title, "") . "?="; $qptitle =~ s#(=\?iso-8859-1\?b\?[^\?]{56})(?!\?=)#$1?=\n =?iso-8859-1?b?#g while ($qptitle =~ /=\?iso-8859-1\?b\?[^\?]{57,}\?=/); return $qptitle; } return $title; } sub PackStatus { #TODO: unused # make a 32 bit signed int with high 16 Bit as event_id and low 16 Bit as # active value my ($active, $event_id) = @_; # we must generate a 32 bit signed int, due perl knows no overflow at 32 bit, # we have to do the overflow manually: # is the 16th bit set? then the signed 32 bit int is negative! if ($event_id & 0x8000) { # strip the first bit (by & 0x7FFF) of the event_id, so a 15 bit # (positive) int will remain, then shift the int 16 bits to the left and # add active -- result is a 31 bit (always positive) int. # The 32nd bit is the minus sign, and due the (binary) smallest value # is the (int) lowest possible number, we have to subtract the lowest # value + 1 from the 31 bit value -- result is the signed 32 bit int equal # to the (unsigned) 32 bit int. return ($active | (($event_id & 0x7FFF) << 16)) - 0x80000000; } else { return $active | ($event_id << 16); } } sub UnpackActive { #TODO: unused my ($tmstatus) = @_; # strip the first 16 bit return ($tmstatus & 0xFFFF); } sub UnpackEvent_id { #TODO: unused my ($tmstatus) = @_; # remove the lower 16 bit by shifting the value 16 bits to the right return $tmstatus >> 16; } sub CheckTimers { return if (!$CONFIG{AT_FUNC} || !$FEATURES{AUTOTIMER}); my $event; for my $timer (ParseTimer(1)) { next unless $timer->{autotimer}; # match by event_id if ($timer->{autotimer} == $AT_BY_EVENT_ID) { for $event (@{ $EPG{ $timer->{vdr_id} } }) { # look for matching event_id on the same channel -- it's unique if ($timer->{event_id} == $event->[EV_EVENT_ID]) { Log(LOG_DEBUG, sprintf("[AUTOTIMER] CheckTimers: Checking timer \"%s\" (No. %s) for changes by Event-ID", $timer->{title}, $timer->{id})); # update timer if the existing one differs from the EPG # (don't check for changed title, as this will break autotimers' "directory" setting) if ( ($timer->{start} != ($event->[EV_START] - $timer->{bstart} * 60)) || ($timer->{stop} != ($event->[EV_STOP] + $timer->{bstop} * 60))) { Log(LOG_INFO, sprintf("[AUTOTIMER] CheckTimers: Timer \"%s\" (No. %s, Event-ID %s, %s - %s) differs from EPG: \"%s\", Event-ID %s, %s - %s)", $timer->{title}, $timer->{id}, $timer->{event_id}, strftime("%Y%m%d-%H%M", localtime($timer->{start})), strftime("%Y%m%d-%H%M", localtime($timer->{stop})), $event->[EV_TITLE], $event->[EV_EVENT_ID], strftime("%Y%m%d-%H%M", localtime($event->[EV_START])), strftime("%Y%m%d-%H%M", localtime($event->[EV_STOP])))); ProgTimer( $timer->{id}, $timer->{active}, $timer->{event_id}, $timer->{vdr_id}, $event->[EV_START] - $timer->{bstart} * 60, $event->[EV_STOP] + $timer->{bstop} * 60, $timer->{prio}, $timer->{lft}, # don't update title as this may differ from what has been set by the user $timer->{title}, # leave summary untouched. $timer->{summary}, ); } } } } # match by channel number and start/stop time elsif ($timer->{autotimer} == $AT_BY_TIME) { # We're checking only timers which don't record if ($timer->{start} > time()) { Log(LOG_DEBUG, sprintf("[AUTOTIMER] CheckTimers: Checking timer \"%s\" (No. %s) for changes by recording time", $timer->{title}, $timer->{id})); my @eventlist; for my $event (@{ $EPG{ $timer->{vdr_id} } }) { # look for events within the margins of the current timer if (($event->[EV_START] < $timer->{stop}) && ($event->[EV_STOP] > $timer->{start})) { push @eventlist, $event; } } # now we have all events in eventlist that touch the old timer margins # check for each event how probable it is matching the old timer if (scalar(@eventlist) > 0) { my $origlen = ($timer->{stop} - $timer->{bstop} * 60) - ($timer->{start} + $timer->{bstart} * 60); next unless($origlen); my $maxwight = 0; $event = $eventlist[0]; for (my $i = 0 ; $i < scalar(@eventlist) ; $i++) { my ($start, $stop); if ($eventlist[$i]->[EV_START] < $timer->{start}) { $start = $timer->{start}; } else { $start = $eventlist[$i]->[EV_START]; } if ($eventlist[$i]->[EV_STOP] > $timer->{stop}) { $stop = $timer->{stop}; } else { $stop = $eventlist[$i]->[EV_STOP]; } my $wight = ($stop - $start) / ($eventlist[$i]->[EV_STOP] - $eventlist[$i]->[EV_START]); if ($wight > $maxwight && (($eventlist[$i]->[EV_STOP] - $eventlist[$i]->[EV_START]) / $origlen) >= 0.9) { $maxwight = $wight; $event = $eventlist[$i]; } } # update timer if the existing one differs from the EPG if ( ($timer->{start} > ($event->[EV_START] - $timer->{bstart} * 60)) || ($timer->{stop} < ($event->[EV_STOP] + $timer->{bstop} * 60))) { Log(LOG_INFO, sprintf("[AUTOTIMER] CheckTimers: Timer \"%s\" (No. %s, Event-ID %s, %s - %s) differs from EPG: \"%s\", Event-ID %s, %s - %s)", $timer->{title}, $timer->{id}, $timer->{event_id}, strftime("%Y%m%d-%H%M", localtime($timer->{start})), strftime("%Y%m%d-%H%M", localtime($timer->{stop})), $event->[EV_TITLE], $event->[EV_EVENT_ID], strftime("%Y%m%d-%H%M", localtime($event->[EV_START])), strftime("%Y%m%d-%H%M", localtime($event->[EV_STOP])))); ProgTimer( $timer->{id}, $timer->{active}, 0, $timer->{vdr_id}, $timer->{start} > ($event->[EV_START] - $timer->{bstart} * 60) ? $event->[EV_START] - $timer->{bstart} * 60 : $timer->{start}, $timer->{stop} < ($event->[EV_STOP] + $timer->{bstop} * 60) ? $event->[EV_STOP] + $timer->{bstop} * 60 : $timer->{stop}, $timer->{prio}, $timer->{lft}, # don't touch the title since we're not too sure about the event $timer->{title}, # leave summary untouched. $timer->{summary}, ); } } } else { Log(LOG_DEBUG, sprintf("[AUTOTIMER] CheckTimers: Skipping Timer \"%s\" (No. %s, %s - %s)", $timer->{title}, $timer->{id}, strftime("%Y%m%d-%H%M", localtime($timer->{start})), strftime("%Y%m%d-%H%M", localtime($timer->{stop})))); } } } } ############################################################################# # epgsearch ############################################################################# sub epgsearch_list { return if (UptoDate() != 0); if ($FEATURES{EPGSEARCH_VERSION} < 924) { HTMLError("Your version of epgsearch plugin is too old! You need at least v0.9.23!"); return } $CONFIG{ES_DESC} = ($q->param("desc") ? 1 : 0) if (defined($q->param("desc"))); $CONFIG{ES_SORTBY} = $q->param("sortby") if (defined($q->param("sortby"))); $CONFIG{ES_SORTBY} = "pattern" if (!$CONFIG{ES_SORTBY}); my @matches; my $do_test = $q->param("execute"); if ($do_test) { my $id = $q->param("id"); unless (defined $id) { for ($q->param) { if (/xxxx_(.*)/) { $id .= "|" if (defined $id); $id .= $1; } } } if (defined $id) { @matches = EpgSearchQuery("plug epgsearch qrys $id"); } } else { $do_test = $q->param("favorites"); @matches = EpgSearchQuery("plug epgsearch qryf") if ($do_test); } my @templates = GetEpgSearchTemplates(); my @searches; for (ParseEpgSearch(undef)) { $_->{modurl} = $MyURL . "?aktion=epgsearch_edit&id=" . $_->{id}; $_->{delurl} = $MyURL . "?aktion=epgsearch_delete&id=" . $_->{id}; $_->{findurl} = $MyURL . "?aktion=epgsearch_aktion&execute=1&id=" . $_->{id}; $_->{toggleurl} = sprintf("%s?aktion=epgsearch_toggle&active=%s&id=%s", $MyURL, $_->{has_action}, $_->{id}); push(@searches, $_); } if ($CONFIG{ES_SORTBY} eq "active") { if ($CONFIG{ES_DESC}) { @searches = sort({ $b->{has_action} <=> $a->{has_action} } @searches); } else { @searches = sort({ $a->{has_action} <=> $b->{has_action} } @searches); } } elsif ($CONFIG{ES_SORTBY} eq "action") { if ($CONFIG{ES_DESC}) { @searches = sort({ lc($b->{action_text}) cmp lc($a->{action_text}) } @searches); } else { @searches = sort({ lc($a->{action_text}) cmp lc($b->{action_text}) } @searches); } } elsif ($CONFIG{ES_SORTBY} eq "pattern") { if ($CONFIG{ES_DESC}) { @searches = sort({ lc($b->{pattern}) cmp lc($a->{pattern}) } @searches); } else { @searches = sort({ lc($a->{pattern}) cmp lc($b->{pattern}) } @searches); } } my $toggle_desc = ($CONFIG{ES_DESC} ? 0 : 1); my $vars = { usercss => $UserCSS, url => $MyURL, sortbypatternurl => "$MyURL?aktion=epgsearch_list&sortby=pattern&desc=" . (($CONFIG{ES_SORTBY} eq "pattern") ? $toggle_desc : $CONFIG{ES_DESC}), sortbyactiveurl => "$MyURL?aktion=epgsearch_list&sortby=active&desc=" . (($CONFIG{ES_SORTBY} eq "active") ? $toggle_desc : $CONFIG{ES_DESC}), sortbyactionurl => "$MyURL?aktion=epgsearch_list&sortby=action&desc=" . (($CONFIG{ES_SORTBY} eq "action") ? $toggle_desc : $CONFIG{ES_DESC}), desc => $CONFIG{ES_DESC} ? "desc" : "asc", sortbypattern => ($CONFIG{ES_SORTBY} eq "pattern") ? 1 : 0, sortbyactive => ($CONFIG{ES_SORTBY} eq "active") ? 1 : 0, sortbyaction => ($CONFIG{ES_SORTBY} eq "action") ? 1 : 0, searches => \@searches, did_search => $do_test, title => $do_test ? ($q->param("favorites") ? gettext("Your favorites") : gettext("Search results")) : undef, matches => (@matches ? \@matches : undef), templates => \@templates, config_url => "$MyURL?aktion=epgsearch_config" }; return showTemplate("epgsearch_list.html", $vars); } sub epgsearch_edit { my $id = $q->param("id"); my $do_test = $q->param("single_test"); my $edit_template = $q->param("edit_template"); my $template_id; $template_id = $q->param("template") if (defined $q->param("template")); $do_test = 0 if ($edit_template); my $search; my @blacklists; my @ch_groups; my @matches; my @sel_bl; if ($do_test) { # test search my $temp = epgsearch_Param2Line(); $search = ExtractEpgSearchConf(($id ? $id : "0") . ":" . $temp); @sel_bl = $q->param("sel_blacklists"); @matches = EpgSearchQuery("plug epgsearch qrys 0:" . $temp); } elsif (defined $id) { # edit search my @temp = ParseEpgSearch($id); $search = pop @temp; @sel_bl = split(/\|/, $search->{sel_blacklists}); } else { # new search if (defined $template_id) { my @temp = GetEpgSearchTemplate($template_id); $search = pop @temp; $search->{pattern} = "" unless ($edit_template); # don't want the template's name as search pattern @sel_bl = split(/\|/, $search->{sel_blacklists}); } else { #TODO: defaults for PRIO, LFT, BUFFER START/STOP $search->{use_title} = 1; $search->{use_subtitle} = 1; $search->{use_descr} = 1; $search->{comp_title} = 1; $search->{comp_subtitle} = 1; $search->{comp_descr} = 1; } } if (@sel_bl) { for my $bl (ParseEpgSearchBlacklists(undef)) { for (@sel_bl) { if ($bl->{id} == $_) { $bl->{sel} = 1; last; } } push(@blacklists, $bl); } } else { @blacklists = ParseEpgSearchBlacklists(undef); } if ($search->{use_channel} == 2) { for my $cg (ParseEpgSearchChanGroups(undef)) { $cg->{sel} = 1 if ($cg->{id} eq $search->{channels}) ; push(@ch_groups, $cg); } } else { @ch_groups = ParseEpgSearchChanGroups(undef); } my @extepg = ParseEpgSearchExtEpgInfos($search->{extepg_infos}); if ($search->{comp_extepg_info}) { foreach (@extepg) { if ($search->{comp_extepg_info} & (1 << ($_->{id} - 1))) { $search->{"comp_extepg_" . $_->{id}} = 1; } } } epgsearch_getSettings(); my $vars = { usercss => $UserCSS, url => $MyURL, epgsearch => $search, channels => \@{$CHAN{$CHAN_FULL}->{channels}}, blacklists => \@blacklists, ch_groups => \@ch_groups, did_search => $do_test, matches => (@matches ? \@matches : undef), do_edit => (defined $edit_template ? undef : (defined $id ? "1" : undef)), mode_template => (defined $edit_template ? "1" : undef), template_id => $template_id, extepg => \@extepg, epgs_settings => \%EPGSEARCH_SETTINGS }; return showTemplate("epgsearch_new.html", $vars); } sub ParseEpgSearch { my $id = shift; my @temp; for (SendCMD("plug epgsearch lsts $id")) { chomp; next if (length($_) == 0); last if (/^no searches defined$/); push(@temp, ExtractEpgSearchConf($_)); } return @temp; } sub ParseEpgSearchBlacklists { my $id = shift; my @temp; for (SendCMD("plug epgsearch lstb $id")) { chomp; next if (length($_) == 0); last if (/^no blacklists defined$/); push(@temp, ExtractEpgSearchBlacklistConf($_)); } return @temp; } sub GetEpgSearchTemplates { my $def_template = 0; for (SendCMD("plug epgsearch deft")) { chomp; next if (length($_) == 0); last if (/^Command unrecognized/); $def_template = $_; } my @temp; for (SendCMD("plug epgsearch lstt")) { chomp; next if (length($_) == 0); last if (/^no search templates defined$|^Command unrecognized/); my $template = ExtractEpgSearchConf($_); if ($template->{id} == $def_template) { $template->{pattern} .= " (" . gettext("Default") . ")"; $template->{sel} = 1; } push(@temp, $template); } return @temp; } sub GetEpgSearchTemplate { my $id = shift; my @temp; for (SendCMD("plug epgsearch lstt $id")) { chomp; next if (length($_) == 0); last if (/^search template id .* not defined$|^Command unrecognized/); push(@temp, ExtractEpgSearchConf($_)); } return @temp; } sub ParseEpgSearchChanGroups { my $id = shift; my @temp; for (SendCMD("plug epgsearch lstc $id")) { chomp; next if (length($_) == 0); last if (/^no channel groups defined$/); my ($name, $channels) = split(/\|/, $_, 2); push(@temp, { id => $name, name => $name, channels => $channels } ); } return @temp; } sub ParseEpgSearchExtEpgInfos { my @temp = split(/\|/, shift); my %sel; foreach (@temp) { my ($id, $val) = split(/#/); $val =~ s/\!\^colon\^\!/\:/g; $val =~ s/\!\^pipe\^\!/\|/g; $sel{$id} = $val; } my @return; for (SendCMD("plug epgsearch lste")) { chomp; next if (length($_) == 0); last if (/^no EPG categories defined$/); my ($id, $name, $title, $values, $searchmode) = split(/\|/, $_, 5); my @val; my $selected; foreach (split(/, /, $values)) { my $value = $_; my @res = grep(/^$value$/, split(/, /, $sel{$id})); $selected = 1 if (@res); push(@val, { name => $value, sel => (@res) ? 1 : undef } ); } push(@return, { id => $id, name => $name, title => $title, data => \@val, searchmode => $searchmode, data_text => $selected ? undef : $sel{$id} } ); } return @return; } sub EpgSearchQuery { my $cmd = shift; my $ref = shift; return unless($cmd); #print("EpgSearchQuery: $cmd\n"); my @result; for (SendCMD($cmd)) { chomp; next if (length($_) == 0); last if(/^no results$/); # Suchtimer-ID : Event-ID : Title : Subtitle : Event-Begin : Event-Ende : # Kanalnummer : Timer-Start : Timer-Ende : Timer-File : hat/bekommt Timer my ($es_id, $event_id, $title, $subtitle, $estart, $estop, $chan, $tstart, $tstop, $tdir, $has_timer) = split(/:/); if ($title) { $title =~ s/\|/:/g; $title =~ s/\!\^pipe\^\!/\|/g; } if ($subtitle) { $subtitle =~ s/\|/:/g; $subtitle =~ s/\!\^pipe\^\!/\|/g; } if ($tdir) { $tdir =~ s/\|/:/g; $tdir =~ s/\!\^pipe\^\!/\|/g; } push(@result, { title => $title, subtitle => $subtitle, date => my_strftime("%A, %x", $estart), start => my_strftime("%H:%M", $estart), stop => my_strftime("%H:%M", $estop), channel => get_name_from_uniqid($chan), folder => $has_timer == 1 ? $tdir : gettext("--- no timer ---"), recurl => $has_timer == 1 ? undef : sprintf("%s?aktion=timer_new_form&epg_id=%s&channel_id=%s&referer=%s", $MyURL, $event_id, $chan, Encode_Referer(getReferer())), infurl => $event_id ? sprintf("%s?aktion=prog_detail&epg_id=%s&channel_id=%s&referer=%s", $MyURL, $event_id, $chan, $ref) : undef, proglink => sprintf("%s?aktion=prog_list&channel_id=%s", $MyURL, $chan) } ); } return @result; } sub ExtractEpgSearchConf { my $line = shift; my $timer; ($timer->{id}, # 1 - unique search timer id $timer->{pattern}, # 2 - the search term $timer->{use_time}, # 3 - use time? 0/1 $timer->{time_start}, # 4 - start time in HHMM $timer->{time_stop}, # 5 - stop time in HHMM $timer->{use_channel}, # 6 - use channel? 0 = no, 1 = Intervall, 2 = Channel group, 3 = FTA only $timer->{channels}, # 7 - if 'use channel' = 1 then channel id[|channel id] in vdr format, # one entry or min/max entry separated with |, if 'use channel' = 2 # then the channel group name $timer->{matchcase}, # 8 - match case? 0/1 $timer->{mode}, # 9 - search mode: # 0 - the whole term must appear as substring # 1 - all single terms (delimiters are blank,',', ';', '|' or '~') # must exist as substrings. # 2 - at least one term (delimiters are blank, ',', ';', '|' or '~') # must exist as substring. # 3 - matches exactly # 4 - regular expression $timer->{use_title}, #10 - use title? 0/1 $timer->{use_subtitle}, #11 - use subtitle? 0/1 $timer->{use_descr}, #12 - use description? 0/1 $timer->{use_duration}, #13 - use duration? 0/1 $timer->{min_duration}, #14 - min duration in minutes $timer->{max_duration}, #15 - max duration in minutes $timer->{has_action}, #16 - use as search timer? 0/1 $timer->{use_days}, #17 - use day of week? 0/1 $timer->{which_days}, #18 - day of week (0 = sunday, 1 = monday...) $timer->{is_series}, #19 - use series recording? 0/1 $timer->{directory}, #20 - directory for recording $timer->{prio}, #21 - priority of recording $timer->{lft}, #22 - lifetime of recording $timer->{bstart}, #23 - time margin for start in minutes $timer->{bstop}, #24 - time margin for stop in minutes $timer->{use_vps}, #25 - use VPS? 0/1 $timer->{action}, #26 - action: # 0 = create a timer # 1 = announce only via OSD (no timer) # 2 = switch only (no timer) $timer->{use_extepg}, #27 - use extended EPG info? 0/1 #TODO $timer->{extepg_infos}, #28 - extended EPG info values. This entry has the following format #TODO # (delimiter is '|' for each category, '#' separates id and value): # 1 - the id of the extended EPG info category as specified in # epgsearchcats.conf # 2 - the value of the extended EPG info category # (a ':' will be tranlated to "!^colon^!", e.g. in "16:9") $timer->{avoid_repeats}, #29 - avoid repeats? 0/1 $timer->{allowed_repeats}, #30 - allowed repeats $timer->{comp_title}, #31 - compare title when testing for a repeat? 0/1 $timer->{comp_subtitle}, #32 - compare subtitle when testing for a repeat? 0/1 $timer->{comp_descr}, #33 - compare description when testing for a repeat? 0/1 $timer->{comp_extepg_info}, #34 - compare extended EPG info when testing for a repeat? #TODO # This entry is a bit field of the category ids. $timer->{repeats_in_days}, #35 - accepts repeats only within x days $timer->{delete_after}, #36 - delete a recording automatically after x days $timer->{keep_recordings}, #37 - but keep this number of recordings anyway $timer->{switch_before}, #38 - minutes before switch (if action = 2) $timer->{pause}, #39 - pause if x recordings already exist $timer->{use_blacklists}, #40 - blacklist usage mode (0 none, 1 selection, 2 all) $timer->{sel_blacklists}, #41 - selected blacklist IDs separated with '|' $timer->{fuzzy_tolerance}, #42 - fuzzy tolerance value for fuzzy searching $timer->{use_for_fav}, #43 - use this search in favorites menu (0 no, 1 yes) $timer->{results_menu}, #44 - menu to display results $timer->{autodelete}, #45 - delMode ( 0 = no autodelete, 1 = after x recordings, 2 = after y days after 1. recording) $timer->{del_after_recs}, #46 - delAfterCountRecs (x recordings) $timer->{del_after_days}, #47 - delAfterDaysOfFirstRec (y days) $timer->{searchtimer_from}, #48 - useAsSearchTimerFrom (if "use as search timer?" = 2) $timer->{searchtimer_until}, #49 - useAsSearchTimerTil (if "use as search timer?" = 2) $timer->{ignore_missing_epgcats}, #50 - ignoreMissingEPGCats $timer->{unmute}, #51 - unmute sound if off when used as switch timer $timer->{min_match}, #52 - the minimum required match in percent when descriptions are compared to avoid repeats (-> 33) $timer->{unused}) = split(/:/, $line); #format selected fields $timer->{time_start} =~ s/(\d\d)(\d\d)/$1:$2/ if($timer->{time_start}); $timer->{time_stop} =~ s/(\d\d)(\d\d)/$1:$2/ if($timer->{time_stop}); $timer->{min_duration} =~ s/(\d\d)(\d\d)/$1:$2/ if($timer->{min_duration}); $timer->{max_duration} =~ s/(\d\d)(\d\d)/$1:$2/ if($timer->{max_duration}); if ($timer->{has_action}) { if ($timer->{action} == 0) { $timer->{action_text} = gettext("record"); } elsif ($timer->{action} == 1) { $timer->{action_text} = gettext("announce by OSD"); } elsif ($timer->{action} == 2) { $timer->{action_text} = gettext("switch only"); } elsif ($timer->{action} == 3) { $timer->{action_text} = gettext("announce and switch"); } elsif ($timer->{action} == 4) { $timer->{action_text} = gettext("announce by mail"); } else { $timer->{action_text} = gettext("unknown"); } } else { $timer->{action_text} = gettext("none"); } if ($timer->{channels} && $timer->{use_channel} == 1) { ($timer->{channel_from}, $timer->{channel_to}) = split(/\|/, $timer->{channels}, 2); $timer->{channel_to} = $timer->{channel_from} unless ($timer->{channel_to}); $timer->{channel_from_name} = get_name_from_uniqid($timer->{channel_from}); $timer->{channel_to_name} = get_name_from_uniqid($timer->{channel_to}); #TODO: links to channels } if ($timer->{use_days}) { if ($timer->{which_days} >= 0) { $timer->{sunday} = 1 if ($timer->{which_days} == 0); $timer->{monday} = 1 if ($timer->{which_days} == 1); $timer->{tuesday} = 1 if ($timer->{which_days} == 2); $timer->{wednesday} = 1 if ($timer->{which_days} == 3); $timer->{thursday} = 1 if ($timer->{which_days} == 4); $timer->{friday} = 1 if ($timer->{which_days} == 5); $timer->{saturday} = 1 if ($timer->{which_days} == 6); } else { my $which_days = -$timer->{which_days}; $timer->{sunday} = 1 if ($which_days & 1); $timer->{monday} = 1 if ($which_days & 2); $timer->{tuesday} = 1 if ($which_days & 4); $timer->{wednesday} = 1 if ($which_days & 8); $timer->{thursday} = 1 if ($which_days & 16); $timer->{friday} = 1 if ($which_days & 32); $timer->{saturday} = 1 if ($which_days & 64); } } if ($timer->{pattern}) { $timer->{pattern} =~ s/\|/:/g; $timer->{pattern} =~ s/\!\^pipe\^\!/\|/g; } if ($timer->{directory}) { $timer->{directory} =~ s/\|/:/g; $timer->{directory} =~ s/\!\^pipe\^\!/\|/g; } if ($timer->{searchtimer_from}) { $timer->{searchtimer_from} = my_strftime("%Y-%m-%d", $timer->{searchtimer_from}); } if ($timer->{searchtimer_until}) { $timer->{searchtimer_until} = my_strftime("%Y-%m-%d", $timer->{searchtimer_until}); } return $timer; } sub validTime { my $t = shift; return unless ($t); my ($h, $m) = split(/:/, $t); $h = "0" . $h if (length($h) == 1); if (length($h) > 2) { #TODO: $m defined? $m = substr($h, -2); $h = substr($h, 0, -2); } return sprintf("%02d%02d", $h, $m); } sub epgsearch_Param2Line { my $mode_blacklist = $q->param("mode_blacklist"); my $weekdays_bits = 0; my $weekdays = 0; my $had_weekday = 0; if ($q->param("use_days")) { if ($q->param("sunday")) { $had_weekday++; $weekdays_bits |= 1; $weekdays = 0; } if ($q->param("monday")) { $had_weekday++; $weekdays_bits |= 2; $weekdays = 1; } if ($q->param("tuesday")) { $had_weekday++; $weekdays_bits |= 4; $weekdays = 2; } if ($q->param("wednesday")) { $had_weekday++; $weekdays_bits |= 8; $weekdays = 3; } if ($q->param("thursday")) { $had_weekday++; $weekdays_bits |= 16; $weekdays = 4; } if ($q->param("friday")) { $had_weekday++; $weekdays_bits |= 32; $weekdays = 5; } if ($q->param("saturday")) { $had_weekday++; $weekdays_bits |= 64; $weekdays = 6; } $weekdays_bits = - $weekdays_bits; } my $time_start = validTime($q->param("time_start")); my $time_stop = validTime($q->param("time_stop")); my $min_duration = validTime($q->param("min_duration")); my $max_duration = validTime($q->param("max_duration")); my $use_channel = $q->param("use_channel"); my $channels; if ($use_channel == 1) { $channels = $q->param("channel_from") . "|" . $q->param("channel_to"); } elsif ($use_channel == 2) { $channels = $q->param("channel_group"); } my $sel_blacklists; for ($q->param("sel_blacklists")) { $sel_blacklists .= "|" if (defined($sel_blacklists)); $sel_blacklists .= $_; } my $pattern = $q->param("pattern"); if ($pattern) { $pattern =~ s/\|/\!\^pipe\^\!/g; $pattern =~ s/:/\|/g; } my $directory = $q->param("directory"); if ($directory) { $directory =~ s/\|/\!\^pipe\^\!/g; $directory =~ s/:/\|/g; } #TODO: $searchtimer_from & $searchtimer_until auf korrektes Format prüfen my $searchtimer_from = $q->param("searchtimer_from"); if ($searchtimer_from) { $searchtimer_from = my_mktime("0", "0", substr($searchtimer_from, 8, 2), substr($searchtimer_from, 5, 2) - 1, substr($searchtimer_from, 0, 4)); } my $searchtimer_until = $q->param("searchtimer_until"); if ($searchtimer_until) { $searchtimer_until = my_mktime("0", "0", substr($searchtimer_until, 8, 2), substr($searchtimer_until, 5, 2) - 1, substr($searchtimer_until, 0, 4)); } my $extepg_info; for ($q->param) { if (/extepg_([0-9]+)_data_text/) { my $e_id = $1; $extepg_info .= "|" if ($extepg_info); my $data = join(", ", $q->param("extepg_" . $e_id . "_data")); $data =~ s/:/\!\^colon\^\!/g; $data =~ s/\|/\!\^pipe\^\!/g; $extepg_info .= sprintf("%s#%s", $e_id, $data); my $data_text = $q->param("extepg_" . $e_id . "_data_text"); if ($data_text) { $extepg_info .= ", " if ($data); $data_text =~ s/:/\!\^colon\^\!/g; $data_text =~ s/\|/\!\^pipe\^\!/g; $extepg_info .= $data_text; } } } my $cmd = $pattern . ":" . ($q->param("use_time") ? "1" : "0") . ":" . $time_start . ":" . $time_stop . ":" . $use_channel . ":" . $channels . ":" . ($q->param("matchcase") ? "1" : "0") . ":" . $q->param("mode") . ":" . ($q->param("use_title") ? "1" : "0") . ":" . ($q->param("use_subtitle") ? "1" : "0") . ":" . ($q->param("use_descr") ? "1" : "0") . ":" . ($q->param("use_duration") ? "1" : "0") . ":" . $min_duration . ":" . $max_duration . ":"; if ($mode_blacklist) { $cmd .= ($q->param("use_days") ? "1" : "0") . ":" . ($had_weekday > 1 ? $weekdays_bits : $weekdays) . ":" . ($q->param("use_extepg") ? "1" : "0") . ":" . $extepg_info . ":" . $q->param("fuzzy_tolerance") . ":" . $q->param("ignore_missing_epgcats"); } else { # ! $mode_blacklist $cmd .= $q->param("has_action") . ":" . ($q->param("use_days") ? "1" : "0") . ":" . ($had_weekday > 1 ? $weekdays_bits : $weekdays) . ":" . ($q->param("is_series") ? "1" : "0") . ":" . $directory . ":" . $q->param("prio") . ":" . $q->param("lft") . ":" . $q->param("bstart") . ":" . $q->param("bstop") . ":" . ($q->param("use_vps") ? "1" : "0") . ":" . $q->param("action") . ":" . ($q->param("use_extepg") ? "1" : "0") . ":" . $extepg_info . ":" . ($q->param("avoid_repeats") ? "1" : "0") . ":" . $q->param("allowed_repeats") . ":" . ($q->param("comp_title") ? "1" : "0") . ":" . ($q->param("comp_subtitle") ? "1" : "0") . ":" . ($q->param("comp_descr") ? "1" : "0") . ":" . ($q->param("comp_extepg_info") ? "1" : "0") . ":" #TODO . $q->param("repeats_in_days") . ":" . $q->param("delete_after") . ":" . $q->param("keep_recordings") . ":" . $q->param("switch_before") . ":" . $q->param("pause") . ":" . $q->param("use_blacklists") . ":" . $sel_blacklists . ":" . $q->param("fuzzy_tolerance") . ":" . ($q->param("use_for_fav") ? "1" : "0") . ":" . $q->param("results_menu") . ":" . $q->param("autodelete") . ":" . $q->param("del_after_recs") . ":" . $q->param("del_after_days") . ":" . $searchtimer_from . ":" . $searchtimer_until . ":" . ($q->param("ignore_missing_epgcats") ? "1" : "0"); if ($FEATURES{EPGSEARCH_VERSION} >= 925) { $cmd .= ":" . $q->param("unmute") . ":" . $q->param("min_match"); } } $cmd .= ":" . $q->param("unused") if ($q->param("unused")); #print("CMD: $cmd\n"); return $cmd; } sub epgsearch_save { my $cmd = (defined $q->param("id") ? "EDIS " . $q->param("id") : "NEWS 0") . ":" . epgsearch_Param2Line(); SendCMD("plug epgsearch " . $cmd); return (headerForward("$MyURL?aktion=epgsearch_list")); } sub epgsearch_save_template { my $cmd = (defined $q->param("template_id") ? "EDIT " . $q->param("template_id") : "NEWT 0") . ":" . epgsearch_Param2Line(); SendCMD("plug epgsearch " . $cmd); return (headerForward("$MyURL?aktion=epgsearch_list")); } sub epgsearch_delete_template { SendCMD("plug epgsearch DELT " . $q->param("template_id")); return (headerForward("$MyURL?aktion=epgsearch_list")); } sub epgsearch_delete { my $id = $q->param("id"); if (defined $id) { SendCMD("plug epgsearch dels $id"); } else { for ($q->param) { SendCMD("plug epgsearch dels $1") if (/xxxx_(.*)/); } } return (headerForward("$MyURL?aktion=epgsearch_list")); } sub epgsearch_toggle { my $id = $q->param("id"); if (defined $id) { SendCMD(sprintf("plug epgsearch mods %s %s", $id, $q->param("active") ? "off" : "on")); } return (headerForward("$MyURL?aktion=epgsearch_list")); } sub epgsearch_getSettings { for (SendCMD("plug epgsearch setp")) { chomp; next if (length($_) == 0); $EPGSEARCH_SETTINGS{$1} = $2 if (/^([^:]*): (.*)/); } } sub epgsearch_upds { SendCMD("plug epgsearch upds osd"); return (headerForward("$MyURL?aktion=epgsearch_list")); } sub epgsearch_getDefTimerCheckMethode { my $id = shift; return 0 unless($id); for (SendCMD(sprintf("plug epgsearch setp deftimercheckmethod %s", $id))) { chomp; next if (length($_) == 0); last if(/^invalid channel id$/); last if(/^unknown channel$/); my ($channel_id, $value) = split(/\: /, $_); return $value; } return 0; } sub epgsearch_config { my @list; for (ParseEpgSearchBlacklists(undef)) { $_->{modurl} = $MyURL . "?aktion=epgsearch_bl_edit&id=" . $_->{id}; $_->{delurl} = $MyURL . "?aktion=epgsearch_bl_delete&id=" . $_->{id}; push(@list, $_); } my $vars = { usercss => $UserCSS, url => $MyURL, list => \@list }; return showTemplate("epgsearch_config.html", $vars); } sub epgsearch_bl_edit { my $id = $q->param("id"); my $blacklist; my @ch_groups; if (defined $id) { # edit blacklist my @temp = ParseEpgSearchBlacklists($id); $blacklist = pop @temp; } else { # new blacklist $blacklist->{use_title} = 1; $blacklist->{use_subtitle} = 1; $blacklist->{use_descr} = 1; } if ($blacklist->{use_channel} == 2) { for my $cg (ParseEpgSearchChanGroups(undef)) { $cg->{sel} = 1 if ($cg->{id} eq $blacklist->{channels}) ; push(@ch_groups, $cg); } } else { @ch_groups = ParseEpgSearchChanGroups(undef); } my @extepg = ParseEpgSearchExtEpgInfos($blacklist->{extepg_infos}); if ($blacklist->{comp_extepg_info}) { foreach (@extepg) { if ($blacklist->{comp_extepg_info} & (1 << ($_->{id} - 1))) { $blacklist->{"comp_extepg_" . $_->{id}} = 1; } } } epgsearch_getSettings(); my $vars = { usercss => $UserCSS, url => $MyURL, epgsearch => $blacklist, channels => \@{$CHAN{$CHAN_FULL}->{channels}}, ch_groups => \@ch_groups, do_edit => (defined $id ? "1" : undef), extepg => \@extepg, mode_blacklist => 1 }; return showTemplate("epgsearch_new.html", $vars); } sub epgsearch_bl_save { my $cmd = (defined $q->param("id") ? "EDIB " . $q->param("id") : "NEWB 0") . ":" . epgsearch_Param2Line(); SendCMD("plug epgsearch " . $cmd); return (headerForward("$MyURL?aktion=epgsearch_config")); } sub epgsearch_bl_delete { my $id = $q->param("id"); if (defined $id) { SendCMD("plug epgsearch delb $id"); } else { for ($q->param) { SendCMD("plug epgsearch delb $1") if (/xxxx_(.*)/); } } return (headerForward("$MyURL?aktion=epgsearch_config")); } sub ExtractEpgSearchBlacklistConf { my $line = shift; my $timer; ($timer->{id}, # 1 - unique search timer id $timer->{pattern}, # 2 - the search term $timer->{use_time}, # 3 - use time? 0/1 $timer->{time_start}, # 4 - start time in HHMM $timer->{time_stop}, # 5 - stop time in HHMM $timer->{use_channel}, # 6 - use channel? 0 = no, 1 = Intervall, 2 = Channel group, 3 = FTA only $timer->{channels}, # 7 - if 'use channel' = 1 then channel id[|channel id] in vdr format, # one entry or min/max entry separated with |, if 'use channel' = 2 # then the channel group name $timer->{matchcase}, # 8 - match case? 0/1 $timer->{mode}, # 9 - search mode: # 0 - the whole term must appear as substring # 1 - all single terms (delimiters are blank,',', ';', '|' or '~') # must exist as substrings. # 2 - at least one term (delimiters are blank, ',', ';', '|' or '~') # must exist as substring. # 3 - matches exactly # 4 - regular expression $timer->{use_title}, #10 - use title? 0/1 $timer->{use_subtitle}, #11 - use subtitle? 0/1 $timer->{use_descr}, #12 - use description? 0/1 $timer->{use_duration}, #13 - use duration? 0/1 $timer->{min_duration}, #14 - min duration in minutes $timer->{max_duration}, #15 - max duration in minutes $timer->{use_days}, #16 - use day of week? 0/1 $timer->{which_days}, #17 - day of week (0 = sunday, 1 = monday...) $timer->{use_extepg}, #18 - use extended EPG info? 0/1 #TODO $timer->{extepg_infos}, #19 - extended EPG info values. This entry has the following format #TODO # (delimiter is '|' for each category, '#' separates id and value): # 1 - the id of the extended EPG info category as specified in # epgsearchcats.conf # 2 - the value of the extended EPG info category # (a ':' will be tranlated to "!^colon^!", e.g. in "16:9") $timer->{fuzzy_tolerance}, #20 - fuzzy tolerance value for fuzzy searching $timer->{ignore_missing_epgcats}, #21 - ignoreMissingEPGCats $timer->{unused}) = split(/:/, $line); #format selected fields $timer->{time_start} =~ s/(\d\d)(\d\d)/$1:$2/ if($timer->{time_start}); $timer->{time_stop} =~ s/(\d\d)(\d\d)/$1:$2/ if($timer->{time_stop}); $timer->{min_duration} =~ s/(\d\d)(\d\d)/$1:$2/ if($timer->{min_duration}); $timer->{max_duration} =~ s/(\d\d)(\d\d)/$1:$2/ if($timer->{max_duration}); if ($timer->{channels} && $timer->{use_channel} == 1) { ($timer->{channel_from}, $timer->{channel_to}) = split(/\|/, $timer->{channels}, 2); $timer->{channel_to} = $timer->{channel_from} unless ($timer->{channel_to}); $timer->{channel_from_name} = get_name_from_uniqid($timer->{channel_from}); $timer->{channel_to_name} = get_name_from_uniqid($timer->{channel_to}); #TODO: links to channels } if ($timer->{use_days}) { if ($timer->{which_days} >= 0) { $timer->{sunday} = 1 if ($timer->{which_days} == 0); $timer->{monday} = 1 if ($timer->{which_days} == 1); $timer->{tuesday} = 1 if ($timer->{which_days} == 2); $timer->{wednesday} = 1 if ($timer->{which_days} == 3); $timer->{thursday} = 1 if ($timer->{which_days} == 4); $timer->{friday} = 1 if ($timer->{which_days} == 5); $timer->{saturday} = 1 if ($timer->{which_days} == 6); } else { my $which_days = -$timer->{which_days}; $timer->{sunday} = 1 if ($which_days & 1); $timer->{monday} = 1 if ($which_days & 2); $timer->{tuesday} = 1 if ($which_days & 4); $timer->{wednesday} = 1 if ($which_days & 8); $timer->{thursday} = 1 if ($which_days & 16); $timer->{friday} = 1 if ($which_days & 32); $timer->{saturday} = 1 if ($which_days & 64); } } if ($timer->{pattern}) { $timer->{pattern} =~ s/\|/:/g; $timer->{pattern} =~ s/\!\^pipe\^\!/\|/g; } return $timer; } ############################################################################# # regulary timers ############################################################################# sub my_mktime { my $sec = 0; my $min = shift; my $hour = shift; my $mday = shift; my $mon = shift; my $year = shift() - 1900; #my $time = mktime($sec, $min, $hour, $mday, $mon, $year, 0, 0, (localtime(time))[8]); my $time = mktime($sec, $min, $hour, $mday, $mon, $year, 0, 0, -1); } sub ParseTimer { my $pc = shift; #TODO: what's this supposed to do? my $tid = shift; my $entry = 1; my @temp; for (SendCMD("lstt")) { last if (/^No timers defined/); chomp; my ($id, $temp) = split(/ /, $_, 2); my ($active, $vdr_id, $dor, $start, $stop, $prio, $lft, $title, $summary) = split(/\:/, $temp, 9); my ($startsse, $stopsse, $weekday, $off, $perrec, $length, $first); my ($autotimer, $event_id, $bstart, $bstop, $pattern, $tool); ($autotimer, $event_id, $bstart, $bstop, $pattern, $tool) = extract_timer_metadata($summary); # VDR > 1.3.24 sets a bit if it's currently recording my $recording = 0; $recording = 1 if (($active & 8) == 8); $active = 1 if ($active == 3 || $active == 9); #$active = 1 if(($active & 1) == 1); #TODO # replace "|" by ":" in timer's title (man vdr.5) $title =~ s/\|/\:/g; my $title_js = $title; $title_js =~ s/\'/\\\'/g; $title_js =~ s/\"/"/g; if (length($dor) == 7) { # repeating timer $startsse = my_mktime(substr($start, 2, 2), substr($start, 0, 2), my_strftime("%d"), (my_strftime("%m") - 1), my_strftime("%Y")); $stopsse = my_mktime(substr($stop, 2, 2), substr($stop, 0, 2), my_strftime("%d"), (my_strftime("%m") - 1), my_strftime("%Y")); if ($stopsse < $startsse) { $stopsse += 86400; # +1day } $weekday = ((localtime(time))[6] + 6) % 7; $perrec = join("", substr($dor, $weekday), substr($dor, 0, $weekday)); $perrec =~ m/^-+/g; $off = (pos $perrec) * 86400; if ($off == 0 && $stopsse < time) { #$weekday = ($weekday + 1) % 7; $perrec = join("", substr($dor, ($weekday + 1) % 7), substr($dor, 0, ($weekday + 1) % 7)); $perrec =~ m/^-+/g; $off = ((pos $perrec) + 1) * 86400; } $startsse += $off; $stopsse += $off; } elsif (length($dor) == 18) { # first-day timer $dor =~ /.{7}\@(\d\d\d\d)-(\d\d)-(\d\d)/; $startsse = my_mktime(substr($start, 2, 2), substr($start, 0, 2), $3, ($2 - 1), $1); # 31 + 1 = ?? $stopsse = my_mktime(substr($stop, 2, 2), substr($stop, 0, 2), $stop > $start ? $3 : $3 + 1, ($2 - 1), $1); } else { # regular timer if ($dor =~ /(\d\d\d\d)-(\d\d)-(\d\d)/) { # vdr >= 1.3.23 $startsse = my_mktime(substr($start, 2, 2), substr($start, 0, 2), $3, ($2 - 1), $1); $stopsse = my_mktime(substr($stop, 2, 2), substr($stop, 0, 2), $stop > $start ? $3 : $3 + 1, ($2 - 1), $1); } else { # vdr < 1.3.23 next unless($start || $stop); $startsse = my_mktime(substr($start, 2, 2), substr($start, 0, 2), $dor, (my_strftime("%m") - 1), my_strftime("%Y")); $stopsse = my_mktime(substr($stop, 2, 2), substr($stop, 0, 2), $stop > $start ? $dor : $dor + 1, (my_strftime("%m") - 1), my_strftime("%Y")); # move timers which have expired one month into the future if (length($dor) != 7 && $stopsse < time) { $startsse = my_mktime(substr($start, 2, 2), substr($start, 0, 2), $dor, (my_strftime("%m") % 12), (my_strftime("%Y") + (my_strftime("%m") == 12 ? 1 : 0))); $stopsse = my_mktime(substr($stop, 2, 2), substr($stop, 0, 2), $stop > $start ? $dor : $dor + 1, (my_strftime("%m") % 12), (my_strftime("%Y") + (my_strftime("%m") == 12 ? 1 : 0))); } } } if ($CONFIG{RECORDINGS} && length($dor) == 7) { # repeating timer # generate repeating timer entries for up to 28 days $first = 1; for ($weekday += $off / 86400, $off = 0 ; $off < 28 ; $off++) { $perrec = join("", substr($dor, ($weekday + $off) % 7), substr($dor, 0, ($weekday + $off) % 7)); $perrec =~ m/^-+/g; next if ($perrec && ((pos $perrec) != 0)); $length = push( @temp, { id => $id, vdr_id => $vdr_id, start => $startsse, stop => $stopsse, startsse => $startsse + $off * 86400, stopsse => $stopsse + $off * 86400, active => $active, recording => $first ? $recording : 0, # only the first might record event_id => $event_id, cdesc => get_name_from_vdrid($vdr_id), transponder => get_transponder_from_vdrid($vdr_id), ca => get_ca_from_vdrid($vdr_id), dor => $dor, prio => $prio, lft => $lft, title => $title, title_js => $title_js, summary => $summary, collision => 0, critical => 0, first => $first, proglink => sprintf("%s?aktion=prog_list&vdr_id=%s", $MyURL, $vdr_id), autotimer => $autotimer, bstart => $bstart, bstop => $bstop, pattern => $pattern, tool => $tool } ); $first = 0; } } else { $length = push(@temp, { id => $id, vdr_id => $vdr_id, start => $startsse, stop => $stopsse, startsse => $startsse, stopsse => $stopsse, active => $active, recording => $recording, event_id => $event_id, cdesc => get_name_from_vdrid($vdr_id), transponder => get_transponder_from_vdrid($vdr_id), ca => get_ca_from_vdrid($vdr_id), dor => $dor, prio => $prio, lft => $lft, title => $title, title_js => $title_js, summary => $summary, collision => 0, critical => 0, first => -1, proglink => sprintf("%s?aktion=prog_list&vdr_id=%s", $MyURL, $vdr_id), autotimer => $autotimer, bstart => $bstart, bstop => $bstop, pattern => $pattern, tool => $tool } ); } # save index of entry with specific timer id for later use if ($tid && $tid == $id) { $entry = $length; } } if ($tid) { return ($temp[ $entry - 1 ]); } else { return (@temp); } } # extract our own metadata from a timer's aux field. sub extract_timer_metadata { my $aux = shift; return unless ($aux =~ /(.*)<\/vdradmin-am>|(.*)<\/epgsearch>/i); if ($1) { # VDRAdmin-AM AutoTimer $aux = $1; my $epg_id = $1 if ($aux =~ /(.*)<\/epgid>/i); my $autotimer = $1 if ($aux =~ /(.*)<\/autotimer>/i); my $bstart = $1 if ($aux =~ /(.*)<\/bstart>/i); my $bstop = $1 if ($aux =~ /(.*)<\/bstop>/i); my $pattern = $1 if ($aux =~ /(.*)<\/pattern>/i); return ($autotimer, $epg_id, $bstart, $bstop, $pattern, $TOOL_AUTOTIMER); } elsif ($2) { # EPGSearch $aux = $2; my $epg_id = $1 if ($aux =~ /(.*)<\/eventid>/i); my $autotimer = $1 if ($aux =~ /(.*)<\/update>/i); my $bstart = $1 if ($aux =~ /(.*)<\/bstart>/i); my $bstop = $1 if ($aux =~ /(.*)<\/bstop>/i); return ($autotimer, $epg_id, $bstart, $bstop, undef, $TOOL_EPGSEARCH); } } sub append_timer_metadata { my ($aux, $epg_id, $autotimer, $bstart, $bstop, $pattern, $tool) = @_; if ($tool == $TOOL_AUTOTIMER) { # remove old autotimer info $aux =~ s/\|?.*<\/vdradmin-am>//i if ($aux); $aux = substr($aux, 0, 9000) if ($FEATURES{VDRVERSION} < 10336 and length($aux) > 9000); # add a new line if VDR<1.3.44 because then there might be a summary $aux .= "|" if ($FEATURES{VDRVERSION} < 10344 and length($aux)); $aux .= ""; $aux .= "$epg_id" if ($epg_id); $aux .= "$autotimer" if ($autotimer); $aux .= "$bstart" if ($bstart); $aux .= "$bstop" if ($bstop); $aux .= "$pattern" if ($pattern); $aux .= ""; } elsif ($tool == $TOOL_EPGSEARCH) { # remove old epgsearch info $aux =~ s/\|?.*<\/epgsearch>//i if ($aux); $aux = substr($aux, 0, 9000) if ($FEATURES{VDRVERSION} < 10336 and length($aux) > 9000); # add a new line if VDR<1.3.44 because then there might be a summary $aux .= "|" if ($FEATURES{VDRVERSION} < 10344 and length($aux)); $aux .= ""; $aux .= "$epg_id" if ($epg_id); $aux .= "$autotimer" if (defined $autotimer); $aux .= "" . ($bstart * 60) . "" if ($bstart); $aux .= "" . ($bstop * 60) . "" if ($bstop); $aux .= ""; } return $aux; } ############################################################################# # Tools ############################################################################# sub DisplayMessage { my $message = shift; SendCMD(sprintf("mesg %s", $message)); } sub LoadTranslation { undef %ERROR_MESSAGE; %ERROR_MESSAGE = (not_found => gettext("Not found"), notfound_long => gettext("The requested URL was not found on this server!"), notfound_file => gettext("The URL \"%s\" was not found on this server!"), forbidden => gettext("Forbidden"), forbidden_long => gettext("You don't have permission to access this function!"), forbidden_file => gettext("Access to file \"%s\" denied!"), cant_open => gettext("Can't open file \"%s\"!"), connect_failed => gettext("Can't connect to VDR at %s:%s: %s

    Please check if VDR is running and if VDR's svdrphosts.conf is configured correctly."), send_command => gettext("Error while sending command to VDR at %s"), ); setlocale(LC_ALL, $CONFIG{LANG}); if (! $CONFIG{LANG} eq '') { setlocale(LC_ALL, $CONFIG{LANG}); chomp($MY_ENCODING = `LC_ALL=$CONFIG{LANG} locale charmap`); } else { chomp($MY_ENCODING = `locale charmap`); } $MY_ENCODING = "UTF-8" unless ($MY_ENCODING); bind_textdomain_codeset("vdradmin", $MY_ENCODING) if($can_use_bind_textdomain_codeset); CGI::charset($MY_ENCODING); } sub HelpURL { my $area = shift; return (sprintf("%s?aktion=show_help&area=%s", $MyURL, $area)); } sub ProgTimer { # $start and $stop are expected as seconds since 00:00:00 1970-01-01 UTC. my ($timer_id, $active, $event_id, $channel, $start, $stop, $prio, $lft, $title, $summary, $dor) = @_; $title =~ s/\:/|/g; # replace ":" by "|" in timer's title (man vdr.5) my $send_cmd = $timer_id ? "modt $timer_id" : "newt"; my $send_dor = $dor ? $dor : RemoveLeadingZero(strftime("%d", localtime($start))); my $send_summary = ($FEATURES{VDRVERSION} >= 10336) ? $summary : substr($summary, 0, $VDR_MAX_SVDRP_LENGTH - 9 - length($send_cmd) - length($active) - length($channel) - length($send_dor) - 8 - length($prio) - length($lft) - length($title)); Log(LOG_DEBUG, sprintf("[SVDRP] ProgTimer: Programming Timer \"%s\" (Channel %s, Event-ID %s, %s - %s, Active %s)", $title, $channel, $event_id, my_strftime("%Y%m%d-%H%M", $start), my_strftime("%Y%m%d-%H%M", $stop), $active)); my $return = SendCMD(sprintf("%s %s:%s:%s:%s:%s:%s:%s:%s:%s", $send_cmd, $active, $channel, $send_dor, strftime("%H%M", localtime($start)), strftime("%H%M", localtime($stop)), $prio, $lft, trim($title), $send_summary)); return $return; } sub RedirectToReferer { my $url = shift; if ($Referer =~ /vdradmin\.pl\?.*$/) { return (headerForward($Referer)); } else { return (headerForward($url)); } } sub salt { #TODO: unused $_ = $_[0]; my $string; my ($offset1, $offset2); if (length($_) > 8) { $offset1 = length($_) - 9; $offset2 = length($_) - 1; } else { $offset1 = 0; $offset2 = length($_) - 1; } $string = substr($_, $offset1, 1); $string .= substr($_, $offset2, 1); return ($string); } sub SigDieHandler { my $error = $_[0]; CloseSocket(); my $vars = { error => gettext("Internal error:") . "
    $error" }; return showTemplate("error.html", $vars); } sub Shutdown { CloseSocket(); if ($CONFIG{AUTO_SAVE_CONFIG}) { (my $err = WriteConfig()) =~ s|$||gi; Log(LOG_ERROR, $err) if $err; } closelog(); if ($DAEMON) { unlink($PIDFILE) or Log(LOG_WARNING, "Can't delete pid file '$PIDFILE': $!"); } exit(0); } sub getPID { my $pidfile = shift; if (!open(PID, $pidfile)) { Log(LOG_WARNING, "Can't open pid file '$pidfile' for reading: $!"); return undef; } chomp(my $pid = || ""); close(PID) or Log(LOG_WARNING, "Error closing pid file '$pidfile': $!"); if ($pid !~ /^\d+$/) { Log(LOG_WARNING, "Ignoring bogus process id '$pid' in pid file '$pidfile'"); $pid = undef; } return $pid; } sub writePID { my $pidfile = shift; if (!open(FILE, ">", $pidfile)) { Log(LOG_ERROR, "Can't open pid file '$pidfile' for writing: $!"); return 0; } print FILE shift; close(FILE) or Log(LOG_WARNING, "Error closing pid file '$pidfile': $!"); return 1; } sub HupSignal { UptoDate(1); } sub UptoDate { my $force = shift; my $rv = 0; if (((time() - $CONFIG{CACHE_LASTUPDATE}) >= ($CONFIG{CACHE_TIMEOUT} * 60)) || $force) { OpenSocket(); Log(LOG_INFO, "[EPG] Building channel tree..."); ChanTree(); Log(LOG_INFO, "[EPG] Finished building channel tree."); if (@{$CHAN{$CHAN_FULL}->{channels}}) { Log(LOG_INFO, "[EPG] Building EPG tree..."); EPG_buildTree(); Log(LOG_INFO, "[EPG] Finished building EPG tree."); $CONFIG{CACHE_LASTUPDATE} = time(); if ($CONFIG{AT_FUNC} && $FEATURES{AUTOTIMER}) { CheckTimers(); AutoTimer(); } } else { $rv = 1; } CloseSocket(); } return ($rv); } sub Log { if ($#_ >= 1) { return 1 unless $LOGGING; my $level = shift; chomp(my $message = join("", @_)); my $my_loglevel = $CONFIG{LOGLEVEL}; $my_loglevel = $LOGLEVEL if defined $LOGLEVEL; if ($my_loglevel >= shift @$level) { if ($LOG_TO_SYSLOG) { syslog(shift @$level, '%s', $message); } elsif ($LOGFILE eq "stderr" || $LOGFILE eq "syslog") { printf STDERR "%s: %s\n", my_strftime("%x %X"), $message; } else { if (open(LOGFILE, ">>", "$LOGDIR/$LOGFILE")) { printf LOGFILE "%s: %s\n", my_strftime("%x %X"), $message; close(LOGFILE); } else { printf STDERR "%s: %s\n", my_strftime("%x %X"), "Could not open log file '$LOGDIR/$LOGFILE' for writing: $!"; } } } } else { Log(LOG_FATALERROR, "[INT] bogus Log() call"); } } sub showTemplate { my $file = shift; my $vars = shift; my $status = shift; my $ctype = shift; $status = "200" unless($status); $ctype = "text/html" unless($ctype); my $output; $Xtemplate->process("$CONFIG{TEMPLATE}/$file", $vars, \$output) || return (header("500", "text/html", $Xtemplate->error())); return (header($status, $ctype, $output)); } sub my_strftime { my $format = shift; my $time = shift; return (strftime($format, $time ? localtime($time) : localtime(time))); } sub GetFirstChannel { #TODO: unused return ($CHAN{$CHAN_FULL}->{channels}[0]->{service_id}); } sub ChannelHasEPG { my $service_id = shift; for my $event (@{ $EPG{$service_id} }) { return (1); } return (0); } sub Encode_Referer { if ($_[0]) { $_ = $_[0]; } else { $_ = $Referer; } return (MIME::Base64::encode_base64(sprintf("%s", $_), "")); } sub Decode_Referer { my $text = shift; $text =~ s/ /+/g; my $ref = MIME::Base64::decode_base64($text); return ($ref); } sub encode_ref { #TODO: unused my ($tmp) = $_[0]->url(-relative => 1, -query => 1); my (undef, $query) = split(/\?/, $tmp, 2); return (MIME::Base64::encode_base64($query, "")); } sub decode_ref { #TODO: unused return (MIME::Base64::decode_base64($_[0])); } sub access_log { my $ip = shift; my $username = shift; my $rawrequest = shift; my $http_status = shift; my $bytes_transfered = shift; my $request = shift; my $useragent = shift; return sprintf("%s %s \"%s\" %s %s \"%s\" \"%s\"", $ip, defined($username) ? $username : "-", $rawrequest, $http_status ? $http_status : "-", $bytes_transfered ? $bytes_transfered : "-", $request, $useragent); } sub ValidConfig { $CONFIG{SKIN} = "default" unless($CONFIG{SKIN}); $CONFIG{TEMPLATE} = "default" unless($CONFIG{TEMPLATE}); $CONFIG{TV_MIMETYPE} = "video/x-mpegurl" if (!$CONFIG{TV_MIMETYPE}); $CONFIG{TV_EXT} = "m3u" if (!$CONFIG{TV_EXT}); $CONFIG{REC_MIMETYPE} = "video/x-mpegurl" if (!$CONFIG{REC_MIMETYPE}); $CONFIG{REC_EXT} = "m3u" if (!$CONFIG{REC_EXT}); $CONFIG{SRCH1_ACTIVE} = 1 unless (defined $CONFIG{SRCH1_ACTIVE}); $CONFIG{SRCH1_URL} = "https://www.imdb.com/find/?q=\%TITLE\%" unless (defined $CONFIG{SRCH1_URL}); $CONFIG{SRCH1_TITLE} = gettext("Lookup movie in the Internet-Movie-Database (IMDb)") unless (defined $CONFIG{SRCH1_TITLE}); if ($CONFIG{AT_OFFER} == 2) { # User wants to use AutoTimer $FEATURES{AUTOTIMER} = 1; } elsif ($CONFIG{AT_OFFER} == 1) { # User doesn't want AutoTimer $FEATURES{AUTOTIMER} = 0; } else { # No decision made yet if (-s $AT_FILENAME && $CONFIG{AT_FUNC}) { $FEATURES{AUTOTIMER} = 1; $CONFIG{AT_OFFER} = 0; } else { $CONFIG{AT_FUNC} = 0; $FEATURES{AUTOTIMER} = 0; $CONFIG{AT_OFFER} = 1; } } $CONFIG{GUI_POPUP_WIDTH} = 550 unless ($CONFIG{GUI_POPUP_WIDTH} =~ /\d+/); $CONFIG{GUI_POPUP_HEIGHT} = 550 unless ($CONFIG{GUI_POPUP_HEIGHT} =~ /\d+/); } sub ReadConfig { if (-e $CONFFILE) { if (open(CONF, $CONFFILE)) { while () { chomp; my ($key, $value) = split(/ \= /, $_, 2); $CONFIG{$key} = $value; } close(CONF) or Log(LOG_WARNING, "Error closing conf file '$CONFFILE': $!"); } else { Log(LOG_ERROR, "Can't open conf file '$CONFFILE' for reading: $!"); } ValidConfig(); #Migrate settings #v3.4.5 $CONFIG{MAIL_FROM} = "autotimer@" . $CONFIG{MAIL_FROMDOMAIN} if ($CONFIG{MAIL_FROM} =~ /from\@address.tld/); #v3.4.6beta $CONFIG{SKIN} = "default" if(($CONFIG{SKIN} eq "bilder") || ($CONFIG{SKIN} eq "copper") || ($CONFIG{SKIN} eq "default.png")); #v3.5.3 delete $CONFIG{EPG_DIRECT}; delete $CONFIG{EPG_FILENAME}; #v3.5.4rc if (defined $CONFIG{AT_TIMEOUT}) { $CONFIG{CACHE_TIMEOUT} = $CONFIG{AT_TIMEOUT} if ($CONFIG{AT_TIMEOUT} < $CONFIG{CACHE_TIMEOUT}); delete $CONFIG{AT_TIMEOUT}; } #v3.6.2 delete $CONFIG{VDRVFAT}; #v3.6.5 $CONFIG{LOGLEVEL} = 4 if ($CONFIG{LOGLEVEL} == 81); } else { print "$CONFFILE doesn't exist. Please run \"$EXENAME --config\"\n"; print "Exiting!\n"; exit(1); #open(CONF, ">$CONFFILE"); #for(keys(%CONFIG)) { # print(CONF "$_ = $CONFIG{$_}\n"); #} #close(CONF); #return(1); } return (0); } sub Question { my ($quest, $default) = @_; print("$quest [$default]: "); my ($answer); chomp($answer = ); if ($answer eq "") { return ($default); } else { return ($answer); } } sub RemoveLeadingZero { my ($str) = @_; while (substr($str, 0, 1) == 0) { $str = substr($str, 1, (length($str) - 1)); } return ($str); } sub csvAdd { my $csv = shift; my $add = shift; my $found = 0; for my $item (split(",", $csv)) { $found = 1 if ($item eq $add); } $csv = join(",", (split(",", $csv), $add)) if (!$found); return ($csv); } sub csvRemove { my $csv = shift; my $remove = shift; my $newcsv = ""; for my $item (split(",", $csv)) { if ($item ne $remove) { my $found = 0; if (defined($newcsv)) { for my $dup (split(",", $newcsv)) { $found = 1 if ($dup eq $item); } } $newcsv = join(",", (split(",", $newcsv), $item)) if (!$found); } } return ($newcsv); } sub Einheit { my @einheiten = qw(MB GB TB); my $einheit = 0; my $zahl = shift; while ($zahl > 1024) { $zahl /= 1024; $einheit++; } return (sprintf("%1.*f", $einheit, $zahl) . $einheiten[$einheit]); } sub MBToMinutes { my $mb = shift; my $minutes = $mb / 25.75; my $hours = $minutes / 60; $minutes %= 60; return (sprintf("%2d:%02d", $hours, $minutes)); } sub VideoDiskFree { $_ = join("", SendCMD("stat disk")); if (/^(\d+)MB (\d+)MB (\d+)%.*?$/) { return (Einheit($1), MBToMinutes($1), Einheit($2), MBToMinutes($2), $3); } elsif (/^Command unrecognized: "stat"$/) { #print "VDR doesnt know about this extension\n"; } else { print "Unknown response $_\n"; } return undef; } ############################################################################# # frontend ############################################################################# sub show_index { return if (UptoDate() != 0); my $page; if (defined($CONFIG{LOGINPAGE})) { $page = $LOGINPAGES[ $CONFIG{LOGINPAGE} ]; } else { $page = $LOGINPAGES[0]; } my $vars = { loginpage => "$MyURL?aktion=$page", version => $VERSION, host => $CONFIG{VDR_HOST} }; return showTemplate("index.html", $vars); } sub show_navi { my $vars = { }; return showTemplate("navigation.html", $vars); } sub prog_switch { my $channel = $q->param("channel"); if ($channel) { SendCMD("chan $channel"); } SendFile("bilder/spacer.gif"); } sub prog_detail { return if (UptoDate() != 0); my $vdr_id = $q->param("vdr_id"); my $epg_id = $q->param("epg_id"); my ($channel_name, $title, $subtitle, $vps, $video, $audio, $start, $stop, $text, @epgimages); my @timers = ParseTimer(0); if ($q->param("channel_id")) { $vdr_id = get_vdrid_from_channelid($q->param("channel_id")); } if ($vdr_id && $epg_id) { for my $event (@{ $EPG{$vdr_id} }) { #if($event->[EV_ID] == $epg_id) { #XXX if ($event->[EV_EVENT_ID] == $epg_id) { $channel_name = $event->[EV_CHANNEL_NAME]; $title = $event->[EV_TITLE]; $subtitle = $event->[EV_SUBTITLE]; $start = $event->[EV_START]; $stop = $event->[EV_STOP]; $text = $event->[EV_SUMMARY]; $vps = $event->[EV_VPS]; $video = getEventVideo($event); $audio = getEventAudio($event); # find epgimages if ($CONFIG{EPGIMAGES} && -d $CONFIG{EPGIMAGES}) { my $uniq_id = GetChannelUniqIdByNumber($vdr_id); for my $epgimage (<$CONFIG{EPGIMAGES}/${uniq_id}_${epg_id}\[\._\]*>) { $epgimage =~ s/.*\///g; $epgimage =~ tr/-/:/; push(@epgimages, { image => "epg/" . $epgimage }); } } last; } } } my $displaytext = CGI::escapeHTML($text); my $displaytitle = CGI::escapeHTML($title); my $displaysubtitle = CGI::escapeHTML($subtitle); my $search_title = $title; $search_title =~ s/^.*\~\%*([^\~]*)$/$1/; $search_title = uri_escape($search_title); my $imdb_url = undef; if ($search_title && $CONFIG{SRCH1_ACTIVE}) { $imdb_url = $CONFIG{SRCH1_URL}; $imdb_url =~ s/\%TITLE\%/$search_title/g; } my $srch2_url = undef; if ($search_title && $CONFIG{SRCH2_ACTIVE}) { $srch2_url = $CONFIG{SRCH2_URL}; $srch2_url =~ s/\%TITLE\%/$search_title/g; } if ($displaytext) { $displaytext =~ s/\n/
    \n/g; $displaytext =~ s/\|/
    \n/g; } if ($displaytitle) { $displaytitle =~ s/\n/
    \n/g; $displaytitle =~ s/\|/
    \n/g; } if ($displaysubtitle) { $displaysubtitle =~ s/\n/
    \n/g; $displaysubtitle =~ s/\|/
    \n/g; } # Do not use prog_detail as referer. # Use the referer we received. my $referer = getReferer(); my ($recurl, $editurl); $recurl = sprintf("%s?aktion=timer_new_form&epg_id=%s&vdr_id=%s&referer=%s", $MyURL, $epg_id, $vdr_id, Encode_Referer($referer)) unless ($referer =~ "timer_list"); $editurl = sprintf("%s?aktion=prog_detail_form&epg_id=%s&vdr_id=%s&referer=%s", $MyURL, $epg_id, $vdr_id, Encode_Referer($referer)); my $timerset = 0; foreach my $timer (@timers) { if (($timer->{vdr_id} == $vdr_id) && ($timer->{start} <= $start) && ($timer->{stop} >= $stop)) { $timerset = 1; last; } } my $now = time(); my $vars = { title => $displaytitle ? $displaytitle : gettext("Can't find EPG entry!"), recurl => $recurl, editurl => $editurl, switchurl => ($start && $stop && $start <= $now && $now <= $stop) ? sprintf("%s?aktion=prog_switch&channel=%s", $MyURL, $vdr_id) : undef, channel_name => CGI::escapeHTML($channel_name), subtitle => $displaysubtitle, vps => ($vps && $start && $start != $vps) ? my_strftime("%H:%M", $vps) : undef, start => my_strftime("%H:%M", $start), stop => my_strftime("%H:%M", $stop), text => $displaytext ? $displaytext : undef, date => $title ? my_strftime("%A, %x", $start) : undef, find_title => $title ? uri_escape("/^" . my_quotemeta($title . "~" . ($subtitle ? $subtitle : "") . "~") . "/") : undef, srch1_url => $imdb_url, srch1_title => $imdb_url ? gettext($CONFIG{SRCH1_TITLE}) : undef, srch2_url => $srch2_url, srch2_title => $srch2_url ? gettext($CONFIG{SRCH2_TITLE}) : undef, epgimages => \@epgimages, audio => $audio, video => $video, vdr_id => $vdr_id, epg_id => $epg_id, timerset => $timerset, }; return showTemplate("prog_detail.html", $vars); } sub prog_detail_form { # determine referer (redirect to where we come from) my $ref = getReferer(); my $vdr_id = $q->param("vdr_id"); my $epg_id = $q->param("epg_id"); my $vars; if ($epg_id) { my $event = EPG_getEntry($vdr_id, $epg_id); my $displaytitle = CGI::escapeHTML($event->[EV_TITLE]); my $displaysubtitle = CGI::escapeHTML($event->[EV_SUBTITLE]); my $displaydescription = CGI::escapeHTML($event->[EV_SUMMARY]); if ($displaydescription) { $displaydescription =~ s/\|/\n/g; } $vars = { url => $MyURL, vdr_id => $event->[EV_VDR_ID], epg_id => $event->[EV_EVENT_ID], channel_name => $event->[EV_CHANNEL_NAME], start_hr => sprintf("%s - %s", my_strftime("%A, %x %H:%M", $event->[EV_START]), my_strftime("%H:%M", $event->[EV_STOP])), start => $event->[EV_START], duration => $event->[EV_STOP] - $event->[EV_START], #table_id => $event->{table_id}, #version => $event->{version}, title => $displaytitle, subtitle => $displaysubtitle, description => $displaydescription, vps => $event->[EV_VPS] ? my_strftime("%A, %x %H:%M", $event->[EV_VPS]) : undef, video => getEventVideo($event), audio => getEventAudio($event), referer => $ref ? Encode_Referer($ref) : undef, help_url => HelpURL("edit_epg") } } return showTemplate("prog_detail_form.html", $vars); } sub prog_detail_aktion { if ($q->param("save")) { my $vdr_id = $q->param("vdr_id"); my $event_id = $q->param("epg_id"); my $channel_id = get_channelid_from_vdrid($vdr_id); my $start = $q->param("start"); my $duration = $q->param("duration"); my $title = CGI::unescapeHTML(scalar $q->param("title")); my $subtitle = CGI::unescapeHTML(scalar $q->param("subtitle")); my $description = CGI::unescapeHTML(scalar $q->param("description")); my $vps = $q->param("vps"); my $table_id = 0; # must be zero for external epg data my ($new_subtitle, $new_description, $new_video, $new_audio, $new_vps) = ("","","","",""); my $event = EPG_getEntry($vdr_id, $event_id); if ($title) { $title =~ s/\r\n//g; $title =~ s/\n//g; } else { $title = $event->[EV_TITLE]; } if ($subtitle) { $subtitle =~ s/\r\n//g; $subtitle =~ s/\n//g; $new_subtitle = sprintf ("S %s\n", $subtitle); } if ($description) { $description =~ s/\r\n/|/g; $description =~ s/\n/|/g; $new_description = sprintf ("D %s\n", $description); } $new_video = getEventVideo($event, 1); $new_video .= "\n" if ($new_video); $new_audio = getEventAudio($event, 1); $new_audio .= "\n" if ($new_audio); $new_vps = sprintf ("V %s\n", $event->[EV_VPS]) if ($event->[EV_VPS]); my ($result) = SendCMD("pute"); if ($result !~ /Enter EPG data/i) { #printf "something went wrong during EPG update: $result\n"; main::HTMLError(sprintf($ERROR_MESSAGE{send_command}, $CONFIG{VDR_HOST})); } else { ($result) = SendCMD(sprintf ("C %s\nE %u %ld %d %X\nT %s\n%s%s%s%s%se\nc\n.\n", $channel_id, $event_id, $start, $duration, $table_id, $title, $new_subtitle, $new_description, $new_video, $new_audio, $new_vps)); if ($result !~ /EPG data processed/i) { #printf "something went wrong during EPG update: %s\n", $result; main::HTMLError(sprintf($ERROR_MESSAGE{send_command}, $CONFIG{VDR_HOST})); } else { # don't reread complete epg, just change the cache $event->[EV_TITLE] = $title; $event->[EV_SUBTITLE] = $subtitle; $event->[EV_SUMMARY] = $description; } } } my $ref = getReferer(); if ($ref) { return (headerForward($ref)); } else { return (headerForward("$MyURL?aktion=prog_summary")); } } ############################################################################# # program listing ############################################################################# sub prog_list { return if (UptoDate() != 0); $CONFIG{CHANNELS_WANTED_PRG} = $q->param("wanted_channels") if (defined $q->param("wanted_channels")); my ($vdr_id, $dummy); ($vdr_id, $dummy) = split("#", $q->param("vdr_id"), 2) if ($q->param("vdr_id")); if ($q->param("channel_id")) { $vdr_id = get_vdrid_from_channelid($q->param("channel_id")); } my $myself = Encode_Referer($MyURL . "?" . $Query); my @timers = ParseTimer(0); # my (@channel, $current); for my $channel (@{$CHAN{$CONFIG{CHANNELS_WANTED_PRG}}->{channels}}) { # skip channels without EPG data if ($CONFIG{CHANNELS_WITHOUT_EPG} || ChannelHasEPG($channel->{vdr_id})) { # called without vdr_id, redirect to the first available channel $vdr_id = $channel->{vdr_id} if(!$vdr_id); $current = 1 if ($vdr_id == $channel->{vdr_id}); push(@channel, { name => $channel->{name} . (!$CONFIG{CHANNELS_WITHOUT_EPG} || ChannelHasEPG($channel->{vdr_id}) ? '' : ' (' . gettext("No EPG information available") . ')'), vdr_id => $channel->{vdr_id}, current => ($vdr_id == $channel->{vdr_id}) ? 1 : 0, } ); } } unless ($current) { my $channel = get_channel_from_vdrid($vdr_id); if ($channel) { unshift(@channel, { name => '[' . $channel->{name} .']' . (!$CONFIG{CHANNELS_WITHOUT_EPG} || ChannelHasEPG($channel->{vdr_id}) ? '' : ' (' . gettext("No EPG information available") . ')'), vdr_id => $channel->{vdr_id}, current => 1 } ); } else { $vdr_id = $channel[0]->{vdr_id}; } } # find the next/prev channel my $ci = 0; for (my $i = 0 ; $i <= $#channel ; $i++) { ($ci = $i) if ($vdr_id == $channel[$i]->{vdr_id}); } my ($next_channel, $prev_channel, $next_channel_name, $prev_channel_name); if ($ci > 0) { $prev_channel = $channel[ $ci - 1 ]->{vdr_id}; $prev_channel_name = $channel[ $ci - 1 ]->{name}; } if ($ci < $#channel) { $next_channel = $channel[ $ci + 1 ]->{vdr_id}; $next_channel_name = $channel[ $ci + 1 ]->{name}; } # my (@show); my $day = 0; for my $event (@{ $EPG{$vdr_id} }) { if (my_strftime("%d", $event->[EV_START]) != $day) { # new day push(@show, { endd => 1, next_channel => $next_channel ? "$MyURL?aktion=prog_list&vdr_id=$next_channel" : undef, prev_channel => $prev_channel ? "$MyURL?aktion=prog_list&vdr_id=$prev_channel" : undef, next_channel_name => $next_channel_name, prev_channel_name => $prev_channel_name, } ) if (scalar(@show) > 0); push(@show, { progname => $event->[EV_CHANNEL_NAME], longdate => my_strftime("%A, %x", $event->[EV_START]), newd => 1, next_channel => $next_channel ? "$MyURL?aktion=prog_list&vdr_id=$next_channel" : undef, prev_channel => $prev_channel ? "$MyURL?aktion=prog_list&vdr_id=$prev_channel" : undef, next_channel_name => $next_channel_name, prev_channel_name => $prev_channel_name, } ); $day = strftime("%d", localtime($event->[EV_START])); } my $search_title = $event->[EV_TITLE]; $search_title =~ s/^.*\~\%*([^\~]*)$/$1/; $search_title = uri_escape($search_title); my $imdb_url = undef; if ($search_title && $CONFIG{SRCH1_ACTIVE}) { $imdb_url = $CONFIG{SRCH1_URL}; $imdb_url =~ s/\%TITLE\%/$search_title/g; } my $srch2_url = undef; if ($search_title && $CONFIG{SRCH2_ACTIVE}) { $srch2_url = $CONFIG{SRCH2_URL}; $srch2_url =~ s/\%TITLE\%/$search_title/g; } my $subtitle = ""; if ($CONFIG{EPG_SUBTITLE}) { $subtitle = CGI::escapeHTML($event->[EV_SUBTITLE]); } if ($CONFIG{EPG_SUMMARY}) { if (length($subtitle)) { $subtitle .= "
    "; } $subtitle .= CGI::escapeHTML($event->[EV_SUMMARY]); $subtitle =~ s/\|/
    /g; } my $timerset = 0; foreach my $timer (@timers) { if (($timer->{vdr_id} == $vdr_id) && ($timer->{start} <= $event->[EV_START]) && ($timer->{stop} >= $event->[EV_STOP])) { $timerset = 1; last; } } push(@show, { ssse => $event->[EV_START], emit => my_strftime("%H:%M", $event->[EV_START]), duration => my_strftime("%H:%M", $event->[EV_STOP]), title => CGI::escapeHTML($event->[EV_TITLE]), subtitle => $subtitle, recurl => sprintf("%s?aktion=timer_new_form&epg_id=%s&vdr_id=%s&referer=%s", $MyURL, $event->[EV_EVENT_ID], $event->[EV_VDR_ID], $myself), infurl => $event->[EV_SUMMARY] ? sprintf("%s?aktion=prog_detail&epg_id=%s&vdr_id=%s&referer=%s", $MyURL, $event->[EV_EVENT_ID], $event->[EV_VDR_ID], $myself) : undef, editurl => sprintf("%s?aktion=prog_detail_form&epg_id=%s&vdr_id=%s&referer=%s", $MyURL, $event->[EV_EVENT_ID], $event->[EV_VDR_ID], $myself), find_title => uri_escape("/^" . my_quotemeta($event->[EV_TITLE] . "~" . ($event->[EV_SUBTITLE] ? $event->[EV_SUBTITLE] : "") . "~") . "/"), srch1_url => $imdb_url, srch1_title => $imdb_url ? gettext($CONFIG{SRCH1_TITLE}) : undef, srch2_url => $srch2_url, srch2_title => $srch2_url ? gettext($CONFIG{SRCH2_TITLE}) : undef, newd => 0, anchor => "id" . $event->[EV_EVENT_ID], timerset => $timerset } ); } if (scalar(@show)) { push(@show, { endd => 1 }); } # my $channel_name = GetChannelDescByNumber($vdr_id); my $now = time(); my $vars = { url => $MyURL, loop => \@show, chanloop => \@channel, progname => $channel_name, switchurl => "$MyURL?aktion=prog_switch&channel=$vdr_id", streamurl => $FEATURES{LIVESTREAM} ? sprintf("%s%s?aktion=live_stream&channel=%s&progname=%s", $MyStreamBase, $CONFIG{TV_EXT}, $vdr_id, uri_escape($channel_name)) : undef, stream_live_on => $FEATURES{LIVESTREAM} && $CONFIG{ST_FUNC} && $CONFIG{ST_LIVE_ON}, toolbarurl => "$MyURL?aktion=toolbar", ch_groups => getChannelGroups($MyURL . "?aktion=prog_list&vdr_id=$vdr_id", $CONFIG{CHANNELS_WANTED_PRG}) }; return showTemplate("prog_list.html", $vars); } ############################################################################# # program listing 2 # "What's up today" extension. # # Contributed by Thomas Blon, 6. Mar 2004 ############################################################################# sub prog_list2 { return if (UptoDate() != 0); my $current_day = my_strftime("%Y%m%d"); my $last_day = 0; my $day = $current_day; $day = $q->param("day") if ($q->param("day")); my $param_time = $q->param("time"); $CONFIG{CHANNELS_WANTED_PRG2} = $q->param("wanted_channels") if (defined $q->param("wanted_channels")); my ($start_hour, $start_min) = getSplittedTime($CONFIG{EPG_START_TIME}); my $day_start = (($start_hour * 60) + $start_min) * 60; # my $vdr_id; my @channel; my $myself = Encode_Referer($MyURL . "?" . $Query); my @timers = ParseTimer(0); for my $channel (@{$CHAN{$CONFIG{CHANNELS_WANTED_PRG2}}->{channels}}) { # skip channels without EPG data if ($CONFIG{CHANNELS_WITHOUT_EPG} || ChannelHasEPG($channel->{vdr_id})) { push(@channel, { name => $channel->{name}, vdr_id => $channel->{vdr_id} } ); } } my (@show, %hash_days); my ($hour, $minute) = getSplittedTime($param_time); my $border; $border = timelocal(0, $minute, $hour, substr($day, 6, 2), substr($day, 4, 2) - 1, substr($day, 0, 4)) if($day); my $time = getStartTime($param_time ? $param_time : undef, undef, $border); foreach (@channel) { # loop through all channels $vdr_id = $_->{vdr_id}; # find the next/prev channel my $ci = 0; for (my $i = 0 ; $i <= $#channel ; $i++) { ($ci = $i) if ($vdr_id == $channel[$i]->{vdr_id}); } my ($next_channel, $prev_channel); ($prev_channel = $channel[ $ci - 1 ]->{vdr_id}) if ($ci > 0); ($next_channel = $channel[ $ci + 1 ]->{vdr_id}) if ($ci < $#channel); if (ChannelHasEPG($_->{vdr_id})) { my $dayflag = 0; for my $event (@{ $EPG{$vdr_id} }) { my $event_day = my_strftime("%d.%m.", $event->[EV_START]-$day_start); my $event_day_long = my_strftime("%Y%m%d", $event->[EV_START]-$day_start); $hash_days{$event_day_long} = $event_day unless(exists $hash_days{$event_day_long}); # print("EVENT: " . $event->[EV_TITLE] . " - " . $event_day . "\n"); if ($event_day_long == $day) { $dayflag = 1 if ($dayflag == 0); } else { $last_day = $event_day_long if ($event_day_long > $last_day); $dayflag = 0; } if ($dayflag == 1 && $time < $event->[EV_STOP]) { push(@show, { channel_name => $event->[EV_CHANNEL_NAME], longdate => my_strftime("%A, %x", $event->[EV_START]), newd => 1, streamurl => $FEATURES{LIVESTREAM} ? sprintf("%s%s?aktion=live_stream&channel=%s&progname=%s", $MyStreamBase, $CONFIG{TV_EXT}, $event->[EV_VDR_ID], uri_escape($event->[EV_CHANNEL_NAME])) : undef, switchurl => "$MyURL?aktion=prog_switch&channel=" . $event->[EV_VDR_ID], proglink => "$MyURL?aktion=prog_list&vdr_id=" . $event->[EV_VDR_ID] } ); $dayflag++; } if ($dayflag == 2) { my $search_title = $event->[EV_TITLE]; $search_title =~ s/^.*\~\%*([^\~]*)$/$1/; $search_title = uri_escape($search_title); my $imdb_url = undef; if ($search_title && $CONFIG{SRCH1_ACTIVE}) { $imdb_url = $CONFIG{SRCH1_URL}; $imdb_url =~ s/\%TITLE\%/$search_title/g; } my $srch2_url = undef; if ($search_title && $CONFIG{SRCH2_ACTIVE}) { $srch2_url = $CONFIG{SRCH2_URL}; $srch2_url =~ s/\%TITLE\%/$search_title/g; } my $subtitle = ""; if ($CONFIG{EPG_SUBTITLE}) { $subtitle = CGI::escapeHTML($event->[EV_SUBTITLE]); } if ($CONFIG{EPG_SUMMARY}) { if (length($subtitle)) { $subtitle .= "
    "; } $subtitle .= CGI::escapeHTML($event->[EV_SUMMARY]); $subtitle =~ s/\|/
    /g; } my $timerset = 0; foreach my $timer (@timers) { if (($timer->{vdr_id} == $vdr_id) && ($timer->{start} <= $event->[EV_START]) && ($timer->{stop} >= $event->[EV_STOP])) { $timerset = 1; last; } } push(@show, { ssse => $event->[EV_START], emit => my_strftime("%H:%M", $event->[EV_START]), duration => my_strftime("%H:%M", $event->[EV_STOP]), title => CGI::escapeHTML($event->[EV_TITLE]), subtitle => $subtitle, recurl => sprintf("%s?aktion=timer_new_form&epg_id=%s&vdr_id=%s&referer=%s", $MyURL, $event->[EV_EVENT_ID], $event->[EV_VDR_ID], $myself), infurl => $event->[EV_SUMMARY] ? sprintf("%s?aktion=prog_detail&epg_id=%s&vdr_id=%s&referer=%s", $MyURL, $event->[EV_EVENT_ID], $event->[EV_VDR_ID], $myself) : undef, editurl => sprintf("%s?aktion=prog_detail_form&epg_id=%s&vdr_id=%s&referer=%s", $MyURL, $event->[EV_EVENT_ID], $event->[EV_VDR_ID], $myself), find_title => uri_escape("/^" . my_quotemeta($event->[EV_TITLE] . "~" . ($event->[EV_SUBTITLE] ? $event->[EV_SUBTITLE] : "") . "~") . "/"), srch1_url => $imdb_url, srch1_title => $imdb_url ? gettext($CONFIG{SRCH1_TITLE}) : undef, srch2_url => $srch2_url, srch2_title => $srch2_url ? gettext($CONFIG{SRCH2_TITLE}) : undef, newd => 0, anchor => "id" . $event->[EV_EVENT_ID], timerset => $timerset } ); } } push(@show, { endd => 1 }); } elsif ($CONFIG{CHANNELS_WITHOUT_EPG}) { push(@show, { channel_name => $_->{name}, longdate => '', newd => 1, streamurl => $FEATURES{LIVESTREAM} ? sprintf("%s%s?aktion=live_stream&channel=%s&progname=%s", $MyStreamBase, $CONFIG{TV_EXT}, $vdr_id, uri_escape($_->{name})) : undef, switchurl => "$MyURL?aktion=prog_switch&channel=" . $vdr_id, proglink => "$MyURL?aktion=prog_list&vdr_id=" . $vdr_id } ); push(@show, { title => gettext("No EPG information available"), newd => 0, } ); push(@show, { endd => 1 }); } } # end: for $vdr_id my @days; foreach (keys %hash_days) { push(@days, { name => $hash_days{$_}, id => "$MyURL?aktion=prog_list2&day=" . $_, sort => $_, sel => $_ == $day ? "1" : undef } ); } @days = sort({ $a->{sort} <=> $b->{sort} } @days); my $prev_day; my $prev_day_name; my $cur_day; my $next_day; my $next_day_name; foreach (@days) { if($_->{sort} == $day) { $cur_day = $_->{sort}; next; } elsif($cur_day) { $next_day = $_->{sort}; $next_day_name = $_->{name}; last; } unless($cur_day) { $prev_day = $_->{sort}; $prev_day_name = $_->{name}; } } # my $vars = { title => $day == $current_day ? gettext("Playing Today") : ($day == $current_day + 1 ? gettext("Playing Tomorrow") : sprintf(gettext("Playing on the %s"), $hash_days{$day})), now => my_strftime("%H:%M", $time), day => $day, days => \@days, url => $MyURL, loop => \@show, chanloop => \@channel, progname => GetChannelDescByNumber($vdr_id), switchurl => "$MyURL?aktion=prog_switch&channel=" . $vdr_id, stream_live_on => $FEATURES{LIVESTREAM} && $CONFIG{ST_FUNC} && $CONFIG{ST_LIVE_ON}, prevdayurl => $prev_day ? "$MyURL?aktion=prog_list2&day=" . $prev_day . ($param_time ? "&time=$param_time" : "") : undef, nextdayurl => $next_day ? "$MyURL?aktion=prog_list2&day=" . $next_day . ($param_time ? "&time=$param_time" : "") : undef, prevdaytext => $prev_day_name, nextdaytext => $next_day_name, toolbarurl => "$MyURL?aktion=toolbar", ch_groups => getChannelGroups("$MyURL?aktion=prog_list2&day=" . $cur_day . ($param_time ? "&time=$param_time" : ""), $CONFIG{CHANNELS_WANTED_PRG2}) }; return showTemplate("prog_list2.html", $vars); } ############################################################################# # regular timers ############################################################################# sub timer_list { return if (UptoDate() != 0); $CONFIG{TM_DESC} = ($q->param("desc") ? 1 : 0) if (defined($q->param("desc"))); $CONFIG{TM_SORTBY} = $q->param("sortby") if (defined($q->param("sortby"))); $CONFIG{TM_SORTBY} = "day" if (!$CONFIG{TM_SORTBY}); # my @timer; my @timer2; my @days; my $myself = Encode_Referer($MyURL . "?" . $Query); my ($TagAnfang, $TagEnde); for my $timer (ParseTimer(0)) { # VDR >= 1.3.24 reports if it's recording, so don't overwrite it here if ($FEATURES{VDRVERSION} < 10324 && $timer->{recording} == 0 && $timer->{startsse} < time() && $timer->{stopsse} > time() && ($timer->{active} & 1)) { $timer->{recording} = 1; } $timer->{active} = 0 unless ($timer->{active} & 1); $timer->{delurl} = $MyURL . "?aktion=timer_delete&timer_id=" . $timer->{id}, $timer->{modurl} = $MyURL . "?aktion=timer_new_form&timer_id=" . $timer->{id}, $timer->{toggleurl} = sprintf("%s?aktion=timer_toggle&active=%s&id=%s", $MyURL, ($timer->{active} & 1) ? 0 : 1, $timer->{id}), #TODO: nur id? $timer->{dor} = my_strftime("%a %d.%m", $timer->{startsse}); #TODO: localize date $timer->{title} = CGI::escapeHTML($timer->{title}); $TagAnfang = my_mktime(0, 0, my_strftime("%d", $timer->{start}), my_strftime("%m", $timer->{start}), my_strftime("%Y", $timer->{start})); $TagEnde = my_mktime(0, 0, my_strftime("%d", $timer->{stop}), my_strftime("%m", $timer->{stop}), my_strftime("%Y", $timer->{stop})); $timer->{duration} = ($timer->{stop} - $timer->{start}) / 60; $timer->{startlong} = ((my_mktime(my_strftime("%M", $timer->{start}), my_strftime("%H", $timer->{start}), my_strftime("%d", $timer->{start}), my_strftime("%m", $timer->{start}), my_strftime("%Y", $timer->{start}))) - $TagAnfang) / 60; $timer->{stoplong} = ((my_mktime(my_strftime("%M", $timer->{stop}), my_strftime("%H", $timer->{stop}), my_strftime("%d", $timer->{stop}), my_strftime("%m", $timer->{stop}), my_strftime("%Y", $timer->{stop}))) - $TagEnde) / 60; $timer->{starttime} = my_strftime("%y%m%d", $timer->{startsse}); $timer->{stoptime} = my_strftime("%y%m%d", $timer->{stopsse}); $timer->{sortfield} = $timer->{cdesc} . $timer->{startsse}; $timer->{infurl} = $timer->{event_id} ? sprintf("%s?aktion=prog_detail&epg_id=%s&vdr_id=%s&referer=%s", $MyURL, $timer->{event_id}, $timer->{vdr_id}, $myself) : undef, $timer->{start} = my_strftime("%H:%M", $timer->{start}); $timer->{stop} = my_strftime("%H:%M", $timer->{stop}); $timer->{sortbyactive} = 1 if ($CONFIG{TM_SORTBY} eq "active"); $timer->{sortbychannel} = 1 if ($CONFIG{TM_SORTBY} eq "channel"); $timer->{sortbyname} = 1 if ($CONFIG{TM_SORTBY} eq "name"); $timer->{sortbystart} = 1 if ($CONFIG{TM_SORTBY} eq "start"); $timer->{sortbystop} = 1 if ($CONFIG{TM_SORTBY} eq "stop"); $timer->{sortbyday} = 1 if ($CONFIG{TM_SORTBY} eq "day"); $timer->{transponder} = get_transponder_from_vdrid($timer->{vdr_id}); $timer->{ca} = get_ca_from_vdrid($timer->{vdr_id}); push(@timer, $timer); } @timer = sort({ $a->{startsse} <=> $b->{startsse} } @timer); # if ($CONFIG{RECORDINGS}) { my ($ii, $jj, $timer, $last); for ($ii = 0 ; $ii < @timer ; $ii++) { if ($timer[$ii]->{first} == -1 || $timer[$ii]->{first} == 1) { $last = $ii; } # Liste der benutzten Transponder my @Transponder = $timer[$ii]->{transponder}; $timer[$ii]->{collision} = 0; for ($jj = 0 ; $jj < $ii ; $jj++) { if ( $timer[$ii]->{startsse} >= $timer[$jj]->{startsse} && $timer[$ii]->{startsse} < $timer[$jj]->{stopsse}) { if ($timer[$ii]->{active} && $timer[$jj]->{active}) { # Timer kollidieren zeitlich. Pruefen, ob die Timer evtl. auf # gleichem Transponder oder CAM liegen und daher ohne Probleme # aufgenommen werden koennen Log(LOG_DEBUG, sprintf("[TIMER] Collision: %s (%s, %s) -- %s (%s, %s)\n", substr($timer[$ii]->{title}, 0, 15), $timer[$ii]->{vdr_id}, $timer[$ii]->{transponder}, $timer[$ii]->{ca}, substr($timer[$jj]->{title}, 0, 15), $timer[$jj]->{vdr_id}, $timer[$jj]->{transponder}, $timer[$jj]->{ca})); if ( $timer[$ii]->{vdr_id} != $timer[$jj]->{vdr_id} && $timer[$ii]->{ca} == $timer[$jj]->{ca} && $timer[$ii]->{ca} >= 100) { # Beide Timer laufen auf dem gleichen CAM auf verschiedenen # Kanaelen, davon kann nur einer aufgenommen werden Log(LOG_DEBUG, "[TIMER] Both channels use same CAM"); #($timer[$ii]->{collision}) = $CONFIG{RECORDINGS}; #OLDIMPL ($timer[$ii]->{collision})++; #NEWIMPL # Nur Kosmetik: Transponderliste vervollstaendigen push(@Transponder, $timer[$jj]->{transponder}); } else { # "grep" prueft die Bedingung fuer jedes Element, daher den # Transponder vorher zwischenspeichern -- ist effizienter my $t = $timer[$jj]->{transponder}; if (scalar(grep($_ eq $t, @Transponder)) == 0) { ($timer[$ii]->{collision})++; push(@Transponder, $timer[$jj]->{transponder}); } } } } } } splice(@timer, $last + 1); for ($ii = 0 ; $ii < @timer ; $ii++) { $timer[$ii]->{critical} = $timer[$ii]->{collision} >= $CONFIG{RECORDINGS}; if ($timer[$ii]->{critical} > 0) { for ($jj = $ii - 1 ; $jj >= 0 ; $jj--) { if ($timer[$jj]->{stopsse} > $timer[$ii]->{startsse}) { $timer[$jj]->{critical} = 1; } else { last; } } } $timer[$ii]->{collision} = $timer[$ii]->{collision} >= ($CONFIG{RECORDINGS} - 1); if ($timer[$ii]->{collision} > 0) { for ($jj = $ii - 1 ; $jj >= 0 ; $jj--) { if ($timer[$jj]->{stopsse} > $timer[$ii]->{startsse}) { $timer[$jj]->{collision} = 1; } else { last; } } } #$timer[$ii]->{collision} |= ($timer[$ii]->{ca} >= 100); #OLDIMPL } } # my ($ii, $jj, $kk, $current, $title); for ($ii = 0 ; $ii < @timer ; $ii++) { if ($ii == 0) { if (!defined($q->param("timer"))) { $current = my_strftime("%y%m%d", $timer[$ii]->{startsse}); my $current_day = my_strftime("%y%m%d", time()); $current = $current_day if ($current < $current_day); $title = my_strftime("%A, %x", $timer[$ii]->{startsse}); } else { $current = $q->param("timer"); $kk = my_mktime(0, 0, substr($current, 4, 2), substr($current, 2, 2) - 1, "20" . substr($current, 0, 2)); $title = my_strftime("%A, %x", $kk); } } $jj = 0; for ($kk = 0 ; $kk < @days ; $kk++) { if ($days[$kk]->{day} == my_strftime("%d.%m", $timer[$ii]->{startsse})) { $jj = 1; last; } } if ($jj == 0) { push(@days, { day => my_strftime("%d.%m", $timer[$ii]->{startsse}), sortfield => my_strftime("%y%m%d", $timer[$ii]->{startsse}), current => ($current == my_strftime("%y%m%d", $timer[$ii]->{startsse})) ? 1 : 0, } ); } $jj = 0; for ($kk = 0 ; $kk < @days ; $kk++) { if ($days[$kk]->{day} == my_strftime("%d.%m", $timer[$ii]->{stopsse})) { $jj = 1; last; } } if ($jj == 0) { push(@days, { day => my_strftime("%d.%m", $timer[$ii]->{stopsse}), sortfield => my_strftime("%y%m%d", $timer[$ii]->{stopsse}), current => ($current == my_strftime("%y%m%d", $timer[$ii]->{stopsse})) ? 1 : 0, } ); } } @days = sort({ $a->{sortfield} <=> $b->{sortfield} } @days); my $prev_day; my $prev_day_name; my $next_day; my $next_day_name; my $cur_day; foreach (@days) { if ($_->{current}) { $cur_day = $_->{sortfield}; next; } if ($cur_day) { $next_day = $_->{sortfield}; $next_day_name = $_->{day}; last; } else { $prev_day = $_->{sortfield}; $prev_day_name = $_->{day}; } } # if ($CONFIG{TM_SORTBY} eq "active") { if ($CONFIG{TM_DESC}) { @timer = sort({ $b->{active} <=> $a->{active} } @timer); } else { @timer = sort({ $a->{active} <=> $b->{active} } @timer); } } elsif ($CONFIG{TM_SORTBY} eq "channel") { if ($CONFIG{TM_DESC}) { @timer = sort({ ciCmp($b->{cdesc}, $a->{cdesc}) } @timer); } else { @timer = sort({ ciCmp($a->{cdesc}, $b->{cdesc}) } @timer); } } elsif ($CONFIG{TM_SORTBY} eq "name") { if ($CONFIG{TM_DESC}) { @timer = sort({ ciCmp($b->{title}, $a->{title}) } @timer); } else { @timer = sort({ ciCmp($a->{title}, $b->{title}) } @timer); } } elsif ($CONFIG{TM_SORTBY} eq "start") { if ($CONFIG{TM_DESC}) { @timer = sort({ $b->{start} <=> $a->{start} } @timer); } else { @timer = sort({ $a->{start} <=> $b->{start} } @timer); } } elsif ($CONFIG{TM_SORTBY} eq "stop") { if ($CONFIG{TM_DESC}) { @timer = sort({ $b->{stop} <=> $a->{stop} } @timer); } else { @timer = sort({ $a->{stop} <=> $b->{stop} } @timer); } } elsif ($CONFIG{TM_SORTBY} eq "day") { if ($CONFIG{TM_DESC}) { @timer = sort({ $b->{startsse} <=> $a->{startsse} } @timer); } else { @timer = sort({ $a->{startsse} <=> $b->{startsse} } @timer); } } my $toggle_desc = ($CONFIG{TM_DESC} ? 0 : 1); @timer2 = @timer; @timer2 = sort({ ciCmp($a->{sortfield}, $b->{sortfield}) } @timer2); my $vars = { sortbydayurl => "$MyURL?aktion=timer_list&sortby=day&desc=" . (($CONFIG{TM_SORTBY} eq "day") ? $toggle_desc : $CONFIG{TM_DESC}), sortbychannelurl => "$MyURL?aktion=timer_list&sortby=channel&desc=" . (($CONFIG{TM_SORTBY} eq "channel") ? $toggle_desc : $CONFIG{TM_DESC}), sortbynameurl => "$MyURL?aktion=timer_list&sortby=name&desc=" . (($CONFIG{TM_SORTBY} eq "name") ? $toggle_desc : $CONFIG{TM_DESC}), sortbyactiveurl => "$MyURL?aktion=timer_list&sortby=active&desc=" . (($CONFIG{TM_SORTBY} eq "active") ? $toggle_desc : $CONFIG{TM_DESC}), sortbystarturl => "$MyURL?aktion=timer_list&sortby=start&desc=" . (($CONFIG{TM_SORTBY} eq "start") ? $toggle_desc : $CONFIG{TM_DESC}), sortbystopurl => "$MyURL?aktion=timer_list&sortby=stop&desc=" . (($CONFIG{TM_SORTBY} eq "stop") ? $toggle_desc : $CONFIG{TM_DESC}), sortbyday => ($CONFIG{TM_SORTBY} eq "day") ? 1 : 0, sortbychannel => ($CONFIG{TM_SORTBY} eq "channel") ? 1 : 0, sortbyname => ($CONFIG{TM_SORTBY} eq "name") ? 1 : 0, sortbyactive => ($CONFIG{TM_SORTBY} eq "active") ? 1 : 0, sortbystart => ($CONFIG{TM_SORTBY} eq "start") ? 1 : 0, sortbystop => ($CONFIG{TM_SORTBY} eq "stop") ? 1 : 0, sortby => $CONFIG{TM_SORTBY}, desc => $CONFIG{TM_DESC} ? "desc" : "asc", timer_loop => \@timer, timers => \@timer2, timers2 => \@timer2, day_loop => \@days, url => $MyURL, help_url => HelpURL("timer_list"), current => $current, title => $title, activateurl => sprintf("%s?aktion=timer_toggle&active=1", $MyURL), inactivateurl => sprintf("%s?aktion=timer_toggle&active=0", $MyURL), prevdayurl => $prev_day ? sprintf("%s?aktion=timer_list&active=0&timer=%s", $MyURL, $prev_day) : undef, nextdayurl => $next_day ? sprintf("%s?aktion=timer_list&active=0&timer=%s", $MyURL, $next_day) : undef, prevdaytext => $prev_day_name, nextdaytext => $next_day_name, my_truncate => \&my_truncate }; return showTemplate("timer_list.html", $vars); } sub timer_toggle { UptoDate(); my $id = $q->param("id"); if ($id) { my $active = $q->param("active"); SendCMD(sprintf("modt %s %s", $id, $active ? "on" : "off")); # XXX check return } else { my $active; $active = "on" if ($q->param("timer_active")); $active = "off" if ($q->param("timer_inactive")); if ($active) { my @sorted; for ($q->param) { if (/xxxx_(.*)/) { push(@sorted, $1); } } @sorted = sort({ $b <=> $a } @sorted); for my $t (@sorted) { SendCMD(sprintf("modt %s %s", $t, $active)); # XXX check return } CloseSocket(); } } return RedirectToReferer("$MyURL?aktion=timer_list"); } sub timer_new_form { UptoDate(); my $epg_id = $q->param("epg_id"); my $vdr_id = $q->param("vdr_id"); my $timer_id = $q->param("timer_id"); if ($q->param("channel_id")) { $vdr_id = get_vdrid_from_channelid($q->param("channel_id")); } my $this_event; if ($epg_id) { # new timer my $this = EPG_getEntry($vdr_id, $epg_id); $this_event->{active} = 1; $this_event->{event_id} = $this->[EV_EVENT_ID]; $this_event->{start} = $this->[EV_START] - ($CONFIG{TM_MARGIN_BEGIN} * 60); $this_event->{stop} = $this->[EV_STOP] + ($CONFIG{TM_MARGIN_END} * 60); #$this_event->{dor} = $this->{dor}; $this_event->{title} = $this->[EV_TITLE]; # Do NOT append EPG summary if VDR >= 10344 as this will be done by VDR itself $this_event->{summary} = $this->[EV_SUMMARY] if ($FEATURES{VDRVERSION} < 10344); $this_event->{vdr_id} = $this->[EV_VDR_ID]; if ($FEATURES{EPGSEARCH}) { $this_event->{tool} = $TOOL_EPGSEARCH; $this_event->{at_epg} = 1; $this_event->{autotimer} = epgsearch_getDefTimerCheckMethode($q->param("channel_id") ? $q->param("channel_id") : get_channelid_from_vdrid($vdr_id)); } elsif ($FEATURES{AUTOTIMER}) { $this_event->{tool} = $TOOL_AUTOTIMER; $this_event->{at_epg} = $this_event->{event_id} ? can_do_eventid_autotimer($this_event->{vdr_id}) : 0; $this_event->{autotimer} = $this_event->{at_epg} ? $AT_BY_EVENT_ID : $AT_BY_TIME; } } elsif ($timer_id) { # edit existing timer $this_event = ParseTimer(0, $timer_id); if (($this_event->{tool} == $TOOL_EPGSEARCH) && $this_event->{pattern}) { $this_event->{hide_at_check} = 1; } $this_event->{at_epg} = $this_event->{event_id} ? 1 : 0; $this_event->{autotimer} = 0 unless($this_event->{autotimer}); } else { # none of the above $this_event->{start} = time(); $this_event->{stop} = 0; $this_event->{active} = 1; $this_event->{vdr_id} = 1; } my @channels; for my $channel (@{$CHAN{$CHAN_FULL}->{channels}}) { ($channel->{vdr_id} == $this_event->{vdr_id}) ? ($channel->{current} = 1) : ($channel->{current} = 0); push(@channels, $channel); } # determine referer (redirect to where we come from) my $ref = getReferer(); my $displaysummary = $this_event->{summary}; $displaysummary =~ s/\|/\n/g if ($displaysummary); my $vars = { url => $MyURL, active => $this_event->{active} & 1, event_id => $this_event->{event_id}, starth => my_strftime("%H", $this_event->{start}), startm => my_strftime("%M", $this_event->{start}), bstart => ($this_event->{tool} == $TOOL_EPGSEARCH ? $this_event->{bstart} / 60 :$this_event->{bstart}), stoph => $this_event->{stop} ? my_strftime("%H", $this_event->{stop}) : "00", stopm => $this_event->{stop} ? my_strftime("%M", $this_event->{stop}) : "00", bstop => ($this_event->{tool} == $TOOL_EPGSEARCH ? $this_event->{bstop} / 60 : $this_event->{bstop}), vps => $this_event->{active} & 4, dor => ($this_event->{dor} && (length($this_event->{dor}) == 7 || length($this_event->{dor}) == 10 || length($this_event->{dor}) == 18)) ? $this_event->{dor} : my_strftime("%d", $this_event->{start}), prio => $this_event->{prio} ne "" ? $this_event->{prio} : $CONFIG{TM_PRIORITY}, lft => $this_event->{lft} ne "" ? $this_event->{lft} : $CONFIG{TM_LIFETIME}, title => $this_event->{title}, summary => $displaysummary, pattern => $this_event->{pattern}, timer_id => $timer_id ? $timer_id : 0, channels => \@channels, newtimer => $timer_id ? 0 : 1, autotimer => $this_event->{autotimer}, at_epg => $this_event->{at_epg}, hide_at_check => $this_event->{hide_at_check}, referer => $ref ? Encode_Referer($ref) : undef, tool => $this_event->{tool}, help_url => HelpURL("timer_new") }; return showTemplate("timer_new.html", $vars); } sub timer_add { my $timer_id = $q->param("timer_id"); my $data; if ($q->param("save")) { my $value = $q->param("starth"); if ($value =~ /\d+/ && $value < 24 && $value >= 0) { $data->{start} = sprintf("%02d", $value); } else { print "Help!\n"; $data->{start} = "00"; } $value = $q->param("startm"); if ($value =~ /\d+/ && $value < 60 && $value >= 0) { $data->{start} .= sprintf("%02d", $value); } else { print "Help!\n"; $data->{start} .= "00"; } $value = $q->param("stoph"); if ($value =~ /\d+/ && $value < 24 && $value >= 0) { $data->{stop} = sprintf("%02d", $value); } else { print "Help!\n"; $data->{stop} = "00"; } $value = $q->param("stopm"); if ($value =~ /\d+/ && $value < 60 && $value >= 0) { $data->{stop} .= sprintf("%02d", $value); } else { print "Help!\n"; $data->{stop} .= "00"; } $data->{active} = $q->param("active"); $data->{autotimer} = $q->param("autotimer"); $data->{event_id} = $q->param("event_id"); $data->{prio} = $1 if ($q->param("prio") =~ /(\d+)/); $data->{lft} = $1 if ($q->param("lft") =~ /(\d+)/); $data->{dor} = $1 if ($q->param("dor") =~ /([0-9MTWTFSS@\-]+)/); $data->{channel} = $1 if ($q->param("channel") =~ /(\d+)/); $data->{active} |= 4 if ($q->param("vps") && $q->param("vps") == 1); if (length($q->param("title")) > 0) { $data->{title} = $q->param("title"); } else { $data->{title} = GetChannelDescByNumber($data->{channel}) if ($data->{channel}); } if (length($q->param("summary")) > 0) { $data->{summary} = $q->param("summary"); #$data->{summary} =~ s/\://g; # summary may have colons (man vdr.5) $data->{summary} =~ s/\r//g; $data->{summary} =~ s/\n/|/g; } my $dor = $data->{dor}; if (length($data->{dor}) == 7 || length($data->{dor}) == 10 || length($data->{dor}) == 18) { # dummy $dor = 1; } $data->{startsse} = my_mktime(substr($data->{start}, 2, 2), substr($data->{start}, 0, 2), $dor, (my_strftime("%m") - 1), my_strftime("%Y")); $data->{stopsse} = my_mktime(substr($data->{stop}, 2, 2), substr($data->{stop}, 0, 2), $data->{stop} > $data->{start} ? $dor : $dor + 1, (my_strftime("%m") - 1), my_strftime("%Y")); $data->{event_id} = 0 unless (can_do_eventid_autotimer($data->{channel})); $data->{tool} = $q->param("tool"); my $return = ProgTimer( $timer_id, $data->{active}, $data->{event_id}, $data->{channel}, $data->{startsse}, $data->{stopsse}, $data->{prio} ne "" ? $data->{prio} : $CONFIG{TM_PRIORITY}, $data->{lft} ne "" ? $data->{lft} : $CONFIG{TM_LIFETIME}, $data->{title}, append_timer_metadata( $data->{summary}, $data->{event_id}, $data->{autotimer}, $CONFIG{TM_MARGIN_BEGIN}, $CONFIG{TM_MARGIN_END}, undef, $data->{tool}), ($dor == 1) ? $data->{dor} : undef); } my $ref = getReferer(); if ($ref) { return (headerForward($ref)); } else { return (headerForward("$MyURL?aktion=timer_list")); } } sub timer_delete { my $timer_id = $q->param('timer_id'); if ($timer_id) { my ($result) = SendCMD("delt $timer_id"); if ($result =~ /Timer "$timer_id" is recording/i) { SendCMD("modt $timer_id off"); sleep(1); SendCMD("delt $timer_id"); } } else { my @sorted; for ($q->param) { if (/xxxx_(.*)/) { push(@sorted, $1); } } @sorted = sort({ $b <=> $a } @sorted); for my $t (@sorted) { my ($result) = SendCMD("delt $t"); if ($result =~ /Timer "$t" is recording/i) { SendCMD("modt $t off"); sleep(1); SendCMD("delt $t"); } } CloseSocket(); } return RedirectToReferer("$MyURL?aktion=timer_list"); } sub getRecordingsPlaylist { my @playlist = (); my $response = HTTP::Tiny->new()->get(streamdevURI()->as_string() . "/recordings.m3u"); if ($response->{success}) { my $content_charset = "UTF-8"; # Content-Type: audio/x-mpegurl; charset=UTF-8 if ($response->{headers}->{'content-type'} && $response->{headers}->{'content-type'} =~ /[ ;]+charset=([^ ;]+)/) { $content_charset = $1; } Encode::from_to($response->{content}, $content_charset, $MY_ENCODING); my $extinf = 1; my $rec; foreach my $line (split(/[ \r]*\n/, $response->{content})) { if ($extinf && $line =~ /^#EXTINF:-1,(\d+)\s+(\d\d\.\d\d\.\d\d)\s+(\d\d:\d\d)\s+(.*)$/) { $extinf = 0; $rec = {id => $1, date => $2, time => $3, title => $4, url => undef}; } if (!$extinf && $line =~ /^http/) { $extinf = 1; $rec->{url} = $line; push(@playlist, $rec); $rec = undef; } } } return @playlist; } sub rec_stream { my $id = $q->param('id'); my ($i, $title, $newtitle); my $data; my ($date, $time); for (SendCMD("lstr")) { if ($FEATURES{VDRVERSION} < 10721) { ($i, $date, $time, $title) = split(/ +/, $_, 4); } else { ($i, $date, $time, undef, $title) = split(/ +/, $_, 5); } last if ($id == $i); } $time = substr($time, 0, 5); # needed for wareagel-patch if ($id == $i) { my @urls = (); $title =~ s/[ ~]+$//; if ($CONFIG{ST_REC_STREAMDEV} && $FEATURES{STREAMDEV}) { foreach my $r (getRecordingsPlaylist()) { if ($date eq $r->{date} && $time eq $r->{time} && $title eq $r->{title}) { push (@urls, $r->{url}); } } if ($CONFIG{ST_DIRECT_LINKS_ON} && @urls) { return headerForward($urls[0]); } } else { # VFAT off @urls = findVideoFiles($date, $time, encode_RecTitle($title, 0)); # VFAT on @urls = findVideoFiles($date, $time, encode_RecTitle($title, 1)) unless (@urls); } if (@urls) { $data = "#EXTM3U\n"; foreach my $url (@urls) { $data .= sprintf("#EXTINF:-1,%s %s %s\n%s\n", $date, $time, $title, $url); } } } return (header("200", $CONFIG{REC_MIMETYPE}, $data)); } sub rec_stream_folder { # return prog_summary(); my $parent = $q->param("parent"); if (!$parent) { $parent = 0; } else { $parent = uri_escape($parent); } ParseRecordings($parent); my @recordings = @RECORDINGS; # sort by date @recordings = sort({ $b->{isfolder} <=> $a->{isfolder} || ciCmp($b->{isfolder} ? $a->{name} : "", $a->{isfolder} ? $b->{name} : "") || $a->{sse} <=> $b->{sse} } @recordings); my $folder_data; my @streamdev_recordings; if ($CONFIG{ST_REC_STREAMDEV} && $FEATURES{STREAMDEV}) { @streamdev_recordings = getRecordingsPlaylist(); } for my $recording (@recordings) { if (!$recording->{isfolder} && $recording->{parent} eq $parent) { # inplace playlist my ($id) = $recording->{recording_id}; my ($i, $title, $newtitle); my ($date, $time); $date = $recording->{date}; $time = $recording->{time}; $title = $recording->{name}; my @urls = (); $title = CGI::unescape($parent) . "~" . $title if ($parent); $title =~ s/[ ~]+$//; if ($CONFIG{ST_REC_STREAMDEV} && $FEATURES{STREAMDEV}) { #$title = $parent_orig if ($parent_orig && !$title); foreach my $r (@streamdev_recordings) { if ($date eq $r->{date} && $time eq $r->{time} && $title eq $r->{title}) { push (@urls, $r->{url}); } } } else { # VFAT off @urls = findVideoFiles($date, $time, encode_RecTitle($title, 0)); # VFAT on @urls = findVideoFiles($date, $time, encode_RecTitle($title, 1)) unless (@urls); } if (@urls) { $folder_data = "#EXTM3U\n" unless ($folder_data); foreach my $url (@urls) { $folder_data .= sprintf("#EXTINF:-1,%s %s %s\n%s\n", $date, $time, $title, $url); } } } } return (header("200", $CONFIG{TV_MIMETYPE}, $folder_data, sprintf("vdradmin.%s", $CONFIG{TV_EXT}) )); } sub encode_RecTitle { my ($title, $use_vfat) = @_; my ($c, $i, $newtitle); if ($use_vfat) { # VFAT on for ($i = 0 ; $i < length($title) ; $i++) { $c = substr($title, $i, 1); unless ($c =~ /[öäüßÖÄÜA-Za-z0123456789_!@\$%&()+,.\-;=~ ]/) { $newtitle .= sprintf("#%02X", ord($c)); } else { $newtitle .= $c; } } } else { # VFAT off for ($i = 0 ; $i < length($title) ; $i++) { $c = substr($title, $i, 1); if ($c eq "/") { $newtitle .= "\x02"; } elsif ($c eq "\\") { $newtitle .= "\x01"; } else { $newtitle .= $c; } } } return $newtitle; } sub findVideoFiles { # VDR < v1.7.2: YYYY-MM-DD-hh[.:]mm.pr.lt.rec (pr=priority, lt=lifetime) # VDR >= v1.7.2: YYYY-MM-DD-hh.mm.ch-ri.rec (ch=channel, ri=resumeId) my ($date, $time, $title) = @_; # DD.MM.YY and hh:mm my ($year, $month, $day, $hour, $minute); ($day, $month, $year) = ($1, $2, $3) if ($date =~ /(\d\d).(\d\d).(\d\d)/); ($hour, $minute) = ($1, $2) if ($time =~ /(\d\d):(\d\d)/); return () unless (defined($day) && defined($hour)); $title =~ s/ /_/g; $title =~ s/~/\//g; $title = quotemeta $title; my $re_compiled = qr"$CONFIG{VIDEODIR}/$title\_*/(_/)?\d{2}$year-$month-$day\.$hour[.:]$minute\.\d+[-.]\d+\.rec/\d{3}(\.vdr|\d{2}\.ts)"; sub find_files { my ($dir, $regex) = @_; my @arr = (); File::Find::find({ wanted => sub {push(@arr, $File::Find::name) if $File::Find::name =~ $regex}, follow => 1, no_chdir => 1}, $dir); return @arr; } my @ret = (); foreach my $path (sort(find_files($CONFIG{VIDEODIR}, $re_compiled))) { chomp; Log(LOG_DEBUG, "[REC] findVideoFiles: found ($path)\n"); $path =~ s/$CONFIG{VIDEODIR}/$CONFIG{ST_VIDEODIR}/; $path =~ s/\n//g; $path = $CONFIG{ST_URL} . $path; $path =~ s/#/%23/g if ($path =~ /^http/); push(@ret, $path) } return @ret; } sub getReferer { my $epg_id = $q->param("epg_id"); my $ref = $q->param("referer"); if ($ref) { $ref = Decode_Referer($ref); if ($ref =~ /#/) { return $ref; } else { return sprintf("%s%s", $ref, $epg_id ? "#id$epg_id" : ""); } } else { return undef; } } ############################################################################# # live streaming ############################################################################# sub streamdevURI { my $url; if ($CONFIG{ST_STREAMDEV_HOST}) { $url = URI->new("http://$CONFIG{ST_STREAMDEV_HOST}"); } elsif ($CONFIG{VDR_HOST} =~ /^localhost(\.localdomain)?|127\.0\.0\.1$/i) { $url = URI->new($q->url(-base => 1)); $url->scheme("http"); } else { $url = URI->new("http://$CONFIG{VDR_HOST}"); } if ($FEATURES{STREAMDEV}) { my ($port, $rest) = split(/\//, $CONFIG{ST_STREAMDEV_PORT}, 2); $url->port($port); $url->path($rest); } elsif ($FEATURES{XINELIB}) { $url->port($CONFIG{ST_XINELIB_PORT}); } return $url; } sub live_stream { my $channel = $q->param("channel"); my $progname = $q->param("progname"); my $url = streamdevURI(); if ($FEATURES{STREAMDEV}) { $url->path($url->path() . "/" . $channel); } elsif ($FEATURES{XINELIB}) { $url->port($CONFIG{ST_XINELIB_PORT}); # No channel support in xineliboutput URLs, need to switch here SendCMD("chan $channel") if $channel; } if ($CONFIG{ST_DIRECT_LINKS_ON} && $FEATURES{STREAMDEV}) { return headerForward($url); } else { my $data = ""; $data .= "#EXTINF:0,$progname\n" if ($progname); $data .= "$url\n"; return (header("200", $CONFIG{TV_MIMETYPE}, $data)); } } ############################################################################# # automatic timers ############################################################################# sub at_timer_list { return if (UptoDate() != 0); $CONFIG{AT_DESC} = ($q->param("desc") ? 1 : 0) if (defined($q->param("desc"))); $CONFIG{AT_SORTBY} = $q->param("sortby") if (defined($q->param("sortby"))); $CONFIG{AT_SORTBY} = "pattern" if (!$CONFIG{AT_SORTBY}); # my @at; my $id = 0; for (AT_Read()) { $id++; if ($_->{start}) { $_->{start} = substr($_->{start}, 0, 2) . ":" . substr($_->{start}, 2, 5); } if ($_->{stop}) { $_->{stop} = substr($_->{stop}, 0, 2) . ":" . substr($_->{stop}, 2, 5); } $_->{pattern_js} = $_->{pattern}; $_->{pattern} = CGI::escapeHTML($_->{pattern}); $_->{pattern_js} =~ s/\'/\\\'/g; $_->{pattern_js} =~ s/\"/"/g; $_->{modurl} = $MyURL . "?aktion=at_timer_edit&id=$id"; $_->{delurl} = $MyURL . "?aktion=at_timer_delete&id=$id"; $_->{prio} = $_->{prio}; $_->{lft} = $_->{lft}; $_->{id} = $id; $_->{proglink} = sprintf("%s?aktion=prog_list&vdr_id=%s", $MyURL, $_->{channel}); $_->{channel} = GetChannelDescByNumber($_->{channel}); $_->{sortbyactive} = 1 if ($CONFIG{AT_SORTBY} eq "active"); $_->{sortbychannel} = 1 if ($CONFIG{AT_SORTBY} eq "channel"); $_->{sortbypattern} = 1 if ($CONFIG{AT_SORTBY} eq "pattern"); $_->{sortbystart} = 1 if ($CONFIG{AT_SORTBY} eq "start"); $_->{sortbystop} = 1 if ($CONFIG{AT_SORTBY} eq "stop"); $_->{toggleurl} = sprintf("%s?aktion=at_timer_toggle&active=%s&id=%s", $MyURL, ($_->{active} & 1) ? 0 : 1, $_->{id}), push(@at, $_); } my @timer = sort({ lc($a->{pattern}) cmp lc($b->{pattern}) } @at); # if ($CONFIG{AT_SORTBY} eq "active") { if ($CONFIG{AT_DESC}) { @timer = sort({ $b->{active} <=> $a->{active} } @timer); } else { @timer = sort({ $a->{active} <=> $b->{active} } @timer); } } elsif ($CONFIG{AT_SORTBY} eq "channel") { if ($CONFIG{AT_DESC}) { @timer = sort({ lc($b->{channel}) cmp lc($a->{channel}) } @timer); } else { @timer = sort({ lc($a->{channel}) cmp lc($b->{channel}) } @timer); } } elsif ($CONFIG{AT_SORTBY} eq "pattern") { if ($CONFIG{AT_DESC}) { @timer = sort({ lc($b->{pattern}) cmp lc($a->{pattern}) } @timer); } else { @timer = sort({ lc($a->{pattern}) cmp lc($b->{pattern}) } @timer); } } elsif ($CONFIG{AT_SORTBY} eq "start") { if ($CONFIG{AT_DESC}) { @timer = sort({ $b->{start} <=> $a->{start} } @timer); } else { @timer = sort({ $a->{start} <=> $b->{start} } @timer); } } elsif ($CONFIG{AT_SORTBY} eq "stop") { if ($CONFIG{AT_DESC}) { @timer = sort({ $b->{stop} <=> $a->{stop} } @timer); } else { @timer = sort({ $a->{stop} <=> $b->{stop} } @timer); } } my $toggle_desc = ($CONFIG{AT_DESC} ? 0 : 1); my $vars = { sortbychannelurl => "$MyURL?aktion=at_timer_list&sortby=channel&desc=" . (($CONFIG{AT_SORTBY} eq "channel") ? $toggle_desc : $CONFIG{AT_DESC}), sortbypatternurl => "$MyURL?aktion=at_timer_list&sortby=pattern&desc=" . (($CONFIG{AT_SORTBY} eq "pattern") ? $toggle_desc : $CONFIG{AT_DESC}), sortbyactiveurl => "$MyURL?aktion=at_timer_list&sortby=active&desc=" . (($CONFIG{AT_SORTBY} eq "active") ? $toggle_desc : $CONFIG{AT_DESC}), sortbystarturl => "$MyURL?aktion=at_timer_list&sortby=start&desc=" . (($CONFIG{AT_SORTBY} eq "start") ? $toggle_desc : $CONFIG{AT_DESC}), sortbystopurl => "$MyURL?aktion=at_timer_list&sortby=stop&desc=" . (($CONFIG{AT_SORTBY} eq "stop") ? $toggle_desc : $CONFIG{AT_DESC}), sortbychannel => ($CONFIG{AT_SORTBY} eq "channel") ? 1 : 0, sortbypattern => ($CONFIG{AT_SORTBY} eq "pattern") ? 1 : 0, sortbyactive => ($CONFIG{AT_SORTBY} eq "active") ? 1 : 0, sortbystart => ($CONFIG{AT_SORTBY} eq "start") ? 1 : 0, sortbystop => ($CONFIG{AT_SORTBY} eq "stop") ? 1 : 0, desc => $CONFIG{AT_DESC} ? "desc" : "asc", at_timer_loop => \@timer, at_timer_loop2 => \@timer, url => $MyURL, help_url => HelpURL("at_timer_list") }; return showTemplate("at_timer_list.html", $vars); } sub at_timer_toggle { UptoDate(); my $active = $q->param("active"); my $id = $q->param("id"); my (@at, $z); for (AT_Read()) { $z++; if ($z == $id) { $_->{active} = $active; } push(@at, $_); } AT_Write(@at); return RedirectToReferer("$MyURL?aktion=at_timer_list"); } sub at_timer_edit { my $id = $q->param("id"); my @at = AT_Read(); # my @chans; for my $chan (@{$CHAN{$CONFIG{CHANNELS_WANTED_AUTOTIMER}}->{channels}}) { if ($chan->{vdr_id}) { $chan->{cur} = ($chan->{vdr_id} == $at[ $id - 1 ]->{channel}) ? 1 : 0; } push(@chans, $chan); } my $pattern = $at[ $id - 1 ]->{pattern}; $pattern =~ s/"/\"/g; my $vars = { channels => \@chans, id => $id, url => $MyURL, prio => $at[ $id - 1 ]->{prio}, lft => $at[ $id - 1 ]->{lft}, active => $at[ $id - 1 ]->{active}, done => $at[ $id - 1 ]->{done}, episode => $at[ $id - 1 ]->{episode}, pattern => $pattern, starth => (length($at[ $id - 1 ]->{start}) >= 4) ? substr($at[ $id - 1 ]->{start}, 0, 2) : undef, startm => (length($at[ $id - 1 ]->{start}) >= 4) ? substr($at[ $id - 1 ]->{start}, 2, 5) : undef, stoph => (length($at[ $id - 1 ]->{stop}) >= 4) ? substr($at[ $id - 1 ]->{stop}, 0, 2) : undef, stopm => (length($at[ $id - 1 ]->{stop}) >= 4) ? substr($at[ $id - 1 ]->{stop}, 2, 5) : undef, buffers => $at[ $id - 1 ]->{buffers}, bstart => $at[ $id - 1 ]->{buffers} ? $at[ $id - 1 ]->{bstart} : "", bstop => $at[ $id - 1 ]->{buffers} ? $at[ $id - 1 ]->{bstop} : "", title => ($at[ $id - 1 ]->{section} & 1) ? 1 : 0, subtitle => ($at[ $id - 1 ]->{section} & 2) ? 1 : 0, description => ($at[ $id - 1 ]->{section} & 4) ? 1 : 0, directory => $at[ $id - 1 ]->{directory}, newtimer => 0, (map { $_ => $at[ $id - 1 ]->{weekdays}->{$_} } qw (wday_mon wday_tue wday_wed wday_thu wday_fri wday_sat wday_sun)), help_url => HelpURL("at_timer_new") }; return showTemplate("at_timer_new.html", $vars); } sub at_timer_new { my $vars = { url => $MyURL, active => $q->param("active"), done => $q->param("done"), title => 1, wday_mon => 1, wday_tue => 1, wday_wed => 1, wday_thu => 1, wday_fri => 1, wday_sat => 1, wday_sun => 1, channels => \@{$CHAN{$CONFIG{CHANNELS_WANTED_AUTOTIMER}}->{channels}}, buffers => 0, bstart => "", bstop => "", prio => "", lft => "", newtimer => 1, help_url => HelpURL("at_timer_new") }; return showTemplate("at_timer_new.html", $vars); } sub at_timer_save { my $id = $q->param("id"); my $start; my $stop; if (length($q->param("starth")) > 0 || length($q->param("startm")) > 0) { $start = sprintf("%02s%02s", $q->param("starth"), $q->param("startm")); } if (length($q->param("stoph")) > 0 || length($q->param("stopm")) > 0) { $stop = sprintf("%02s%02s", $q->param("stoph"), $q->param("stopm")); } if ($q->param("save")) { if (!$id) { my @at = AT_Read(); my $section = 0; ($section += 1) if ($q->param("title")); ($section += 2) if ($q->param("subtitle")); ($section += 4) if ($q->param("description")); push(@at, { episode => $q->param("episode") ? $q->param("episode") : 0, active => $q->param("active"), done => $q->param("done"), pattern => $q->param("pattern"), section => $section, start => $start, stop => $stop, buffers => $q->param("buffers"), bstart => $q->param("buffers") ? $q->param("bstart") : "", bstop => $q->param("buffers") ? $q->param("bstop") : "", prio => $q->param("prio"), lft => $q->param("lft"), channel => $q->param("channel"), directory => $q->param("directory"), weekdays => { map { $_ => $q->param($_) ? $q->param($_) : 0 } (qw (wday_mon wday_tue wday_wed wday_thu wday_fri wday_sat wday_sun)) } } ); AT_Write(@at); } else { my $z = 0; my @at; for (AT_Read()) { $z++; if ($z != $id) { push(@at, $_); } else { my $section = 0; ($section += 1) if ($q->param("title")); ($section += 2) if ($q->param("subtitle")); ($section += 4) if ($q->param("description")); push(@at, { episode => $q->param("episode") ? $q->param("episode") : 0, active => $q->param("active"), done => $q->param("done"), pattern => $q->param("pattern"), section => $section, start => $start, stop => $stop, buffers => $q->param("buffers"), bstart => $q->param("buffers") ? $q->param("bstart") : "", bstop => $q->param("buffers") ? $q->param("bstop") : "", prio => $q->param("prio"), lft => $q->param("lft"), channel => $q->param("channel"), directory => $q->param("directory"), weekdays => { map { $_ => $q->param($_) ? $q->param($_) : 0 } (qw (wday_mon wday_tue wday_wed wday_thu wday_fri wday_sat wday_sun)) } } ); } } AT_Write(@at); } $CONFIG{CACHE_LASTUPDATE} = 0; UptoDate(); } headerForward("$MyURL?aktion=at_timer_list"); } sub at_timer_delete { my $id = $q->param("id"); my $z = 0; my @at = AT_Read(); my @new; if ($id) { for (@at) { $z++; push(@new, $_) if ($id != $z); } AT_Write(@new); } else { my @sorted; for ($q->param) { if (/xxxx_(.*)/) { push(@sorted, $1); } } @sorted = sort({ $b <=> $a } @sorted); my $z = 0; for my $at (@at) { $z++; my $push = 1; for my $sorted (@sorted) { ($push = 0) if ($z == $sorted); } push(@new, $at) if ($push); } AT_Write(@new); } headerForward("$MyURL?aktion=at_timer_list"); } sub at_timer_test { my $id = $q->param("id"); my @chans; for my $chan (@{$CHAN{$CONFIG{CHANNELS_WANTED_AUTOTIMER}}->{channels}}) { if ($chan->{vdr_id}) { $chan->{cur} = ($chan->{vdr_id} == $q->param("channel")) ? 1 : 0; } push(@chans, $chan); } my $section = 0; ($section += 1) if ($q->param("title")); ($section += 2) if ($q->param("subtitle")); ($section += 4) if ($q->param("description")); my @at = { episode => $q->param("episode") ? $q->param("episode") : 0, active => $q->param("active"), pattern => $q->param("pattern"), channel => $q->param("channel"), section => $section, start => length($q->param("starth")) > 0 || length($q->param("startm")) > 0 ? sprintf("%02s%02s", $q->param("starth"), $q->param("startm")) : undef, stop => length($q->param("stoph")) > 0 || length($q->param("stopm")) > 0 ? sprintf("%02s%02s", $q->param("stoph"), $q->param("stopm")) : undef, directory => $q->param("directory"), weekdays => { map { $_ => $q->param($_) ? $q->param($_) : 0 } (qw (wday_mon wday_tue wday_wed wday_thu wday_fri wday_sat wday_sun)) } }; my @at_matches = AutoTimer(1, @at); my $pattern = $q->param("pattern"); $pattern =~ s/"/\"/g; my $directory = $q->param("directory"); $directory =~ s/"/\"/g; my $vars = { id => $id, url => $MyURL, channels => \@chans, #TODO $q->Vars, active => $q->param("active"), pattern => $pattern, title => $q->param("title") ? $q->param("title") : 0, subtitle => $q->param("subtitle") ? $q->param("subtitle") : 0, description => $q->param("description") ? $q->param("description") : 0, wday_mon => $q->param("wday_mon") ? $q->param("wday_mon") : 0, wday_tue => $q->param("wday_tue") ? $q->param("wday_tue") : 0, wday_wed => $q->param("wday_wed") ? $q->param("wday_wed") : 0, wday_thu => $q->param("wday_thu") ? $q->param("wday_thu") : 0, wday_fri => $q->param("wday_fri") ? $q->param("wday_fri") : 0, wday_sat => $q->param("wday_sat") ? $q->param("wday_sat") : 0, wday_sun => $q->param("wday_sun") ? $q->param("wday_sun") : 0, channel => $q->param("channel"), starth => $q->param("starth"), startm => $q->param("startm"), stoph => $q->param("stoph"), stopm => $q->param("stopm"), prio => $q->param("prio"), lft => $q->param("lft"), episode => $q->param("episode") ? $q->param("episode") : 0, done => $q->param("done"), directory => $directory, at_test => 1, matches => \@at_matches }; return showTemplate("at_timer_new.html", $vars); } sub getSplittedTime { my $time = shift; if ($time) { my ($hour, $minute); if ($time =~ /(\d{1,2})(\D?)(\d{1,2})/) { if (length($1) == 1 && length($3) == 1 && !$2) { $hour = $1 . $3; } else { ($hour, $minute) = ($1, $3); } } elsif ($time =~ /\d/) { $hour = $time; } return ($hour, $minute); } else { return (my_strftime("%H"), my_strftime("%M")); } } sub getStartTime { my $time = shift; my $day = shift; my $border = shift; if ($time) { my ($hour, $minute) = getSplittedTime($time); $border = time() if (!$border); $time = timelocal(0, 0, 0, my_strftime("%d", $border), (my_strftime("%m", $border) - 1), my_strftime("%Y", $border)) + $hour * 3600 + $minute * 60; $time += 86400 if ($time < $border); return $time; } else { return time(); } } ############################################################################# # timeline ############################################################################# sub prog_timeline { return if (UptoDate() != 0); my $myself = Encode_Referer($MyURL . "?" . $Query); $CONFIG{CHANNELS_WANTED_TIMELINE} = $q->param("wanted_channels") if (defined $q->param("wanted_channels")); # zeitpunkt bestimmen my $border; if ($q->param("time")) { if ($q->param("frame")) { $border = $q->param("frame"); } else { $border = time + 1799 - $CONFIG{ZEITRAHMEN} * 3600; $border -= $border % 1800; } } my $event_time = getStartTime(scalar $q->param("time"), undef, $border); my $event_time_to; # calculate start time of the 30 min interval to avoid gaps at the beginning my $start_time = $event_time - $event_time % 1800; $event_time_to = $start_time + ($CONFIG{ZEITRAHMEN} * 3600); # Timer parsen, und erstmal alle rausschmeissen die nicht in der Zeitzone liegen my $TIM; for my $timer (ParseTimer(0)) { next if ($timer->{stopsse} <= $start_time or $timer->{startsse} >= $event_time_to); my $title = (split(/\~/, $timer->{title}))[-1]; $TIM->{$title} = $timer; } my (@show, @temp); my $shows; foreach (@{$CHAN{$CONFIG{CHANNELS_WANTED_TIMELINE}}->{channels}}) { if (ChannelHasEPG($_->{vdr_id})) { foreach my $event (sort { $a->[EV_START] <=> $b->[EV_START] } @{ $EPG{$_->{vdr_id}} }) { # Events durchgehen next if ($event->[EV_STOP] <= $start_time or $event->[EV_START] >= $event_time_to); my $progname = $event->[EV_CHANNEL_NAME]; $progname =~ s/\"/\"/g; push(@show, { start => $event->[EV_START], stop => $event->[EV_STOP], title => $event->[EV_TITLE], # subtitle => (($event->[EV_SUBTITLE] && length($event->[EV_SUBTITLE]) > 30) ? substr($event->[EV_SUBTITLE], 0, 30) . "..." : $event->[EV_SUBTITLE]), progname => $progname, summary => $event->[EV_SUMMARY], vdr_id => $event->[EV_VDR_ID], proglink => sprintf("%s?aktion=prog_list&vdr_id=%s", $MyURL, $event->[EV_VDR_ID]), # switchurl => sprintf("%s?aktion=prog_switch&channel=%s", $MyURL, $event->[EV_VDR_ID]), # infurl => ($event->[EV_SUMMARY] ? sprintf("%s?aktion=prog_detail&epg_id=%s&vdr_id=%s&referer=%s", $MyURL, $event->[EV_EVENT_ID], $event->[EV_VDR_ID], $myself) : undef), # recurl => sprintf("%s?aktion=timer_new_form&epg_id=%s&vdr_id=%s&referer=%s", $MyURL, $event->[EV_EVENT_ID], $event->[EV_VDR_ID], $myself), anchor => $event->[EV_EVENT_ID], timer => (defined $TIM->{ $event->[EV_TITLE] } && $TIM->{ $event->[EV_TITLE] }->{vdr_id} == $event->[EV_VDR_ID] && $TIM->{ $event->[EV_TITLE] }->{active} ? 1 : 0), #TODO } ); } } elsif ($CONFIG{CHANNELS_WITHOUT_EPG}) { my $progname = $_->{name}; $progname =~ s/\"/\"/g; push(@show, { progname => $progname, title => gettext("No EPG information available"), start => 0, stop => 0, vdr_id => 0, timer => 0 } ); } # needed for vdr 1.0.x, dunno why # @show = sort({ $a->{vdr_id} <=> $b->{vdr_id} } @show); push(@{ $shows->{ $_->{vdr_id} } }, @show) if @show; undef @show; } my $vars = { shows => $shows, shows2 => $shows, now_sec => $event_time, now => strftime("%H:%M", localtime($event_time)), datum => my_strftime("%A, %x", time), nowurl => $MyURL . "?aktion=prog_timeline", url => $MyURL, ch_groups => getChannelGroups($MyURL . "?aktion=prog_timeline&time=" . $q->param("time"), $CONFIG{CHANNELS_WANTED_TIMELINE}) }; return showTemplate("prog_timeline.html", $vars); } ############################################################################# # summary ############################################################################# sub prog_summary { return if (UptoDate() != 0); my $time = $q->param("time"); my $search = $q->param("search"); my $next = $q->param("next"); my $view = $CONFIG{PS_VIEW}; $view = $q->param("view") if($q->param("view")); $CONFIG{PS_VIEW} = $view; $CONFIG{CHANNELS_WANTED_SUMMARY} = $q->param("wanted_channels") if (defined $q->param("wanted_channels")); my @timers = ParseTimer(0); # zeitpunkt bestimmen my $event_time = getStartTime($time); my $pattern; my $is_regex = 0; my $ignore_case = 0; my @search_words = (); if ($search) { $pattern = $search; if ($pattern =~ /^\/(.*)\/(i?)$/) { $pattern = $1; my $mode = $2; $is_regex = 1; if ($mode eq "i") { $pattern = Encode::decode($MY_ENCODING, $pattern) if $can_use_encode; $pattern = qr/$pattern/i; Log(LOG_DEBUG, "[SEARCH] REGEX:" . Encode::encode($MY_ENCODING, $pattern) . "\n"); $ignore_case = 1; } else { $pattern = qr/$pattern/; Log(LOG_DEBUG, "[SEARCH] REGEX:" . $pattern . "\n"); } } else { $pattern = Encode::decode($MY_ENCODING, $pattern) if $can_use_encode; for my $word (split(/ +/, $pattern)) { if ($word) { if ($can_use_encode) { # case-insensitive search for 'abc' from fastest to slowest: # (?>a|A)(?>b|B)(?>c|C) on byte strings # [aA][bB][cC] on unicode strings # substr() + uc()/lc() on unicode strings # /abc/i on unicode strings my @pat = (); my $prefix; for my $ch (split(//, $word)) { if (uc($ch) ne lc($ch)) { if (!@pat && !defined($prefix)) { # first character $prefix = $ch; } else { push(@pat, "(?>"); push(@pat, lc($ch)); push(@pat, "|"); push(@pat, uc($ch)); push(@pat, ")"); } } else { push(@pat, $ch); } } if (defined($prefix)) { my $word_pat1 = Encode::encode($MY_ENCODING, join("", uc($prefix), @pat)); my $word_pat2 = Encode::encode($MY_ENCODING, join("", lc($prefix), @pat)); push(@search_words, [qr/$word_pat1/, qr/$word_pat2/]); } else { my $word_pat = Encode::encode($MY_ENCODING, join("", @pat)); push(@search_words, [qr/$word_pat/, undef]); } } else { my $word_pat = quotemeta($word); push(@search_words, [qr/$word_pat/, undef]); } } } Log(LOG_DEBUG, "[SEARCH] PATTERNS:" . join("&&", map {$_->[0] . "||" . ($_->[1] || "NULL")} @search_words) . "\n"); } } my $now = time(); my (@show, @temp); for my $channel ($search ? @{$CHAN{$CHAN_FULL}->{channels}} : @{$CHAN{$CONFIG{CHANNELS_WANTED_SUMMARY}}->{channels}}) { if (ChannelHasEPG($channel->{vdr_id})) { for my $event (@{ $EPG{$channel->{vdr_id}} }) { next if ($event->[EV_STOP] <= $now); if (!$search) { next if(!$next && $event_time >= $event->[EV_STOP]); next if($next && $event_time >= $event->[EV_START]); } else { my ($found); if ($is_regex) { # We have a RegExp next if (!defined($pattern)); my $SearchStr = join("~", $event->[EV_TITLE], ($event->[EV_SUBTITLE] || ""), ($event->[EV_SUMMARY] || "")); if ($ignore_case) { $SearchStr = Encode::decode($MY_ENCODING, $SearchStr) if $can_use_encode; } $found = ($SearchStr =~ /$pattern/); } else { $found = 1; my $SearchStr = join(" ", $event->[EV_TITLE], ($event->[EV_SUBTITLE] || ""), ($event->[EV_SUMMARY] || "")); for my $pat (@search_words) { if ($SearchStr !~ /$pat->[0]/ && (!defined($pat->[1]) || $SearchStr !~ /$pat->[1]/)) { $found = 0; last; } } } next unless ($found); } my $displaytext = CGI::escapeHTML($event->[EV_SUMMARY]) || ""; my $displaytitle = CGI::escapeHTML($event->[EV_TITLE]); my $displaysubtitle = CGI::escapeHTML($event->[EV_SUBTITLE]); my $search_title = $event->[EV_TITLE]; $search_title =~ s/^.*\~\%*([^\~]*)$/$1/; $search_title = uri_escape($search_title); my $imdb_url = undef; if ($search_title && $CONFIG{SRCH1_ACTIVE}) { $imdb_url = $CONFIG{SRCH1_URL}; $imdb_url =~ s/\%TITLE\%/$search_title/g; } my $srch2_url = undef; if ($search_title && $CONFIG{SRCH2_ACTIVE}) { $srch2_url = $CONFIG{SRCH2_URL}; $srch2_url =~ s/\%TITLE\%/$search_title/g; } $displaytext =~ s/\n/
    \n/g; $displaytext =~ s/\|/
    \n/g; $displaytitle =~ s/\n/
    \n/g; $displaytitle =~ s/\|/
    \n/g; if ($displaysubtitle) { $displaysubtitle =~ s/\n/
    \n/g; $displaysubtitle =~ s/\|/
    \n/g; } my $myself = Encode_Referer($MyURL . "?" . $Query); my $running = $event->[EV_START] <= $now && $now <= $event->[EV_STOP]; my $timerset = 0; foreach my $timer (@timers) { if (($timer->{vdr_id} == $event->[EV_VDR_ID]) && ($timer->{start} <= $event->[EV_START]) && ($timer->{stop} >= $event->[EV_STOP])) { $timerset = 1; last; } } push(@show, { date => my_strftime("%x", $event->[EV_START]), longdate => my_strftime("%A, %x", $event->[EV_START]), start => my_strftime("%H:%M", $event->[EV_START]), stop => my_strftime("%H:%M", $event->[EV_STOP]), event_start => $event->[EV_START], show_percent => $event->[EV_START] <= $now && $now <= $event->[EV_STOP] ? "1" : undef, percent => $event->[EV_STOP] > $event->[EV_START] ? int(($now - $event->[EV_START]) / ($event->[EV_STOP] - $event->[EV_START]) * 100) : 0, elapsed_min => int(($now - $event->[EV_START]) / 60), length_min => int(($event->[EV_STOP] - $event->[EV_START]) / 60), title => $displaytitle, subtitle => $displaysubtitle, progname => CGI::escapeHTML($event->[EV_CHANNEL_NAME]), summary => $displaytext, vdr_id => $event->[EV_VDR_ID], proglink => sprintf("%s?aktion=prog_list&vdr_id=%s", $MyURL, $event->[EV_VDR_ID]), switchurl => $running ? sprintf("%s?aktion=prog_switch&channel=%s", $MyURL, $event->[EV_VDR_ID]) : undef, streamurl => $FEATURES{LIVESTREAM} ? sprintf("%s%s?aktion=live_stream&channel=%s&progname=%s", $MyStreamBase, $CONFIG{TV_EXT}, $event->[EV_VDR_ID], uri_escape($event->[EV_CHANNEL_NAME])) : undef, stream_live_on => $FEATURES{LIVESTREAM} && $running ? $CONFIG{ST_FUNC} && $CONFIG{ST_LIVE_ON} : undef, infurl => $event->[EV_SUMMARY] ? sprintf("%s?aktion=prog_detail&epg_id=%s&vdr_id=%s&referer=%s", $MyURL, $event->[EV_EVENT_ID], $event->[EV_VDR_ID], $myself) : undef, editurl => sprintf("%s?aktion=prog_detail_form&epg_id=%s&vdr_id=%s&referer=%s", $MyURL, $event->[EV_EVENT_ID], $event->[EV_VDR_ID], $myself), recurl => sprintf("%s?aktion=timer_new_form&epg_id=%s&vdr_id=%s&referer=%s", $MyURL, $event->[EV_EVENT_ID], $event->[EV_VDR_ID], $myself), find_title => uri_escape("/^" . my_quotemeta($event->[EV_TITLE] . "~" . ($event->[EV_SUBTITLE] ? $event->[EV_SUBTITLE] : "") . "~") . "/"), srch1_url => $imdb_url, srch1_title => $imdb_url ? gettext($CONFIG{SRCH1_TITLE}) : undef, srch2_url => $srch2_url, srch2_title => $srch2_url ? gettext($CONFIG{SRCH2_TITLE}) : undef, anchor => "id" . $event->[EV_EVENT_ID], timerset => $timerset } ); last if (!$search); } } elsif (!$search && $CONFIG{CHANNELS_WITHOUT_EPG}) { # no EPG push(@show, { date => my_strftime("%x", $event_time), longdate => my_strftime("%A, %x", $event_time), start => undef, show_percent => undef, title => gettext("No EPG information available"), progname => CGI::escapeHTML($channel->{name}), vdr_id => $channel->{vdr_id}, proglink => sprintf("%s?aktion=prog_list&vdr_id=%s", $MyURL, $channel->{vdr_id}), switchurl => sprintf("%s?aktion=prog_switch&channel=%s", $MyURL, $channel->{vdr_id}), streamurl => $FEATURES{LIVESTREAM} ? sprintf("%s%s?aktion=live_stream&channel=%s&progname=%s", $MyStreamBase, $CONFIG{TV_EXT}, $channel->{vdr_id}, uri_escape($channel->{name})) : undef, stream_live_on => $FEATURES{LIVESTREAM} ? $CONFIG{ST_FUNC} && $CONFIG{ST_LIVE_ON} : undef, anchor => "id" . $channel->{vdr_id} } ); } } if ($search) { # sort by event's start time and with equal start time sort by channel id @show = sort({ $a->{event_start} <=> $b->{event_start} || $a->{vdr_id} <=> $b->{vdr_id} } @show); } else { # sort by channel id @show = sort({ $a->{vdr_id} <=> $b->{vdr_id} } @show); } my $displayed_time = strftime("%H:%M", localtime($event_time)); my @times; unless ($search) { push(@times, { name => gettext("now"), id => "$MyURL?aktion=prog_summary&view=$view", } ); push(@times, { name => gettext("next"), id => "$MyURL?aktion=prog_summary&next=1&view=$view", sel => $next ? "1" : undef } ); for (split(/,\s*/, $CONFIG{TIMES})) { s/\s//g; my $id = $_; $id =~ s/://; push(@times, { name => gettext("at") . " $_ " . gettext("o'clock"), id => "$MyURL?aktion=prog_summary&time=$id", sel => $displayed_time eq $_ ? "1" : undef } ); } } # my $label = $next ? gettext("What's on after") : gettext("What's on at"); my $vars = { rows => \@show, now => $displayed_time, title => ($search ? gettext("Suitable matches for:") . " " . CGI::escapeHTML($search) . "" : $label . " " . strftime("%H:%M", localtime($event_time)) . " " . gettext("o'clock")), switchview_url => $MyURL . "?aktion=prog_summary&view=" . ($view eq "ext" ? "sml" : "ext") . ($next ? "&next=1" : "") . ($search ? "&search=" . uri_escape($search) : "") . ($time ? "&time=$time" : ""), switchview_text => ($view eq "ext" ? gettext("short view") : gettext("long view")), times => \@times, url => $MyURL, searchresults => $search, ch_groups => getChannelGroups($MyURL . "?aktion=prog_summary&view=" . $view . ($next ? "&next=1" : "") . ($search ? "&search=" . uri_escape($search) : "") . ($time ? "&time=$time" : ""), $CONFIG{CHANNELS_WANTED_SUMMARY}) }; return showTemplate($view eq "ext" ? "prog_summary.html" : "prog_summary2.html", $vars); } ############################################################################# # recordings ############################################################################# sub rec_list { my @recordings; $CONFIG{REC_DESC} = ($q->param("desc") ? 1 : 0) if (defined($q->param("desc"))); $CONFIG{REC_SORTBY} = $q->param("sortby") if (defined($q->param("sortby"))); $CONFIG{REC_SORTBY} = "name" if (!$CONFIG{REC_SORTBY}); my $parent = $q->param("parent"); if (!$parent) { $parent = 0; } else { $parent = uri_escape($parent); } ParseRecordings($parent); # returns by parent filtered list # create path array my @path; my @split_parent = split("~", $parent); my $last = 1; while ((scalar(@split_parent) > 0) && ($parent ne "0")) { push(@path, { name => uri_unescape($split_parent[-1]), url => ($last == 0) ? sprintf("%s?aktion=rec_list&parent=%s", $MyURL, join("~", @split_parent)) : "" } ); pop(@split_parent); $last = 0; }; push(@path, { name => gettext("Recordings"), url => ($parent ne 0) ? sprintf("%s?aktion=rec_list&parent=%s", $MyURL, 0) : "" } ); @path = reverse(@path); @recordings = @RECORDINGS; # if ($CONFIG{REC_SORTBY} eq "time") { if ($CONFIG{REC_DESC}) { @recordings = sort({ $b->{isfolder} <=> $a->{isfolder} || ciCmp($b->{isfolder} ? $a->{name} : "", $a->{isfolder} ? $b->{name} : "") || $b->{time} <=> $a->{time} } @recordings); } else { @recordings = sort({ $b->{isfolder} <=> $a->{isfolder} || ciCmp($b->{isfolder} ? $a->{name} : "", $a->{isfolder} ? $b->{name} : "") || $a->{time} <=> $b->{time} } @recordings); } } elsif ($CONFIG{REC_SORTBY} eq "name") { if ($CONFIG{REC_DESC}) { @recordings = sort({ $b->{isfolder} <=> $a->{isfolder} || ciCmp($b->{isfolder} ? $b->{name} : "", $a->{isfolder} ? $a->{name} : "") || ciCmp($b->{name}, $a->{name}) || $b->{sse} <=> $a->{sse} } @recordings); } else { @recordings = sort({ $b->{isfolder} <=> $a->{isfolder} || ciCmp($b->{isfolder} ? $a->{name} : "", $a->{isfolder} ? $b->{name} : "") || ciCmp($a->{name}, $b->{name}) || $a->{sse} <=> $b->{sse} } @recordings); } } elsif ($CONFIG{REC_SORTBY} eq "date") { if ($CONFIG{REC_DESC}) { @recordings = sort({ $b->{isfolder} <=> $a->{isfolder} || ciCmp($b->{isfolder} ? $a->{name} : "", $a->{isfolder} ? $b->{name} : "") || $b->{sse} <=> $a->{sse} } @recordings); } else { @recordings = sort({ $b->{isfolder} <=> $a->{isfolder} || ciCmp($b->{isfolder} ? $a->{name} : "", $a->{isfolder} ? $b->{name} : "") || $a->{sse} <=> $b->{sse} } @recordings); } } elsif ($CONFIG{REC_SORTBY} eq "length") { if ($CONFIG{REC_DESC}) { @recordings = sort({ $b->{isfolder} <=> $a->{isfolder} || $b->{lengthmin} <=> $a->{lengthmin} || ciCmp($b->{isfolder} ? $a->{name} : "", $a->{isfolder} ? $b->{name} : "") } @recordings); } else { @recordings = sort({ $b->{isfolder} <=> $a->{isfolder} || $a->{lengthmin} <=> $b->{lengthmin} || ciCmp($b->{isfolder} ? $a->{name} : "", $a->{isfolder} ? $b->{name} : "") } @recordings); } } my $toggle_desc = ($CONFIG{REC_DESC} ? 0 : 1); # my ($total, $minutes_total, $free, $minutes_free, $percent) = VideoDiskFree(); my $referer = Encode_Referer($MyURL . "?" . $Query); chomp($referer); my $vars = { recloop => \@recordings, sortbydateurl => "$MyURL?aktion=rec_list&parent=$parent&sortby=date&parent=$parent&desc=" . (($CONFIG{REC_SORTBY} eq "date") ? $toggle_desc : $CONFIG{REC_DESC}), sortbytimeurl => "$MyURL?aktion=rec_list&parent=$parent&sortby=time&parent=$parent&desc=" . (($CONFIG{REC_SORTBY} eq "time") ? $toggle_desc : $CONFIG{REC_DESC}), sortbylengthurl => "$MyURL?aktion=rec_list&parent=$parent&sortby=length&parent=$parent&desc=" . (($CONFIG{REC_SORTBY} eq "length") ? $toggle_desc : $CONFIG{REC_DESC}), sortbynameurl => "$MyURL?aktion=rec_list&parent=$parent&sortby=name&parent=$parent&desc=" . (($CONFIG{REC_SORTBY} eq "name") ? $toggle_desc : $CONFIG{REC_DESC}), sortbydate => ($CONFIG{REC_SORTBY} eq "date") ? 1 : 0, sortbytime => ($CONFIG{REC_SORTBY} eq "time") ? 1 : 0, sortbylength => ($CONFIG{REC_SORTBY} eq "length") ? 1 : 0, sortbyname => ($CONFIG{REC_SORTBY} eq "name") ? 1 : 0, desc => $CONFIG{REC_DESC} ? "desc" : "asc", disk_total => $total, disk_free => $free, disk_percent => $percent, minutes_free => $minutes_free, minutes_total => $minutes_total, path => \@path, url => $MyURL, help_url => HelpURL("rec_list"), reccmds => \@reccmds, stream_rec_on => $CONFIG{ST_FUNC} && $CONFIG{ST_REC_ON}, streamfolderurl => ($CONFIG{ST_FUNC} && $CONFIG{ST_REC_ON}) ? "$MyURL?aktion=rec_stream_folder&parent=$parent" : undef, referer => "&referer=$referer" }; return showTemplate("rec_list.html", $vars); } sub ParseRecordings { my $parent_select = shift; Log(LOG_DEBUG, "[ParseRecordings] start parent: $parent_select"); # clear global lists @RECORDINGS = (); %RECORDING_FOLDERS = {}; %RECORDING_BY_ID = {}; Log(LOG_DEBUG, "[ParseRecordings] begin 'lstr'"); for my $recording (SendCMD("lstr")) { chomp($recording); next if (length($recording) == 0); last if ($recording =~ /^No recordings available/); my ($id, $date, $time, $length, $name, $new); if ($FEATURES{VDRVERSION} < 10721) { # id date time* name ($id, $date, $time, $name) = split(/ +/, $recording, 4); if (length($time) > 5) { $new = 1; $time = substr($time, 0, 5); } } else { # id date time length* name ($id, $date, $time, $length, $name) = split(/ +/, $recording, 5); if ($length =~ /^(\d+:\d+)\D/) { $new = 1; $length = $1; } } my @path = split("~", $name); my $rec_name = pop(@path); my $rparent; if (@path) { $rparent = uri_escape(join("~", @path)); } else { $rparent = 0; }; my $lengthmin = 0; if ($length =~ /^(\d+):(\d{1,2})$/) { $lengthmin = $1 * 60 + $2; } elsif ($length =~ /^\d+/) { $lengthmin = $length; } # store recording in hash $RECORDING_BY_ID{$id}->{'name'} = $rec_name; $RECORDING_BY_ID{$id}->{'date'} = $date; $RECORDING_BY_ID{$id}->{'time'} = $time; $RECORDING_BY_ID{$id}->{'length'} = $length; $RECORDING_BY_ID{$id}->{'rec_name'} = $rec_name; $RECORDING_BY_ID{$id}->{'parent'} = $rparent; $RECORDING_BY_ID{$id}->{'new'} = $new; $RECORDING_BY_ID{$id}->{'lengthmin'} = $lengthmin; # create folder tree my $parent; if (@path) { while (scalar(@path) > 0) { $name = pop(@path); if (scalar(@path) > 0) { $parent = uri_escape(join("~", @path)); } else { $parent = '#ROOT#'; }; $RECORDING_FOLDERS{$parent}->{$name}->{'count'}++; $RECORDING_FOLDERS{$parent}->{$name}->{'new'}++ if ($new); $RECORDING_FOLDERS{$parent}->{$name}->{'lengthmin'} += $lengthmin; }; }; }; # Create folder list my $folder_entries; if ($parent_select eq "0" ) { $folder_entries = $RECORDING_FOLDERS{'#ROOT#'}; } elsif (defined $RECORDING_FOLDERS{$parent_select}) { $folder_entries = $RECORDING_FOLDERS{$parent_select}; }; ## Folders if (scalar(keys %$folder_entries) > 0) { foreach my $name (sort keys %$folder_entries) { my $folder = $folder_entries->{$name}; my $parent = $parent_select; my $path = ($parent eq "0") ? uri_escape($name) : $parent . "~" . uri_escape($name); Log(LOG_DEBUG, sprintf("FOLDERLIST entry='%s' path='%s' parent='%s'", $name, $path, $parent)); push(@RECORDINGS, { name => CGI::escapeHTML($name), recording_id => $name, parent => $parent, isfolder => 1, date => $folder->{'count'}, time => (defined $folder->{'new'}) ? $folder->{'new'} : 0, lengthmin => $folder->{'lengthmin'}, infurl => sprintf("%s?aktion=rec_list&parent=%s", $MyURL, $path), streamurl => "$MyURL?aktion=rec_stream_folder&parent=" . $path } ); }; }; # Records for my $id (keys %RECORDING_BY_ID) { my ($date, $time, $length, $name, $rec_name, $serie, $episode, $new); my ($lengthmin, $parent); $parent = $RECORDING_BY_ID{$id}->{'parent'}; next if ($parent_select ne $parent); # skip adding entries to list which are not selected $name = $RECORDING_BY_ID{$id}->{'name'}; $date = $RECORDING_BY_ID{$id}->{'date'}; $time = $RECORDING_BY_ID{$id}->{'time'}; $length = $RECORDING_BY_ID{$id}->{'length'}; $rec_name = $RECORDING_BY_ID{$id}->{'rec_name'}; $new = $RECORDING_BY_ID{$id}->{'new'}; $lengthmin = $RECORDING_BY_ID{$id}->{'lengthmin'}; Log(LOG_DEBUG, sprintf("RECLIST rec_name='%s' id=%s parent='%s'",$rec_name, $id, $parent)); my $yearofrecording; if ($FEATURES{VDRVERSION} >= 10326) { # let localtime() decide about the century $yearofrecording = substr($date, 6, 2); # alternatively decide about the century ourself # my $shortyear = substr($date,6,2); # if ($shortyear > 70) { # $yearofrecording = "19" . $shortyear; # } else { # $yearofrecording = "20" . $shortyear; # } } else { # old way of vdradmin to handle the date while vdr did not report the year # current year was assumed. if ($date eq "29.02") { $yearofrecording = "2004"; } else { $yearofrecording = my_strftime("%Y"); } } # endif my $name_js = $name; $name_js =~ s/\'/\\\'/g; $name_js =~ s/\"/\"/g; push(@RECORDINGS, { sse => timelocal(undef, substr($time, 3, 2), substr($time, 0, 2), substr($date, 0, 2), (substr($date, 3, 2) - 1), $yearofrecording), date => $date, time => $time, length => $length, lengthmin => $lengthmin, name => CGI::escapeHTML($name), name_js => $name_js, serie => $serie, episode => $episode, parent => $parent, new => $new, id => $id, isfolder => 0, delurl => $MyURL . "?aktion=rec_delete&rec_delete=y&id=$id", editurl => $FEATURES{REC_RENAME} ? $MyURL . "?aktion=rec_edit&id=$id" : undef, infurl => $MyURL . "?aktion=rec_detail&id=$id", playurl => $FEATURES{VDRVERSION} >= 10331 ? $MyURL . "?aktion=rec_play&id=$id" : undef, #TODO cuturl => $FEATURES{VDRVERSION} >= 10331 ? $MyURL . "?aktion=rec_cut&id=$id" : undef, #TODO streamurl => ($CONFIG{ST_FUNC} && $CONFIG{ST_REC_ON}) ? $MyStreamBase . $CONFIG{REC_EXT} . "?aktion=rec_stream&id=$id" : undef } ); } Log(LOG_DEBUG, "[ParseRecordings] end 'lstr'"); for (@RECORDINGS) { $_->{length} ||= sprintf("%d:%02d", $_->{lengthmin} / 60, $_->{lengthmin} % 60); } Log(LOG_DEBUG, "[ParseRecordings] end"); } sub getRecInfo { my $id = shift; my $ref = shift; my $rename = shift; my ($i, $length, $title); for (SendCMD("lstr")) { if ($FEATURES{VDRVERSION} < 10721) { ($i, undef, undef, $title) = split(/ +/, $_, 4); } else { ($i, undef, undef, $length, $title) = split(/ +/, $_, 5); } last if ($id == $i); } chomp($title); $length =~ s/\*+$//; my $vars; if ($FEATURES{VDRVERSION} >= 10325) { $SVDRP->command("lstr $id"); my ($channel_name, $subtitle, $text, $video, $audio, $subs); while ($_ = $SVDRP->readoneline) { if (/^C (.*)/) { $channel_name = get_name_from_uniqid($1); } #elsif (/^E (.*)/) { $epg = $1; } elsif (/^T (.*)/) { $title = $1; } elsif (/^S (.*)/) { $subtitle = $1; } elsif (/^D (.*)/) { $text = $1; } elsif (/^X 1 [^ ]* (.*)/) { my ($lang, $format) = split(" ", $1, 2); $video .= ", " if($video); $video .= $format; $video .= " (" . $lang . ")"; } elsif (/^X 2 [^ ]* (.*)/) { my ($lang, $descr) = split(" ", $1, 2); $audio .= ", " if ($audio); $audio .= ($descr ? $descr. " (" . $lang . ")" : $lang); } elsif(/^X 3 [^ ]* (.*)/) { my ($lang, $descr) = split(" ", $1, 2); $subs .= ", " if ($subs); $subs .= ($descr ? $descr. " (" . $lang . ")" : $lang); } #elsif (/^V (.*)/) { $vps = $1; } } my $displaytext = CGI::escapeHTML($text) || ""; my $displaytitle = CGI::escapeHTML($title); my $displaysubtitle = CGI::escapeHTML($subtitle); my $search_title = $title; $search_title =~ s/^.*\~\%*([^\~]*)$/$1/; $search_title = uri_escape($search_title); my $imdb_url = undef; if ($search_title && $CONFIG{SRCH1_ACTIVE}) { $imdb_url = $CONFIG{SRCH1_URL}; $imdb_url =~ s/\%TITLE\%/$search_title/g; } my $srch2_url = undef; if ($search_title && $CONFIG{SRCH2_ACTIVE}) { $srch2_url = $CONFIG{SRCH2_URL}; $srch2_url =~ s/\%TITLE\%/$search_title/g; } $displaytext =~ s/\n/
    \n/g; $displaytext =~ s/\|/
    \n/g; unless ($rename) { $displaytitle =~ s/\~/ - /g; $displaytitle =~ s/\n/
    \n/g; $displaytitle =~ s/\|/
    \n/g; } $displaysubtitle =~ s/\n/
    \n/g; $displaysubtitle =~ s/\|/
    \n/g; $vars = { url => $MyURL, text => $displaytext || undef, title => $displaytitle || undef, subtitle => $displaysubtitle || undef, channel_name => $channel_name || undef, srch1_url => $imdb_url, srch1_title => $imdb_url ? gettext($CONFIG{SRCH1_TITLE}) : undef, srch2_url => $srch2_url, srch2_title => $srch2_url ? gettext($CONFIG{SRCH2_TITLE}) : undef, id => $id, video => $video, audio => $audio, subs => $subs, length => $length, referer => $ref || undef }; } else { my ($text); my ($first) = 1; my ($result) = SendCMD("lstr $id"); if ($result !~ /No summary availab/i) { for (split(/\|/, $result)) { if ($_ ne (split(/\~/, $title))[1] && "%" . $_ ne (split(/\~/, $title))[1] && "@" . $_ ne (split(/\~/, $title))[1]) { if ($first && $title !~ /\~/ && length($title) < 20) { $title .= "~" . $_; $first = 0; } else { if ($text) { $text .= "
    "; } $text .= CGI::escapeHTML("$_ "); } } } } my $search_title = $title; $search_title =~ s/^.*\~\%*([^\~]*)$/$1/; $search_title = uri_escape($search_title); # TODO? $search_title =~ s/^.*\~//; my $imdb_url = undef; if ($search_title && $CONFIG{SRCH1_ACTIVE}) { $imdb_url = $CONFIG{SRCH1_URL}; $imdb_url =~ s/\%TITLE\%/$search_title/g; } my $srch2_url = undef; if ($search_title && $CONFIG{SRCH2_ACTIVE}) { $srch2_url = $CONFIG{SRCH2_URL}; $srch2_url =~ s/\%TITLE\%/$search_title/g; } $title =~ s/\~/ - /g unless($rename); $vars = { url => $MyURL, text => $text ? $text : "", srch1_url => $imdb_url, srch1_title => $imdb_url ? gettext($CONFIG{SRCH1_TITLE}) : undef, srch2_url => $srch2_url, srch2_title => $srch2_url ? gettext($CONFIG{SRCH2_TITLE}) : undef, title => CGI::escapeHTML($title), id => $id }; } return $vars; } sub rec_detail { my $vars = getRecInfo(scalar $q->param('id')); return showTemplate("prog_detail.html", $vars); } sub rec_delete { my $id = $q->param('id'); if ($q->param("rec_delete")) { if ($id) { SendCMD("delr $id"); } else { my @id_arr = (); for ($q->param) { if (/xxxx_(.*)/) { push (@id_arr, $1); } } # VDR 2.3.x workaround: # delete starting with the largest id and proceed to the smallest. # In this case, ids won't change while removing items from the list. @id_arr = sort {$b <=> $a} @id_arr; for my $del_id (@id_arr) { SendCMD("delr $del_id"); } } CloseSocket(); } elsif ($q->param("rec_runcmd")) { if ($id) { recRunCmd($q->param("rec_cmd"), $id); } else { for ($q->param) { if (/xxxx_(.*)/) { recRunCmd($q->param("rec_cmd"), $1); } } } } elsif ($q->param("rec_update")) { } return RedirectToReferer("$MyURL?aktion=rec_list&sortby=" . $q->param("sortby") . "&desc=" . $q->param("desc")); } sub recRunCmd { my ($cmdID, $id) = @_; my $cmd = ${reccmds}[$cmdID]{cmd}; my ($rec_id, $date, $time, $title); my ($day, $month, $hour, $minute, $newtitle, $c, $folder); for (SendCMD("lstr")) { if ($FEATURES{VDRVERSION} < 10721) { ($rec_id, $date, $time, $title) = split(/ +/, $_, 4); } else { ($rec_id, $date, $time, undef, $title) = split(/ +/, $_, 5); } last if ($rec_id == $id); } $time = substr($time, 0, 5); # needed for wareagel-patch if ($rec_id == $id) { chomp($title); ($day, $month) = split(/\./, $date); ($hour, $minute) = split(/:/, $time); # VFAT off my $folder = findVideoFolder($minute, $hour, $day, $month, encode_RecTitle($title, 0)); unless ($folder) { # VFAT on $folder = findVideoFolder($minute, $hour, $day, $month, encode_RecTitle($title, 1)); } if ($folder) { Log(LOG_DEBUG, "[REC] recRunCmd: executing ($cmd \"$folder\")"); `$cmd "$folder"`; } } } sub findVideoFolder { # VDR < v1.7.2: YYYY-MM-DD-hh[.:]mm.pr.lt.rec (pr=priority, lt=lifetime) # VDR >= v1.7.2: YYYY-MM-DD-hh.mm.ch-ri.rec (ch=channel, ri=resumeId) my ($minute, $hour, $day, $month, $title) = @_; my $folder; $title =~ s/ /_/g; $title =~ s/~/\//g; $folder = `find $CONFIG{VIDEODIR}/ -follow -regex "$CONFIG{VIDEODIR}/$title\_*/\\(\_/\\)?....-$month-$day\\.$hour.$minute\\.\[0-9\]+\[.-\]\[0-9\]+\\.rec"`; Log(LOG_DEBUG, "[REC] findVideoFolder: find $CONFIG{VIDEODIR}/ -follow -regex \"$CONFIG{VIDEODIR}/$title\_*/\\(\_/\\)?....-$month-$day\\.$hour.$minute\\.\[0-9\]+\[.-\]\[0-9\]+\\.rec\""); chomp($folder) if ($folder); return $folder; } sub rec_edit { # determine referer (redirect to where we come from) my $ref = getReferer(); my $vars = getRecInfo(scalar $q->param("id"), $ref ? Encode_Referer($ref) : undef, "renr"); return showTemplate("rec_edit.html", $vars); } sub rec_rename { my $id = $q->param('id'); my $nn = $q->param('nn'); if ($id && $q->param("save")) { SendCMD("$FEATURES{REC_RENAME} $id $nn"); CloseSocket(); } my $ref = getReferer(); if ($ref) { return headerForward($ref); } else { return headerForward("$MyURL?aktion=rec_list&sortby=" . $q->param("sortby") . "&desc=" . $q->param("desc")); } } sub rec_play { my $id = $q->param('id'); if ($id) { SendCMD("PLAY $id"); CloseSocket(); } } sub rec_cut { my $id = $q->param('id'); if ($id) { SendCMD("EDIT $id"); CloseSocket(); } } ############################################################################# # configuration ############################################################################# sub config { my $error_msg; unless ($q->param("save") || $q->param("apply") || $q->param("submit")) { undef %CONFIG_TEMP; for my $key (keys(%CONFIG)) { $CONFIG_TEMP{$key} = $CONFIG{$key}; } } sub ApplyConfig { for ($q->param) { if (/[A-Z]+/) { $CONFIG_TEMP{$_} = $q->param($_); } } my $need_trans_reload = 1 if ($CONFIG_TEMP{LANG} ne $CONFIG{LANG}); my $need_vdrconf_reload = 1 if ($CONFIG_TEMP{VDRCONFDIR} ne $CONFIG{VDRCONFDIR}); my $need_update = 1 if ($CONFIG_TEMP{EPG_PRUNE} != $CONFIG{EPG_PRUNE} || $CONFIG_TEMP{CHANNELS_WANTED} ne $CONFIG{CHANNELS_WANTED}); for my $key (keys(%CONFIG_TEMP)) { $CONFIG{$key} = $CONFIG_TEMP{$key}; } ValidConfig(); LoadTranslation() if ($need_trans_reload); UptoDate(1) if ($need_update); if ($need_vdrconf_reload) { @reccmds = loadCommandsConf("$CONFIG{VDRCONFDIR}/reccmds.conf"); @vdrcmds = loadCommandsConf("$CONFIG{VDRCONFDIR}/commands.conf"); } } sub WriteConfig { open(CONF, ">$CONFFILE") || return sprintf(gettext("Can't write configuration file %s! Reason: %s") . "
    ", $CONFFILE, "$!"); my $old_collate = setlocale(LC_COLLATE); setlocale(LC_COLLATE, "C"); for my $key (sort(keys(%CONFIG))) { print CONF "$key = $CONFIG{$key}\n"; } setlocale(LC_COLLATE, $old_collate); close(CONF); return ""; } if ($q->param("submit")) { if ($q->param("submit") eq ">>>>>") { for my $vdr_id ($q->param("all_channels")) { $CONFIG_TEMP{CHANNELS_WANTED} = csvAdd($CONFIG_TEMP{CHANNELS_WANTED}, $vdr_id); } } elsif ($q->param("submit") eq "<<<<<") { for my $vdr_id ($q->param("selected_channels")) { $CONFIG_TEMP{CHANNELS_WANTED} = csvRemove($CONFIG_TEMP{CHANNELS_WANTED}, $vdr_id); } } } elsif ($q->param("save")) { ApplyConfig(); $error_msg .= WriteConfig(); } elsif ($q->param("apply")) { ApplyConfig(); } # vdradmind.conf writable? $error_msg .= sprintf(gettext("Configuration file %s not writable! Configuration won't be saved!") . "
    ", $CONFFILE) unless (-w $CONFFILE); # my @LOGINPAGES_DESCRIPTION = (gettext("What's On Now?"), gettext("Playing Today?"), gettext("Timeline"), gettext("Channels"), gettext("Timers"), gettext("Recordings")); my (@loginpages); my $i = 0; for my $loginpage (@LOGINPAGES) { push(@loginpages, { id => $i, name => $LOGINPAGES_DESCRIPTION[$i], current => ($CONFIG_TEMP{LOGINPAGE} == $i) ? 1 : 0 } ); $i++; } # my @template; for my $dir (<$TEMPLATEDIR/*>) { next if (!-d $dir); $dir =~ s/.*\///g; my $found = 0; for (@template) { ($found = 1) if ($1 && ($_->{name} eq $1)); } if (!$found) { push(@template, { name => $dir, aktemplate => ($CONFIG_TEMP{TEMPLATE} eq $dir) ? 1 : 0, } ); } } my @selected_channels; my @not_selected_channels; for my $channel (@{$CHAN{$CHAN_FULL}->{channels}}) { my $found = 0; for (split(",", $CONFIG_TEMP{CHANNELS_WANTED})) { if ($_ eq $channel->{vdr_id}) { $found = 1; last; } } if ($found) { push(@selected_channels, { name => $channel->{name}, vdr_id => $channel->{vdr_id} } ); } else { push(@not_selected_channels, { name => $channel->{name}, vdr_id => $channel->{vdr_id} } ); }; } my @skinlist; foreach my $file (glob(sprintf("%s/%s/*", $TEMPLATEDIR, $CONFIG_TEMP{TEMPLATE}))) { my $name = (split('\/', $file))[-1]; next if ($name eq 'js'); push(@skinlist, { name => $name, sel => ($CONFIG_TEMP{SKIN} eq $name ? 1 : 0) } ) if (-d $file); } my @my_locales; if (-f "/usr/bin/locale" && -x _) { push(@my_locales, { id => "", name => gettext("System default"), cur => 0 }); foreach my $loc (`locale -a`) { chomp $loc; push(@my_locales, { id => $loc, name => $loc, cur => ($loc eq $CONFIG_TEMP{LANG} ? 1 : 0) } ) if ($loc =~ $SUPPORTED_LOCALE_PREFIXES); } } my $vars = { TEMPLATELIST => \@template, ALL_CHANNELS => \@not_selected_channels, SELECTED_CHANNELS => \@selected_channels, LOGINPAGES => \@loginpages, SKINLIST => \@skinlist, MY_LOCALES => \@my_locales, url => $MyURL, help_url => HelpURL("config"), config => \%CONFIG_TEMP, error_msg => $error_msg }; return showTemplate("config.html", $vars); } ############################################################################# # remote control ############################################################################# sub rc_show { $CONFIG{CHANNELS_WANTED_WATCHTV} = $q->param("wanted_channels") if (defined $q->param("wanted_channels")); my ($cur_channel_id, $cur_channel_name); for (SendCMD("chan")) { ($cur_channel_id, $cur_channel_name) = split(" ", $_, 2); } my @chans; for my $chan (@{$CHAN{$CONFIG{CHANNELS_WANTED_WATCHTV}}->{channels}}) { if ($chan->{vdr_id}) { $chan->{cur} = ($chan->{vdr_id} == $cur_channel_id) ? 1 : 0; } push(@chans, $chan); } my $vars = { url => sprintf("%s?aktion=grab_picture", $MyURL), host => $CONFIG{VDR_HOST}, channels => \@chans, ch_groups => getChannelGroups($MyURL . "?aktion=rc_show&full_rc=1", $CONFIG{CHANNELS_WANTED_WATCHTV}), full_rc => $q->param('full_rc') ? 1 : 0 }; return showTemplate("rc.html", $vars); } sub rc_hitk { my $key = $q->param("key"); if ($key eq "VolumePlus") { $key = "Volume+"; } if ($key eq "VolumeMinus") { $key = "Volume-"; } SendCMD("hitk $key"); #XXX SendFile("bilder/spacer.gif"); } sub tv_show { $CONFIG{TV_INTERVAL} = $q->param("interval") if($q->param("interval")); $CONFIG{TV_INTERVAL} = "5" unless($CONFIG{TV_INTERVAL}); $CONFIG{TV_SIZE} = $q->param("size") if($q->param("size")); $CONFIG{TV_SIZE} = "half" unless($CONFIG{TV_SIZE}); $CONFIG{CHANNELS_WANTED_WATCHTV} = $q->param("wanted_channels") if (defined $q->param("wanted_channels")); my ($cur_channel_id, $cur_channel_name); for (SendCMD("chan")) { ($cur_channel_id, $cur_channel_name) = split(" ", $_, 2); } my @chans; for my $chan (@{$CHAN{$CONFIG{CHANNELS_WANTED_WATCHTV}}->{channels}}) { if ($chan->{vdr_id}) { $chan->{cur} = ($chan->{vdr_id} == $cur_channel_id) ? 1 : 0; } push(@chans, $chan); } my $vars = { full_tv => $q->param("full_tv") ? 1 : undef, interval => $CONFIG{TV_INTERVAL}, size => $CONFIG{TV_SIZE}, new_win => ($q->param("new_win") && $q->param("new_win") eq "1") ? "1" : undef, url => sprintf("%s?aktion=grab_picture", $MyURL), channels => \@chans, ch_groups => getChannelGroups($MyURL . "?aktion=tv_show&full_tv=1", $CONFIG{CHANNELS_WANTED_WATCHTV}), host => $CONFIG{VDR_HOST} }; return showTemplate("tv.html", $vars); } sub tv_switch { my $channel = $q->param("channel"); if ($channel) { SendCMD("chan $channel"); } } sub show_help { my $area = $q->param("area"); my $filename = "help_" . $area . ".html"; if (!-e "$TEMPLATEDIR/$CONFIG{TEMPLATE}/$filename") { $filename = "help_no.html"; } my $vars = { area => $area }; return showTemplate($filename, $vars); } ############################################################################# # information ############################################################################# sub about { my $vars = { }; return showTemplate("about.html", $vars); } ############################################################################# # experimental ############################################################################# sub grab_picture { $CONFIG{TV_INTERVAL} = $q->param("interval") if($q->param("interval")); $CONFIG{TV_INTERVAL} = "5" unless($CONFIG{TV_INTERVAL}); $CONFIG{TV_SIZE} = $q->param("size") if($q->param("size")); $CONFIG{TV_SIZE} = "half" unless($CONFIG{TV_SIZE}); my $maxwidth = 1920; # FullHD my $maxheight = 1080; my ($width, $height); if ($CONFIG{TV_SIZE} eq "full") { ($width, $height) = ($maxwidth, $maxheight); } elsif ($CONFIG{TV_SIZE} eq "half") { ($width, $height) = ($maxwidth / 2, $maxheight / 2); } elsif ($CONFIG{TV_SIZE} eq "quarter") { ($width, $height) = ($maxwidth / 4, $maxheight / 4); } else { ($width, $height) = ($maxwidth / 4, $maxheight / 4); } if ($FEATURES{VDRVERSION} < 10338) { # Grab using temporary file my $file = new File::Temp(TEMPLATE => "vdr-XXXXX", DIR => File::Spec->tmpdir(), UNLINK => 1, SUFFIX => ".jpg"); chmod 0666, $file if (-e $file); SendCMD("grab $file jpeg 70 $width $height"); if (-e $file && -r _) { return (header("200", "image/jpeg", ReadFile($file))); } else { print "Expected $file does not exist.\n"; print "Obviously VDR Admin could not find the screenshot file. Ensure that:\n"; print " - VDR has the rights to write $file\n"; print " - VDR and VDR Admin run on the same machine\n"; print " - VDR Admin may read $file\n"; print " - VDR has access to /dev/video* files\n"; print " - you have a full featured card\n"; return SendFile("bilder/spacer.gif"); } } else { my $image; for (SendCMD("grab .jpg 70 $width $height")) { $image .= $_ unless (/Grabbed image/); } return SendFile("bilder/noise.gif") if ($image =~ /Grab image failed/); return (header("200", "image/jpeg", MIME::Base64::decode_base64($image))); } } sub force_update { UptoDate(1); RedirectToReferer("$MyURL?aktion=prog_summary"); } sub loadCommandsConf { my $conf_file = shift; my @commands; my $id = 0; if (-e $conf_file and my $text = open(FH, $conf_file)) { while () { chomp; s/#.*//; s/^\s+//; s/\s+$//; next unless length; next if (/{$/); next if (/^}$/); my ($title, $cmd) = split(":", $_); push(@commands, { title => $title, cmd => $cmd, id => $id }); $id = $id + 1; } close(FH); } return @commands; } sub vdr_cmds { my @show_output; @show_output = run_vdrcmd() if ($q->param("run_vdrcmd")); @show_output = run_svdrpcmd() if ($q->param("run_svdrpcmd")); my $svdrp_cmd = "help"; $svdrp_cmd = $q->param("svdrp_cmd") if ($q->param("svdrp_cmd")); $CONFIG{CMD_LINES} = $q->param("max_lines") if ($q->param("max_lines")); my @export_cmds = ( { url => sprintf("%s%s?aktion=export_channels_m3u&wanted=%d", $MyStreamBase, $CONFIG{TV_EXT}, $CHAN_FULL), text => gettext('All channels') }, { url => sprintf("%s%s?aktion=export_channels_m3u&wanted=%d", $MyStreamBase, $CONFIG{TV_EXT}, $CHAN_WANTED), text => gettext('Selected channels') }, { url => sprintf("%s%s?aktion=export_channels_m3u&wanted=%d", $MyStreamBase, $CONFIG{TV_EXT}, $CHAN_TV), text => gettext('TV channels') }, { url => sprintf("%s%s?aktion=export_channels_m3u&wanted=%d", $MyStreamBase, $CONFIG{TV_EXT}, $CHAN_RADIO), text => gettext('Radio channels') } ); my $vars = { url => sprintf("%s?aktion=vdr_cmds", $MyURL), commands => \@vdrcmds, show_output => \@show_output, max_lines => $CONFIG{CMD_LINES}, svdrp_cmd => $svdrp_cmd, vdr_cmd => $q->param("vdr_cmd") ? $q->param("vdr_cmd") : undef, export_cmds => \@export_cmds }; return showTemplate("vdr_cmds.html", $vars); } sub run_vdrcmd { my $id = $q->param("vdr_cmd"); my $max_lines = $q->param("max_lines"); return unless (defined($id) && $id =~ /^\d+$/); my $counter = 1; my $cmd = ${vdrcmds}[$id]{cmd}; my @output; open(FH, "$cmd |") or return; while () { chomp; push(@output, { line => $_ }); last if ($max_lines > 0 && $counter >= $max_lines); $counter++; } close(FH); return @output; } sub run_svdrpcmd { my $id = $q->param("svdrp_cmd"); my $max_lines = $q->param("max_lines"); return unless ($id); my $counter = 1; my @output; for (SendCMD(scalar $q->param("svdrp_cmd"))) { push(@output, { line => $_ }); last if ($max_lines > 0 && $counter >= $max_lines); $counter++; } return @output; } sub export_channels_m3u { my $wanted = $q->param("wanted"); my @filenames = ( 'vdr_full_channels', 'vdr_selected_channels', 'vdr_tv_channels', 'vdr_radio_channels' ); my $url = streamdevURI(); my $data = ""; foreach (sort({ $a->{vdr_id} <=> $b->{vdr_id} } (@{$CHAN{$wanted}->{channels}}))) { $url->path($_->{uniq_id}); $data .= sprintf("#EXTINF:0,%s\n%s\n", $_->{name}, $url); } return (header("200", $CONFIG{TV_MIMETYPE}, $data, sprintf("%s.%s", $filenames[$wanted], $CONFIG{TV_EXT}) )); } ############################################################################# # Authentication ############################################################################# sub subnetcheck { #TODO: IPv6 support my $ip = $_[0]; my $nets = $_[1]; my ($ip1, $ip2, $ip3, $ip4, $net_base, $net_range, $net_base1, $net_base2, $net_base3, $net_base4, $bin_ip, $bin_net); ($ip1, $ip2, $ip3, $ip4) = split(/\./, $ip); $bin_ip = unpack("B*", pack("C", $ip1)); $bin_ip .= unpack("B*", pack("C", $ip2)); $bin_ip .= unpack("B*", pack("C", $ip3)); $bin_ip .= unpack("B*", pack("C", $ip4)); for my $net (split(/[\s,]+/, $nets)) { ($net_base, $net_range) = split(/\//, $net); ($net_base1, $net_base2, $net_base3, $net_base4) = split(/\./, $net_base); $bin_net = unpack("B*", pack("C", $net_base1)); $bin_net .= unpack("B*", pack("C", $net_base2)); $bin_net .= unpack("B*", pack("C", $net_base3)); $bin_net .= unpack("B*", pack("C", $net_base4)); return 1 if substr($bin_ip, 0, $net_range) eq substr($bin_net, 0, $net_range); } return 0; } ############################################################################# # communication with vdr ############################################################################# package SVDRP; sub true () { main::true(); } sub false () { main::false(); } sub LOG_DEBUG () { main::LOG_DEBUG(); } sub CRLF () { main::CRLF(); } my ($SOCKET, $query, $connected, $VDR_ENCODING, $need_recode); sub new { my $invocant = shift; my $class = ref($invocant) || $invocant; my $self = {}; bless($self, $class); $connected = false; $query = false; $VDR_ENCODING = ''; $need_recode = 0; return $self; } sub myconnect { my $this = shift; main::Log(LOG_DEBUG, "[SVDRP] Connecting to $CONFIG{VDR_HOST}:$CONFIG{VDR_PORT}"); my $connect_error = undef; $SOCKET = $VdrSocketModule->new(PeerAddr => $CONFIG{VDR_HOST}, PeerPort => $CONFIG{VDR_PORT}, Proto => 'tcp' ); my $line; if ($SOCKET) { chomp($line = <$SOCKET>); main::Log(LOG_DEBUG, sprintf("[SVDRP] Read \"%s\"", $line)); if ($line =~ /access\s+denied/i) { # Blocked by svdrphosts.conf - VDR will close the connection $this->close(); $connect_error = $line; } } else { $connect_error = "$@"; } if (defined($connect_error)) { main::Log(main::LOG_WARNING, sprintf("Connection to %s:%s failed: %s", $CONFIG{VDR_HOST}, $CONFIG{VDR_PORT}, $connect_error)); main::HTMLError(sprintf($ERROR_MESSAGE{connect_failed}, $CONFIG{VDR_HOST}, $CONFIG{VDR_PORT}, CGI::escapeHTML($connect_error))) if $Client && $Client->connected; return 0; } $connected = true; if (!$FEATURES{VDRVERSION}) { $line =~ /^220.*VideoDiskRecorder (\d+)\.(\d+)\.(\d+)([^;]*);/; $FEATURES{VDRVERSION_HR} = "$1.$2.$3$4"; $FEATURES{VDRVERSION} = ($1 * 10000 + $2 * 100 + $3); getSupportedFeatures($this); } $line =~ /^220.*VideoDiskRecorder (\d+)\.(\d+)\.(\d+).*; .*; (.*)\r|$/; $VDR_ENCODING = $4; $need_recode = ($can_use_encode and $VDR_ENCODING and $VDR_ENCODING ne $MY_ENCODING) ? 1 : 0; return 1; } sub getSupportedFeatures { my $this = shift; if ($FEATURES{VDRVERSION} >= 10331) { command($this, "plug"); while ($_ = readoneline($this)) { if (/^epgsearch v(\d+)\.(\d+)\.(\d+)([^ ]*)/) { $FEATURES{EPGSEARCH} = 1; $FEATURES{EPGSEARCH_VERSION} = ($1 * 10000 + $2 * 100 + $3); $FEATURES{EPGSEARCH_VERSION_HR} = "$1.$2.$3$4"; } elsif (/^streamdev-server(?:\s+v(\S+))?/) { $FEATURES{STREAMDEV} = 1; $FEATURES{STREAMDEV_VERSION_HR} = $1; } elsif (/^xineliboutput(?:\s+v(\S+))?/) { $FEATURES{XINELIB} = 1; $FEATURES{XINELIB_VERSION_HR} = $1; } } } $FEATURES{LIVESTREAM} = $FEATURES{STREAMDEV} || $FEATURES{XINELIB}; command($this, "help"); while ($_ = readoneline($this)) { if ($_ =~ /\s(RENR|MOVR)\s/) { $FEATURES{REC_RENAME} = $1; } } } sub close { my $this = shift; if ($connected) { main::Log(LOG_DEBUG, "[SVDRP] Closing connection"); command($this, "quit"); readoneline($this); close $SOCKET if $SOCKET; $connected = false; } } sub command { my $this = shift; my $cmd = join("", @_); if (!$connected) { myconnect($this) or return; } main::Log(LOG_DEBUG, sprintf("[SVDRP] Sending \"%s\"", $cmd)); $cmd = $cmd . CRLF; if ($SOCKET && $SOCKET->connected()) { Encode::from_to($cmd, $MY_ENCODING, $VDR_ENCODING) if ($need_recode); my $result = send($SOCKET, $cmd, 0); if ($result != length($cmd)) { main::HTMLError(sprintf($ERROR_MESSAGE{send_command}, $CONFIG{VDR_HOST})); } else { $query = true; } } } sub readoneline { my $this = shift; my $line; if ($SOCKET && $SOCKET->connected() && $query) { $line = <$SOCKET>; $line =~ s/\r\n$//; if (substr($line, 3, 1) ne "-") { $query = 0; } $line = substr($line, 4, length($line)); Encode::from_to($line, $VDR_ENCODING, $MY_ENCODING) if ($need_recode); main::Log(LOG_DEBUG, sprintf("[SVDRP] Read \"%s\"", $line)); return ($line); } else { return undef; } } sub readresponse { my $this = shift; my @a = (); if($connected) { while (<$SOCKET>) { chomp; my $end = substr($_, 3, 1) ne "-"; $_ = substr($_, 4, length($_)); Encode::from_to($_, $VDR_ENCODING, $MY_ENCODING) if ($need_recode); push(@a, $_); last if ($end); } } return \@a; } sub socket { return $SOCKET; } sub encoding { return $VDR_ENCODING; } # ############################################################################# # Local variables: # indent-tabs-mode: nil # cperl-indent-level: 4 # perl-indent-level: 4 # tab-width: 4 # End: # EOF # vim: tabstop=4 smartindent shiftwidth=4 expandtab vdradmin-am-3.6.13/vdradmind.pl.1000066400000000000000000000036561443716113400164650ustar00rootroot00000000000000.\" Man page for vdradmind .TH vdradmind 8 .SH NAME vdradmind \- Web-based administration tool for VDR .SH SYNOPSIS .B vdradmind [OPTION]... .SH DESCRIPTION .B vdradmind provides a webinterface for managing the Linux Video Disk Recorder (VDR), it has a virtual remote to control your VDR, you can view live-tv as a small slideshow, you can search for certain shows in the EPG.... .PP By default .B vdradmind will listen on port 8001. .PP .B Note: Your VDR must be configured to be accessible via SVDRP from the machine, you run vdradmind from. .SH OPTIONS .IP "\-\-nofork / -n" Do not fork on start of vdradmind. (vdradmind does not go into daemon-mode) .IP "\-\-config / -c" Ask some questions, to interactively generate the config-file /etc/vdradmin/vdradmind.conf .IP "\-\-cfgdir dir/ -d dir" Path to the directory containing the VDRAdmin-AM config files. .IP "\-\-kill / -k" Kill a forked vdradmind. .IP "\-\-pid pidfile / -p pidfile" Set the pidfile to use. .IP "\-\-ipv6 / \-6" use IPv6. [EXPERIMENTAL!] .IP "\-\-ssl / -s" only accept https:// connections. .B NOTE: this requires server-cert.pem and server-key.pem in the "certs" directory. You can create them for example like this: # openssl req -new -x509 -days 9999 -keyout server-rsa-key.pem -out server-cert.pem # openssl rsa -in server-rsa-key.pem > server-key.pem .IP "\-\-log level / \-l level" set log level for this session [0 - 7]. .IP "\-\-help / -h" Display a short message about the options of vdradmind. .SH AUTHOR This man-page has been written by Thomas Schmidt and has been updated by Andreas Mair . .PP Permission is granted to copy, distribute and/or modify this document under the terms of the GNU General Public License, Version 2 any later version published by the Free Software Foundation. .PP On Debian systems, the complete text of the GNU General Public License can be found in /usr/share/common\-licenses/GPL.