diff --git a/.travis.yml b/.travis.yml index da5bf96b4..f51d80cbc 100644 --- a/.travis.yml +++ b/.travis.yml @@ -32,8 +32,8 @@ install: - sudo make install-libs before_script: - cd $TRAVIS_BUILD_DIR - - if [ "$ZM_BUILDMETHOD" = "autotools" ]; then libtoolize --force; fi - - if [ "$ZM_BUILDMETHOD" = "autotools" ]; then aclocal; fi + - if [ "$ZM_BUILDMETHOD" = "autotools" ]; then libtoolize -v --force; fi + - if [ "$ZM_BUILDMETHOD" = "autotools" ]; then aclocal -I m4; fi - if [ "$ZM_BUILDMETHOD" = "autotools" ]; then autoheader; fi - if [ "$ZM_BUILDMETHOD" = "autotools" ]; then automake --force-missing --add-missing; fi - if [ "$ZM_BUILDMETHOD" = "autotools" ]; then autoconf; fi diff --git a/CMakeLists.txt b/CMakeLists.txt index 787d2052c..d7d6a457c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,25 +1,28 @@ # Main CMake file for the ZoneMinder project. # Created by mastertheknife (Kfir Itzhak) -# The goal is to ease up the installation of zoneminder. -# Our current installation method (using autotools) is outdated, slow and breaks now and then. -# The CMake installation method will require no parameters at all, default should sufficient and reliable. -# It will be still possible to install ZoneMinder using autotools, they don't conflict with each other. The cmake way is a complete re-write (different syntax) and aims to be identical to the autotools way, -# by having options using the same name and leaving ZM totally unmodified, while providing exactly the same things that ZM expects (config.h, configuration in *.in files, etc). -# # For more information and installation, see the INSTALL file # cmake_minimum_required (VERSION 2.6) project (zoneminder) set(zoneminder_VERSION "1.28.1") -# CMake does not allow out-of-source build if CMakeCache.exists in the source folder. Abort and notify the user to save him from headache why it doesn't work. -if((NOT (CMAKE_BINARY_DIR STREQUAL CMAKE_SOURCE_DIR)) AND (EXISTS "${CMAKE_SOURCE_DIR}/CMakeCache.txt")) - message(FATAL_ERROR " You are attempting to do an out-of-source build, but a cmake cache file for an in-source build exists. Please delete the file CMakeCache.txt from the source folder to proceed.") -endif((NOT (CMAKE_BINARY_DIR STREQUAL CMAKE_SOURCE_DIR)) AND (EXISTS "${CMAKE_SOURCE_DIR}/CMakeCache.txt")) +# CMake does not allow out-of-source build if CMakeCache.exists +# in the source folder. Abort and notify the user +if( + (NOT (CMAKE_BINARY_DIR STREQUAL CMAKE_SOURCE_DIR)) + AND (EXISTS "${CMAKE_SOURCE_DIR}/CMakeCache.txt")) + message(FATAL_ERROR " You are attempting to do an out-of-source build, + but a cmake cache file for an in-source build exists. Please delete + the file CMakeCache.txt from the source folder to proceed.") +endif( + (NOT (CMAKE_BINARY_DIR STREQUAL CMAKE_SOURCE_DIR)) + AND (EXISTS "${CMAKE_SOURCE_DIR}/CMakeCache.txt")) -# Default build type. To change the build type, use the CMAKE_BUILD_TYPE configuration option. +# Default build type. To change the build type, +# use the CMAKE_BUILD_TYPE configuration option. if(NOT CMAKE_BUILD_TYPE) - set(CMAKE_BUILD_TYPE Release CACHE STRING "Build type: Release or Debug" FORCE) + set(CMAKE_BUILD_TYPE + Release CACHE STRING "Build type: Release or Debug" FORCE) endif(NOT CMAKE_BUILD_TYPE) # Can assist in troubleshooting @@ -42,35 +45,80 @@ include (CheckFunctionExists) include (CheckPrototypeDefinition_fixed) include (CheckTypeSize) include (CheckStructHasMember) +include (CheckSendfile) # Configuration options -mark_as_advanced(FORCE ZM_EXTRA_LIBS ZM_MYSQL_ENGINE ZM_NO_MMAP CMAKE_INSTALL_FULL_BINDIR ZM_PERL_SUBPREFIX ZM_PERL_USE_PATH ZM_TARGET_DISTRO ZM_CONFIG_DIR) -set(ZM_RUNDIR "/var/run/zm" CACHE PATH "Location of transient process files, default: /var/run/zm") -set(ZM_SOCKDIR "/var/run/zm" CACHE PATH "Location of Unix domain socket files, default /var/run/zm") -set(ZM_TMPDIR "/var/tmp/zm" CACHE PATH "Location of temporary files, default: /tmp/zm") -set(ZM_LOGDIR "/var/log/zm" CACHE PATH "Location of generated log files, default: /var/log/zm") -set(ZM_WEBDIR "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_DATADIR}/zoneminder/www" CACHE PATH "Location of the web files, default: /${CMAKE_INSTALL_DATADIR}/zoneminder/www") -set(ZM_CGIDIR "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBEXECDIR}/zoneminder/cgi-bin" CACHE PATH "Location of the cgi-bin files, default: /${CMAKE_INSTALL_LIBEXECDIR}/zoneminder/cgi-bin") -set(ZM_CONTENTDIR "/var/lib/zoneminder" CACHE PATH "Location of dynamic content (events and images), default: /var/lib/zoneminder") -set(ZM_DB_HOST "localhost" CACHE STRING "Hostname where ZoneMinder database located, default: localhost") -set(ZM_DB_NAME "zm" CACHE STRING "Name of ZoneMinder database, default: zm") -set(ZM_DB_USER "zmuser" CACHE STRING "Name of ZoneMinder database user, default: zmuser") -set(ZM_DB_PASS "zmpass" CACHE STRING "Password of ZoneMinder database user, default: zmpass") -set(ZM_WEB_USER "" CACHE STRING "The user apache or the local web server runs on. Leave empty for automatic detection. If that fails, you can use this variable to force") -set(ZM_WEB_GROUP "" CACHE STRING "The group apache or the local web server runs on, Leave empty to be the same as the web user") +mark_as_advanced( + FORCE ZM_EXTRA_LIBS + ZM_MYSQL_ENGINE + ZM_NO_MMAP + CMAKE_INSTALL_FULL_BINDIR + ZM_PERL_MM_PARMS + ZM_PERL_SEARCH_PATH + ZM_TARGET_DISTRO + ZM_CONFIG_DIR) + +set(ZM_RUNDIR "/var/run/zm" CACHE PATH + "Location of transient process files, default: /var/run/zm") +set(ZM_SOCKDIR "/var/run/zm" CACHE PATH + "Location of Unix domain socket files, default /var/run/zm") +set(ZM_TMPDIR "/var/tmp/zm" CACHE PATH + "Location of temporary files, default: /tmp/zm") +set(ZM_LOGDIR "/var/log/zm" CACHE PATH + "Location of generated log files, default: /var/log/zm") +set(ZM_WEBDIR "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_DATADIR}/zoneminder/www" CACHE PATH + "Location of the web files, default: /${CMAKE_INSTALL_DATADIR}/zoneminder/www") +set(ZM_CGIDIR "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBEXECDIR}/zoneminder/cgi-bin" CACHE PATH + "Location of the cgi-bin files, default: /${CMAKE_INSTALL_LIBEXECDIR}/zoneminder/cgi-bin") +set(ZM_CONTENTDIR "/var/lib/zoneminder" CACHE PATH + "Location of dynamic content (events and images), default: /var/lib/zoneminder") +set(ZM_DB_HOST "localhost" CACHE STRING + "Hostname where ZoneMinder database located, default: localhost") +set(ZM_DB_NAME "zm" CACHE STRING + "Name of ZoneMinder database, default: zm") +set(ZM_DB_USER "zmuser" CACHE STRING + "Name of ZoneMinder database user, default: zmuser") +set(ZM_DB_PASS "zmpass" CACHE STRING + "Password of ZoneMinder database user, default: zmpass") +set(ZM_WEB_USER "" CACHE STRING + "The user apache or the local web server runs on. Leave empty for automatic detection. + If that fails, you can use this variable to force") +set(ZM_WEB_GROUP "" CACHE STRING + "The group apache or the local web server runs on, + Leave empty to be the same as the web user") # Advanced -set(ZM_CONFIG_DIR "/${CMAKE_INSTALL_SYSCONFDIR}" CACHE PATH "Location of ZoneMinder configuration, default system config directory") -set(ZM_EXTRA_LIBS "" CACHE STRING "A list of optional libraries, separated by semicolons, e.g. ssl;theora") -set(ZM_MYSQL_ENGINE "InnoDB" CACHE STRING "MySQL engine to use with database, default: InnoDB") -set(ZM_NO_MMAP "OFF" CACHE BOOL "Set to ON to not use mmap shared memory. Shouldn't be enabled unless you experience problems with the shared memory. default: OFF") -set(ZM_NO_FFMPEG "OFF" CACHE BOOL "Set to ON to skip ffmpeg checks and force building ZM without ffmpeg. default: OFF") -set(ZM_NO_LIBVLC "OFF" CACHE BOOL "Set to ON to skip libvlc checks and force building ZM without libvlc. default: OFF") -set(ZM_NO_CURL "OFF" CACHE BOOL "Set to ON to skip cURL checks and force building ZM without cURL. default: OFF") -set(ZM_NO_X10 "OFF" CACHE BOOL "Set to ON to build ZoneMinder without X10 support. default: OFF") -set(ZM_ONVIF "OFF" CACHE BOOL "Set to ON to enable basic ONVIF support. This is EXPERIMENTAL and may not work with all cameras claiming to be ONVIF compliant. default: OFF") -set(ZM_PERL_SUBPREFIX "${CMAKE_INSTALL_LIBDIR}/perl5" CACHE PATH "Use a different directory for the zm perl modules. NOTE: This is a subprefix, e.g. lib will be turned into /lib, default: /perl5") -set(ZM_PERL_USE_PATH "${CMAKE_INSTALL_PREFIX}/${ZM_PERL_SUBPREFIX}" CACHE PATH "Override the include path for zm perl modules. Useful if you are moving the perl modules without using the ZM_PERL_SUBPREFIX option. default: /") -set(ZM_TARGET_DISTRO "" CACHE STRING "Build ZoneMinder for a specific distribution. Currently, valid names are: f21, f20, el6, OS13") +set(ZM_CONFIG_DIR "/${CMAKE_INSTALL_SYSCONFDIR}" CACHE PATH + "Location of ZoneMinder configuration, default system config directory") +set(ZM_EXTRA_LIBS "" CACHE STRING + "A list of optional libraries, separated by semicolons, e.g. ssl;theora") +set(ZM_MYSQL_ENGINE "InnoDB" CACHE STRING + "MySQL engine to use with database, default: InnoDB") +set(ZM_NO_MMAP "OFF" CACHE BOOL + "Set to ON to not use mmap shared memory. Shouldn't be enabled unless you + experience problems with the shared memory. default: OFF") +set(ZM_NO_FFMPEG "OFF" CACHE BOOL + "Set to ON to skip ffmpeg checks and force building ZM without ffmpeg. default: OFF") +set(ZM_NO_LIBVLC "OFF" CACHE BOOL +"Set to ON to skip libvlc checks and force building ZM without libvlc. default: OFF") +set(ZM_NO_CURL "OFF" CACHE BOOL + "Set to ON to skip cURL checks and force building ZM without cURL. default: OFF") +set(ZM_NO_X10 "OFF" CACHE BOOL + "Set to ON to build ZoneMinder without X10 support. default: OFF") +set(ZM_ONVIF "OFF" CACHE BOOL + "Set to ON to enable basic ONVIF support. This is EXPERIMENTAL and may not + work with all cameras claiming to be ONVIF compliant. default: OFF") +set(ZM_PERL_MM_PARMS INSTALLDIRS=vendor NO_PACKLIST=1 NO_PERLLOCAL=1 CACHE STRING + "By default, ZoneMinder's Perl modules are installed into the Vendor folders, + as defined by your installation of Perl. You can change that here. Consult Perl's + MakeMaker documentation for a definition of acceptable parameters. If you set this + to something that causes the modules to be installed outside Perl's normal search + path, then you will also need to set ZM_PERL_SEARCH_PATH accordingly.") +set(ZM_PERL_SEARCH_PATH "" CACHE PATH + "Use to add a folder to your Perl's search path. This will need to be set in cases + where ZM_PERL_MM_PARMS has been modified such that ZoneMinder's Perl modules are + installed outside Perl's default search path.") +set(ZM_TARGET_DISTRO "" CACHE STRING + "Build ZoneMinder for a specific distribution. Currently, valid names are: f21, f20, el6, OS13") # Reassign some variables if a target distro has been specified if((ZM_TARGET_DISTRO STREQUAL "f21") OR (ZM_TARGET_DISTRO STREQUAL "f20")) @@ -105,14 +153,40 @@ elseif(ZM_TARGET_DISTRO STREQUAL "OS13") endif((ZM_TARGET_DISTRO STREQUAL "f21") OR (ZM_TARGET_DISTRO STREQUAL "f20")) # Required for certain checks to work -set(CMAKE_EXTRA_INCLUDE_FILES ${CMAKE_EXTRA_INCLUDE_FILES} stdio.h stdlib.h math.h signal.h) +set(CMAKE_EXTRA_INCLUDE_FILES + ${CMAKE_EXTRA_INCLUDE_FILES} stdio.h stdlib.h math.h signal.h + ) # Required for including headers from the this folder include_directories("${CMAKE_BINARY_DIR}") # This is required to enable searching in lib64 (if exists), do not change set_property(GLOBAL PROPERTY FIND_LIBRARY_USE_LIB64_PATHS ON) +# Host OS Check +set(HOST_OS "") +if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux") + set(HOST_OS "linux") +endif(${CMAKE_SYSTEM_NAME} STREQUAL "Linux") +if(${CMAKE_SYSTEM_NAME} MATCHES ".*(SunOS|Solaris).*") + set(HOST_OS "solaris") + set(SOLARIS 1) +endif(${CMAKE_SYSTEM_NAME} MATCHES ".*(SunOS|Solaris).*") +if(${CMAKE_SYSTEM_NAME} MATCHES ".*BSD.*") + set(HOST_OS "BSD") + set(BSD 1) +endif(${CMAKE_SYSTEM_NAME} MATCHES ".*BSD.*") +if(${CMAKE_SYSTEM_NAME} STREQUAL "Darwin") + set(HOST_OS "darwin") +endif(${CMAKE_SYSTEM_NAME} STREQUAL "Darwin") +if(NOT HOST_OS) + message(FATAL_ERROR + "ZoneMinder was unable to deterimine the host OS. Please report this. Value of CMAKE_SYSTEM_NAME: ${CMAKE_SYSTEM_NAME}") +endif(NOT HOST_OS) + # System checks -check_include_file("linux/videodev.h" HAVE_LINUX_VIDEODEV_H) +check_include_file("libv4l1-videodev.h" HAVE_LIBV4L1_VIDEODEV_H) +if(NOT HAVE_LIBV4L1_VIDEODEV_H) + check_include_file("linux/videodev.h" HAVE_LINUX_VIDEODEV_H) +endif(NOT HAVE_LIBV4L1_VIDEODEV_H) check_include_file("linux/videodev2.h" HAVE_LINUX_VIDEODEV2_H) check_include_file("execinfo.h" HAVE_EXECINFO_H) check_include_file("ucontext.h" HAVE_UCONTEXT_H) @@ -167,10 +241,12 @@ if(JPEG_FOUND) set(CMAKE_REQUIRED_INCLUDES "${JPEG_INCLUDE_DIR}") check_include_files("stdio.h;jpeglib.h" HAVE_JPEGLIB_H) if(NOT HAVE_JPEGLIB_H) - message(FATAL_ERROR " zm requires libjpeg headers - check that libjpeg development packages are installed") + message(FATAL_ERROR + "ZoneMinder requires libjpeg headers - check that libjpeg development packages are installed") endif(NOT HAVE_JPEGLIB_H) else(JPEG_FOUND) - message(FATAL_ERROR "zm requires jpeg but it was not found on your system") + message(FATAL_ERROR + "ZoneMinder requires jpeg but it was not found on your system") endif(JPEG_FOUND) # OpenSSL @@ -200,10 +276,12 @@ if(PTHREAD_LIBRARIES) mark_as_advanced(FORCE PTHREAD_LIBRARIES PTHREAD_INCLUDE_DIR) check_include_file("pthread.h" HAVE_PTHREAD_H) if(NOT HAVE_PTHREAD_H) - message(FATAL_ERROR " zm requires pthread headers - check that pthread development packages are installed") + message(FATAL_ERROR + "ZoneMinder requires pthread headers - check that pthread development packages are installed") endif(NOT HAVE_PTHREAD_H) else(PTHREAD_LIBRARIES) - message(FATAL_ERROR "zm requires pthread but it was not found on your system") + message(FATAL_ERROR + "ZoneMinder requires pthread but it was not found on your system") endif(PTHREAD_LIBRARIES) # pcre (using find_library and find_path) @@ -275,10 +353,12 @@ if(MYSQLCLIENT_LIBRARIES) mark_as_advanced(FORCE MYSQLCLIENT_LIBRARIES MYSQLCLIENT_INCLUDE_DIR) check_include_file("mysql/mysql.h" HAVE_MYSQL_H) if(NOT HAVE_MYSQL_H) - message(FATAL_ERROR "zm requires MySQL headers - check that MySQL development packages are installed") + message(FATAL_ERROR + "ZoneMinder requires MySQL headers - check that MySQL development packages are installed") endif(NOT HAVE_MYSQL_H) else(MYSQLCLIENT_LIBRARIES) - message(FATAL_ERROR "zm requires mysqlclient but it was not found on your system") + message(FATAL_ERROR + "ZoneMinder requires mysqlclient but it was not found on your system") endif(MYSQLCLIENT_LIBRARIES) # x264 (using find_library and find_path) @@ -458,7 +538,8 @@ endif(NOT ZM_NO_LIBVLC) # Check for gnutls or crypto if((NOT HAVE_LIBCRYPTO) AND (NOT HAVE_LIBGNUTLS)) - message(FATAL_ERROR " zm requires crypto or gnutls but none were found on your system") + message(FATAL_ERROR + "ZoneMinder requires crypto or gnutls but none were found on your system") endif((NOT HAVE_LIBCRYPTO) AND (NOT HAVE_LIBGNUTLS)) # Check for V4L header files and enable ZM_HAS_V4L, ZM_HAS_V4L1, ZM_HAS_V4L2 accordingly @@ -466,17 +547,22 @@ endif((NOT HAVE_LIBCRYPTO) AND (NOT HAVE_LIBGNUTLS)) set(ZM_HAS_V4L 0) set(ZM_HAS_V4L1 0) set(ZM_HAS_V4L2 0) -if(HAVE_LINUX_VIDEODEV_H) +if(HAVE_LINUX_VIDEODEV_H OR HAVE_LIBV4L1_VIDEODEV_H) set(ZM_HAS_V4L 1) set(ZM_HAS_V4L1 1) -endif(HAVE_LINUX_VIDEODEV_H) +endif(HAVE_LINUX_VIDEODEV_H OR HAVE_LIBV4L1_VIDEODEV_H) if(HAVE_LINUX_VIDEODEV2_H) set(ZM_HAS_V4L 1) set(ZM_HAS_V4L2 1) endif(HAVE_LINUX_VIDEODEV2_H) -if((NOT HAVE_LINUX_VIDEODEV_H) AND (NOT HAVE_LINUX_VIDEODEV2_H)) - message(AUTHOR_WARNING " Video 4 Linux headers weren't found - Analog and USB camera support will not be available") -endif((NOT HAVE_LINUX_VIDEODEV_H) AND (NOT HAVE_LINUX_VIDEODEV2_H)) +if((NOT HAVE_LINUX_VIDEODEV_H) + AND (NOT HAVE_LIBV4L1_VIDEODEV_H) + AND (NOT HAVE_LINUX_VIDEODEV2_H)) + message(AUTHOR_WARNING + "Video 4 Linux headers weren't found - Analog and USB camera support will not be available") +endif((NOT HAVE_LINUX_VIDEODEV_H) + AND (NOT HAVE_LIBV4L1_VIDEODEV_H) + AND (NOT HAVE_LINUX_VIDEODEV2_H)) # Check for PCRE and enable ZM_PCRE accordingly set(ZM_PCRE 0) if(HAVE_LIBPCRE AND HAVE_PCRE_H) @@ -497,26 +583,37 @@ if(ZM_ONVIF) set(ZM_HAS_ONVIF 1) endif(ZM_ONVIF) -# Check for authenication functions +# Check for authentication functions if(HAVE_OPENSSL_MD5_H) set(CMAKE_REQUIRED_LIBRARIES "${OPENSSL_LIBRARIES}") set(CMAKE_REQUIRED_INCLUDES "${OPENSSL_INCLUDE_DIR}") - check_prototype_definition(MD5 "unsigned char *MD5(const unsigned char *d, size_t n, unsigned char *md)" "NULL" "openssl/md5.h" HAVE_MD5_OPENSSL) + check_prototype_definition( + MD5 + "unsigned char *MD5(const unsigned char *d, size_t n, unsigned char *md)" "NULL" "openssl/md5.h" + HAVE_MD5_OPENSSL) endif(HAVE_OPENSSL_MD5_H) if(HAVE_GNUTLS_OPENSSL_H) set(CMAKE_REQUIRED_LIBRARIES "${GNUTLS_LIBRARIES}") set(CMAKE_REQUIRED_INCLUDES "${GNUTLS_INCLUDE_DIR}") - check_prototype_definition(MD5 "unsigned char *MD5 (const unsigned char *buf, unsigned long len, unsigned char *md)" "NULL" "gnutls/openssl.h" HAVE_MD5_GNUTLS) + check_prototype_definition( + MD5 + "unsigned char *MD5 (const unsigned char *buf, unsigned long len, unsigned char *md)" "NULL" "gnutls/openssl.h" + HAVE_MD5_GNUTLS) endif(HAVE_GNUTLS_OPENSSL_H) if(HAVE_GNUTLS_GNUTLS_H) set(CMAKE_REQUIRED_LIBRARIES "${GNUTLS_LIBRARIES}") set(CMAKE_REQUIRED_INCLUDES "${GNUTLS_INCLUDE_DIR}") - check_prototype_definition(gnutls_fingerprint "int gnutls_fingerprint (gnutls_digest_algorithm_t algo, const gnutls_datum_t * data, void *result, size_t * result_size)" "0" "stdlib.h;gnutls/gnutls.h" HAVE_DECL_GNUTLS_FINGERPRINT) + check_prototype_definition( + gnutls_fingerprint + "int gnutls_fingerprint (gnutls_digest_algorithm_t algo, const gnutls_datum_t * data, void *result, size_t * result_size)" "0" "stdlib.h;gnutls/gnutls.h" + HAVE_DECL_GNUTLS_FINGERPRINT) endif(HAVE_GNUTLS_GNUTLS_H) if(HAVE_MD5_OPENSSL OR HAVE_MD5_GNUTLS) set(HAVE_DECL_MD5 1) else(HAVE_MD5_OPENSSL OR HAVE_MD5_GNUTLS) - message(AUTHOR_WARNING " ZM requires a working MD5 function for hashed authenication but none were found - hashed authenication will not be available") + message(AUTHOR_WARNING + "ZoneMinder requires a working MD5 function for hashed authenication but + none were found - hashed authenication will not be available") endif(HAVE_MD5_OPENSSL OR HAVE_MD5_GNUTLS) # Dirty fix for zm_user only using openssl's md5 if gnutls and gcrypt are not available. # This needs to be fixed in zm_user.[h,cpp] but such fix will also require changes to configure.ac @@ -528,26 +625,40 @@ endif(HAVE_LIBCRYPTO AND HAVE_OPENSSL_MD5_H AND HAVE_MD5_OPENSSL) # Check for Perl find_package(Perl) if(NOT PERL_FOUND) - message(FATAL_ERROR "zm requires Perl 5.6.0 or newer but it was not found on your system") + message(FATAL_ERROR + "ZoneMinder requires Perl 5.6.0 or newer but it was not found on your system") endif(NOT PERL_FOUND) # Checking for perl modules requires FindPerlModules.cmake # Check all required modules at once # TODO: Add checking for the optional modules -find_package(PerlModules COMPONENTS Sys::Syslog DBI DBD::mysql Getopt::Long Time::HiRes Date::Manip LWP::UserAgent ExtUtils::MakeMaker ${ZM_MMAP_PERLPACKAGE}) +find_package( + PerlModules COMPONENTS Sys::Syslog DBI DBD::mysql + Getopt::Long Time::HiRes Date::Manip LWP::UserAgent + ExtUtils::MakeMaker ${ZM_MMAP_PERLPACKAGE}) if(NOT PERLMODULES_FOUND) - message(FATAL_ERROR "Not all required perl modules were found on your system") + message(FATAL_ERROR + "Not all required perl modules were found on your system") endif(NOT PERLMODULES_FOUND) -# Attempt to check which user apache (or other web server) runs on by searching for a user beginning with apache or www and then cutting the user from the first matching user line +# Attempt to check which user apache (or other web server) runs on by +# searching for a user beginning with apache or www and then cutting the user +# from the first matching user line if(ZM_WEB_USER STREQUAL "") - # Check for a user matching ^apache and cut the username from the userline in the first match + # Check for a user matching ^apache and cut the username from the + # userline in the first match file(STRINGS "/etc/passwd" userline_apache REGEX "^apache") file(STRINGS "/etc/passwd" userline_www REGEX "^www") if(NOT (userline_apache STREQUAL "")) - execute_process(COMMAND echo ${userline_apache} COMMAND cut -d: -f1 OUTPUT_VARIABLE ZM_WEB_USER OUTPUT_STRIP_TRAILING_WHITESPACE) + execute_process( + COMMAND echo ${userline_apache} + COMMAND cut -d: -f1 OUTPUT_VARIABLE ZM_WEB_USER + OUTPUT_STRIP_TRAILING_WHITESPACE) elseif(NOT (userline_www STREQUAL "")) - execute_process(COMMAND echo ${userline_www} COMMAND cut -d: -f1 OUTPUT_VARIABLE ZM_WEB_USER OUTPUT_STRIP_TRAILING_WHITESPACE) + execute_process( + COMMAND echo ${userline_www} + COMMAND cut -d: -f1 OUTPUT_VARIABLE ZM_WEB_USER + OUTPUT_STRIP_TRAILING_WHITESPACE) endif(NOT (userline_apache STREQUAL "")) message(STATUS "Detected web server user: ${ZM_WEB_USER}") endif(ZM_WEB_USER STREQUAL "") @@ -561,7 +672,8 @@ message(STATUS "Using web group: ${ZM_WEB_GROUP}") # Check for polkit find_package(Polkit) if(NOT POLKIT_FOUND) - message(FATAL_ERROR "Running ZoneMinder requires polkit. Building ZoneMinder requires the polkit development package.") + message(FATAL_ERROR + "Running ZoneMinder requires polkit. Building ZoneMinder requires the polkit development package.") endif(NOT POLKIT_FOUND) # Some variables that zm expects @@ -577,7 +689,11 @@ set(CGI_PREFIX "${ZM_CGIDIR}") set(WEB_USER "${ZM_WEB_USER}") set(WEB_GROUP "${ZM_WEB_GROUP}") set(ZM_DB_TYPE "mysql") -set(EXTRA_PERL_LIB "use lib '${ZM_PERL_USE_PATH}';") +if(ZM_PERL_SEARCH_PATH) + set(EXTRA_PERL_LIB "use lib '${ZM_PERL_SEARCH_PATH}'; # Include custom perl install path") +else(ZM_PERL_SEARCH_PATH) + set(EXTRA_PERL_LIB "# Include from system perl paths only") +endif(ZM_PERL_SEARCH_PATH) # Generate files from the .in files configure_file(zm.conf.in "${CMAKE_CURRENT_BINARY_DIR}/zm.conf" @ONLY) @@ -593,9 +709,9 @@ add_subdirectory(web) add_subdirectory(misc) # Enable ONVIF support -if (ZM_ONVIF) +if(ZM_ONVIF) add_subdirectory(onvif) -endif (ZM_ONVIF) +endif(ZM_ONVIF) # Process distro subdirectories if((ZM_TARGET_DISTRO STREQUAL "f21") OR (ZM_TARGET_DISTRO STREQUAL "f20")) @@ -614,9 +730,11 @@ message(STATUS "Optional libraries not found:${optlibsnotfound}") message(STATUS "Running ZoneMinder configuration generator") execute_process(COMMAND perl ./zmconfgen.pl RESULT_VARIABLE zmconfgen_result) if(zmconfgen_result EQUAL 0) - message(STATUS "ZoneMinder configuration generator completed successfully") + message(STATUS + "ZoneMinder configuration generator completed successfully") else(zmconfgen_result EQUAL 0) - message(FATAL_ERROR "ZoneMinder configuration generator failed. Exit code: ${zmconfgen_result}") + message(FATAL_ERROR + "ZoneMinder configuration generator failed. Exit code: ${zmconfgen_result}") endif(zmconfgen_result EQUAL 0) # Install zm.conf diff --git a/INSTALL b/INSTALL index 6d329bcd4..8f892e840 100644 --- a/INSTALL +++ b/INSTALL @@ -53,8 +53,8 @@ Advanced: ZM_NO_MMAP Set to ON to not use mmap shared memory. Shouldn't be enabled unless you experience problems with the shared memory. default: OFF ZM_NO_FFMPEG Set to ON to skip ffmpeg checks and force building ZM without ffmpeg. default: OFF ZM_NO_X10 Set to ON to build ZoneMinder without X10 support. default: OFF - ZM_PERL_SUBPREFIX Use a different directory for the zm perl modules. NOTE: This is a subprefix, e.g. /lib will be turned into /lib, default: /perl5 - ZM_PERL_USE_PATH Override the include path for zm perl modules. Useful if you are moving the perl modules without using the ZM_PERL_SUBPREFIX option. default: / + ZM_PERL_MM_PARMS By default, ZoneMinder's Perl modules are installed into the Vendor folders, as defined by your installation of Perl. You can change that here. Consult Perl's MakeMaker documentation for a definition of acceptable parameters. If you set this to something that causes the modules to be installed outside Perl's normal serach path, then you will also need to set ZM_PERL_SEARCH_PATH accordingly. default: "INSTALLDIRS=vendor NO_PACKLIST=1 NO_PERLLOCAL=1" + ZM_PERL_SEARCH_PATH Use to add a folder to your Perl's search path. This will need to be set in cases where ZM_PERL_MM_PARMS has been modified such that ZoneMinder's Perl modules are installed outside Perl's default search path. default: "" Useful configuration options provided by cmake: CMAKE_VERBOSE_MAKEFILE - Set this to ON (default OFF) to see what cmake is doing. Very useful for troubleshooting. @@ -93,9 +93,19 @@ NOTE: The database server, database name, user and password can be different and 8) Create an apache virtual host for ZoneMinder. Make sure to use the same paths as ZM_WEBDIR and ZM_CGIDIR in /etc/zm.conf 9) Create other config if desired (e.g. rsyslog, logrotate and such). Some of this can be found in /share/zoneminder/misc or project/misc directory -10) Setup an appropriate startup script for your system. A generic sys v init script is here: /scripts/zm while a generic systemd service file is here: /misc/zoneminder.service -You must determine which file to use, verify it is correct, and then copy it to the correct location. Consult your distro's documentation. Note that distros using systemd also -require /misc/zoneminder-tmpfiles.conf to be copied into the system's tmpfiles.d folder. +10) Setup an appropriate startup script for your system. Two generic startup scripts have been provided, a legacy Sys V Init script and a Systemd service file. + +*Sys V Init Setup* +- Copy the sys v init script /scripts/zm from the build folder to /etc/init. +- Inspect the contents to make sure they apply to your distro. + +*SystemD Setup* +- Copy the zoneminder systemd service file /misc/zoneminder.service from the build folder to the systemd service file location. + For Redhat based distros, that folder is /usr/lib/systemd/system. +- Inspect the contents to make sure they apply to your distro. +- Tell systemd to load the new service file: "sudo systemctl daemon-reload". +- Copy /misc/zoneminder-tmpfiles.conf to /etc/tmpfiles.d +- Tell systemd to process this file: "sudo /usr/bin/systemd-tmpfiles --create /etc/tmpfiles.d/zoneminder.conf". Basic steps for upgrading ZoneMinder ------------------------------------ diff --git a/Makefile.am b/Makefile.am index f6d46bc3d..62f767e75 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,4 +1,5 @@ AUTOMAKE_OPTIONS = foreign +ACLOCAL_AMFLAGS = -I m4 # And these to the user and group of your webserver webuser = @WEB_USER@ diff --git a/README.md b/README.md index 1008c8560..fa3265d82 100644 --- a/README.md +++ b/README.md @@ -12,13 +12,46 @@ All documentation for ZoneMinder is now online at http://www.zoneminder.com/wiki ZoneMinder is an integrated set of applications which provide a complete surveillance solution allowing capture, analysis, recording and monitoring of any CCTV or security cameras attached to a Linux based machine. It is designed to run on distributions which support the Video For Linux (V4L) interface and has been tested with video cameras attached to BTTV cards, various USB cameras and also supports most IP network cameras. -## Requirements +## Installation Methods -If you are installing ZoneMinder from a package, that package should provide all of the needed core components. +### Building from Source is Discouraged -### Packages +Historically, installing ZoneMinder onto your system required building from source code by issuing the traditional configure, make, make install commands. To get ZoneMinder to build, all of its dependencies had to be determined and installed beforehand. Init and logrotate scripts had to be manually copied into place following the build. Optional packages such as jscalendar and Cambozola had to be manually installed. Uninstalls could leave stale files around, which could cause problems during an upgrade. Speaking of upgrades, when it comes time to upgrade all these manual steps must be repeated again. -If you are compiling ZoneMinder from source, the below list contains the packages needed to get ZoneMinder built: +Better methods exist today that do much of this for you. The current development team, along with other volunteers, have taken great strides in providing the resources necessary to avoid building from source. + +### Install from a Package Repository + +This is the recommended method to install ZoneMinder onto your system. ZoneMinder packages are maintained for the following distros: + +- Ubuntu via [Iconnor's PPA](https://launchpad.net/~iconnor/+archive/ubuntu/zoneminder) +- Debian from their [default repository](https://packages.debian.org/search?searchon=names&keywords=zoneminder) +- RHEL/CentOS and clones via [zmrepo](http://zmrepo.zoneminder.com/) +- Fedora via [zmrepo](http://zmrepo.zoneminder.com/) +- OpenSuse via [third party repository](http://www.zoneminder.com/wiki/index.php/Installing_using_ZoneMinder_RPMs_for_SuSE) +- Maegia from their default repository + +If a repository that hosts ZoneMinder packages is not available for your distro, then you are encouraged to build your own package, rather than build from source. While each distro is different in ways that set it apart from all the others, they are often similar enough to allow you to adapt another distro's package building instructions to your own. + +### Building a ZoneMinder Package + +Building ZoneMinder into a package is not any harder than building from source. As a matter of fact, if you have successfully built ZoneMinder from source in the past, then you may find these steps to be easier. + +When building a package, it is best to do this work in a separate environment, dedicated to development purposes. This could be as simple as creating a virtual machine, using Docker, or using mock. All it takes is one “Oops” to regret doing this work on your production server. + +Lastly, if you desire to build a development snapshot from the master branch, it is recommended you first build your package using an official release of ZoneMinder. This will help identify whether any problems you may encounter are caused by the build process or is a new issue in the master branch. + +What follows are instructions for various distros to build ZoneMinder into a package. + +### Package Maintainters +Many of the ZoneMinder configration variable default values are not configurable at build time through autotools or cmake. A new tool called *zmeditconfigdata.sh* has been added to allow package maintainers to manipulate any variable stored in ConfigData.pm without patching the source. + +For example, let's say I have created a new ZoneMinder package that contains the cambolzola javascript file. However, by default cambozola support is turned off. To fix that, add this to the pacakging script: +```bash +./utils/zmeditconfigdata.sh ZM_OPT_CAMBOZOLA yes +``` + +Note that zmeditconfigdata.sh is intended to be called, from the root build folder, prior to running cmake or configure. #### Ubuntu @@ -104,42 +137,118 @@ root@host:~# aptitude install -y gdebi; root@host:~# gdebi /root/zoneminder_1.26.4-1_amd64.deb; ``` -#### CentOS / RHEL +#### Fedora / CentOS / RHEL -Additional repositories must be added before one can build zoneminder on CentOS or RHEL: +***DRAFT* ** Needs Testing -1. Zmrepo [ZoneMinder WiKi](http://www.zoneminder.com/wiki/index.php/CentOS#Zmrepo_-_A_ZoneMinder_repository_for_RPM_based_distros) -2. EPEL https://fedoraproject.org/wiki/EPEL -3. RPMFusion: http://rpmfusion.org/ +##### Background +The following method documents how to build ZoneMinder into an RPM package, compatible with Fedora, Redhat, CentOS, and other compatible clones. This is exactly how the RPMS in zmrepo are built. -When adding third party repositories, it is highly recommended that the user also install and configure yum priorities as documented in the [CentOS WiKi](http://wiki.centos.org/PackageManagement/Yum/Priorities) +The method documented below was chosen because: +- All of ZoneMinder's dependencies are downloaded and installed automatically +- Cross platform capable. The build host does not have to be the same distro or release version as the target. +- Once your build environment is set up, few steps are required to run the build again in the future. +- Troubleshooting becomes easier if we are all building ZoneMinder the same way. -Prioritize the repositories: +The build instructions below make use of a custom script called "buildzm.sh". Advanced users are encouraged to view the contents of this script. Notice that the script doesn't really do a whole lot. The goal of the script is to simply make the process a little easier for the first time user. Once you become familar with the build process, you can issue the mock commands found in the buildzm.sh script yourself if you so desire. -1. Base -2. EPEL -3. RPMFusion -4. Zmrepo +***IMPORTANT*** +Certain commands in these instructions require root privileges while other commands do not. Pay close attention to this. If the instructions below state to issue a command without a “sudo” prefix, then you should *not* be root while issuing the command. Getting this incorrect will result in a failed build. -Once your repos are in order, install the following: -```bash -sudo yum install cmake bzip2-devel ffmpeg ffmpeg-devel gnutls-devel httpd libjpeg-turbo libjpeg-turbo-devel mysql-devel mysql-server pcre-devel \ -perl-Archive-Tar perl-Archive-Zip perl-Convert-BinHex perl-Date-Manip perl-DBD-MySQL perl-DBI perl-Device-SerialPort perl-Email-Date-Format perl-IO-stringy \ -perl-IO-Zlib perl-MailTools perl-MIME-Lite perl-MIME-tools perl-MIME-Types perl-Module-Load perl-Package-Constants perl-Sys-Mmap perl-Time-HiRes \ -perl-TimeDate perl-YAML-Syck perl-X10 perl-URI-Encode php php-cli php-mysql x264 vlc-devel vlc-core \ -libcurl libcurl-devel polkit-devel git +##### Set Up Your Environment +Before you begin, set up an rpmbuild environment by following [this guide](http://wiki.centos.org/HowTos/SetupRpmBuildEnvironment) by the CentOS developers. + +Next, navigate to [Zmrepo](http://zmrepo.zoneminder.com/), and follow the instructions to enable zmrepo on your system. + +With zmrepo enabled, issue the following command: +````bash +sudo yum install zmrepo-mock-configs mock ``` -To build from the master branch: +Add your user account to the group mock: ```bash -git clone https://github.com/ZoneMinder/ZoneMinder.git -cd ZoneMinder -cmake . -make -sudo make install +sudo gpasswd -a {your account name} mock ``` -IMPORTANT: Don't forget the trailing "." when calling cmake +Your build environment is now set up. + +##### Build from SRPM +To continue, you need a ZoneMinder SRPM. For starters, let's use one of the SRPMS from zmrepo. Go browse the [Zmrepo](http://zmrepo.zoneminder.com/) site and choose an appropriate SRPM and place it into the ~/rpmbuild/SRPMS folder. + +For CentOS 7, I have chosen the following SRPM: +```bash +wget -P ~/rpmbuild/SRPMS http://zmrepo.zoneminder.com/el/7/SRPMS/zoneminder-1.28.1-2.el7.centos.src.rpm +``` + +Now comes the fun part. To build ZoneMinder, issue the following command: +```bash +buildzm.sh zmrepo-el7-x86_64 ~/rpmbuild/SRPMS/zoneminder-1.28.1-2.el7.centos.src.rpm +``` + +Want to build ZoneMinder for Fedora, instead of CentOS, from the same host? Once you download the Fedora SRPM, issue the following: +```bash +buildzm.sh zmrepo-f21-x86_64 ~/rpmbuild/SRPMS/zoneminder-1.28.1-1.fc21.src.rpm +``` +Notice that the buildzm.sh tool requires the following parameters: +```bash +buildzm.sh MOCKCONFIG ZONEMINDER_SRPM +``` +The list of available Mock config files are available here: +```bash +ls /etc/mock/zmrepo*.cfg +``` + +You choose the config file based on the desired distro (e.g. el6, el7, f20, f21) and basearch (e.g. x86, x86_64, arhmhfp). Notice that, when specifying the Mock config as a commandline parameter, you should leave off the ".cfg" filename extension. + +##### Installation +Once the build completes, you will be presented with a folder containing the RPM's that were built. Copy the newly built ZoneMinder RPM to the desired system, enable zmrepo per the instruction on the [Zmrepo](http://zmrepo.zoneminder.com/) website, and then install the rpm by issuing the appropriate yum install command. Finish the installation by following the zoneminder setup instructions in the distro specific readme file, named README.{distroname}, which will be installed into the /usr/share/doc/zoneminder* folder. + +Finally, you may want to consider editing the zmrepo repo file under /etc/yum.repos.d and placing an “exclude=zoneminder*” line into the config file. This will prevent your system from overwriting your manually built RPM with the ZoneMinder RPM found in the repo. + +##### How to Modify the Source Prior to Build +** UNFINISHED ** + +Before attempting this part of the instructions, make sure and follow the previous instructions for building one of the unmodified SRPMS from zmrepo. Knowing this part works will assist in troubleshooting should something go wrong. + +These instructions may vary depending on what exactly you want to do. The following example assumes you want to build a development snapshot from the master branch. + +From the previous instructions, we downloaded a CentOS 7 ZoneMinder SRPM and placed it into ~/rpmbuild/SRPMS. For this example, install it onto your system: +```bash +rpm -Uvh ~/rpmbuild/SRPMS/zoneminder-1.28.1-2.el7.centos.src.rpm +``` + +IMPORTANT: This operation must be done with your normal user account. Do *not* perform this command as root. + +Make sure you have git installed: +```bash +sudo yum install git +``` + +Now clone the ZoneMinder git repository: +```bash +git clone https://github.com/ZoneMinder/ZoneMinder +``` +This will create a sub-folder called ZoneMinder, which will contain the latest developement. + +We want to turn this into a tarball, but first we need to figure out what to name it. Look here: +```bash +ls ~/rpmbuild/SOURCES +``` +The tarball from the previsouly installed SRPM should be there. This is the name we will use. For this example, the name is ZoneMinder-1.28.1.tar.gz. From one folder above the local ZoneMinder git repository, execute the following: +```bash +mv ZoneMinder ZoneMinder-1.28.1 +tar -cvzf ~/rpmbuild/SOURCES/ZoneMinder-1.28.1.tar.gz ZoneMinder-1.28.1/* +``` +The trailing "/*" leaves off the hidden dot "." file and folders from the git repo, which is what we want. +Note that we are overwriting the original tarball. If you wish to keep the original tarball then create a copy prior to creating the new tarball. + +Now build a new src.rpm: +```bash +rpmbuild -bs --nodeps ~/rpmbuild/SPECS/zoneminder.el7.spec +``` +This step will overwrite the SRPM you originally downloaded, so you may want to back it up prior to completing this step. Note that the name of the specfile will vary slightly depending on what distro you are building for. + +You should now have a a new SRPM under ~/rpmbuild/SRPMS. In our example, the SRPM is called zoneminder-1.28.1-2.el7.centos.src.rpm. Now follow the previous instructions that describe how to use the buildzm script, using ~/rpmbuild/SRPMS/zoneminder-1.28.1-2.el7.centos.src.rpm as the path to your SRPM. #### Docker @@ -147,11 +256,6 @@ Docker is a system to run applications inside isolated containers. ZoneMinder, a Dockerfile contained in this repository. However, there is still work needed to ensure that the main ZM features work properly and are documented. -### ffmpeg - -This release of ZoneMinder has been tested on and works with ffmpeg version N-55540-g93f4277. - - ## Contribution Model and Development * Source hosted at [GitHub](https://github.com/ZoneMinder/ZoneMinder/) @@ -172,14 +276,4 @@ the following steps. 6. Create new Pull Request 7. The team will then review, discuss and hopefully merge your changes. -### Package Maintainters -Many of the ZoneMinder configration variable default values are not configurable at build time through autotools or cmake. A new tool called *zmeditconfigdata.sh* has been added to allow package maintainers to manipulate any variable stored in ConfigData.pm without patching the source. - -For example, let's say I have created a new ZoneMinder package that contains the cambolzola javascript file. However, by default cambozola support is turned off. To fix that, add this to the pacakging script: -```bash -./utils/zmeditconfigdata.sh ZM_OPT_CAMBOZOLA yes -``` - -Note that zmeditconfigdata.sh is intended to be called, from the root build folder, prior to running cmake or configure. - [![Analytics](https://ga-beacon.appspot.com/UA-15147273-6/ZoneMinder/README.md)](https://github.com/igrigorik/ga-beacon) diff --git a/bootstrap.sh b/bootstrap.sh index 681d5b319..0bc041f18 100755 --- a/bootstrap.sh +++ b/bootstrap.sh @@ -1,5 +1,5 @@ #!/bin/bash -aclocal +aclocal -I m4 autoheader automake --add-missing autoconf diff --git a/cmake/Modules/CheckSendfile.cmake b/cmake/Modules/CheckSendfile.cmake new file mode 100644 index 000000000..1796b92e3 --- /dev/null +++ b/cmake/Modules/CheckSendfile.cmake @@ -0,0 +1,58 @@ +# Check whether sendfile() is supported and what prototype it has +include(CheckCSourceCompiles) +if (UNIX OR MINGW) +SET(CMAKE_REQUIRED_DEFINITIONS -Werror-implicit-function-declaration) +endif() +check_c_source_compiles("#include +#include +int main() +{ +sendfile(1, 1, NULL, 0); +return 0; +}" HAVE_SENDFILE4_SUPPORT) +if(HAVE_SENDFILE4_SUPPORT) +add_definitions(-DHAVE_SENDFILE4_SUPPORT=1) +unset(CMAKE_REQUIRED_DEFINITIONS) +message(STATUS "Sendfile support: Linux/Solaris sendfile()") +return() +endif() +find_library(SENDFILE_LIBRARIES NAMES sendfile) +if(SENDFILE_LIBRARIES) +include(CheckLibraryExists) +check_library_exists(sendfile sendfile ${SENDFILE_LIBRARIES} HAVE_SENDFILE4_SUPPORT) +if(HAVE_SENDFILE4_SUPPORT) +add_definitions(-DHAVE_SENDFILE4_SUPPORT=1) +unset(CMAKE_REQUIRED_DEFINITIONS) +message(STATUS "Sendfile support: Solaris sendfile()") +return() +endif() +endif() +set(SENDFILE_LIBRARIES "") +check_c_source_compiles("#include +#include +int main() +{ +sendfile(1, 1, 0, 0, NULL, NULL, 0); +return 0; +}" HAVE_SENDFILE7_SUPPORT) +if(HAVE_SENDFILE7_SUPPORT) +add_definitions(-DHAVE_SENDFILE7_SUPPORT=1) +unset(CMAKE_REQUIRED_DEFINITIONS) +message(STATUS "Sendfile support: FreeBSD sendfile()") +return() +endif() +check_c_source_compiles("#include +#include +#include +int main() +{ +sendfile(1, 1, 0, NULL, NULL, 0); +return 0; +}" HAVE_SENDFILE6_SUPPORT) +if(HAVE_SENDFILE6_SUPPORT) +add_definitions(-DHAVE_SENDFILE6_SUPPORT=1) +unset(CMAKE_REQUIRED_DEFINITIONS) +message(STATUS "Sendfile support: MacOS sendfile()") +return() +endif() + diff --git a/configure.ac b/configure.ac index f6cb789a3..7060bd38b 100644 --- a/configure.ac +++ b/configure.ac @@ -3,6 +3,7 @@ AC_INIT(zm,1.28.1,[http://www.zoneminder.com/forums/ - Please check FAQ first],z AM_INIT_AUTOMAKE AC_CONFIG_SRCDIR(src/zm.h) AC_CONFIG_HEADERS(config.h) +AC_CONFIG_MACRO_DIR([m4]) AC_SUBST([AM_CXXFLAGS], [-D__STDC_CONSTANT_MACROS]) @@ -26,6 +27,17 @@ case $host_os in *BSD*) # Do something specific for BSD HOST_OS='BSD' + AC_DEFINE(BSD,1,"This is a BSD system") + ;; + *bsd*) + # Do something specific for BSD + HOST_OS='BSD' + AC_DEFINE(BSD,1,"This is a BSD system") + ;; + *solaris*) + # Do something specific for Solaris + HOST_OS='solaris' + AC_DEFINE(SOLARIS,1,"We are running a Solaroid OS [tested on OmniOS]") ;; *) #Default Case @@ -315,22 +327,20 @@ AC_FUNC_STRTOD AC_FUNC_VPRINTF AC_CHECK_FUNCS([gethostbyname gethostname gettimeofday memmove memset mkdir munmap posix_memalign putenv select sendfile socket sqrt strcasecmp strchr strcspn strerror strncasecmp strrchr strspn strstr strtol strtoull]) AC_CHECK_FUNCS([syscall sleep usleep ioctl ioctlsocket sigaction]) - +# this is required for freebsd to compile. Look for it in m4/ac_check_sendfile.m4 +AC_CHECK_SENDFILE # Other programs AC_CHECK_PROG(OPT_FFMPEG,ffmpeg,yes,no) AC_PATH_PROG(PATH_FFMPEG,ffmpeg) -AC_CHECK_PROG(OPT_NETPBM,pnmscale,yes,no) -AC_PATH_PROG(PATH_NETPBM,pnmscale) -if test "$OPT_NETPBM" == "yes"; then -PATH_NETPBM=`dirname $PATH_NETPBM` -fi # Checks for libraries. AC_CHECK_LIB(rt,clock_gettime,,AC_MSG_ERROR(zm requires librt)) AC_SEARCH_LIBS(mysql_init,[mysqlclient mariadbclient],,AC_MSG_ERROR(zm requires libmysqlclient.a or libmariadbclient.a)) AC_CHECK_LIB(jpeg,jpeg_start_compress,,AC_MSG_ERROR(zm requires libjpeg.a)) AC_CHECK_LIB(pthread,pthread_create,,AC_MSG_ERROR(zm requires libpthread.a)) +if test "$BSD" == "0"; then AC_CHECK_LIB(dl,dlsym,,AC_MSG_ERROR(zm requires libdl.a)) +fi if test "$ZM_SSL_LIB" == "openssl"; then AC_CHECK_HEADERS(openssl/md5.h,,AC_MSG_WARN(zm requires openssl/md5.h header to be installed for openssl),) AC_CHECK_LIB(crypto,MD5,,AC_MSG_WARN([libcrypto.a is required for authenticated streaming - use ZM_SSL_LIB option to select gnutls instead])) @@ -374,14 +384,26 @@ AC_CHECK_HEADERS(execinfo.h,,,) AC_CHECK_HEADERS(ucontext.h,,,) AC_CHECK_HEADERS(sys/syscall.h,,,) AC_CHECK_HEADERS(pthread.h,,,) -AC_CHECK_HEADERS(linux/videodev.h,AC_SUBST(ZM_HAS_V4L1,1),AC_SUBST(ZM_HAS_V4L1,0),) -AC_CHECK_HEADERS(linux/videodev2.h,AC_SUBST(ZM_HAS_V4L2,1),AC_SUBST(ZM_HAS_V4L2,0),) + +# Check for Video for Linux 1 Header Files +ZM_HAS_V4L1=0 +AC_CHECK_HEADERS([libv4l1-videodev.h linux/videodev.h],[ZM_HAS_V4L1=1; break;],,) +AC_SUBST(ZM_HAS_V4L1) + +# Check for Video for Linux 2 Header Files +ZM_HAS_V4L2=0 +AC_CHECK_HEADERS(linux/videodev2.h,ZM_HAS_V4L2=1,,) +AC_SUBST(ZM_HAS_V4L2) + +# Set global Video for Linux flag +ZM_HAS_V4L=0 if test "$ZM_HAS_V4L1" == "1" || test "$ZM_HAS_V4L2" == "1"; then -AC_SUBST(ZM_HAS_V4L,1) +ZM_HAS_V4L=1 else -AC_SUBST(ZM_HAS_V4L,0) AC_MSG_WARN(zm requires Video4Linux or Video4Linux2 to be installed for analog or USB camera support) fi +AC_SUBST(ZM_HAS_V4L) + AC_CHECK_HEADERS(jpeglib.h,,AC_MSG_ERROR(zm requires libjpeg headers to be installed),) AC_CHECK_HEADERS(mysql/mysql.h,,AC_MSG_ERROR(zm requires MySQL headers - check that MySQL development packages are installed),) AC_LANG_PUSH([C]) diff --git a/db/zm_update-1.28.99.sql b/db/zm_update-1.28.99.sql index 5c2c9aeff..660b19db4 100644 --- a/db/zm_update-1.28.99.sql +++ b/db/zm_update-1.28.99.sql @@ -108,4 +108,9 @@ SELECT * FROM (SELECT NULL as Id, WHERE NOT EXISTS ( SELECT Name FROM Controls WHERE name = 'ONVIF Camera' ) LIMIT 1; +-- +-- Hide USE_DEEP_STORAGE from user to prevent accidental event loss +-- +UPDATE `zm`.`Config` SET `Category`='hidden' WHERE `Name`='ZM_USE_DEEP_STORAGE'; + diff --git a/distros/debian_cmake/rules b/distros/debian_cmake/rules index 0bf0f3362..aa0501ab1 100755 --- a/distros/debian_cmake/rules +++ b/distros/debian_cmake/rules @@ -22,7 +22,6 @@ override_dh_auto_configure: -DZM_CGIDIR=/usr/lib/cgi-bin \ -DZM_WEB_USER=www-data \ -DZM_WEB_GROUP=www-data \ - -DZM_PERL_SUBPREFIX=/share/perl5 \ -DCMAKE_INSTALL_SYSCONFDIR=etc/zm override_dh_auto_install: diff --git a/distros/fedora/CMakeLists.txt b/distros/fedora/CMakeLists.txt index 7409a2e39..deec840f7 100644 --- a/distros/fedora/CMakeLists.txt +++ b/distros/fedora/CMakeLists.txt @@ -32,7 +32,7 @@ install(CODE "execute_process(COMMAND ln -sf ../../java/cambozola.jar \"\$ENV{DE # Install auxillary files required to run zoneminder on Fedora install(FILES zoneminder.conf DESTINATION /etc/httpd/conf.d PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ) install(FILES zoneminder.logrotate DESTINATION /etc/logrotate.d RENAME zoneminder PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ) -install(FILES zoneminder.tmpfiles DESTINATION /etc/tmpfiles.d RENAME zoneminder.conf PERMISSIONS OWNER_WRITE OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) +install(FILES ../../misc/zoneminder-tmpfiles.conf DESTINATION /etc/tmpfiles.d RENAME zoneminder.conf PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ) install(FILES redalert.wav DESTINATION ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_DATAROOTDIR}/zoneminder/www/sounds PERMISSIONS OWNER_WRITE OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) install(FILES zoneminder.service DESTINATION /usr/lib/systemd/system PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ) diff --git a/distros/fedora/archive/zoneminder.cmake.f19.spec b/distros/fedora/archive/zoneminder.cmake.f19.spec index a7aee3265..771209247 100644 --- a/distros/fedora/archive/zoneminder.cmake.f19.spec +++ b/distros/fedora/archive/zoneminder.cmake.f19.spec @@ -72,7 +72,6 @@ too much degradation of performance. %build %cmake \ -DZM_TARGET_DISTRO="f19" \ - -DZM_PERL_SUBPREFIX=`x="%{perl_vendorlib}" ; echo ${x#"%{_prefix}"}` \ %{?_without_ffmpeg:-DZM_NO_FFMPEG=ON} \ %{?_without_x10:-DZM_NO_X10=ON} \ . diff --git a/distros/fedora/zoneminder.f20.spec b/distros/fedora/zoneminder.f20.spec index a49361ef3..59dfa6c1e 100644 --- a/distros/fedora/zoneminder.f20.spec +++ b/distros/fedora/zoneminder.f20.spec @@ -31,7 +31,7 @@ BuildRequires: perl(MIME::Entity) perl(MIME::Lite) BuildRequires: perl(PHP::Serialization) perl(Sys::Mmap) BuildRequires: perl(Time::HiRes) perl(Net::SFTP::Foreign) BuildRequires: perl(Expect) perl(Sys::Syslog) -BuildRequires: gcc gcc-c++ vlc-devel libcurl-devel +BuildRequires: gcc gcc-c++ vlc-devel libcurl-devel libv4l-devel %{!?_without_ffmpeg:BuildRequires: ffmpeg-devel} %{!?_without_x10:BuildRequires: perl(X10::ActiveHome) perl(Astro::SunTime)} # cmake needs the following installed at build time due to the way it auto-detects certain parameters @@ -76,7 +76,6 @@ too much degradation of performance. %build %cmake \ -DZM_TARGET_DISTRO="f20" \ - -DZM_PERL_SUBPREFIX=`x="%{perl_vendorlib}" ; echo ${x#"%{_prefix}"}` \ %{?_without_ffmpeg:-DZM_NO_FFMPEG=ON} \ %{?_without_x10:-DZM_NO_X10=ON} \ . diff --git a/distros/fedora/zoneminder.f21.spec b/distros/fedora/zoneminder.f21.spec index 31afc0417..94986336e 100644 --- a/distros/fedora/zoneminder.f21.spec +++ b/distros/fedora/zoneminder.f21.spec @@ -31,7 +31,7 @@ BuildRequires: perl(MIME::Entity) perl(MIME::Lite) BuildRequires: perl(PHP::Serialization) perl(Sys::Mmap) BuildRequires: perl(Time::HiRes) perl(Net::SFTP::Foreign) BuildRequires: perl(Expect) perl(Sys::Syslog) -BuildRequires: gcc gcc-c++ vlc-devel libcurl-devel +BuildRequires: gcc gcc-c++ vlc-devel libcurl-devel libv4l-devel %{!?_without_ffmpeg:BuildRequires: ffmpeg-devel} %{!?_without_x10:BuildRequires: perl(X10::ActiveHome) perl(Astro::SunTime)} # cmake needs the following installed at build time due to the way it auto-detects certain parameters @@ -76,7 +76,6 @@ too much degradation of performance. %build %cmake \ -DZM_TARGET_DISTRO="f21" \ - -DZM_PERL_SUBPREFIX=`x="%{perl_vendorlib}" ; echo ${x#"%{_prefix}"}` \ %{?_without_ffmpeg:-DZM_NO_FFMPEG=ON} \ %{?_without_x10:-DZM_NO_X10=ON} \ . @@ -155,8 +154,6 @@ fi %{!?_without_x10:%{_bindir}/zmx10.pl} %{perl_vendorlib}/ZoneMinder* -%{perl_vendorlib}/%{_arch}-linux-thread-multi/auto/ZoneMinder* -#%{perl_archlib}/ZoneMinder* %{_mandir}/man*/* %dir %{_libexecdir}/zoneminder %{_libexecdir}/zoneminder/cgi-bin diff --git a/distros/redhat/CMakeLists.txt b/distros/redhat/CMakeLists.txt index 7422be107..129d666d4 100644 --- a/distros/redhat/CMakeLists.txt +++ b/distros/redhat/CMakeLists.txt @@ -58,7 +58,7 @@ if(ZM_TARGET_DISTRO STREQUAL "el7") install(FILES zoneminder.el7.conf DESTINATION /etc/httpd/conf.d RENAME zoneminder.conf PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ) install(FILES zoneminder.el7.logrotate DESTINATION /etc/logrotate.d RENAME zoneminder PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ) install(FILES zoneminder.service DESTINATION /usr/lib/systemd/system PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ) - install(FILES zoneminder.tmpfiles DESTINATION /etc/tmpfiles.d RENAME zoneminder.conf PERMISSIONS OWNER_WRITE OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) + install(FILES ../../misc/zoneminder-tmpfiles.conf DESTINATION /etc/tmpfiles.d RENAME zoneminder.conf PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ) else(ZM_TARGET_DISTRO STREQUAL "el7") install(FILES zoneminder.el6.conf DESTINATION /etc/httpd/conf.d RENAME zoneminder.conf PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ) install(FILES zoneminder.el6.logrotate DESTINATION /etc/logrotate.d RENAME zoneminder PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ) diff --git a/distros/redhat/zoneminder.el6.spec b/distros/redhat/zoneminder.el6.spec index 8ca8415dd..e50db96e7 100644 --- a/distros/redhat/zoneminder.el6.spec +++ b/distros/redhat/zoneminder.el6.spec @@ -73,7 +73,7 @@ too much degradation of performance. %build # Have to override CMAKE_INSTALL_LIBDIR for cmake < 2.8.7 due to this bug: # https://bugzilla.redhat.com/show_bug.cgi?id=795542 -%cmake -DZM_TARGET_DISTRO="el6" -DCMAKE_INSTALL_LIBDIR:PATH=%{_lib} -DZM_PERL_SUBPREFIX=`x="%{perl_vendorlib}" ; echo ${x#"%{_prefix}"}` . +%cmake -DZM_TARGET_DISTRO="el6" -DCMAKE_INSTALL_LIBDIR:PATH=%{_lib} . make %{?_smp_mflags} diff --git a/distros/redhat/zoneminder.el7.spec b/distros/redhat/zoneminder.el7.spec index b21a3901d..63d7fe920 100644 --- a/distros/redhat/zoneminder.el7.spec +++ b/distros/redhat/zoneminder.el7.spec @@ -27,7 +27,7 @@ BuildRequires: perl(MIME::Entity) perl(MIME::Lite) BuildRequires: perl(PHP::Serialization) perl(Sys::Mmap) BuildRequires: perl(Time::HiRes) perl(Net::SFTP::Foreign) BuildRequires: perl(Expect) perl(Sys::Syslog) -BuildRequires: gcc gcc-c++ vlc-devel libcurl-devel +BuildRequires: gcc gcc-c++ vlc-devel libcurl-devel libv4l-devel BuildRequires: ffmpeg ffmpeg-devel perl(X10::ActiveHome) perl(Astro::SunTime) # cmake needs the following installed at build time due to the way it auto-detects certain parameters BuildRequires: httpd polkit-devel @@ -69,7 +69,6 @@ too much degradation of performance. %build %cmake \ -DZM_TARGET_DISTRO="el7" \ - -DZM_PERL_SUBPREFIX=`x="%{perl_vendorlib}" ; echo ${x#"%{_prefix}"}` \ . make %{?_smp_mflags} @@ -108,6 +107,8 @@ if [ $1 -eq 0 ] ; then # Package removal, not upgrade /bin/systemctl --no-reload disable zoneminder.service > /dev/null 2>&1 || : /bin/systemctl stop zoneminder.service > /dev/null 2>&1 || : + echo -e "\nRemoving ZoneMinder SELinux policy module. Please wait.\n" + /usr/sbin/semodule -r local_zoneminder.pp fi %postun @@ -129,7 +130,8 @@ fi %files %defattr(-,root,root,-) -%doc AUTHORS COPYING README.md distros/redhat/README.Centos7 distros/redhat/jscalendar-doc +%doc AUTHORS BUGS ChangeLog COPYING LICENSE NEWS README.md distros/redhat/README.Centos7 distros/redhat/jscalendar-doc +%doc distros/redhat/cambozola-doc distros/redhat/local_zoneminder.te %config %attr(640,root,%{zmgid_final}) /etc/zm/zm.conf %config(noreplace) %attr(644,root,root) /etc/httpd/conf.d/zoneminder.conf %config(noreplace) /etc/tmpfiles.d/zoneminder.conf @@ -157,7 +159,8 @@ fi %{_bindir}/zmx10.pl %{perl_vendorlib}/ZoneMinder* -%{perl_vendorlib}/%{_arch}-linux-thread-multi/auto/ZoneMinder* +%{perl_vendorarch}/auto/ZoneMinder/.packlist +#%{perl_vendorlib}/%{_arch}-linux-thread-multi/auto/ZoneMinder* #%{perl_archlib}/ZoneMinder* %{_mandir}/man*/* %dir %{_libexecdir}/zoneminder diff --git a/distros/ubuntu1504/README.Debian b/distros/ubuntu1504/README.Debian new file mode 100644 index 000000000..b8ea413e3 --- /dev/null +++ b/distros/ubuntu1504/README.Debian @@ -0,0 +1,51 @@ +zoneminder for Debian +--------------------- + +There is one manual step to get the web interface working. +You need to link /etc/zm/apache.conf to /etc/apache2/conf.d/zoneminder.conf, +then reload the apache config (i.e. /etc/init.d/apache2 reload) + +Changing the location for images and events +------------------------------------------- + +Zoneminder, in its upstream form, stores data in /usr/share/zoneminder/. This +package modifies that by changing /usr/share/zoneminder/images and +/usr/share/zoneminder/events to symlinks to directories under +/var/cache/zoneminder. + +There are numerous places these could be put and ways to do it. But, at the +moment, if you change this, an upgrade will fail with a warning about these +locations having changed (the reason for this was that previously, an upgrade +would silently revert the changes and cause event loss - refer +bug #608793). + +If you do want to change the location, here are a couple of suggestions. +(thanks to vagrant@freegeek.org): + +These lines in fstab could allow you to bind-mount an alternate location + + /dev/sdX1 /otherdrive ext3 defaults 0 2 + /otherdrive/zoneminder/images /var/cache/zoneminder/images bind defaults 0 2 + /otherdrive/zoneminder/events /var/cache/zoneminder/events bind defaults 0 2 + + or if you have a separate partition for each: + + /dev/sdX1 /var/cache/zoneminder/images ext3 defaults 0 2 + /dev/sdX2 /var/cache/zoneminder/events ext3 defaults 0 2 + + + + -- Peter Howard , Sun, 16 Jan 2010 01:35:51 +1100 + +Access to /dev/video* +--------------------- + +For cameras which require access to /dev/video*, zoneminder may need the +www-data user added to the video group in order to see those cameras: + + adduser www-data video + +Note that all web applications running on the zoneminder server will then have +access to all video devices on the system. + + -- Vagrant Cascadian Sun, 27 Mar 2011 13:06:56 -0700 diff --git a/distros/ubuntu1504/apache.conf b/distros/ubuntu1504/apache.conf new file mode 100644 index 000000000..92a2b6414 --- /dev/null +++ b/distros/ubuntu1504/apache.conf @@ -0,0 +1,9 @@ +Alias /zm /usr/share/zoneminder + + + php_flag register_globals off + Options Indexes FollowSymLinks + + DirectoryIndex index.php + + diff --git a/distros/ubuntu1504/changelog b/distros/ubuntu1504/changelog new file mode 100644 index 000000000..2dfc8b63c --- /dev/null +++ b/distros/ubuntu1504/changelog @@ -0,0 +1,86 @@ +zoneminder (1.28.1+1-trusty-SNAPSHOT2015030201) trusty; urgency=medium + + * maybe fix for RTSP Basic Auth + * Also remove dependency on netpbm + + -- Isaac Connor Mon, 02 Mar 2015 11:25:59 -0500 + +zoneminder (1.28.1+1-utopic-SNAPSHOT2015022301) utopic; urgency=medium + + * Big merge of onvif support and some fixes. + + -- Isaac Connor Mon, 23 Feb 2015 19:45:45 -0500 + +zoneminder (1.28.0+1-trusty-SNAPSHOT2015021201) trusty; urgency=medium + + * add mysql-client-5.6 as a dependency instaed of mysql-client. + + -- Isaac Connor Fri, 13 Feb 2015 09:35:13 -0500 + +zoneminder (1.28.0+1-trusty-SNAPSHOT2015011101) trusty; urgency=medium + + * small changes + + -- Isaac Connor Fri, 12 Dec 2014 16:38:36 -0500 + +zoneminder (1.28.0+1-utopic-SNAPSHOT2014112001) utopic; urgency=medium + + * Various fixes and developments since 1.28.0. Includes Digest-Auth for HTTP and better for RTSP + + -- Isaac Connor Thu, 20 Nov 2014 10:57:57 -0500 + +zoneminder (1.28.0-trusty) trusty; urgency=medium + + * Release + + -- Isaac Connor Fri, 17 Oct 2014 09:25:55 -0400 + +zoneminder (1.27.99+1-trusty-SNAPSHOT2014101401) trusty; urgency=medium + + * Several PR merges in big push for 1.28.0 + + -- Isaac Connor Tue, 14 Oct 2014 09:28:29 -0400 + +zoneminder (1.27.99+1-trusty-SNAPSHOT2014092601) trusty; urgency=medium + + * style updates and db fixes for database logging filters + + -- Isaac Connor Fri, 26 Sep 2014 14:44:45 -0400 + +zoneminder (1.27.99+1-trusty-SNAPSHOT2014090801) trusty; urgency=medium + + * several segfault fixes for local cameras + + -- Isaac Connor Mon, 08 Sep 2014 16:56:57 -0400 + +zoneminder (1.27.99+1-trusty-SNAPSHOT2014090701) trusty; urgency=medium + + * Fix segfaults for local cameras, also now includes the systemd support patch + + -- Isaac Connor Sun, 07 Sep 2014 17:19:01 -0400 + +zoneminder (1.27.99+1-trusty-SNAPSHOT2014082102) trusty; urgency=medium + + * Fix UI inputs for v4l multibuffer and captures per frame + + -- Isaac Connor Thu, 21 Aug 2014 12:03:31 -0400 + +zoneminder (1.27.99+1-trusty-SNAPSHOT2014082101) trusty; urgency=medium + + * fall back to Config table values for V4l MultiBUffer and Captures Per Frame + * add mention of monitor page settings for thse in the config table + + -- Isaac Connor Thu, 21 Aug 2014 10:04:46 -0400 + +zoneminder (1.27.99+1-precise-SNAPSHOT2014080601) precise; urgency=medium + + * improve error messages + * Make zmupdate re-run the most recent patch so that people running the daily builds get their db updates + + -- Isaac Connor Wed, 06 Aug 2014 20:20:20 -0400 + +zoneminder (1.27.0+1-trusty-v4ltomonitor-1) trusty; urgency=high + + * Snapshot release - + + -- Isaac Connor Wed, 09 Jul 2014 21:35:29 -0400 diff --git a/distros/ubuntu1504/compat b/distros/ubuntu1504/compat new file mode 100644 index 000000000..ec635144f --- /dev/null +++ b/distros/ubuntu1504/compat @@ -0,0 +1 @@ +9 diff --git a/distros/ubuntu1504/control b/distros/ubuntu1504/control new file mode 100644 index 000000000..5b63046c3 --- /dev/null +++ b/distros/ubuntu1504/control @@ -0,0 +1,40 @@ +Source: zoneminder +Section: net +Priority: optional +Maintainer: Isaac Connor +Build-Depends: debhelper (>= 9), dh-systemd (>= 1.5), autoconf, automake, quilt, libphp-serialization-perl, libgnutls-dev, libmysqlclient-dev | libmariadbclient-dev, libdbd-mysql-perl, libdate-manip-perl, libwww-perl, libjpeg8-dev|libjpeg9-dev|libjpeg62-turbo-dev, libpcre3-dev, libavcodec-ffmpeg-dev, libavformat-ffmpeg-dev, libswscale-ffmpeg-dev, libavutil-ffmpeg-dev, libv4l-dev (>= 0.8.3), libbz2-dev, libtool, libsys-mmap-perl, ffmpeg, libavdevice-ffmpeg-dev, libdevice-serialport-perl, libpcre3, libarchive-zip-perl, libmime-lite-perl, dh-autoreconf, libvlccore-dev, libvlc-dev, libcurl4-gnutls-dev | libcurl4-nss-dev | libcurl4-openssl-dev, libgcrypt11-dev, libpolkit-gobject-1-dev +Standards-Version: 3.9.4 + +Package: zoneminder +Architecture: any +Depends: ${shlibs:Depends}, ${misc:Depends}, ${perl:Depends}, apache2, libapache2-mod-php5 | libapache2-mod-fcgid, php5, php5-mysql|php5-mysqlnd, libphp-serialization-perl, libdate-manip-perl, libmime-lite-perl, libmime-tools-perl, mariadb-client|mysql-client|mysql-client-5.6, libwww-perl, libarchive-tar-perl, libarchive-zip-perl, libdevice-serialport-perl, libpcre3, ffmpeg, rsyslog | system-log-daemon, libmodule-load-perl, libsys-mmap-perl, libjson-any-perl, libavdevice-ffmpeg56, libjpeg8|libjpeg9|libjpeg62-turbo, zip, libnet-sftp-foreign-perl, libio-pty-perl, libexpect-perl, libvlccore5 | libvlccore7 | libvlccore8, libvlc5, libcurl4-gnutls-dev | libcurl4-nss-dev | libcurl4-openssl-dev, libpolkit-gobject-1-0, liburi-encode-perl +Recommends: mysql-server|mariadb-server +Description: Video camera security and surveillance solution + ZoneMinder is intended for use in single or multi-camera video security + applications, including commercial or home CCTV, theft prevention and child + or family member or home monitoring and other care scenarios. It + supports capture, analysis, recording, and monitoring of video data coming + from one or more video or network cameras attached to a Linux system. + ZoneMinder also support web and semi-automatic control of Pan/Tilt/Zoom + cameras using a variety of protocols. It is suitable for use as a home + video security system and for commercial or professional video security + and surveillance. It can also be integrated into a home automation system + via X.10 or other protocols. + +Package: zoneminder-dbg +Section: debug +Priority: extra +Architecture: any +Depends: zoneminder (= ${binary:Version}), ${misc:Depends} +Description: Debugging symbols for zoneminder. + ZoneMinder is a video camera security and surveillance solution. + ZoneMinder is intended for use in single or multi-camera video security + applications, including commercial or home CCTV, theft prevention and child + or family member or home monitoring and other care scenarios. It + supports capture, analysis, recording, and monitoring of video data coming + from one or more video or network cameras attached to a Linux system. + ZoneMinder also support web and semi-automatic control of Pan/Tilt/Zoom + cameras using a variety of protocols. It is suitable for use as a home + video security system and for commercial or professional video security + and surveillance. It can also be integrated into a home automation system + via X.10 or other protocols. diff --git a/distros/ubuntu1504/copyright b/distros/ubuntu1504/copyright new file mode 100644 index 000000000..a177502a0 --- /dev/null +++ b/distros/ubuntu1504/copyright @@ -0,0 +1,22 @@ +Copyright: + +Copyright 2002 Philip Coombes + +License: + +This package 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 package is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public +License along with this package; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +On Debian GNU/Linux systems, the text of the GPL can be found in +/usr/share/common-licenses/GPL. diff --git a/distros/ubuntu1504/dirs b/distros/ubuntu1504/dirs new file mode 100644 index 000000000..4178482c1 --- /dev/null +++ b/distros/ubuntu1504/dirs @@ -0,0 +1,6 @@ +var/log/zm +var/lib/zm +var/cache/zoneminder/events +var/cache/zoneminder/images +var/cache/zoneminder/temp +usr/share/zoneminder/db diff --git a/distros/ubuntu1504/docs b/distros/ubuntu1504/docs new file mode 100644 index 000000000..b43bf86b5 --- /dev/null +++ b/distros/ubuntu1504/docs @@ -0,0 +1 @@ +README.md diff --git a/distros/ubuntu1504/install b/distros/ubuntu1504/install new file mode 100644 index 000000000..4b0009cea --- /dev/null +++ b/distros/ubuntu1504/install @@ -0,0 +1,12 @@ +usr/bin +usr/lib/cgi-bin +usr/share/man +usr/share/perl5/ZoneMinder +usr/share/perl5/ZoneMinder.pm +usr/share/polkit-1/actions +usr/share/polkit-1/rules.d +usr/share/zoneminder +etc/zm +db/zm_create.sql usr/share/zoneminder/db +db/zm_update-*.sql usr/share/zoneminder/db +debian/apache.conf etc/zm diff --git a/distros/ubuntu1504/links b/distros/ubuntu1504/links new file mode 100644 index 000000000..9715ee428 --- /dev/null +++ b/distros/ubuntu1504/links @@ -0,0 +1,4 @@ +var/cache/zoneminder/events usr/share/zoneminder/events +var/cache/zoneminder/images usr/share/zoneminder/images +var/cache/zoneminder/temp usr/share/zoneminder/temp +usr/lib/cgi-bin usr/share/zoneminder/cgi-bin diff --git a/distros/ubuntu1504/patches/series b/distros/ubuntu1504/patches/series new file mode 100644 index 000000000..e69de29bb diff --git a/distros/ubuntu1504/postinst b/distros/ubuntu1504/postinst new file mode 100644 index 000000000..e009a9799 --- /dev/null +++ b/distros/ubuntu1504/postinst @@ -0,0 +1,53 @@ +#! /bin/sh + +set -e + +if [ "$1" = "configure" ]; then + if [ -e "/lib/systemd/system/mysql.service" ]; then + # + # Get mysql started if it isn't + # + if ! $(systemctl is-active mysql >/dev/null 2>&1); then + systemctl start mysql + fi + if $(systemctl is-active mysql >/dev/null 2>&1); then + mysqladmin --defaults-file=/etc/mysql/debian.cnf -f reload + # test if database if already present... + if ! $(echo quit | mysql --defaults-file=/etc/mysql/debian.cnf zm > /dev/null 2> /dev/null) ; then + cat /usr/share/zoneminder/db/zm_create.sql | mysql --defaults-file=/etc/mysql/debian.cnf + echo 'grant lock tables, alter,select,insert,update,delete on zm.* to 'zmuser'@localhost identified by "zmpass";' | mysql --defaults-file=/etc/mysql/debian.cnf mysql + fi + + systemctl stop zoneminder || true #not sure about "|| true" + zmupdate.pl --nointeractive + + else + echo 'NOTE: mysql not running, please start mysql and run dpkg-reconfigure zoneminder when it is running.' + fi + else + echo 'mysql not found, assuming remote server.' + fi + chown www-data:www-data /var/log/zm + chown www-data:www-data /var/lib/zm/ + if [ -z "$2" ]; then + chown www-data:www-data -R /var/cache/zoneminder + fi +fi +# Ensure zoneminder is stopped... +if [ -e "/lib/systemd/system/zoneminder.service" ]; then #changed from -x to -e, could be wrong + if systemctl is-active zoneminder >/dev/null 2>&1 ; then + systemctl stop zoneminder || exit $? + fi +fi + +if [ "$1" = "configure" ]; then + if [ -z "$2" ]; then + chown www-data:www-data /var/log/zm + chown www-data:www-data /var/lib/zm/ + chown www-data:www-data -R /var/cache/zoneminder + else + chown www-data:www-data /var/log/zm + zmupdate.pl + fi +fi +#DEBHELPER# diff --git a/distros/ubuntu1504/postrm b/distros/ubuntu1504/postrm new file mode 100644 index 000000000..28a00a7a0 --- /dev/null +++ b/distros/ubuntu1504/postrm @@ -0,0 +1,9 @@ +#! /bin/sh +# set -e # to be reinstated later + +if [ "$1" = "purge" ]; then + echo 'delete from user where User="zmuser";' | mysql --defaults-file=/etc/mysql/debian.cnf mysql + echo 'delete from db where User="zmuser";' | mysql --defaults-file=/etc/mysql/debian.cnf mysql + mysqladmin --defaults-file=/etc/mysql/debian.cnf -f drop zm +fi +#DEBHELPER# diff --git a/distros/ubuntu1504/preinst b/distros/ubuntu1504/preinst new file mode 100755 index 000000000..6cd01ba55 --- /dev/null +++ b/distros/ubuntu1504/preinst @@ -0,0 +1,32 @@ +#!/bin/sh + +set -e + +abort=false +if [ -L /usr/share/zoneminder/events ]; then + l=$(readlink /usr/share/zoneminder/events) + if [ "$l" != "/var/cache/zoneminder/events" ]; then + abort=true + fi +fi +if [ -L /usr/share/zoneminder/images ]; then + l=$(readlink /usr/share/zoneminder/images ) + if [ "$l" != "/var/cache/zoneminder/images" ]; then + abort=true + fi +fi + +if [ "$abort" = "true" ]; then + cat >&2 << EOF +Aborting installation of zoneminder due to non-default symlinks in +/usr/share/zoneminder for the images and/or events directory, which could +result in loss of data. Please move your data in each of these directories to +/var/cache/zoneminder before installing zoneminder from the package. +EOF + exit 1 + +fi + +#DEBHELPER# + +exit 0 diff --git a/distros/ubuntu1504/rules b/distros/ubuntu1504/rules new file mode 100755 index 000000000..280d5faef --- /dev/null +++ b/distros/ubuntu1504/rules @@ -0,0 +1,67 @@ +#!/usr/bin/make -f +# -*- makefile -*- +# Sample debian/rules that uses debhelper. +# This file was originally written by Joey Hess and Craig Small. +# As a special exception, when this file is copied by dh-make into a +# dh-make output file, you may use that output file without restriction. +# This special exception was added by Craig Small in version 0.37 of dh-make. + +# Uncomment this to turn on verbose mode. +#export DH_VERBOSE=1 + +# These are used for cross-compiling and for saving the configure script +# from having to guess our platform (since we know it already) +DEB_HOST_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_HOST_GNU_TYPE) +DEB_BUILD_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_BUILD_GNU_TYPE) + +CFLAGS = -Wall -g +CPPFLAGS = -D__STDC_CONSTANT_MACROS +CXXFLAGS = -DHAVE_LIBCRYPTO + +ifneq (,$(findstring noopt,$(DEB_BUILD_OPTIONS))) + CFLAGS += -O0 +else + CFLAGS += -O2 +endif + +%: + dh $@ --with quilt,autoreconf,systemd + +override_dh_auto_configure: + CFLAGS="$(CFLAGS)" CXXFLAGS="$(CXXFLAGS)" dh_auto_configure -- --host=$(DEB_HOST_GNU_TYPE) --build=$(DEB_BUILD_GNU_TYPE) --sysconfdir=/etc/zm --prefix=/usr --mandir=\$${prefix}/share/man --infodir=\$${prefix}/share/info --with-mysql=/usr --with-mariadb=/usr --with-webdir=/usr/share/zoneminder --with-ffmpeg=/usr --with-cgidir=/usr/lib/cgi-bin --with-webuser=www-data --with-webgroup=www-data --enable-crashtrace=no --enable-mmap=yes + +override_dh_clean: + # Add here commands to clean up after the build process. + [ ! -f Makefile ] || $(MAKE) distclean + dh_clean + +override_dh_install: + dh_install --fail-missing + # + # NOTE: This is a short-term kludge; hopefully changes in the next + # upstream version will render this unnecessary. + rm -rf debian/zoneminder/usr/share/zoneminder/events + rm -rf debian/zoneminder/usr/share/zoneminder/images + rm -rf debian/zoneminder/usr/share/zoneminder/temp + dh_link var/cache/zoneminder/events usr/share/zoneminder/events + dh_link var/cache/zoneminder/images usr/share/zoneminder/images + dh_link var/cache/zoneminder/temp usr/share/zoneminder/temp + + # + # This is a slightly lesser kludge; moving the cgi stuff to + # /usr/share/zoneminder/cgi-bin breaks one set of behavior, + # having it just in /usr/lib/cgi-bin breaks another bit of + # behavior. + # + dh_link usr/lib/cgi-bin usr/share/zoneminder/cgi-bin + +override_dh_fixperms: + dh_fixperms + chown root:root debian/zoneminder/etc/zm/zm.conf + +override_dh_auto_test: + # do not run tests... + +.PHONY: override_dh_strip +override_dh_strip: + dh_strip --dbg-package=zoneminder-dbg diff --git a/distros/ubuntu1504/watch b/distros/ubuntu1504/watch new file mode 100644 index 000000000..5a8a9c4d7 --- /dev/null +++ b/distros/ubuntu1504/watch @@ -0,0 +1,3 @@ +version=3 +http://www.zoneminder.com/downloads.html \ + .*/ZoneMinder-(.*).tar.gz diff --git a/distros/ubuntu1504/zoneminder.service b/distros/ubuntu1504/zoneminder.service new file mode 100644 index 000000000..3ce608a49 --- /dev/null +++ b/distros/ubuntu1504/zoneminder.service @@ -0,0 +1,16 @@ +# ZoneMinder systemd unit file + # This file is intended to work with all Linux distributions + [Unit] + Description=ZoneMinder CCTV recording and security system + After=network.target mysql.service apache2.service + Requires=mysql.service apache2.service + [Service] + User=www-data + Type=forking + ExecStart=/usr/bin/zmpkg.pl start + ExecReload=/usr/bin/zmpkg.pl restart + ExecStop=/usr/bin/zmpkg.pl stop + PIDFile="/run/zm/zm.pid" + [Install] + WantedBy=multi-user.target + diff --git a/distros/ubuntu1504/zoneminder.tmpfile b/distros/ubuntu1504/zoneminder.tmpfile new file mode 100644 index 000000000..036883750 --- /dev/null +++ b/distros/ubuntu1504/zoneminder.tmpfile @@ -0,0 +1,2 @@ +d /var/run/zm 0755 www-data www-data + diff --git a/m4/ac_check_sendfile.m4 b/m4/ac_check_sendfile.m4 new file mode 100644 index 000000000..12605d588 --- /dev/null +++ b/m4/ac_check_sendfile.m4 @@ -0,0 +1,63 @@ +AC_DEFUN([AC_CHECK_SENDFILE],[ +AC_MSG_CHECKING([whether sendfile() is supported and what prototype it has]) + +saved_CFLAGS="$CFLAGS" +CFLAGS="$CFLAGS -Werror-implicit-function-declaration" +ac_sendfile_supported=no +AC_TRY_LINK([#include + #include ], + [sendfile(1, 1, NULL, 0);], + [ + AC_DEFINE(HAVE_SENDFILE4_SUPPORT, 1, + [Define this if Linux/Solaris sendfile() is supported]) + AC_MSG_RESULT([Linux sendfile()]) + ac_sendfile_supported=yes + ], []) + +if test x$ac_sendfile_supported = xno; then + dnl Checking wether we need libsendfile + dnl Presumably on Solaris + AC_CHECK_LIB(sendfile, sendfile, + [ + AC_DEFINE(HAVE_SENDFILE4_SUPPORT, 1, + [Define this if Linux/Solaris sendfile() is supported]) + SENDFILE_LIBS="-lsendfile" + AC_SUBST(SENDFILE_LIBS) + AC_MSG_RESULT([Solaris sendfile()]) + ac_sendfile_supported=yes + ], []) +fi + +if test x$ac_sendfile_supported = xno; then + dnl Checking wether we have FreeBSD-like sendfile() support. + AC_TRY_LINK([#include + #include ], + [sendfile(1, 1, 0, 0, NULL, NULL, 0);], + [ + AC_DEFINE(HAVE_SENDFILE7_SUPPORT, 1, + [Define this if FreeBSD sendfile() is supported]) + AC_MSG_RESULT([FreeBSD sendfile()]) + ac_sendfile_supported=yes + ], []) +fi + +if test x$ac_sendfile_supported = xno; then + dnl Checking wether we have MacOS-like sendfile() support. + AC_TRY_LINK([#include + #include + #include ], + [sendfile(1, 1, 0, NULL, NULL, 0);], + [ + AC_DEFINE(HAVE_SENDFILE6_SUPPORT, 1, + [Define this if MacOS sendfile() is supported]) + AC_MSG_RESULT([MacOS sendfile()]) + ac_sendfile_supported=yes + ], []) +fi + +CFLAGS="$saved_CFLAGS" + +if test x$ac_sendfile_supported = xno; then + AC_MSG_RESULT([no sendfile() support, using read/send]) +fi +]) diff --git a/misc/zoneminder-tmpfiles.conf.in b/misc/zoneminder-tmpfiles.conf.in index 8f55ce295..79b27f909 100644 --- a/misc/zoneminder-tmpfiles.conf.in +++ b/misc/zoneminder-tmpfiles.conf.in @@ -1 +1,4 @@ -d @ZM_RUNDIR@ 0755 @WEB_USER@ @WEB_GROUP@ +D @ZM_RUNDIR@ 0755 @WEB_USER@ @WEB_GROUP@ +D @ZM_TMPDIR@ 0755 @WEB_USER@ @WEB_GROUP@ +D @ZM_SOCKDIR@ 0755 @WEB_USER@ @WEB_GROUP@ + diff --git a/onvif/modules/CMakeLists.txt b/onvif/modules/CMakeLists.txt index 5e3a878bb..9e46ef9f7 100644 --- a/onvif/modules/CMakeLists.txt +++ b/onvif/modules/CMakeLists.txt @@ -1,10 +1,18 @@ +# CMakeLists.txt for the ZoneMinder ONVIF modules. +# If this is an out-of-source build, copy the files we need to the binary directory +if(NOT (CMAKE_BINARY_DIR STREQUAL CMAKE_SOURCE_DIR)) + file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/Makefile.PL" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}") + file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/lib" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}" PATTERN "*.in" EXCLUDE) +endif(NOT (CMAKE_BINARY_DIR STREQUAL CMAKE_SOURCE_DIR)) + +# MAKEMAKER_NOECHO_COMMAND previously defined in /scripts/zoneminder/CMakeLists.txt # Add build target for the perl modules -add_custom_target(zmonvifmodules ALL perl Makefile.PL FIRST_MAKEFILE=MakefilePerl PREFIX="${CMAKE_CURRENT_BINARY_DIR}/output" LIB="${CMAKE_CURRENT_BINARY_DIR}/output/${ZM_PERL_SUBPREFIX}" INSTALLSITEMAN3DIR="${CMAKE_CURRENT_BINARY_DIR}/output/${CMAKE_INSTALL_MANDIR}/man3" ${MAKEMAKER_NOECHO_COMMAND} COMMAND make --makefile=MakefilePerl COMMAND make --makefile=MakefilePerl pure_install COMMENT "Building ZoneMinder perl modules") +add_custom_target(zmonvifmodules ALL perl Makefile.PL ${ZM_PERL_MM_PARMS} FIRST_MAKEFILE=MakefilePerl DESTDIR="${CMAKE_CURRENT_BINARY_DIR}/output" ${MAKEMAKER_NOECHO_COMMAND} COMMAND make --makefile=MakefilePerl pure_install COMMENT "Building ZoneMinder perl ONVIF proxy module") # Add install target for the perl modules -install(DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/output/" DESTINATION "${CMAKE_INSTALL_PREFIX}") +install(DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/output/" DESTINATION "/") # Add additional files and directories to make clean set_directory_properties(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES "output;blib;pm_to_blib;MakefilePerl") diff --git a/onvif/proxy/CMakeLists.txt b/onvif/proxy/CMakeLists.txt index fece81d11..0051bf2b1 100644 --- a/onvif/proxy/CMakeLists.txt +++ b/onvif/proxy/CMakeLists.txt @@ -1,10 +1,18 @@ +# CMakeLists.txt for the ZoneMinder ONVIF proxy module. +# If this is an out-of-source build, copy the files we need to the binary directory +if(NOT (CMAKE_BINARY_DIR STREQUAL CMAKE_SOURCE_DIR)) + file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/Makefile.PL" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}") + file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/lib" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}" PATTERN "*.in" EXCLUDE) +endif(NOT (CMAKE_BINARY_DIR STREQUAL CMAKE_SOURCE_DIR)) + +# MAKEMAKER_NOECHO_COMMAND previously defined in /scripts/zoneminder/CMakeLists.txt # Add build target for the perl modules -add_custom_target(zmonvifproxy ALL perl Makefile.PL FIRST_MAKEFILE=MakefilePerl PREFIX="${CMAKE_CURRENT_BINARY_DIR}/output" LIB="${CMAKE_CURRENT_BINARY_DIR}/output/${ZM_PERL_SUBPREFIX}" INSTALLSITEMAN3DIR="${CMAKE_CURRENT_BINARY_DIR}/output/${CMAKE_INSTALL_MANDIR}/man3" ${MAKEMAKER_NOECHO_COMMAND} COMMAND make --makefile=MakefilePerl COMMAND make --makefile=MakefilePerl pure_install COMMENT "Building ZoneMinder perl modules") +add_custom_target(zmonvifproxy ALL perl Makefile.PL ${ZM_PERL_MM_PARMS} FIRST_MAKEFILE=MakefilePerl DESTDIR="${CMAKE_CURRENT_BINARY_DIR}/output" ${MAKEMAKER_NOECHO_COMMAND} COMMAND make --makefile=MakefilePerl pure_install COMMENT "Building ZoneMinder perl ONVIF proxy module") # Add install target for the perl modules -install(DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/output/" DESTINATION "${CMAKE_INSTALL_PREFIX}") +install(DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/output/" DESTINATION "/") # Add additional files and directories to make clean set_directory_properties(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES "output;blib;pm_to_blib;MakefilePerl") diff --git a/scripts/ZoneMinder/CMakeLists.txt b/scripts/ZoneMinder/CMakeLists.txt index 61bee83af..09c02b816 100644 --- a/scripts/ZoneMinder/CMakeLists.txt +++ b/scripts/ZoneMinder/CMakeLists.txt @@ -2,13 +2,13 @@ # If this is an out-of-source build, copy the files we need to the binary directory if(NOT (CMAKE_BINARY_DIR STREQUAL CMAKE_SOURCE_DIR)) - execute_process(COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/Changes" "${CMAKE_CURRENT_BINARY_DIR}/Changes") - execute_process(COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/Makefile.PL" "${CMAKE_CURRENT_BINARY_DIR}/Makefile.PL") - execute_process(COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/MANIFEST" "${CMAKE_CURRENT_BINARY_DIR}/MANIFEST") - execute_process(COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/META.yml" "${CMAKE_CURRENT_BINARY_DIR}/META.yml") - execute_process(COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/README" "${CMAKE_CURRENT_BINARY_DIR}/README") - execute_process(COMMAND ${CMAKE_COMMAND} -E copy_directory "${CMAKE_CURRENT_SOURCE_DIR}/t" "${CMAKE_CURRENT_BINARY_DIR}/t") - execute_process(COMMAND ${CMAKE_COMMAND} -E copy_directory "${CMAKE_CURRENT_SOURCE_DIR}/lib" "${CMAKE_CURRENT_BINARY_DIR}/lib") + file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/Changes" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}") + file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/Makefile.PL" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}") + file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/MANIFEST" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}") + file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/META.yml" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}") + file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/README" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}") + file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/t" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}") + file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/lib" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}" PATTERN "*.in" EXCLUDE) endif(NOT (CMAKE_BINARY_DIR STREQUAL CMAKE_SOURCE_DIR)) # Create files from the .in files @@ -24,10 +24,10 @@ else(CMAKE_VERBOSE_MAKEFILE) endif(CMAKE_VERBOSE_MAKEFILE) # Add build target for the perl modules -add_custom_target(zmperlmodules ALL perl Makefile.PL FIRST_MAKEFILE=MakefilePerl PREFIX="${CMAKE_CURRENT_BINARY_DIR}/output" LIB="${CMAKE_CURRENT_BINARY_DIR}/output/${ZM_PERL_SUBPREFIX}" INSTALLSITEMAN3DIR="${CMAKE_CURRENT_BINARY_DIR}/output/${CMAKE_INSTALL_MANDIR}/man3" ${MAKEMAKER_NOECHO_COMMAND} COMMAND make --makefile=MakefilePerl COMMAND make --makefile=MakefilePerl pure_install COMMENT "Building ZoneMinder perl modules") +add_custom_target(zmperlmodules ALL perl Makefile.PL ${ZM_PERL_MM_PARMS} FIRST_MAKEFILE=MakefilePerl DESTDIR="${CMAKE_CURRENT_BINARY_DIR}/output" ${MAKEMAKER_NOECHO_COMMAND} COMMAND make --makefile=MakefilePerl pure_install COMMENT "Building ZoneMinder perl modules") # Add install target for the perl modules -install(DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/output/" DESTINATION "${CMAKE_INSTALL_PREFIX}") +install(DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/output/" DESTINATION "/") # Add additional files and directories to make clean set_directory_properties(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES "output;blib;pm_to_blib;MakefilePerl") diff --git a/scripts/ZoneMinder/lib/ZoneMinder.pm b/scripts/ZoneMinder/lib/ZoneMinder.pm index 41c972650..87a6b14b7 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder.pm @@ -36,34 +36,42 @@ use ZoneMinder::General qw(:all); use ZoneMinder::Database qw(:all); use ZoneMinder::Memory qw(:all); -our @ISA = qw(Exporter ZoneMinder::Base ZoneMinder::Config ZoneMinder::Logger ZoneMinder::General ZoneMinder::Database ZoneMinder::Memory); +our @ISA = qw( + Exporter + ZoneMinder::Base + ZoneMinder::Config + ZoneMinder::Logger + ZoneMinder::General + ZoneMinder::Database + ZoneMinder::Memory +); # Items to export into callers namespace by default. Note: do not export # names by default without a very good reason. Use EXPORT_OK instead. # Do not simply export all your public functions/methods/constants. -# This allows declaration use ZoneMinder ':all'; +# This allows declaration use ZoneMinder ':all'; # If you do not need this, moving things directly into @EXPORT or @EXPORT_OK # will save memory. our %EXPORT_TAGS = ( - 'base' => [ - @ZoneMinder::Base::EXPORT_OK - ], - 'config' => [ - @ZoneMinder::Config::EXPORT_OK - ], - 'debug' => [ - @ZoneMinder::Logger::EXPORT_OK - ], - 'general' => [ - @ZoneMinder::General::EXPORT_OK - ], - 'database' => [ - @ZoneMinder::Database::EXPORT_OK - ], - 'memory' => [ - @ZoneMinder::Memory::EXPORT_OK - ], + 'base' => [ + @ZoneMinder::Base::EXPORT_OK + ], + 'config' => [ + @ZoneMinder::Config::EXPORT_OK + ], + 'debug' => [ + @ZoneMinder::Logger::EXPORT_OK + ], + 'general' => [ + @ZoneMinder::General::EXPORT_OK + ], + 'database' => [ + @ZoneMinder::Database::EXPORT_OK + ], + 'memory' => [ + @ZoneMinder::Memory::EXPORT_OK + ], ); push( @{$EXPORT_TAGS{all}}, @{$EXPORT_TAGS{$_}} ) foreach keys %EXPORT_TAGS; diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Base.pm.in b/scripts/ZoneMinder/lib/ZoneMinder/Base.pm.in index 3f10e9137..70140ea66 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Base.pm.in +++ b/scripts/ZoneMinder/lib/ZoneMinder/Base.pm.in @@ -19,7 +19,7 @@ # # ========================================================================== # -# This module contains the common definitions and functions used by the rest +# This module contains the common definitions and functions used by the rest # of the ZoneMinder scripts # package ZoneMinder::Base; @@ -38,7 +38,7 @@ use constant ZM_VERSION => "@VERSION@"; # names by default without a very good reason. Use EXPORT_OK instead. # Do not simply export all your public functions/methods/constants. -# This allows declaration use ZoneMinder ':all'; +# This allows declaration use ZoneMinder ':all'; # If you do not need this, moving things directly into @EXPORT or @EXPORT_OK # will save memory. our %EXPORT_TAGS = ( 'all' => [ qw(ZM_VERSION) ] ); @@ -62,7 +62,11 @@ ZoneMinder::Base - Base perl module for ZoneMinder =head1 DESCRIPTION -This module is the base module for the rest of the ZoneMinder modules. It is included by each of the other modules but serves no purpose other than to propagate the perl module version amongst the other modules. You will never need to use this module directly but if you write new ZoneMinder modules they should include it. +This module is the base module for the rest of the ZoneMinder modules. It +is included by each of the other modules but serves no purpose other than +to propagate the perl module version amongst the other modules. You will +never need to use this module directly but if you write new ZoneMinder +modules they should include it. =head2 EXPORT diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Config.pm.in b/scripts/ZoneMinder/lib/ZoneMinder/Config.pm.in index 21f7a2d50..e38d151c0 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Config.pm.in +++ b/scripts/ZoneMinder/lib/ZoneMinder/Config.pm.in @@ -19,7 +19,7 @@ # # ========================================================================== # -# This module contains the common definitions and functions used by the rest +# This module contains the common definitions and functions used by the rest # of the ZoneMinder scripts # package ZoneMinder::Config; @@ -38,15 +38,15 @@ use vars qw( %Config ); # names by default without a very good reason. Use EXPORT_OK instead. # Do not simply export all your public functions/methods/constants. -# This allows declaration use ZoneMinder ':all'; +# This allows declaration use ZoneMinder ':all'; # If you do not need this, moving things directly into @EXPORT or @EXPORT_OK # will save memory. our @EXPORT_CONFIG = qw( %Config ); # Get populated by BEGIN our %EXPORT_TAGS = ( - 'constants' => [ qw( - ZM_PID - ) ] + 'constants' => [ qw( + ZM_PID + ) ] ); push( @{$EXPORT_TAGS{config}}, @EXPORT_CONFIG ); push( @{$EXPORT_TAGS{all}}, @{$EXPORT_TAGS{$_}} ) foreach keys %EXPORT_TAGS; @@ -65,38 +65,43 @@ use Carp; # Load the config from the database into the symbol table BEGIN { - my $config_file = ZM_CONFIG; - ( my $local_config_file = $config_file ) =~ s|^.*/|./|; - if ( -s $local_config_file and -r $local_config_file ) - { - print( STDERR "Warning, overriding installed $local_config_file file with local copy\n" ); - $config_file = $local_config_file; - } - open( CONFIG, "<".$config_file ) or croak( "Can't open config file '$config_file': $!" ); - foreach my $str ( ) - { - next if ( $str =~ /^\s*$/ ); - next if ( $str =~ /^\s*#/ ); + my $config_file = ZM_CONFIG; + ( my $local_config_file = $config_file ) =~ s|^.*/|./|; + if ( -s $local_config_file and -r $local_config_file ) + { + print( STDERR "Warning, overriding installed $local_config_file file with local copy\n" ); + $config_file = $local_config_file; + } + open( my $CONFIG, "<", $config_file ) + or croak( "Can't open config file '$config_file': $!" ); + foreach my $str ( <$CONFIG> ) + { + next if ( $str =~ /^\s*$/ ); + next if ( $str =~ /^\s*#/ ); my ( $name, $value ) = $str =~ /^\s*([^=\s]+)\s*=\s*(.*?)\s*$/; - if ( ! $name ) { - print( STDERR "Warning, bad line in $config_file: $str\n" ); - next; - } # end if - $name =~ tr/a-z/A-Z/; - $Config{$name} = $value; - } - close( CONFIG ); + if ( ! $name ) { + print( STDERR "Warning, bad line in $config_file: $str\n" ); + next; + } # end if + $name =~ tr/a-z/A-Z/; + $Config{$name} = $value; + } + close( $CONFIG ); - use DBI; - my $dbh = DBI->connect( "DBI:mysql:database=".$Config{ZM_DB_NAME}.";host=".$Config{ZM_DB_HOST}, $Config{ZM_DB_USER}, $Config{ZM_DB_PASS} ) or croak( "Can't connect to db" ); - my $sql = 'select * from Config'; - my $sth = $dbh->prepare_cached( $sql ) or croak( "Can't prepare '$sql': ".$dbh->errstr() ); - my $res = $sth->execute() or croak( "Can't execute: ".$sth->errstr() ); - while( my $config = $sth->fetchrow_hashref() ) { - $Config{$config->{Name}} = $config->{Value}; - } - $sth->finish(); - #$dbh->disconnect(); + use DBI; + my $dbh = DBI->connect( "DBI:mysql:database=".$Config{ZM_DB_NAME} + .";host=".$Config{ZM_DB_HOST} + , $Config{ZM_DB_USER} + , $Config{ZM_DB_PASS} + ) or croak( "Can't connect to db" ); + my $sql = 'select * from Config'; + my $sth = $dbh->prepare_cached( $sql ) or croak( "Can't prepare '$sql': ".$dbh->errstr() ); + my $res = $sth->execute() or croak( "Can't execute: ".$sth->errstr() ); + while( my $config = $sth->fetchrow_hashref() ) { + $Config{$config->{Name}} = $config->{Value}; + } + $sth->finish(); + #$dbh->disconnect(); } 1; @@ -112,9 +117,16 @@ ZoneMinder::Config - ZoneMinder configuration module. =head1 DESCRIPTION -The ZoneMinder::Config module is used to import the ZoneMinder configuration from the database. It will do this at compile time in a BEGIN block and require access to the zm.conf file either in the current directory or in its defined location in order to determine database access details, configuration from this file will also be included. If the :all or :config tags are used then this configuration is exported into the namespace of the calling program or module. +The ZoneMinder::Config module is used to import the ZoneMinder +configuration from the database. It will do this at compile time in a BEGIN +block and require access to the zm.conf file either in the current +directory or in its defined location in order to determine database access +details, configuration from this file will also be included. If the :all or +:config tags are used then this configuration is exported into the +namespace of the calling program or module. -Once the configuration has been imported then configuration variables are defined as constants and can be accessed directory by name, e.g. +Once the configuration has been imported then configuration variables are +defined as constants and can be accessed directory by name, e.g. $lang = $Config{ZM_LANG_DEFAULT}; diff --git a/scripts/ZoneMinder/lib/ZoneMinder/ConfigAdmin.pm b/scripts/ZoneMinder/lib/ZoneMinder/ConfigAdmin.pm index 673e13c98..f586448fb 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/ConfigAdmin.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/ConfigAdmin.pm @@ -19,7 +19,7 @@ # # ========================================================================== # -# This module contains the debug definitions and functions used by the rest +# This module contains the debug definitions and functions used by the rest # of the ZoneMinder scripts # package ZoneMinder::ConfigAdmin; @@ -37,14 +37,14 @@ our @ISA = qw(Exporter ZoneMinder::Base); # names by default without a very good reason. Use EXPORT_OK instead. # Do not simply export all your public functions/methods/constants. -# This allows declaration use ZoneMinder ':all'; +# This allows declaration use ZoneMinder ':all'; # If you do not need this, moving things directly into @EXPORT or @EXPORT_OK # will save memory. our %EXPORT_TAGS = ( - 'functions' => [ qw( - loadConfigFromDB - saveConfigToDB - ) ] + 'functions' => [ qw( + loadConfigFromDB + saveConfigToDB + ) ] ); push( @{$EXPORT_TAGS{all}}, @{$EXPORT_TAGS{$_}} ) foreach keys %EXPORT_TAGS; @@ -67,99 +67,138 @@ use Carp; sub loadConfigFromDB { - print( "Loading config from DB\n" ); - my $dbh = DBI->connect( "DBI:mysql:database=".$Config{ZM_DB_NAME}.";host=".$Config{ZM_DB_HOST}, $Config{ZM_DB_USER}, $Config{ZM_DB_PASS} ); - - if ( !$dbh ) - { - print( "Error: unable to load options from database: $DBI::errstr\n" ); - return( 0 ); - } - my $sql = "select * from Config"; - my $sth = $dbh->prepare_cached( $sql ) or croak( "Can't prepare '$sql': ".$dbh->errstr() ); - my $res = $sth->execute() or croak( "Can't execute: ".$sth->errstr() ); - my $option_count = 0; - while( my $config = $sth->fetchrow_hashref() ) - { - my ( $name, $value ) = ( $config->{Name}, $config->{Value} ); - #print( "Name = '$name'\n" ); - my $option = $options_hash{$name}; - if ( !$option ) - { - warn( "No option '$name' found, removing" ); - next; - } - #next if ( $option->{category} eq 'hidden' ); - if ( defined($value) ) - { - if ( $option->{type} == $types{boolean} ) - { - $option->{value} = $value?"yes":"no"; - } - else - { - $option->{value} = $value; - } - } - $option_count++;; - } - $sth->finish(); - $dbh->disconnect(); - return( $option_count ); + print( "Loading config from DB\n" ); + my $dbh = DBI->connect( "DBI:mysql:database=".$Config{ZM_DB_NAME} + .";host=".$Config{ZM_DB_HOST} + ,$Config{ZM_DB_USER} + ,$Config{ZM_DB_PASS} + ); + + if ( !$dbh ) + { + print( "Error: unable to load options from database: $DBI::errstr\n" ); + return( 0 ); + } + my $sql = "select * from Config"; + my $sth = $dbh->prepare_cached( $sql ) + or croak( "Can't prepare '$sql': ".$dbh->errstr() ); + my $res = $sth->execute() + or croak( "Can't execute: ".$sth->errstr() ); + my $option_count = 0; + while( my $config = $sth->fetchrow_hashref() ) + { + my ( $name, $value ) = ( $config->{Name}, $config->{Value} ); + #print( "Name = '$name'\n" ); + my $option = $options_hash{$name}; + if ( !$option ) + { + warn( "No option '$name' found, removing" ); + next; + } + #next if ( $option->{category} eq 'hidden' ); + if ( defined($value) ) + { + if ( $option->{type} == $types{boolean} ) + { + $option->{value} = $value?"yes":"no"; + } + else + { + $option->{value} = $value; + } + } + $option_count++;; + } + $sth->finish(); + $dbh->disconnect(); + return( $option_count ); } sub saveConfigToDB { - print( "Saving config to DB\n" ); - my $dbh = DBI->connect( "DBI:mysql:database=".$Config{ZM_DB_NAME}.";host=".$Config{ZM_DB_HOST}, $Config{ZM_DB_USER}, $Config{ZM_DB_PASS} ); + print( "Saving config to DB\n" ); + my $dbh = DBI->connect( "DBI:mysql:database=".$Config{ZM_DB_NAME} + .";host=".$Config{ZM_DB_HOST} + ,$Config{ZM_DB_USER} + ,$Config{ZM_DB_PASS} + ); - if ( !$dbh ) - { - print( "Error: unable to save options to database: $DBI::errstr\n" ); - return( 0 ); - } + if ( !$dbh ) + { + print( "Error: unable to save options to database: $DBI::errstr\n" ); + return( 0 ); + } my $ac = $dbh->{AutoCommit}; $dbh->{AutoCommit} = 0; - $dbh->do('LOCK TABLE Config WRITE') or croak( "Can't lock Config table: " . $dbh->errstr() ); + $dbh->do('LOCK TABLE Config WRITE') + or croak( "Can't lock Config table: " . $dbh->errstr() ); - my $sql = "delete from Config"; - my $res = $dbh->do( $sql ) or croak( "Can't do '$sql': ".$dbh->errstr() ); + my $sql = "delete from Config"; + my $res = $dbh->do( $sql ) + or croak( "Can't do '$sql': ".$dbh->errstr() ); - $sql = "replace into Config set Id = ?, Name = ?, Value = ?, Type = ?, DefaultValue = ?, Hint = ?, Pattern = ?, Format = ?, Prompt = ?, Help = ?, Category = ?, Readonly = ?, Requires = ?"; - my $sth = $dbh->prepare_cached( $sql ) or croak( "Can't prepare '$sql': ".$dbh->errstr() ); - foreach my $option ( @options ) - { - #next if ( $option->{category} eq 'hidden' ); - #print( $option->{name}."\n" ) if ( !$option->{category} ); - $option->{db_type} = $option->{type}->{db_type}; - $option->{db_hint} = $option->{type}->{hint}; - $option->{db_pattern} = $option->{type}->{pattern}; - $option->{db_format} = $option->{type}->{format}; - if ( $option->{db_type} eq "boolean" ) - { - $option->{db_value} = ($option->{value} eq "yes")?"1":"0"; - } - else - { - $option->{db_value} = $option->{value}; - } - if ( my $requires = $option->{requires} ) - { - $option->{db_requires} = join( ";", map { my $value = $_->{value}; $value = ($value eq "yes")?1:0 if ( $options_hash{$_->{name}}->{db_type} eq "boolean" ); ( "$_->{name}=$value" ) } @$requires ); - } - else - { - } - my $res = $sth->execute( $option->{id}, $option->{name}, $option->{db_value}, $option->{db_type}, $option->{default}, $option->{db_hint}, $option->{db_pattern}, $option->{db_format}, $option->{description}, $option->{help}, $option->{category}, $option->{readonly}?1:0, $option->{db_requires} ) or croak( "Can't execute: ".$sth->errstr() ); - } - $sth->finish(); + $sql = "replace into Config set Id = ?, Name = ?, Value = ?, Type = ?, DefaultValue = ?, Hint = ?, Pattern = ?, Format = ?, Prompt = ?, Help = ?, Category = ?, Readonly = ?, Requires = ?"; + my $sth = $dbh->prepare_cached( $sql ) + or croak( "Can't prepare '$sql': ".$dbh->errstr() ); + foreach my $option ( @options ) + { + #next if ( $option->{category} eq 'hidden' ); + #print( $option->{name}."\n" ) if ( !$option->{category} ); + $option->{db_type} = $option->{type}->{db_type}; + $option->{db_hint} = $option->{type}->{hint}; + $option->{db_pattern} = $option->{type}->{pattern}; + $option->{db_format} = $option->{type}->{format}; + if ( $option->{db_type} eq "boolean" ) + { + $option->{db_value} = ($option->{value} eq "yes") + ? "1" + : "0" + ; + } + else + { + $option->{db_value} = $option->{value}; + } + if ( my $requires = $option->{requires} ) + { + $option->{db_requires} = join( ";", + map { + my $value = $_->{value}; + $value = ($value eq "yes") + ? 1 + : 0 + if ( $options_hash{$_->{name}}->{db_type} eq "boolean" ) + ; ( "$_->{name}=$value" ) + } @$requires + ); + } + else + { + } + my $res = $sth->execute( + $option->{id}, + $option->{name}, + $option->{db_value}, + $option->{db_type}, + $option->{default}, + $option->{db_hint}, + $option->{db_pattern}, + $option->{db_format}, + $option->{description}, + $option->{help}, + $option->{category}, + $option->{readonly} ? 1 : 0, + $option->{db_requires} + ) or croak( "Can't execute: ".$sth->errstr() ); + } + $sth->finish(); $dbh->do('UNLOCK TABLES'); $dbh->{AutoCommit} = $ac; - $dbh->disconnect(); + $dbh->disconnect(); } 1; @@ -179,9 +218,15 @@ ZoneMinder::ConfigAdmin - ZoneMinder Configuration Administration module =head1 DESCRIPTION -The ZoneMinder:ConfigAdmin module contains the master definition of the ZoneMinder configuration options as well as helper methods. This module is intended for specialist confguration management and would not normally be used by end users. +The ZoneMinder:ConfigAdmin module contains the master definition of the +ZoneMinder configuration options as well as helper methods. This module is +intended for specialist confguration management and would not normally be +used by end users. -The configuration held in this module, which was previously in zmconfig.pl, includes the name, default value, description, help text, type and category for each option, as well as a number of additional fields in a small number of cases. +The configuration held in this module, which was previously in zmconfig.pl, +includes the name, default value, description, help text, type and category +for each option, as well as a number of additional fields in a small number +of cases. =head1 METHODS @@ -189,11 +234,19 @@ The configuration held in this module, which was previously in zmconfig.pl, incl =item loadConfigFromDB (); -Loads existing configuration from the database (if any) and merges it with the definitions held in this module. This results in the merging of any new configuration and the removal of any deprecated configuration while preserving the existing values of every else. +Loads existing configuration from the database (if any) and merges it with +the definitions held in this module. This results in the merging of any new +configuration and the removal of any deprecated configuration while +preserving the existing values of every else. =item saveConfigToDB (); -Saves configuration held in memory to the database. The act of loading and saving configuration is a convenient way to ensure that the configuration held in the database corresponds with the most recent definitions and that all components are using the same set of configuration. +Saves configuration held in memory to the database. The act of loading and +saving configuration is a convenient way to ensure that the configuration +held in the database corresponds with the most recent definitions and that +all components are using the same set of configuration. + +=back =head2 EXPORT diff --git a/scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm.in b/scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm.in index b5eec34a4..e55e856e4 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm.in +++ b/scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm.in @@ -19,7 +19,7 @@ # # ========================================================================== # -# This module contains the debug definitions and functions used by the rest +# This module contains the debug definitions and functions used by the rest # of the ZoneMinder scripts # package ZoneMinder::ConfigData; @@ -37,15 +37,15 @@ our @ISA = qw(Exporter ZoneMinder::Base); # names by default without a very good reason. Use EXPORT_OK instead. # Do not simply export all your public functions/methods/constants. -# This allows declaration use ZoneMinder ':all'; +# This allows declaration use ZoneMinder ':all'; # If you do not need this, moving things directly into @EXPORT or @EXPORT_OK # will save memory. our %EXPORT_TAGS = ( - 'data' => [ qw( - %types - @options - %options_hash - ) ] + 'data' => [ qw( + %types + @options + %options_hash + ) ] ); push( @{$EXPORT_TAGS{all}}, @{$EXPORT_TAGS{$_}} ) foreach keys %EXPORT_TAGS; @@ -73,952 +73,2022 @@ sub INIT # Types our %types = ( - string => { db_type=>"string", hint=>"string", pattern=>qr|^(.+)$|, format=>q( $1 ) }, - alphanum => { db_type=>"string", hint=>"alphanumeric", pattern=>qr|^([a-zA-Z0-9-_]+)$|, format=>q( $1 ) }, - text => { db_type=>"text", hint=>"free text", pattern=>qr|^(.+)$|, format=>q( $1 ) }, - boolean => { db_type=>"boolean", hint=>"yes|no", pattern=>qr|^([yn])|i, check=>q( $1 ), format=>q( ($1 =~ /^y/) ? "yes" : "no" ) }, - integer => { db_type=>"integer", hint=>"integer", pattern=>qr|^(\d+)$|, format=>q( $1 ) }, - decimal => { db_type=>"decimal", hint=>"decimal", pattern=>qr|^(\d+(?:\.\d+)?)$|, format=>q( $1 ) }, - hexadecimal => { db_type=>"hexadecimal", hint=>"hexadecimal", pattern=>qr|^(?:0x)?([0-9a-f]{1,8})$|, format=>q( "0x".$1 ) }, - tristate => { db_type=>"string", hint=>"auto|yes|no", pattern=>qr|^([ayn])|i, check=>q( $1 ), format=>q( ($1 =~ /^y/) ? "yes" : ($1 =~ /^n/ ? "no" : "auto" ) ) }, - abs_path => { db_type=>"string", hint=>"/absolute/path/to/somewhere", pattern=>qr|^((?:/[^/]*)+?)/?$|, format=>q( $1 ) }, - rel_path => { db_type=>"string", hint=>"relative/path/to/somewhere", pattern=>qr|^((?:[^/].*)?)/?$|, format=>q( $1 ) }, - directory => { db_type=>"string", hint=>"directory", pattern=>qr|^([a-zA-Z0-9-_.]+)$|, format=>q( $1 ) }, - file => { db_type=>"string", hint=>"filename", pattern=>qr|^([a-zA-Z0-9-_.]+)$|, format=>q( $1 ) }, - hostname => { db_type=>"string", hint=>"host.your.domain", pattern=>qr|^([a-zA-Z0-9_.-]+)$|, format=>q( $1 ) }, - url => { db_type=>"string", hint=>"http://host.your.domain/", pattern=>qr|^(?:http://)?(.+)$|, format=>q( "http://".$1 ) }, - email => { db_type=>"string", hint=>"your.name\@your.domain", pattern=>qr|^([a-zA-Z0-9_.-]+)\@([a-zA-Z0-9_.-]+)$|, format=>q( $1\@$2 ) }, + string => { + db_type =>"string", + hint =>"string", + pattern =>qr|^(.+)$|, + format =>q( $1 ) + }, + alphanum => { + db_type =>"string", + hint =>"alphanumeric", + pattern =>qr|^([a-zA-Z0-9-_]+)$|, + format =>q( $1 ) + }, + text => { + db_type =>"text", + hint =>"free text", + pattern =>qr|^(.+)$|, + format =>q( $1 ) + }, + boolean => { + db_type =>"boolean", + hint =>"yes|no", + pattern =>qr|^([yn])|i, + check =>q( $1 ), + format =>q( ($1 =~ /^y/) + ? "yes" + : "no" + ) + }, + integer => { + db_type =>"integer", + hint =>"integer", + pattern =>qr|^(\d+)$|, + format =>q( $1 ) + }, + decimal => { + db_type =>"decimal", + hint =>"decimal", + pattern =>qr|^(\d+(?:\.\d+)?)$|, + format =>q( $1 ) + }, + hexadecimal => { + db_type =>"hexadecimal", + hint =>"hexadecimal", + pattern =>qr|^(?:0x)?([0-9a-f]{1,8})$|, + format =>q( "0x".$1 ) + }, + tristate => { + db_type =>"string", + hint =>"auto|yes|no", + pattern =>qr|^([ayn])|i, check=>q( $1 ), + format =>q( ($1 =~ /^y/) + ? "yes" + : ($1 =~ /^n/ ? "no" : "auto" ) + ) + }, + abs_path => { + db_type =>"string", + hint =>"/absolute/path/to/somewhere", + pattern =>qr|^((?:/[^/]*)+?)/?$|, + format =>q( $1 ) + }, + rel_path => { + db_type =>"string", + hint =>"relative/path/to/somewhere", + pattern =>qr|^((?:[^/].*)?)/?$|, + format =>q( $1 ) + }, + directory => { + db_type =>"string", + hint =>"directory", + pattern =>qr|^([a-zA-Z0-9-_.]+)$|, + format =>q( $1 ) + }, + file => { + db_type =>"string", + hint =>"filename", + pattern =>qr|^([a-zA-Z0-9-_.]+)$|, + format =>q( $1 ) + }, + hostname => { + db_type =>"string", + hint =>"host.your.domain", + pattern =>qr|^([a-zA-Z0-9_.-]+)$|, + format =>q( $1 ) + }, + url => { + db_type =>"string", + hint =>"http://host.your.domain/", + pattern =>qr|^(?:http://)?(.+)$|, + format =>q( "http://".$1 ) + }, + email => { + db_type =>"string", + hint =>"your.name\@your.domain", + pattern =>qr|^([a-zA-Z0-9_.-]+)\@([a-zA-Z0-9_.-]+)$|, + format =>q( $1\@$2 ) + }, ); +sub qqq { ## Un-pad paragraph of text. + local $_ = shift; + s{\n?^\s*}{ }mg; + return $_; +} + our @options = ( { - name => "ZM_SKIN_DEFAULT", - default => "classic", + name => "ZM_SKIN_DEFAULT", + default => "classic", description => "Default skin used by web interface", - help => "ZoneMinder allows the use of many different web interfaces. This option allows you to set the default skin used by the website. Users can change their skin later, this merely sets the default.", - type => $types{string}, - category => "system", + + help => qqq(" + ZoneMinder allows the use of many different web interfaces. + This option allows you to set the default skin used by the + website. Users can change their skin later, this merely sets + the default. + "), + type => $types{string}, + category => "system", }, { - name => "ZM_CSS_DEFAULT", - default => "classic", + name => "ZM_CSS_DEFAULT", + default => "classic", description => "Default set of css files used by web interface", - help => "ZoneMinder allows the use of many different web interfaces, and some skins allow the use of different set of CSS files to control the appearance. This option allows you to set the default set of css files used by the website. Users can change their css later, this merely sets the default.", - type => $types{string}, - category => "system", + help => qqq(" + ZoneMinder allows the use of many different web interfaces, and + some skins allow the use of different set of CSS files to + control the appearance. This option allows you to set the + default set of css files used by the website. Users can change + their css later, this merely sets the default. + "), + type => $types{string}, + category => "system", }, - { - name => "ZM_LANG_DEFAULT", - default => "en_gb", - description => "Default language used by web interface", - help => "ZoneMinder allows the web interface to use languages other than English if the appropriate language file has been created and is present. This option allows you to change the default language that is used from the shipped language, British English, to another language", - type => $types{string}, - category => "system", - }, - { - name => "ZM_OPT_USE_AUTH", - default => "no", - description => "Authenticate user logins to ZoneMinder", - help => "ZoneMinder can run in two modes. The simplest is an entirely unauthenticated mode where anyone can access ZoneMinder and perform all tasks. This is most suitable for installations where the web server access is limited in other ways. The other mode enables user accounts with varying sets of permissions. Users must login or authenticate to access ZoneMinder and are limited by their defined permissions.", - type => $types{boolean}, - category => "system", - }, - { - name => "ZM_AUTH_TYPE", - default => "builtin", - description => "What is used to authenticate ZoneMinder users", - help => "ZoneMinder can use two methods to authenticate users when running in authenticated mode. The first is a builtin method where ZoneMinder provides facilities for users to log in and maintains track of their identity. The second method allows interworking with other methods such as http basic authentication which passes an independently authentication 'remote' user via http. In this case ZoneMinder would use the supplied user without additional authentication provided such a user is configured ion ZoneMinder.", - requires => [ { name=>"ZM_OPT_USE_AUTH", value=>"yes" } ], - type => { db_type=>"string", hint=>"builtin|remote", pattern=>qr|^([br])|i, format=>q( $1 =~ /^b/ ? "builtin" : "remote" ) }, - category => "system", - }, - { - name => "ZM_AUTH_RELAY", - default => "hashed", - description => "Method used to relay authentication information", - help => "When ZoneMinder is running in authenticated mode it can pass user details between the web pages and the back end processes. There are two methods for doing this. This first is to use a time limited hashed string which contains no direct username or password details, the second method is to pass the username and passwords around in plaintext. This method is not recommend except where you do not have the md5 libraries available on your system or you have a completely isolated system with no external access. You can also switch off authentication relaying if your system is isolated in other ways.", - requires => [ { name=>"ZM_OPT_USE_AUTH", value=>"yes" } ], - type => { db_type=>"string", hint=>"hashed|plain|none", pattern=>qr|^([hpn])|i, format=>q( ($1 =~ /^h/) ? "hashed" : ($1 =~ /^p/ ? "plain" : "none" ) ) }, - category => "system", - }, - { - name => "ZM_AUTH_HASH_SECRET", - default => "...Change me to something unique...", - description => "Secret for encoding hashed authentication information", - help => "When ZoneMinder is running in hashed authenticated mode it is necessary to generate hashed strings containing encrypted sensitive information such as usernames and password. Although these string are reasonably secure the addition of a random secret increases security substantially.", - requires => [ { name=>"ZM_OPT_USE_AUTH", value=>"yes" }, { name=>"ZM_AUTH_RELAY", value=>"hashed" } ], - type => $types{string}, - category => "system", - }, - { - name => "ZM_AUTH_HASH_IPS", - default => "yes", - description => "Include IP addresses in the authentication hash", - help => "When ZoneMinder is running in hashed authenticated mode it can optionally include the requesting IP address in the resultant hash. This adds an extra level of security as only requests from that address may use that authentication key. However in some circumstances, such as access over mobile networks, the requesting address can change for each request which will cause most requests to fail. This option allows you to control whether IP addresses are included in the authentication hash on your system. If you experience intermitent problems with authentication, switching this option off may help.", - requires => [ { name=>"ZM_OPT_USE_AUTH", value=>"yes" }, { name=>"ZM_AUTH_RELAY", value=>"hashed" } ], - type => $types{boolean}, - category => "system", - }, - { - name => "ZM_AUTH_HASH_LOGINS", - default => "no", - description => "Allow login by authentication hash", - help => "The normal process for logging into ZoneMinder is via the login screen with username and password. In some circumstances it may be desirable to allow access directly to one or more pages, for instance from a third party application. If this option is enabled then adding an 'auth' parameter to any request will include a shortcut login bypassing the login screen, if not already logged in. As authentication hashes are time and, optionally, IP limited this can allow short-term access to ZoneMinder screens from other web pages etc. In order to use this the calling application will hae to generate the authentication hash itself and ensure it is valid. If you use this option you should ensure that you have modified the ZM_AUTH_HASH_SECRET to somethign unique to your system.", - requires => [ { name=>"ZM_OPT_USE_AUTH", value=>"yes" }, { name=>"ZM_AUTH_RELAY", value=>"hashed" } ], - type => $types{boolean}, - category => "system", - }, - { - name => "ZM_DIR_EVENTS", - default => "events", - description => "Directory where events are stored", - help => "This is the path to the events directory where all the event images and other miscellaneous files are stored. CAUTION: The directory you specify here cannot be outside the web root. This is a common mistake. Most users should never change this value. If you intend to record events to a second disk or network share, then you should mount the drive or share directly to the ZoneMinder events folder or follow the instructions in the ZoneMinder Wiki titled Using a dedicated Hard Drive.", - type => $types{directory}, - category => "paths", - }, - { - name => "ZM_USE_DEEP_STORAGE", - default => "yes", - description => "Use a deep filesystem hierarchy for events", - help => "Traditionally ZoneMinder stores all events for a monitor in one directory for that monitor. This is simple and efficient except when you have very large amounts of events. Some filesystems are unable to store more than 32k files in one directory and even without this limitation, large numbers of files in a directory can slow creation and deletion of files. This option allows you to select an alternate method of storing events by year/month/day/hour/min/second which has the effect of separating events out into more directories, resulting in less per directory, and also making it easier to manually navigate to any events that may have happened at a particular time or date.", - type => $types{boolean}, - category => "paths", - }, - { - name => "ZM_DIR_IMAGES", - default => "images", - description => "Directory where the images that the ZoneMinder client generates are stored", - help => "ZoneMinder generates a myriad of images, mostly of which are associated with events. For those that aren't this is where they go. CAUTION: The directory you specify here cannot be outside the web root. This is a common mistake. Most users should never change this value. If you intend to save images to a second disk or network share, then you should mount the drive or share directly to the ZoneMinder images folder or follow the instructions in the ZoneMinder Wiki titled Using a dedicated Hard Drive.", - type => $types{directory}, - category => "paths", - }, - { - name => "ZM_DIR_SOUNDS", - default => "sounds", - description => "Directory to the sounds that the ZoneMinder client can use", - help => "ZoneMinder can optionally play a sound file when an alarm is detected. This indicates where to look for this file. CAUTION: The directory you specify here cannot be outside the web root. Most users should never change this value.", - type => $types{directory}, - category => "paths", - }, - { - name => "ZM_PATH_ZMS", - default => "/cgi-bin/nph-zms", - description => "Web path to zms streaming server", - help => "The ZoneMinder streaming server is required to send streamed images to your browser. It will be installed into the cgi-bin path given at configuration time. This option determines what the web path to the server is rather than the local path on your machine. Ordinarily the streaming server runs in parser-header mode however if you experience problems with streaming you can change this to non-parsed-header (nph) mode by changing 'zms' to 'nph-zms'.", - type => $types{rel_path}, - category => "paths", - }, - { - name => "ZM_USE_MKV_STORAGE", - default => "no", - description => "UNDER DEVELOPMENT: Use a .mkv storage for events vs. JPEG", - help => "This is currently under active development and not working correctly. For now, ensure /var/www/zm/eventtemp is present and able to be written to (otherwise change the source). Please only use this option if you know what you're doing!", - type => $types{boolean}, - category => "paths", - }, - { - name => "ZM_COLOUR_JPEG_FILES", - default => "no", - description => "Colourise greyscale JPEG files", - help => "Cameras that capture in greyscale can write their captured images to jpeg files with a corresponding greyscale colour space. This saves a small amount of disk space over colour ones. However some tools such as ffmpeg either fail to work with this colour space or have to convert it beforehand. Setting this option to yes uses up a little more space but makes creation of MPEG files much faster.", - type => $types{boolean}, - category => "images", - }, - { - name => "ZM_ADD_JPEG_COMMENTS", - default => "no", - description => "Add jpeg timestamp annotations as file header comments", - help => "JPEG files may have a number of extra fields added to the file header. The comment field may have any kind of text added. This options allows you to have the same text that is used to annotate the image additionally included as a file header comment. If you archive event images to other locations this may help you locate images for particular events or times if you use software that can read comment headers.", - type => $types{boolean}, - category => "images", - }, - { - name => "ZM_JPEG_FILE_QUALITY", - default => "70", - description => "Set the JPEG quality setting for the saved event files (1-100)", - help => "When ZoneMinder detects an event it will save the images associated with that event to files. These files are in the JPEG format and can be viewed or streamed later. This option specifies what image quality should be used to save these files. A higher number means better quality but less compression so will take up more disk space and take longer to view over a slow connection. By contrast a low number means smaller, quicker to view, files but at the price of lower quality images. This setting applies to all images written except if the capture image has caused an alarm and the alarm file quality option is set at a higher value when that is used instead.", - type => $types{integer}, - category => "images", - }, - { - name => "ZM_JPEG_ALARM_FILE_QUALITY", - default => "0", - description => "Set the JPEG quality setting for the saved event files during an alarm (1-100)", - help => "This value is equivalent to the regular jpeg file quality setting above except that it only applies to images saved while in an alarm state and then only if this value is set to a higher quality setting than the ordinary file setting. If set to a lower value then it is ignored. Thus leaving it at the default of 0 effectively means to use the regular file quality setting for all saved images. This is to prevent acccidentally saving important images at a worse quality setting.", - type => $types{integer}, - category => "images", - }, - # Deprecated, now stream quality - { - name => "ZM_JPEG_IMAGE_QUALITY", - default => "70", - description => "Set the JPEG quality setting for the streamed 'live' images (1-100)", - help => "When viewing a 'live' stream for a monitor ZoneMinder will grab an image from the buffer and encode it into JPEG format before sending it. This option specifies what image quality should be used to encode these images. A higher number means better quality but less compression so will take longer to view over a slow connection. By contrast a low number means quicker to view images but at the price of lower quality images. This option does not apply when viewing events or still images as these are usually just read from disk and so will be encoded at the quality specified by the previous options.", - type => $types{integer}, - category => "hidden", - }, - { - name => "ZM_JPEG_STREAM_QUALITY", - default => "70", - description => "Set the JPEG quality setting for the streamed 'live' images (1-100)", - help => "When viewing a 'live' stream for a monitor ZoneMinder will grab an image from the buffer and encode it into JPEG format before sending it. This option specifies what image quality should be used to encode these images. A higher number means better quality but less compression so will take longer to view over a slow connection. By contrast a low number means quicker to view images but at the price of lower quality images. This option does not apply when viewing events or still images as these are usually just read from disk and so will be encoded at the quality specified by the previous options.", - type => $types{integer}, - category => "images", - }, - { - name => "ZM_MPEG_TIMED_FRAMES", - default => "yes", - description => "Tag video frames with a timestamp for more realistic streaming", - help => "When using streamed MPEG based video, either for live monitor streams or events, ZoneMinder can send the streams in two ways. If this option is selected then the timestamp for each frame, taken from it's capture time, is included in the stream. This means that where the frame rate varies, for instance around an alarm, the stream will still maintain it's 'real' timing. If this option is not selected then an approximate frame rate is calculated and that is used to schedule frames instead. This option should be selected unless you encounter problems with your preferred streaming method.", - type => $types{boolean}, - category => "images", - }, - { - name => "ZM_MPEG_LIVE_FORMAT", - default => "swf", - description => "What format 'live' video streams are played in", - help => "When using MPEG mode ZoneMinder can output live video. However what formats are handled by the browser varies greatly between machines. This option allows you to specify a video format using a file extension format, so you would just enter the extension of the file type you would like and the rest is determined from that. The default of 'asf' works well under Windows with Windows Media Player but I'm currently not sure what, if anything, works on a Linux platform. If you find out please let me know! If this option is left blank then live streams will revert to being in motion jpeg format", - type => $types{string}, - category => "images", - }, - { - name => "ZM_MPEG_REPLAY_FORMAT", - default => "swf", - description => "What format 'replay' video streams are played in", - help => "When using MPEG mode ZoneMinder can replay events in encoded video format. However what formats are handled by the browser varies greatly between machines. This option allows you to specify a video format using a file extension format, so you would just enter the extension of the file type you would like and the rest is determined from that. The default of 'asf' works well under Windows with Windows Media Player and 'mpg', or 'avi' etc should work under Linux. If you know any more then please let me know! If this option is left blank then live streams will revert to being in motion jpeg format", - type => $types{string}, - category => "images", - }, - { - name => "ZM_RAND_STREAM", - default => "yes", - description => "Add a random string to prevent caching of streams", - help => "Some browsers can cache the streams used by ZoneMinder. In order to prevent his a harmless random string can be appended to the url to make each invocation of the stream appear unique.", - type => $types{boolean}, - category => "images", - }, - { - name => "ZM_OPT_CAMBOZOLA", - default => "no", - description => "Is the (optional) cambozola java streaming client installed", - help => "Cambozola is a handy low fat cheese flavoured Java applet that ZoneMinder uses to view image streams on browsers such as Internet Explorer that don't natively support this format. If you use this browser it is highly recommended to install this from http://www.charliemouse.com/code/cambozola/ however if it is not installed still images at a lower refresh rate can still be viewed.", - type => $types{boolean}, - category => "images", - }, - { - name => "ZM_PATH_CAMBOZOLA", - default => "cambozola.jar", - description => "Web path to (optional) cambozola java streaming client", - help => "Cambozola is a handy low fat cheese flavoured Java applet that ZoneMinder uses to view image streams on browsers such as Internet Explorer that don't natively support this format. If you use this browser it is highly recommended to install this from http://www.charliemouse.com/code/cambozola/ however if it is not installed still images at a lower refresh rate can still be viewed. Leave this as 'cambozola.jar' if cambozola is installed in the same directory as the ZoneMinder web client files.", - requires => [ { name=>"ZM_OPT_CAMBOZOLA", value=>"yes" } ], - type => $types{rel_path}, - category => "images", - }, - { - name => "ZM_RELOAD_CAMBOZOLA", - default => "0", - description => "After how many seconds should Cambozola be reloaded in live view", - help => "Cambozola allows for the viewing of streaming MJPEG however it caches the entire stream into cache space on the computer, setting this to a number > 0 will cause it to automatically reload after that many seconds to avoid filling up a hard drive.", - type => $types{integer}, - category => "images", - }, - { - name => "ZM_TIMESTAMP_ON_CAPTURE", - default => "yes", - description => "Timestamp images as soon as they are captured", - help => "ZoneMinder can add a timestamp to images in two ways. The default method, when this option is set, is that each image is timestamped immediately when captured and so the image held in memory is marked right away. The second method does not timestamp the images until they are either saved as part of an event or accessed over the web. The timestamp used in both methods will contain the same time as this is preserved along with the image. The first method ensures that an image is timestamped regardless of any other circumstances but will result in all images being timestamped even those never saved or viewed. The second method necessitates that saved images are copied before being saved otherwise two timestamps perhaps at different scales may be applied. This has the (perhaps) desirable side effect that the timestamp is always applied at the same resolution so an image that has scaling applied will still have a legible and correctly scaled timestamp.", - type => $types{boolean}, - category => "config", - }, - { - name => "ZM_CPU_EXTENSIONS", - default => "yes", - description => "Use advanced CPU extensions to increase performance", - help => "When advanced processor extensions such as SSE2 or SSSE3 are available, ZoneMinder can use them, which should increase performance and reduce system load. Enabling this option on processors that do not support the advanced processors extensions used by ZoneMinder is harmless and will have no effect.", - type => $types{boolean}, - category => "config", - }, - { - name => "ZM_FAST_IMAGE_BLENDS", - default => "yes", - description => "Use a fast algorithm to blend the reference image", - help => "To detect alarms ZoneMinder needs to blend the captured image with the stored reference image to update it for comparison with the next image. The reference blend percentage specified for the monitor controls how much the new image affects the reference image. There are two methods that are available for this. If this option is set then fast calculation which does not use any multiplication or division is used. This calculation is extremely fast, however it limits the possible blend percentages to 50%, 25%, 12.5%, 6.25%, 3.25% and 1.5%. Any other blend percentage will be rounded to the nearest possible one. The alternative is to switch this option off and use standard blending instead, which is slower.", - type => $types{boolean}, - category => "config", - }, - { - name => "ZM_OPT_ADAPTIVE_SKIP", - default => "yes", - description => "Should frame analysis try and be efficient in skipping frames", - help => "In previous versions of ZoneMinder the analysis daemon would attempt to keep up with the capture daemon by processing the last captured frame on each pass. This would sometimes have the undesirable side-effect of missing a chunk of the initial activity that caused the alarm because the pre-alarm frames would all have to be written to disk and the database before processing the next frame, leading to some delay between the first and second event frames. Setting this option enables a newer adaptive algorithm where the analysis daemon attempts to process as many captured frames as possible, only skipping frames when in danger of the capture daemon overwriting yet to be processed frames. This skip is variable depending on the size of the ring buffer and the amount of space left in it. Enabling this option will give you much better coverage of the beginning of alarms whilst biasing out any skipped frames towards the middle or end of the event. However you should be aware that this will have the effect of making the analysis daemon run somewhat behind the capture daemon during events and for particularly fast rates of capture it is possible for the adaptive algorithm to be overwhelmed and not have time to react to a rapid build up of pending frames and thus for a buffer overrun condition to occur.", - type => $types{boolean}, - category => "config", - }, - { - name => "ZM_MAX_SUSPEND_TIME", - default => "30", - description => "Maximum time that a monitor may have motion detection suspended", - help => "ZoneMinder allows monitors to have motion detection to be suspended, for instance while panning a camera. Ordinarily this relies on the operator resuming motion detection afterwards as failure to do so can leave a monitor in a permanently suspended state. This setting allows you to set a maximum time which a camera may be suspended for before it automatically resumes motion detection. This time can be extended by subsequent suspend indications after the first so continuous camera movement will also occur while the monitor is suspended.", - type => $types{integer}, - category => "config", - }, - # Deprecated, really no longer necessary - { - name => "ZM_OPT_REMOTE_CAMERAS", - default => "no", - description => "Are you going to use remote/networked cameras", - help => "ZoneMinder can work with both local cameras, ie. those attached physically to your computer and remote or network cameras. If you will be using networked cameras select this option.", - type => $types{boolean}, - category => "hidden", - }, - # Deprecated, now set on a per monitor basis using the Method field - { - name => "ZM_NETCAM_REGEXPS", - default => "yes", - description => "Use regular expression matching with network cameras", - help => "Traditionally ZoneMinder has used complex regular regular expressions to handle the multitude of formats that network cameras produce. In versions from 1.21.1 the default is to use a simpler and faster built in pattern matching methodology. This works well with most networks cameras but if you have problems you can try the older, but more flexible, regular expression based method by selecting this option. Note, to use this method you must have libpcre installed on your system.", - requires => [ { name => "ZM_OPT_REMOTE_CAMERAS", value => "yes" } ], - type => $types{boolean}, - category => "hidden", - }, - { - name => "ZM_HTTP_VERSION", - default => "1.0", - description => "The version of HTTP that ZoneMinder will use to connect", - help => "ZoneMinder can communicate with network cameras using either of the HTTP/1.1 or HTTP/1.0 standard. A server will normally fall back to the version it supports with no problem so this should usually by left at the default. However it can be changed to HTTP/1.0 if necessary to resolve particular issues.", - type => { db_type=>"string", hint=>"1.1|1.0", pattern=>qr|^(1\.[01])$|, format=>q( $1?$1:"" ) }, - category => "network", - }, - { - name => "ZM_HTTP_UA", - default => "ZoneMinder", - description => "The user agent that ZoneMinder uses to identify itself", - help => "When ZoneMinder communicates with remote cameras it will identify itself using this string and it's version number. This is normally sufficient, however if a particular cameras expects only to communicate with certain browsers then this can be changed to a different string identifying ZoneMinder as Internet Explorer or Netscape etc.", - type => $types{string}, - category => "network", - }, - { - name => "ZM_HTTP_TIMEOUT", - default => "2500", - description => "How long ZoneMinder waits before giving up on images (milliseconds)", - help => "When retrieving remote images ZoneMinder will wait for this length of time before deciding that an image is not going to arrive and taking steps to retry. This timeout is in milliseconds (1000 per second) and will apply to each part of an image if it is not sent in one whole chunk.", - type => $types{integer}, - category => "network", - }, { - name => "ZM_MIN_RTP_PORT", - default => "40200", - description => "Minimum port that ZoneMinder will listen for RTP traffic on", - help => "When ZoneMinder communicates with MPEG4 capable cameras using RTP with the unicast method it must open ports for the camera to connect back to for control and streaming purposes. This setting specifies the minimum port number that ZoneMinder will use. Ordinarily two adjacent ports are used for each camera, one for control packets and one for data packets. This port should be set to an even number, you may also need to open up a hole in your firewall to allow cameras to connect back if you wish to use unicasting.", - type => $types{integer}, - category => "network", - }, - { - name => "ZM_MAX_RTP_PORT", - default => "40499", - description => "Maximum port that ZoneMinder will listen for RTP traffic on", - help => "When ZoneMinder communicates with MPEG4 capable cameras using RTP with the unicast method it must open ports for the camera to connect back to for control and streaming purposes. This setting specifies the maximum port number that ZoneMinder will use. Ordinarily two adjacent ports are used for each camera, one for control packets and one for data packets. This port should be set to an even number, you may also need to open up a hole in your firewall to allow cameras to connect back if you wish to use unicasting. You should also ensure that you have opened up at least two ports for each monitor that will be connecting to unicasting network cameras.", - type => $types{integer}, - category => "network", - }, - { - name => "ZM_OPT_FFMPEG", - default => "@OPT_FFMPEG@", - description => "Is the ffmpeg video encoder/decoder installed", - help => "ZoneMinder can optionally encode a series of video images into an MPEG encoded movie file for viewing, downloading or storage. This option allows you to specify whether you have the ffmpeg tools installed. Note that creating MPEG files can be fairly CPU and disk intensive and is not a required option as events can still be reviewed as video streams without it.", - type => $types{boolean}, - category => "images", - }, - { - name => "ZM_PATH_FFMPEG", - default => "@PATH_FFMPEG@", - description => "Path to (optional) ffmpeg mpeg encoder", - help => "This path should point to where ffmpeg has been installed.", - requires => [ { name=>"ZM_OPT_FFMPEG", value=>"yes" } ], - type => $types{abs_path}, - category => "images", - }, - { - name => "ZM_FFMPEG_INPUT_OPTIONS", - default => "", - description => "Additional input options to ffmpeg", - help => "Ffmpeg can take many options on the command line to control the quality of video produced. This option allows you to specify your own set that apply to the input to ffmpeg (options that are given before the -i option). Check the ffmpeg documentation for a full list of options which may be used here.", - requires => [ { name=>"ZM_OPT_FFMPEG", value=>"yes" } ], - type => $types{string}, - category => "images", - }, - { - name => "ZM_FFMPEG_OUTPUT_OPTIONS", - default => "-r 25", - description => "Additional output options to ffmpeg", - help => "Ffmpeg can take many options on the command line to control the quality of video produced. This option allows you to specify your own set that apply to the output from ffmpeg (options that are given after the -i option). Check the ffmpeg documentation for a full list of options which may be used here. The most common one will often be to force an output frame rate supported by the video encoder.", - requires => [ { name=>"ZM_OPT_FFMPEG", value=>"yes" } ], - type => $types{string}, - category => "images", - }, - { - name => "ZM_FFMPEG_FORMATS", - default => "mpg mpeg wmv asf avi* mov swf 3gp**", - description => "Formats to allow for ffmpeg video generation", - help => "Ffmpeg can generate video in many different formats. This option allows you to list the ones you want to be able to select. As new formats are supported by ffmpeg you can add them here and be able to use them immediately. Adding a '*' after a format indicates that this will be the default format used for web video, adding '**' defines the default format for phone video.", - requires => [ { name=>"ZM_OPT_FFMPEG", value=>"yes" } ], - type => $types{string}, - category => "images", - }, - { - name => "ZM_FFMPEG_OPEN_TIMEOUT", - default => "10", - description => "Timeout in seconds when opening a stream.", - help => "When Ffmpeg is opening a stream, it can take a long time before failing; certain circumstances even seem to be able to lock indefinitely. This option allows you to set a maximum time in seconds to pass before closing the stream and trying to reopen it again.", - requires => [ { name=>"ZM_OPT_FFMPEG", value=>"yes" } ], - type => $types{integer}, - category => "images", - }, - { - name => "ZM_LOG_LEVEL_SYSLOG", - default => "0", - description => "Save logging output to the system log", - help => "ZoneMinder logging is now more more integrated between components and allows you to specify the destination for logging output and the individual levels for each. This option lets you control the level of logging output that goes to the system log. ZoneMinder binaries have always logged to the system log but now scripts and web logging is also included. To preserve the previous behaviour you should ensure this value is set to Info or Warning. This option controls the maximum level of logging that will be written, so Info includes Warnings and Errors etc. To disable entirely, set this option to None. You should use caution when setting this option to Debug as it can affect severely affect system performance. If you want debug you will also need to set a level and component below", - type => { db_type=>"integer", hint=>"None=-5|Panic=-4|Fatal=-3|Error=-2|Warning=-1|Info=0|Debug=1", pattern=>qr|^(\d+)$|, format=>q( $1 ) }, - category => "logging", - }, - { - name => "ZM_LOG_LEVEL_FILE", - default => "-5", - description => "Save logging output to component files", - help => "ZoneMinder logging is now more more integrated between components and allows you to specify the destination for logging output and the individual levels for each. This option lets you control the level of logging output that goes to individual log files written by specific components. This is how logging worked previously and although useful for tracking down issues in specific components it also resulted in many disparate log files. To preserve this behaviour you should ensure this value is set to Info or Warning. This option controls the maximum level of logging that will be written, so Info includes Warnings and Errors etc. To disable entirely, set this option to None. You should use caution when setting this option to Debug as it can affect severely affect system performance though file output has less impact than the other options. If you want debug you will also need to set a level and component below", - type => { db_type=>"integer", hint=>"None=-5|Panic=-4|Fatal=-3|Error=-2|Warning=-1|Info=0|Debug=1", pattern=>qr|^(\d+)$|, format=>q( $1 ) }, - category => "logging", - }, - { - name => "ZM_LOG_LEVEL_WEBLOG", - default => "-5", - description => "Save logging output to the weblog", - help => "ZoneMinder logging is now more more integrated between components and allows you to specify the destination for logging output and the individual levels for each. This option lets you control the level of logging output from the web interface that goes to the httpd error log. Note that only web logging from PHP and JavaScript files is included and so this option is really only useful for investigating specific issues with those components. This option controls the maximum level of logging that will be written, so Info includes Warnings and Errors etc. To disable entirely, set this option to None. You should use caution when setting this option to Debug as it can affect severely affect system performance. If you want debug you will also need to set a level and component below", - type => { db_type=>"integer", hint=>"None=-5|Panic=-4|Fatal=-3|Error=-2|Warning=-1|Info=0|Debug=1", pattern=>qr|^(\d+)$|, format=>q( $1 ) }, - category => "logging", - }, - { - name => "ZM_LOG_LEVEL_DATABASE", - default => "0", - description => "Save logging output to the database", - help => "ZoneMinder logging is now more more integrated between components and allows you to specify the destination for logging output and the individual levels for each. This option lets you control the level of logging output that is written to the database. This is a new option which can make viewing logging output easier and more intuitive and also makes it easier to get an overall impression of how the system is performing. If you have a large or very busy system then it is possible that use of this option may slow your system down if the table becomes very large. Ensure you use the LOG_DATABASE_LIMIT option to keep the table to a manageable size. This option controls the maximum level of logging that will be written, so Info includes Warnings and Errors etc. To disable entirely, set this option to None. You should use caution when setting this option to Debug as it can affect severely affect system performance. If you want debug you will also need to set a level and component below", - type => { db_type=>"integer", hint=>"None=-5|Panic=-4|Fatal=-3|Error=-2|Warning=-1|Info=0|Debug=1", pattern=>qr|^(\d+)$|, format=>q( $1 ) }, - category => "logging", - }, - { - name => "ZM_LOG_DATABASE_LIMIT", - default => "7 day", - description => "Maximum number of log entries to retain", - help => "If you are using database logging then it is possible to quickly build up a large number of entries in the Logs table. This option allows you to specify how many of these entries are kept. If you set this option to a number greater than zero then that number is used to determine the maximum number of rows, less than or equal to zero indicates no limit and is not recommended. You can also set this value to time values such as ' day' which will limit the log entries to those newer than that time. You can specify 'hour', 'day', 'week', 'month' and 'year', note that the values should be singular (no 's' at the end). The Logs table is pruned periodically so it is possible for more than the expected number of rows to be present briefly in the meantime.", - type => $types{string}, - category => "logging", - }, - { - name => "ZM_LOG_DEBUG", - default => "no", - description => "Switch debugging on", - help => "ZoneMinder components usually support debug logging available to help with diagnosing problems. Binary components have several levels of debug whereas more other components have only one. Normally this is disabled to minimise performance penalties and avoid filling logs too quickly. This option lets you switch on other options that allow you to configure additional debug information to be output. Components will pick up this instruction when they are restarted.", - type => $types{boolean}, - category => "logging", - }, - { - name => "ZM_LOG_DEBUG_TARGET", - default => "", - description => "What components should have extra debug enabled", - help => "There are three scopes of debug available. Leaving this option blank means that all components will use extra debug (not recommended). Setting this option to '_', e.g. _zmc, will limit extra debug to that component only. Setting this option to '__', e.g. '_zmc_m1' will limit extra debug to that instance of the component only. This is ordinarily what you probably want to do. To debug scripts use their names without the .pl extension, e.g. '_zmvideo' and to debug issues with the web interface use '_web'. You can specify multiple targets by separating them with '|' characters.", - requires => [ { name => "ZM_LOG_DEBUG", value => "yes" } ], - type => $types{string}, - category => "logging", - }, - { - name => "ZM_LOG_DEBUG_LEVEL", - default => 1, - description => "What level of extra debug should be enabled", - help => "There are 9 levels of debug available, with higher numbers being more debug and level 0 being no debug. However not all levels are used by all components. Also if there is debug at a high level it is usually likely to be output at such a volume that it may obstruct normal operation. For this reason you should set the level carefully and cautiously until the degree of debug you wish to see is present. Scripts and the web interface only have one level so this is an on/off type option for them.", - requires => [ { name => "ZM_LOG_DEBUG", value => "yes" } ], - type => { db_type=>"integer", hint=>"1|2|3|4|5|6|7|8|9", pattern=>qr|^(\d+)$|, format=>q( $1 ) }, - category => "logging", - }, - { - name => "ZM_LOG_DEBUG_FILE", - default => "@ZM_LOGDIR@/zm_debug.log+", - description => "Where extra debug is output to", - help => "This option allows you to specify a different target for debug output. All components have a default log file which will norally be in /tmp or /var/log and this is where debug will be written to if this value is empty. Adding a path here will temporarily redirect debug, and other logging output, to this file. This option is a simple filename and you are debugging several components then they will all try and write to the same file with undesirable consequences. Appending a '+' to the filename will cause the file to be created with a '.' suffix containing your process id. In this way debug from each run of a component is kept separate. This is the recommended setting as it will also prevent subsequent runs from overwriting the same log. You should ensure that permissions are set up to allow writing to the file and directory specified here.", - requires => [ { name => "ZM_LOG_DEBUG", value => "yes" } ], - type => $types{string}, - category => "logging", - }, - { - name => "ZM_LOG_CHECK_PERIOD", - default => "900", - description => "Time period used when calculating overall system health", - help => "When ZoneMinder is logging events to the database it can retrospectively examine the number of warnings and errors that have occurred to calculate an overall state of system health. This option allows you to indicate what period of historical events are used in this calculation. This value is expressed in seconds and is ignored if LOG_LEVEL_DATABASE is set to None.", - type => $types{integer}, - category => "logging", - }, - { - name => "ZM_LOG_ALERT_WAR_COUNT", - default => "1", - description => "Number of warnings indicating system alert state", - help => "When ZoneMinder is logging events to the database it can retrospectively examine the number of warnings and errors that have occurred to calculate an overall state of system health. This option allows you to specify how many warnings must have occurred within the defined time period to generate an overall system alert state. A value of zero means warnings are not considered. This value is ignored if LOG_LEVEL_DATABASE is set to None.", - type => $types{integer}, - category => "logging", - }, - { - name => "ZM_LOG_ALERT_ERR_COUNT", - default => "1", - description => "Number of errors indicating system alert state", - help => "When ZoneMinder is logging events to the database it can retrospectively examine the number of warnings and errors that have occurred to calculate an overall state of system health. This option allows you to specify how many errors must have occurred within the defined time period to generate an overall system alert state. A value of zero means errors are not considered. This value is ignored if LOG_LEVEL_DATABASE is set to None.", - type => $types{integer}, - category => "logging", - }, - { - name => "ZM_LOG_ALERT_FAT_COUNT", - default => "0", - description => "Number of fatal error indicating system alert state", - help => "When ZoneMinder is logging events to the database it can retrospectively examine the number of warnings and errors that have occurred to calculate an overall state of system health. This option allows you to specify how many fatal errors (including panics) must have occurred within the defined time period to generate an overall system alert state. A value of zero means fatal errors are not considered. This value is ignored if LOG_LEVEL_DATABASE is set to None.", - type => $types{integer}, - category => "logging", - }, - { - name => "ZM_LOG_ALARM_WAR_COUNT", - default => "100", - description => "Number of warnings indicating system alarm state", - help => "When ZoneMinder is logging events to the database it can retrospectively examine the number of warnings and errors that have occurred to calculate an overall state of system health. This option allows you to specify how many warnings must have occurred within the defined time period to generate an overall system alarm state. A value of zero means warnings are not considered. This value is ignored if LOG_LEVEL_DATABASE is set to None.", - type => $types{integer}, - category => "logging", - }, - { - name => "ZM_LOG_ALARM_ERR_COUNT", - default => "10", - description => "Number of errors indicating system alarm state", - help => "When ZoneMinder is logging events to the database it can retrospectively examine the number of warnings and errors that have occurred to calculate an overall state of system health. This option allows you to specify how many errors must have occurred within the defined time period to generate an overall system alarm state. A value of zero means errors are not considered. This value is ignored if LOG_LEVEL_DATABASE is set to None.", - type => $types{integer}, - category => "logging", - }, - { - name => "ZM_LOG_ALARM_FAT_COUNT", - default => "1", - description => "Number of fatal error indicating system alarm state", - help => "When ZoneMinder is logging events to the database it can retrospectively examine the number of warnings and errors that have occurred to calculate an overall state of system health. This option allows you to specify how many fatal errors (including panics) must have occurred within the defined time period to generate an overall system alarm state. A value of zero means fatal errors are not considered. This value is ignored if LOG_LEVEL_DATABASE is set to None.", - type => $types{integer}, - category => "logging", - }, - { - name => "ZM_RECORD_EVENT_STATS", - default => "yes", - description => "Record event statistical information, switch off if too slow", - help => "This version of ZoneMinder records detailed information about events in the Stats table. This can help in profiling what the optimum settings are for Zones though this is tricky at present. However in future releases this will be done more easily and intuitively, especially with a large sample of events. The default option of 'yes' allows this information to be collected now in readiness for this but if you are concerned about performance you can switch this off in which case no Stats information will be saved.", - type => $types{boolean}, - category => "logging", - }, - { - name => "ZM_RECORD_DIAG_IMAGES", - default => "no", - description => "Record intermediate alarm diagnostic images, can be very slow", - help => "In addition to recording event statistics you can also record the intermediate diagnostic images that display the results of the various checks and processing that occur when trying to determine if an alarm event has taken place. There are several of these images generated for each frame and zone for each alarm or alert frame so this can have a massive impact on performance. Only switch this setting on for debug or analysis purposes and remember to switch it off again once no longer required.", - type => $types{boolean}, - category => "logging", - }, - { - name => "ZM_DUMP_CORES", - default => "no", - description => "Create core files on unexpected process failure.", - help => "When an unrecoverable error occurs in a ZoneMinder binary process is has traditionally been trapped and the details written to logs to aid in remote analysis. However in some cases it is easier to diagnose the error if a core file, which is a memory dump of the process at the time of the error, is created. This can be interactively analysed in the debugger and may reveal more or better information than that available from the logs. This option is recommended for advanced users only otherwise leave at the default. Note using this option to trigger core files will mean that there will be no indication in the binary logs that a process has died, they will just stop, however the zmdc log will still contain an entry. Also note that you may have to explicitly enable core file creation on your system via the 'ulimit -c' command or other means otherwise no file will be created regardless of the value of this option.", - type => $types{boolean}, - category => "logging", - }, - { - name => "ZM_PATH_MAP", - default => "/dev/shm", - description => "Path to the mapped memory files that that ZoneMinder can use", - help => "ZoneMinder has historically used IPC shared memory for shared data between processes. This has it's advantages and limitations. This version of ZoneMinder can use an alternate method, mapped memory, instead with can be enabled with the --enable--mmap directive to configure. This requires less system configuration and is generally more flexible. However it requires each shared data segment to map onto a filesystem file. This option indicates where those mapped files go. You should ensure that this location has sufficient space for these files and for the best performance it should be a tmpfs file system or ramdisk otherwise disk access may render this method slower than the regular shared memory one.", - type => $types{abs_path}, - category => "paths", - }, - { - name => "ZM_PATH_SOCKS", - default => "@ZM_SOCKDIR@", - description => "Path to the various Unix domain socket files that ZoneMinder uses", - help => "ZoneMinder generally uses Unix domain sockets where possible. This reduces the need for port assignments and prevents external applications from possibly compromising the daemons. However each Unix socket requires a .sock file to be created. This option indicates where those socket files go.", - type => $types{abs_path}, - category => "paths", - }, - { - name => "ZM_PATH_LOGS", - default => "@ZM_LOGDIR@", - description => "Path to the various logs that the ZoneMinder daemons generate", - help => "There are various daemons that are used by ZoneMinder to perform various tasks. Most generate helpful log files and this is where they go. They can be deleted if not required for debugging.", - type => $types{abs_path}, - category => "paths", - }, - { - name => "ZM_PATH_SWAP", - default => "@ZM_TMPDIR@", - description => "Path to location for temporary swap images used in streaming", - help => "Buffered playback requires temporary swap images to be stored for each instance of the streaming daemons. This option determines where these images will be stored. The images will actually be stored in sub directories beneath this location and will be automatically cleaned up after a period of time.", - type => $types{abs_path}, - category => "paths", - }, - { - name => "ZM_PATH_ARP", - default => "", - description => "Path to a supported ARP tool", - help => "The camera probe function uses Address Resolution Protocol in order to find known devices on the network. Optionally supply the full path to \"ip neigh\", \"arp -a\", or any other tool on your system that returns ip/mac address pairs. If this field is left empty, ZoneMinder will search for the command \"arp\" and attempt to use that.", - type => $types{abs_path}, - category => "paths", - }, - { - name => "ZM_WEB_TITLE_PREFIX", - default => "ZM", - description => "The title prefix displayed on each window", - help => "If you have more than one installation of ZoneMinder it can be helpful to display different titles for each one. Changing this option allows you to customise the window titles to include further information to aid identification.", - type => $types{string}, - category => "web", - }, - { - name => "ZM_WEB_RESIZE_CONSOLE", - default => "yes", - description => "Should the console window resize itself to fit", - help => "Traditionally the main ZoneMinder web console window has resized itself to shrink to a size small enough to list only the monitors that are actually present. This is intended to make the window more unobtrusize but may not be to everyones tastes, especially if opened in a tab in browsers which support this kind if layout. Switch this option off to have the console window size left to the users preference", - type => $types{boolean}, - category => "web", - }, - { - name => "ZM_WEB_POPUP_ON_ALARM", - default => "yes", - description => "Should the monitor window jump to the top if an alarm occurs", - help => "When viewing a live monitor stream you can specify whether you want the window to pop to the front if an alarm occurs when the window is minimised or behind another window. This is most useful if your monitors are over doors for example when they can pop up if someone comes to the doorway.", - type => $types{boolean}, - category => "web", - }, - { - name => "ZM_OPT_X10", - default => "no", - description => "Support interfacing with X10 devices", - help => "If you have an X10 Home Automation setup in your home you can use ZoneMinder to initiate or react to X10 signals if your computer has the appropriate interface controller. This option indicates whether X10 options will be available in the browser client.", - type => $types{boolean}, - category => "x10", - }, - { - name => "ZM_X10_DEVICE", - default => "/dev/ttyS0", - description => "What device is your X10 controller connected on", - requires => [ { name => "ZM_OPT_X10", value => "yes" } ], - help => "If you have an X10 controller device (e.g. XM10U) connected to your computer this option details which port it is conected on, the default of /dev/ttyS0 maps to serial or com port 1.", - type => $types{abs_path}, - category => "x10", - }, - { - name => "ZM_X10_HOUSE_CODE", - default => "A", - description => "What X10 house code should be used", - requires => [ { name => "ZM_OPT_X10", value => "yes" } ], - help => "X10 devices are grouped together by identifying them as all belonging to one House Code. This option details what that is. It should be a single letter between A and P.", - type => { db_type=>"string", hint=>"A-P", pattern=>qr|^([A-P])|i, format=>q( uc($1) ) }, - category => "x10", - }, - { - name => "ZM_X10_DB_RELOAD_INTERVAL", - default => "60", - description => "How often (in seconds) the X10 daemon reloads the monitors from the database", - requires => [ { name => "ZM_OPT_X10", value => "yes" } ], - help => "The zmx10 daemon periodically checks the database to find out what X10 events trigger, or result from, alarms. This option determines how frequently this check occurs, unless you change this area frequently this can be a fairly large value.", - type => $types{integer}, - category => "x10", - }, - { - name => "ZM_WEB_SOUND_ON_ALARM", - default => "no", - description => "Should the monitor window play a sound if an alarm occurs", - help => "When viewing a live monitor stream you can specify whether you want the window to play a sound to alert you if an alarm occurs.", - type => $types{boolean}, - category => "web", - }, - { - name => "ZM_WEB_ALARM_SOUND", - default => "", - description => "The sound to play on alarm, put this in the sounds directory", - help => "You can specify a sound file to play if an alarm occurs whilst you are watching a live monitor stream. So long as your browser understands the format it does not need to be any particular type. This file should be placed in the sounds directory defined earlier.", - type => $types{file}, - requires => [ { name => "ZM_WEB_SOUND_ON_ALARM", value => "yes" } ], - category => "web", - }, - { - name => "ZM_WEB_COMPACT_MONTAGE", - default => "no", - description => "Compact the montage view by removing extra detail", - help => "The montage view shows the output of all of your active monitors in one window. This include a small menu and status information for each one. This can increase the web traffic and make the window larger than may be desired. Setting this option on removes all this extraneous information and just displays the images.", - type => $types{boolean}, - category => "web", - }, - { - name => "ZM_OPT_FAST_DELETE", - default => "yes", - description => "Delete only event database records for speed", - help => "Normally an event created as the result of an alarm consists of entries in one or more database tables plus the various files associated with it. When deleting events in the browser it can take a long time to remove all of this if your are trying to do a lot of events at once. It is recommended that you set this option which means that the browser client only deletes the key entries in the events table, which means the events will no longer appear in the listing, and leaves the zmaudit daemon to clear up the rest later.", - type => $types{boolean}, - category => "system", - }, - { - name => "ZM_STRICT_VIDEO_CONFIG", - default => "yes", - description => "Allow errors in setting video config to be fatal", - help => "With some video devices errors can be reported in setting the various video attributes when in fact the operation was successful. Switching this option off will still allow these errors to be reported but will not cause them to kill the video capture daemon. Note however that doing this will cause all errors to be ignored including those which are genuine and which may cause the video capture to not function correctly. Use this option with caution.", - type => $types{boolean}, - category => "config", - }, - { - name => "ZM_SIGNAL_CHECK_POINTS", - default => "10", - description => "How many points in a captured image to check for signal loss", - help => "For locally attached video cameras ZoneMinder can check for signal loss by looking at a number of random points on each captured image. If all of these points are set to the same fixed colour then the camera is assumed to have lost signal. When this happens any open events are closed and a short one frame signal loss event is generated, as is another when the signal returns. This option defines how many points on each image to check. Note that this is a maximum, any points found to not have the check colour will abort any further checks so in most cases on a couple of points will actually be checked. Network and file based cameras are never checked.", - type => $types{integer}, - category => "config", - }, - { - name => "ZM_V4L_MULTI_BUFFER", - default => "yes", - description => "Use more than one buffer for Video 4 Linux devices", - help => "Performance when using Video 4 Linux devices is usually best if multiple buffers are used allowing the next image to be captured while the previous one is being processed. If you have multiple devices on a card sharing one input that requires switching then this approach can sometimes cause frames from one source to be mixed up with frames from another. Switching this option off prevents multi buffering resulting in slower but more stable image capture. This option is ignored for non-local cameras or if only one input is present on a capture chip. This option addresses a similar problem to the ZM_CAPTURES_PER_FRAME option and you should normally change the value of only one of the options at a time. If you have different capture cards that need different values you can ovveride them in each individual monitor on the source page.", - type => $types{boolean}, - category => "config", - }, - { - name => "ZM_CAPTURES_PER_FRAME", - default => "1", - description => "How many images are captured per returned frame, for shared local cameras", - help => "If you are using cameras attached to a video capture card which forces multiple inputs to share one capture chip, it can sometimes produce images with interlaced frames reversed resulting in poor image quality and a distinctive comb edge appearance. Increasing this setting allows you to force additional image captures before one is selected as the captured frame. This allows the capture hardware to 'settle down' and produce better quality images at the price of lesser capture rates. This option has no effect on (a) network cameras, or (b) where multiple inputs do not share a capture chip. This option addresses a similar problem to the ZM_V4L_MULTI_BUFFER option and you should normally change the value of only one of the options at a time. If you have different capture cards that need different values you can ovveride them in each individual monitor on the source page.", - type => $types{integer}, - category => "config", - }, - { - name => "ZM_FILTER_RELOAD_DELAY", - default => "300", - description => "How often (in seconds) filters are reloaded in zmfilter", - help => "ZoneMinder allows you to save filters to the database which allow events that match certain criteria to be emailed, deleted or uploaded to a remote machine etc. The zmfilter daemon loads these and does the actual operation. This option determines how often the filters are reloaded from the database to get the latest versions or new filters. If you don't change filters very often this value can be set to a large value.", - type => $types{integer}, - category => "system", - }, - { - name => "ZM_FILTER_EXECUTE_INTERVAL", - default => "60", - description => "How often (in seconds) to run automatic saved filters", - help => "ZoneMinder allows you to save filters to the database which allow events that match certain criteria to be emailed, deleted or uploaded to a remote machine etc. The zmfilter daemon loads these and does the actual operation. This option determines how often the filters are executed on the saved event in the database. If you want a rapid response to new events this should be a smaller value, however this may increase the overall load on the system and affect performance of other elements.", - type => $types{integer}, - category => "system", - }, - { - name => "ZM_OPT_UPLOAD", - default => "no", - description => "Should ZoneMinder support uploading events from filters", - help => "In ZoneMinder you can create event filters that specify whether events that match certain criteria should be uploaded to a remote server for archiving. This option specifies whether this functionality should be available", - type => $types{boolean}, - category => "upload", - }, - { - name => "ZM_UPLOAD_ARCH_FORMAT", - default => "tar", - description => "What format the uploaded events should be created in.", - requires => [ { name => "ZM_OPT_UPLOAD", value => "yes" } ], - help => "Uploaded events may be stored in either .tar or .zip format, this option specifies which. Note that to use this you will need to have the Archive::Tar and/or Archive::Zip perl modules installed.", - type => { db_type=>"string", hint=>"tar|zip", pattern=>qr|^([tz])|i, format=>q( $1 =~ /^t/ ? "tar" : "zip" ) }, - category => "upload", - }, - { - name => "ZM_UPLOAD_ARCH_COMPRESS", - default => "no", - description => "Should archive files be compressed", - help => "When the archive files are created they can be compressed. However in general since the images are compressed already this saves only a minimal amount of space versus utilising more CPU in their creation. Only enable if you have CPU to waste and are limited in disk space on your remote server or bandwidth.", - requires => [ { name => "ZM_OPT_UPLOAD", value => "yes" } ], - type => $types{boolean}, - category => "upload", - }, - { - name => "ZM_UPLOAD_ARCH_ANALYSE", - default => "no", - description => "Include the analysis files in the archive", - help => "When the archive files are created they can contain either just the captured frames or both the captured frames and, for frames that caused an alarm, the analysed image with the changed area highlighted. This option controls files are included. Only include analysed frames if you have a high bandwidth connection to the remote server or if you need help in figuring out what caused an alarm in the first place as archives with these files in can be considerably larger.", - requires => [ { name => "ZM_OPT_UPLOAD", value => "yes" } ], - type => $types{boolean}, - category => "upload", - }, - { - name => "ZM_UPLOAD_PROTOCOL", - default => "ftp", - description => "What protocol to use to upload events", - requires => [ { name => "ZM_OPT_UPLOAD", value => "yes" } ], - help => "ZoneMinder can upload events to a remote server using either FTP or SFTP. Regular FTP is widely supported but not necessarily very secure whereas SFTP (Secure FTP) runs over an ssh connection and so is encrypted and uses regular ssh ports. Note that to use this you will need to have the appropriate perl module, either Net::FTP or Net::SFTP installed depending on your choice.", - type => { db_type=>"string", hint=>"ftp|sftp", pattern=>qr|^([tz])|i, format=>q( $1 =~ /^f/ ? "ftp" : "sftp" ) }, - category => "upload", - }, - { - name => "ZM_UPLOAD_FTP_HOST", - default => "", - description => "The remote server to upload to", - help => "You can use filters to instruct ZoneMinder to upload events to a remote ftp server. This option indicates the name, or ip address, of the server to use.", - requires => [ { name => "ZM_OPT_UPLOAD", value => "yes" } ], - type => $types{hostname}, - category => "hidden", - }, - { - name => "ZM_UPLOAD_HOST", - default => "", - description => "The remote server to upload events to", - help => "You can use filters to instruct ZoneMinder to upload events to a remote server. This option indicates the name, or ip address, of the server to use.", - requires => [ { name => "ZM_OPT_UPLOAD", value => "yes" } ], - type => $types{hostname}, - category => "upload", - }, - { - name => "ZM_UPLOAD_PORT", - default => "", - description => "The port on the remote upload server, if not the default (SFTP only)", - help => "You can use filters to instruct ZoneMinder to upload events to a remote server. If you are using the SFTP protocol then this option allows you to specify a particular port to use for connection. If this option is left blank then the default, port 22, is used. This option is ignored for FTP uploads.", - requires => [ { name => "ZM_OPT_UPLOAD", value => "yes" } ], - type => $types{integer}, - category => "upload", - }, - { - name => "ZM_UPLOAD_FTP_USER", - default => "", - description => "Your ftp username", - help => "You can use filters to instruct ZoneMinder to upload events to a remote ftp server. This option indicates the username that ZoneMinder should use to log in for ftp transfer.", - requires => [ { name => "ZM_OPT_UPLOAD", value => "yes" } ], - type => $types{alphanum}, - category => "hidden", - }, - { - name => "ZM_UPLOAD_USER", - default => "", - description => "Remote server username", - help => "You can use filters to instruct ZoneMinder to upload events to a remote server. This option indicates the username that ZoneMinder should use to log in for transfer.", - requires => [ { name => "ZM_OPT_UPLOAD", value => "yes" } ], - type => $types{alphanum}, - category => "upload", - }, - { - name => "ZM_UPLOAD_FTP_PASS", - default => "", - description => "Your ftp password", - help => "You can use filters to instruct ZoneMinder to upload events to a remote ftp server. This option indicates the password that ZoneMinder should use to log in for ftp transfer.", - requires => [ { name => "ZM_OPT_UPLOAD", value => "yes" } ], - type => $types{string}, - category => "hidden", - }, - { - name => "ZM_UPLOAD_PASS", - default => "", - description => "Remote server password", - help => "You can use filters to instruct ZoneMinder to upload events to a remote server. This option indicates the password that ZoneMinder should use to log in for transfer. If you are using certicate based logins for SFTP servers you can leave this option blank.", - requires => [ { name => "ZM_OPT_UPLOAD", value => "yes" } ], - type => $types{string}, - category => "upload", - }, - { - name => "ZM_UPLOAD_FTP_LOC_DIR", - default => "@ZM_TMPDIR@", - description => "The local directory in which to create upload files", - help => "You can use filters to instruct ZoneMinder to upload events to a remote ftp server. This option indicates the local directory that ZoneMinder should use for temporary upload files. These are files that are created from events, uploaded and then deleted.", - requires => [ { name => "ZM_OPT_UPLOAD", value => "yes" } ], - type => $types{abs_path}, - category => "hidden", - }, - { - name => "ZM_UPLOAD_LOC_DIR", - default => "@ZM_TMPDIR@", - description => "The local directory in which to create upload files", - help => "You can use filters to instruct ZoneMinder to upload events to a remote server. This option indicates the local directory that ZoneMinder should use for temporary upload files. These are files that are created from events, uploaded and then deleted.", - requires => [ { name => "ZM_OPT_UPLOAD", value => "yes" } ], - type => $types{abs_path}, - category => "upload", - }, - { - name => "ZM_UPLOAD_FTP_REM_DIR", - default => "", - description => "The remote directory to upload to", - help => "You can use filters to instruct ZoneMinder to upload events to a remote ftp server. This option indicates the remote directory that ZoneMinder should use to upload event files to.", - requires => [ { name => "ZM_OPT_UPLOAD", value => "yes" } ], - type => $types{rel_path}, - category => "hidden", - }, - { - name => "ZM_UPLOAD_REM_DIR", - default => "", - description => "The remote directory to upload to", - help => "You can use filters to instruct ZoneMinder to upload events to a remote server. This option indicates the remote directory that ZoneMinder should use to upload event files to.", - requires => [ { name => "ZM_OPT_UPLOAD", value => "yes" } ], - type => $types{rel_path}, - category => "upload", - }, - { - name => "ZM_UPLOAD_FTP_TIMEOUT", - default => "120", - description => "How long to allow the transfer to take for each file", - help => "You can use filters to instruct ZoneMinder to upload events to a remote ftp server. This option indicates the maximum ftp inactivity timeout (in seconds) that should be tolerated before ZoneMinder determines that the transfer has failed and closes down the connection.", - requires => [ { name => "ZM_OPT_UPLOAD", value => "yes" } ], - type => $types{integer}, - category => "hidden", - }, - { - name => "ZM_UPLOAD_TIMEOUT", - default => "120", - description => "How long to allow the transfer to take for each file", - help => "You can use filters to instruct ZoneMinder to upload events to a remote server. This option indicates the maximum inactivity timeout (in seconds) that should be tolerated before ZoneMinder determines that the transfer has failed and closes down the connection.", - requires => [ { name => "ZM_OPT_UPLOAD", value => "yes" } ], - type => $types{integer}, - category => "upload", - }, - { - name => "ZM_UPLOAD_FTP_PASSIVE", - default => "yes", - description => "Use passive ftp when uploading", - help => "You can use filters to instruct ZoneMinder to upload events to a remote ftp server. This option indicates that ftp transfers should be done in passive mode. This uses a single connection for all ftp activity and, whilst slower than active transfers, is more robust and likely to work from behind filewalls. This option is ignored for SFTP transfers.", - requires => [ { name => "ZM_OPT_UPLOAD", value => "yes" } ], - help => "If your computer is behind a firewall or proxy you may need to set FTP to passive mode. In fact for simple transfers it makes little sense to do otherwise anyway but you can set this to 'No' if you wish.", - type => $types{boolean}, - category => "upload", - }, - { - name => "ZM_UPLOAD_FTP_DEBUG", - default => "no", - description => "Switch ftp debugging on", - help => "You can use filters to instruct ZoneMinder to upload events to a remote ftp server. If you are having (or expecting) troubles with uploading events then setting this to 'yes' permits additional information to be included in the zmfilter log file.", - requires => [ { name => "ZM_OPT_UPLOAD", value => "yes" } ], - type => $types{boolean}, - category => "hidden", - }, - { - name => "ZM_UPLOAD_DEBUG", - default => "no", - description => "Switch upload debugging on", - help => "You can use filters to instruct ZoneMinder to upload events to a remote server. If you are having (or expecting) troubles with uploading events then setting this to 'yes' permits additional information to be generated by the underlying transfer modules and included in the logs.", - requires => [ { name => "ZM_OPT_UPLOAD", value => "yes" } ], - type => $types{boolean}, - category => "upload", - }, - { - name => "ZM_OPT_EMAIL", - default => "no", - description => "Should ZoneMinder email you details of events that match corresponding filters", - help => "In ZoneMinder you can create event filters that specify whether events that match certain criteria should have their details emailed to you at a designated email address. This will allow you to be notified of events as soon as they occur and also to quickly view the events directly. This option specifies whether this functionality should be available. The email created with this option can be any size and is intended to be sent to a regular email reader rather than a mobile device.", - type => $types{boolean}, - category => "mail", - }, - { - name => "ZM_EMAIL_ADDRESS", - default => "", - description => "The email address to send matching event details to", - requires => [ { name => "ZM_OPT_EMAIL", value => "yes" } ], - help => "This option is used to define the email address that any events that match the appropriate filters will be sent to.", - type => $types{email}, - category => "mail", - }, - { - name => "ZM_EMAIL_TEXT", - default => 'subject = "ZoneMinder: Alarm - %MN%-%EI% (%ESM% - %ESA% %EFA%)" + name => "ZM_LANG_DEFAULT", + default => "en_gb", + description => "Default language used by web interface", + help => qqq(" + ZoneMinder allows the web interface to use languages other than + English if the appropriate language file has been created and + is present. This option allows you to change the default + language that is used from the shipped language, British + English, to another language + "), + type => $types{string}, + category => "system", + }, + { + name => "ZM_OPT_USE_AUTH", + default => "no", + description => "Authenticate user logins to ZoneMinder", + help => qqq(" + ZoneMinder can run in two modes. The simplest is an entirely + unauthenticated mode where anyone can access ZoneMinder and + perform all tasks. This is most suitable for installations + where the web server access is limited in other ways. The other + mode enables user accounts with varying sets of permissions. + Users must login or authenticate to access ZoneMinder and are + limited by their defined permissions. + "), + type => $types{boolean}, + category => "system", + }, + { + name => "ZM_AUTH_TYPE", + default => "builtin", + description => "What is used to authenticate ZoneMinder users", + help => qqq(" + ZoneMinder can use two methods to authenticate users when + running in authenticated mode. The first is a builtin method + where ZoneMinder provides facilities for users to log in and + maintains track of their identity. The second method allows + interworking with other methods such as http basic + authentication which passes an independently authentication + 'remote' user via http. In this case ZoneMinder would use the + supplied user without additional authentication provided such a + user is configured ion ZoneMinder. + "), + requires => [ { name=>"ZM_OPT_USE_AUTH", value=>"yes" } ], + type => { + db_type =>"string", + hint =>"builtin|remote", + pattern =>qr|^([br])|i, + format =>q( $1 =~ /^b/ ? "builtin" : "remote" ) + }, + category => "system", + }, + { + name => "ZM_AUTH_RELAY", + default => "hashed", + description => "Method used to relay authentication information", + help => qqq(" + When ZoneMinder is running in authenticated mode it can pass + user details between the web pages and the back end processes. + There are two methods for doing this. This first is to use a + time limited hashed string which contains no direct username or + password details, the second method is to pass the username and + passwords around in plaintext. This method is not recommend + except where you do not have the md5 libraries available on + your system or you have a completely isolated system with no + external access. You can also switch off authentication + relaying if your system is isolated in other ways. + "), + requires => [ { name=>"ZM_OPT_USE_AUTH", value=>"yes" } ], + type => { + db_type =>"string", + hint =>"hashed|plain|none", + pattern =>qr|^([hpn])|i, + format =>q( ($1 =~ /^h/) + ? "hashed" + : ($1 =~ /^p/ ? "plain" : "none" ) + ) + }, + category => "system", + }, + { + name => "ZM_AUTH_HASH_SECRET", + default => "...Change me to something unique...", + description => "Secret for encoding hashed authentication information", + help => qqq(" + When ZoneMinder is running in hashed authenticated mode it is + necessary to generate hashed strings containing encrypted + sensitive information such as usernames and password. Although + these string are reasonably secure the addition of a random + secret increases security substantially. + "), + requires => [ + { name=>"ZM_OPT_USE_AUTH", value=>"yes" }, + { name=>"ZM_AUTH_RELAY", value=>"hashed" } + ], + type => $types{string}, + category => "system", + }, + { + name => "ZM_AUTH_HASH_IPS", + default => "yes", + description => "Include IP addresses in the authentication hash", + help => qqq(" + When ZoneMinder is running in hashed authenticated mode it can + optionally include the requesting IP address in the resultant + hash. This adds an extra level of security as only requests + from that address may use that authentication key. However in + some circumstances, such as access over mobile networks, the + requesting address can change for each request which will cause + most requests to fail. This option allows you to control + whether IP addresses are included in the authentication hash on + your system. If you experience intermitent problems with + authentication, switching this option off may help. + "), + requires => [ + { name=>"ZM_OPT_USE_AUTH", value=>"yes" }, + { name=>"ZM_AUTH_RELAY", value=>"hashed" } + ], + type => $types{boolean}, + category => "system", + }, + { + name => "ZM_AUTH_HASH_LOGINS", + default => "no", + description => "Allow login by authentication hash", + help => qqq(" + The normal process for logging into ZoneMinder is via the login + screen with username and password. In some circumstances it may + be desirable to allow access directly to one or more pages, for + instance from a third party application. If this option is + enabled then adding an 'auth' parameter to any request will + include a shortcut login bypassing the login screen, if not + already logged in. As authentication hashes are time and, + optionally, IP limited this can allow short-term access to + ZoneMinder screens from other web pages etc. In order to use + this the calling application will hae to generate the + authentication hash itself and ensure it is valid. If you use + this option you should ensure that you have modified the + ZM_AUTH_HASH_SECRET to somethign unique to your system. + "), + requires => [ + { name=>"ZM_OPT_USE_AUTH", value=>"yes" }, + { name=>"ZM_AUTH_RELAY", value=>"hashed" } + ], + type => $types{boolean}, + category => "system", + }, + { + name => "ZM_DIR_EVENTS", + default => "events", + description => "Directory where events are stored", + help => qqq(" + This is the path to the events directory where all the event + images and other miscellaneous files are stored. CAUTION: The + directory you specify here cannot be outside the web root. This + is a common mistake. Most users should never change this value. + If you intend to record events to a second disk or network + share, then you should mount the drive or share directly to the + ZoneMinder events folder or follow the instructions in the + ZoneMinder Wiki titled Using a dedicated Hard Drive. + "), + type => $types{directory}, + category => "paths", + }, + { + name => "ZM_USE_DEEP_STORAGE", + default => "yes", + description => "Use a deep filesystem hierarchy for events", + help => qqq(" + This option is now the default for new ZoneMinder systems and + should not be changed. Previous versions of ZoneMinder stored + all events for a monitor under one folder. Enabling + USE_DEEP_STORAGE causes ZoneMinder to store events under a + folder structure that follows year/month/day/hour/min/second. + Storing events this way avoids the limitation of storing more + than 32k files in a single folder inherent in some filesystems. + It is important to note that you cannot simply change this + option. You must stop zoneminder, enable USE_DEEP_STORAGE, and + then run \"sudo zmupdate.pl --migrate-events\". FAILURE TO DO + SO WILL RESULT IN LOSS OF YOUR DATA! Consult the ZoneMinder + WiKi for further details. + "), + type => $types{boolean}, + category => "hidden", + }, + { + name => "ZM_DIR_IMAGES", + default => "images", + description => "Directory where the images that the ZoneMinder client generates are stored", + help => qqq(" + ZoneMinder generates a myriad of images, mostly of which are + associated with events. For those that aren't this is where + they go. CAUTION: The directory you specify here cannot be + outside the web root. This is a common mistake. Most users + should never change this value. If you intend to save images to + a second disk or network share, then you should mount the drive + or share directly to the ZoneMinder images folder or follow the + instructions in the ZoneMinder Wiki titled Using a dedicated + Hard Drive. + "), + type => $types{directory}, + category => "paths", + }, + { + name => "ZM_DIR_SOUNDS", + default => "sounds", + description => "Directory to the sounds that the ZoneMinder client can use", + help => qqq(" + ZoneMinder can optionally play a sound file when an alarm is + detected. This indicates where to look for this file. CAUTION: + The directory you specify here cannot be outside the web root. + Most users should never change this value. + "), + type => $types{directory}, + category => "paths", + }, + { + name => "ZM_PATH_ZMS", + default => "/cgi-bin/nph-zms", + description => "Web path to zms streaming server", + help => qqq(" + The ZoneMinder streaming server is required to send streamed + images to your browser. It will be installed into the cgi-bin + path given at configuration time. This option determines what + the web path to the server is rather than the local path on + your machine. Ordinarily the streaming server runs in + parser-header mode however if you experience problems with + streaming you can change this to non-parsed-header (nph) mode + by changing 'zms' to 'nph-zms'. + "), + type => $types{rel_path}, + category => "paths", + }, + { + name => "ZM_COLOUR_JPEG_FILES", + default => "no", + description => "Colourise greyscale JPEG files", + help => qqq(" + Cameras that capture in greyscale can write their captured + images to jpeg files with a corresponding greyscale colour + space. This saves a small amount of disk space over colour + ones. However some tools such as ffmpeg either fail to work + with this colour space or have to convert it beforehand. + Setting this option to yes uses up a little more space but + makes creation of MPEG files much faster. + "), + type => $types{boolean}, + category => "images", + }, + { + name => "ZM_ADD_JPEG_COMMENTS", + default => "no", + description => "Add jpeg timestamp annotations as file header comments", + help => qqq(" + JPEG files may have a number of extra fields added to the file + header. The comment field may have any kind of text added. This + options allows you to have the same text that is used to + annotate the image additionally included as a file header + comment. If you archive event images to other locations this + may help you locate images for particular events or times if + you use software that can read comment headers. + "), + type => $types{boolean}, + category => "images", + }, + { + name => "ZM_JPEG_FILE_QUALITY", + default => "70", + description => "Set the JPEG quality setting for the saved event files (1-100)", + help => qqq(" + When ZoneMinder detects an event it will save the images + associated with that event to files. These files are in the + JPEG format and can be viewed or streamed later. This option + specifies what image quality should be used to save these + files. A higher number means better quality but less + compression so will take up more disk space and take longer to + view over a slow connection. By contrast a low number means + smaller, quicker to view, files but at the price of lower + quality images. This setting applies to all images written + except if the capture image has caused an alarm and the alarm + file quality option is set at a higher value when that is used + instead. + "), + type => $types{integer}, + category => "images", + }, + { + name => "ZM_JPEG_ALARM_FILE_QUALITY", + default => "0", + description => "Set the JPEG quality setting for the saved event files during an alarm (1-100)", + help => qqq(" + This value is equivalent to the regular jpeg file quality + setting above except that it only applies to images saved while + in an alarm state and then only if this value is set to a + higher quality setting than the ordinary file setting. If set + to a lower value then it is ignored. Thus leaving it at the + default of 0 effectively means to use the regular file quality + setting for all saved images. This is to prevent acccidentally + saving important images at a worse quality setting. + "), + type => $types{integer}, + category => "images", + }, + # Deprecated, now stream quality + { + name => "ZM_JPEG_IMAGE_QUALITY", + default => "70", + description => "Set the JPEG quality setting for the streamed 'live' images (1-100)", + help => qqq(" + When viewing a 'live' stream for a monitor ZoneMinder will grab + an image from the buffer and encode it into JPEG format before + sending it. This option specifies what image quality should be + used to encode these images. A higher number means better + quality but less compression so will take longer to view over a + slow connection. By contrast a low number means quicker to view + images but at the price of lower quality images. This option + does not apply when viewing events or still images as these are + usually just read from disk and so will be encoded at the + quality specified by the previous options. + "), + type => $types{integer}, + category => "hidden", + }, + { + name => "ZM_JPEG_STREAM_QUALITY", + default => "70", + description => "Set the JPEG quality setting for the streamed 'live' images (1-100)", + help => qqq(" + When viewing a 'live' stream for a monitor ZoneMinder will grab + an image from the buffer and encode it into JPEG format before + sending it. This option specifies what image quality should be + used to encode these images. A higher number means better + quality but less compression so will take longer to view over a + slow connection. By contrast a low number means quicker to view + images but at the price of lower quality images. This option + does not apply when viewing events or still images as these are + usually just read from disk and so will be encoded at the + quality specified by the previous options. + "), + type => $types{integer}, + category => "images", + }, + { + name => "ZM_MPEG_TIMED_FRAMES", + default => "yes", + description => "Tag video frames with a timestamp for more realistic streaming", + help => qqq(" + When using streamed MPEG based video, either for live monitor + streams or events, ZoneMinder can send the streams in two ways. + If this option is selected then the timestamp for each frame, + taken from it's capture time, is included in the stream. This + means that where the frame rate varies, for instance around an + alarm, the stream will still maintain it's 'real' timing. If + this option is not selected then an approximate frame rate is + calculated and that is used to schedule frames instead. This + option should be selected unless you encounter problems with + your preferred streaming method. + "), + type => $types{boolean}, + category => "images", + }, + { + name => "ZM_MPEG_LIVE_FORMAT", + default => "swf", + description => "What format 'live' video streams are played in", + help => qqq(" + When using MPEG mode ZoneMinder can output live video. However + what formats are handled by the browser varies greatly between + machines. This option allows you to specify a video format + using a file extension format, so you would just enter the + extension of the file type you would like and the rest is + determined from that. The default of 'asf' works well under + Windows with Windows Media Player but I'm currently not sure + what, if anything, works on a Linux platform. If you find out + please let me know! If this option is left blank then live + streams will revert to being in motion jpeg format + "), + type => $types{string}, + category => "images", + }, + { + name => "ZM_MPEG_REPLAY_FORMAT", + default => "swf", + description => "What format 'replay' video streams are played in", + help => qqq(" + When using MPEG mode ZoneMinder can replay events in encoded + video format. However what formats are handled by the browser + varies greatly between machines. This option allows you to + specify a video format using a file extension format, so you + would just enter the extension of the file type you would like + and the rest is determined from that. The default of 'asf' + works well under Windows with Windows Media Player and 'mpg', + or 'avi' etc should work under Linux. If you know any more then + please let me know! If this option is left blank then live + streams will revert to being in motion jpeg format + "), + type => $types{string}, + category => "images", + }, + { + name => "ZM_RAND_STREAM", + default => "yes", + description => "Add a random string to prevent caching of streams", + help => qqq(" + Some browsers can cache the streams used by ZoneMinder. In + order to prevent his a harmless random string can be appended + to the url to make each invocation of the stream appear unique. + "), + type => $types{boolean}, + category => "images", + }, + { + name => "ZM_OPT_CAMBOZOLA", + default => "no", + description => "Is the (optional) cambozola java streaming client installed", + help => qqq(" + Cambozola is a handy low fat cheese flavoured Java applet that + ZoneMinder uses to view image streams on browsers such as + Internet Explorer that don't natively support this format. If + you use this browser it is highly recommended to install this + from http://www.charliemouse.com/code/cambozola/ however if it + is not installed still images at a lower refresh rate can still + be viewed. + "), + type => $types{boolean}, + category => "images", + }, + { + name => "ZM_PATH_CAMBOZOLA", + default => "cambozola.jar", + description => "Web path to (optional) cambozola java streaming client", + help => qqq(" + Cambozola is a handy low fat cheese flavoured Java applet that + ZoneMinder uses to view image streams on browsers such as + Internet Explorer that don't natively support this format. If + you use this browser it is highly recommended to install this + from http://www.charliemouse.com/code/cambozola/ however if it + is not installed still images at a lower refresh rate can still + be viewed. Leave this as 'cambozola.jar' if cambozola is + installed in the same directory as the ZoneMinder web client + files. + "), + requires => [ { name=>"ZM_OPT_CAMBOZOLA", value=>"yes" } ], + type => $types{rel_path}, + category => "images", + }, + { + name => "ZM_RELOAD_CAMBOZOLA", + default => "0", + description => "After how many seconds should Cambozola be reloaded in live view", + help => qqq(" + Cambozola allows for the viewing of streaming MJPEG however it + caches the entire stream into cache space on the computer, + setting this to a number > 0 will cause it to automatically + reload after that many seconds to avoid filling up a hard + drive. + "), + type => $types{integer}, + category => "images", + }, + { + name => "ZM_TIMESTAMP_ON_CAPTURE", + default => "yes", + description => "Timestamp images as soon as they are captured", + help => qqq(" + ZoneMinder can add a timestamp to images in two ways. The + default method, when this option is set, is that each image is + timestamped immediately when captured and so the image held in + memory is marked right away. The second method does not + timestamp the images until they are either saved as part of an + event or accessed over the web. The timestamp used in both + methods will contain the same time as this is preserved along + with the image. The first method ensures that an image is + timestamped regardless of any other circumstances but will + result in all images being timestamped even those never saved + or viewed. The second method necessitates that saved images are + copied before being saved otherwise two timestamps perhaps at + different scales may be applied. This has the (perhaps) + desirable side effect that the timestamp is always applied at + the same resolution so an image that has scaling applied will + still have a legible and correctly scaled timestamp. + "), + type => $types{boolean}, + category => "config", + }, + { + name => "ZM_CPU_EXTENSIONS", + default => "yes", + description => "Use advanced CPU extensions to increase performance", + help => qqq(" + When advanced processor extensions such as SSE2 or SSSE3 are + available, ZoneMinder can use them, which should increase + performance and reduce system load. Enabling this option on + processors that do not support the advanced processors + extensions used by ZoneMinder is harmless and will have no + effect. + "), + type => $types{boolean}, + category => "config", + }, + { + name => "ZM_FAST_IMAGE_BLENDS", + default => "yes", + description => "Use a fast algorithm to blend the reference image", + help => qqq(" + To detect alarms ZoneMinder needs to blend the captured image + with the stored reference image to update it for comparison + with the next image. The reference blend percentage specified + for the monitor controls how much the new image affects the + reference image. There are two methods that are available for + this. If this option is set then fast calculation which does + not use any multiplication or division is used. This + calculation is extremely fast, however it limits the possible + blend percentages to 50%, 25%, 12.5%, 6.25%, 3.25% and 1.5%. + Any other blend percentage will be rounded to the nearest + possible one. The alternative is to switch this option off + and use standard blending instead, which is slower. + "), + type => $types{boolean}, + category => "config", + }, + { + name => "ZM_OPT_ADAPTIVE_SKIP", + default => "yes", + description => "Should frame analysis try and be efficient in skipping frames", + help => qqq(" + In previous versions of ZoneMinder the analysis daemon would + attempt to keep up with the capture daemon by processing the + last captured frame on each pass. This would sometimes have the + undesirable side-effect of missing a chunk of the initial + activity that caused the alarm because the pre-alarm frames + would all have to be written to disk and the database before + processing the next frame, leading to some delay between the + first and second event frames. Setting this option enables a + newer adaptive algorithm where the analysis daemon attempts to + process as many captured frames as possible, only skipping + frames when in danger of the capture daemon overwriting yet to + be processed frames. This skip is variable depending on the + size of the ring buffer and the amount of space left in it. + Enabling this option will give you much better coverage of the + beginning of alarms whilst biasing out any skipped frames + towards the middle or end of the event. However you should be + aware that this will have the effect of making the analysis + daemon run somewhat behind the capture daemon during events and + for particularly fast rates of capture it is possible for the + adaptive algorithm to be overwhelmed and not have time to react + to a rapid build up of pending frames and thus for a buffer + overrun condition to occur. + "), + type => $types{boolean}, + category => "config", + }, + { + name => "ZM_MAX_SUSPEND_TIME", + default => "30", + description => "Maximum time that a monitor may have motion detection suspended", + help => qqq(" + ZoneMinder allows monitors to have motion detection to be + suspended, for instance while panning a camera. Ordinarily this + relies on the operator resuming motion detection afterwards as + failure to do so can leave a monitor in a permanently suspended + state. This setting allows you to set a maximum time which a + camera may be suspended for before it automatically resumes + motion detection. This time can be extended by subsequent + suspend indications after the first so continuous camera + movement will also occur while the monitor is suspended. + "), + type => $types{integer}, + category => "config", + }, + # Deprecated, really no longer necessary + { + name => "ZM_OPT_REMOTE_CAMERAS", + default => "no", + description => "Are you going to use remote/networked cameras", + help => qqq(" + ZoneMinder can work with both local cameras, ie. those attached + physically to your computer and remote or network cameras. If + you will be using networked cameras select this option. + "), + type => $types{boolean}, + category => "hidden", + }, + # Deprecated, now set on a per monitor basis using the Method field + { + name => "ZM_NETCAM_REGEXPS", + default => "yes", + description => "Use regular expression matching with network cameras", + help => qqq(" + Traditionally ZoneMinder has used complex regular regular + expressions to handle the multitude of formats that network + cameras produce. In versions from 1.21.1 the default is to use + a simpler and faster built in pattern matching methodology. + This works well with most networks cameras but if you have + problems you can try the older, but more flexible, regular + expression based method by selecting this option. Note, to use + this method you must have libpcre installed on your system. + "), + requires => [ { name => "ZM_OPT_REMOTE_CAMERAS", value => "yes" } ], + type => $types{boolean}, + category => "hidden", + }, + { + name => "ZM_HTTP_VERSION", + default => "1.0", + description => "The version of HTTP that ZoneMinder will use to connect", + help => qqq(" + ZoneMinder can communicate with network cameras using either of + the HTTP/1.1 or HTTP/1.0 standard. A server will normally fall + back to the version it supports with no problem so this should + usually by left at the default. However it can be changed to + HTTP/1.0 if necessary to resolve particular issues. + "), + type => { + db_type =>"string", + hint =>"1.1|1.0", + pattern =>qr|^(1\.[01])$|, + format =>q( $1?$1:"" ) + }, + category => "network", + }, + { + name => "ZM_HTTP_UA", + default => "ZoneMinder", + description => "The user agent that ZoneMinder uses to identify itself", + help => qqq(" + When ZoneMinder communicates with remote cameras it will + identify itself using this string and it's version number. This + is normally sufficient, however if a particular cameras expects + only to communicate with certain browsers then this can be + changed to a different string identifying ZoneMinder as + Internet Explorer or Netscape etc. + "), + type => $types{string}, + category => "network", + }, + { + name => "ZM_HTTP_TIMEOUT", + default => "2500", + description => "How long ZoneMinder waits before giving up on images (milliseconds)", + help => qqq(" + When retrieving remote images ZoneMinder will wait for this + length of time before deciding that an image is not going to + arrive and taking steps to retry. This timeout is in + milliseconds (1000 per second) and will apply to each part of + an image if it is not sent in one whole chunk. + "), + type => $types{integer}, + category => "network", + }, + { + name => "ZM_MIN_RTP_PORT", + default => "40200", + description => "Minimum port that ZoneMinder will listen for RTP traffic on", + help => qqq(" + When ZoneMinder communicates with MPEG4 capable cameras using + RTP with the unicast method it must open ports for the camera + to connect back to for control and streaming purposes. This + setting specifies the minimum port number that ZoneMinder will + use. Ordinarily two adjacent ports are used for each camera, + one for control packets and one for data packets. This port + should be set to an even number, you may also need to open up a + hole in your firewall to allow cameras to connect back if you + wish to use unicasting. + "), + type => $types{integer}, + category => "network", + }, + { + name => "ZM_MAX_RTP_PORT", + default => "40499", + description => "Maximum port that ZoneMinder will listen for RTP traffic on", + help => qqq(" + When ZoneMinder communicates with MPEG4 capable cameras using + RTP with the unicast method it must open ports for the camera + to connect back to for control and streaming purposes. This + setting specifies the maximum port number that ZoneMinder will + use. Ordinarily two adjacent ports are used for each camera, + one for control packets and one for data packets. This port + should be set to an even number, you may also need to open up a + hole in your firewall to allow cameras to connect back if you + wish to use unicasting. You should also ensure that you have + opened up at least two ports for each monitor that will be + connecting to unicasting network cameras. + "), + type => $types{integer}, + category => "network", + }, + { + name => "ZM_OPT_FFMPEG", + default => "@OPT_FFMPEG@", + description => "Is the ffmpeg video encoder/decoder installed", + help => qqq(" + ZoneMinder can optionally encode a series of video images into + an MPEG encoded movie file for viewing, downloading or storage. + This option allows you to specify whether you have the ffmpeg + tools installed. Note that creating MPEG files can be fairly + CPU and disk intensive and is not a required option as events + can still be reviewed as video streams without it. + "), + type => $types{boolean}, + category => "images", + }, + { + name => "ZM_PATH_FFMPEG", + default => "@PATH_FFMPEG@", + description => "Path to (optional) ffmpeg mpeg encoder", + help => "This path should point to where ffmpeg has been installed.", + requires => [ { name=>"ZM_OPT_FFMPEG", value=>"yes" } ], + type => $types{abs_path}, + category => "images", + }, + { + name => "ZM_FFMPEG_INPUT_OPTIONS", + default => "", + description => "Additional input options to ffmpeg", + help => qqq(" + Ffmpeg can take many options on the command line to control the + quality of video produced. This option allows you to specify + your own set that apply to the input to ffmpeg (options that + are given before the -i option). Check the ffmpeg documentation + for a full list of options which may be used here. + "), + requires => [ { name=>"ZM_OPT_FFMPEG", value=>"yes" } ], + type => $types{string}, + category => "images", + }, + { + name => "ZM_FFMPEG_OUTPUT_OPTIONS", + default => "-r 25", + description => "Additional output options to ffmpeg", + help => qqq(" + Ffmpeg can take many options on the command line to control the + quality of video produced. This option allows you to specify + your own set that apply to the output from ffmpeg (options that + are given after the -i option). Check the ffmpeg documentation + for a full list of options which may be used here. The most + common one will often be to force an output frame rate + supported by the video encoder. + "), + requires => [ { name=>"ZM_OPT_FFMPEG", value=>"yes" } ], + type => $types{string}, + category => "images", + }, + { + name => "ZM_FFMPEG_FORMATS", + default => "mpg mpeg wmv asf avi* mov swf 3gp**", + description => "Formats to allow for ffmpeg video generation", + help => qqq(" + Ffmpeg can generate video in many different formats. This + option allows you to list the ones you want to be able to + select. As new formats are supported by ffmpeg you can add them + here and be able to use them immediately. Adding a '*' after a + format indicates that this will be the default format used for + web video, adding '**' defines the default format for phone + video. + "), + requires => [ { name=>"ZM_OPT_FFMPEG", value=>"yes" } ], + type => $types{string}, + category => "images", + }, + { + name => "ZM_FFMPEG_OPEN_TIMEOUT", + default => "10", + description => "Timeout in seconds when opening a stream.", + help => qqq(" + When Ffmpeg is opening a stream, it can take a long time before + failing; certain circumstances even seem to be able to lock + indefinitely. This option allows you to set a maximum time in + seconds to pass before closing the stream and trying to reopen + it again. + "), + requires => [ { name=>"ZM_OPT_FFMPEG", value=>"yes" } ], + type => $types{integer}, + category => "images", + }, + { + name => "ZM_LOG_LEVEL_SYSLOG", + default => "0", + description => "Save logging output to the system log", + help => qqq(" + ZoneMinder logging is now more more integrated between + components and allows you to specify the destination for + logging output and the individual levels for each. This option + lets you control the level of logging output that goes to the + system log. ZoneMinder binaries have always logged to the + system log but now scripts and web logging is also included. To + preserve the previous behaviour you should ensure this value is + set to Info or Warning. This option controls the maximum level + of logging that will be written, so Info includes Warnings and + Errors etc. To disable entirely, set this option to None. You + should use caution when setting this option to Debug as it can + affect severely affect system performance. If you want debug + you will also need to set a level and component below + "), + type => { + db_type =>"integer", + hint =>"None=-5|Panic=-4|Fatal=-3|Error=-2|Warning=-1|Info=0|Debug=1", + pattern =>qr|^(\d+)$|, + format =>q( $1 ) + }, + category => "logging", + }, + { + name => "ZM_LOG_LEVEL_FILE", + default => "-5", + description => "Save logging output to component files", + help => qqq(" + ZoneMinder logging is now more more integrated between + components and allows you to specify the destination for + logging output and the individual levels for each. This option + lets you control the level of logging output that goes to + individual log files written by specific components. This is + how logging worked previously and although useful for tracking + down issues in specific components it also resulted in many + disparate log files. To preserve this behaviour you should + ensure this value is set to Info or Warning. This option + controls the maximum level of logging that will be written, so + Info includes Warnings and Errors etc. To disable entirely, set + this option to None. You should use caution when setting this + option to Debug as it can affect severely affect system + performance though file output has less impact than the other + options. If you want debug you will also need to set a level + and component below + "), + type => { + db_type =>"integer", + hint =>"None=-5|Panic=-4|Fatal=-3|Error=-2|Warning=-1|Info=0|Debug=1", + pattern =>qr|^(\d+)$|, + format =>q( $1 ) + }, + category => "logging", + }, + { + name => "ZM_LOG_LEVEL_WEBLOG", + default => "-5", + description => "Save logging output to the weblog", + help => qqq(" + ZoneMinder logging is now more more integrated between + components and allows you to specify the destination for + logging output and the individual levels for each. This option + lets you control the level of logging output from the web + interface that goes to the httpd error log. Note that only web + logging from PHP and JavaScript files is included and so this + option is really only useful for investigating specific issues + with those components. This option controls the maximum level + of logging that will be written, so Info includes Warnings and + Errors etc. To disable entirely, set this option to None. You + should use caution when setting this option to Debug as it can + affect severely affect system performance. If you want debug + you will also need to set a level and component below + "), + type => { + db_type =>"integer", + hint =>"None=-5|Panic=-4|Fatal=-3|Error=-2|Warning=-1|Info=0|Debug=1", + pattern =>qr|^(\d+)$|, + format =>q( $1 ) + }, + category => "logging", + }, + { + name => "ZM_LOG_LEVEL_DATABASE", + default => "0", + description => "Save logging output to the database", + help => qqq(" + ZoneMinder logging is now more more integrated between + components and allows you to specify the destination for + logging output and the individual levels for each. This option + lets you control the level of logging output that is written to + the database. This is a new option which can make viewing + logging output easier and more intuitive and also makes it + easier to get an overall impression of how the system is + performing. If you have a large or very busy system then it is + possible that use of this option may slow your system down if + the table becomes very large. Ensure you use the + LOG_DATABASE_LIMIT option to keep the table to a manageable + size. This option controls the maximum level of logging that + will be written, so Info includes Warnings and Errors etc. To + disable entirely, set this option to None. You should use + caution when setting this option to Debug as it can affect + severely affect system performance. If you want debug you will + also need to set a level and component below + "), + type => { + db_type =>"integer", + hint =>"None=-5|Panic=-4|Fatal=-3|Error=-2|Warning=-1|Info=0|Debug=1", + pattern =>qr|^(\d+)$|, + format =>q( $1 ) + }, + category => "logging", + }, + { + name => "ZM_LOG_DATABASE_LIMIT", + default => "7 day", + description => "Maximum number of log entries to retain", + help => qqq(" + If you are using database logging then it is possible to + quickly build up a large number of entries in the Logs table. + This option allows you to specify how many of these entries are + kept. If you set this option to a number greater than zero then + that number is used to determine the maximum number of rows, + less than or equal to zero indicates no limit and is not + recommended. You can also set this value to time values such as + ' day' which will limit the log entries to those newer than + that time. You can specify 'hour', 'day', 'week', 'month' and + 'year', note that the values should be singular (no 's' at the + end). The Logs table is pruned periodically so it is possible + for more than the expected number of rows to be present briefly + in the meantime. + "), + type => $types{string}, + category => "logging", + }, + { + name => "ZM_LOG_DEBUG", + default => "no", + description => "Switch debugging on", + help => qqq(" + ZoneMinder components usually support debug logging available + to help with diagnosing problems. Binary components have + several levels of debug whereas more other components have only + one. Normally this is disabled to minimise performance + penalties and avoid filling logs too quickly. This option lets + you switch on other options that allow you to configure + additional debug information to be output. Components will pick + up this instruction when they are restarted. + "), + type => $types{boolean}, + category => "logging", + }, + { + name => "ZM_LOG_DEBUG_TARGET", + default => "", + description => "What components should have extra debug enabled", + help => qqq(" + There are three scopes of debug available. Leaving this option + blank means that all components will use extra debug (not + recommended). Setting this option to '_', e.g. _zmc, + will limit extra debug to that component only. Setting this + option to '__', e.g. '_zmc_m1' will limit + extra debug to that instance of the component only. This is + ordinarily what you probably want to do. To debug scripts use + their names without the .pl extension, e.g. '_zmvideo' and to + debug issues with the web interface use '_web'. You can specify + multiple targets by separating them with '|' characters. + "), + requires => [ { name => "ZM_LOG_DEBUG", value => "yes" } ], + type => $types{string}, + category => "logging", + }, + { + name => "ZM_LOG_DEBUG_LEVEL", + default => 1, + description => "What level of extra debug should be enabled", + help => qqq(" + There are 9 levels of debug available, with higher numbers + being more debug and level 0 being no debug. However not all + levels are used by all components. Also if there is debug at a + high level it is usually likely to be output at such a volume + that it may obstruct normal operation. For this reason you + should set the level carefully and cautiously until the degree + of debug you wish to see is present. Scripts and the web + interface only have one level so this is an on/off type option + for them. + "), + requires => [ { name => "ZM_LOG_DEBUG", value => "yes" } ], + type => { + db_type =>"integer", + hint =>"1|2|3|4|5|6|7|8|9", + pattern =>qr|^(\d+)$|, + format =>q( $1 ) + }, + category => "logging", + }, + { + name => "ZM_LOG_DEBUG_FILE", + default => "@ZM_LOGDIR@/zm_debug.log+", + description => "Where extra debug is output to", + help => qqq(" + This option allows you to specify a different target for debug + output. All components have a default log file which will + norally be in /tmp or /var/log and this is where debug will be + written to if this value is empty. Adding a path here will + temporarily redirect debug, and other logging output, to this + file. This option is a simple filename and you are debugging + several components then they will all try and write to the same + file with undesirable consequences. Appending a '+' to the + filename will cause the file to be created with a '.' + suffix containing your process id. In this way debug from each + run of a component is kept separate. This is the recommended + setting as it will also prevent subsequent runs from + overwriting the same log. You should ensure that permissions + are set up to allow writing to the file and directory specified + here. + "), + requires => [ { name => "ZM_LOG_DEBUG", value => "yes" } ], + type => $types{string}, + category => "logging", + }, + { + name => "ZM_LOG_CHECK_PERIOD", + default => "900", + description => "Time period used when calculating overall system health", + help => qqq(" + When ZoneMinder is logging events to the database it can + retrospectively examine the number of warnings and errors that + have occurred to calculate an overall state of system health. + This option allows you to indicate what period of historical + events are used in this calculation. This value is expressed in + seconds and is ignored if LOG_LEVEL_DATABASE is set to None. + "), + type => $types{integer}, + category => "logging", + }, + { + name => "ZM_LOG_ALERT_WAR_COUNT", + default => "1", + description => "Number of warnings indicating system alert state", + help => qqq(" + When ZoneMinder is logging events to the database it can + retrospectively examine the number of warnings and errors that + have occurred to calculate an overall state of system health. + This option allows you to specify how many warnings must have + occurred within the defined time period to generate an overall + system alert state. A value of zero means warnings are not + considered. This value is ignored if LOG_LEVEL_DATABASE is set + to None. + "), + type => $types{integer}, + category => "logging", + }, + { + name => "ZM_LOG_ALERT_ERR_COUNT", + default => "1", + description => "Number of errors indicating system alert state", + help => qqq(" + When ZoneMinder is logging events to the database it can + retrospectively examine the number of warnings and errors that + have occurred to calculate an overall state of system health. + This option allows you to specify how many errors must have + occurred within the defined time period to generate an overall + system alert state. A value of zero means errors are not + considered. This value is ignored if LOG_LEVEL_DATABASE is set + to None. + "), + type => $types{integer}, + category => "logging", + }, + { + name => "ZM_LOG_ALERT_FAT_COUNT", + default => "0", + description => "Number of fatal error indicating system alert state", + help => qqq(" + When ZoneMinder is logging events to the database it can + retrospectively examine the number of warnings and errors that + have occurred to calculate an overall state of system health. + This option allows you to specify how many fatal errors + (including panics) must have occurred within the defined time + period to generate an overall system alert state. A value of + zero means fatal errors are not considered. This value is + ignored if LOG_LEVEL_DATABASE is set to None. + "), + type => $types{integer}, + category => "logging", + }, + { + name => "ZM_LOG_ALARM_WAR_COUNT", + default => "100", + description => "Number of warnings indicating system alarm state", + help => qqq(" + When ZoneMinder is logging events to the database it can + retrospectively examine the number of warnings and errors that + have occurred to calculate an overall state of system health. + This option allows you to specify how many warnings must have + occurred within the defined time period to generate an overall + system alarm state. A value of zero means warnings are not + considered. This value is ignored if LOG_LEVEL_DATABASE is set + to None. + "), + type => $types{integer}, + category => "logging", + }, + { + name => "ZM_LOG_ALARM_ERR_COUNT", + default => "10", + description => "Number of errors indicating system alarm state", + help => qqq(" + When ZoneMinder is logging events to the database it can + retrospectively examine the number of warnings and errors that + have occurred to calculate an overall state of system health. + This option allows you to specify how many errors must have + occurred within the defined time period to generate an overall + system alarm state. A value of zero means errors are not + considered. This value is ignored if LOG_LEVEL_DATABASE is set + to None. + "), + type => $types{integer}, + category => "logging", + }, + { + name => "ZM_LOG_ALARM_FAT_COUNT", + default => "1", + description => "Number of fatal error indicating system alarm state", + help => qqq(" + When ZoneMinder is logging events to the database it can + retrospectively examine the number of warnings and errors that + have occurred to calculate an overall state of system health. + This option allows you to specify how many fatal errors + (including panics) must have occurred within the defined time + period to generate an overall system alarm state. A value of + zero means fatal errors are not considered. This value is + ignored if LOG_LEVEL_DATABASE is set to None. + "), + type => $types{integer}, + category => "logging", + }, + { + name => "ZM_RECORD_EVENT_STATS", + default => "yes", + description => "Record event statistical information, switch off if too slow", + help => qqq(" + This version of ZoneMinder records detailed information about + events in the Stats table. This can help in profiling what the + optimum settings are for Zones though this is tricky at + present. However in future releases this will be done more + easily and intuitively, especially with a large sample of + events. The default option of 'yes' allows this information to + be collected now in readiness for this but if you are concerned + about performance you can switch this off in which case no + Stats information will be saved. + "), + type => $types{boolean}, + category => "logging", + }, + { + name => "ZM_RECORD_DIAG_IMAGES", + default => "no", + description => "Record intermediate alarm diagnostic images, can be very slow", + help => qqq(" + In addition to recording event statistics you can also record + the intermediate diagnostic images that display the results of + the various checks and processing that occur when trying to + determine if an alarm event has taken place. There are several + of these images generated for each frame and zone for each + alarm or alert frame so this can have a massive impact on + performance. Only switch this setting on for debug or analysis + purposes and remember to switch it off again once no longer + required. + "), + type => $types{boolean}, + category => "logging", + }, + { + name => "ZM_DUMP_CORES", + default => "no", + description => "Create core files on unexpected process failure.", + help => qqq(" + When an unrecoverable error occurs in a ZoneMinder binary + process is has traditionally been trapped and the details + written to logs to aid in remote analysis. However in some + cases it is easier to diagnose the error if a core file, which + is a memory dump of the process at the time of the error, is + created. This can be interactively analysed in the debugger and + may reveal more or better information than that available from + the logs. This option is recommended for advanced users only + otherwise leave at the default. Note using this option to + trigger core files will mean that there will be no indication + in the binary logs that a process has died, they will just + stop, however the zmdc log will still contain an entry. Also + note that you may have to explicitly enable core file creation + on your system via the 'ulimit -c' command or other means + otherwise no file will be created regardless of the value of + this option. + "), + type => $types{boolean}, + category => "logging", + }, + { + name => "ZM_PATH_MAP", + default => "/dev/shm", + description => "Path to the mapped memory files that that ZoneMinder can use", + help => qqq(" + ZoneMinder has historically used IPC shared memory for shared + data between processes. This has it's advantages and + limitations. This version of ZoneMinder can use an alternate + method, mapped memory, instead with can be enabled with the + --enable--mmap directive to configure. This requires less + system configuration and is generally more flexible. However it + requires each shared data segment to map onto a filesystem + file. This option indicates where those mapped files go. You + should ensure that this location has sufficient space for these + files and for the best performance it should be a tmpfs file + system or ramdisk otherwise disk access may render this method + slower than the regular shared memory one. + "), + type => $types{abs_path}, + category => "paths", + }, + { + name => "ZM_PATH_SOCKS", + default => "@ZM_SOCKDIR@", + description => "Path to the various Unix domain socket files that ZoneMinder uses", + help => qqq(" + ZoneMinder generally uses Unix domain sockets where possible. + This reduces the need for port assignments and prevents + external applications from possibly compromising the daemons. + However each Unix socket requires a .sock file to be created. + This option indicates where those socket files go. + "), + type => $types{abs_path}, + category => "paths", + }, + { + name => "ZM_PATH_LOGS", + default => "@ZM_LOGDIR@", + description => "Path to the various logs that the ZoneMinder daemons generate", + help => qqq(" + There are various daemons that are used by ZoneMinder to + perform various tasks. Most generate helpful log files and this + is where they go. They can be deleted if not required for + debugging. + "), + type => $types{abs_path}, + category => "paths", + }, + { + name => "ZM_PATH_SWAP", + default => "@ZM_TMPDIR@", + description => "Path to location for temporary swap images used in streaming", + help => qqq(" + Buffered playback requires temporary swap images to be stored + for each instance of the streaming daemons. This option + determines where these images will be stored. The images will + actually be stored in sub directories beneath this location and + will be automatically cleaned up after a period of time. + "), + type => $types{abs_path}, + category => "paths", + }, + { + name => "ZM_PATH_ARP", + default => "", + description => "Path to a supported ARP tool", + help => qqq(" + The camera probe function uses Address Resolution Protocol in + order to find known devices on the network. Optionally supply + the full path to \"ip neigh\", \"arp -a\", or any other tool on + your system that returns ip/mac address pairs. If this field is + left empty, ZoneMinder will search for the command \"arp\" and + attempt to use that. + "), + type => $types{abs_path}, + category => "paths", + }, + { + name => "ZM_WEB_TITLE_PREFIX", + default => "ZM", + description => "The title prefix displayed on each window", + help => qqq(" + If you have more than one installation of ZoneMinder it can be + helpful to display different titles for each one. Changing this + option allows you to customise the window titles to include + further information to aid identification. + "), + type => $types{string}, + category => "web", + }, + { + name => "ZM_WEB_RESIZE_CONSOLE", + default => "yes", + description => "Should the console window resize itself to fit", + help => qqq(" + Traditionally the main ZoneMinder web console window has + resized itself to shrink to a size small enough to list only + the monitors that are actually present. This is intended to + make the window more unobtrusize but may not be to everyones + tastes, especially if opened in a tab in browsers which support + this kind if layout. Switch this option off to have the console + window size left to the users preference + "), + type => $types{boolean}, + category => "web", + }, + { + name => "ZM_WEB_POPUP_ON_ALARM", + default => "yes", + description => "Should the monitor window jump to the top if an alarm occurs", + help => qqq(" + When viewing a live monitor stream you can specify whether you + want the window to pop to the front if an alarm occurs when the + window is minimised or behind another window. This is most + useful if your monitors are over doors for example when they + can pop up if someone comes to the doorway. + "), + type => $types{boolean}, + category => "web", + }, + { + name => "ZM_OPT_X10", + default => "no", + description => "Support interfacing with X10 devices", + help => qqq(" + If you have an X10 Home Automation setup in your home you can + use ZoneMinder to initiate or react to X10 signals if your + computer has the appropriate interface controller. This option + indicates whether X10 options will be available in the browser + client. + "), + type => $types{boolean}, + category => "x10", + }, + { + name => "ZM_X10_DEVICE", + default => "/dev/ttyS0", + description => "What device is your X10 controller connected on", + requires => [ { name => "ZM_OPT_X10", value => "yes" } ], + help => qqq(" + If you have an X10 controller device (e.g. XM10U) connected to + your computer this option details which port it is connected on, + the default of /dev/ttyS0 maps to serial or com port 1. + "), + type => $types{abs_path}, + category => "x10", + }, + { + name => "ZM_X10_HOUSE_CODE", + default => "A", + description => "What X10 house code should be used", + requires => [ { name => "ZM_OPT_X10", value => "yes" } ], + help => qqq(" + X10 devices are grouped together by identifying them as all + belonging to one House Code. This option details what that is. + It should be a single letter between A and P. + "), + type => { db_type=>"string", hint=>"A-P", pattern=>qr|^([A-P])|i, format=>q( uc($1) ) }, + category => "x10", + }, + { + name => "ZM_X10_DB_RELOAD_INTERVAL", + default => "60", + description => "How often (in seconds) the X10 daemon reloads the monitors from the database", + requires => [ { name => "ZM_OPT_X10", value => "yes" } ], + help => qqq(" + The zmx10 daemon periodically checks the database to find out + what X10 events trigger, or result from, alarms. This option + determines how frequently this check occurs, unless you change + this area frequently this can be a fairly large value. + "), + type => $types{integer}, + category => "x10", + }, + { + name => "ZM_WEB_SOUND_ON_ALARM", + default => "no", + description => "Should the monitor window play a sound if an alarm occurs", + help => qqq(" + When viewing a live monitor stream you can specify whether you + want the window to play a sound to alert you if an alarm + occurs. + "), + type => $types{boolean}, + category => "web", + }, + { + name => "ZM_WEB_ALARM_SOUND", + default => "", + description => "The sound to play on alarm, put this in the sounds directory", + help => qqq(" + You can specify a sound file to play if an alarm occurs whilst + you are watching a live monitor stream. So long as your browser + understands the format it does not need to be any particular + type. This file should be placed in the sounds directory + defined earlier. + "), + type => $types{file}, + requires => [ { name => "ZM_WEB_SOUND_ON_ALARM", value => "yes" } ], + category => "web", + }, + { + name => "ZM_WEB_COMPACT_MONTAGE", + default => "no", + description => "Compact the montage view by removing extra detail", + help => qqq(" + The montage view shows the output of all of your active + monitors in one window. This include a small menu and status + information for each one. This can increase the web traffic and + make the window larger than may be desired. Setting this option + on removes all this extraneous information and just displays + the images. + "), + type => $types{boolean}, + category => "web", + }, + { + name => "ZM_OPT_FAST_DELETE", + default => "yes", + description => "Delete only event database records for speed", + help => qqq(" + Normally an event created as the result of an alarm consists of + entries in one or more database tables plus the various files + associated with it. When deleting events in the browser it can + take a long time to remove all of this if your are trying to do + a lot of events at once. It is recommended that you set this + option which means that the browser client only deletes the key + entries in the events table, which means the events will no + longer appear in the listing, and leaves the zmaudit daemon to + clear up the rest later. + "), + type => $types{boolean}, + category => "system", + }, + { + name => "ZM_STRICT_VIDEO_CONFIG", + default => "yes", + description => "Allow errors in setting video config to be fatal", + help => qqq(" + With some video devices errors can be reported in setting the + various video attributes when in fact the operation was + successful. Switching this option off will still allow these + errors to be reported but will not cause them to kill the video + capture daemon. Note however that doing this will cause all + errors to be ignored including those which are genuine and + which may cause the video capture to not function correctly. + Use this option with caution. + "), + type => $types{boolean}, + category => "config", + }, + { + name => "ZM_SIGNAL_CHECK_POINTS", + default => "10", + description => "How many points in a captured image to check for signal loss", + help => qqq(" + For locally attached video cameras ZoneMinder can check for + signal loss by looking at a number of random points on each + captured image. If all of these points are set to the same + fixed colour then the camera is assumed to have lost signal. + When this happens any open events are closed and a short one + frame signal loss event is generated, as is another when the + signal returns. This option defines how many points on each + image to check. Note that this is a maximum, any points found + to not have the check colour will abort any further checks so + in most cases on a couple of points will actually be checked. + Network and file based cameras are never checked. + "), + type => $types{integer}, + category => "config", + }, + { + name => "ZM_V4L_MULTI_BUFFER", + default => "yes", + description => "Use more than one buffer for Video 4 Linux devices", + help => qqq(" + Performance when using Video 4 Linux devices is usually best if + multiple buffers are used allowing the next image to be + captured while the previous one is being processed. If you have + multiple devices on a card sharing one input that requires + switching then this approach can sometimes cause frames from + one source to be mixed up with frames from another. Switching + this option off prevents multi buffering resulting in slower + but more stable image capture. This option is ignored for + non-local cameras or if only one input is present on a capture + chip. This option addresses a similar problem to the + ZM_CAPTURES_PER_FRAME option and you should normally change the + value of only one of the options at a time. If you have + different capture cards that need different values you can + ovveride them in each individual monitor on the source page. + "), + type => $types{boolean}, + category => "config", + }, + { + name => "ZM_CAPTURES_PER_FRAME", + default => "1", + description => "How many images are captured per returned frame, for shared local cameras", + help => qqq(" + If you are using cameras attached to a video capture card which + forces multiple inputs to share one capture chip, it can + sometimes produce images with interlaced frames reversed + resulting in poor image quality and a distinctive comb edge + appearance. Increasing this setting allows you to force + additional image captures before one is selected as the + captured frame. This allows the capture hardware to 'settle + down' and produce better quality images at the price of lesser + capture rates. This option has no effect on (a) network + cameras, or (b) where multiple inputs do not share a capture + chip. This option addresses a similar problem to the + ZM_V4L_MULTI_BUFFER option and you should normally change the + value of only one of the options at a time. If you have + different capture cards that need different values you can + ovveride them in each individual monitor on the source page. + "), + type => $types{integer}, + category => "config", + }, + { + name => "ZM_FILTER_RELOAD_DELAY", + default => "300", + description => "How often (in seconds) filters are reloaded in zmfilter", + help => qqq(" + ZoneMinder allows you to save filters to the database which + allow events that match certain criteria to be emailed, deleted + or uploaded to a remote machine etc. The zmfilter daemon loads + these and does the actual operation. This option determines how + often the filters are reloaded from the database to get the + latest versions or new filters. If you don't change filters + very often this value can be set to a large value. + "), + type => $types{integer}, + category => "system", + }, + { + name => "ZM_FILTER_EXECUTE_INTERVAL", + default => "60", + description => "How often (in seconds) to run automatic saved filters", + help => qqq(" + ZoneMinder allows you to save filters to the database which + allow events that match certain criteria to be emailed, deleted + or uploaded to a remote machine etc. The zmfilter daemon loads + these and does the actual operation. This option determines how + often the filters are executed on the saved event in the + database. If you want a rapid response to new events this + should be a smaller value, however this may increase the + overall load on the system and affect performance of other + elements. + "), + type => $types{integer}, + category => "system", + }, + { + name => "ZM_OPT_UPLOAD", + default => "no", + description => "Should ZoneMinder support uploading events from filters", + help => qqq(" + In ZoneMinder you can create event filters that specify whether + events that match certain criteria should be uploaded to a + remote server for archiving. This option specifies whether this + functionality should be available + "), + type => $types{boolean}, + category => "upload", + }, + { + name => "ZM_UPLOAD_ARCH_FORMAT", + default => "tar", + description => "What format the uploaded events should be created in.", + requires => [ { name => "ZM_OPT_UPLOAD", value => "yes" } ], + help => qqq(" + Uploaded events may be stored in either .tar or .zip format, + this option specifies which. Note that to use this you will + need to have the Archive::Tar and/or Archive::Zip perl modules + installed. + "), + type => { + db_type =>"string", + hint =>"tar|zip", + pattern =>qr|^([tz])|i, + format =>q( $1 =~ /^t/ ? "tar" : "zip" ) + }, + category => "upload", + }, + { + name => "ZM_UPLOAD_ARCH_COMPRESS", + default => "no", + description => "Should archive files be compressed", + help => qqq(" + When the archive files are created they can be compressed. + However in general since the images are compressed already this + saves only a minimal amount of space versus utilising more CPU + in their creation. Only enable if you have CPU to waste and are + limited in disk space on your remote server or bandwidth. + "), + requires => [ { name => "ZM_OPT_UPLOAD", value => "yes" } ], + type => $types{boolean}, + category => "upload", + }, + { + name => "ZM_UPLOAD_ARCH_ANALYSE", + default => "no", + description => "Include the analysis files in the archive", + help => qqq(" + When the archive files are created they can contain either just + the captured frames or both the captured frames and, for frames + that caused an alarm, the analysed image with the changed area + highlighted. This option controls files are included. Only + include analysed frames if you have a high bandwidth connection + to the remote server or if you need help in figuring out what + caused an alarm in the first place as archives with these files + in can be considerably larger. + "), + requires => [ { name => "ZM_OPT_UPLOAD", value => "yes" } ], + type => $types{boolean}, + category => "upload", + }, + { + name => "ZM_UPLOAD_PROTOCOL", + default => "ftp", + description => "What protocol to use to upload events", + requires => [ { name => "ZM_OPT_UPLOAD", value => "yes" } ], + help => qqq(" + ZoneMinder can upload events to a remote server using either + FTP or SFTP. Regular FTP is widely supported but not + necessarily very secure whereas SFTP (Secure FTP) runs over an + ssh connection and so is encrypted and uses regular ssh ports. + Note that to use this you will need to have the appropriate + perl module, either Net::FTP or Net::SFTP installed depending + on your choice. + "), + type => { + db_type =>"string", + hint =>"ftp|sftp", + pattern =>qr|^([tz])|i, + format =>q( $1 =~ /^f/ ? "ftp" : "sftp" ) + }, + category => "upload", + }, + { + name => "ZM_UPLOAD_FTP_HOST", + default => "", + description => "The remote server to upload to", + help => qqq(" + You can use filters to instruct ZoneMinder to upload events to + a remote ftp server. This option indicates the name, or ip + address, of the server to use. + "), + requires => [ { name => "ZM_OPT_UPLOAD", value => "yes" } ], + type => $types{hostname}, + category => "hidden", + }, + { + name => "ZM_UPLOAD_HOST", + default => "", + description => "The remote server to upload events to", + help => qqq(" + You can use filters to instruct ZoneMinder to upload events to + a remote server. This option indicates the name, or ip address, + of the server to use. + "), + requires => [ { name => "ZM_OPT_UPLOAD", value => "yes" } ], + type => $types{hostname}, + category => "upload", + }, + { + name => "ZM_UPLOAD_PORT", + default => "", + description => "The port on the remote upload server, if not the default (SFTP only)", + help => qqq(" + You can use filters to instruct ZoneMinder to upload events to + a remote server. If you are using the SFTP protocol then this + option allows you to specify a particular port to use for + connection. If this option is left blank then the default, port + 22, is used. This option is ignored for FTP uploads. + "), + requires => [ { name => "ZM_OPT_UPLOAD", value => "yes" } ], + type => $types{integer}, + category => "upload", + }, + { + name => "ZM_UPLOAD_FTP_USER", + default => "", + description => "Your ftp username", + help => qqq(" + You can use filters to instruct ZoneMinder to upload events to + a remote ftp server. This option indicates the username that + ZoneMinder should use to log in for ftp transfer. + "), + requires => [ { name => "ZM_OPT_UPLOAD", value => "yes" } ], + type => $types{alphanum}, + category => "hidden", + }, + { + name => "ZM_UPLOAD_USER", + default => "", + description => "Remote server username", + help => qqq(" + You can use filters to instruct ZoneMinder to upload events to + a remote server. This option indicates the username that + ZoneMinder should use to log in for transfer. + "), + requires => [ { name => "ZM_OPT_UPLOAD", value => "yes" } ], + type => $types{alphanum}, + category => "upload", + }, + { + name => "ZM_UPLOAD_FTP_PASS", + default => "", + description => "Your ftp password", + help => qqq(" + You can use filters to instruct ZoneMinder to upload events to + a remote ftp server. This option indicates the password that + ZoneMinder should use to log in for ftp transfer. + "), + requires => [ { name => "ZM_OPT_UPLOAD", value => "yes" } ], + type => $types{string}, + category => "hidden", + }, + { + name => "ZM_UPLOAD_PASS", + default => "", + description => "Remote server password", + help => qqq(" + You can use filters to instruct ZoneMinder to upload events to + a remote server. This option indicates the password that + ZoneMinder should use to log in for transfer. If you are using + certicate based logins for SFTP servers you can leave this + option blank. + "), + requires => [ { name => "ZM_OPT_UPLOAD", value => "yes" } ], + type => $types{string}, + category => "upload", + }, + { + name => "ZM_UPLOAD_FTP_LOC_DIR", + default => "@ZM_TMPDIR@", + description => "The local directory in which to create upload files", + help => qqq(" + You can use filters to instruct ZoneMinder to upload events to + a remote ftp server. This option indicates the local directory + that ZoneMinder should use for temporary upload files. These + are files that are created from events, uploaded and then + deleted. + "), + requires => [ { name => "ZM_OPT_UPLOAD", value => "yes" } ], + type => $types{abs_path}, + category => "hidden", + }, + { + name => "ZM_UPLOAD_LOC_DIR", + default => "@ZM_TMPDIR@", + description => "The local directory in which to create upload files", + help => qqq(" + You can use filters to instruct ZoneMinder to upload events to + a remote server. This option indicates the local directory that + ZoneMinder should use for temporary upload files. These are + files that are created from events, uploaded and then deleted. + "), + requires => [ { name => "ZM_OPT_UPLOAD", value => "yes" } ], + type => $types{abs_path}, + category => "upload", + }, + { + name => "ZM_UPLOAD_FTP_REM_DIR", + default => "", + description => "The remote directory to upload to", + help => qqq(" + You can use filters to instruct ZoneMinder to upload events to + a remote ftp server. This option indicates the remote directory + that ZoneMinder should use to upload event files to. + "), + requires => [ { name => "ZM_OPT_UPLOAD", value => "yes" } ], + type => $types{rel_path}, + category => "hidden", + }, + { + name => "ZM_UPLOAD_REM_DIR", + default => "", + description => "The remote directory to upload to", + help => qqq(" + You can use filters to instruct ZoneMinder to upload events to + a remote server. This option indicates the remote directory + that ZoneMinder should use to upload event files to. + "), + requires => [ { name => "ZM_OPT_UPLOAD", value => "yes" } ], + type => $types{rel_path}, + category => "upload", + }, + { + name => "ZM_UPLOAD_FTP_TIMEOUT", + default => "120", + description => "How long to allow the transfer to take for each file", + help => qqq(" + You can use filters to instruct ZoneMinder to upload events to + a remote ftp server. This option indicates the maximum ftp + inactivity timeout (in seconds) that should be tolerated before + ZoneMinder determines that the transfer has failed and closes + down the connection. + "), + requires => [ { name => "ZM_OPT_UPLOAD", value => "yes" } ], + type => $types{integer}, + category => "hidden", + }, + { + name => "ZM_UPLOAD_TIMEOUT", + default => "120", + description => "How long to allow the transfer to take for each file", + help => qqq(" + You can use filters to instruct ZoneMinder to upload events to + a remote server. This option indicates the maximum inactivity + timeout (in seconds) that should be tolerated before ZoneMinder + determines that the transfer has failed and closes down the + connection. + "), + requires => [ { name => "ZM_OPT_UPLOAD", value => "yes" } ], + type => $types{integer}, + category => "upload", + }, + { + name => "ZM_UPLOAD_FTP_PASSIVE", + default => "yes", + description => "Use passive ftp when uploading", + help => qqq(" + You can use filters to instruct ZoneMinder to upload events to + a remote ftp server. This option indicates that ftp transfers + should be done in passive mode. This uses a single connection + for all ftp activity and, whilst slower than active transfers, + is more robust and likely to work from behind filewalls. This + option is ignored for SFTP transfers. + "), + requires => [ { name => "ZM_OPT_UPLOAD", value => "yes" } ], + help => qqq(" + If your computer is behind a firewall or proxy you may need to + set FTP to passive mode. In fact for simple transfers it makes + little sense to do otherwise anyway but you can set this to + 'No' if you wish. + "), + type => $types{boolean}, + category => "upload", + }, + { + name => "ZM_UPLOAD_FTP_DEBUG", + default => "no", + description => "Switch ftp debugging on", + help => qqq(" + You can use filters to instruct ZoneMinder to upload events to + a remote ftp server. If you are having (or expecting) troubles + with uploading events then setting this to 'yes' permits + additional information to be included in the zmfilter log file. + "), + requires => [ { name => "ZM_OPT_UPLOAD", value => "yes" } ], + type => $types{boolean}, + category => "hidden", + }, + { + name => "ZM_UPLOAD_DEBUG", + default => "no", + description => "Switch upload debugging on", + help => qqq(" + You can use filters to instruct ZoneMinder to upload events to + a remote server. If you are having (or expecting) troubles with + uploading events then setting this to 'yes' permits additional + information to be generated by the underlying transfer modules + and included in the logs. + "), + requires => [ { name => "ZM_OPT_UPLOAD", value => "yes" } ], + type => $types{boolean}, + category => "upload", + }, + { + name => "ZM_OPT_EMAIL", + default => "no", + description => "Should ZoneMinder email you details of events that match corresponding filters", + help => qqq(" + In ZoneMinder you can create event filters that specify whether + events that match certain criteria should have their details + emailed to you at a designated email address. This will allow + you to be notified of events as soon as they occur and also to + quickly view the events directly. This option specifies whether + this functionality should be available. The email created with + this option can be any size and is intended to be sent to a + regular email reader rather than a mobile device. + "), + type => $types{boolean}, + category => "mail", + }, + { + name => "ZM_EMAIL_ADDRESS", + default => "", + description => "The email address to send matching event details to", + requires => [ { name => "ZM_OPT_EMAIL", value => "yes" } ], + help => qqq(" + This option is used to define the email address that any events + that match the appropriate filters will be sent to. + "), + type => $types{email}, + category => "mail", + }, + { + name => "ZM_EMAIL_TEXT", + default => 'subject = "ZoneMinder: Alarm - %MN%-%EI% (%ESM% - %ESA% %EFA%)" body = " Hello, @@ -1035,24 +2105,30 @@ The details are as follows :- This alarm was matched by the %FN% filter and can be viewed at %EPS% ZoneMinder"', - description => "The text of the email used to send matching event details", - requires => [ { name => "ZM_OPT_EMAIL", value => "yes" } ], - help => "This option is used to define the content of the email that is sent for any events that match the appropriate filters.", - type => $types{text}, - category => "hidden", - }, - { - name => "ZM_EMAIL_SUBJECT", - default => "ZoneMinder: Alarm - %MN%-%EI% (%ESM% - %ESA% %EFA%)", - description => "The subject of the email used to send matching event details", - requires => [ { name => "ZM_OPT_EMAIL", value => "yes" } ], - help => "This option is used to define the subject of the email that is sent for any events that match the appropriate filters.", - type => $types{string}, - category => "mail", - }, - { - name => "ZM_EMAIL_BODY", - default => " + description => "The text of the email used to send matching event details", + requires => [ { name => "ZM_OPT_EMAIL", value => "yes" } ], + help => qqq(" + This option is used to define the content of the email that is + sent for any events that match the appropriate filters. + "), + type => $types{text}, + category => "hidden", + }, + { + name => "ZM_EMAIL_SUBJECT", + default => "ZoneMinder: Alarm - %MN%-%EI% (%ESM% - %ESA% %EFA%)", + description => "The subject of the email used to send matching event details", + requires => [ { name => "ZM_OPT_EMAIL", value => "yes" } ], + help => qqq(" + This option is used to define the subject of the email that is + sent for any events that match the appropriate filters. + "), + type => $types{string}, + category => "mail", + }, + { + name => "ZM_EMAIL_BODY", + default => " Hello, An alarm has been detected on your installation of the ZoneMinder. @@ -1068,896 +2144,1853 @@ The details are as follows :- This alarm was matched by the %FN% filter and can be viewed at %EPS% ZoneMinder", - description => "The body of the email used to send matching event details", - requires => [ { name => "ZM_OPT_EMAIL", value => "yes" } ], - help => "This option is used to define the content of the email that is sent for any events that match the appropriate filters.", - type => $types{text}, - category => "mail", - }, - { - name => "ZM_OPT_MESSAGE", - default => "no", - description => "Should ZoneMinder message you with details of events that match corresponding filters", - help => "In ZoneMinder you can create event filters that specify whether events that match certain criteria should have their details sent to you at a designated short message email address. This will allow you to be notified of events as soon as they occur. This option specifies whether this functionality should be available. The email created by this option will be brief and is intended to be sent to an SMS gateway or a minimal mail reader such as a mobile device or phone rather than a regular email reader.", - type => $types{boolean}, - category => "mail", - }, - { - name => "ZM_MESSAGE_ADDRESS", - default => "", - description => "The email address to send matching event details to", - requires => [ { name => "ZM_OPT_MESSAGE", value => "yes" } ], - help => "This option is used to define the short message email address that any events that match the appropriate filters will be sent to.", - type => $types{email}, - category => "mail", - }, - { - name => "ZM_MESSAGE_TEXT", - default => 'subject = "ZoneMinder: Alarm - %MN%-%EI%" + description => "The body of the email used to send matching event details", + requires => [ { name => "ZM_OPT_EMAIL", value => "yes" } ], + help => qqq(" + This option is used to define the content of the email that is + sent for any events that match the appropriate filters. + "), + type => $types{text}, + category => "mail", + }, + { + name => "ZM_OPT_MESSAGE", + default => "no", + description => "Should ZoneMinder message you with details of events that match corresponding filters", + help => qqq(" + In ZoneMinder you can create event filters that specify whether + events that match certain criteria should have their details + sent to you at a designated short message email address. This + will allow you to be notified of events as soon as they occur. + This option specifies whether this functionality should be + available. The email created by this option will be brief and + is intended to be sent to an SMS gateway or a minimal mail + reader such as a mobile device or phone rather than a regular + email reader. + "), + type => $types{boolean}, + category => "mail", + }, + { + name => "ZM_MESSAGE_ADDRESS", + default => "", + description => "The email address to send matching event details to", + requires => [ { name => "ZM_OPT_MESSAGE", value => "yes" } ], + help => qqq(" + This option is used to define the short message email address + that any events that match the appropriate filters will be sent + to. + "), + type => $types{email}, + category => "mail", + }, + { + name => "ZM_MESSAGE_TEXT", + default => 'subject = "ZoneMinder: Alarm - %MN%-%EI%" body = "ZM alarm detected - %EL% secs, %EF%/%EFA% frames, t%EST%/m%ESM%/a%ESA% score."', - description => "The text of the message used to send matching event details", - requires => [ { name => "ZM_OPT_MESSAGE", value => "yes" } ], - help => "This option is used to define the content of the message that is sent for any events that match the appropriate filters.", - type => $types{text}, - category => "hidden", - }, - { - name => "ZM_MESSAGE_SUBJECT", - default => "ZoneMinder: Alarm - %MN%-%EI%", - description => "The subject of the message used to send matching event details", - requires => [ { name => "ZM_OPT_MESSAGE", value => "yes" } ], - help => "This option is used to define the subject of the message that is sent for any events that match the appropriate filters.", - type => $types{string}, - category => "mail", - }, - { - name => "ZM_MESSAGE_BODY", - default => "ZM alarm detected - %EL% secs, %EF%/%EFA% frames, t%EST%/m%ESM%/a%ESA% score.", - description => "The body of the message used to send matching event details", - requires => [ { name => "ZM_OPT_MESSAGE", value => "yes" } ], - help => "This option is used to define the content of the message that is sent for any events that match the appropriate filters.", - type => $types{text}, - category => "mail", - }, - { - name => "ZM_NEW_MAIL_MODULES", - default => "no", - description => "Use a newer perl method to send emails", - requires => [ { name => "ZM_OPT_EMAIL", value => "yes" }, { name => "ZM_OPT_MESSAGE", value => "yes" } ], - help => "Traditionally ZoneMinder has used the MIME::Entity perl module to construct and send notification emails and messages. Some people have reported problems with this module not being present at all or flexible enough for their needs. If you are one of those people this option allows you to select a new mailing method using MIME::Lite and Net::SMTP instead. This method was contributed by Ross Melin and should work for everyone but has not been extensively tested so currently is not selected by default.", - type => $types{boolean}, - category => "mail", - }, - { - name => "ZM_EMAIL_HOST", - default => "localhost", - description => "The host address of your SMTP mail server", - requires => [ { name => "ZM_OPT_EMAIL", value => "yes" }, { name => "ZM_OPT_MESSAGE", value => "yes" } ], - help => "If you have chosen SMTP as the method by which to send notification emails or messages then this option allows you to choose which SMTP server to use to send them. The default of localhost may work if you have the sendmail, exim or a similar daemon running however you may wish to enter your ISP's SMTP mail server here.", - type => $types{hostname}, - category => "mail", - }, - { - name => "ZM_FROM_EMAIL", - default => "", - description => "The email address you wish your event notifications to originate from", - requires => [ { name => "ZM_OPT_EMAIL", value => "yes" }, { name => "ZM_OPT_MESSAGE", value => "yes" } ], - help => "The emails or messages that will be sent to you informing you of events can appear to come from a designated email address to help you with mail filtering etc. An address of something like ZoneMinder\@your.domain is recommended.", - type => $types{email}, - category => "mail", - }, - { - name => "ZM_URL", - default => "", - description => "The URL of your ZoneMinder installation", - requires => [ { name => "ZM_OPT_EMAIL", value => "yes" }, { name => "ZM_OPT_MESSAGE", value => "yes" } ], - help => "The emails or messages that will be sent to you informing you of events can include a link to the events themselves for easy viewing. If you intend to use this feature then set this option to the url of your installation as it would appear from where you read your email, e.g. http://host.your.domain/zm.php.", - type => $types{url}, - category => "mail", - }, - { - name => "ZM_MAX_RESTART_DELAY", - default => "600", - description => "Maximum delay (in seconds) for daemon restart attempts.", - help => "The zmdc (zm daemon control) process controls when processeses are started or stopped and will attempt to restart any that fail. If a daemon fails frequently then a delay is introduced between each restart attempt. If the daemon stills fails then this delay is increased to prevent extra load being placed on the system by continual restarts. This option controls what this maximum delay is.", - type => $types{integer}, - category => "system", - }, - { - name => "ZM_WATCH_CHECK_INTERVAL", - default => "10", - description => "How often to check the capture daemons have not locked up", - help => "The zmwatch daemon checks the image capture performance of the capture daemons to ensure that they have not locked up (rarely a sync error may occur which blocks indefinately). This option determines how often the daemons are checked.", - type => $types{integer}, - category => "system", - }, - { - name => "ZM_WATCH_MAX_DELAY", - default => "5", - description => "The maximum delay allowed since the last captured image", - help => "The zmwatch daemon checks the image capture performance of the capture daemons to ensure that they have not locked up (rarely a sync error may occur which blocks indefinately). This option determines the maximum delay to allow since the last captured frame. The daemon will be restarted if it has not captured any images after this period though the actual restart may take slightly longer in conjunction with the check interval value above.", - type => $types{decimal}, - category => "system", - }, - { + description => "The text of the message used to send matching event details", + requires => [ { name => "ZM_OPT_MESSAGE", value => "yes" } ], + help => qqq(" + This option is used to define the content of the message that + is sent for any events that match the appropriate filters. + "), + type => $types{text}, + category => "hidden", + }, + { + name => "ZM_MESSAGE_SUBJECT", + default => "ZoneMinder: Alarm - %MN%-%EI%", + description => "The subject of the message used to send matching event details", + requires => [ { name => "ZM_OPT_MESSAGE", value => "yes" } ], + help => qqq(" + This option is used to define the subject of the message that + is sent for any events that match the appropriate filters. + "), + type => $types{string}, + category => "mail", + }, + { + name => "ZM_MESSAGE_BODY", + default => "ZM alarm detected - %EL% secs, %EF%/%EFA% frames, t%EST%/m%ESM%/a%ESA% score.", + description => "The body of the message used to send matching event details", + requires => [ { name => "ZM_OPT_MESSAGE", value => "yes" } ], + help => qqq(" + This option is used to define the content of the message that + is sent for any events that match the appropriate filters. + "), + type => $types{text}, + category => "mail", + }, + { + name => "ZM_NEW_MAIL_MODULES", + default => "no", + description => "Use a newer perl method to send emails", + requires => [ + { name => "ZM_OPT_EMAIL", value => "yes" }, + { name => "ZM_OPT_MESSAGE", value => "yes" } + ], + help => qqq(" + Traditionally ZoneMinder has used the MIME::Entity perl module + to construct and send notification emails and messages. Some + people have reported problems with this module not being + present at all or flexible enough for their needs. If you are + one of those people this option allows you to select a new + mailing method using MIME::Lite and Net::SMTP instead. This + method was contributed by Ross Melin and should work for + everyone but has not been extensively tested so currently is + not selected by default. + "), + type => $types{boolean}, + category => "mail", + }, + { + name => "ZM_EMAIL_HOST", + default => "localhost", + description => "The host address of your SMTP mail server", + requires => [ + { name => "ZM_OPT_EMAIL", value => "yes" }, + { name => "ZM_OPT_MESSAGE", value => "yes" } + ], + help => qqq(" + If you have chosen SMTP as the method by which to send + notification emails or messages then this option allows you to + choose which SMTP server to use to send them. The default of + localhost may work if you have the sendmail, exim or a similar + daemon running however you may wish to enter your ISP's SMTP + mail server here. + "), + type => $types{hostname}, + category => "mail", + }, + { + name => "ZM_FROM_EMAIL", + default => "", + description => "The email address you wish your event notifications to originate from", + requires => [ + { name => "ZM_OPT_EMAIL", value => "yes" }, + { name => "ZM_OPT_MESSAGE", value => "yes" } + ], + help => qqq(" + The emails or messages that will be sent to you informing you + of events can appear to come from a designated email address to + help you with mail filtering etc. An address of something like + ZoneMinder\@your.domain is recommended. + "), + type => $types{email}, + category => "mail", + }, + { + name => "ZM_URL", + default => "", + description => "The URL of your ZoneMinder installation", + requires => [ + { name => "ZM_OPT_EMAIL", value => "yes" }, + { name => "ZM_OPT_MESSAGE", value => "yes" } + ], + help => qqq(" + The emails or messages that will be sent to you informing you + of events can include a link to the events themselves for easy + viewing. If you intend to use this feature then set this option + to the url of your installation as it would appear from where + you read your email, e.g. http://host.your.domain/zm.php. + "), + type => $types{url}, + category => "mail", + }, + { + name => "ZM_MAX_RESTART_DELAY", + default => "600", + description => "Maximum delay (in seconds) for daemon restart attempts.", + help => qqq(" + The zmdc (zm daemon control) process controls when processeses + are started or stopped and will attempt to restart any that + fail. If a daemon fails frequently then a delay is introduced + between each restart attempt. If the daemon stills fails then + this delay is increased to prevent extra load being placed on + the system by continual restarts. This option controls what + this maximum delay is. + "), + type => $types{integer}, + category => "system", + }, + { + name => "ZM_WATCH_CHECK_INTERVAL", + default => "10", + description => "How often to check the capture daemons have not locked up", + help => qqq(" + The zmwatch daemon checks the image capture performance of the + capture daemons to ensure that they have not locked up (rarely + a sync error may occur which blocks indefinitely). This option + determines how often the daemons are checked. + "), + type => $types{integer}, + category => "system", + }, + { + name => "ZM_WATCH_MAX_DELAY", + default => "5", + description => "The maximum delay allowed since the last captured image", + help => qqq(" + The zmwatch daemon checks the image capture performance of the + capture daemons to ensure that they have not locked up (rarely + a sync error may occur which blocks indefinitely). This option + determines the maximum delay to allow since the last captured + frame. The daemon will be restarted if it has not captured any + images after this period though the actual restart may take + slightly longer in conjunction with the check interval value + above. + "), + type => $types{decimal}, + category => "system", + }, + { - name => "ZM_RUN_AUDIT", - default => "yes", - description => "Run zmaudit to check data consistency", - help => "The zmaudit daemon exists to check that the saved information in the database and on the filesystem match and are consistent with each other. If an error occurs or if you are using 'fast deletes' it may be that database records are deleted but files remain. In this case, and similar, zmaudit will remove redundant information to synchronise the two data stores. This option controls whether zmaudit is run in the background and performs these checks and fixes continuously. This is recommended for most systems however if you have a very large number of events the process of scanning the database and filesystem may take a long time and impact performance. In this case you may prefer to not have zmaudit running unconditionally and schedule occasional checks at other, more convenient, times.", - type => $types{boolean}, - category => "system", - }, - { - - name => "ZM_AUDIT_CHECK_INTERVAL", - default => "900", - description => "How often to check database and filesystem consistency", - help => "The zmaudit daemon exists to check that the saved information in the database and on the filesystem match and are consistent with each other. If an error occurs or if you are using 'fast deletes' it may be that database records are deleted but files remain. In this case, and similar, zmaudit will remove redundant information to synchronise the two data stores. The default check interval of 900 seconds (15 minutes) is fine for most systems however if you have a very large number of events the process of scanning the database and filesystem may take a long time and impact performance. In this case you may prefer to make this interval much larger to reduce the impact on your system. This option determines how often these checks are performed.", - type => $types{integer}, - category => "system", - }, - { - name => "ZM_FORCED_ALARM_SCORE", - default => "255", - description => "Score to give forced alarms", - help => "The 'zmu' utility can be used to force an alarm on a monitor rather than rely on the motion detection algorithms. This option determines what score to give these alarms to distinguish them from regular ones. It must be 255 or less.", - type => $types{integer}, - category => "config", - }, - { - name => "ZM_BULK_FRAME_INTERVAL", - default => "100", - description => "How often a bulk frame should be written to the database", - help => "Traditionally ZoneMinder writes an entry into the Frames database table for each frame that is captured and saved. This works well in motion detection scenarios but when in a DVR situation ('Record' or 'Mocord' mode) this results in a huge number of frame writes and a lot of database and disk bandwidth for very little additional information. Setting this to a non-zero value will enabled ZoneMinder to group these non-alarm frames into one 'bulk' frame entry which saves a lot of bandwidth and space. The only disadvantage of this is that timing information for individual frames is lost but in constant frame rate situations this is usually not significant. This setting is ignored in Modect mode and individual frames are still written if an alarm occurs in Mocord mode also.", - type => $types{integer}, - category => "config", - }, - { - name => "ZM_EVENT_CLOSE_MODE", - default => "idle", - description => "When continuous events are closed.", - help => "When a monitor is running in a continuous recording mode (Record or Mocord) events are usually closed after a fixed period of time (the section length). However in Mocord mode it is possible that motion detection may occur near the end of a section. This option controls what happens when an alarm occurs in Mocord mode. The 'time' setting means that the event will be closed at the end of the section regardless of alarm activity. The 'idle' setting means that the event will be closed at the end of the section if there is no alarm activity occuring at the time otherwise it will be closed once the alarm is over meaning the event may end up being longer than the normal section length. The 'alarm' setting means that if an alarm occurs during the event, the event will be closed once the alarm is over regardless of when this occurs. This has the effect of limiting the number of alarms to one per event and the events will be shorter than the section length if an alarm has occurred.", - type => $types{boolean}, - type => { db_type=>"string", hint=>"time|idle|alarm", pattern=>qr|^([tia])|i, format=>q( ($1 =~ /^t/) ? "time" : ($1 =~ /^i/ ? "idle" : "time" ) ) }, - category => "config", - }, + name => "ZM_RUN_AUDIT", + default => "yes", + description => "Run zmaudit to check data consistency", + help => qqq(" + The zmaudit daemon exists to check that the saved information + in the database and on the filesystem match and are consistent + with each other. If an error occurs or if you are using 'fast + deletes' it may be that database records are deleted but files + remain. In this case, and similar, zmaudit will remove + redundant information to synchronise the two data stores. This + option controls whether zmaudit is run in the background and + performs these checks and fixes continuously. This is + recommended for most systems however if you have a very large + number of events the process of scanning the database and + filesystem may take a long time and impact performance. In this + case you may prefer to not have zmaudit running unconditionally + and schedule occasional checks at other, more convenient, + times. + "), + type => $types{boolean}, + category => "system", + }, + { + name => "ZM_AUDIT_CHECK_INTERVAL", + default => "900", + description => "How often to check database and filesystem consistency", + help => qqq(" + The zmaudit daemon exists to check that the saved information + in the database and on the filesystem match and are consistent + with each other. If an error occurs or if you are using 'fast + deletes' it may be that database records are deleted but files + remain. In this case, and similar, zmaudit will remove + redundant information to synchronise the two data stores. The + default check interval of 900 seconds (15 minutes) is fine for + most systems however if you have a very large number of events + the process of scanning the database and filesystem may take a + long time and impact performance. In this case you may prefer + to make this interval much larger to reduce the impact on your + system. This option determines how often these checks are + performed. + "), + type => $types{integer}, + category => "system", + }, + { + name => "ZM_AUDIT_MIN_AGE", + default => "86400", + description => "The minimum age in seconds event data must be in order to be deleted.", + help => qqq(" + The zmaudit daemon exists to check that the saved information + in the database and on the filesystem match and are consistent + with each other. Event files or db records that are younger than + this setting will not be deleted and a warning will be given. + "), + type => $types{integer}, + category => "system", + }, + { + name => "ZM_FORCED_ALARM_SCORE", + default => "255", + description => "Score to give forced alarms", + help => qqq(" + The 'zmu' utility can be used to force an alarm on a monitor + rather than rely on the motion detection algorithms. This + option determines what score to give these alarms to + distinguish them from regular ones. It must be 255 or less. + "), + type => $types{integer}, + category => "config", + }, + { + name => "ZM_BULK_FRAME_INTERVAL", + default => "100", + description => "How often a bulk frame should be written to the database", + help => qqq(" + Traditionally ZoneMinder writes an entry into the Frames + database table for each frame that is captured and saved. This + works well in motion detection scenarios but when in a DVR + situation ('Record' or 'Mocord' mode) this results in a huge + number of frame writes and a lot of database and disk bandwidth + for very little additional information. Setting this to a + non-zero value will enabled ZoneMinder to group these non-alarm + frames into one 'bulk' frame entry which saves a lot of + bandwidth and space. The only disadvantage of this is that + timing information for individual frames is lost but in + constant frame rate situations this is usually not significant. + This setting is ignored in Modect mode and individual frames + are still written if an alarm occurs in Mocord mode also. + "), + type => $types{integer}, + category => "config", + }, + { + name => "ZM_EVENT_CLOSE_MODE", + default => "idle", + description => "When continuous events are closed.", + help => qqq(" + When a monitor is running in a continuous recording mode + (Record or Mocord) events are usually closed after a fixed + period of time (the section length). However in Mocord mode it + is possible that motion detection may occur near the end of a + section. This option controls what happens when an alarm occurs + in Mocord mode. The 'time' setting means that the event will be + closed at the end of the section regardless of alarm activity. + The 'idle' setting means that the event will be closed at the + end of the section if there is no alarm activity occurring at + the time otherwise it will be closed once the alarm is over + meaning the event may end up being longer than the normal + section length. The 'alarm' setting means that if an alarm + occurs during the event, the event will be closed once the + alarm is over regardless of when this occurs. This has the + effect of limiting the number of alarms to one per event and + the events will be shorter than the section length if an alarm + has occurred. + "), + type => $types{boolean}, + type => { + db_type =>"string", + hint =>"time|idle|alarm", + pattern =>qr|^([tia])|i, + format =>q( ($1 =~ /^t/) + ? "time" + : ($1 =~ /^i/ ? "idle" : "time" ) + ) + }, + category => "config", + }, # Deprecated, superseded by event close mode - { - name => "ZM_FORCE_CLOSE_EVENTS", - default => "no", - description => "Close events at section ends.", - help => "When a monitor is running in a continuous recording mode (Record or Mocord) events are usually closed after a fixed period of time (the section length). However in Mocord mode it is possible that motion detection may occur near the end of a section and ordinarily this will prevent the event being closed until the motion has ceased. Switching this option on will force the event closed at the specified time regardless of any motion activity.", - type => $types{boolean}, - category => "hidden", - }, - { - name => "ZM_CREATE_ANALYSIS_IMAGES", - default => "yes", - description => "Create analysed alarm images with motion outlined", - help => "By default during an alarm ZoneMinder records both the raw captured image and one that has been analysed and had areas where motion was detected outlined. This can be very useful during zone configuration or in analysing why events occured. However it also incurs some overhead and in a stable system may no longer be necessary. This parameter allows you to switch the generation of these images off.", - type => $types{boolean}, - category => "config", - }, - { - name => "ZM_WEIGHTED_ALARM_CENTRES", - default => "no", - description => "Use a weighted algorithm to calculate the centre of an alarm", - help => "ZoneMinder will always calculate the centre point of an alarm in a zone to give some indication of where on the screen it is. This can be used by the experimental motion tracking feature or your own custom extensions. In the alarmed or filtered pixels mode this is a simple midpoint between the extents of the detected pxiesl. However in the blob method this can instead be calculated using weighted pixel locations to give more accurate positioning for irregularly shaped blobs. This method, while more precise is also slower and so is turned off by default.", - type => $types{boolean}, - category => "config", - }, - { - name => "ZM_EVENT_IMAGE_DIGITS", - default => "5", - description => "How many significant digits are used in event image numbering", - help => "As event images are captured they are stored to the filesystem with a numerical index. By default this index has three digits so the numbers start 001, 002 etc. This works works for most scenarios as events with more than 999 frames are rarely captured. However if you have extremely long events and use external applications then you may wish to increase this to ensure correct sorting of images in listings etc. Warning, increasing this value on a live system may render existing events unviewable as the event will have been saved with the previous scheme. Decreasing this value should have no ill effects.", - type => $types{integer}, - category => "config", - }, - { - name => "ZM_DEFAULT_ASPECT_RATIO", - default => "4:3", - description => "The default width:height aspect ratio used in monitors", - help => "When specifying the dimensions of monitors you can click a checkbox to ensure that the width stays in the correct ratio to the height, or vice versa. This setting allows you to indicate what the ratio of these settings should be. This should be specified in the format : and the default of 4:3 normally be acceptable but 11:9 is another common setting. If the checkbox is not clicked when specifying monitor dimensions this setting has no effect.", - type => $types{string}, - category => "config", - }, - { - name => "ZM_USER_SELF_EDIT", - default => "no", - description => "Allow unprivileged users to change their details", - help => "Ordinarily only users with system edit privilege are able to change users details. Switching this option on allows ordinary users to change their passwords and their language settings", - type => $types{boolean}, - category => "config", - }, - { - name => "ZM_OPT_FRAME_SERVER", - default => "no", - description => "Should analysis farm out the writing of images to disk", - #requires => [ { name => "ZM_OPT_ADAPTIVE_SKIP", value => "yes" } ], - help => "In some circumstances it is possible for a slow disk to take so long writing images to disk that it causes the analysis daemon to fall behind especially during high frame rate events. Setting this option to yes enables a frame server daemon (zmf) which will be sent the images from the analysis daemon and will do the actual writing of images itself freeing up the analysis daemon to get on with other things. Should this transmission fail or other permanent or transient error occur, this function will fall back to the analysis daemon.", - type => $types{boolean}, - category => "system", - }, - { - name => "ZM_FRAME_SOCKET_SIZE", - default => "0", - description => "Specify the frame server socket buffer size if non-standard", - requires => [ { name => "ZM_OPT_FRAME_SERVER", value => "yes" } ], - help => "For large captured images it is possible for the writes from the analysis daemon to the frame server to fail as the amount to be written exceeds the default buffer size. While the images are then written by the analysis daemon so no data is lost, it defeats the object of the frame server daemon in the first place. You can use this option to indicate that a larger buffer size should be used. Note that you may have to change the existing maximum socket buffer size on your system via sysctl (or in /proc/sys/net/core/wmem_max) to allow this new size to be set. Alternatively you can change the default buffer size on your system in the same way in which case that will be used with no change necessary in this option", - type => $types{integer}, - category => "system", - }, - { - name => "ZM_OPT_CONTROL", - default => "no", - description => "Support controllable (e.g. PTZ) cameras", - help => "ZoneMinder includes limited support for controllable cameras. A number of sample protocols are included and others can easily be added. If you wish to control your cameras via ZoneMinder then select this option otherwise if you only have static cameras or use other control methods then leave this option off.", - type => $types{boolean}, - category => "system", - }, - { - name => "ZM_OPT_TRIGGERS", - default => "no", - description => "Interface external event triggers via socket or device files", - help => "ZoneMinder can interact with external systems which prompt or cancel alarms. This is done via the zmtrigger.pl script. This option indicates whether you want to use these external triggers. Most people will say no here.", - type => $types{boolean}, - category => "system", - }, - { - name => "ZM_CHECK_FOR_UPDATES", - default => "yes", - description => "Check with zoneminder.com for updated versions", - help => "From ZoneMinder version 1.17.0 onwards new versions are expected to be more frequent. To save checking manually for each new version ZoneMinder can check with the zoneminder.com website to determine the most recent release. These checks are infrequent, about once per week, and no personal or system information is transmitted other than your current version number. If you do not wish these checks to take place or your ZoneMinder system has no internet access you can switch these check off with this configuration variable", - type => $types{boolean}, - category => "system", - }, - { - name => "ZM_UPDATE_CHECK_PROXY", - default => "", - description => "Proxy url if required to access zoneminder.com", - help => "If you use a proxy to access the internet then ZoneMinder needs to know so it can access zoneminder.com to check for updates. If you do use a proxy enter the full proxy url here in the form of http://:/", - type => $types{string}, - category => "system", - }, - { - name => "ZM_SHM_KEY", - default => "0x7a6d0000", - description => "Shared memory root key to use", - help => "ZoneMinder uses shared memory to speed up communication between modules. To identify the right area to use shared memory keys are used. This option controls what the base key is, each monitor will have it's Id or'ed with this to get the actual key used. You will not normally need to change this value unless it clashes with another instance of ZoneMinder on the same machine. Only the first four hex digits are used, the lower four will be masked out and ignored.", - type => $types{hexadecimal}, - category => "system", - }, + { + name => "ZM_FORCE_CLOSE_EVENTS", + default => "no", + description => "Close events at section ends.", + help => qqq(" + When a monitor is running in a continuous recording mode + (Record or Mocord) events are usually closed after a fixed + period of time (the section length). However in Mocord mode it + is possible that motion detection may occur near the end of a + section and ordinarily this will prevent the event being closed + until the motion has ceased. Switching this option on will + force the event closed at the specified time regardless of any + motion activity. + "), + type => $types{boolean}, + category => "hidden", + }, + { + name => "ZM_CREATE_ANALYSIS_IMAGES", + default => "yes", + description => "Create analysed alarm images with motion outlined", + help => qqq(" + By default during an alarm ZoneMinder records both the raw + captured image and one that has been analysed and had areas + where motion was detected outlined. This can be very useful + during zone configuration or in analysing why events occurred. + However it also incurs some overhead and in a stable system may + no longer be necessary. This parameter allows you to switch the + generation of these images off. + "), + type => $types{boolean}, + category => "config", + }, + { + name => "ZM_WEIGHTED_ALARM_CENTRES", + default => "no", + description => "Use a weighted algorithm to calculate the centre of an alarm", + help => qqq(" + ZoneMinder will always calculate the centre point of an alarm + in a zone to give some indication of where on the screen it is. + This can be used by the experimental motion tracking feature or + your own custom extensions. In the alarmed or filtered pixels + mode this is a simple midpoint between the extents of the + detected pxiesl. However in the blob method this can instead be + calculated using weighted pixel locations to give more accurate + positioning for irregularly shaped blobs. This method, while + more precise is also slower and so is turned off by default. + "), + type => $types{boolean}, + category => "config", + }, + { + name => "ZM_EVENT_IMAGE_DIGITS", + default => "5", + description => "How many significant digits are used in event image numbering", + help => qqq(" + As event images are captured they are stored to the filesystem + with a numerical index. By default this index has three digits + so the numbers start 001, 002 etc. This works works for most + scenarios as events with more than 999 frames are rarely + captured. However if you have extremely long events and use + external applications then you may wish to increase this to + ensure correct sorting of images in listings etc. Warning, + increasing this value on a live system may render existing + events unviewable as the event will have been saved with the + previous scheme. Decreasing this value should have no ill + effects. + "), + type => $types{integer}, + category => "config", + }, + { + name => "ZM_DEFAULT_ASPECT_RATIO", + default => "4:3", + description => "The default width:height aspect ratio used in monitors", + help => qqq(" + When specifying the dimensions of monitors you can click a + checkbox to ensure that the width stays in the correct ratio to + the height, or vice versa. This setting allows you to indicate + what the ratio of these settings should be. This should be + specified in the format : and the + default of 4:3 normally be acceptable but 11:9 is another + common setting. If the checkbox is not clicked when specifying + monitor dimensions this setting has no effect. + "), + type => $types{string}, + category => "config", + }, + { + name => "ZM_USER_SELF_EDIT", + default => "no", + description => "Allow unprivileged users to change their details", + help => qqq(" + Ordinarily only users with system edit privilege are able to + change users details. Switching this option on allows ordinary + users to change their passwords and their language settings + "), + type => $types{boolean}, + category => "config", + }, + { + name => "ZM_OPT_FRAME_SERVER", + default => "no", + description => "Should analysis farm out the writing of images to disk", + #requires => [ { name => "ZM_OPT_ADAPTIVE_SKIP", value => "yes" } ], + help => qqq(" + In some circumstances it is possible for a slow disk to take so + long writing images to disk that it causes the analysis daemon + to fall behind especially during high frame rate events. + Setting this option to yes enables a frame server daemon (zmf) + which will be sent the images from the analysis daemon and will + do the actual writing of images itself freeing up the analysis + daemon to get on with other things. Should this transmission + fail or other permanent or transient error occur, this function + will fall back to the analysis daemon. + "), + type => $types{boolean}, + category => "system", + }, + { + name => "ZM_FRAME_SOCKET_SIZE", + default => "0", + description => "Specify the frame server socket buffer size if non-standard", + requires => [ { name => "ZM_OPT_FRAME_SERVER", value => "yes" } ], + help => qqq(" + For large captured images it is possible for the writes from + the analysis daemon to the frame server to fail as the amount + to be written exceeds the default buffer size. While the images + are then written by the analysis daemon so no data is lost, it + defeats the object of the frame server daemon in the first + place. You can use this option to indicate that a larger buffer + size should be used. Note that you may have to change the + existing maximum socket buffer size on your system via sysctl + (or in /proc/sys/net/core/wmem_max) to allow this new size to + be set. Alternatively you can change the default buffer size on + your system in the same way in which case that will be used + with no change necessary in this option + "), + type => $types{integer}, + category => "system", + }, + { + name => "ZM_OPT_CONTROL", + default => "no", + description => "Support controllable (e.g. PTZ) cameras", + help => qqq(" + ZoneMinder includes limited support for controllable cameras. A + number of sample protocols are included and others can easily + be added. If you wish to control your cameras via ZoneMinder + then select this option otherwise if you only have static + cameras or use other control methods then leave this option + off. + "), + type => $types{boolean}, + category => "system", + }, + { + name => "ZM_OPT_TRIGGERS", + default => "no", + description => "Interface external event triggers via socket or device files", + help => qqq(" + ZoneMinder can interact with external systems which prompt or + cancel alarms. This is done via the zmtrigger.pl script. This + option indicates whether you want to use these external + triggers. Most people will say no here. + "), + type => $types{boolean}, + category => "system", + }, + { + name => "ZM_CHECK_FOR_UPDATES", + default => "yes", + description => "Check with zoneminder.com for updated versions", + help => qqq(" + From ZoneMinder version 1.17.0 onwards new versions are + expected to be more frequent. To save checking manually for + each new version ZoneMinder can check with the zoneminder.com + website to determine the most recent release. These checks are + infrequent, about once per week, and no personal or system + information is transmitted other than your current version + number. If you do not wish these checks to take place or your + ZoneMinder system has no internet access you can switch these + check off with this configuration variable + "), + type => $types{boolean}, + category => "system", + }, + { + name => "ZM_UPDATE_CHECK_PROXY", + default => "", + description => "Proxy url if required to access zoneminder.com", + help => qqq(" + If you use a proxy to access the internet then ZoneMinder needs + to know so it can access zoneminder.com to check for updates. + If you do use a proxy enter the full proxy url here in the form + of http://:/ + "), + type => $types{string}, + category => "system", + }, + { + name => "ZM_SHM_KEY", + default => "0x7a6d0000", + description => "Shared memory root key to use", + help => qqq(" + ZoneMinder uses shared memory to speed up communication between + modules. To identify the right area to use shared memory keys + are used. This option controls what the base key is, each + monitor will have it's Id or'ed with this to get the actual key + used. You will not normally need to change this value unless it + clashes with another instance of ZoneMinder on the same + machine. Only the first four hex digits are used, the lower + four will be masked out and ignored. + "), + type => $types{hexadecimal}, + category => "system", + }, # Deprecated, really no longer necessary - { - name => "ZM_WEB_REFRESH_METHOD", - default => "javascript", - description => "What method windows should use to refresh themselves", - help => "Many windows in Javascript need to refresh themselves to keep their information current. This option determines what method they should use to do this. Choosing 'javascript' means that each window will have a short JavaScript statement in with a timer to prompt the refresh. This is the most compatible method. Choosing 'http' means the refresh instruction is put in the HTTP header. This is a cleaner method but refreshes are interrupted or cancelled when a link in the window is clicked meaning that the window will no longer refresh and this would have to be done manually.", - type => { db_type=>"string", hint=>"javascript|http", pattern=>qr|^([jh])|i, format=>q( $1 =~ /^j/ ? "javascript" : "http" ) }, - category => "hidden", - }, - { - name => "ZM_WEB_EVENT_SORT_FIELD", - default => "DateTime", - description => "Default field the event lists are sorted by", - help => "Events in lists can be initially ordered in any way you want. This option controls what field is used to sort them. You can modify this ordering from filters or by clicking on headings in the lists themselves. Bear in mind however that the 'Prev' and 'Next' links, when scrolling through events, relate to the ordering in the lists and so not always to time based ordering.", - type => { db_type=>"string", hint=>"Id|Name|Cause|MonitorName|DateTime|Length|Frames|AlarmFrames|TotScore|AvgScore|MaxScore", pattern=>qr|.|, format=>q( $1 ) }, - category => "web", - }, - { - name => "ZM_WEB_EVENT_SORT_ORDER", - default => "asc", - description => "Default order the event lists are sorted by", - help => "Events in lists can be initially ordered in any way you want. This option controls what order (ascending or descending) is used to sort them. You can modify this ordering from filters or by clicking on headings in the lists themselves. Bear in mind however that the 'Prev' and 'Next' links, when scrolling through events, relate to the ordering in the lists and so not always to time based ordering.", - type => { db_type=>"string", hint=>"asc|desc", pattern=>qr|^([ad])|i, format=>q( $1 =~ /^a/i ? "asc" : "desc" ) }, - category => "web", - }, - { - name => "ZM_WEB_EVENTS_PER_PAGE", - default => "25", - description => "How many events to list per page in paged mode", - help => "In the event list view you can either list all events or just a page at a time. This option controls how many events are listed per page in paged mode and how often to repeat the column headers in non-paged mode.", - type => $types{integer}, - category => "web", - }, - { - name => "ZM_WEB_LIST_THUMBS", - default => "no", - description => "Display mini-thumbnails of event images in event lists", - help => "Ordinarily the event lists just display text details of the events to save space and time. By switching this option on you can also display small thumbnails to help you identify events of interest. The size of these thumbnails is controlled by the following two options.", - type => $types{boolean}, - category => "web", - }, - { - name => "ZM_WEB_LIST_THUMB_WIDTH", - default => "48", - description => "The width of the thumbnails that appear in the event lists", - help => "This options controls the width of the thumbnail images that appear in the event lists. It should be fairly small to fit in with the rest of the table. If you prefer you can specify a height instead in the next option but you should only use one of the width or height and the other option should be set to zero. If both width and height are specified then width will be used and height ignored.", - type => $types{integer}, - requires => [ { name => "ZM_WEB_LIST_THUMBS", value => "yes" } ], - category => "web", - }, - { - name => "ZM_WEB_LIST_THUMB_HEIGHT", - default => "0", - description => "The height of the thumbnails that appear in the event lists", - help => "This options controls the height of the thumbnail images that appear in the event lists. It should be fairly small to fit in with the rest of the table. If you prefer you can specify a width instead in the previous option but you should only use one of the width or height and the other option should be set to zero. If both width and height are specified then width will be used and height ignored.", - type => $types{integer}, - requires => [ { name => "ZM_WEB_LIST_THUMBS", value => "yes" } ], - category => "web", - }, - { - name => "ZM_WEB_USE_OBJECT_TAGS", - default => "yes", - description => "Wrap embed in object tags for media content", - help => "There are two methods of including media content in web pages. The most common way is use the EMBED tag which is able to give some indication of the type of content. However this is not a standard part of HTML. The official method is to use OBJECT tags which are able to give more information allowing the correct media viewers etc to be loaded. However these are less widely supported and content may be specifically tailored to a particular platform or player. This option controls whether media content is enclosed in EMBED tags only or whether, where appropriate, it is additionally wrapped in OBJECT tags. Currently OBJECT tags are only used in a limited number of circumstances but they may become more widespread in the future. It is suggested that you leave this option on unless you encounter problems playing some content.", - type => $types{boolean}, - category => "web", - }, - { - name => "ZM_WEB_H_REFRESH_MAIN", - default => "60", - introduction => "There are now a number of options that are grouped into bandwidth categories, this allows you to configure the ZoneMinder client to work optimally over the various access methods you might to access the client.\n\nThe next few options control what happens when the client is running in 'high' bandwidth mode. You should set these options for when accessing the ZoneMinder client over a local network or high speed link. In most cases the default values will be suitable as a starting point.", - description => "How often (in seconds) the main console window should refresh itself", - help => "The main console window lists a general status and the event totals for all monitors. This is not a trivial task and should not be repeated too frequently or it may affect the performance of the rest of the system.", - type => $types{integer}, - category => "highband", - }, - { - name => "ZM_WEB_H_REFRESH_CYCLE", - default => "10", - description => "How often (in seconds) the cycle watch window swaps to the next monitor", - help => "The cycle watch window is a method of continuously cycling between images from all of your monitors. This option determines how often to refresh with a new image.", - type => $types{integer}, - category => "highband", - }, - { - name => "ZM_WEB_H_REFRESH_IMAGE", - default => "3", - description => "How often (in seconds) the watched image is refreshed (if not streaming)", - help => "The live images from a monitor can be viewed in either streamed or stills mode. This option determines how often a stills image is refreshed, it has no effect if streaming is selected.", - type => $types{integer}, - category => "highband", - }, - { - name => "ZM_WEB_H_REFRESH_STATUS", - default => "1", - description => "How often (in seconds) the status refreshes itself in the watch window", - help => "The monitor window is actually made from several frames. The one in the middle merely contains a monitor status which needs to refresh fairly frequently to give a true indication. This option determines that frequency.", - type => $types{integer}, - category => "highband", - }, - { - name => "ZM_WEB_H_REFRESH_EVENTS", - default => "5", - description => "How often (in seconds) the event listing is refreshed in the watch window", - help => "The monitor window is actually made from several frames. The lower framme contains a listing of the last few events for easy access. This option determines how often this is refreshed.", - type => $types{integer}, - category => "highband", - }, - { - name => "ZM_WEB_H_CAN_STREAM", - default => "auto", - description => "Override the automatic detection of browser streaming capability", - help => "If you know that your browser can handle image streams of the type 'multipart/x-mixed-replace' but ZoneMinder does not detect this correctly you can set this option to ensure that the stream is delivered with or without the use of the Cambozola plugin. Selecting 'yes' will tell ZoneMinder that your browser can handle the streams natively, 'no' means that it can't and so the plugin will be used while 'auto' lets ZoneMinder decide.", - type => $types{tristate}, - category => "highband", - }, - { - name => "ZM_WEB_H_STREAM_METHOD", - default => "jpeg", - description => "Which method should be used to send video streams to your browser.", - help => "ZoneMinder can be configured to use either mpeg encoded video or a series or still jpeg images when sending video streams. This option defines which is used. If you choose mpeg you should ensure that you have the appropriate plugins available on your browser whereas choosing jpeg will work natively on Mozilla and related browsers and with a Java applet on Internet Explorer", - type => { db_type=>"string", hint=>"mpeg|jpeg", pattern=>qr|^([mj])|i, format=>q( $1 =~ /^m/ ? "mpeg" : "jpeg" ) }, - category => "highband", - }, - { - name => "ZM_WEB_H_DEFAULT_SCALE", - default => "100", - description => "What the default scaling factor applied to 'live' or 'event' views is (%)", - help => "Normally ZoneMinder will display 'live' or 'event' streams in their native size. However if you have monitors with large dimensions or a slow link you may prefer to reduce this size, alternatively for small monitors you can enlarge it. This options lets you specify what the default scaling factor will be. It is expressed as a percentage so 100 is normal size, 200 is double size etc.", - type => { db_type=>"integer", hint=>"25|33|50|75|100|150|200|300|400", pattern=>qr|^(\d+)$|, format=>q( $1 ) }, - category => "highband", - }, - { - name => "ZM_WEB_H_DEFAULT_RATE", - default => "100", - description => "What the default replay rate factor applied to 'event' views is (%)", - help => "Normally ZoneMinder will display 'event' streams at their native rate, i.e. as close to real-time as possible. However if you have long events it is often convenient to replay them at a faster rate for review. This option lets you specify what the default replay rate will be. It is expressed as a percentage so 100 is normal rate, 200 is double speed etc.", - type => { db_type=>"integer", hint=>"25|50|100|150|200|400|1000|2500|5000|10000", pattern=>qr|^(\d+)$|, format=>q( $1 ) }, - category => "highband", - }, - { - name => "ZM_WEB_H_VIDEO_BITRATE", - default => "150000", - description => "What the bitrate of the video encoded stream should be set to", - help => "When encoding real video via the ffmpeg library a bit rate can be specified which roughly corresponds to the available bandwidth used for the stream. This setting effectively corresponds to a 'quality' setting for the video. A low value will result in a blocky image whereas a high value will produce a clearer view. Note that this setting does not control the frame rate of the video however the quality of the video produced is affected both by this setting and the frame rate that the video is produced at. A higher frame rate at a particular bit rate result in individual frames being at a lower quality.", - type => $types{integer}, - category => "highband", - }, - { - name => "ZM_WEB_H_VIDEO_MAXFPS", - default => "30", - description => "What the maximum frame rate for streamed video should be", - help => "When using streamed video the main control is the bitrate which determines how much data can be transmitted. However a lower bitrate at high frame rates results in a lower quality image. This option allows you to limit the maximum frame rate to ensure that video quality is maintained. An additional advantage is that encoding video at high frame rates is a processor intensive task when for the most part a very high frame rate offers little perceptible improvement over one that has a more manageable resource requirement. Note, this option is implemented as a cap beyond which binary reduction takes place. So if you have a device capturing at 15fps and set this option to 10fps then the video is not produced at 10fps, but rather at 7.5fps (15 divided by 2) as the final frame rate must be the original divided by a power of 2.", - type => $types{integer}, - category => "highband", - }, - { - name => "ZM_WEB_H_SCALE_THUMBS", - default => "no", - description => "Scale thumbnails in events, bandwidth versus cpu in rescaling", - help => "If unset, this option sends the whole image to the browser which resizes it in the window. If set the image is scaled down on the server before sending a reduced size image to the browser to conserve bandwidth at the cost of cpu on the server. Note that ZM can only perform the resizing if the appropriate PHP graphics functionality is installed. This is usually available in the php-gd package.", - type => $types{boolean}, - category => "highband", - }, - { - name => "ZM_WEB_H_EVENTS_VIEW", - default => "events", - description => "What the default view of multiple events should be.", - help => "Stored events can be viewed in either an events list format or in a timeline based one. This option sets the default view that will be used. Choosing one view here does not prevent the other view being used as it will always be selectable from whichever view is currently being used.", - type => { db_type=>"string", hint=>"events|timeline", pattern=>qr|^([lt])|i, format=>q( $1 =~ /^e/ ? "events" : "timeline" ) }, - category => "highband", - }, - { - name => "ZM_WEB_H_SHOW_PROGRESS", - default => "yes", - description => "Show the progress of replay in event view.", - help => "When viewing events an event navigation panel and progress bar is shown below the event itself. This allows you to jump to specific points in the event, but can can also dynamically update to display the current progress of the event replay itself. This progress is calculated from the actual event duration and is not directly linked to the replay itself, so on limited bandwidth connections may be out of step with the replay. This option allows you to turn off the progress display, whilst still keeping the navigation aspect, where bandwidth prevents it functioning effectively.", - type => $types{boolean}, - category => "highband", - }, - { - name => "ZM_WEB_H_AJAX_TIMEOUT", - default => "3000", - description => "How long to wait for Ajax request responses (ms)", - help => "The newer versions of the live feed and event views use Ajax to request information from the server and populate the views dynamically. This option allows you to specify a timeout if required after which requests are abandoned. A timeout may be necessary if requests would overwise hang such as on a slow connection. This would tend to consume a lot of browser memory and make the interface unresponsive. Ordinarily no requests should timeout so this setting should be set to a value greater than the slowest expected response. This value is in milliseconds but if set to zero then no timeout will be used.", - type => $types{integer}, - category => "highband", - }, - { - name => "ZM_WEB_M_REFRESH_MAIN", - default => "300", - description => "How often (in seconds) the main console window should refresh itself", - help => "The main console window lists a general status and the event totals for all monitors. This is not a trivial task and should not be repeated too frequently or it may affect the performance of the rest of the system.", - type => $types{integer}, - introduction => "The next few options control what happens when the client is running in 'medium' bandwidth mode. You should set these options for when accessing the ZoneMinder client over a slower cable or DSL link. In most cases the default values will be suitable as a starting point.", - category => "medband", - }, - { - name => "ZM_WEB_M_REFRESH_CYCLE", - default => "20", - description => "How often (in seconds) the cycle watch window swaps to the next monitor", - help => "The cycle watch window is a method of continuously cycling between images from all of your monitors. This option determines how often to refresh with a new image.", - type => $types{integer}, - category => "medband", - }, - { - name => "ZM_WEB_M_REFRESH_IMAGE", - default => "10", - description => "How often (in seconds) the watched image is refreshed (if not streaming)", - help => "The live images from a monitor can be viewed in either streamed or stills mode. This option determines how often a stills image is refreshed, it has no effect if streaming is selected.", - type => $types{integer}, - category => "medband", - }, - { - name => "ZM_WEB_M_REFRESH_STATUS", - default => "5", - description => "How often (in seconds) the status refreshes itself in the watch window", - help => "The monitor window is actually made from several frames. The one in the middle merely contains a monitor status which needs to refresh fairly frequently to give a true indication. This option determines that frequency.", - type => $types{integer}, - category => "medband", - }, - { - name => "ZM_WEB_M_REFRESH_EVENTS", - default => "60", - description => "How often (in seconds) the event listing is refreshed in the watch window", - help => "The monitor window is actually made from several frames. The lower framme contains a listing of the last few events for easy access. This option determines how often this is refreshed.", - type => $types{integer}, - category => "medband", - }, - { - name => "ZM_WEB_M_CAN_STREAM", - default => "auto", - description => "Override the automatic detection of browser streaming capability", - help => "If you know that your browser can handle image streams of the type 'multipart/x-mixed-replace' but ZoneMinder does not detect this correctly you can set this option to ensure that the stream is delivered with or without the use of the Cambozola plugin. Selecting 'yes' will tell ZoneMinder that your browser can handle the streams natively, 'no' means that it can't and so the plugin will be used while 'auto' lets ZoneMinder decide.", - type => $types{tristate}, - category => "medband", - }, - { - name => "ZM_WEB_M_STREAM_METHOD", - default => "jpeg", - description => "Which method should be used to send video streams to your browser.", - help => "ZoneMinder can be configured to use either mpeg encoded video or a series or still jpeg images when sending video streams. This option defines which is used. If you choose mpeg you should ensure that you have the appropriate plugins available on your browser whereas choosing jpeg will work natively on Mozilla and related browsers and with a Java applet on Internet Explorer", - type => { db_type=>"string", hint=>"mpeg|jpeg", pattern=>qr|^([mj])|i, format=>q( $1 =~ /^m/ ? "mpeg" : "jpeg" ) }, - category => "medband", - }, - { - name => "ZM_WEB_M_DEFAULT_SCALE", - default => "100", - description => "What the default scaling factor applied to 'live' or 'event' views is (%)", - help => "Normally ZoneMinder will display 'live' or 'event' streams in their native size. However if you have monitors with large dimensions or a slow link you may prefer to reduce this size, alternatively for small monitors you can enlarge it. This options lets you specify what the default scaling factor will be. It is expressed as a percentage so 100 is normal size, 200 is double size etc.", - type => { db_type=>"integer", hint=>"25|33|50|75|100|150|200|300|400", pattern=>qr|^(\d+)$|, format=>q( $1 ) }, - category => "medband", - }, - { - name => "ZM_WEB_M_DEFAULT_RATE", - default => "100", - description => "What the default replay rate factor applied to 'event' views is (%)", - help => "Normally ZoneMinder will display 'event' streams at their native rate, i.e. as close to real-time as possible. However if you have long events it is often convenient to replay them at a faster rate for review. This option lets you specify what the default replay rate will be. It is expressed as a percentage so 100 is normal rate, 200 is double speed etc.", - type => { db_type=>"integer", hint=>"25|50|100|150|200|400|1000|2500|5000|10000", pattern=>qr|^(\d+)$|, format=>q( $1 ) }, - category => "medband", - }, - { - name => "ZM_WEB_M_VIDEO_BITRATE", - default => "75000", - description => "What the bitrate of the video encoded stream should be set to", - help => "When encoding real video via the ffmpeg library a bit rate can be specified which roughly corresponds to the available bandwidth used for the stream. This setting effectively corresponds to a 'quality' setting for the video. A low value will result in a blocky image whereas a high value will produce a clearer view. Note that this setting does not control the frame rate of the video however the quality of the video produced is affected both by this setting and the frame rate that the video is produced at. A higher frame rate at a particular bit rate result in individual frames being at a lower quality.", - type => $types{integer}, - category => "medband", - }, - { - name => "ZM_WEB_M_VIDEO_MAXFPS", - default => "10", - description => "What the maximum frame rate for streamed video should be", - help => "When using streamed video the main control is the bitrate which determines how much data can be transmitted. However a lower bitrate at high frame rates results in a lower quality image. This option allows you to limit the maximum frame rate to ensure that video quality is maintained. An additional advantage is that encoding video at high frame rates is a processor intensive task when for the most part a very high frame rate offers little perceptible improvement over one that has a more manageable resource requirement. Note, this option is implemented as a cap beyond which binary reduction takes place. So if you have a device capturing at 15fps and set this option to 10fps then the video is not produced at 10fps, but rather at 7.5fps (15 divided by 2) as the final frame rate must be the original divided by a power of 2.", - type => $types{integer}, - category => "medband", - }, - { - name => "ZM_WEB_M_SCALE_THUMBS", - default => "yes", - description => "Scale thumbnails in events, bandwidth versus cpu in rescaling", - help => "If unset, this option sends the whole image to the browser which resizes it in the window. If set the image is scaled down on the server before sending a reduced size image to the browser to conserve bandwidth at the cost of cpu on the server. Note that ZM can only perform the resizing if the appropriate PHP graphics functionality is installed. This is usually available in the php-gd package.", - type => $types{boolean}, - category => "medband", - }, - { - name => "ZM_WEB_M_EVENTS_VIEW", - default => "events", - description => "What the default view of multiple events should be.", - help => "Stored events can be viewed in either an events list format or in a timeline based one. This option sets the default view that will be used. Choosing one view here does not prevent the other view being used as it will always be selectable from whichever view is currently being used.", - type => { db_type=>"string", hint=>"events|timeline", pattern=>qr|^([lt])|i, format=>q( $1 =~ /^e/ ? "events" : "timeline" ) }, - category => "medband", - }, - { - name => "ZM_WEB_M_SHOW_PROGRESS", - default => "yes", - description => "Show the progress of replay in event view.", - help => "When viewing events an event navigation panel and progress bar is shown below the event itself. This allows you to jump to specific points in the event, but can can also dynamically update to display the current progress of the event replay itself. This progress is calculated from the actual event duration and is not directly linked to the replay itself, so on limited bandwidth connections may be out of step with the replay. This option allows you to turn off the progress display, whilst still keeping the navigation aspect, where bandwidth prevents it functioning effectively.", - type => $types{boolean}, - category => "medband", - }, - { - name => "ZM_WEB_M_AJAX_TIMEOUT", - default => "5000", - description => "How long to wait for Ajax request responses (ms)", - help => "The newer versions of the live feed and event views use Ajax to request information from the server and populate the views dynamically. This option allows you to specify a timeout if required after which requests are abandoned. A timeout may be necessary if requests would overwise hang such as on a slow connection. This would tend to consume a lot of browser memory and make the interface unresponsive. Ordinarily no requests should timeout so this setting should be set to a value greater than the slowest expected response. This value is in milliseconds but if set to zero then no timeout will be used.", - type => $types{integer}, - category => "medband", - }, - { - name => "ZM_WEB_L_REFRESH_MAIN", - default => "300", - description => "How often (in seconds) the main console window should refresh itself", - introduction => "The next few options control what happens when the client is running in 'low' bandwidth mode. You should set these options for when accessing the ZoneMinder client over a modem or slow link. In most cases the default values will be suitable as a starting point.", - help => "The main console window lists a general status and the event totals for all monitors. This is not a trivial task and should not be repeated too frequently or it may affect the performance of the rest of the system.", - type => $types{integer}, - category => "lowband", - }, - { - name => "ZM_WEB_L_REFRESH_CYCLE", - default => "30", - description => "How often (in seconds) the cycle watch window swaps to the next monitor", - help => "The cycle watch window is a method of continuously cycling between images from all of your monitors. This option determines how often to refresh with a new image.", - type => $types{integer}, - category => "lowband", - }, - { - name => "ZM_WEB_L_REFRESH_IMAGE", - default => "15", - description => "How often (in seconds) the watched image is refreshed (if not streaming)", - help => "The live images from a monitor can be viewed in either streamed or stills mode. This option determines how often a stills image is refreshed, it has no effect if streaming is selected.", - type => $types{integer}, - category => "lowband", - }, - { - name => "ZM_WEB_L_REFRESH_STATUS", - default => "10", - description => "How often (in seconds) the status refreshes itself in the watch window", - help => "The monitor window is actually made from several frames. The one in the middle merely contains a monitor status which needs to refresh fairly frequently to give a true indication. This option determines that frequency.", - type => $types{integer}, - category => "lowband", - }, - { - name => "ZM_WEB_L_REFRESH_EVENTS", - default => "180", - description => "How often (in seconds) the event listing is refreshed in the watch window", - help => "The monitor window is actually made from several frames. The lower framme contains a listing of the last few events for easy access. This option determines how often this is refreshed.", - type => $types{integer}, - category => "lowband", - }, - { - name => "ZM_WEB_L_CAN_STREAM", - default => "auto", - description => "Override the automatic detection of browser streaming capability", - help => "If you know that your browser can handle image streams of the type 'multipart/x-mixed-replace' but ZoneMinder does not detect this correctly you can set this option to ensure that the stream is delivered with or without the use of the Cambozola plugin. Selecting 'yes' will tell ZoneMinder that your browser can handle the streams natively, 'no' means that it can't and so the plugin will be used while 'auto' lets ZoneMinder decide.", - type => $types{tristate}, - category => "lowband", - }, - { - name => "ZM_WEB_L_STREAM_METHOD", - default => "jpeg", - description => "Which method should be used to send video streams to your browser.", - help => "ZoneMinder can be configured to use either mpeg encoded video or a series or still jpeg images when sending video streams. This option defines which is used. If you choose mpeg you should ensure that you have the appropriate plugins available on your browser whereas choosing jpeg will work natively on Mozilla and related browsers and with a Java applet on Internet Explorer", - type => { db_type=>"string", hint=>"mpeg|jpeg", pattern=>qr|^([mj])|i, format=>q( $1 =~ /^m/ ? "mpeg" : "jpeg" ) }, - category => "lowband", - }, - { - name => "ZM_WEB_L_DEFAULT_SCALE", - default => "100", - description => "What the default scaling factor applied to 'live' or 'event' views is (%)", - help => "Normally ZoneMinder will display 'live' or 'event' streams in their native size. However if you have monitors with large dimensions or a slow link you may prefer to reduce this size, alternatively for small monitors you can enlarge it. This options lets you specify what the default scaling factor will be. It is expressed as a percentage so 100 is normal size, 200 is double size etc.", - type => { db_type=>"integer", hint=>"25|33|50|75|100|150|200|300|400", pattern=>qr|^(\d+)$|, format=>q( $1 ) }, - category => "lowband", - }, - { - name => "ZM_WEB_L_DEFAULT_RATE", - default => "100", - description => "What the default replay rate factor applied to 'event' views is (%)", - help => "Normally ZoneMinder will display 'event' streams at their native rate, i.e. as close to real-time as possible. However if you have long events it is often convenient to replay them at a faster rate for review. This option lets you specify what the default replay rate will be. It is expressed as a percentage so 100 is normal rate, 200 is double speed etc.", - type => { db_type=>"integer", hint=>"25|50|100|150|200|400|1000|2500|5000|10000", pattern=>qr|^(\d+)$|, format=>q( $1 ) }, - category => "lowband", - }, - { - name => "ZM_WEB_L_VIDEO_BITRATE", - default => "25000", - description => "What the bitrate of the video encoded stream should be set to", - help => "When encoding real video via the ffmpeg library a bit rate can be specified which roughly corresponds to the available bandwidth used for the stream. This setting effectively corresponds to a 'quality' setting for the video. A low value will result in a blocky image whereas a high value will produce a clearer view. Note that this setting does not control the frame rate of the video however the quality of the video produced is affected both by this setting and the frame rate that the video is produced at. A higher frame rate at a particular bit rate result in individual frames being at a lower quality.", - type => $types{integer}, - category => "lowband", - }, - { - name => "ZM_WEB_L_VIDEO_MAXFPS", - default => "5", - description => "What the maximum frame rate for streamed video should be", - help => "When using streamed video the main control is the bitrate which determines how much data can be transmitted. However a lower bitrate at high frame rates results in a lower quality image. This option allows you to limit the maximum frame rate to ensure that video quality is maintained. An additional advantage is that encoding video at high frame rates is a processor intensive task when for the most part a very high frame rate offers little perceptible improvement over one that has a more manageable resource requirement. Note, this option is implemented as a cap beyond which binary reduction takes place. So if you have a device capturing at 15fps and set this option to 10fps then the video is not produced at 10fps, but rather at 7.5fps (15 divided by 2) as the final frame rate must be the original divided by a power of 2.", - type => $types{integer}, - category => "lowband", - }, - { - name => "ZM_WEB_L_SCALE_THUMBS", - default => "yes", - description => "Scale thumbnails in events, bandwidth versus cpu in rescaling", - help => "If unset, this option sends the whole image to the browser which resizes it in the window. If set the image is scaled down on the server before sending a reduced size image to the browser to conserve bandwidth at the cost of cpu on the server. Note that ZM can only perform the resizing if the appropriate PHP graphics functionality is installed. This is usually available in the php-gd package.", - type => $types{boolean}, - category => "lowband", - }, - { - name => "ZM_WEB_L_EVENTS_VIEW", - default => "events", - description => "What the default view of multiple events should be.", - help => "Stored events can be viewed in either an events list format or in a timeline based one. This option sets the default view that will be used. Choosing one view here does not prevent the other view being used as it will always be selectable from whichever view is currently being used.", - type => { db_type=>"string", hint=>"events|timeline", pattern=>qr|^([lt])|i, format=>q( $1 =~ /^e/ ? "events" : "timeline" ) }, - category => "lowband", - }, - { - name => "ZM_WEB_L_SHOW_PROGRESS", - default => "no", - description => "Show the progress of replay in event view.", - help => "When viewing events an event navigation panel and progress bar is shown below the event itself. This allows you to jump to specific points in the event, but can can also dynamically update to display the current progress of the event replay itself. This progress is calculated from the actual event duration and is not directly linked to the replay itself, so on limited bandwidth connections may be out of step with the replay. This option allows you to turn off the progress display, whilst still keeping the navigation aspect, where bandwidth prevents it functioning effectively.", - type => $types{boolean}, - category => "lowband", - }, - { - name => "ZM_WEB_L_AJAX_TIMEOUT", - default => "10000", - description => "How long to wait for Ajax request responses (ms)", - help => "The newer versions of the live feed and event views use Ajax to request information from the server and populate the views dynamically. This option allows you to specify a timeout if required after which requests are abandoned. A timeout may be necessary if requests would overwise hang such as on a slow connection. This would tend to consume a lot of browser memory and make the interface unresponsive. Ordinarily no requests should timeout so this setting should be set to a value greater than the slowest expected response. This value is in milliseconds but if set to zero then no timeout will be used.", - type => $types{integer}, - category => "lowband", - }, - { - name => "ZM_WEB_P_CAN_STREAM", - default => "auto", - description => "Override the automatic detection of browser streaming capability", - help => "If you know that your browser can handle image streams of the type 'multipart/x-mixed-replace' but ZoneMinder does not detect this correctly you can set this option to ensure that the stream is delivered with or without the use of the Cambozola plugin. Selecting 'yes' will tell ZoneMinder that your browser can handle the streams natively, 'no' means that it can't and so the plugin will be used while 'auto' lets ZoneMinder decide.", - type => $types{tristate}, - category => "phoneband", - }, - { - name => "ZM_WEB_P_STREAM_METHOD", - default => "jpeg", - description => "Which method should be used to send video streams to your browser.", - help => "ZoneMinder can be configured to use either mpeg encoded video or a series or still jpeg images when sending video streams. This option defines which is used. If you choose mpeg you should ensure that you have the appropriate plugins available on your browser whereas choosing jpeg will work natively on Mozilla and related browsers and with a Java applet on Internet Explorer", - type => { db_type=>"string", hint=>"mpeg|jpeg", pattern=>qr|^([mj])|i, format=>q( $1 =~ /^m/ ? "mpeg" : "jpeg" ) }, - category => "phoneband", - }, - { - name => "ZM_WEB_P_DEFAULT_SCALE", - default => "100", - description => "What the default scaling factor applied to 'live' or 'event' views is (%)", - help => "Normally ZoneMinder will display 'live' or 'event' streams in their native size. However if you have monitors with large dimensions or a slow link you may prefer to reduce this size, alternatively for small monitors you can enlarge it. This options lets you specify what the default scaling factor will be. It is expressed as a percentage so 100 is normal size, 200 is double size etc.", - type => { db_type=>"integer", hint=>"25|33|50|75|100|150|200|300|400", pattern=>qr|^(\d+)$|, format=>q( $1 ) }, - category => "phoneband", - }, - { - name => "ZM_WEB_P_DEFAULT_RATE", - default => "100", - description => "What the default replay rate factor applied to 'event' views is (%)", - help => "Normally ZoneMinder will display 'event' streams at their native rate, i.e. as close to real-time as possible. However if you have long events it is often convenient to replay them at a faster rate for review. This option lets you specify what the default replay rate will be. It is expressed as a percentage so 100 is normal rate, 200 is double speed etc.", - type => { db_type=>"integer", hint=>"25|50|100|150|200|400|1000|2500|5000|10000", pattern=>qr|^(\d+)$|, format=>q( $1 ) }, - category => "phoneband", - }, - { - name => "ZM_WEB_P_VIDEO_BITRATE", - default => "8000", - description => "What the bitrate of the video encoded stream should be set to", - help => "When encoding real video via the ffmpeg library a bit rate can be specified which roughly corresponds to the available bandwidth used for the stream. This setting effectively corresponds to a 'quality' setting for the video. A low value will result in a blocky image whereas a high value will produce a clearer view. Note that this setting does not control the frame rate of the video however the quality of the video produced is affected both by this setting and the frame rate that the video is produced at. A higher frame rate at a particular bit rate result in individual frames being at a lower quality.", - type => $types{integer}, - category => "phoneband", - }, - { - name => "ZM_WEB_P_VIDEO_MAXFPS", - default => "5", - description => "What the maximum frame rate for streamed video should be", - help => "When using streamed video the main control is the bitrate which determines how much data can be transmitted. However a lower bitrate at high frame rates results in a lower quality image. This option allows you to limit the maximum frame rate to ensure that video quality is maintained. An additional advantage is that encoding video at high frame rates is a processor intensive task when for the most part a very high frame rate offers little perceptible improvement over one that has a more manageable resource requirement. Note, this option is implemented as a cap beyond which binary reduction takes place. So if you have a device capturing at 15fps and set this option to 10fps then the video is not produced at 10fps, but rather at 7.5fps (15 divided by 2) as the final frame rate must be the original divided by a power of 2.", - type => $types{integer}, - category => "phoneband", - }, - { - name => "ZM_WEB_P_SCALE_THUMBS", - default => "yes", - description => "Scale thumbnails in events, bandwidth versus cpu in rescaling", - help => "If unset, this option sends the whole image to the browser which resizes it in the window. If set the image is scaled down on the server before sending a reduced size image to the browser to conserve bandwidth at the cost of cpu on the server. Note that ZM can only perform the resizing if the appropriate PHP graphics functionality is installed. This is usually available in the php-gd package.", - type => $types{boolean}, - category => "phoneband", - }, - { - name => "ZM_WEB_P_AJAX_TIMEOUT", - default => "10000", - description => "How long to wait for Ajax request responses (ms)", - help => "The newer versions of the live feed and event views use Ajax to request information from the server and populate the views dynamically. This option allows you to specify a timeout if required after which requests are abandoned. A timeout may be necessary if requests would overwise hang such as on a slow connection. This would tend to consume a lot of browser memory and make the interface unresponsive. Ordinarily no requests should timeout so this setting should be set to a value greater than the slowest expected response. This value is in milliseconds but if set to zero then no timeout will be used.", - type => $types{integer}, - category => "phoneband", - }, - { - name => "ZM_DYN_LAST_VERSION", - default => "", - description => "What the last version of ZoneMinder recorded from zoneminder.com is", - help => "", - type => $types{string}, - readonly => 1, - category => "dynamic", - }, - { - name => "ZM_DYN_CURR_VERSION", - default => "@VERSION@", - description => "What the effective current version of ZoneMinder is, might be different from actual if versions ignored", - help => "", - type => $types{string}, - readonly => 1, - category => "dynamic", - }, - { - name => "ZM_DYN_DB_VERSION", - default => "@VERSION@", - description => "What the version of the database is, from zmupdate", - help => "", - type => $types{string}, - readonly => 1, - category => "dynamic", - }, - { - name => "ZM_DYN_LAST_CHECK", - default => "", - description => "When the last check for version from zoneminder.com was", - help => "", - type => $types{integer}, - readonly => 1, - category => "dynamic", - }, - { - name => "ZM_DYN_NEXT_REMINDER", - default => "", - description => "When the earliest time to remind about versions will be", - help => "", - type => $types{string}, - readonly => 1, - category => "dynamic", - }, - { - name => "ZM_DYN_DONATE_REMINDER_TIME", - default => 0, - description => "When the earliest time to remind about donations will be", - help => "", - type => $types{integer}, - readonly => 1, - category => "dynamic", - }, - { - name => "ZM_DYN_SHOW_DONATE_REMINDER", - default => "yes", - description => "Remind about donations or not", - help => "", - type => $types{boolean}, - readonly => 1, - category => "dynamic", - }, - { - name => "ZM_EYEZM_DEBUG", - default => "no", - description => "Switch additional debugging on for eyeZm Plugin", - help => "Enable or Disable extra debugging from the eyeZm Plugin. Extra debugging information will be displayed in it's own file (EYEZM_LOG_TO_FILE is set), or your Apache error log", - type => $types{boolean}, - category => "eyeZm", - }, - { - name => "ZM_EYEZM_LOG_TO_FILE", - default => "yes", - description => "When eyeZm Debugging is enabled, enabling this logs output to it's own file", - help => "When EYEZM_DEBUG is on and EYEZM_LOG_TO_FILE is on, output generated from the eyeZm Plugin will go to it's own file. Otherwise it will go to the apache error log.", - type => $types{boolean}, - category => "eyeZm", - }, - { - name => "ZM_EYEZM_LOG_FILE", - default => "@ZM_LOGDIR@/zm_xml.log", - description => "Default filename to use when logging eyeZm Output and EYEZM_LOG_TO_FILE is enabled", - help => "This file will contain it's own output from the eyeZm Plugin when EYEZM_LOG_TO_FILE and EYEZM_DEBUG are both enabled", - type => $types{string}, - category => "eyeZm", - }, - { - name => "ZM_EYEZM_EVENT_VCODEC", - default => "mpeg4", - description => "Default video-codec to use for encoding events", - help => "The eyeZm Plugin calls FFMPEG externally to encode the captured images. If your FFMPEG is not built with support for H264, change this to MPEG-4. If using H264, please check http://www.eyezm.com for H264 requirements and that your eyeZm version supports H264 (v1.2+).", - type => { db_type=>"string", hint=>"mpeg4|h264", pattern=>qr|^([mh])|i, format=>q( $1 =~ /^m/ ? "mpeg4" : "h264" ) }, - category => "eyeZm", - }, - { - name => "ZM_EYEZM_FEED_VCODEC", - default => "mjpeg", - description => "Default video-codec to use for streaming the live feed", - help => "Determines whether the live stream is generated using native MJPEG streaming with ZoneMinder, or H264 using FFMPEG and HTML-5 streaming. If using H264, please check http://www.eyezm.com for H264 requirements and that your eyeZm version supports H264 (v1.2+). This is just a default parameter, and can be overridden with eyeZm.", - type => { db_type=>"string", hint=>"mjpeg|h264", pattern=>qr|^([mh])|i, format=>q( $1 =~ /^m/ ? "mjpeg" : "h264" ) }, - category => "eyeZm", - }, - { - name => "ZM_EYEZM_H264_DEFAULT_BR", - default => "96k", - description => "Default bit-rate to use with FFMPEG for H264 streaming", - help => "When using the eyeZm Plugin to stream H264 data, FFMPEG requires a bitrate to control the quality and bandwidth of the video. This should be specified in a format acceptable to FFMPEG. The default value is sufficient for most installations. This is just a default parameter, and can be overridden with eyeZm.", - type => $types{string}, - category => "eyeZm", - }, - { - name => "ZM_EYEZM_H264_DEFAULT_EVBR", - default => "128k", - description => "Default bit-rate to use with FFMPEG for H264 event viewing", - help => "When using the eyeZm Plugin to view events in H264, FFMPEG requires a bitrate to control the quality and bandwidth of the video. This should be specified in a format acceptable to FFMPEG. The default value is sufficient for most installations. This is just a default parameter, and can be overridden with eyeZm.", - type => $types{string}, - category => "eyeZm", - }, - { - name => "ZM_EYEZM_H264_TIMEOUT", - default => "20", - description => "Timeout (sec) to wait for H264 stream to start before terminating", - help => "The eyeZm Plugin will attempt to spawn an H264 stream when requested, and require that it complete within the timeout specified. If you have a slow system or find through the logs that the H264 stream is not starting because the timeout is expiring, even though FFMPEG is running, try increasing this value. If you have a fast system, decreasing this value can improve the responsiveness when there are issues starting H264 streams", - type => $types{string}, - category => "eyeZm", - }, - { - name => "ZM_EYEZM_SEG_DURATION", - default => "3", - description => "Segment duration used for streaming using HTTP-5 Streaming protocol", - help => "The HTTP-5 Live Streaming Protocol segments the input video stream into small chunks of a duration specified by this parameter. Increasing the segment duration will help with choppy connections on the other end, but will increase the latency in starting a stream.", - type => $types{string}, - category => "eyeZm", - }, + { + name => "ZM_WEB_REFRESH_METHOD", + default => "javascript", + description => "What method windows should use to refresh themselves", + help => qqq(" + Many windows in Javascript need to refresh themselves to keep + their information current. This option determines what method + they should use to do this. Choosing 'javascript' means that + each window will have a short JavaScript statement in with a + timer to prompt the refresh. This is the most compatible + method. Choosing 'http' means the refresh instruction is put in + the HTTP header. This is a cleaner method but refreshes are + interrupted or cancelled when a link in the window is clicked + meaning that the window will no longer refresh and this would + have to be done manually. + "), + type => { + db_type =>"string", + hint =>"javascript|http", + pattern =>qr|^([jh])|i, + format =>q( $1 =~ /^j/ + ? "javascript" + : "http" + ) + }, + category => "hidden", + }, + { + name => "ZM_WEB_EVENT_SORT_FIELD", + default => "DateTime", + description => "Default field the event lists are sorted by", + help => qqq(" + Events in lists can be initially ordered in any way you want. + This option controls what field is used to sort them. You can + modify this ordering from filters or by clicking on headings in + the lists themselves. Bear in mind however that the 'Prev' and + 'Next' links, when scrolling through events, relate to the + ordering in the lists and so not always to time based ordering. + "), + type => { + db_type =>"string", + hint =>"Id|Name|Cause|MonitorName|DateTime|Length|Frames|AlarmFrames|TotScore|AvgScore|MaxScore", + pattern =>qr|.|, + format =>q( $1 ) + }, + category => "web", + }, + { + name => "ZM_WEB_EVENT_SORT_ORDER", + default => "asc", + description => "Default order the event lists are sorted by", + help => qqq(" + Events in lists can be initially ordered in any way you want. + This option controls what order (ascending or descending) is + used to sort them. You can modify this ordering from filters or + by clicking on headings in the lists themselves. Bear in mind + however that the 'Prev' and 'Next' links, when scrolling + through events, relate to the ordering in the lists and so not + always to time based ordering. + "), + type => { + db_type =>"string", + hint =>"asc|desc", + pattern =>qr|^([ad])|i, + format =>q( $1 =~ /^a/i ? "asc" : "desc" ) + }, + category => "web", + }, + { + name => "ZM_WEB_EVENTS_PER_PAGE", + default => "25", + description => "How many events to list per page in paged mode", + help => qqq(" + In the event list view you can either list all events or just a + page at a time. This option controls how many events are listed + per page in paged mode and how often to repeat the column + headers in non-paged mode. + "), + type => $types{integer}, + category => "web", + }, + { + name => "ZM_WEB_LIST_THUMBS", + default => "no", + description => "Display mini-thumbnails of event images in event lists", + help => qqq(" + Ordinarily the event lists just display text details of the + events to save space and time. By switching this option on you + can also display small thumbnails to help you identify events + of interest. The size of these thumbnails is controlled by the + following two options. + "), + type => $types{boolean}, + category => "web", + }, + { + name => "ZM_WEB_LIST_THUMB_WIDTH", + default => "48", + description => "The width of the thumbnails that appear in the event lists", + help => qqq(" + This options controls the width of the thumbnail images that + appear in the event lists. It should be fairly small to fit in + with the rest of the table. If you prefer you can specify a + height instead in the next option but you should only use one + of the width or height and the other option should be set to + zero. If both width and height are specified then width will be + used and height ignored. + "), + type => $types{integer}, + requires => [ { name => "ZM_WEB_LIST_THUMBS", value => "yes" } ], + category => "web", + }, + { + name => "ZM_WEB_LIST_THUMB_HEIGHT", + default => "0", + description => "The height of the thumbnails that appear in the event lists", + help => qqq(" + This options controls the height of the thumbnail images that + appear in the event lists. It should be fairly small to fit in + with the rest of the table. If you prefer you can specify a + width instead in the previous option but you should only use + one of the width or height and the other option should be set + to zero. If both width and height are specified then width will + be used and height ignored. + "), + type => $types{integer}, + requires => [ { name => "ZM_WEB_LIST_THUMBS", value => "yes" } ], + category => "web", + }, + { + name => "ZM_WEB_USE_OBJECT_TAGS", + default => "yes", + description => "Wrap embed in object tags for media content", + help => qqq(" + There are two methods of including media content in web pages. + The most common way is use the EMBED tag which is able to give + some indication of the type of content. However this is not a + standard part of HTML. The official method is to use OBJECT + tags which are able to give more information allowing the + correct media viewers etc to be loaded. However these are less + widely supported and content may be specifically tailored to a + particular platform or player. This option controls whether + media content is enclosed in EMBED tags only or whether, where + appropriate, it is additionally wrapped in OBJECT tags. + Currently OBJECT tags are only used in a limited number of + circumstances but they may become more widespread in the + future. It is suggested that you leave this option on unless + you encounter problems playing some content. + "), + type => $types{boolean}, + category => "web", + }, + { + name => "ZM_WEB_H_REFRESH_MAIN", + default => "60", + introduction => qqq(" + There are now a number of options that are grouped into + bandwidth categories, this allows you to configure the + ZoneMinder client to work optimally over the various access + methods you might to access the client.\n\nThe next few options + control what happens when the client is running in 'high' + bandwidth mode. You should set these options for when accessing + the ZoneMinder client over a local network or high speed link. + In most cases the default values will be suitable as a starting + point. + "), + description => "How often (in seconds) the main console window should refresh itself", + help => qqq(" + The main console window lists a general status and the event + totals for all monitors. This is not a trivial task and should + not be repeated too frequently or it may affect the performance + of the rest of the system. + "), + type => $types{integer}, + category => "highband", + }, + { + name => "ZM_WEB_H_REFRESH_CYCLE", + default => "10", + description => "How often (in seconds) the cycle watch window swaps to the next monitor", + help => qqq(" + The cycle watch window is a method of continuously cycling + between images from all of your monitors. This option + determines how often to refresh with a new image. + "), + type => $types{integer}, + category => "highband", + }, + { + name => "ZM_WEB_H_REFRESH_IMAGE", + default => "3", + description => "How often (in seconds) the watched image is refreshed (if not streaming)", + help => qqq(" + The live images from a monitor can be viewed in either streamed + or stills mode. This option determines how often a stills image + is refreshed, it has no effect if streaming is selected. + "), + type => $types{integer}, + category => "highband", + }, + { + name => "ZM_WEB_H_REFRESH_STATUS", + default => "1", + description => "How often (in seconds) the status refreshes itself in the watch window", + help => qqq(" + The monitor window is actually made from several frames. The + one in the middle merely contains a monitor status which needs + to refresh fairly frequently to give a true indication. This + option determines that frequency. + "), + type => $types{integer}, + category => "highband", + }, + { + name => "ZM_WEB_H_REFRESH_EVENTS", + default => "5", + description => "How often (in seconds) the event listing is refreshed in the watch window", + help => qqq(" + The monitor window is actually made from several frames. The + lower framme contains a listing of the last few events for easy + access. This option determines how often this is refreshed. + "), + type => $types{integer}, + category => "highband", + }, + { + name => "ZM_WEB_H_CAN_STREAM", + default => "auto", + description => "Override the automatic detection of browser streaming capability", + help => qqq(" + If you know that your browser can handle image streams of the + type 'multipart/x-mixed-replace' but ZoneMinder does not detect + this correctly you can set this option to ensure that the + stream is delivered with or without the use of the Cambozola + plugin. Selecting 'yes' will tell ZoneMinder that your browser + can handle the streams natively, 'no' means that it can't and + so the plugin will be used while 'auto' lets ZoneMinder decide. + "), + type => $types{tristate}, + category => "highband", + }, + { + name => "ZM_WEB_H_STREAM_METHOD", + default => "jpeg", + description => "Which method should be used to send video streams to your browser.", + help => qqq(" + ZoneMinder can be configured to use either mpeg encoded video + or a series or still jpeg images when sending video streams. + This option defines which is used. If you choose mpeg you + should ensure that you have the appropriate plugins available + on your browser whereas choosing jpeg will work natively on + Mozilla and related browsers and with a Java applet on Internet + Explorer + "), + type => { + db_type =>"string", + hint =>"mpeg|jpeg", + pattern =>qr|^([mj])|i, + format =>q( $1 =~ /^m/ ? "mpeg" : "jpeg" ) + }, + category => "highband", + }, + { + name => "ZM_WEB_H_DEFAULT_SCALE", + default => "100", + description => "What the default scaling factor applied to 'live' or 'event' views is (%)", + help => qqq(" + Normally ZoneMinder will display 'live' or 'event' streams in + their native size. However if you have monitors with large + dimensions or a slow link you may prefer to reduce this size, + alternatively for small monitors you can enlarge it. This + options lets you specify what the default scaling factor will + be. It is expressed as a percentage so 100 is normal size, 200 + is double size etc. + "), + type => { + db_type =>"integer", + hint =>"25|33|50|75|100|150|200|300|400", + pattern =>qr|^(\d+)$|, + format =>q( $1 ) + }, + category => "highband", + }, + { + name => "ZM_WEB_H_DEFAULT_RATE", + default => "100", + description => "What the default replay rate factor applied to 'event' views is (%)", + help => qqq(" + Normally ZoneMinder will display 'event' streams at their + native rate, i.e. as close to real-time as possible. However if + you have long events it is often convenient to replay them at a + faster rate for review. This option lets you specify what the + default replay rate will be. It is expressed as a percentage so + 100 is normal rate, 200 is double speed etc. + "), + type => { + db_type =>"integer", + hint =>"25|50|100|150|200|400|1000|2500|5000|10000", + pattern =>qr|^(\d+)$|, + format =>q( $1 ) + }, + category => "highband", + }, + { + name => "ZM_WEB_H_VIDEO_BITRATE", + default => "150000", + description => "What the bitrate of the video encoded stream should be set to", + help => qqq(" + When encoding real video via the ffmpeg library a bit rate can + be specified which roughly corresponds to the available + bandwidth used for the stream. This setting effectively + corresponds to a 'quality' setting for the video. A low value + will result in a blocky image whereas a high value will produce + a clearer view. Note that this setting does not control the + frame rate of the video however the quality of the video + produced is affected both by this setting and the frame rate + that the video is produced at. A higher frame rate at a + particular bit rate result in individual frames being at a + lower quality. + "), + type => $types{integer}, + category => "highband", + }, + { + name => "ZM_WEB_H_VIDEO_MAXFPS", + default => "30", + description => "What the maximum frame rate for streamed video should be", + help => qqq(" + When using streamed video the main control is the bitrate which + determines how much data can be transmitted. However a lower + bitrate at high frame rates results in a lower quality image. + This option allows you to limit the maximum frame rate to + ensure that video quality is maintained. An additional + advantage is that encoding video at high frame rates is a + processor intensive task when for the most part a very high + frame rate offers little perceptible improvement over one that + has a more manageable resource requirement. Note, this option + is implemented as a cap beyond which binary reduction takes + place. So if you have a device capturing at 15fps and set this + option to 10fps then the video is not produced at 10fps, but + rather at 7.5fps (15 divided by 2) as the final frame rate must + be the original divided by a power of 2. + "), + type => $types{integer}, + category => "highband", + }, + { + name => "ZM_WEB_H_SCALE_THUMBS", + default => "no", + description => "Scale thumbnails in events, bandwidth versus cpu in rescaling", + help => qqq(" + If unset, this option sends the whole image to the browser + which resizes it in the window. If set the image is scaled down + on the server before sending a reduced size image to the + browser to conserve bandwidth at the cost of cpu on the server. + Note that ZM can only perform the resizing if the appropriate + PHP graphics functionality is installed. This is usually + available in the php-gd package. + "), + type => $types{boolean}, + category => "highband", + }, + { + name => "ZM_WEB_H_EVENTS_VIEW", + default => "events", + description => "What the default view of multiple events should be.", + help => qqq(" + Stored events can be viewed in either an events list format or + in a timeline based one. This option sets the default view that + will be used. Choosing one view here does not prevent the other + view being used as it will always be selectable from whichever + view is currently being used. + "), + type => { + db_type =>"string", + hint =>"events|timeline", + pattern =>qr|^([lt])|i, + format =>q( $1 =~ /^e/ ? "events" : "timeline" ) + }, + category => "highband", + }, + { + name => "ZM_WEB_H_SHOW_PROGRESS", + default => "yes", + description => "Show the progress of replay in event view.", + help => qqq(" + When viewing events an event navigation panel and progress bar + is shown below the event itself. This allows you to jump to + specific points in the event, but can can also dynamically + update to display the current progress of the event replay + itself. This progress is calculated from the actual event + duration and is not directly linked to the replay itself, so on + limited bandwidth connections may be out of step with the + replay. This option allows you to turn off the progress + display, whilst still keeping the navigation aspect, where + bandwidth prevents it functioning effectively. + "), + type => $types{boolean}, + category => "highband", + }, + { + name => "ZM_WEB_H_AJAX_TIMEOUT", + default => "3000", + description => "How long to wait for Ajax request responses (ms)", + help => qqq(" + The newer versions of the live feed and event views use Ajax to + request information from the server and populate the views + dynamically. This option allows you to specify a timeout if + required after which requests are abandoned. A timeout may be + necessary if requests would overwise hang such as on a slow + connection. This would tend to consume a lot of browser memory + and make the interface unresponsive. Ordinarily no requests + should timeout so this setting should be set to a value greater + than the slowest expected response. This value is in + milliseconds but if set to zero then no timeout will be used. + "), + type => $types{integer}, + category => "highband", + }, + { + name => "ZM_WEB_M_REFRESH_MAIN", + default => "300", + description => "How often (in seconds) the main console window should refresh itself", + help => qqq(" + The main console window lists a general status and the event + totals for all monitors. This is not a trivial task and should + not be repeated too frequently or it may affect the performance + of the rest of the system. + "), + type => $types{integer}, + introduction => qqq(" + The next few options control what happens when the client is + running in 'medium' bandwidth mode. You should set these + options for when accessing the ZoneMinder client over a slower + cable or DSL link. In most cases the default values will be + suitable as a starting point. + "), + category => "medband", + }, + { + name => "ZM_WEB_M_REFRESH_CYCLE", + default => "20", + description => "How often (in seconds) the cycle watch window swaps to the next monitor", + help => qqq(" + The cycle watch window is a method of continuously cycling + between images from all of your monitors. This option + determines how often to refresh with a new image. + "), + type => $types{integer}, + category => "medband", + }, + { + name => "ZM_WEB_M_REFRESH_IMAGE", + default => "10", + description => "How often (in seconds) the watched image is refreshed (if not streaming)", + help => qqq(" + The live images from a monitor can be viewed in either streamed + or stills mode. This option determines how often a stills image + is refreshed, it has no effect if streaming is selected. + "), + type => $types{integer}, + category => "medband", + }, + { + name => "ZM_WEB_M_REFRESH_STATUS", + default => "5", + description => "How often (in seconds) the status refreshes itself in the watch window", + help => qqq(" + The monitor window is actually made from several frames. The + one in the middle merely contains a monitor status which needs + to refresh fairly frequently to give a true indication. This + option determines that frequency. + "), + type => $types{integer}, + category => "medband", + }, + { + name => "ZM_WEB_M_REFRESH_EVENTS", + default => "60", + description => "How often (in seconds) the event listing is refreshed in the watch window", + help => qqq(" + The monitor window is actually made from several frames. The + lower framme contains a listing of the last few events for easy + access. This option determines how often this is refreshed. + "), + type => $types{integer}, + category => "medband", + }, + { + name => "ZM_WEB_M_CAN_STREAM", + default => "auto", + description => "Override the automatic detection of browser streaming capability", + help => qqq(" + If you know that your browser can handle image streams of the + type 'multipart/x-mixed-replace' but ZoneMinder does not detect + this correctly you can set this option to ensure that the + stream is delivered with or without the use of the Cambozola + plugin. Selecting 'yes' will tell ZoneMinder that your browser + can handle the streams natively, 'no' means that it can't and + so the plugin will be used while 'auto' lets ZoneMinder decide. + "), + type => $types{tristate}, + category => "medband", + }, + { + name => "ZM_WEB_M_STREAM_METHOD", + default => "jpeg", + description => "Which method should be used to send video streams to your browser.", + help => qqq(" + ZoneMinder can be configured to use either mpeg encoded video + or a series or still jpeg images when sending video streams. + This option defines which is used. If you choose mpeg you + should ensure that you have the appropriate plugins available + on your browser whereas choosing jpeg will work natively on + Mozilla and related browsers and with a Java applet on Internet + Explorer + "), + type => { + db_type =>"string", + hint =>"mpeg|jpeg", + pattern =>qr|^([mj])|i, + format =>q( $1 =~ /^m/ ? "mpeg" : "jpeg" ) + }, + category => "medband", + }, + { + name => "ZM_WEB_M_DEFAULT_SCALE", + default => "100", + description => "What the default scaling factor applied to 'live' or 'event' views is (%)", + help => qqq(" + Normally ZoneMinder will display 'live' or 'event' streams in + their native size. However if you have monitors with large + dimensions or a slow link you may prefer to reduce this size, + alternatively for small monitors you can enlarge it. This + options lets you specify what the default scaling factor will + be. It is expressed as a percentage so 100 is normal size, 200 + is double size etc. + "), + type => { + db_type =>"integer", + hint =>"25|33|50|75|100|150|200|300|400", + pattern =>qr|^(\d+)$|, + format =>q( $1 ) + }, + category => "medband", + }, + { + name => "ZM_WEB_M_DEFAULT_RATE", + default => "100", + description => "What the default replay rate factor applied to 'event' views is (%)", + help => qqq(" + Normally ZoneMinder will display 'event' streams at their + native rate, i.e. as close to real-time as possible. However if + you have long events it is often convenient to replay them at a + faster rate for review. This option lets you specify what the + default replay rate will be. It is expressed as a percentage so + 100 is normal rate, 200 is double speed etc. + "), + type => { + db_type =>"integer", + hint =>"25|50|100|150|200|400|1000|2500|5000|10000", + pattern =>qr|^(\d+)$|, + format =>q( $1 ) + }, + category => "medband", + }, + { + name => "ZM_WEB_M_VIDEO_BITRATE", + default => "75000", + description => "What the bitrate of the video encoded stream should be set to", + help => qqq(" + When encoding real video via the ffmpeg library a bit rate can + be specified which roughly corresponds to the available + bandwidth used for the stream. This setting effectively + corresponds to a 'quality' setting for the video. A low value + will result in a blocky image whereas a high value will produce + a clearer view. Note that this setting does not control the + frame rate of the video however the quality of the video + produced is affected both by this setting and the frame rate + that the video is produced at. A higher frame rate at a + particular bit rate result in individual frames being at a + lower quality. + "), + type => $types{integer}, + category => "medband", + }, + { + name => "ZM_WEB_M_VIDEO_MAXFPS", + default => "10", + description => "What the maximum frame rate for streamed video should be", + help => qqq(" + When using streamed video the main control is the bitrate which + determines how much data can be transmitted. However a lower + bitrate at high frame rates results in a lower quality image. + This option allows you to limit the maximum frame rate to + ensure that video quality is maintained. An additional + advantage is that encoding video at high frame rates is a + processor intensive task when for the most part a very high + frame rate offers little perceptible improvement over one that + has a more manageable resource requirement. Note, this option + is implemented as a cap beyond which binary reduction takes + place. So if you have a device capturing at 15fps and set this + option to 10fps then the video is not produced at 10fps, but + rather at 7.5fps (15 divided by 2) as the final frame rate must + be the original divided by a power of 2. + "), + type => $types{integer}, + category => "medband", + }, + { + name => "ZM_WEB_M_SCALE_THUMBS", + default => "yes", + description => "Scale thumbnails in events, bandwidth versus cpu in rescaling", + help => qqq(" + If unset, this option sends the whole image to the browser + which resizes it in the window. If set the image is scaled down + on the server before sending a reduced size image to the + browser to conserve bandwidth at the cost of cpu on the server. + Note that ZM can only perform the resizing if the appropriate + PHP graphics functionality is installed. This is usually + available in the php-gd package. + "), + type => $types{boolean}, + category => "medband", + }, + { + name => "ZM_WEB_M_EVENTS_VIEW", + default => "events", + description => "What the default view of multiple events should be.", + help => qqq(" + Stored events can be viewed in either an events list format or + in a timeline based one. This option sets the default view that + will be used. Choosing one view here does not prevent the other + view being used as it will always be selectable from whichever + view is currently being used. + "), + type => { + db_type =>"string", + hint =>"events|timeline", + pattern =>qr|^([lt])|i, + format =>q( $1 =~ /^e/ ? "events" : "timeline" ) + }, + category => "medband", + }, + { + name => "ZM_WEB_M_SHOW_PROGRESS", + default => "yes", + description => "Show the progress of replay in event view.", + help => qqq(" + When viewing events an event navigation panel and progress bar + is shown below the event itself. This allows you to jump to + specific points in the event, but can can also dynamically + update to display the current progress of the event replay + itself. This progress is calculated from the actual event + duration and is not directly linked to the replay itself, so on + limited bandwidth connections may be out of step with the + replay. This option allows you to turn off the progress + display, whilst still keeping the navigation aspect, where + bandwidth prevents it functioning effectively. + "), + type => $types{boolean}, + category => "medband", + }, + { + name => "ZM_WEB_M_AJAX_TIMEOUT", + default => "5000", + description => "How long to wait for Ajax request responses (ms)", + help => qqq(" + The newer versions of the live feed and event views use Ajax to + request information from the server and populate the views + dynamically. This option allows you to specify a timeout if + required after which requests are abandoned. A timeout may be + necessary if requests would overwise hang such as on a slow + connection. This would tend to consume a lot of browser memory + and make the interface unresponsive. Ordinarily no requests + should timeout so this setting should be set to a value greater + than the slowest expected response. This value is in + milliseconds but if set to zero then no timeout will be used. + "), + type => $types{integer}, + category => "medband", + }, + { + name => "ZM_WEB_L_REFRESH_MAIN", + default => "300", + description => "How often (in seconds) the main console window should refresh itself", + introduction => qqq(" + The next few options control what happens when the client is + running in 'low' bandwidth mode. You should set these options + for when accessing the ZoneMinder client over a modem or slow + link. In most cases the default values will be suitable as a + starting point. + "), + help => qqq(" + The main console window lists a general status and the event + totals for all monitors. This is not a trivial task and should + not be repeated too frequently or it may affect the performance + of the rest of the system. + "), + type => $types{integer}, + category => "lowband", + }, + { + name => "ZM_WEB_L_REFRESH_CYCLE", + default => "30", + description => "How often (in seconds) the cycle watch window swaps to the next monitor", + help => qqq(" + The cycle watch window is a method of continuously cycling + between images from all of your monitors. This option + determines how often to refresh with a new image. + "), + type => $types{integer}, + category => "lowband", + }, + { + name => "ZM_WEB_L_REFRESH_IMAGE", + default => "15", + description => "How often (in seconds) the watched image is refreshed (if not streaming)", + help => qqq(" + The live images from a monitor can be viewed in either streamed + or stills mode. This option determines how often a stills image + is refreshed, it has no effect if streaming is selected. + "), + type => $types{integer}, + category => "lowband", + }, + { + name => "ZM_WEB_L_REFRESH_STATUS", + default => "10", + description => "How often (in seconds) the status refreshes itself in the watch window", + help => qqq(" + The monitor window is actually made from several frames. The + one in the middle merely contains a monitor status which needs + to refresh fairly frequently to give a true indication. This + option determines that frequency. + "), + type => $types{integer}, + category => "lowband", + }, + { + name => "ZM_WEB_L_REFRESH_EVENTS", + default => "180", + description => "How often (in seconds) the event listing is refreshed in the watch window", + help => qqq(" + The monitor window is actually made from several frames. The + lower framme contains a listing of the last few events for easy + access. This option determines how often this is refreshed. + "), + type => $types{integer}, + category => "lowband", + }, + { + name => "ZM_WEB_L_CAN_STREAM", + default => "auto", + description => "Override the automatic detection of browser streaming capability", + help => qqq(" + If you know that your browser can handle image streams of the + type 'multipart/x-mixed-replace' but ZoneMinder does not detect + this correctly you can set this option to ensure that the + stream is delivered with or without the use of the Cambozola + plugin. Selecting 'yes' will tell ZoneMinder that your browser + can handle the streams natively, 'no' means that it can't and + so the plugin will be used while 'auto' lets ZoneMinder decide. + "), + type => $types{tristate}, + category => "lowband", + }, + { + name => "ZM_WEB_L_STREAM_METHOD", + default => "jpeg", + description => "Which method should be used to send video streams to your browser.", + help => qqq(" + ZoneMinder can be configured to use either mpeg encoded video + or a series or still jpeg images when sending video streams. + This option defines which is used. If you choose mpeg you + should ensure that you have the appropriate plugins available + on your browser whereas choosing jpeg will work natively on + Mozilla and related browsers and with a Java applet on Internet + Explorer + "), + type => { + db_type =>"string", + hint =>"mpeg|jpeg", + pattern =>qr|^([mj])|i, + format =>q( $1 =~ /^m/ ? "mpeg" : "jpeg" ) + }, + category => "lowband", + }, + { + name => "ZM_WEB_L_DEFAULT_SCALE", + default => "100", + description => "What the default scaling factor applied to 'live' or 'event' views is (%)", + help => qqq(" + Normally ZoneMinder will display 'live' or 'event' streams in + their native size. However if you have monitors with large + dimensions or a slow link you may prefer to reduce this size, + alternatively for small monitors you can enlarge it. This + options lets you specify what the default scaling factor will + be. It is expressed as a percentage so 100 is normal size, 200 + is double size etc. + "), + type => { + db_type =>"integer", + hint =>"25|33|50|75|100|150|200|300|400", + pattern =>qr|^(\d+)$|, + format =>q( $1 ) + }, + category => "lowband", + }, + { + name => "ZM_WEB_L_DEFAULT_RATE", + default => "100", + description => "What the default replay rate factor applied to 'event' views is (%)", + help => qqq(" + Normally ZoneMinder will display 'event' streams at their + native rate, i.e. as close to real-time as possible. However if + you have long events it is often convenient to replay them at a + faster rate for review. This option lets you specify what the + default replay rate will be. It is expressed as a percentage so + 100 is normal rate, 200 is double speed etc. + "), + type => { + db_type =>"integer", + hint =>"25|50|100|150|200|400|1000|2500|5000|10000", + pattern =>qr|^(\d+)$|, format=>q( $1 ) + }, + category => "lowband", + }, + { + name => "ZM_WEB_L_VIDEO_BITRATE", + default => "25000", + description => "What the bitrate of the video encoded stream should be set to", + help => qqq(" + When encoding real video via the ffmpeg library a bit rate can + be specified which roughly corresponds to the available + bandwidth used for the stream. This setting effectively + corresponds to a 'quality' setting for the video. A low value + will result in a blocky image whereas a high value will produce + a clearer view. Note that this setting does not control the + frame rate of the video however the quality of the video + produced is affected both by this setting and the frame rate + that the video is produced at. A higher frame rate at a + particular bit rate result in individual frames being at a + lower quality. + "), + type => $types{integer}, + category => "lowband", + }, + { + name => "ZM_WEB_L_VIDEO_MAXFPS", + default => "5", + description => "What the maximum frame rate for streamed video should be", + help => qqq(" + When using streamed video the main control is the bitrate which + determines how much data can be transmitted. However a lower + bitrate at high frame rates results in a lower quality image. + This option allows you to limit the maximum frame rate to + ensure that video quality is maintained. An additional + advantage is that encoding video at high frame rates is a + processor intensive task when for the most part a very high + frame rate offers little perceptible improvement over one that + has a more manageable resource requirement. Note, this option + is implemented as a cap beyond which binary reduction takes + place. So if you have a device capturing at 15fps and set this + option to 10fps then the video is not produced at 10fps, but + rather at 7.5fps (15 divided by 2) as the final frame rate must + be the original divided by a power of 2. + "), + type => $types{integer}, + category => "lowband", + }, + { + name => "ZM_WEB_L_SCALE_THUMBS", + default => "yes", + description => "Scale thumbnails in events, bandwidth versus cpu in rescaling", + help => qqq(" + If unset, this option sends the whole image to the browser + which resizes it in the window. If set the image is scaled down + on the server before sending a reduced size image to the + browser to conserve bandwidth at the cost of cpu on the server. + Note that ZM can only perform the resizing if the appropriate + PHP graphics functionality is installed. This is usually + available in the php-gd package. + "), + type => $types{boolean}, + category => "lowband", + }, + { + name => "ZM_WEB_L_EVENTS_VIEW", + default => "events", + description => "What the default view of multiple events should be.", + help => qqq(" + Stored events can be viewed in either an events list format or + in a timeline based one. This option sets the default view that + will be used. Choosing one view here does not prevent the other + view being used as it will always be selectable from whichever + view is currently being used. + "), + type => { + db_type =>"string", + hint =>"events|timeline", + pattern =>qr|^([lt])|i, + format =>q( $1 =~ /^e/ ? "events" : "timeline" ) + }, + category => "lowband", + }, + { + name => "ZM_WEB_L_SHOW_PROGRESS", + default => "no", + description => "Show the progress of replay in event view.", + help => qqq(" + When viewing events an event navigation panel and progress bar + is shown below the event itself. This allows you to jump to + specific points in the event, but can can also dynamically + update to display the current progress of the event replay + itself. This progress is calculated from the actual event + duration and is not directly linked to the replay itself, so on + limited bandwidth connections may be out of step with the + replay. This option allows you to turn off the progress + display, whilst still keeping the navigation aspect, where + bandwidth prevents it functioning effectively. + "), + type => $types{boolean}, + category => "lowband", + }, + { + name => "ZM_WEB_L_AJAX_TIMEOUT", + default => "10000", + description => "How long to wait for Ajax request responses (ms)", + help => qqq(" + The newer versions of the live feed and event views use Ajax to + request information from the server and populate the views + dynamically. This option allows you to specify a timeout if + required after which requests are abandoned. A timeout may be + necessary if requests would overwise hang such as on a slow + connection. This would tend to consume a lot of browser memory + and make the interface unresponsive. Ordinarily no requests + should timeout so this setting should be set to a value greater + than the slowest expected response. This value is in + milliseconds but if set to zero then no timeout will be used. + "), + type => $types{integer}, + category => "lowband", + }, + { + name => "ZM_WEB_P_CAN_STREAM", + default => "auto", + description => "Override the automatic detection of browser streaming capability", + help => qqq(" + If you know that your browser can handle image streams of the + type 'multipart/x-mixed-replace' but ZoneMinder does not detect + this correctly you can set this option to ensure that the + stream is delivered with or without the use of the Cambozola + plugin. Selecting 'yes' will tell ZoneMinder that your browser + can handle the streams natively, 'no' means that it can't and + so the plugin will be used while 'auto' lets ZoneMinder decide. + "), + type => $types{tristate}, + category => "phoneband", + }, + { + name => "ZM_WEB_P_STREAM_METHOD", + default => "jpeg", + description => "Which method should be used to send video streams to your browser.", + help => qqq(" + ZoneMinder can be configured to use either mpeg encoded video + or a series or still jpeg images when sending video streams. + This option defines which is used. If you choose mpeg you + should ensure that you have the appropriate plugins available + on your browser whereas choosing jpeg will work natively on + Mozilla and related browsers and with a Java applet on Internet + Explorer + "), + type => { + db_type =>"string", + hint =>"mpeg|jpeg", + pattern =>qr|^([mj])|i, + format =>q( $1 =~ /^m/ ? "mpeg" : "jpeg" ) + }, + category => "phoneband", + }, + { + name => "ZM_WEB_P_DEFAULT_SCALE", + default => "100", + description => "What the default scaling factor applied to 'live' or 'event' views is (%)", + help => qqq(" + Normally ZoneMinder will display 'live' or 'event' streams in + their native size. However if you have monitors with large + dimensions or a slow link you may prefer to reduce this size, + alternatively for small monitors you can enlarge it. This + options lets you specify what the default scaling factor will + be. It is expressed as a percentage so 100 is normal size, 200 + is double size etc. + "), + type => { + db_type =>"integer", + hint =>"25|33|50|75|100|150|200|300|400", + pattern =>qr|^(\d+)$|, format=>q( $1 ) + }, + category => "phoneband", + }, + { + name => "ZM_WEB_P_DEFAULT_RATE", + default => "100", + description => "What the default replay rate factor applied to 'event' views is (%)", + help => qqq(" + Normally ZoneMinder will display 'event' streams at their + native rate, i.e. as close to real-time as possible. However if + you have long events it is often convenient to replay them at a + faster rate for review. This option lets you specify what the + default replay rate will be. It is expressed as a percentage so + 100 is normal rate, 200 is double speed etc. + "), + type => { + db_type =>"integer", + hint =>"25|50|100|150|200|400|1000|2500|5000|10000", + pattern =>qr|^(\d+)$|, + format =>q( $1 ) + }, + category => "phoneband", + }, + { + name => "ZM_WEB_P_VIDEO_BITRATE", + default => "8000", + description => "What the bitrate of the video encoded stream should be set to", + help => qqq(" + When encoding real video via the ffmpeg library a bit rate can + be specified which roughly corresponds to the available + bandwidth used for the stream. This setting effectively + corresponds to a 'quality' setting for the video. A low value + will result in a blocky image whereas a high value will produce + a clearer view. Note that this setting does not control the + frame rate of the video however the quality of the video + produced is affected both by this setting and the frame rate + that the video is produced at. A higher frame rate at a + particular bit rate result in individual frames being at a + lower quality. + "), + type => $types{integer}, + category => "phoneband", + }, + { + name => "ZM_WEB_P_VIDEO_MAXFPS", + default => "5", + description => "What the maximum frame rate for streamed video should be", + help => qqq(" + When using streamed video the main control is the bitrate which + determines how much data can be transmitted. However a lower + bitrate at high frame rates results in a lower quality image. + This option allows you to limit the maximum frame rate to + ensure that video quality is maintained. An additional + advantage is that encoding video at high frame rates is a + processor intensive task when for the most part a very high + frame rate offers little perceptible improvement over one that + has a more manageable resource requirement. Note, this option + is implemented as a cap beyond which binary reduction takes + place. So if you have a device capturing at 15fps and set this + option to 10fps then the video is not produced at 10fps, but + rather at 7.5fps (15 divided by 2) as the final frame rate must + be the original divided by a power of 2. + "), + type => $types{integer}, + category => "phoneband", + }, + { + name => "ZM_WEB_P_SCALE_THUMBS", + default => "yes", + description => "Scale thumbnails in events, bandwidth versus cpu in rescaling", + help => qqq(" + If unset, this option sends the whole image to the browser + which resizes it in the window. If set the image is scaled down + on the server before sending a reduced size image to the + browser to conserve bandwidth at the cost of cpu on the server. + Note that ZM can only perform the resizing if the appropriate + PHP graphics functionality is installed. This is usually + available in the php-gd package. + "), + type => $types{boolean}, + category => "phoneband", + }, + { + name => "ZM_WEB_P_AJAX_TIMEOUT", + default => "10000", + description => "How long to wait for Ajax request responses (ms)", + help => qqq(" + The newer versions of the live feed and event views use Ajax to + request information from the server and populate the views + dynamically. This option allows you to specify a timeout if + required after which requests are abandoned. A timeout may be + necessary if requests would overwise hang such as on a slow + connection. This would tend to consume a lot of browser memory + and make the interface unresponsive. Ordinarily no requests + should timeout so this setting should be set to a value greater + than the slowest expected response. This value is in + milliseconds but if set to zero then no timeout will be used. + "), + type => $types{integer}, + category => "phoneband", + }, + { + name => "ZM_DYN_LAST_VERSION", + default => "", + description => "What the last version of ZoneMinder recorded from zoneminder.com is", + help => "", + type => $types{string}, + readonly => 1, + category => "dynamic", + }, + { + name => "ZM_DYN_CURR_VERSION", + default => "@VERSION@", + description => qqq(" + What the effective current version of ZoneMinder is, might be + different from actual if versions ignored + "), + help => "", + type => $types{string}, + readonly => 1, + category => "dynamic", + }, + { + name => "ZM_DYN_DB_VERSION", + default => "@VERSION@", + description => "What the version of the database is, from zmupdate", + help => "", + type => $types{string}, + readonly => 1, + category => "dynamic", + }, + { + name => "ZM_DYN_LAST_CHECK", + default => "", + description => "When the last check for version from zoneminder.com was", + help => "", + type => $types{integer}, + readonly => 1, + category => "dynamic", + }, + { + name => "ZM_DYN_NEXT_REMINDER", + default => "", + description => "When the earliest time to remind about versions will be", + help => "", + type => $types{string}, + readonly => 1, + category => "dynamic", + }, + { + name => "ZM_DYN_DONATE_REMINDER_TIME", + default => 0, + description => "When the earliest time to remind about donations will be", + help => "", + type => $types{integer}, + readonly => 1, + category => "dynamic", + }, + { + name => "ZM_DYN_SHOW_DONATE_REMINDER", + default => "yes", + description => "Remind about donations or not", + help => "", + type => $types{boolean}, + readonly => 1, + category => "dynamic", + }, + { + name => "ZM_EYEZM_DEBUG", + default => "no", + description => "Switch additional debugging on for eyeZm Plugin", + help => qqq(" + Enable or Disable extra debugging from the eyeZm Plugin. Extra + debugging information will be displayed in it's own file + (EYEZM_LOG_TO_FILE is set), or your Apache error log + "), + type => $types{boolean}, + category => "eyeZm", + }, + { + name => "ZM_EYEZM_LOG_TO_FILE", + default => "yes", + description => "When eyeZm Debugging is enabled, enabling this logs output to it's own file", + help => qqq(" + When EYEZM_DEBUG is on and EYEZM_LOG_TO_FILE is on, output + generated from the eyeZm Plugin will go to it's own file. + Otherwise it will go to the apache error log. + "), + type => $types{boolean}, + category => "eyeZm", + }, + { + name => "ZM_EYEZM_LOG_FILE", + default => "@ZM_LOGDIR@/zm_xml.log", + description => "Default filename to use when logging eyeZm Output and EYEZM_LOG_TO_FILE is enabled", + help => qqq(" + This file will contain it's own output from the eyeZm Plugin + when EYEZM_LOG_TO_FILE and EYEZM_DEBUG are both enabled + "), + type => $types{string}, + category => "eyeZm", + }, + { + name => "ZM_EYEZM_EVENT_VCODEC", + default => "mpeg4", + description => "Default video-codec to use for encoding events", + help => qqq(" + The eyeZm Plugin calls FFMPEG externally to encode the captured + images. If your FFMPEG is not built with support for H264, + change this to MPEG-4. If using H264, please check + http://www.eyezm.com for H264 requirements and that your eyeZm + version supports H264 (v1.2+). + "), + type => { + db_type =>"string", + hint =>"mpeg4|h264", + pattern =>qr|^([mh])|i, + format =>q( $1 =~ /^m/ ? "mpeg4" : "h264" ) + }, + category => "eyeZm", + }, + { + name => "ZM_EYEZM_FEED_VCODEC", + default => "mjpeg", + description => "Default video-codec to use for streaming the live feed", + help => qqq(" + Determines whether the live stream is generated using native + MJPEG streaming with ZoneMinder, or H264 using FFMPEG and + HTML-5 streaming. If using H264, please check + http://www.eyezm.com for H264 requirements and that your eyeZm + version supports H264 (v1.2+). This is just a default + parameter, and can be overridden with eyeZm. + "), + type => { + db_type =>"string", + hint =>"mjpeg|h264", + pattern =>qr|^([mh])|i, + format =>q( $1 =~ /^m/ ? "mjpeg" : "h264" ) + }, + category => "eyeZm", + }, + { + name => "ZM_EYEZM_H264_DEFAULT_BR", + default => "96k", + description => "Default bit-rate to use with FFMPEG for H264 streaming", + help => qqq(" + When using the eyeZm Plugin to stream H264 data, FFMPEG + requires a bitrate to control the quality and bandwidth of the + video. This should be specified in a format acceptable to + FFMPEG. The default value is sufficient for most installations. + This is just a default parameter, and can be overridden with + eyeZm. + "), + type => $types{string}, + category => "eyeZm", + }, + { + name => "ZM_EYEZM_H264_DEFAULT_EVBR", + default => "128k", + description => "Default bit-rate to use with FFMPEG for H264 event viewing", + help => qqq(" + When using the eyeZm Plugin to view events in H264, FFMPEG + requires a bitrate to control the quality and bandwidth of the + video. This should be specified in a format acceptable to + FFMPEG. The default value is sufficient for most installations. + This is just a default parameter, and can be overridden with + eyeZm. + "), + type => $types{string}, + category => "eyeZm", + }, + { + name => "ZM_EYEZM_H264_TIMEOUT", + default => "20", + description => "Timeout (sec) to wait for H264 stream to start before terminating", + help => qqq(" + The eyeZm Plugin will attempt to spawn an H264 stream when + requested, and require that it complete within the timeout + specified. If you have a slow system or find through the logs + that the H264 stream is not starting because the timeout is + expiring, even though FFMPEG is running, try increasing this + value. If you have a fast system, decreasing this value can + improve the responsiveness when there are issues starting H264 + streams + "), + type => $types{string}, + category => "eyeZm", + }, + { + name => "ZM_EYEZM_SEG_DURATION", + default => "3", + description => "Segment duration used for streaming using HTTP-5 Streaming protocol", + help => qqq(" + The HTTP-5 Live Streaming Protocol segments the input video + stream into small chunks of a duration specified by this + parameter. Increasing the segment duration will help with + choppy connections on the other end, but will increase the + latency in starting a stream. + "), + type => $types{string}, + category => "eyeZm", + }, ); our %options_hash = map { ( $_->{name}, $_ ) } @options; @@ -1968,22 +4001,22 @@ sub initialiseConfig { return if ( $configInitialised ); - # Do some initial data munging to finish the data structures - # Create option ids - my $option_id = 0; - foreach my $option ( @options ) - { - if ( defined($option->{default}) ) - { - $option->{value} = $option->{default} - } - else - { - $option->{value} = ''; - } - #next if ( $option->{category} eq 'hidden' ); - $option->{id} = $option_id++; - } + # Do some initial data munging to finish the data structures + # Create option ids + my $option_id = 0; + foreach my $option ( @options ) + { + if ( defined($option->{default}) ) + { + $option->{value} = $option->{default} + } + else + { + $option->{value} = ''; + } + #next if ( $option->{category} eq 'hidden' ); + $option->{id} = $option_id++; + } $configInitialised = 1; } @@ -2004,9 +4037,15 @@ ZoneMinder::ConfigData - ZoneMinder Configuration Data module =head1 DESCRIPTION -The ZoneMinder:ConfigData module contains the master definition of the ZoneMinder configuration options as well as helper methods. This module is intended for specialist confguration management and would not normally be used by end users. +The ZoneMinder:ConfigData module contains the master definition of the +ZoneMinder configuration options as well as helper methods. This module is +intended for specialist confguration management and would not normally be +used by end users. -The configuration held in this module, which was previously in zmconfig.pl, includes the name, default value, description, help text, type and category for each option, as well as a number of additional fields in a small number of cases. +The configuration held in this module, which was previously in zmconfig.pl, +includes the name, default value, description, help text, type and category +for each option, as well as a number of additional fields in a small number +of cases. =head1 METHODS @@ -2014,11 +4053,19 @@ The configuration held in this module, which was previously in zmconfig.pl, incl =item loadConfigFromDB (); -Loads existing configuration from the database (if any) and merges it with the definitions held in this module. This results in the merging of any new configuration and the removal of any deprecated configuration while preserving the existing values of every else. +Loads existing configuration from the database (if any) and merges it with +the definitions held in this module. This results in the merging of any new +configuration and the removal of any deprecated configuration while +preserving the existing values of every else. =item saveConfigToDB (); -Saves configuration held in memory to the database. The act of loading and saving configuration is a convenient way to ensure that the configuration held in the database corresponds with the most recent definitions and that all components are using the same set of configuration. +Saves configuration held in memory to the database. The act of loading and +saving configuration is a convenient way to ensure that the configuration +held in the database corresponds with the most recent definitions and that +all components are using the same set of configuration. + +=back =head2 EXPORT diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Control.pm b/scripts/ZoneMinder/lib/ZoneMinder/Control.pm index 2a646772d..0822dc3d3 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Control.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Control.pm @@ -19,7 +19,7 @@ # # ========================================================================== # -# This module contains the base class definitions for the camera control +# This module contains the base class definitions for the camera control # protocol implementations # package ZoneMinder::Control; @@ -45,17 +45,17 @@ our $AUTOLOAD; sub new { - my $class = shift; - my $id = shift; - my $self = {}; - $self->{name} = "PelcoD"; + my $class = shift; + my $id = shift; + my $self = {}; + $self->{name} = "PelcoD"; if ( !defined($id) ) { Fatal( "No monitor defined when invoking protocol ".$self->{name} ); } - $self->{id} = $id; - bless( $self, $class ); - return $self; + $self->{id} = $id; + bless( $self, $class ); + return $self; } sub DESTROY @@ -64,32 +64,32 @@ sub DESTROY sub AUTOLOAD { - my $self = shift; - my $class = ref($self) || croak( "$self not object" ); - my $name = $AUTOLOAD; - $name =~ s/.*://; - if ( exists($self->{$name}) ) - { - return( $self->{$name} ); - } - croak( "Can't access $name member of object of class $class" ); + my $self = shift; + my $class = ref($self) || croak( "$self not object" ); + my $name = $AUTOLOAD; + $name =~ s/.*://; + if ( exists($self->{$name}) ) + { + return( $self->{$name} ); + } + croak( "Can't access $name member of object of class $class" ); } -sub getKey() +sub getKey { - my $self = shift; + my $self = shift; return( $self->{id} ); } sub open { - my $self = shift; + my $self = shift; Fatal( "No open method defined for protocol ".$self->{name} ); } sub close { - my $self = shift; + my $self = shift; Fatal( "No close method defined for protocol ".$self->{name} ); } @@ -145,9 +145,9 @@ sub executeCommand &{$self->{$command}}( $self, $params ); } -sub printMsg() +sub printMsg { - my $self = shift; + my $self = shift; Fatal( "No printMsg method defined for protocol ".$self->{name} ); } diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Control/3S.pm b/scripts/ZoneMinder/lib/ZoneMinder/Control/3S.pm index f825af109..47d783bff 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Control/3S.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Control/3S.pm @@ -21,10 +21,10 @@ # # This module contains the implementation of the 3S camera control # protocol -#Model: N5071 -#Hardware Version: 00 -#Firmware Version: V1.03_STD-1 -#Firmware Build Time: Jun 19 2012 15:28:17 +#Model: N5071 +#Hardware Version: 00 +#Firmware Version: V1.03_STD-1 +#Firmware Build Time: Jun 19 2012 15:28:17 package ZoneMinder::Control::3S; diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Control/FI8608W_Y2k.pm b/scripts/ZoneMinder/lib/ZoneMinder/Control/FI8608W_Y2k.pm index 7ffbf248a..2e5b21f76 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Control/FI8608W_Y2k.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Control/FI8608W_Y2k.pm @@ -53,7 +53,7 @@ our @ISA = qw(ZoneMinder::Control); # of the position of your mouse on the arrow. # Extremity of arrow equal to fastest speed of movement # Close the base of arrow to lowest speed of movement -# for diagonaly you can click before the begining of the arrow for low speed +# for diagonaly you can click before the beginning of the arrow for low speed # In round center equal to stop to move and switch of latest OSD # -You can clic directly on the image that equal to click on arrow (for the left there is a bug in zoneminder speed is inverted) # -Zoom Tele switch ON InfraRed LED and stay to manual IR MODE @@ -63,7 +63,7 @@ our @ISA = qw(ZoneMinder::Control); # -8 Preset PTZ are implemented and functionnal # -This Script use for login "admin" this hardcoded and your password must setup in "Control Device" section # -This script is compatible with the basic authentification method used by mostly new camera based with hi3510 chipset -# -AutoStop function is active and you must set up value (in sec exemple 0.7) under AutoStop section +# -AutoStop function is active and you must set up value (in sec example 0.7) under AutoStop section # or you can set up to 0 for disable it (in this case you need to click to the circle center for stop) # -"White In" to control Brightness, "auto" for restore the original value of Brightness # -"White Out" to control Contrast, "man" for restore the original value of Contrast @@ -129,7 +129,7 @@ sub printMsg } sub sendCmd -{ +{ my $self = shift; my $cmd = shift; my $result = undef; @@ -211,7 +211,7 @@ sub moveConUp if ( $tiltspeed < 10 ) { $tiltspeed = 1; } - Debug( "Move Up" ); + Debug( "Move Up" ); if ( $osd eq "on" ) { my $cmd = "param.cgi?cmd=setoverlayattr&-region=1&-show=1&-name=Move Up $tiltspeed"; @@ -658,9 +658,9 @@ sub presetGoto __END__ # Below is stub documentation for your module. You'd better edit it! -=head1 FI-8608W +=head1 NAME -ZoneMinder::Database - Perl extension for FOSCAM FI-8608W by Christophe_Y2k +ZoneMinder::Control::FI-8608W - Perl extension for FOSCAM FI-8608W by Christophe_Y2k =head1 SYNOPSIS diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Control/FI8620_Y2k.pm b/scripts/ZoneMinder/lib/ZoneMinder/Control/FI8620_Y2k.pm index 7d9cd261d..3e2addf85 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Control/FI8620_Y2k.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Control/FI8620_Y2k.pm @@ -57,7 +57,7 @@ our @ISA = qw(ZoneMinder::Control); # of the position of your mouse on the arrow. # Extremity of arrow equal to fastest speed of movement # Close the base of arrow to lowest speed of movement -# for diagonaly you can click before the begining of the arrow for low speed +# for diagonaly you can click before the beginning of the arrow for low speed # In round center equal to stop to move # -You can clic directly on the image that equal to click on arrow (for the left there is a bug in zoneminder speed is inverted) # -Zoom Tele/Wide with time control to simulate speed because speed value do not work (buggy firmware or not implemented on this cam) @@ -67,7 +67,7 @@ our @ISA = qw(ZoneMinder::Control); # You Need to configure ZoneMinder PANSPEED & TILTSEPPED & ZOOMSPEED 1 to 63 by 1 step # -This Script use for login "admin" this hardcoded and your password must setup in "Control Device" section # -This script is compatible with the basic authentification method used by mostly new camera -# -AutoStop function is active and you must set up value (in sec exemple 0.5) under AutoStop section +# -AutoStop function is active and you must set up value (in sec example 0.5) under AutoStop section # or you can set up to 0 for disable it but the camera never stop to move and trust me, she can move all the night... # (you need to click to the center arrow for stop) # -"White In" to control Brightness, "auto" for restore the original value of Brightness @@ -734,9 +734,9 @@ sub presetGoto __END__ # Below is stub documentation for your module. You'd better edit it! -=head1 FI8620 +=head1 NAME -ZoneMinder::Database - Perl extension for FOSCAM FI8620 +ZoneMinder::Control::FI8620 - Perl extension for FOSCAM FI8620 =head1 SYNOPSIS diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Control/FI8908W.pm b/scripts/ZoneMinder/lib/ZoneMinder/Control/FI8908W.pm index ab877c609..dd30484c3 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Control/FI8908W.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Control/FI8908W.pm @@ -43,176 +43,176 @@ use ZoneMinder::Config qw(:all); use Time::HiRes qw( usleep ); sub new -{ - my $class = shift; - my $id = shift; - my $self = ZoneMinder::Control->new( $id ); - bless( $self, $class ); - srand( time() ); - return $self; +{ + my $class = shift; + my $id = shift; + my $self = ZoneMinder::Control->new( $id ); + bless( $self, $class ); + srand( time() ); + return $self; } our $AUTOLOAD; sub AUTOLOAD { - my $self = shift; - my $class = ref($self) || croak( "$self not object" ); - my $name = $AUTOLOAD; - $name =~ s/.*://; - if ( exists($self->{$name}) ) - { - return( $self->{$name} ); - } - Fatal( "Can't access $name member of object of class $class" ); + my $self = shift; + my $class = ref($self) || croak( "$self not object" ); + my $name = $AUTOLOAD; + $name =~ s/.*://; + if ( exists($self->{$name}) ) + { + return( $self->{$name} ); + } + Fatal( "Can't access $name member of object of class $class" ); } sub open { - my $self = shift; + my $self = shift; - $self->loadMonitor(); + $self->loadMonitor(); - use LWP::UserAgent; - $self->{ua} = LWP::UserAgent->new; - $self->{ua}->agent( "ZoneMinder Control Agent/".ZoneMinder::Base::ZM_VERSION ); + use LWP::UserAgent; + $self->{ua} = LWP::UserAgent->new; + $self->{ua}->agent( "ZoneMinder Control Agent/".ZoneMinder::Base::ZM_VERSION ); - $self->{state} = 'open'; + $self->{state} = 'open'; } sub close { - my $self = shift; - $self->{state} = 'closed'; + my $self = shift; + $self->{state} = 'closed'; } sub printMsg { - my $self = shift; - my $msg = shift; - my $msg_len = length($msg); + my $self = shift; + my $msg = shift; + my $msg_len = length($msg); - Debug( $msg."[".$msg_len."]" ); + Debug( $msg."[".$msg_len."]" ); } sub sendCmd { - my $self = shift; - my $cmd = shift; - my $result = undef; + my $self = shift; + my $cmd = shift; + my $result = undef; - my ($user, $password) = split /:/, $self->{Monitor}->{ControlDevice}; + my ($user, $password) = split /:/, $self->{Monitor}->{ControlDevice}; - if ( !defined $password ) { - # If value of "Control device" does not consist of two parts, then only password is given and we fallback to default user: - $password = $user; - $user = 'admin'; - } + if ( !defined $password ) { + # If value of "Control device" does not consist of two parts, then only password is given and we fallback to default user: + $password = $user; + $user = 'admin'; + } - $cmd .= "user=$user&pwd=$password"; + $cmd .= "user=$user&pwd=$password"; - printMsg( $cmd, "Tx" ); + printMsg( $cmd, "Tx" ); - my $req = HTTP::Request->new( GET=>"http://".$self->{Monitor}->{ControlAddress}."/$cmd" ); - my $res = $self->{ua}->request($req); + my $req = HTTP::Request->new( GET=>"http://".$self->{Monitor}->{ControlAddress}."/$cmd" ); + my $res = $self->{ua}->request($req); - if ( $res->is_success ) - { - $result = !undef; - } - else - { - Error( "Error check failed: '".$res->status_line()."' for URL ".$req->uri() ); - } + if ( $res->is_success ) + { + $result = !undef; + } + else + { + Error( "Error check failed: '".$res->status_line()."' for URL ".$req->uri() ); + } - return( $result ); + return( $result ); } sub reset { - my $self = shift; - Debug( "Camera Reset" ); - $self->sendCmd( 'reboot.cgi?' ); + my $self = shift; + Debug( "Camera Reset" ); + $self->sendCmd( 'reboot.cgi?' ); } #Up Arrow sub moveConUp { - my $self = shift; - Debug( "Move Up" ); - $self->sendCmd( 'decoder_control.cgi?command=0&' ); + my $self = shift; + Debug( "Move Up" ); + $self->sendCmd( 'decoder_control.cgi?command=0&' ); } #Down Arrow sub moveConDown { - my $self = shift; - Debug( "Move Down" ); - $self->sendCmd( 'decoder_control.cgi?command=2&' ); + my $self = shift; + Debug( "Move Down" ); + $self->sendCmd( 'decoder_control.cgi?command=2&' ); } #Left Arrow sub moveConLeft { - my $self = shift; - Debug( "Move Left" ); - $self->sendCmd( 'decoder_control.cgi?command=6&' ); + my $self = shift; + Debug( "Move Left" ); + $self->sendCmd( 'decoder_control.cgi?command=6&' ); } #Right Arrow sub moveConRight { - my $self = shift; - Debug( "Move Right" ); - $self->sendCmd( 'decoder_control.cgi?command=4&' ); + my $self = shift; + Debug( "Move Right" ); + $self->sendCmd( 'decoder_control.cgi?command=4&' ); } #Diagonally Up Right Arrow sub moveConUpRight { - my $self = shift; - Debug( "Move Diagonally Up Right" ); - $self->sendCmd( 'decoder_control.cgi?command=90&' ); + my $self = shift; + Debug( "Move Diagonally Up Right" ); + $self->sendCmd( 'decoder_control.cgi?command=90&' ); } #Diagonally Down Right Arrow sub moveConDownRight { - my $self = shift; - Debug( "Move Diagonally Down Right" ); - $self->sendCmd( 'decoder_control.cgi?command=92&' ); + my $self = shift; + Debug( "Move Diagonally Down Right" ); + $self->sendCmd( 'decoder_control.cgi?command=92&' ); } #Diagonally Up Left Arrow sub moveConUpLeft { - my $self = shift; - Debug( "Move Diagonally Up Left" ); - $self->sendCmd( 'decoder_control.cgi?command=91&' ); + my $self = shift; + Debug( "Move Diagonally Up Left" ); + $self->sendCmd( 'decoder_control.cgi?command=91&' ); } #Diagonally Down Left Arrow sub moveConDownLeft { - my $self = shift; - Debug( "Move Diagonally Down Left" ); - $self->sendCmd( 'decoder_control.cgi?command=93&' ); + my $self = shift; + Debug( "Move Diagonally Down Left" ); + $self->sendCmd( 'decoder_control.cgi?command=93&' ); } #Stop sub moveStop { - my $self = shift; - Debug( "Move Stop" ); - $self->sendCmd( 'decoder_control.cgi?command=1&' ); + my $self = shift; + Debug( "Move Stop" ); + $self->sendCmd( 'decoder_control.cgi?command=1&' ); } #Move Camera to Home Position sub presetHome { - my $self = shift; - Debug( "Home Preset" ); - $self->sendCmd( 'decoder_control.cgi?command=25&' ); + my $self = shift; + Debug( "Home Preset" ); + $self->sendCmd( 'decoder_control.cgi?command=25&' ); } 1; @@ -220,12 +220,17 @@ sub presetHome __END__ =pod +=head1 NAME + +ZoneMinder::Control::FI8908W - Foscam FI8908W camera control + =head1 DESCRIPTION -This module contains the implementation of the Foscam FI8908W / FI8918W IP camera control -protocol. +This module contains the implementation of the Foscam FI8908W / FI8918W IP +camera control protocol. + +The module uses "Control Device" value to retrieve user and password. User +and password should be separated by colon, e.g. user:password. If colon is +not provided, then "admin" is used as a fallback value for the user. -The module uses "Control Device" value to retrieve user and password. User and password should -be separated by colon, e.g. user:password. If colon is not provided, then "admin" is used -as a fallback value for the user. =cut diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Control/FI9821W_Y2k.pm b/scripts/ZoneMinder/lib/ZoneMinder/Control/FI9821W_Y2k.pm index 4177f5857..dd73a04e6 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Control/FI9821W_Y2k.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Control/FI9821W_Y2k.pm @@ -102,7 +102,6 @@ sub close sub printMsg { - my $self = shift; my $msg = shift; my $msg_len = length($msg); Debug( $msg."[".$msg_len."]" ); @@ -113,9 +112,28 @@ sub sendCmd my $self = shift; my $cmd = shift; my $result = undef; + + my ($user, $password) = split /:/, $self->{Monitor}->{ControlDevice}; + if ( ! $password ) { + $password = $user; + $user = 'admin'; + } + $user = 'admin' if ! $user; + $password = 'pwd' if ! $password; + + $cmd .= "&usr=$user&pwd=$password"; + printMsg( $cmd, "Tx" ); - my $temps = time(); - my $req = HTTP::Request->new( GET=>"http://".$self->{Monitor}->{ControlAddress}."/cgi-bin/CGIProxy.fcgi?usr%3Dadmin%26pwd%3D".$self->{Monitor}->{ControlDevice}."%26cmd%3D".$cmd."%26".$temps ); + my $url; + if ( $self->{Monitor}->{ControlAddress} =~ /^http/ ) { + $url = $self->{Monitor}->{ControlAddress}; + } else { + $url = "http://".$self->{Monitor}->{ControlAddress}; + } + $url .= "/cgi-bin/CGIProxy.fcgi?cmd=$cmd%26".time; + printMsg( $url, "Tx" ); + + my $req = HTTP::Request->new( GET=>$url ); my $res = $self->{ua}->request($req); if ( $res->is_success ) { @@ -134,7 +152,7 @@ sub reset # Setup OSD my $cmd = "setOSDSetting%26isEnableTimeStamp%3D0%26isEnableDevName%3D1%26dispPos%3D0%26isEnabledOSDMask%3D0"; $self->sendCmd( $cmd ); - # Setup For Stream=0 Resolution=720p Bandwith=4M FPS=30 KeyFrameInterval/GOP=100 VBR=ON + # Setup For Stream=0 Resolution=720p Bandwidth=4M FPS=30 KeyFrameInterval/GOP=100 VBR=ON $cmd = "setVideoStreamParam%26streamType%3D0%26resolution%3D0%26bitRate%3D4194304%26frameRate%3D30%26GOP%3D100%26isVBR%3D1"; $self->sendCmd( $cmd ); # Setup For Infrared AUTO @@ -696,9 +714,9 @@ sub presetGoto __END__ # Below is stub documentation for your module. You'd better edit it! -=head1 FI9821W +=head1 NAME -ZoneMinder::Database - Perl extension for FOSCAM FI9821W +ZoneMinder::Control::FI9821W - Perl extension for FOSCAM FI9821W =head1 SYNOPSIS diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Control/M8640.pm b/scripts/ZoneMinder/lib/ZoneMinder/Control/M8640.pm index 584e04dd1..10bbea5de 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Control/M8640.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Control/M8640.pm @@ -107,14 +107,18 @@ sub sendCmd { printMsg( $cmd, "Tx" ); #print( "http://$address/$cmd\n" ); #my $req = HTTP::Request->new( GET=>"http://".$self->{Monitor}->{ControlAddress}."/$cmd" ); - - my $url; - if ( $self->{Monitor}->{ControlAddress} =~ /^http/ ) { - $url = $self->{Monitor}->{ControlAddress}.'/cgi-bin/setGPIO.cgi?preventCache='.time; - } else { - $url = 'http://'.$self->{Monitor}->{ControlAddress}.'/cgi-bin/setGPIO.cgi?preventCache='.time; - } # en dif - Error("Url: $url $cmd"); + + my $url; + if ( $self->{Monitor}->{ControlAddress} =~ /^http/ ) { + $url = $self->{Monitor}->{ControlAddress} + .'/cgi-bin/setGPIO.cgi?preventCache='.time + ; + } else { + $url = 'http://'.$self->{Monitor}->{ControlAddress} + .'/cgi-bin/setGPIO.cgi?preventCache='.time + ; + } # en dif + Error("Url: $url $cmd"); my $uri = URI::Encode->new( { encode_reserved => 0 } ); my $encoded = $uri->encode( $cmd ); my $res = $self->{ua}->post( $url, Content=>"data=$encoded" ); @@ -203,7 +207,11 @@ sub moveMap my $xcoord = $self->getParam( $params, 'xcoord' ); my $ycoord = $self->getParam( $params, 'ycoord' ); Debug( "Move Map to $xcoord,$ycoord" ); - my $cmd = "/axis-cgi/com/ptz.cgi?center=$xcoord,$ycoord&imagewidth=".$self->{Monitor}->{Width}."&imageheight=".$self->{Monitor}->{Height}; + my $cmd = "/axis-cgi/com/ptz.cgi?center=$xcoord,$ycoord&imagewidth=" + .$self->{Monitor}->{Width} + ."&imageheight=" + .$self->{Monitor}->{Height} + ; $self->sendCmd( $cmd ); } diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Control/PelcoP.pm b/scripts/ZoneMinder/lib/ZoneMinder/Control/PelcoP.pm index c9d9d907d..c8fafe023 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Control/PelcoP.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Control/PelcoP.pm @@ -22,7 +22,7 @@ # This module contains the implementation of the Pelco-P camera control # protocol # -package ZoneMinder::Control::PelcoD; +package ZoneMinder::Control::PelcoP; use 5.006; use strict; diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Control/TVIP862.pm b/scripts/ZoneMinder/lib/ZoneMinder/Control/TVIP862.pm index 7f5058dec..050e2bb75 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Control/TVIP862.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Control/TVIP862.pm @@ -60,16 +60,16 @@ our @ISA = qw(ZoneMinder::Control); # # ******** YOU MUST CHANGE THE FOLLOWING LINES TO MATCH YOUR CAMERA! ********** -# +# # I assume that "TV-IP672WI" would work for the TV-IP672WI, but can't test since I don't own one. -# +# # TV-IP672PI works for the PI version, of course. # # Finally, the username is the username you'd like to authenticate as. # our $REALM = 'TV-IP862IC'; our $USERNAME = 'admin'; -our $PASSWORD = ''; +our $PASSWORD = ''; our $ADDRESS = ''; # ========================================================================== @@ -111,26 +111,32 @@ sub open my $self = shift; $self->loadMonitor(); - my ( $protocol, $username, $password, $address ) = $self->{Monitor}->{ControlAddress} =~ /^(https?:\/\/)?([^:]+):([^\/@]+)@(.*)$/; - if ( $username ) { - $USERNAME = $username; - $PASSWORD = $password; - $ADDRESS = $address; - } else { - Error( "Failed to parse auth from address"); - $ADDRESS = $self->{Monitor}->{ControlAddress}; - } - if ( ! $ADDRESS =~ /:/ ) { - Error( "You generally need to also specify the port. I will append :80" ); - $ADDRESS .= ':80'; - } + my ( $protocol, $username, $password, $address ) + = $self->{Monitor}->{ControlAddress} =~ /^(https?:\/\/)?([^:]+):([^\/@]+)@(.*)$/; + if ( $username ) { + $USERNAME = $username; + $PASSWORD = $password; + $ADDRESS = $address; + } else { + Error( "Failed to parse auth from address"); + $ADDRESS = $self->{Monitor}->{ControlAddress}; + } + if ( ! $ADDRESS =~ /:/ ) { + Error( "You generally need to also specify the port. I will append :80" ); + $ADDRESS .= ':80'; + } use LWP::UserAgent; $self->{ua} = LWP::UserAgent->new; $self->{ua}->agent( "ZoneMinder Control Agent/".$ZoneMinder::Base::ZM_VERSION ); $self->{state} = 'open'; -# credentials: ("ip:port" (no prefix!), realm (string), username (string), password (string) - Debug ( "sendCmd credentials control address:'".$ADDRESS."' realm:'" . $REALM . "' username:'" . $USERNAME . "' password:'".$PASSWORD."'"); +# credentials: ("ip:port" (no prefix!), realm (string), username (string), password (string) + Debug ( "sendCmd credentials control address:'".$ADDRESS + ."' realm:'" . $REALM + . "' username:'" . $USERNAME + . "' password:'".$PASSWORD + ."'" + ); $self->{ua}->credentials($ADDRESS,$REALM,$USERNAME,$PASSWORD); } @@ -159,29 +165,29 @@ sub sendCmd my $result = undef; - my $url = "http://".$ADDRESS."/cgi/ptdc.cgi?command=".$cmd; + my $url = "http://".$ADDRESS."/cgi/ptdc.cgi?command=".$cmd; my $req = HTTP::Request->new( GET=>$url ); Debug ("sendCmd command: " . $url ); - + my $res = $self->{ua}->request($req); if ( $res->is_success ) { $result = !undef; } else { - if ( $res->status_line() eq '401 Unauthorized' ) { - Error( "Error check failed, trying again: USERNAME: $USERNAME realm: $REALM password: " . $PASSWORD ); - Error("Content was " . $res->content() ); - my $res = $self->{ua}->request($req); - if ( $res->is_success ) { - $result = !undef; - } else { - Error("Content was " . $res->content() ); - } - } - if ( ! $result ) { - Error( "Error check failed: '".$res->status_line()."' cmd:'".$cmd."'" ); - } + if ( $res->status_line() eq '401 Unauthorized' ) { + Error( "Error check failed, trying again: USERNAME: $USERNAME realm: $REALM password: " . $PASSWORD ); + Error("Content was " . $res->content() ); + my $res = $self->{ua}->request($req); + if ( $res->is_success ) { + $result = !undef; + } else { + Error("Content was " . $res->content() ); + } + } + if ( ! $result ) { + Error( "Error check failed: '".$res->status_line()."' cmd:'".$cmd."'" ); + } } return( $result ); @@ -203,10 +209,10 @@ sub sendCmdPost my $result = undef; if ($url eq undef) - { - Error ("url passed to sendCmdPost is undefined."); - return(-1); - } + { + Error ("url passed to sendCmdPost is undefined."); + return(-1); + } Debug ("sendCmdPost url: " . $url . " cmd: " . $cmd); @@ -215,7 +221,7 @@ sub sendCmdPost $req->content($cmd); Debug ( "sendCmdPost credentials control address:'".$ADDRESS."' realm:'" . $REALM . "' username:'" . $USERNAME . "' password:'".$PASSWORD."'"); - + my $res = $self->{ua}->request($req); if ( $res->is_success ) @@ -225,11 +231,11 @@ sub sendCmdPost else { Error( "sendCmdPost Error check failed: '".$res->status_line()."' cmd:'".$cmd."'" ); - if ( $res->status_line() eq '401 Unauthorized' ) { - Error( "sendCmdPost Error check failed: USERNAME: $USERNAME realm: $REALM password: " . $PASSWORD ); - } else { - Error( "sendCmdPost Error check failed: USERNAME: $USERNAME realm: $REALM password: " . $PASSWORD ); - } # endif + if ( $res->status_line() eq '401 Unauthorized' ) { + Error( "sendCmdPost Error check failed: USERNAME: $USERNAME realm: $REALM password: " . $PASSWORD ); + } else { + Error( "sendCmdPost Error check failed: USERNAME: $USERNAME realm: $REALM password: " . $PASSWORD ); + } # endif } return( $result ); diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Control/Wanscam.pm b/scripts/ZoneMinder/lib/ZoneMinder/Control/Wanscam.pm index b2ed3e2b5..f419aacfc 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Control/Wanscam.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Control/Wanscam.pm @@ -16,8 +16,8 @@ # Rename to Wanscam # Pan Left/Right switched # IR On/Off switched -# Brightness Increase/Decrease in 16 steps -# +# Brightness Increase/Decrease in 16 steps +# # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Control/mjpgStreamer.pm b/scripts/ZoneMinder/lib/ZoneMinder/Control/mjpgStreamer.pm index 255dac056..18a73cae8 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Control/mjpgStreamer.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Control/mjpgStreamer.pm @@ -126,32 +126,32 @@ sub sendCmd sub Up { my $self = shift; - $self->moveConUp(); + $self->moveConUp(); } sub Down { my $self = shift; - $self->moveConDown(); + $self->moveConDown(); } sub Left { my $self = shift; - $self->moveConLeft(); + $self->moveConLeft(); } sub Right { my $self = shift; - $self->moveConRight(); + $self->moveConRight(); } sub reset { my $self = shift; - $self->cameraReset(); + $self->cameraReset(); } diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Control/onvif.pm b/scripts/ZoneMinder/lib/ZoneMinder/Control/onvif.pm index 09ef59c8e..76b161582 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Control/onvif.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Control/onvif.pm @@ -36,7 +36,7 @@ our %CamParams = (); # ========================================================================== # # ONVIF Control Protocol -# +# # On ControlAddress use the format : # USERNAME:PASSWORD@ADDRESS:PORT # eg : admin:@10.1.2.1:80 @@ -50,7 +50,7 @@ use ZoneMinder::Config qw(:all); use Time::HiRes qw( usleep ); sub new -{ +{ my $class = shift; my $id = shift; @@ -90,7 +90,7 @@ sub open } sub close -{ +{ my $self = shift; $self->{state} = 'closed'; } @@ -133,7 +133,7 @@ sub getCamParams my $req = HTTP::Request->new( GET=>"http://".$self->{Monitor}->{ControlAddress}."/get_camera_params.cgi" ); my $res = $self->{ua}->request($req); - if ( $res->is_success ) + if ( $res->is_success ) { # Parse results setting values in %FCParams my $content = $res->decoded_content; @@ -141,7 +141,7 @@ sub getCamParams while ($content =~ s/var\s+([^=]+)=([^;]+);//ms) { $CamParams{$1} = $2; } - } + } else { Error( "Error check failed:'".$res->status_line()."'" ); diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Database.pm b/scripts/ZoneMinder/lib/ZoneMinder/Database.pm index 29b3c8b2a..7dfe0654b 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Database.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Database.pm @@ -19,7 +19,7 @@ # # ========================================================================== # -# This module contains the common definitions and functions used by the rest +# This module contains the common definitions and functions used by the rest # of the ZoneMinder scripts # package ZoneMinder::Database; @@ -37,17 +37,17 @@ our @ISA = qw(Exporter ZoneMinder::Base); # names by default without a very good reason. Use EXPORT_OK instead. # Do not simply export all your public functions/methods/constants. -# This allows declaration use ZoneMinder ':all'; +# This allows declaration use ZoneMinder ':all'; # If you do not need this, moving things directly into @EXPORT or @EXPORT_OK # will save memory. our %EXPORT_TAGS = ( 'functions' => [ qw( - zmDbConnect - zmDbDisconnect - zmDbGetMonitors - zmDbGetMonitor - zmDbGetMonitorAndControl - ) ] + zmDbConnect + zmDbDisconnect + zmDbGetMonitors + zmDbGetMonitor + zmDbGetMonitorAndControl + ) ] ); push( @{$EXPORT_TAGS{all}}, @{$EXPORT_TAGS{$_}} ) foreach keys %EXPORT_TAGS; @@ -70,37 +70,46 @@ use Carp; our $dbh = undef; -sub zmDbConnect( ;$ ) +sub zmDbConnect { - my $force = shift; - if ( $force ) - { - zmDbDisconnect(); - } - if ( !defined( $dbh ) ) - { + my $force = shift; + if ( $force ) + { + zmDbDisconnect(); + } + if ( !defined( $dbh ) ) + { my ( $host, $port ) = ( $Config{ZM_DB_HOST} =~ /^([^:]+)(?::(.+))?$/ ); if ( defined($port) ) { - $dbh = DBI->connect( "DBI:mysql:database=".$Config{ZM_DB_NAME}.";host=".$host.";port=".$port, $Config{ZM_DB_USER}, $Config{ZM_DB_PASS} ); + $dbh = DBI->connect( "DBI:mysql:database=".$Config{ZM_DB_NAME} + .";host=".$host + .";port=".$port + , $Config{ZM_DB_USER} + , $Config{ZM_DB_PASS} + ); } else { - $dbh = DBI->connect( "DBI:mysql:database=".$Config{ZM_DB_NAME}.";host=".$Config{ZM_DB_HOST}, $Config{ZM_DB_USER}, $Config{ZM_DB_PASS} ); + $dbh = DBI->connect( "DBI:mysql:database=".$Config{ZM_DB_NAME} + .";host=".$Config{ZM_DB_HOST} + , $Config{ZM_DB_USER} + , $Config{ZM_DB_PASS} + ); } $dbh->trace( 0 ); - } - return( $dbh ); + } + return( $dbh ); } -sub zmDbDisconnect() +sub zmDbDisconnect { - if ( defined( $dbh ) ) - { - $dbh->disconnect(); - $dbh = undef; - } + if ( defined( $dbh ) ) + { + $dbh->disconnect(); + $dbh = undef; + } } use constant DB_MON_ALL => 0; # All monitors @@ -110,78 +119,88 @@ use constant DB_MON_MOTION => 3; # All monitors that are doing motion detection use constant DB_MON_RECORD => 4; # All monitors that are doing unconditional recording use constant DB_MON_PASSIVE => 5; # All monitors that are in nodect state -sub zmDbGetMonitors( ;$ ) +sub zmDbGetMonitors { - zmDbConnect(); + zmDbConnect(); - my $function = shift || DB_MON_ALL; - my $sql = "select * from Monitors"; + my $function = shift || DB_MON_ALL; + my $sql = "select * from Monitors"; - if ( $function ) - { - if ( $function == DB_MON_CAPT ) - { - $sql .= " where Function >= 'Monitor'"; - } - elsif ( $function == DB_MON_ACTIVE ) - { - $sql .= " where Function > 'Monitor'"; - } - elsif ( $function == DB_MON_MOTION ) - { - $sql .= " where Function = 'Modect' or Function = 'Mocord'"; - } - elsif ( $function == DB_MON_RECORD ) - { - $sql .= " where Function = 'Record' or Function = 'Mocord'"; - } - elsif ( $function == DB_MON_PASSIVE ) - { - $sql .= " where Function = 'Nodect'"; - } - } - my $sth = $dbh->prepare_cached( $sql ) or croak( "Can't prepare '$sql': ".$dbh->errstr() ); - my $res = $sth->execute() or croak( "Can't execute '$sql': ".$sth->errstr() ); + if ( $function ) + { + if ( $function == DB_MON_CAPT ) + { + $sql .= " where Function >= 'Monitor'"; + } + elsif ( $function == DB_MON_ACTIVE ) + { + $sql .= " where Function > 'Monitor'"; + } + elsif ( $function == DB_MON_MOTION ) + { + $sql .= " where Function = 'Modect' or Function = 'Mocord'"; + } + elsif ( $function == DB_MON_RECORD ) + { + $sql .= " where Function = 'Record' or Function = 'Mocord'"; + } + elsif ( $function == DB_MON_PASSIVE ) + { + $sql .= " where Function = 'Nodect'"; + } + } + my $sth = $dbh->prepare_cached( $sql ) + or croak( "Can't prepare '$sql': ".$dbh->errstr() ); + my $res = $sth->execute() + or croak( "Can't execute '$sql': ".$sth->errstr() ); - my @monitors; + my @monitors; while( my $monitor = $sth->fetchrow_hashref() ) { - push( @monitors, $monitor ); - } - $sth->finish(); - return( \@monitors ); + push( @monitors, $monitor ); + } + $sth->finish(); + return( \@monitors ); } -sub zmDbGetMonitor( $ ) +sub zmDbGetMonitor { - zmDbConnect(); + zmDbConnect(); - my $id = shift; + my $id = shift; - return( undef ) if ( !defined($id) ); + return( undef ) if ( !defined($id) ); - my $sql = "select * from Monitors where Id = ?"; - my $sth = $dbh->prepare_cached( $sql ) or croak( "Can't prepare '$sql': ".$dbh->errstr() ); - my $res = $sth->execute( $id ) or croak( "Can't execute '$sql': ".$sth->errstr() ); + my $sql = "select * from Monitors where Id = ?"; + my $sth = $dbh->prepare_cached( $sql ) + or croak( "Can't prepare '$sql': ".$dbh->errstr() ); + my $res = $sth->execute( $id ) + or croak( "Can't execute '$sql': ".$sth->errstr() ); my $monitor = $sth->fetchrow_hashref(); - return( $monitor ); + return( $monitor ); } -sub zmDbGetMonitorAndControl( $ ) +sub zmDbGetMonitorAndControl { - zmDbConnect(); + zmDbConnect(); - my $id = shift; + my $id = shift; - return( undef ) if ( !defined($id) ); + return( undef ) if ( !defined($id) ); - my $sql = "select C.*,M.*,C.Protocol from Monitors as M inner join Controls as C on (M.ControlId = C.Id) where M.Id = ?"; - my $sth = $dbh->prepare_cached( $sql ) or Fatal( "Can't prepare '$sql': ".$dbh->errstr() ); - my $res = $sth->execute( $id ) or Fatal( "Can't execute '$sql': ".$sth->errstr() ); + my $sql = "SELECT C.*,M.*,C.Protocol + FROM Monitors as M + INNER JOIN Controls as C on (M.ControlId = C.Id) + WHERE M.Id = ?" + ; + my $sth = $dbh->prepare_cached( $sql ) + or Fatal( "Can't prepare '$sql': ".$dbh->errstr() ); + my $res = $sth->execute( $id ) + or Fatal( "Can't execute '$sql': ".$sth->errstr() ); my $monitor = $sth->fetchrow_hashref(); - return( $monitor ); + return( $monitor ); } 1; diff --git a/scripts/ZoneMinder/lib/ZoneMinder/General.pm b/scripts/ZoneMinder/lib/ZoneMinder/General.pm index 4d60852a7..195bd265f 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/General.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/General.pm @@ -19,7 +19,7 @@ # # ========================================================================== # -# This module contains the common definitions and functions used by the rest +# This module contains the common definitions and functions used by the rest # of the ZoneMinder scripts # package ZoneMinder::General; @@ -76,7 +76,7 @@ use ZoneMinder::Database qw(:all); use POSIX; # For running general shell commands -sub executeShellCommand( $ ) +sub executeShellCommand { my $command = shift; my $output = qx( $command ); @@ -90,7 +90,7 @@ sub executeShellCommand( $ ) return( $status ); } -sub getCmdFormat() +sub getCmdFormat { Debug( "Testing valid shell syntax\n" ); @@ -162,7 +162,7 @@ our $testedShellSyntax = 0; our ( $cmdPrefix, $cmdSuffix ); # For running ZM daemons etc -sub runCommand( $ ) +sub runCommand { if ( !$testedShellSyntax ) { @@ -196,30 +196,45 @@ sub runCommand( $ ) return( $output ); } -sub getEventPath( $ ) +sub getEventPath { my $event = shift; my $event_path = ""; if ( $Config{ZM_USE_DEEP_STORAGE} ) { - $event_path = $Config{ZM_DIR_EVENTS}.'/'.$event->{MonitorId}.'/'.strftime( "%y/%m/%d/%H/%M/%S", localtime($event->{Time}) ); + $event_path = $Config{ZM_DIR_EVENTS} + .'/'.$event->{MonitorId} + .'/'.strftime( "%y/%m/%d/%H/%M/%S", + localtime($event->{Time}) + ) + ; } else { - $event_path = $Config{ZM_DIR_EVENTS}.'/'.$event->{MonitorId}.'/'.$event->{Id}; + $event_path = $Config{ZM_DIR_EVENTS} + .'/'.$event->{MonitorId} + .'/'.$event->{Id} + ; + } + + if ( index($Config{ZM_DIR_EVENTS},'/') != 0 ){ + $event_path = $Config{ZM_PATH_WEB} + .'/'.$event_path + ; } - $event_path = $Config{ZM_PATH_WEB}.'/'.$event_path if ( index($Config{ZM_DIR_EVENTS},'/') != 0 ); return( $event_path ); } -sub createEventPath( $ ) +sub createEventPath { # # WARNING assumes running from events directory # my $event = shift; - my $eventRootPath = ($Config{ZM_DIR_EVENTS}=~m|/|)?$Config{ZM_DIR_EVENTS}:($Config{ZM_PATH_WEB}.'/'.$Config{ZM_DIR_EVENTS}); + my $eventRootPath = ($Config{ZM_DIR_EVENTS}=~m|/|) + ? $Config{ZM_DIR_EVENTS} + : ($Config{ZM_PATH_WEB}.'/'.$Config{ZM_DIR_EVENTS}); my $eventPath = $eventRootPath.'/'.$event->{MonitorId}; if ( $Config{ZM_USE_DEEP_STORAGE} ) @@ -242,7 +257,8 @@ sub createEventPath( $ ) # Create event id symlink my $idFile = sprintf( "%s/.%d", $eventPath, $event->{Id} ); - symlink( $timePath, $idFile ) or Fatal( "Can't symlink $idFile -> $eventPath: $!" ); + symlink( $timePath, $idFile ) + or Fatal( "Can't symlink $idFile -> $eventPath: $!" ); makePath( $timePath, $eventPath ); $eventPath .= '/'.$timePath; @@ -250,8 +266,9 @@ sub createEventPath( $ ) # Create empty id tag file $idFile = sprintf( "%s/.%d", $eventPath, $event->{Id} ); - open( ID_FP, ">$idFile" ) or Fatal( "Can't open $idFile: $!" ); - close( ID_FP ); + open( my $ID_FP, ">", $idFile ) + or Fatal( "Can't open $idFile: $!" ); + close( $ID_FP ); setFileOwner( $idFile ); } else @@ -260,8 +277,9 @@ sub createEventPath( $ ) $eventPath .= '/'.$event->{Id}; my $idFile = sprintf( "%s/.%d", $eventPath, $event->{Id} ); - open( ID_FP, ">$idFile" ) or Fatal( "Can't open $idFile: $!" ); - close( ID_FP ); + open( my $ID_FP, ">", $idFile ) + or Fatal( "Can't open $idFile: $!" ); + close( $ID_FP ); setFileOwner( $idFile ); } return( $eventPath ); @@ -272,15 +290,20 @@ use Data::Dumper; our $_setFileOwner = undef; our ( $_ownerUid, $_ownerGid ); -sub _checkProcessOwner() +sub _checkProcessOwner { if ( !defined($_setFileOwner) ) { my ( $processOwner ) = getpwuid( $> ); if ( $processOwner ne $Config{ZM_WEB_USER} ) { - # Not running as web user, so should be root in whch case chown the temporary directory - ( my $ownerName, my $ownerPass, $_ownerUid, $_ownerGid ) = getpwnam( $Config{ZM_WEB_USER} ) or Fatal( "Can't get user details for web user '".$Config{ZM_WEB_USER}."': $!" ); + # Not running as web user, so should be root in which case chown + # the temporary directory + ( my $ownerName, my $ownerPass, $_ownerUid, $_ownerGid ) + = getpwnam( $Config{ZM_WEB_USER} ) + or Fatal( "Can't get user details for web user '" + .$Config{ZM_WEB_USER}."': $!" + ); $_setFileOwner = 1; } else @@ -291,19 +314,22 @@ sub _checkProcessOwner() return( $_setFileOwner ); } -sub setFileOwner( $ ) +sub setFileOwner { my $file = shift; if ( _checkProcessOwner() ) { - chown( $_ownerUid, $_ownerGid, $file ) or Fatal( "Can't change ownership of file '$file' to '".$Config{ZM_WEB_USER}.":".$Config{ZM_WEB_GROUP}."': $!" ); + chown( $_ownerUid, $_ownerGid, $file ) + or Fatal( "Can't change ownership of file '$file' to '" + .$Config{ZM_WEB_USER}.":".$Config{ZM_WEB_GROUP}."': $!" + ); } } our $_hasImageInfo = undef; -sub _checkForImageInfo() +sub _checkForImageInfo { if ( !defined($_hasImageInfo) ) { @@ -317,7 +343,7 @@ sub _checkForImageInfo() return( $_hasImageInfo ); } -sub createEvent( $;$ ) +sub createEvent { my $event = shift; @@ -335,9 +361,14 @@ sub createEvent( $;$ ) elsif ( $event->{MonitorId} ) { my $sql = "select * from Monitors where Id = ?"; - my $sth = $dbh->prepare_cached( $sql ) or Fatal( "Can't prepare sql '$sql': ".$dbh->errstr() ); - my $res = $sth->execute( $event->{MonitorId} ) or Fatal( "Can't execute sql '$sql': ".$sth->errstr() ); - $event->{monitor} = $sth->fetchrow_hashref() or Fatal( "Unable to create event, can't load monitor with id '".$event->{MonitorId}."'" ); + my $sth = $dbh->prepare_cached( $sql ) + or Fatal( "Can't prepare sql '$sql': ".$dbh->errstr() ); + my $res = $sth->execute( $event->{MonitorId} ) + or Fatal( "Can't execute sql '$sql': ".$sth->errstr() ); + $event->{monitor} = $sth->fetchrow_hashref() + or Fatal( "Unable to create event, can't load monitor with id '" + .$event->{MonitorId}."'" + ); $sth->finish(); } else @@ -358,7 +389,9 @@ sub createEvent( $;$ ) my $imageInfo = Image::Info::image_info( $frame->{imagePath} ); if ( $imageInfo->{error} ) { - Error( "Unable to extract image info from '".$frame->{imagePath}."': ".$imageInfo->{error} ); + Error( "Unable to extract image info from '" + .$frame->{imagePath}."': ".$imageInfo->{error} + ); } else { @@ -394,18 +427,25 @@ sub createEvent( $;$ ) push( @values, $event->{$field} ); } - my $sql = "insert into Events (".join(',',@fields).") values (".join(',',@formats).")"; - my $sth = $dbh->prepare_cached( $sql ) or Fatal( "Can't prepare sql '$sql': ".$dbh->errstr() ); - my $res = $sth->execute( @values ) or Fatal( "Can't execute sql '$sql': ".$sth->errstr() ); + my $sql = "INSERT INTO Events (".join(',',@fields) + .") VALUES (".join(',',@formats).")" + ; + my $sth = $dbh->prepare_cached( $sql ) + or Fatal( "Can't prepare sql '$sql': ".$dbh->errstr() ); + my $res = $sth->execute( @values ) + or Fatal( "Can't execute sql '$sql': ".$sth->errstr() ); $event->{Id} = $dbh->{mysql_insertid}; Info( "Created event ".$event->{Id} ); if ( $event->{EndTime} ) { - $event->{Name} = $event->{monitor}->{EventPrefix}.$event->{Id} if ( $event->{Name} eq 'New Event' ); + $event->{Name} = $event->{monitor}->{EventPrefix}.$event->{Id} + if ( $event->{Name} eq 'New Event' ); my $sql = "update Events set Name = ? where Id = ?"; - my $sth = $dbh->prepare_cached( $sql ) or Fatal( "Can't prepare sql '$sql': ".$dbh->errstr() ); - my $res = $sth->execute( $event->{Name}, $event->{Id} ) or Fatal( "Can't execute sql '$sql': ".$sth->errstr() ); + my $sth = $dbh->prepare_cached( $sql ) + or Fatal( "Can't prepare sql '$sql': ".$dbh->errstr() ); + my $res = $sth->execute( $event->{Name}, $event->{Id} ) + or Fatal( "Can't execute sql '$sql': ".$sth->errstr() ); } my $eventPath = createEventPath( $event ); @@ -428,26 +468,46 @@ sub createEvent( $;$ ) push( @values, $frame->{$field} ); } - my $sql = "insert into Frames (".join(',',@fields).") values (".join(',',@formats).")"; - my $sth = $dbh->prepare_cached( $sql ) or Fatal( "Can't prepare sql '$sql': ".$dbh->errstr() ); - my $res = $sth->execute( @values ) or Fatal( "Can't execute sql '$sql': ".$sth->errstr() ); + my $sql = "insert into Frames (".join(',',@fields) + .") values (".join(',',@formats).")" + ; + my $sth = $dbh->prepare_cached( $sql ) + or Fatal( "Can't prepare sql '$sql': ".$dbh->errstr() ); + my $res = $sth->execute( @values ) + or Fatal( "Can't execute sql '$sql': ".$sth->errstr() ); #$frame->{FrameId} = $dbh->{mysql_insertid}; if ( $frame->{imagePath} ) { - $frame->{capturePath} = sprintf( "%s/%0".$Config{ZM_EVENT_IMAGE_DIGITS}."d-capture.jpg", $eventPath, $frame->{FrameId} ); - rename( $frame->{imagePath}, $frame->{capturePath} ) or Fatal( "Can't copy ".$frame->{imagePath}." to ".$frame->{capturePath}.": $!" ); + $frame->{capturePath} = sprintf( + "%s/%0".$Config{ZM_EVENT_IMAGE_DIGITS} + ."d-capture.jpg" + , $eventPath + , $frame->{FrameId} + ); + rename( $frame->{imagePath}, $frame->{capturePath} ) + or Fatal( "Can't copy ".$frame->{imagePath} + ." to ".$frame->{capturePath}.": $!" + ); setFileOwner( $frame->{capturePath} ); if ( 0 && $Config{ZM_CREATE_ANALYSIS_IMAGES} ) { - $frame->{analysePath} = sprintf( "%s/%0".$Config{ZM_EVENT_IMAGE_DIGITS}."d-analyse.jpg", $eventPath, $frame->{FrameId} ); - link( $frame->{capturePath}, $frame->{analysePath} ) or Fatal( "Can't link ".$frame->{capturePath}." to ".$frame->{analysePath}.": $!" ); + $frame->{analysePath} = sprintf( + "%s/%0".$Config{ZM_EVENT_IMAGE_DIGITS} + ."d-analyse.jpg" + , $eventPath + , $frame->{FrameId} + ); + link( $frame->{capturePath}, $frame->{analysePath} ) + or Fatal( "Can't link ".$frame->{capturePath} + ." to ".$frame->{analysePath}.": $!" + ); setFileOwner( $frame->{analysePath} ); } } } } -sub addEventImage( $$ ) +sub addEventImage { my $event = shift; my $frame = shift; @@ -455,7 +515,7 @@ sub addEventImage( $$ ) # TBD } -sub updateEvent( $ ) +sub updateEvent { my $event = shift; @@ -467,7 +527,8 @@ sub updateEvent( $ ) my $dbh = zmDbConnect(); - $event->{Name} = $event->{monitor}->{EventPrefix}.$event->{Id} if ( $event->{Name} eq 'New Event' ); + $event->{Name} = $event->{monitor}->{EventPrefix}.$event->{Id} + if ( $event->{Name} eq 'New Event' ); my %formats = ( StartTime => 'from_unixtime(?)', @@ -484,11 +545,13 @@ sub updateEvent( $ ) my $sql = "update Events set ".join(',',@sets)." where Id = ?"; push( @values, $event->{Id} ); - my $sth = $dbh->prepare_cached( $sql ) or Fatal( "Can't prepare sql '$sql': ".$dbh->errstr() ); - my $res = $sth->execute( @values ) or Fatal( "Can't execute sql '$sql': ".$sth->errstr() ); + my $sth = $dbh->prepare_cached( $sql ) + or Fatal( "Can't prepare sql '$sql': ".$dbh->errstr() ); + my $res = $sth->execute( @values ) + or Fatal( "Can't execute sql '$sql': ".$sth->errstr() ); } -sub deleteEventFiles( $;$ ) +sub deleteEventFiles { # # WARNING assumes running from events directory @@ -541,7 +604,7 @@ sub deleteEventFiles( $;$ ) } } -sub makePath( $;$ ) +sub makePath { my $path = shift; my $root = shift; @@ -585,7 +648,7 @@ sub _testJSON $hasJSONAny = 1 if ( $result ); } -sub _getJSONType( $ ) +sub _getJSONType { my $value = shift; return( 'null' ) unless( defined($value) ); @@ -596,9 +659,9 @@ sub _getJSONType( $ ) return( 'string' ); } -sub jsonEncode( $ ); +sub jsonEncode; -sub jsonEncode( $ ) +sub jsonEncode { my $value = shift; @@ -649,7 +712,7 @@ sub jsonEncode( $ ) } } -sub jsonDecode( $ ) +sub jsonDecode { my $value = shift; diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Logger.pm b/scripts/ZoneMinder/lib/ZoneMinder/Logger.pm index 5b4438c72..a6a82db87 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Logger.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Logger.pm @@ -19,7 +19,7 @@ # # ========================================================================== # -# This module contains the debug definitions and functions used by the rest +# This module contains the debug definitions and functions used by the rest # of the ZoneMinder scripts # package ZoneMinder::Logger; @@ -126,6 +126,7 @@ our %priorities = ( ); our $logger; +our $LOGFILE; sub new { @@ -257,7 +258,12 @@ sub initialise( @ ) { foreach my $target ( split( /\|/, $Config{ZM_LOG_DEBUG_TARGET} ) ) { - if ( $target eq $this->{id} || $target eq "_".$this->{id} || $target eq $this->{idRoot} || $target eq "_".$this->{idRoot} || $target eq "" ) + if ( $target eq $this->{id} + || $target eq "_".$this->{id} + || $target eq $this->{idRoot} + || $target eq "_".$this->{idRoot} + || $target eq "" + ) { if ( $Config{ZM_LOG_DEBUG_LEVEL} > NOLOG ) { @@ -286,11 +292,18 @@ sub initialise( @ ) $this->{autoFlush} = $ENV{'LOG_FLUSH'}?1:0 if ( defined($ENV{'LOG_FLUSH'}) ); $this->{initialised} = !undef; - - Debug( "LogOpts: level=".$codes{$this->{level}}."/".$codes{$this->{effectiveLevel}}.", screen=".$codes{$this->{termLevel}}.", database=".$codes{$this->{databaseLevel}}.", logfile=".$codes{$this->{fileLevel}}."->".$this->{logFile}.", syslog=".$codes{$this->{syslogLevel}} ); + + Debug( "LogOpts: level=".$codes{$this->{level}} + ."/".$codes{$this->{effectiveLevel}} + .", screen=".$codes{$this->{termLevel}} + .", database=".$codes{$this->{databaseLevel}} + .", logfile=".$codes{$this->{fileLevel}} + ."->".$this->{logFile} + .", syslog=".$codes{$this->{syslogLevel}} + ); } -sub terminate() +sub terminate { my $this = shift; return unless ( $this->{initialised} ); @@ -300,7 +313,7 @@ sub terminate() $this->termLevel( NOLOG ); } -sub reinitialise() +sub reinitialise { my $this = shift; @@ -322,7 +335,7 @@ sub reinitialise() $this->databaseLevel( $databaseLevel ) if ( $databaseLevel > NOLOG ); } -sub limit( $ ) +sub limit { my $this = shift; my $level = shift; @@ -331,7 +344,7 @@ sub limit( $ ) return( $level ); } -sub getTargettedEnv( $ ) +sub getTargettedEnv { my $this = shift; my $name = shift; @@ -354,7 +367,7 @@ sub getTargettedEnv( $ ) return( $value ); } -sub fetch() +sub fetch { if ( !$logger ) { @@ -364,7 +377,7 @@ sub fetch() return( $logger ); } -sub id( ;$ ) +sub id { my $this = shift; my $id = shift; @@ -388,7 +401,7 @@ sub id( ;$ ) return( $this->{id} ); } -sub level( ;$ ) +sub level { my $this = shift; my $level = shift; @@ -405,20 +418,20 @@ sub level( ;$ ) return( $this->{level} ); } -sub debugOn() +sub debugOn { my $this = shift; return( $this->{effectiveLevel} >= DEBUG ); } -sub trace( ;$ ) +sub trace { my $this = shift; $this->{trace} = $_[0] if ( @_ ); return( $this->{trace} ); } -sub termLevel( ;$ ) +sub termLevel { my $this = shift; my $termLevel = shift; @@ -434,7 +447,7 @@ sub termLevel( ;$ ) return( $this->{termLevel} ); } -sub databaseLevel( ;$ ) +sub databaseLevel { my $this = shift; my $databaseLevel = shift; @@ -451,23 +464,39 @@ sub databaseLevel( ;$ ) if ( defined($port) ) { - $this->{dbh} = DBI->connect( "DBI:mysql:database=".$Config{ZM_DB_NAME}.";host=".$host.";port=".$port, $Config{ZM_DB_USER}, $Config{ZM_DB_PASS} ); + $this->{dbh} = DBI->connect( "DBI:mysql:database=".$Config{ZM_DB_NAME} + .";host=".$host + .";port=".$port + , $Config{ZM_DB_USER} + , $Config{ZM_DB_PASS} + ); } else { - $this->{dbh} = DBI->connect( "DBI:mysql:database=".$Config{ZM_DB_NAME}.";host=".$Config{ZM_DB_HOST}, $Config{ZM_DB_USER}, $Config{ZM_DB_PASS} ); + $this->{dbh} = DBI->connect( "DBI:mysql:database=".$Config{ZM_DB_NAME} + .";host=".$Config{ZM_DB_HOST} + , $Config{ZM_DB_USER} + , $Config{ZM_DB_PASS} + ); } if ( !$this->{dbh} ) { $databaseLevel = NOLOG; - Error( "Unable to write log entries to DB, can't connect to database '".$Config{ZM_DB_NAME}."' on host '".$Config{ZM_DB_HOST}."'" ); + Error( "Unable to write log entries to DB, can't connect to database '" + .$Config{ZM_DB_NAME} + ."' on host '" + .$Config{ZM_DB_HOST} + ."'" + ); } else { $this->{dbh}->{AutoCommit} = 1; - Fatal( "Can't set AutoCommit on in database connection" ) unless( $this->{dbh}->{AutoCommit} ); + Fatal( "Can't set AutoCommit on in database connection" ) + unless( $this->{dbh}->{AutoCommit} ); $this->{dbh}->{mysql_auto_reconnect} = 1; - Fatal( "Can't set mysql_auto_reconnect on in database connection" ) unless( $this->{dbh}->{mysql_auto_reconnect} ); + Fatal( "Can't set mysql_auto_reconnect on in database connection" ) + unless( $this->{dbh}->{mysql_auto_reconnect} ); $this->{dbh}->trace( 0 ); } } @@ -486,7 +515,7 @@ sub databaseLevel( ;$ ) return( $this->{databaseLevel} ); } -sub fileLevel( ;$ ) +sub fileLevel { my $this = shift; my $fileLevel = shift; @@ -503,7 +532,7 @@ sub fileLevel( ;$ ) return( $this->{fileLevel} ); } -sub syslogLevel( ;$ ) +sub syslogLevel { my $this = shift; my $syslogLevel = shift; @@ -520,19 +549,19 @@ sub syslogLevel( ;$ ) return( $this->{syslogLevel} ); } -sub openSyslog() +sub openSyslog { my $this = shift; openlog( $this->{id}, "pid", "local1" ); } -sub closeSyslog() +sub closeSyslog { my $this = shift; #closelog(); } -sub logFile( $ ) +sub logFile { my $this = shift; my $logFile = shift; @@ -546,18 +575,21 @@ sub logFile( $ ) } } -sub openFile() +sub openFile { my $this = shift; - if ( open( LOGFILE, ">>".$this->{logFile} ) ) + if ( open( $LOGFILE, ">>", $this->{logFile} ) ) { - LOGFILE->autoflush() if ( $this->{autoFlush} ); + $LOGFILE->autoflush() if ( $this->{autoFlush} ); my $webUid = (getpwnam( $Config{ZM_WEB_USER} ))[2]; my $webGid = (getgrnam( $Config{ZM_WEB_GROUP} ))[2]; if ( $> == 0 ) { - chown( $webUid, $webGid, $this->{logFile} ) or Fatal( "Can't change permissions on log file '".$this->{logFile}."': $!" ) + chown( $webUid, $webGid, $this->{logFile} ) + or Fatal( "Can't change permissions on log file '" + .$this->{logFile}."': $!" + ) } } else @@ -567,13 +599,13 @@ sub openFile() } } -sub closeFile() +sub closeFile { my $this = shift; - close( LOGFILE ) if ( fileno(LOGFILE) ); + close( $LOGFILE ) if ( fileno($LOGFILE) ); } -sub logPrint( $;$ ) +sub logPrint { my $this = shift; my $level = shift; @@ -586,7 +618,17 @@ sub logPrint( $;$ ) my $code = $codes{$level}; my ($seconds, $microseconds) = gettimeofday(); - my $message = sprintf( "%s.%06d %s[%d].%s [%s]", strftime( "%x %H:%M:%S", localtime( $seconds ) ), $microseconds, $this->{id}, $$, $code, $string ); + my $message = sprintf( + "%s.%06d %s[%d].%s [%s]" + , strftime( "%x %H:%M:%S" + ,localtime( $seconds ) + ) + , $microseconds + , $this->{id} + , $$ + , $code + , $string + ); if ( $this->{trace} ) { $message = Carp::shortmess( $message ); @@ -595,8 +637,9 @@ sub logPrint( $;$ ) { $message = $message."\n"; } - syslog( $priorities{$level}, $code." [%s]", $string ) if ( $level <= $this->{syslogLevel} ); - print( LOGFILE $message ) if ( $level <= $this->{fileLevel} ); + syslog( $priorities{$level}, $code." [%s]", $string ) + if ( $level <= $this->{syslogLevel} ); + print( $LOGFILE $message ) if ( $level <= $this->{fileLevel} ); if ( $level <= $this->{databaseLevel} ) { my $sql = "insert into Logs ( TimeKey, Component, Pid, Level, Code, Message, File, Line ) values ( ?, ?, ?, ?, ?, ?, ?, NULL )"; @@ -606,7 +649,14 @@ sub logPrint( $;$ ) $this->{databaseLevel} = NOLOG; Fatal( "Can't prepare log entry '$sql': ".$this->{dbh}->errstr() ); } - my $res = $this->{sth}->execute( $seconds+($microseconds/1000000.0), $this->{id}, $$, $level, $code, $string, $this->{fileName} ); + my $res = $this->{sth}->execute( $seconds+($microseconds/1000000.0) + , $this->{id} + , $$ + , $level + , $code + , $string + , $this->{fileName} + ); if ( !$res ) { $this->{databaseLevel} = NOLOG; @@ -624,7 +674,7 @@ sub logInit( ;@ ) $logger->initialise( %options ); } -sub logReinit() +sub logReinit { fetch()->reinitialise(); } @@ -636,7 +686,7 @@ sub logTerm $logger = undef; } -sub logHupHandler() +sub logHupHandler { my $savedErrno = $!; return unless( $logger ); @@ -645,47 +695,47 @@ sub logHupHandler() $! = $savedErrno; } -sub logSetSignal() +sub logSetSignal { $SIG{HUP} = \&logHupHandler; } -sub logClearSignal() +sub logClearSignal { $SIG{HUP} = 'DEFAULT'; } -sub logLevel( ;$ ) +sub logLevel { return( fetch()->level( @_ ) ); } -sub logDebugging() +sub logDebugging { return( fetch()->debugOn() ); } -sub logTermLevel( ;$ ) +sub logTermLevel { return( fetch()->termLevel( @_ ) ); } -sub logDatabaseLevel( ;$ ) +sub logDatabaseLevel { return( fetch()->databaseLevel( @_ ) ); } -sub logFileLevel( ;$ ) +sub logFileLevel { return( fetch()->fileLevel( @_ ) ); } -sub logSyslogLevel( ;$ ) +sub logSyslogLevel { return( fetch()->syslogLevel( @_ ) ); } -sub Mark( ;$$ ) +sub Mark { my $level = shift; $level = DEBUG unless( defined($level) ); @@ -693,7 +743,7 @@ sub Mark( ;$$ ) fetch()->logPrint( $level, $tag ); } -sub Dump( \$;$ ) +sub Dump { my $var = shift; my $label = shift; @@ -756,11 +806,19 @@ ZoneMinder::Logger - ZoneMinder Logger module =head1 DESCRIPTION -The ZoneMinder:Logger module contains the common debug and error reporting routines used by the ZoneMinder scripts. +The ZoneMinder:Logger module contains the common debug and error reporting +routines used by the ZoneMinder scripts. -To use debug in your scripts you need to include this module, and call logInit. Thereafter you can sprinkle Debug or Error calls etc throughout the code safe in the knowledge that they will be reported to your error log, and possibly the syslogger, in a meaningful and consistent format. +To use debug in your scripts you need to include this module, and call +logInit. Thereafter you can sprinkle Debug or Error calls etc throughout +the code safe in the knowledge that they will be reported to your error +log, and possibly the syslogger, in a meaningful and consistent format. -Debug is discussed in terms of levels where 1 and above (currently only 1 for scripts) is considered debug, 0 is considered as informational, -1 is a warning, -2 is an error and -3 is a fatal error or panic. Where levels are mentioned below as thresholds the value given and anything with a lower level (ie. more serious) will be included. +Debug is discussed in terms of levels where 1 and above (currently only 1 +for scripts) is considered debug, 0 is considered as informational, -1 is a +warning, -2 is an error and -3 is a fatal error or panic. Where levels are +mentioned below as thresholds the value given and anything with a lower +level (ie. more serious) will be included. =head1 METHODS @@ -768,7 +826,12 @@ Debug is discussed in terms of levels where 1 and above (currently only 1 for sc =item logInit ( $id, %options ); -Initialises the debug and prepares the logging for forthcoming operations. If not called explicitly it will be called by the first debug call in your script, but with default (and probably meaningless) options. The only compulsory arguments are $id which must be a string that will identify debug coming from this script in mixed logs. Other options may be provided as below, +Initialises the debug and prepares the logging for forthcoming operations. +If not called explicitly it will be called by the first debug call in your +script, but with default (and probably meaningless) options. The only +compulsory arguments are $id which must be a string that will identify +debug coming from this script in mixed logs. Other options may be provided +as below, Option Default Description --------- --------- ----------- @@ -805,27 +868,41 @@ These methods can be used to get and set the current settings as defined in logI =item Debug( $string ); -This method will output a debug message if the current debug level permits it, otherwise does nothing. This message will be tagged with the DBG string in the logs. +This method will output a debug message if the current debug level permits +it, otherwise does nothing. This message will be tagged with the DBG string +in the logs. =item Info( $string ); -This method will output an informational message if the current debug level permits it, otherwise does nothing. This message will be tagged with the INF string in the logs. +This method will output an informational message if the current debug level +permits it, otherwise does nothing. This message will be tagged with the +INF string in the logs. =item Warning( $string ); -This method will output a warning message if the current debug level permits it, otherwise does nothing. This message will be tagged with the WAR string in the logs. +This method will output a warning message if the current debug level +permits it, otherwise does nothing. This message will be tagged with the +WAR string in the logs. =item Error( $string ); -This method will output an error message if the current debug level permits it, otherwise does nothing. This message will be tagged with the ERR string in the logs. +This method will output an error message if the current debug level permits +it, otherwise does nothing. This message will be tagged with the ERR string +in the logs. =item Fatal( $string ); -This method will output a fatal error message and then die if the current debug level permits it, otherwise does nothing. This message will be tagged with the FAT string in the logs. +This method will output a fatal error message and then die if the current +debug level permits it, otherwise does nothing. This message will be tagged +with the FAT string in the logs. =item Panic( $string ); -This method will output a panic error message and then die with a stack trace if the current debug level permits it, otherwise does nothing. This message will be tagged with the PNC string in the logs. +This method will output a panic error message and then die with a stack +trace if the current debug level permits it, otherwise does nothing. This +message will be tagged with the PNC string in the logs. + +=back =head2 EXPORT @@ -841,7 +918,8 @@ The :all tag will export all above symbols. Carp Sys::Syslog -The ZoneMinder README file Troubleshooting section for an extended discussion on the use and configuration of syslog with ZoneMinder. +The ZoneMinder README file Troubleshooting section for an extended +discussion on the use and configuration of syslog with ZoneMinder. http://www.zoneminder.com diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Memory.pm.in b/scripts/ZoneMinder/lib/ZoneMinder/Memory.pm.in index 844074911..8e7b9228e 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Memory.pm.in +++ b/scripts/ZoneMinder/lib/ZoneMinder/Memory.pm.in @@ -19,7 +19,7 @@ # # ========================================================================== # -# This module contains the common definitions and functions used by the rest +# This module contains the common definitions and functions used by the rest # of the ZoneMinder scripts # package ZoneMinder::Memory; @@ -37,48 +37,48 @@ our @ISA = qw(Exporter ZoneMinder::Base); # names by default without a very good reason. Use EXPORT_OK instead. # Do not simply export all your public functions/methods/constants. -# This allows declaration use ZoneMinder ':all'; +# This allows declaration use ZoneMinder ':all'; # If you do not need this, moving things directly into @EXPORT or @EXPORT_OK # will save memory. our %EXPORT_TAGS = ( - 'constants' => [ qw( - STATE_IDLE - STATE_PREALARM - STATE_ALARM - STATE_ALERT - STATE_TAPE - ACTION_GET - ACTION_SET - ACTION_RELOAD - ACTION_SUSPEND - ACTION_RESUME - TRIGGER_CANCEL - TRIGGER_ON - TRIGGER_OFF - ) ], - 'functions' => [ qw( - zmMemVerify - zmMemInvalidate - zmMemRead - zmMemWrite - zmMemTidy - zmGetMonitorState - zmGetAlarmLocation - zmIsAlarmed - zmInAlarm - zmHasAlarmed - zmGetLastEvent - zmGetLastWriteTime - zmGetLastReadTime - zmMonitorEnable - zmMonitorDisable - zmMonitorSuspend - zmMonitorResume - zmTriggerEventOn - zmTriggerEventOff - zmTriggerEventCancel - zmTriggerShowtext - ) ], + 'constants' => [ qw( + STATE_IDLE + STATE_PREALARM + STATE_ALARM + STATE_ALERT + STATE_TAPE + ACTION_GET + ACTION_SET + ACTION_RELOAD + ACTION_SUSPEND + ACTION_RESUME + TRIGGER_CANCEL + TRIGGER_ON + TRIGGER_OFF + ) ], + 'functions' => [ qw( + zmMemVerify + zmMemInvalidate + zmMemRead + zmMemWrite + zmMemTidy + zmGetMonitorState + zmGetAlarmLocation + zmIsAlarmed + zmInAlarm + zmHasAlarmed + zmGetLastEvent + zmGetLastWriteTime + zmGetLastReadTime + zmMonitorEnable + zmMonitorDisable + zmMonitorSuspend + zmMonitorResume + zmTriggerEventOn + zmTriggerEventOff + zmTriggerEventCancel + zmTriggerShowtext + ) ], ); push( @{$EXPORT_TAGS{all}}, @{$EXPORT_TAGS{$_}} ) foreach keys %EXPORT_TAGS; @@ -144,48 +144,42 @@ our $mem_seq = 0; our $mem_data = { - "shared_data" => { "type"=>"SharedData", "seq"=>$mem_seq++, "contents"=> { - "size" => { "type"=>"uint32", "seq"=>$mem_seq++ }, - "last_write_index" => { "type"=>"uint32", "seq"=>$mem_seq++ }, - "last_read_index" => { "type"=>"uint32", "seq"=>$mem_seq++ }, - "state" => { "type"=>"uint32", "seq"=>$mem_seq++ }, - "last_event" => { "type"=>"uint32", "seq"=>$mem_seq++ }, - "action" => { "type"=>"uint32", "seq"=>$mem_seq++ }, - "brightness" => { "type"=>"int32", "seq"=>$mem_seq++ }, - "hue" => { "type"=>"int32", "seq"=>$mem_seq++ }, - "colour" => { "type"=>"int32", "seq"=>$mem_seq++ }, - "contrast" => { "type"=>"int32", "seq"=>$mem_seq++ }, - "alarm_x" => { "type"=>"int32", "seq"=>$mem_seq++ }, - "alarm_y" => { "type"=>"int32", "seq"=>$mem_seq++ }, - "valid" => { "type"=>"uint8", "seq"=>$mem_seq++ }, - "active" => { "type"=>"uint8", "seq"=>$mem_seq++ }, - "signal" => { "type"=>"uint8", "seq"=>$mem_seq++ }, - "format" => { "type"=>"uint8", "seq"=>$mem_seq++ }, - "imagesize" => { "type"=>"uint32", "seq"=>$mem_seq++ }, - "epadding1" => { "type"=>"uint32", "seq"=>$mem_seq++ }, - "epadding2" => { "type"=>"uint32", "seq"=>$mem_seq++ }, - "last_write_time" => { "type"=>"time_t64", "seq"=>$mem_seq++ }, - "last_read_time" => { "type"=>"time_t64", "seq"=>$mem_seq++ }, - "control_state" => { "type"=>"uint8[256]", "seq"=>$mem_seq++ }, - } - }, - "trigger_data" => { "type"=>"TriggerData", "seq"=>$mem_seq++, "contents"=> { - "size" => { "type"=>"uint32", "seq"=>$mem_seq++ }, - "trigger_state" => { "type"=>"uint32", "seq"=>$mem_seq++ }, - "trigger_score" => { "type"=>"uint32", "seq"=>$mem_seq++ }, - "padding" => { "type"=>"uint32", "seq"=>$mem_seq++ }, - "trigger_cause" => { "type"=>"int8[32]", "seq"=>$mem_seq++ }, - "trigger_text" => { "type"=>"int8[256]", "seq"=>$mem_seq++ }, - "trigger_showtext" => { "type"=>"int8[256]", "seq"=>$mem_seq++ }, - } - }, - "video_store_data" => { "type"=>"VideoStoreData", "seq"=>$mem_seq++, "contents"=> { + "shared_data" => { "type"=>"SharedData", "seq"=>$mem_seq++, "contents"=> { "size" => { "type"=>"uint32", "seq"=>$mem_seq++ }, - "event_directory" => { "type"=>"int8[4096]", "seq"=>$mem_seq++ }, - "recording" => { "type"=>"uint32", "seq"=>$mem_seq++ }, - } - }, - "end" => { "seq"=>$mem_seq++, "size"=> 0 } + "last_write_index" => { "type"=>"uint32", "seq"=>$mem_seq++ }, + "last_read_index" => { "type"=>"uint32", "seq"=>$mem_seq++ }, + "state" => { "type"=>"uint32", "seq"=>$mem_seq++ }, + "last_event" => { "type"=>"uint32", "seq"=>$mem_seq++ }, + "action" => { "type"=>"uint32", "seq"=>$mem_seq++ }, + "brightness" => { "type"=>"int32", "seq"=>$mem_seq++ }, + "hue" => { "type"=>"int32", "seq"=>$mem_seq++ }, + "colour" => { "type"=>"int32", "seq"=>$mem_seq++ }, + "contrast" => { "type"=>"int32", "seq"=>$mem_seq++ }, + "alarm_x" => { "type"=>"int32", "seq"=>$mem_seq++ }, + "alarm_y" => { "type"=>"int32", "seq"=>$mem_seq++ }, + "valid" => { "type"=>"uint8", "seq"=>$mem_seq++ }, + "active" => { "type"=>"uint8", "seq"=>$mem_seq++ }, + "signal" => { "type"=>"uint8", "seq"=>$mem_seq++ }, + "format" => { "type"=>"uint8", "seq"=>$mem_seq++ }, + "imagesize" => { "type"=>"uint32", "seq"=>$mem_seq++ }, + "epadding1" => { "type"=>"uint32", "seq"=>$mem_seq++ }, + "epadding2" => { "type"=>"uint32", "seq"=>$mem_seq++ }, + "last_write_time" => { "type"=>"time_t64", "seq"=>$mem_seq++ }, + "last_read_time" => { "type"=>"time_t64", "seq"=>$mem_seq++ }, + "control_state" => { "type"=>"uint8[256]", "seq"=>$mem_seq++ }, + } + }, + "trigger_data" => { "type"=>"TriggerData", "seq"=>$mem_seq++, "contents"=> { + "size" => { "type"=>"uint32", "seq"=>$mem_seq++ }, + "trigger_state" => { "type"=>"uint32", "seq"=>$mem_seq++ }, + "trigger_score" => { "type"=>"uint32", "seq"=>$mem_seq++ }, + "padding" => { "type"=>"uint32", "seq"=>$mem_seq++ }, + "trigger_cause" => { "type"=>"int8[32]", "seq"=>$mem_seq++ }, + "trigger_text" => { "type"=>"int8[256]", "seq"=>$mem_seq++ }, + "trigger_showtext" => { "type"=>"int8[256]", "seq"=>$mem_seq++ }, + } + }, + "end" => { "seq"=>$mem_seq++, "size"=> 0 } }; our $mem_size = 0; @@ -193,222 +187,248 @@ our $mem_verified = {}; sub zmMemInit { - my $offset = 0; + my $offset = 0; - foreach my $section_data ( sort { $a->{seq} <=> $b->{seq} } values( %$mem_data ) ) - { - $section_data->{offset} = $offset; - $section_data->{align} = 0; + foreach my $section_data ( sort { $a->{seq} <=> $b->{seq} } values( %$mem_data ) ) + { + $section_data->{offset} = $offset; + $section_data->{align} = 0; - if ( $section_data->{align} > 1 ) - { - my $rem = $offset % $section_data->{align}; - if ( $rem > 0 ) - { - $offset += ($section_data->{align} - $rem); - } - } - foreach my $member_data ( sort { $a->{seq} <=> $b->{seq} } values( %{$section_data->{contents}} ) ) - { - if ( $member_data->{type} eq "long" || $member_data->{type} eq "ulong" || $member_data->{type} eq "size_t") - { - $member_data->{size} = $member_data->{align} = $native; - } - elsif( $member_data->{type} eq "int64" || $member_data->{type} eq "uint64" || $member_data->{type} eq "time_t64") - { - $member_data->{size} = $member_data->{align} = 8; - } - elsif ( $member_data->{type} eq "int32" || $member_data->{type} eq "uint32" || $member_data->{type} eq "bool4" ) - { - $member_data->{size} = $member_data->{align} = 4; - } - elsif ($member_data->{type} eq "int16" || $member_data->{type} eq "uint16") - { - $member_data->{size} = $member_data->{align} = 2; - } - elsif ( $member_data->{type} eq "int8" || $member_data->{type} eq "uint8" || $member_data->{type} eq "bool1" ) - { - $member_data->{size} = $member_data->{align} = 1; - } - elsif ( $member_data->{type} =~ /^u?int8\[(\d+)\]$/ ) - { - $member_data->{size} = $1; - $member_data->{align} = 1; - } - else - { - Fatal( "Unexpected type '".$member_data->{type}."' found in shared data definition." ); - } + if ( $section_data->{align} > 1 ) + { + my $rem = $offset % $section_data->{align}; + if ( $rem > 0 ) + { + $offset += ($section_data->{align} - $rem); + } + } + foreach my $member_data ( sort { $a->{seq} <=> $b->{seq} } values( %{$section_data->{contents}} ) ) + { + if ( $member_data->{type} eq "long" + || $member_data->{type} eq "ulong" + || $member_data->{type} eq "size_t" + ) + { + $member_data->{size} = $member_data->{align} = $native; + } + elsif( $member_data->{type} eq "int64" + || $member_data->{type} eq "uint64" + || $member_data->{type} eq "time_t64" + ) + { + $member_data->{size} = $member_data->{align} = 8; + } + elsif ( $member_data->{type} eq "int32" + || $member_data->{type} eq "uint32" + || $member_data->{type} eq "bool4" + ) + { + $member_data->{size} = $member_data->{align} = 4; + } + elsif ($member_data->{type} eq "int16" + || $member_data->{type} eq "uint16" + ) + { + $member_data->{size} = $member_data->{align} = 2; + } + elsif ( $member_data->{type} eq "int8" + || $member_data->{type} eq "uint8" + || $member_data->{type} eq "bool1" + ) + { + $member_data->{size} = $member_data->{align} = 1; + } + elsif ( $member_data->{type} =~ /^u?int8\[(\d+)\]$/ ) + { + $member_data->{size} = $1; + $member_data->{align} = 1; + } + else + { + Fatal( "Unexpected type '".$member_data->{type} + ."' found in shared data definition." + ); + } - if ( $member_data->{align} > 1 && ($offset%$member_data->{align}) > 0 ) - { - $offset += ($member_data->{align} - ($offset%$member_data->{align})); - } - $member_data->{offset} = $offset; - $offset += $member_data->{size} - } - $section_data->{size} = $offset - $section_data->{offset}; - } + if ( $member_data->{align} > 1 && ($offset%$member_data->{align}) > 0 ) + { + $offset += ($member_data->{align} - ($offset%$member_data->{align})); + } + $member_data->{offset} = $offset; + $offset += $member_data->{size} + } + $section_data->{size} = $offset - $section_data->{offset}; + } - $mem_size = $offset; + $mem_size = $offset; } &zmMemInit(); -sub zmMemVerify( $ ) +sub zmMemVerify { - my $monitor = shift; - if ( !zmMemAttach( $monitor, $mem_size ) ) - { - return( undef ); - } + my $monitor = shift; + if ( !zmMemAttach( $monitor, $mem_size ) ) + { + return( undef ); + } my $mem_key = zmMemKey( $monitor ); - if ( !defined($mem_verified->{$mem_key}) ) - { - my $sd_size = zmMemRead( $monitor, "shared_data:size", 1 ); - if ( $sd_size != $mem_data->{shared_data}->{size} ) - { - if ( $sd_size ) - { - Error( "Shared data size conflict in shared_data for monitor ".$monitor->{Name}.", expected ".$mem_data->{shared_data}->{size}.", got ".$sd_size ); - } - else - { - Debug( "Shared data size conflict in shared_data for monitor ".$monitor->{Name}.", expected ".$mem_data->{shared_data}->{size}.", got ".$sd_size ); - } - return( undef ); - } - my $td_size = zmMemRead( $monitor, "trigger_data:size", 1 ); - if ( $td_size != $mem_data->{trigger_data}->{size} ) - { - if ( $td_size ) - { - Error( "Shared data size conflict in trigger_data for monitor ".$monitor->{Name}.", expected ".$mem_data->{triggger_data}->{size}.", got ".$td_size ); - } - else - { - Debug( "Shared data size conflict in trigger_data for monitor ".$monitor->{Name}.", expected ".$mem_data->{triggger_data}->{size}.", got ".$td_size ); - } - return( undef ); - } - my $vs_size = zmMemRead( $monitor, "video_store_data:size", 1 ); - if ( $vs_size != $mem_data->{video_store_data}->{size} ) - { - if ( $vs_size ) - { - Error( "Shared data size conflict in video_store_data for monitor ".$monitor->{Name}.", expected ".$mem_data->{video_store_data}->{size}.", got ".$vs_size ); - } - else - { - Debug( "Shared data size conflict in video_store_data for monitor ".$monitor->{Name}.", expected ".$mem_data->{video_store_data}->{size}.", got ".$vs_size ); - } - return( undef ); - } - $mem_verified->{$mem_key} = !undef; - } - return( !undef ); + if ( !defined($mem_verified->{$mem_key}) ) + { + my $sd_size = zmMemRead( $monitor, "shared_data:size", 1 ); + if ( $sd_size != $mem_data->{shared_data}->{size} ) + { + if ( $sd_size ) + { + Error( "Shared data size conflict in shared_data for monitor " + .$monitor->{Name} + .", expected " + .$mem_data->{shared_data}->{size} + .", got " + .$sd_size + ); + } + else + { + Debug( "Shared data size conflict in shared_data for monitor " + .$monitor->{Name} + .", expected " + .$mem_data->{shared_data}->{size} + .", got ".$sd_size + ); + } + return( undef ); + } + my $td_size = zmMemRead( $monitor, "trigger_data:size", 1 ); + if ( $td_size != $mem_data->{trigger_data}->{size} ) + { + if ( $td_size ) + { + Error( "Shared data size conflict in trigger_data for monitor " + .$monitor->{Name} + .", expected " + .$mem_data->{triggger_data}->{size} + .", got " + .$td_size + ); + } + else + { + Debug( "Shared data size conflict in trigger_data for monitor " + .$monitor->{Name} + .", expected " + .$mem_data->{triggger_data}->{size} + .", got " + .$td_size + ); + } + return( undef ); + } + $mem_verified->{$mem_key} = !undef; + } + return( !undef ); } -sub zmMemRead( $$;$ ) +sub zmMemRead { - my $monitor = shift; - my $fields = shift; - my $nocheck = shift; + my $monitor = shift; + my $fields = shift; + my $nocheck = shift; - if ( !($nocheck || zmMemVerify( $monitor )) ) - { - return( undef ); - } + if ( !($nocheck || zmMemVerify( $monitor )) ) + { + return( undef ); + } - if ( !ref($fields) ) - { - $fields = [ $fields ]; - } - my @values; - foreach my $field ( @$fields ) - { - my ( $section, $element ) = split( /[\/:.]/, $field ); - Fatal( "Invalid shared data selector '$field'" ) if ( !$section || !$element ); + if ( !ref($fields) ) + { + $fields = [ $fields ]; + } + my @values; + foreach my $field ( @$fields ) + { + my ( $section, $element ) = split( /[\/:.]/, $field ); + Fatal( "Invalid shared data selector '$field'" ) if ( !$section || !$element ); - my $offset = $mem_data->{$section}->{contents}->{$element}->{offset}; - my $type = $mem_data->{$section}->{contents}->{$element}->{type}; - my $size = $mem_data->{$section}->{contents}->{$element}->{size}; + my $offset = $mem_data->{$section}->{contents}->{$element}->{offset}; + my $type = $mem_data->{$section}->{contents}->{$element}->{type}; + my $size = $mem_data->{$section}->{contents}->{$element}->{size}; - my $data = zmMemGet( $monitor, $offset, $size ); + my $data = zmMemGet( $monitor, $offset, $size ); if ( !defined($data) ) { Error( "Unable to read '$field' from memory for monitor ".$monitor->{Id} ); zmMemInvalidate( $monitor ); return( undef ); } - my $value; - if ( $type eq "long" ) - { - ( $value ) = unpack( "l!", $data ); - } - elsif ( $type eq "ulong" || $type eq "size_t" ) - { - ( $value ) = unpack( "L!", $data ); - } - elsif ( $type eq "int64" || $type eq "time_t64" ) - { - # The "q" type is only available on 64bit platforms, so use native. - ( $value ) = unpack( "l!", $data ); - } - elsif ( $type eq "uint64" ) - { - # The "q" type is only available on 64bit platforms, so use native. - ( $value ) = unpack( "L!", $data ); - } - elsif ( $type eq "int32" ) - { - ( $value ) = unpack( "l", $data ); - } - elsif ( $type eq "uint32" || $type eq "bool4" ) - { - ( $value ) = unpack( "L", $data ); - } - elsif ( $type eq "int16" ) - { - ( $value ) = unpack( "s", $data ); - } - elsif ( $type eq "uint16" ) - { - ( $value ) = unpack( "S", $data ); - } - elsif ( $type eq "int8" ) - { - ( $value ) = unpack( "c", $data ); - } - elsif ( $type eq "uint8" || $type eq "bool1" ) - { - ( $value ) = unpack( "C", $data ); - } - elsif ( $type =~ /^int8\[\d+\]$/ ) - { - ( $value ) = unpack( "Z".$size, $data ); - } - elsif ( $type =~ /^uint8\[\d+\]$/ ) - { - ( $value ) = unpack( "C".$size, $data ); - } - else - { - Fatal( "Unexpected type '".$type."' found for '".$field."'" ); - } - push( @values, $value ); - } - if ( wantarray() ) - { - return( @values ) - } - return( $values[0] ); + my $value; + if ( $type eq "long" ) + { + ( $value ) = unpack( "l!", $data ); + } + elsif ( $type eq "ulong" || $type eq "size_t" ) + { + ( $value ) = unpack( "L!", $data ); + } + elsif ( $type eq "int64" || $type eq "time_t64" ) + { + # The "q" type is only available on 64bit platforms, so use native. + ( $value ) = unpack( "l!", $data ); + } + elsif ( $type eq "uint64" ) + { + # The "q" type is only available on 64bit platforms, so use native. + ( $value ) = unpack( "L!", $data ); + } + elsif ( $type eq "int32" ) + { + ( $value ) = unpack( "l", $data ); + } + elsif ( $type eq "uint32" || $type eq "bool4" ) + { + ( $value ) = unpack( "L", $data ); + } + elsif ( $type eq "int16" ) + { + ( $value ) = unpack( "s", $data ); + } + elsif ( $type eq "uint16" ) + { + ( $value ) = unpack( "S", $data ); + } + elsif ( $type eq "int8" ) + { + ( $value ) = unpack( "c", $data ); + } + elsif ( $type eq "uint8" || $type eq "bool1" ) + { + ( $value ) = unpack( "C", $data ); + } + elsif ( $type =~ /^int8\[\d+\]$/ ) + { + ( $value ) = unpack( "Z".$size, $data ); + } + elsif ( $type =~ /^uint8\[\d+\]$/ ) + { + ( $value ) = unpack( "C".$size, $data ); + } + else + { + Fatal( "Unexpected type '".$type."' found for '".$field."'" ); + } + push( @values, $value ); + } + if ( wantarray() ) + { + return( @values ) + } + return( $values[0] ); } -sub zmMemInvalidate( $ ) +sub zmMemInvalidate { - my $monitor = shift; + my $monitor = shift; my $mem_key = zmMemKey($monitor); if ( $mem_key ) { @@ -417,307 +437,313 @@ sub zmMemInvalidate( $ ) } } -sub zmMemTidy() +sub zmMemTidy { zmMemClean(); } -sub zmMemWrite( $$;$ ) +sub zmMemWrite { - my $monitor = shift; - my $field_values = shift; - my $nocheck = shift; + my $monitor = shift; + my $field_values = shift; + my $nocheck = shift; - if ( !($nocheck || zmMemVerify( $monitor )) ) - { - return( undef ); - } + if ( !($nocheck || zmMemVerify( $monitor )) ) + { + return( undef ); + } - while ( my ( $field, $value ) = each( %$field_values ) ) - { - my ( $section, $element ) = split( /[\/:.]/, $field ); - Fatal( "Invalid shared data selector '$field'" ) if ( !$section || !$element ); + while ( my ( $field, $value ) = each( %$field_values ) ) + { + my ( $section, $element ) = split( /[\/:.]/, $field ); + Fatal( "Invalid shared data selector '$field'" ) + if ( !$section || !$element ); - my $offset = $mem_data->{$section}->{contents}->{$element}->{offset}; - my $type = $mem_data->{$section}->{contents}->{$element}->{type}; - my $size = $mem_data->{$section}->{contents}->{$element}->{size}; + my $offset = $mem_data->{$section}->{contents}->{$element}->{offset}; + my $type = $mem_data->{$section}->{contents}->{$element}->{type}; + my $size = $mem_data->{$section}->{contents}->{$element}->{size}; - my $data; - if ( $type eq "long" ) - { - $data = pack( "l!", $value ); - } - elsif ( $type eq "ulong" || $type eq "size_t" ) - { - $data = pack( "L!", $value ); - } - elsif ( $type eq "int64" || $type eq "time_t64" ) - { - # The "q" type is only available on 64bit platforms, so use native. - $data = pack( "l!", $value ); - } - elsif ( $type eq "uint64" ) - { - # The "q" type is only available on 64bit platforms, so use native. - $data = pack( "L!", $value ); - } - elsif ( $type eq "int32" ) - { - $data = pack( "l", $value ); - } - elsif ( $type eq "uint32" || $type eq "bool4" ) - { - $data = pack( "L", $value ); - } - elsif ( $type eq "int16" ) - { - $data = pack( "s", $value ); - } - elsif ( $type eq "uint16" ) - { - $data = pack( "S", $value ); - } - elsif ( $type eq "int8" ) - { - $data = pack( "c", $value ); - } - elsif ( $type eq "uint8" || $type eq "bool1" ) - { - $data = pack( "C", $value ); - } - elsif ( $type =~ /^int8\[\d+\]$/ ) - { - $data = pack( "Z".$size, $value ); - } - elsif ( $type =~ /^uint8\[\d+\]$/ ) - { - $data = pack( "C".$size, $value ); - } - else - { - Fatal( "Unexpected type '".$type."' found for '".$field."'" ); - } + my $data; + if ( $type eq "long" ) + { + $data = pack( "l!", $value ); + } + elsif ( $type eq "ulong" || $type eq "size_t" ) + { + $data = pack( "L!", $value ); + } + elsif ( $type eq "int64" || $type eq "time_t64" ) + { + # The "q" type is only available on 64bit platforms, so use native. + $data = pack( "l!", $value ); + } + elsif ( $type eq "uint64" ) + { + # The "q" type is only available on 64bit platforms, so use native. + $data = pack( "L!", $value ); + } + elsif ( $type eq "int32" ) + { + $data = pack( "l", $value ); + } + elsif ( $type eq "uint32" || $type eq "bool4" ) + { + $data = pack( "L", $value ); + } + elsif ( $type eq "int16" ) + { + $data = pack( "s", $value ); + } + elsif ( $type eq "uint16" ) + { + $data = pack( "S", $value ); + } + elsif ( $type eq "int8" ) + { + $data = pack( "c", $value ); + } + elsif ( $type eq "uint8" || $type eq "bool1" ) + { + $data = pack( "C", $value ); + } + elsif ( $type =~ /^int8\[\d+\]$/ ) + { + $data = pack( "Z".$size, $value ); + } + elsif ( $type =~ /^uint8\[\d+\]$/ ) + { + $data = pack( "C".$size, $value ); + } + else + { + Fatal( "Unexpected type '".$type."' found for '".$field."'" ); + } if ( !zmMemPut( $monitor, $offset, $size, $data ) ) { - Error( "Unable to write '$value' to '$field' in memory for monitor ".$monitor->{Id} ); + Error( "Unable to write '$value' to '$field' in memory for monitor " + .$monitor->{Id} + ); zmMemInvalidate( $monitor ); return( undef ); } - } - return( !undef ); + } + return( !undef ); } -sub zmGetMonitorState( $ ) +sub zmGetMonitorState { - my $monitor = shift; + my $monitor = shift; - return( zmMemRead( $monitor, "shared_data:state" ) ); + return( zmMemRead( $monitor, "shared_data:state" ) ); } -sub zmGetAlarmLocation( $ ) +sub zmGetAlarmLocation { - my $monitor = shift; + my $monitor = shift; - return( zmMemRead( $monitor, [ "shared_data:alarm_x", "shared_data:alarm_y" ] ) ); + return( zmMemRead( $monitor, [ "shared_data:alarm_x", "shared_data:alarm_y" ] ) ); } -sub zmSetControlState( $$ ) +sub zmSetControlState { - my $monitor = shift; - my $control_state = shift; + my $monitor = shift; + my $control_state = shift; - zmMemWrite( $monitor, { "shared_data:control_state" => $control_state } ); + zmMemWrite( $monitor, { "shared_data:control_state" => $control_state } ); } -sub zmGetControlState( $ ) +sub zmGetControlState { - my $monitor = shift; + my $monitor = shift; - return( zmMemRead( $monitor, "shared_data:control_state" ) ); + return( zmMemRead( $monitor, "shared_data:control_state" ) ); } -sub zmSaveControlState( $$ ) +sub zmSaveControlState { - my $monitor = shift; - my $control_state = shift; + my $monitor = shift; + my $control_state = shift; - zmSetControlState( $monitor, freeze( $control_state ) ); + zmSetControlState( $monitor, freeze( $control_state ) ); } -sub zmRestoreControlState( $ ) +sub zmRestoreControlState { - my $monitor = shift; + my $monitor = shift; - return( thaw( zmGetControlState( $monitor ) ) ); + return( thaw( zmGetControlState( $monitor ) ) ); } -sub zmIsAlarmed( $ ) +sub zmIsAlarmed { - my $monitor = shift; + my $monitor = shift; - my $state = zmGetMonitorState( $monitor ); + my $state = zmGetMonitorState( $monitor ); - return( $state == STATE_ALARM ); + return( $state == STATE_ALARM ); } -sub zmInAlarm( $ ) +sub zmInAlarm { - my $monitor = shift; + my $monitor = shift; - my $state = zmGetMonitorState( $monitor ); + my $state = zmGetMonitorState( $monitor ); - return( $state == STATE_ALARM || $state == STATE_ALERT ); + return( $state == STATE_ALARM || $state == STATE_ALERT ); } -sub zmHasAlarmed( $$ ) +sub zmHasAlarmed { - my $monitor = shift; - my $last_event_id = shift; + my $monitor = shift; + my $last_event_id = shift; - my ( $state, $last_event ) = zmMemRead( $monitor, [ "shared_data:state", "shared_data:last_event" ] ); + my ( $state, $last_event ) = zmMemRead( $monitor, [ "shared_data:state" + ,"shared_data:last_event" + ] + ); - if ( $state == STATE_ALARM || $state == STATE_ALERT ) - { - return( $last_event ); - } - elsif( $last_event != $last_event_id ) - { - return( $last_event ); - } - return( undef ); + if ( $state == STATE_ALARM || $state == STATE_ALERT ) + { + return( $last_event ); + } + elsif( $last_event != $last_event_id ) + { + return( $last_event ); + } + return( undef ); } -sub zmGetLastEvent( $ ) +sub zmGetLastEvent { - my $monitor = shift; + my $monitor = shift; - return( zmMemRead( $monitor, "shared_data:last_event" ) ); + return( zmMemRead( $monitor, "shared_data:last_event" ) ); } -sub zmGetLastWriteTime( $ ) +sub zmGetLastWriteTime { - my $monitor = shift; + my $monitor = shift; - return( zmMemRead( $monitor, "shared_data:last_write_time" ) ); + return( zmMemRead( $monitor, "shared_data:last_write_time" ) ); } -sub zmGetLastReadTime( $ ) +sub zmGetLastReadTime { - my $monitor = shift; + my $monitor = shift; - return( zmMemRead( $monitor, "shared_data:last_read_time" ) ); + return( zmMemRead( $monitor, "shared_data:last_read_time" ) ); } -sub zmGetMonitorActions( $ ) +sub zmGetMonitorActions { - my $monitor = shift; + my $monitor = shift; - return( zmMemRead( $monitor, "shared_data:action" ) ); + return( zmMemRead( $monitor, "shared_data:action" ) ); } -sub zmMonitorEnable( $ ) +sub zmMonitorEnable { - my $monitor = shift; + my $monitor = shift; - my $action = zmMemRead( $monitor, "shared_data:action" ); - $action |= ACTION_SUSPEND; - zmMemWrite( $monitor, { "shared_data:action" => $action } ); + my $action = zmMemRead( $monitor, "shared_data:action" ); + $action |= ACTION_SUSPEND; + zmMemWrite( $monitor, { "shared_data:action" => $action } ); } -sub zmMonitorDisable( $ ) +sub zmMonitorDisable { - my $monitor = shift; + my $monitor = shift; - my $action = zmMemRead( $monitor, "shared_data:action" ); - $action |= ACTION_RESUME; - zmMemWrite( $monitor, { "shared_data:action" => $action } ); + my $action = zmMemRead( $monitor, "shared_data:action" ); + $action |= ACTION_RESUME; + zmMemWrite( $monitor, { "shared_data:action" => $action } ); } -sub zmMonitorSuspend( $ ) +sub zmMonitorSuspend { - my $monitor = shift; + my $monitor = shift; - my $action = zmMemRead( $monitor, "shared_data:action" ); - $action |= ACTION_SUSPEND; - zmMemWrite( $monitor, { "shared_data:action" => $action } ); + my $action = zmMemRead( $monitor, "shared_data:action" ); + $action |= ACTION_SUSPEND; + zmMemWrite( $monitor, { "shared_data:action" => $action } ); } -sub zmMonitorResume( $ ) +sub zmMonitorResume { - my $monitor = shift; + my $monitor = shift; - my $action = zmMemRead( $monitor, "shared_data:action" ); - $action |= ACTION_RESUME; - zmMemWrite( $monitor, { "shared_data:action" => $action } ); + my $action = zmMemRead( $monitor, "shared_data:action" ); + $action |= ACTION_RESUME; + zmMemWrite( $monitor, { "shared_data:action" => $action } ); } -sub zmGetTriggerState( $ ) +sub zmGetTriggerState { - my $monitor = shift; + my $monitor = shift; - return( zmMemRead( $monitor, "trigger_data:trigger_state" ) ); + return( zmMemRead( $monitor, "trigger_data:trigger_state" ) ); } -sub zmTriggerEventOn( $$$;$$ ) +sub zmTriggerEventOn { - my $monitor = shift; - my $score = shift; - my $cause = shift; - my $text = shift; - my $showtext = shift; + my $monitor = shift; + my $score = shift; + my $cause = shift; + my $text = shift; + my $showtext = shift; - my $values = { - "trigger_data:trigger_score" => $score, - "trigger_data:trigger_cause" => $cause, - }; - $values->{"trigger_data:trigger_text"} = $text if ( defined($text) ); - $values->{"trigger_data:trigger_showtext"} = $showtext if ( defined($showtext) ); - $values->{"trigger_data:trigger_state"} = TRIGGER_ON; # Write state last so event not read incomplete + my $values = { + "trigger_data:trigger_score" => $score, + "trigger_data:trigger_cause" => $cause, + }; + $values->{"trigger_data:trigger_text"} = $text if ( defined($text) ); + $values->{"trigger_data:trigger_showtext"} = $showtext if ( defined($showtext) ); + $values->{"trigger_data:trigger_state"} = TRIGGER_ON; # Write state last so event not read incomplete - zmMemWrite( $monitor, $values ); + zmMemWrite( $monitor, $values ); } -sub zmTriggerEventOff( $ ) +sub zmTriggerEventOff { - my $monitor = shift; + my $monitor = shift; - my $values = { - "trigger_data:trigger_state" => TRIGGER_OFF, - "trigger_data:trigger_score" => 0, - "trigger_data:trigger_cause" => "", - "trigger_data:trigger_text" => "", - "trigger_data:trigger_showtext" => "", - }; + my $values = { + "trigger_data:trigger_state" => TRIGGER_OFF, + "trigger_data:trigger_score" => 0, + "trigger_data:trigger_cause" => "", + "trigger_data:trigger_text" => "", + "trigger_data:trigger_showtext" => "", + }; - zmMemWrite( $monitor, $values ); + zmMemWrite( $monitor, $values ); } -sub zmTriggerEventCancel( $ ) +sub zmTriggerEventCancel { - my $monitor = shift; + my $monitor = shift; - my $values = { - "trigger_data:trigger_state" => TRIGGER_CANCEL, - "trigger_data:trigger_score" => 0, - "trigger_data:trigger_cause" => "", - "trigger_data:trigger_text" => "", - "trigger_data:trigger_showtext" => "", - }; + my $values = { + "trigger_data:trigger_state" => TRIGGER_CANCEL, + "trigger_data:trigger_score" => 0, + "trigger_data:trigger_cause" => "", + "trigger_data:trigger_text" => "", + "trigger_data:trigger_showtext" => "", + }; - zmMemWrite( $monitor, $values ); + zmMemWrite( $monitor, $values ); } -sub zmTriggerShowtext( $$ ) +sub zmTriggerShowtext { - my $monitor = shift; - my $showtext = shift; + my $monitor = shift; + my $showtext = shift; - my $values = { - "trigger_data:trigger_showtext" => $showtext, - }; + my $values = { + "trigger_data:trigger_showtext" => $showtext, + }; - zmMemWrite( $monitor, $values ); + zmMemWrite( $monitor, $values ); } 1; @@ -741,44 +767,76 @@ ZoneMinder::MappedMem - ZoneMinder Mapped Memory access module } } - ( $lri, $lwi ) = zmMemRead( $monitor, [ "shared_data:last_read_index", "shared_data:last_write_index" ] ); + ( $lri, $lwi ) = zmMemRead( $monitor, [ "shared_data:last_read_index", + "shared_data:last_write_index" + ] + ); zmMemWrite( $monitor, { "trigger_data:trigger_showtext" => "Some Text" } ); =head1 DESCRIPTION -The ZoneMinder:MappedMem module contains methods for accessing and writing to mapped memory as well as helper methods for common operations. +The ZoneMinder:MappedMem module contains methods for accessing and writing +to mapped memory as well as helper methods for common operations. -The core elements of ZoneMinder used mapped memory to allow multiple access to resources. Although ZoneMinder scripts have used this information before, up until now it was difficult to access and prone to errors. This module introduces a common API for mapped memory access (both reading and writing) making it a lot easier to customise scripts or even create your own. +The core elements of ZoneMinder used mapped memory to allow multiple access +to resources. Although ZoneMinder scripts have used this information +before, up until now it was difficult to access and prone to errors. This +module introduces a common API for mapped memory access (both reading and +writing) making it a lot easier to customise scripts or even create your +own. -All the methods listed below require a 'monitor' parameter. This must be a reference to a hash with at least the 'Id' field set to the monitor id of the mapped memory you wish to access. Using database methods to select the monitor details will also return this kind of data. Some of the mapped memory methods will add and amend new fields to this hash. - -=over 4 +All the methods listed below require a 'monitor' parameter. This must be a +reference to a hash with at least the 'Id' field set to the monitor id of +the mapped memory you wish to access. Using database methods to select the +monitor details will also return this kind of data. Some of the mapped +memory methods will add and amend new fields to this hash. =head1 METHODS +=over 4 + =item zmMemVerify ( $monitor ); -Verify that the mapped memory of the monitor given exists and is valid. It will return an undefined value if it is not valid. You should generally call this method first before using any of the other methods, but most of the remaining methods will also do so if the memory has not already been verified. +Verify that the mapped memory of the monitor given exists and is valid. It +will return an undefined value if it is not valid. You should generally +call this method first before using any of the other methods, but most of +the remaining methods will also do so if the memory has not already been +verified. =item zmMemInvalidate ( $monitor ); -Following an error, reset the mapped memory ids and attempt to reverify on the next operation. This is mostly used when a mapped memory segment has gone away and been recreated with a different id. +Following an error, reset the mapped memory ids and attempt to reverify on +the next operation. This is mostly used when a mapped memory segment has +gone away and been recreated with a different id. =item zmMemRead ( $monitor, $readspec ); -This method is used to read data from mapped memory attached to the given monitor. The mapped memory will be verified if it has not already been. The 'readspec' must either be a string of the form "
:" or a reference to an array of strings of the same format. In the first case a single value is returned, in the latter case a list of values is return. Errors will cause undefined to be returned. The allowable sections and field names are described below. +This method is used to read data from mapped memory attached to the given +monitor. The mapped memory will be verified if it has not already been. The +'readspec' must either be a string of the form "
:" or a +reference to an array of strings of the same format. In the first case a +single value is returned, in the latter case a list of values is return. +Errors will cause undefined to be returned. The allowable sections and +field names are described below. =item zmMemWrite ( $monitor, $writespec ); -This method is used to write data to mapped memory attached to the given monitor. The mapped memory will be verified if it has not already been. The 'writespec' must be a reference to a hash with keys of the form "
:" and values as the data to be written. Errors will cause undefined to be returned, otherwise a non-undefined value will be returned. The allowable sections and field names are described below. +This method is used to write data to mapped memory attached to the given +monitor. The mapped memory will be verified if it has not already been. The +'writespec' must be a reference to a hash with keys of the form +"
:" and values as the data to be written. Errors will cause +undefined to be returned, otherwise a non-undefined value will be returned. +The allowable sections and field names are described below. =item $state = zmGetMonitorState ( $monitor ); -Return the current state of the given monitor. This is an integer value and can be compared with the STATE constants given below. +Return the current state of the given monitor. This is an integer value and +can be compared with the STATE constants given below. =item $event_id = zmGetLastEvent ( $monitor ); -Return the event id of the last event that the monitor generated, or 0 if no event has been generated by the current monitor process. +Return the event id of the last event that the monitor generated, or 0 if +no event has been generated by the current monitor process. =item zmIsAlarmed ( $monitor ); @@ -786,27 +844,38 @@ Return 1 if the monitor given is currently in an alarm state, 0 otherwise. =item zmInAlarm ( $monitor ); -Return 1 if the monitor given is currently in an alarm or alerted state, 0 otherwise. +Return 1 if the monitor given is currently in an alarm or alerted state, 0 +otherwise. =item zmHasAlarmed ( $monitor ); -Return 1 if the given monitor is in an alarm state, or has been in an alarm state since the last call to this method. +Return 1 if the given monitor is in an alarm state, or has been in an alarm +state since the last call to this method. =item ( $x, $y ) = zmGetAlarmLocation ( $monitor ); -Return an x,y pair indicating the image co-ordinates of the centre of the last motion event generated by the given monitor. If no event has been generated by the current monitor process, or the alarm was not motion related, returns -1,-1. +Return an x,y pair indicating the image co-ordinates of the centre of the +last motion event generated by the given monitor. If no event has been +generated by the current monitor process, or the alarm was not motion +related, returns -1,-1. =item zmGetLastWriteTime ( $monitor ); -Returns the time (in utc seconds) since the last image was captured by the given monitor and written to shared memory, or 0 otherwise. +Returns the time (in utc seconds) since the last image was captured by the +given monitor and written to shared memory, or 0 otherwise. =item zmGetLastReadTime ( $monitor ); -Returns the time (in utc seconds) since the last image was read from shared memory by the analysis daemon of the given monitor, or 0 otherwise or if the monitor is in monitor only mode. +Returns the time (in utc seconds) since the last image was read from shared +memory by the analysis daemon of the given monitor, or 0 otherwise or if +the monitor is in monitor only mode. =item zmMonitorSuspend ( $monitor ); -Suspend the given monitor from generating events caused by motion. This method can be used to prevent camera actions such as panning or zooming from causing events. If configured to do so, the monitor may automatically resume after a defined period. +Suspend the given monitor from generating events caused by motion. This +method can be used to prevent camera actions such as panning or zooming +from causing events. If configured to do so, the monitor may automatically +resume after a defined period. =item zmMonitorResume ( $monitor ); @@ -814,23 +883,43 @@ Allow the given monitor to resume generating events caused by motion. =item zmTriggerEventOn ( $monitor, $score, $cause [, $text, $showtext ] ); -Trigger the given monitor to generate an event. You must supply an event score and a cause string indicating the reason for the event. You may also supply a text string containing further details about the event and a showtext string which may be included in the timestamp annotation on any images captured during the event, if configured to do so. +Trigger the given monitor to generate an event. You must supply an event +score and a cause string indicating the reason for the event. You may also +supply a text string containing further details about the event and a +showtext string which may be included in the timestamp annotation on any +images captured during the event, if configured to do so. =item zmTriggerEventOff ( $monitor ); -Trigger the given monitor to not generate any events. This method does not cancel zmTriggerEventOn, but is exclusive to it. This method is intended to allow external triggers to prevent normal events being generated by monitors in the same way as zmMonitorSuspend but applies to all events and not just motion, and is intended for longer timescales than are appropriate for suspension. +Trigger the given monitor to not generate any events. This method does not +cancel zmTriggerEventOn, but is exclusive to it. This method is intended to +allow external triggers to prevent normal events being generated by +monitors in the same way as zmMonitorSuspend but applies to all events and +not just motion, and is intended for longer timescales than are appropriate +for suspension. =item zmTriggerEventCancel ( $monitor ); -Cancel any previous trigger on or off requests. This stops a triggered alarm if it exists from a previous 'on' and allows events to be generated once more following a previous 'off'. +Cancel any previous trigger on or off requests. This stops a triggered +alarm if it exists from a previous 'on' and allows events to be generated +once more following a previous 'off'. =item zmTriggerShowtext ( $monitor, $showtest ); -Indicate that the given text should be displayed in the timestamp annotation on any images captured, if the format of the annotation string defined for the monitor permits. +Indicate that the given text should be displayed in the timestamp +annotation on any images captured, if the format of the annotation string +defined for the monitor permits. + +=back =head1 DATA -The data fields in mapped memory that may be accessed are as follows. There are two main sections, shared_data which is general data and trigger_data which is used for event triggering. Whilst reading from these fields is harmless, extreme care must be taken when writing to mapped memory, especially in the shared_data section as this is normally written to only by monitor capture and analysis processes. +The data fields in mapped memory that may be accessed are as follows. There +are two main sections, shared_data which is general data and trigger_data +which is used for event triggering. Whilst reading from these fields is +harmless, extreme care must be taken when writing to mapped memory, +especially in the shared_data section as this is normally written to only +by monitor capture and analysis processes. shared_data The general mapped memory section size The size, in bytes, of this section @@ -861,19 +950,40 @@ The data fields in mapped memory that may be accessed are as follows. There are =head1 CONSTANTS -The following constants are used by the methods above, but can also be used by user scripts if required. +The following constants are used by the methods above, but can also be used +by user scripts if required. + +=over 4 =item STATE_IDLE STATE_PREALARM STATE_ALARM STATE_ALERT STATE_TAPE -These constants define the state of the monitor with respect to alarms and events. They are used in the shared_data:state field. +These constants define the state of the monitor with respect to alarms and +events. They are used in the shared_data:state field. =item ACTION_GET ACTION_SET ACTION_RELOAD ACTION_SUSPEND ACTION_RESUME -These constants defines the various values that can exist in the shared_data:action field. This is a bitmask which when non-zero defines an action that an executing monitor process should take. ACTION_GET requires that the current values of brightness, contrast, colour and hue are taken from the camera and written to the equivalent mapped memory fields. ACTION_SET implies the reverse, that the values in mapped memory should be written to the camera. ACTION_RELOAD signal that the monitor process should reload itself from the database in case any settings have changed there. ACTION_SUSPEND signals that a monitor should stop exaiming images for motion, though other alarms may still occur. ACTION_RESUME sigansl that a monitor should resume motion detectiom. +These constants defines the various values that can exist in the +shared_data:action field. This is a bitmask which when non-zero defines an +action that an executing monitor process should take. ACTION_GET requires +that the current values of brightness, contrast, colour and hue are taken +from the camera and written to the equivalent mapped memory fields. +ACTION_SET implies the reverse, that the values in mapped memory should be +written to the camera. ACTION_RELOAD signal that the monitor process should +reload itself from the database in case any settings have changed there. +ACTION_SUSPEND signals that a monitor should stop exaiming images for +motion, though other alarms may still occur. ACTION_RESUME sigansl that a +monitor should resume motion detectiom. -=item TRIGGER_CANCEL TRIGGER_ON TRIGGER_OFF +=item TRIGGER_CANCEL TRIGGER_ON TRIGGER_OFF -These constants are used in the definition of external triggers. TRIGGER_CANCEL is used to indicated that any previous trigger settings should be cancelled, TRIGGER_ON signals that an alarm should be created (or continued)) as a result of the current trigger and TRIGGER_OFF signals that the trigger should prevent any alarms from being generated. See the trigger methods above for further details. +These constants are used in the definition of external triggers. +TRIGGER_CANCEL is used to indicated that any previous trigger settings +should be cancelled, TRIGGER_ON signals that an alarm should be created (or +continued)) as a result of the current trigger and TRIGGER_OFF signals that +the trigger should prevent any alarms from being generated. See the trigger +methods above for further details. + +=back =head1 EXPORT diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Memory/Mapped.pm b/scripts/ZoneMinder/lib/ZoneMinder/Memory/Mapped.pm index 173c48493..017b5aa8c 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Memory/Mapped.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Memory/Mapped.pm @@ -36,18 +36,18 @@ our @ISA = qw(Exporter ZoneMinder::Base); # names by default without a very good reason. Use EXPORT_OK instead. # Do not simply export all your public functions/methods/constants. -# This allows declaration use ZoneMinder ':all'; +# This allows declaration use ZoneMinder ':all'; # If you do not need this, moving things directly into @EXPORT or @EXPORT_OK # will save memory. our %EXPORT_TAGS = ( - 'functions' => [ qw( - zmMemKey - zmMemAttach - zmMemDetach - zmMemGet - zmMemPut - zmMemClean - ) ], + 'functions' => [ qw( + zmMemKey + zmMemAttach + zmMemDetach + zmMemGet + zmMemPut + zmMemClean + ) ], ); push( @{$EXPORT_TAGS{all}}, @{$EXPORT_TAGS{$_}} ) foreach keys %EXPORT_TAGS; @@ -68,117 +68,131 @@ use ZoneMinder::Logger qw(:all); use Sys::Mmap; -sub zmMemKey( $ ) +sub zmMemKey { - my $monitor = shift; + my $monitor = shift; return( defined($monitor->{MMapAddr})?$monitor->{MMapAddr}:undef ); } -sub zmMemAttach( $$ ) +sub zmMemAttach { - my ( $monitor, $size ) = @_; - if ( ! $size ) { - Error( "No size passed to zmMemAttach for monitor $$monitor{Id}\n" ); - return( undef ); - } - if ( !defined($monitor->{MMapAddr}) ) - { + my ( $monitor, $size ) = @_; + if ( ! $size ) { + Error( "No size passed to zmMemAttach for monitor $$monitor{Id}\n" ); + return( undef ); + } + if ( !defined($monitor->{MMapAddr}) ) + { my $mmap_file = $Config{ZM_PATH_MAP}."/zm.mmap.".$monitor->{Id}; - if ( ! -e $mmap_file ) { - Error( sprintf( "Memory map file '%s' does not exist. zmc might not be running.", $mmap_file ) ); - return ( undef ); - } + if ( ! -e $mmap_file ) { + Error( sprintf( "Memory map file '%s' does not exist. zmc might not be running." + , $mmap_file + ) + ); + return ( undef ); + } - my $mmap_file_size = -s $mmap_file; + my $mmap_file_size = -s $mmap_file; - if ( $mmap_file_size < $size ) { - Error( sprintf( "Memory map file '%s' should have been %d but was instead %d", $mmap_file, $size, $mmap_file_size ) ); - return ( undef ); - } - if ( !open( MMAP, "+<".$mmap_file ) ) + if ( $mmap_file_size < $size ) { + Error( sprintf( "Memory map file '%s' should have been %d but was instead %d" + , $mmap_file + , $size + , $mmap_file_size + ) + ); + return ( undef ); + } + if ( !open( MMAP, "+<", $mmap_file ) ) { - Error( sprintf( "Can't open memory map file '%s': $!\n", $mmap_file ) ); - return( undef ); + Error( sprintf( "Can't open memory map file '%s': $!\n", $mmap_file ) ); + return( undef ); } my $mmap = undef; my $mmap_addr = mmap( $mmap, $size, PROT_READ|PROT_WRITE, MAP_SHARED, \*MMAP ); if ( !$mmap_addr || !$mmap ) { - Error( sprintf( "Can't mmap to file '%s': $!\n", $mmap_file ) ); - close( MMAP ); - return( undef ); + Error( sprintf( "Can't mmap to file '%s': $!\n", $mmap_file ) ); + close( MMAP ); + return( undef ); } - $monitor->{MMapHandle} = \*MMAP; - $monitor->{MMapAddr} = $mmap_addr; - $monitor->{MMap} = \$mmap; - } - return( !undef ); + $monitor->{MMapHandle} = \*MMAP; + $monitor->{MMapAddr} = $mmap_addr; + $monitor->{MMap} = \$mmap; + } + return( !undef ); } -sub zmMemDetach( $ ) +sub zmMemDetach { - my $monitor = shift; + my $monitor = shift; if ( $monitor->{MMap} ) { if ( ! munmap( ${$monitor->{MMap}} ) ) { - Warn( "Unable to munmap for monitor $$monitor{Id}\n"); - } - delete $monitor->{MMap}; + Warn( "Unable to munmap for monitor $$monitor{Id}\n"); + } + delete $monitor->{MMap}; } if ( $monitor->{MMapAddr} ) { - delete $monitor->{MMapAddr}; + delete $monitor->{MMapAddr}; } if ( $monitor->{MMapHandle} ) { close( $monitor->{MMapHandle} ); - delete $monitor->{MMapHandle}; + delete $monitor->{MMapHandle}; } } -sub zmMemGet( $$$ ) +sub zmMemGet { - my $monitor = shift; - my $offset = shift; - my $size = shift; + my $monitor = shift; + my $offset = shift; + my $size = shift; - my $mmap = $monitor->{MMap}; + my $mmap = $monitor->{MMap}; if ( !$mmap || !$$mmap ) { - Error( sprintf( "Can't read from mapped memory for monitor '%d', gone away?", $monitor->{Id} ) ); + Error( sprintf( "Can't read from mapped memory for monitor '%d', gone away?" + , $monitor->{Id} + ) + ); return( undef ); } - my $data = substr( $$mmap, $offset, $size ); + my $data = substr( $$mmap, $offset, $size ); return( $data ); } -sub zmMemPut( $$$$ ) +sub zmMemPut { - my $monitor = shift; - my $offset = shift; - my $size = shift; - my $data = shift; + my $monitor = shift; + my $offset = shift; + my $size = shift; + my $data = shift; - my $mmap = $monitor->{MMap}; + my $mmap = $monitor->{MMap}; if ( !$mmap || !$$mmap ) { - Error( sprintf( "Can't write mapped memory for monitor '%d', gone away?", $monitor->{Id} ) ); + Error( sprintf( "Can't write mapped memory for monitor '%d', gone away?" + , $monitor->{Id} + ) + ); return( undef ); } - substr( $$mmap, $offset, $size ) = $data; - return( !undef ); + substr( $$mmap, $offset, $size ) = $data; + return( !undef ); } sub zmMemClean { - Debug( "Removing memory map files\n" ); + Debug( "Removing memory map files\n" ); my $mapPath = $Config{ZM_PATH_MAP}."/zm.mmap.*"; foreach my $mapFile( glob( $mapPath ) ) { ( $mapFile ) = $mapFile =~ /^(.+)$/; - Debug( "Removing memory map file '$mapFile'\n" ); + Debug( "Removing memory map file '$mapFile'\n" ); unlink( $mapFile ); } } diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Memory/Shared.pm b/scripts/ZoneMinder/lib/ZoneMinder/Memory/Shared.pm index 59dc399f1..301327095 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Memory/Shared.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Memory/Shared.pm @@ -19,7 +19,7 @@ # # ========================================================================== # -# This module contains the common definitions and functions used by the rest +# This module contains the common definitions and functions used by the rest # of the ZoneMinder scripts # package ZoneMinder::Memory::Shared; @@ -39,18 +39,18 @@ eval 'sub IPC_CREAT {0001000}' unless defined &IPC_CREAT; # names by default without a very good reason. Use EXPORT_OK instead. # Do not simply export all your public functions/methods/constants. -# This allows declaration use ZoneMinder ':all'; +# This allows declaration use ZoneMinder ':all'; # If you do not need this, moving things directly into @EXPORT or @EXPORT_OK # will save memory. our %EXPORT_TAGS = ( - 'functions' => [ qw( + 'functions' => [ qw( zmMemKey zmMemAttach zmMemDetach zmMemGet zmMemPut zmMemClean - ) ], + ) ], ); push( @{$EXPORT_TAGS{all}}, @{$EXPORT_TAGS{$_}} ) foreach keys %EXPORT_TAGS; @@ -69,82 +69,98 @@ our $VERSION = $ZoneMinder::Base::VERSION; use ZoneMinder::Config qw(:all); use ZoneMinder::Logger qw(:all); -sub zmMemKey( $ ) +sub zmMemKey { - my $monitor = shift; - return( defined($monitor->{ShmKey})?$monitor->{ShmKey}:undef ); + my $monitor = shift; + return( defined($monitor->{ShmKey})?$monitor->{ShmKey}:undef ); } -sub zmMemAttach( $$ ) +sub zmMemAttach { - my $monitor = shift; - my $size = shift; - if ( !defined($monitor->{ShmId}) ) - { - my $shm_key = (hex($Config{ZM_SHM_KEY})&0xffff0000)|$monitor->{Id}; - my $shm_id = shmget( $shm_key, $size, &IPC_CREAT | 0777 ); - if ( !defined($shm_id) ) - { - Error( sprintf( "Can't get shared memory id '%x', %d: $!\n", $shm_key, $monitor->{Id} ) ); - return( undef ); - } - $monitor->{ShmKey} = $shm_key; - $monitor->{ShmId} = $shm_id; - } - return( !undef ); + my $monitor = shift; + my $size = shift; + if ( !defined($monitor->{ShmId}) ) + { + my $shm_key = (hex($Config{ZM_SHM_KEY})&0xffff0000)|$monitor->{Id}; + my $shm_id = shmget( $shm_key, $size, &IPC_CREAT | 0777 ); + if ( !defined($shm_id) ) + { + Error( sprintf( "Can't get shared memory id '%x', %d: $!\n" + , $shm_key + , $monitor->{Id} + ) + ); + return( undef ); + } + $monitor->{ShmKey} = $shm_key; + $monitor->{ShmId} = $shm_id; + } + return( !undef ); } -sub zmMemDetach( $ ) +sub zmMemDetach { - my $monitor = shift; + my $monitor = shift; - delete $monitor->{ShmId}; + delete $monitor->{ShmId}; } -sub zmMemGet( $$$ ) +sub zmMemGet { - my $monitor = shift; - my $offset = shift; - my $size = shift; + my $monitor = shift; + my $offset = shift; + my $size = shift; + + my $shm_key = $monitor->{ShmKey}; + my $shm_id = $monitor->{ShmId}; - my $shm_key = $monitor->{ShmKey}; - my $shm_id = $monitor->{ShmId}; - my $data; if ( !shmread( $shm_id, $data, $offset, $size ) ) { - Error( sprintf( "Can't read from shared memory '%x/%d': $!", $shm_key, $shm_id ) ); + Error( sprintf( "Can't read from shared memory '%x/%d': $!" + , $shm_key + , $shm_id + ) + ); return( undef ); } - return( $data ); + return( $data ); } -sub zmMemPut( $$$$ ) +sub zmMemPut { - my $monitor = shift; - my $offset = shift; - my $size = shift; - my $data = shift; + my $monitor = shift; + my $offset = shift; + my $size = shift; + my $data = shift; + + my $shm_key = $monitor->{ShmKey}; + my $shm_id = $monitor->{ShmId}; - my $shm_key = $monitor->{ShmKey}; - my $shm_id = $monitor->{ShmId}; - if ( !shmwrite( $shm_id, $data, $offset, $size ) ) { - Error( sprintf( "Can't write to shared memory '%x/%d': $!", $shm_key, $shm_id ) ); + Error( sprintf( "Can't write to shared memory '%x/%d': $!" + , $shm_key + , $shm_id + ) + ); return( undef ); } - return( !undef ); + return( !undef ); } sub zmMemClean { Debug( "Removing shared memory\n" ); # Find ZoneMinder shared memory - my $command = "ipcs -m | grep '^".substr( sprintf( "0x%x", hex($Config{ZM_SHM_KEY}) ), 0, -2 )."'"; + my $command = "ipcs -m | grep '^" + .substr( sprintf( "0x%x", hex($Config{ZM_SHM_KEY}) ), 0, -2 ) + ."'" + ; Debug( "Checking for shared memory with '$command'\n" ); - open( CMD, "$command |" ) or Fatal( "Can't execute '$command': $!" ); - while( ) + open( my $CMD, '<', "$command |" ) + or Fatal( "Can't execute '$command': $!" ); + while( <$CMD> ) { chomp; my ( $key, $id ) = split( /\s+/ ); @@ -156,7 +172,7 @@ sub zmMemClean qx( $command ); } } - close( CMD ); + close( $CMD ); } 1; diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Trigger/Channel.pm b/scripts/ZoneMinder/lib/ZoneMinder/Trigger/Channel.pm index 0344e6d94..8b746ac3d 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Trigger/Channel.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Trigger/Channel.pm @@ -46,53 +46,53 @@ our $AUTOLOAD; sub new { - my $class = shift; - my $self = {}; - $self->{readable} = !undef; - $self->{writeable} = !undef; - $self->{selectable} = undef; - $self->{state} = 'closed'; - bless( $self, $class ); - return $self; + my $class = shift; + my $self = {}; + $self->{readable} = !undef; + $self->{writeable} = !undef; + $self->{selectable} = undef; + $self->{state} = 'closed'; + bless( $self, $class ); + return $self; } sub clone { - my $self = shift; - my $clone = { %$self }; - bless $clone, ref $self; + my $self = shift; + my $clone = { %$self }; + bless $clone, ref $self; } -sub open() +sub open { - my $self = shift; - my $class = ref($self) or croak( "Can't get class for non object $self" ); - croak( "Abstract base class method called for object of class $class" ); + my $self = shift; + my $class = ref($self) or croak( "Can't get class for non object $self" ); + croak( "Abstract base class method called for object of class $class" ); } -sub close() +sub close { - my $self = shift; - my $class = ref($self) or croak( "Can't get class for non object $self" ); - croak( "Abstract base class method called for object of class $class" ); + my $self = shift; + my $class = ref($self) or croak( "Can't get class for non object $self" ); + croak( "Abstract base class method called for object of class $class" ); } -sub getState() +sub getState { - my $self = shift; - return( $self->{state} ); + my $self = shift; + return( $self->{state} ); } -sub isOpen() +sub isOpen { - my $self = shift; - return( $self->{state} eq "open" ); + my $self = shift; + return( $self->{state} eq "open" ); } -sub isConnected() +sub isConnected { - my $self = shift; - return( $self->{state} eq "connected" ); + my $self = shift; + return( $self->{state} eq "connected" ); } sub DESTROY @@ -101,15 +101,15 @@ sub DESTROY sub AUTOLOAD { - my $self = shift; - my $class = ref($self) || croak( "$self not object" ); - my $name = $AUTOLOAD; - $name =~ s/.*://; - if ( !exists($self->{$name}) ) - { - croak( "Can't access $name member of object of class $class" ); - } - return( $self->{$name} ); + my $self = shift; + my $class = ref($self) || croak( "$self not object" ); + my $name = $AUTOLOAD; + $name =~ s/.*://; + if ( !exists($self->{$name}) ) + { + croak( "Can't access $name member of object of class $class" ); + } + return( $self->{$name} ); } 1; diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Trigger/Channel/File.pm b/scripts/ZoneMinder/lib/ZoneMinder/Trigger/Channel/File.pm index 234dae3d7..6c4254a7e 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Trigger/Channel/File.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Trigger/Channel/File.pm @@ -48,23 +48,23 @@ use Fcntl; sub new { - my $class = shift; - my %params = @_; - my $self = ZoneMinder::Trigger::Channel::Handle->new; - $self->{path} = $params{path}; - bless( $self, $class ); - return $self; + my $class = shift; + my %params = @_; + my $self = ZoneMinder::Trigger::Channel::Handle->new; + $self->{path} = $params{path}; + bless( $self, $class ); + return $self; } -sub open() +sub open { - my $self = shift; - local *sfh; - #sysopen( *sfh, $conn->{path}, O_NONBLOCK|O_RDONLY ) or croak( "Can't sysopen: $!" ); - #open( *sfh, "<".$conn->{path} ) or croak( "Can't open: $!" ); - open( *sfh, "+<".$self->{path} ) or croak( "Can't open: $!" ); - $self->{state} = 'open'; - $self->{handle} = *sfh; + my $self = shift; + local *sfh; + #sysopen( *sfh, $conn->{path}, O_NONBLOCK|O_RDONLY ) or croak( "Can't sysopen: $!" ); + #open( *sfh, "<".$conn->{path} ) or croak( "Can't open: $!" ); + open( *sfh, "+<", $self->{path} ) or croak( "Can't open: $!" ); + $self->{state} = 'open'; + $self->{handle} = *sfh; } 1; diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Trigger/Channel/Handle.pm b/scripts/ZoneMinder/lib/ZoneMinder/Trigger/Channel/Handle.pm index 353dc4a32..d26924476 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Trigger/Channel/Handle.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Trigger/Channel/Handle.pm @@ -46,12 +46,12 @@ use POSIX; sub new { - my $class = shift; - my $port = shift; - my $self = ZoneMinder::Trigger::Channel->new(); - $self->{handle} = undef; - bless( $self, $class ); - return $self; + my $class = shift; + my $port = shift; + my $self = ZoneMinder::Trigger::Channel->new(); + $self->{handle} = undef; + bless( $self, $class ); + return $self; } sub spawns @@ -59,45 +59,51 @@ sub spawns return( undef ); } -sub close() +sub close { - my $self = shift; - close( $self->{handle} ); - $self->{state} = 'closed'; - $self->{handle} = undef; + my $self = shift; + close( $self->{handle} ); + $self->{state} = 'closed'; + $self->{handle} = undef; } -sub read() +sub read { - my $self = shift; - my $buffer; - my $nbytes = sysread( $self->{handle}, $buffer, POSIX::BUFSIZ ); - if ( !$nbytes ) - { - return( undef ); - } - Debug( "Read '$buffer' ($nbytes bytes)\n" ); - return( $buffer ); + my $self = shift; + my $buffer; + my $nbytes = sysread( $self->{handle}, $buffer, POSIX::BUFSIZ ); + if ( !$nbytes ) + { + return( undef ); + } + Debug( "Read '$buffer' ($nbytes bytes)\n" ); + return( $buffer ); } -sub write() +sub write { - my $self = shift; - my $buffer = shift; - my $nbytes = syswrite( $self->{handle}, $buffer ); - if ( !defined( $nbytes) || $nbytes < length($buffer) ) - { - Error( "Unable to write buffer '".$buffer.", expected ".length($buffer)." bytes, sent ".($nbytes?$nbytes:'undefined').": $!\n" ); - return( undef ); - } - Debug( "Wrote '$buffer' ($nbytes bytes)\n" ); - return( !undef ); + my $self = shift; + my $buffer = shift; + my $nbytes = syswrite( $self->{handle}, $buffer ); + if ( !defined( $nbytes) || $nbytes < length($buffer) ) + { + Error( "Unable to write buffer '".$buffer + .", expected " + .length($buffer) + ." bytes, sent " + .($nbytes?$nbytes:'undefined') + .": $!\n" + ); + return( undef ); + } + Debug( "Wrote '$buffer' ($nbytes bytes)\n" ); + return( !undef ); } -sub fileno() +sub fileno { - my $self = shift; - return( defined($self->{handle})?fileno($self->{handle}):-1 ); + my $self = shift; + return( defined($self->{handle})?fileno($self->{handle}):-1 ); } 1; diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Trigger/Channel/Inet.pm b/scripts/ZoneMinder/lib/ZoneMinder/Trigger/Channel/Inet.pm index 68df0980f..6c5f21961 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Trigger/Channel/Inet.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Trigger/Channel/Inet.pm @@ -48,44 +48,45 @@ use Socket; sub new { - my $class = shift; - my %params = @_; - my $self = ZoneMinder::Trigger::Channel::Spawning->new(); - $self->{selectable} = !undef; - $self->{port} = $params{port}; - bless( $self, $class ); - return $self; + my $class = shift; + my %params = @_; + my $self = ZoneMinder::Trigger::Channel::Spawning->new(); + $self->{selectable} = !undef; + $self->{port} = $params{port}; + bless( $self, $class ); + return $self; } -sub open() +sub open { - my $self = shift; - local *sfh; - my $saddr = sockaddr_in( $self->{port}, INADDR_ANY ); - socket( *sfh, PF_INET, SOCK_STREAM, getprotobyname('tcp') ) or croak( "Can't open socket: $!" ); - setsockopt( *sfh, SOL_SOCKET, SO_REUSEADDR, 1 ); - bind( *sfh, $saddr ) or croak( "Can't bind: $!" ); - listen( *sfh, SOMAXCONN ) or croak( "Can't listen: $!" ); - $self->{state} = 'open'; - $self->{handle} = *sfh; + my $self = shift; + local *sfh; + my $saddr = sockaddr_in( $self->{port}, INADDR_ANY ); + socket( *sfh, PF_INET, SOCK_STREAM, getprotobyname('tcp') ) + or croak( "Can't open socket: $!" ); + setsockopt( *sfh, SOL_SOCKET, SO_REUSEADDR, 1 ); + bind( *sfh, $saddr ) or croak( "Can't bind: $!" ); + listen( *sfh, SOMAXCONN ) or croak( "Can't listen: $!" ); + $self->{state} = 'open'; + $self->{handle} = *sfh; } -sub _spawn( $ ) +sub _spawn { - my $self = shift; - my $new_handle = shift; - my $clone = $self->clone(); - $clone->{handle} = $new_handle; - $clone->{state} = 'connected'; - return( $clone ); + my $self = shift; + my $new_handle = shift; + my $clone = $self->clone(); + $clone->{handle} = $new_handle; + $clone->{state} = 'connected'; + return( $clone ); } -sub accept() +sub accept { - my $self = shift; - local *cfh; - my $paddr = accept( *cfh, $self->{handle} ); - return( $self->_spawn( *cfh ) ); + my $self = shift; + local *cfh; + my $paddr = accept( *cfh, $self->{handle} ); + return( $self->_spawn( *cfh ) ); } 1; diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Trigger/Channel/Serial.pm b/scripts/ZoneMinder/lib/ZoneMinder/Trigger/Channel/Serial.pm index 7e4ad4730..a3709b5bb 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Trigger/Channel/Serial.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Trigger/Channel/Serial.pm @@ -46,64 +46,70 @@ use Device::SerialPort; sub new { - my $class = shift; - my %params = @_; - my $self = ZoneMinder::Trigger::Channel->new; - $self->{path} = $params{path}; - bless( $self, $class ); - return $self; + my $class = shift; + my %params = @_; + my $self = ZoneMinder::Trigger::Channel->new; + $self->{path} = $params{path}; + bless( $self, $class ); + return $self; } -sub open() +sub open { - my $self = shift; - my $device = new Device::SerialPort( $self->{path} ); - $device->baudrate(9600); - $device->databits(8); - $device->parity('none'); - $device->stopbits(1); - $device->handshake('none'); + my $self = shift; + my $device = new Device::SerialPort( $self->{path} ); + $device->baudrate(9600); + $device->databits(8); + $device->parity('none'); + $device->stopbits(1); + $device->handshake('none'); - $device->read_const_time(50); - $device->read_char_time(10); + $device->read_const_time(50); + $device->read_char_time(10); - $self->{device} = $device; - $self->{state} = 'open'; - $self->{state} = 'connected'; + $self->{device} = $device; + $self->{state} = 'open'; + $self->{state} = 'connected'; } -sub close() +sub close { - my $self = shift; - $self->{device}->close(); - $self->{state} = 'closed'; + my $self = shift; + $self->{device}->close(); + $self->{state} = 'closed'; } -sub read() +sub read { - my $self = shift; - my $buffer = $self->{device}->lookfor(); - if ( !$buffer || !length($buffer) ) - { - return( undef ); - } - Debug( "Read '$buffer' (".length($buffer)." bytes)\n" ); - return( $buffer ); + my $self = shift; + my $buffer = $self->{device}->lookfor(); + if ( !$buffer || !length($buffer) ) + { + return( undef ); + } + Debug( "Read '$buffer' (".length($buffer)." bytes)\n" ); + return( $buffer ); } -sub write() +sub write { - my $self = shift; - my $buffer = shift; - my $nbytes = $self->{device}->write( $buffer ); - $self->{device}->write_drain(); - if ( !defined( $nbytes) || $nbytes < length($buffer) ) - { - Error( "Unable to write buffer '".$buffer.", expected ".length($buffer)." bytes, sent ".$nbytes.": $!\n" ); - return( undef ); - } - Debug( "Wrote '$buffer' ($nbytes bytes)\n" ); - return( !undef ); + my $self = shift; + my $buffer = shift; + my $nbytes = $self->{device}->write( $buffer ); + $self->{device}->write_drain(); + if ( !defined( $nbytes) || $nbytes < length($buffer) ) + { + Error( "Unable to write buffer '".$buffer + .", expected " + .length($buffer) + ." bytes, sent " + .$nbytes + .": $!\n" + ); + return( undef ); + } + Debug( "Wrote '$buffer' ($nbytes bytes)\n" ); + return( !undef ); } 1; diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Trigger/Channel/Spawning.pm b/scripts/ZoneMinder/lib/ZoneMinder/Trigger/Channel/Spawning.pm index ff726ac38..aeaca182e 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Trigger/Channel/Spawning.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Trigger/Channel/Spawning.pm @@ -45,12 +45,12 @@ use ZoneMinder::Logger qw(:all); sub new { - my $class = shift; - my $port = shift; - my $self = ZoneMinder::Trigger::Channel::Handle->new(); - $self->{spawns} = !undef; - bless( $self, $class ); - return $self; + my $class = shift; + my $port = shift; + my $self = ZoneMinder::Trigger::Channel::Handle->new(); + $self->{spawns} = !undef; + bless( $self, $class ); + return $self; } sub spawns diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Trigger/Channel/Unix.pm b/scripts/ZoneMinder/lib/ZoneMinder/Trigger/Channel/Unix.pm index a671ccd66..71d6e89fc 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Trigger/Channel/Unix.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Trigger/Channel/Unix.pm @@ -48,28 +48,28 @@ use Socket; sub new { - my $class = shift; - my %params = @_; - my $self = ZoneMinder::Trigger::Channel->new; - $self->{selectable} = !undef; - $self->{path} = $params{path}; - bless( $self, $class ); - return $self; + my $class = shift; + my %params = @_; + my $self = ZoneMinder::Trigger::Channel->new; + $self->{selectable} = !undef; + $self->{path} = $params{path}; + bless( $self, $class ); + return $self; } -sub open() +sub open { - my $self = shift; - local *sfh; - unlink( $self->{path} ); - my $saddr = sockaddr_un( $self->{path} ); - socket( *sfh, PF_UNIX, SOCK_STREAM, 0 ) or croak( "Can't open socket: $!" ); - bind( *sfh, $saddr ) or croak( "Can't bind: $!" ); - listen( *sfh, SOMAXCONN ) or croak( "Can't listen: $!" ); - $self->{handle} = *sfh; + my $self = shift; + local *sfh; + unlink( $self->{path} ); + my $saddr = sockaddr_un( $self->{path} ); + socket( *sfh, PF_UNIX, SOCK_STREAM, 0 ) or croak( "Can't open socket: $!" ); + bind( *sfh, $saddr ) or croak( "Can't bind: $!" ); + listen( *sfh, SOMAXCONN ) or croak( "Can't listen: $!" ); + $self->{handle} = *sfh; } -sub _spawn( $ ) +sub _spawn { my $self = shift; my $new_handle = shift; @@ -79,7 +79,7 @@ sub _spawn( $ ) return( $clone ); } -sub accept() +sub accept { my $self = shift; local *cfh; diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Trigger/Connection.pm b/scripts/ZoneMinder/lib/ZoneMinder/Trigger/Connection.pm index 41b332d46..12cf3136d 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Trigger/Connection.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Trigger/Connection.pm @@ -46,115 +46,121 @@ our $AUTOLOAD; sub new { - my $class = shift; - my %params = @_; - my $self = {}; - $self->{name} = $params{name}; - $self->{channel} = $params{channel}; - $self->{input} = $params{mode} =~ /r/i; - $self->{output} = $params{mode} =~ /w/i; - bless( $self, $class ); - return $self; + my $class = shift; + my %params = @_; + my $self = {}; + $self->{name} = $params{name}; + $self->{channel} = $params{channel}; + $self->{input} = $params{mode} =~ /r/i; + $self->{output} = $params{mode} =~ /w/i; + bless( $self, $class ); + return $self; } sub clone { - my $self = shift; - my $clone = { %$self }; - bless $clone, ref $self; - return( $clone ); + my $self = shift; + my $clone = { %$self }; + bless $clone, ref $self; + return( $clone ); } sub spawns { - my $self = shift; + my $self = shift; return( $self->{channel}->spawns() ); } -sub _spawn( $ ) +sub _spawn { - my $self = shift; - my $new_channel = shift; - my $clone = $self->clone(); - $clone->{channel} = $new_channel; - return( $clone ); + my $self = shift; + my $new_channel = shift; + my $clone = $self->clone(); + $clone->{channel} = $new_channel; + return( $clone ); } -sub accept() +sub accept { - my $self = shift; - my $new_channel = $self->{channel}->accept(); - return( $self->_spawn( $new_channel ) ); + my $self = shift; + my $new_channel = $self->{channel}->accept(); + return( $self->_spawn( $new_channel ) ); } -sub open() +sub open { - my $self = shift; - return( $self->{channel}->open() ); + my $self = shift; + return( $self->{channel}->open() ); } -sub close() +sub close { - my $self = shift; - return( $self->{channel}->close() ); + my $self = shift; + return( $self->{channel}->close() ); } -sub fileno() +sub fileno { - my $self = shift; - return( $self->{channel}->fileno() ); + my $self = shift; + return( $self->{channel}->fileno() ); } -sub isOpen() +sub isOpen { - my $self = shift; - return( $self->{channel}->isOpen() ); + my $self = shift; + return( $self->{channel}->isOpen() ); } -sub isConnected() +sub isConnected { - my $self = shift; - return( $self->{channel}->isConnected() ); + my $self = shift; + return( $self->{channel}->isConnected() ); } -sub canRead() +sub canRead { - my $self = shift; - return( $self->{input} && $self->isConnected() ); + my $self = shift; + return( $self->{input} && $self->isConnected() ); } -sub canWrite() +sub canWrite { - my $self = shift; - return( $self->{output} && $self->isConnected() ); + my $self = shift; + return( $self->{output} && $self->isConnected() ); } sub getMessages { - my $self = shift; - my $buffer = $self->{channel}->read(); + my $self = shift; + my $buffer = $self->{channel}->read(); - return( undef ) if ( !defined($buffer) ); + return( undef ) if ( !defined($buffer) ); - my @messages = split( /\r?\n/, $buffer ); - return( \@messages ); + my @messages = split( /\r?\n/, $buffer ); + return( \@messages ); } sub putMessages { - my $self = shift; - my $messages = shift; + my $self = shift; + my $messages = shift; - if ( @$messages ) - { - my $buffer = join( "\n", @$messages ); - $buffer .= "\n"; - if ( !$self->{channel}->write( $buffer ) ) - { - Error( "Unable to write buffer '".$buffer." to connection ".$self->{name}." (".$self->fileno().")\n" ); - } - } - return( undef ); + if ( @$messages ) + { + my $buffer = join( "\n", @$messages ); + $buffer .= "\n"; + if ( !$self->{channel}->write( $buffer ) ) + { + Error( "Unable to write buffer '".$buffer + ." to connection " + .$self->{name} + ." (" + .$self->fileno() + .")\n" + ); + } + } + return( undef ); } sub timedActions @@ -167,22 +173,22 @@ sub DESTROY sub AUTOLOAD { - my $self = shift; - my $class = ref($self) || croak( "$self not object" ); - my $name = $AUTOLOAD; - $name =~ s/.*://; - if ( exists($self->{$name}) ) - { - return( $self->{$name} ); - } - elsif ( defined($self->{channel}) ) - { - if ( exists($self->{channel}->{$name}) ) - { - return( $self->{channel}->{$name} ); - } - } - croak( "Can't access $name member of object of class $class" ); + my $self = shift; + my $class = ref($self) || croak( "$self not object" ); + my $name = $AUTOLOAD; + $name =~ s/.*://; + if ( exists($self->{$name}) ) + { + return( $self->{$name} ); + } + elsif ( defined($self->{channel}) ) + { + if ( exists($self->{channel}->{$name}) ) + { + return( $self->{channel}->{$name} ); + } + } + croak( "Can't access $name member of object of class $class" ); } 1; diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Trigger/Connection/Example.pm b/scripts/ZoneMinder/lib/ZoneMinder/Trigger/Connection/Example.pm index 3bed2b351..6f3a86575 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Trigger/Connection/Example.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Trigger/Connection/Example.pm @@ -44,40 +44,40 @@ use ZoneMinder::Logger qw(:all); sub new { - my $class = shift; - my $path = shift; - my $self = ZoneMinder::Trigger::Connection->new( @_ ); - bless( $self, $class ); - return $self; + my $class = shift; + my $path = shift; + my $self = ZoneMinder::Trigger::Connection->new( @_ ); + bless( $self, $class ); + return $self; } sub getMessages { - my $self = shift; - my $buffer = $self->{channel}->read(); + my $self = shift; + my $buffer = $self->{channel}->read(); - return( undef ) if ( !defined($buffer) ); + return( undef ) if ( !defined($buffer) ); - Debug( "Handling buffer '$buffer'\n" ); - my @messages = grep { s/-/|/g; 1; } split( /\r?\n/, $buffer ); - return( \@messages ); + Debug( "Handling buffer '$buffer'\n" ); + my @messages = grep { s/-/|/g; 1; } split( /\r?\n/, $buffer ); + return( \@messages ); } sub putMessages { - my $self = shift; - my $messages = shift; + my $self = shift; + my $messages = shift; - if ( @$messages ) - { - my $buffer = join( "\n", grep{ s/\|/-/; 1; } @$messages ); - $buffer .= "\n"; - if ( !$self->{channel}->write( $buffer ) ) - { - Error( "Unable to write buffer '".$buffer." to connection ".$self->{name}." (".$self->fileno().")\n" ); - } - } - return( undef ); + if ( @$messages ) + { + my $buffer = join( "\n", grep{ s/\|/-/; 1; } @$messages ); + $buffer .= "\n"; + if ( !$self->{channel}->write( $buffer ) ) + { + Error( "Unable to write buffer '".$buffer." to connection ".$self->{name}." (".$self->fileno().")\n" ); + } + } + return( undef ); } 1; diff --git a/scripts/zm.in b/scripts/zm.in index 33c32ac6c..b600cd983 100755 --- a/scripts/zm.in +++ b/scripts/zm.in @@ -16,12 +16,12 @@ LOCKFILE=/var/lock/subsys/zm loadconf() { - if [ -f $ZM_CONFIG ]; then - . $ZM_CONFIG - else - echo "ERROR: $ZM_CONFIG not found." - return 1 - fi + if [ -f $ZM_CONFIG ]; then + . $ZM_CONFIG + else + echo "ERROR: $ZM_CONFIG not found." + return 1 + fi } loadconf @@ -30,95 +30,95 @@ command="$ZM_PATH_BIN/zmpkg.pl" start() { # Commenting out as it is not needed. Leaving as a placeholder for future use. -# zmupdate || return $? - loadconf || return $? - #Make sure the directory for our PID folder exists or create one. - [ ! -d $pidfile ] \ - && mkdir -m 774 $pidfile \ - && chown $ZM_WEB_USER:$ZM_WEB_GROUP $pidfile - #Make sure the folder for the socks file exists or create one - GetPath="select Value from Config where Name='ZM_PATH_SOCKS'" +# zmupdate || return $? + loadconf || return $? + #Make sure the directory for our PID folder exists or create one. + [ ! -d $pidfile ] \ + && mkdir -m 774 $pidfile \ + && chown $ZM_WEB_USER:$ZM_WEB_GROUP $pidfile + #Make sure the folder for the socks file exists or create one + GetPath="select Value from Config where Name='ZM_PATH_SOCKS'" dbHost=`echo $ZM_DB_HOST | cut -d: -f1` dbPort=`echo $ZM_DB_HOST | cut -d: -s -f2` if [ "$dbPort" = "" ] then - ZM_PATH_SOCK=`echo $GetPath | mysql -B -h$ZM_DB_HOST -u$ZM_DB_USER -p$ZM_DB_PASS $ZM_DB_NAME | grep -v '^Value'` + ZM_PATH_SOCK=`echo $GetPath | mysql -B -h$ZM_DB_HOST -u$ZM_DB_USER -p$ZM_DB_PASS $ZM_DB_NAME | grep -v '^Value'` else - ZM_PATH_SOCK=`echo $GetPath | mysql -B -h$dbHost -P$dbPort -u$ZM_DB_USER -p$ZM_DB_PASS $ZM_DB_NAME | grep -v '^Value'` + ZM_PATH_SOCK=`echo $GetPath | mysql -B -h$dbHost -P$dbPort -u$ZM_DB_USER -p$ZM_DB_PASS $ZM_DB_NAME | grep -v '^Value'` fi - [ ! -d $ZM_PATH_SOCK ] \ - && mkdir -m 774 $ZM_PATH_SOCK \ - && chown $ZM_WEB_USER:$ZM_WEB_GROUP $ZM_PATH_SOCK - echo -n $"Starting $prog: " - $command start - RETVAL=$? - [ $RETVAL = 0 ] && success || failure - echo - [ $RETVAL = 0 ] && touch $LOCKFILE - return $RETVAL + [ ! -d $ZM_PATH_SOCK ] \ + && mkdir -m 774 $ZM_PATH_SOCK \ + && chown $ZM_WEB_USER:$ZM_WEB_GROUP $ZM_PATH_SOCK + echo -n $"Starting $prog: " + $command start + RETVAL=$? + [ $RETVAL = 0 ] && success || failure + echo + [ $RETVAL = 0 ] && touch $LOCKFILE + return $RETVAL } stop() { - loadconf - echo -n $"Stopping $prog: " - $command stop - RETVAL=$? - [ $RETVAL = 0 ] && success || failure - echo - [ $RETVAL = 0 ] && rm -f $LOCKFILE + loadconf + echo -n $"Stopping $prog: " + $command stop + RETVAL=$? + [ $RETVAL = 0 ] && success || failure + echo + [ $RETVAL = 0 ] && rm -f $LOCKFILE } zmstatus() { - loadconf - result=`$command status` - if [ "$result" = "running" ]; then - echo "ZoneMinder is running" - $ZM_PATH_BIN/zmu -l - RETVAL=0 - else - echo "ZoneMinder is stopped" - RETVAL=1 - fi + loadconf + result=`$command status` + if [ "$result" = "running" ]; then + echo "ZoneMinder is running" + $ZM_PATH_BIN/zmu -l + RETVAL=0 + else + echo "ZoneMinder is stopped" + RETVAL=1 + fi } zmupdate() { - if [ -x $ZM_PATH_BIN/zmupdate.pl ]; then - $ZM_PATH_BIN/zmupdate.pl -f - fi + if [ -x $ZM_PATH_BIN/zmupdate.pl ]; then + $ZM_PATH_BIN/zmupdate.pl -f + fi } case "$1" in - 'start') - start - ;; - 'stop') - stop - ;; - 'restart') - stop - start - ;; - 'condrestart') - loadconf - result=`$ZM_PATH_BIN/zmdc.pl check` - if [ "$result" = "running" ]; then - $ZM_PATH_BIN/zmdc.pl shutdown > /dev/null - rm -f $LOCKFILE - start - fi - ;; - 'status') - status httpd - status mysqld - zmstatus - ;; - *) - echo "Usage: $0 { start | stop | restart | condrestart | status }" - RETVAL=1 - ;; + 'start') + start + ;; + 'stop') + stop + ;; + 'restart') + stop + start + ;; + 'condrestart') + loadconf + result=`$ZM_PATH_BIN/zmdc.pl check` + if [ "$result" = "running" ]; then + $ZM_PATH_BIN/zmdc.pl shutdown > /dev/null + rm -f $LOCKFILE + start + fi + ;; + 'status') + status httpd + status mysqld + zmstatus + ;; + *) + echo "Usage: $0 { start | stop | restart | condrestart | status }" + RETVAL=1 + ;; esac exit $RETVAL diff --git a/scripts/zmaudit.pl.in b/scripts/zmaudit.pl.in index f7bd18540..7a74303fc 100644 --- a/scripts/zmaudit.pl.in +++ b/scripts/zmaudit.pl.in @@ -20,15 +20,33 @@ # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # # ========================================================================== -# -# This script checks for consistency between the event filesystem and -# the database. If events are found in one and not the other they are -# deleted (optionally). Additionally any monitor event directories that -# do not correspond to a database monitor are similarly disposed of. -# However monitors in the database that don't have a directory are left -# alone as this is valid if they are newly created and have no events -# yet. -# + +=head1 NAME + +zmaudit.pl - ZoneMinder event file system and database consistency checker + +=head1 SYNOPSIS + + zmaudit.pl [-r,-report|-i,-interactive] + +=head1 DESCRIPTION + +This script checks for consistency between the event filesystem and +the database. If events are found in one and not the other they are +deleted (optionally). Additionally any monitor event directories that +do not correspond to a database monitor are similarly disposed of. +However monitors in the database that don't have a directory are left +alone as this is valid if they are newly created and have no events +yet. + +=head1 OPTIONS + + -r, --report - Just report don't actually do anything + -i, --interactive - Ask before applying any changes + -c, --continuous - Run continuously + -v, --version - Print the installed version of ZoneMinder + +=cut use strict; use bytes; @@ -38,7 +56,6 @@ use bytes; # # ========================================================================== -use constant MIN_AGE => 300; # Minimum age when we will delete anything use constant MAX_AGED_DIRS => 10; # Number of event dirs to check age on use constant RECOVER_TAG => "(r)"; # Tag to append to event name when recovered use constant RECOVER_TEXT => "Recovered."; # Text to append to event notes when recovered @@ -56,9 +73,13 @@ use POSIX; use File::Find; use Time::HiRes qw/gettimeofday/; use Getopt::Long; +use autouse 'Pod::Usage'=>qw(pod2usage); use constant IMAGE_PATH => $Config{ZM_PATH_WEB}.'/'.$Config{ZM_DIR_IMAGES}; -use constant EVENT_PATH => ($Config{ZM_DIR_EVENTS}=~m|/|)?$Config{ZM_DIR_EVENTS}:($Config{ZM_PATH_WEB}.'/'.$Config{ZM_DIR_EVENTS}); +use constant EVENT_PATH => ($Config{ZM_DIR_EVENTS}=~m|/|) + ? $Config{ZM_DIR_EVENTS} + : ($Config{ZM_PATH_WEB}.'/'.$Config{ZM_DIR_EVENTS}) +; $| = 1; @@ -71,39 +92,24 @@ my $interactive = 0; my $continuous = 0; my $version; -sub usage -{ - print( " -Usage: zmaudit.pl [-r,-report|-i,-interactive] -Parameters are :- --r, --report - Just report don't actually do anything --i, --interactive - Ask before applying any changes --c, --continuous - Run continuously --v, --version - Print the installed version of ZoneMinder -"); - exit( -1 ); -} - -sub aud_print( $ ); -sub confirm( ;$$ ); -sub deleteSwapImage(); - logInit(); logSetSignal(); -if ( !GetOptions( report=>\$report, interactive=>\$interactive, continuous=>\$continuous, version=>\$version ) ) -{ - usage(); -} +GetOptions( + 'report' =>\$report, + 'interactive' =>\$interactive, + 'continuous' =>\$continuous, + 'version' =>\$version +) or pod2usage(-exitstatus => -1); if ( $version ) { - print( ZoneMinder::Base::ZM_VERSION . "\n"); - exit(0); + print( ZoneMinder::Base::ZM_VERSION . "\n"); + exit(0); } if ( ($report + $interactive + $continuous) > 1 ) { print( STDERR "Error, only one option may be specified\n" ); - usage(); + pod2usage(-exitstatus => -1); } my $dbh = zmDbConnect(); @@ -113,36 +119,46 @@ chdir( EVENT_PATH ); my $max_image_age = 6/24; # 6 hours my $max_swap_age = 24/24; # 24 hours my $image_path = IMAGE_PATH; -my $swap_image_path = $Config{ZM_PATH_SWAP}; my $loop = 1; my $cleaned = 0; MAIN: while( $loop ) { - while ( ! ( $dbh and $dbh->ping() ) ) { - $dbh = zmDbConnect(); + while ( ! ( $dbh and $dbh->ping() ) ) { + $dbh = zmDbConnect(); - last if $dbh; - if ( $continuous ) { - # if we are running continuously, then just skip to the next interval, otherwise we are a one off run, so wait a second and retry until someone kills us. - sleep( $Config{ZM_AUDIT_CHECK_INTERVAL} ); - } else { - sleep 1; - } # end if - } # end while can't connect to the db + last if $dbh; + if ( $continuous ) { + # if we are running continuously, then just skip to the next + # interval, otherwise we are a one off run, so wait a second and + # retry until someone kills us. + sleep( $Config{ZM_AUDIT_CHECK_INTERVAL} ); + } else { + sleep 1; + } # end if + } # end while can't connect to the db - my $db_monitors; + if ( ! exists $Config{ZM_AUDIT_MIN_AGE} ) { + Fatal("ZM_AUDIT_MIN_AGE is not set in config."); + } + + my $db_monitors; my $monitorSelectSql = "select Id from Monitors order by Id"; - my $monitorSelectSth = $dbh->prepare_cached( $monitorSelectSql ) or Fatal( "Can't prepare '$monitorSelectSql': ".$dbh->errstr() ); - my $eventSelectSql = "select Id, (unix_timestamp() - unix_timestamp(StartTime)) as Age from Events where MonitorId = ? order by Id"; - my $eventSelectSth = $dbh->prepare_cached( $eventSelectSql ) or Fatal( "Can't prepare '$eventSelectSql': ".$dbh->errstr() ); + my $monitorSelectSth = $dbh->prepare_cached( $monitorSelectSql ) + or Fatal( "Can't prepare '$monitorSelectSql': ".$dbh->errstr() ); + my $eventSelectSql = "SELECT Id, (unix_timestamp() - unix_timestamp(StartTime)) as Age + FROM Events WHERE MonitorId = ? ORDER BY Id"; + my $eventSelectSth = $dbh->prepare_cached( $eventSelectSql ) + or Fatal( "Can't prepare '$eventSelectSql': ".$dbh->errstr() ); $cleaned = 0; - my $res = $monitorSelectSth->execute() or Fatal( "Can't execute: ".$monitorSelectSth->errstr() ); + my $res = $monitorSelectSth->execute() + or Fatal( "Can't execute: ".$monitorSelectSth->errstr() ); while( my $monitor = $monitorSelectSth->fetchrow_hashref() ) { Debug( "Found database monitor '$monitor->{Id}'" ); my $db_events = $db_monitors->{$monitor->{Id}} = {}; - my $res = $eventSelectSth->execute( $monitor->{Id} ) or Fatal( "Can't execute: ".$eventSelectSth->errstr() ); + my $res = $eventSelectSth->execute( $monitor->{Id} ) + or Fatal( "Can't execute: ".$eventSelectSth->errstr() ); while ( my $event = $eventSelectSth->fetchrow_hashref() ) { $db_events->{$event->{Id}} = $event->{Age}; @@ -151,7 +167,7 @@ MAIN: while( $loop ) { } my $fs_monitors; - foreach my $monitor ( <[0-9]*> ) + foreach my $monitor ( glob("[0-9]*") ) { Debug( "Found filesystem monitor '$monitor'" ); my $fs_events = $fs_monitors->{$monitor} = {}; @@ -159,12 +175,13 @@ MAIN: while( $loop ) { if ( $Config{ZM_USE_DEEP_STORAGE} ) { - foreach my $day_dir ( <$monitor_dir/*/*/*> ) + foreach my $day_dir ( glob("$monitor_dir/*/*/*") ) { Debug( "Checking $day_dir" ); ( $day_dir ) = ( $day_dir =~ /^(.*)$/ ); # De-taint chdir( $day_dir ); - opendir( DIR, "." ) or Fatal( "Can't open directory '$day_dir': $!" ); + opendir( DIR, "." ) + or Fatal( "Can't open directory '$day_dir': $!" ); my @event_links = sort { $b <=> $a } grep { -l $_ } readdir( DIR ); closedir( DIR ); my $count = 0; @@ -231,7 +248,7 @@ MAIN: while( $loop ) { { while ( my ( $fs_event, $age ) = each(%$fs_events ) ) { - if ( !defined($db_events->{$fs_event}) && ($age < 0 || ($age > MIN_AGE)) ) + if ( !defined($db_events->{$fs_event}) && ($age < 0 || ($age > $Config{ZM_AUDIT_MIN_AGE})) ) { aud_print( "Filesystem event '$fs_monitor/$fs_event' does not exist in database" ); if ( confirm() ) @@ -256,7 +273,7 @@ MAIN: while( $loop ) { } my $monitor_links; - foreach my $link ( <*> ) + foreach my $link ( glob("*") ) { next if ( !-l $link ); next if ( -e $link ); @@ -274,13 +291,17 @@ MAIN: while( $loop ) { $cleaned = 0; my $deleteMonitorSql = "delete low_priority from Monitors where Id = ?"; - my $deleteMonitorSth = $dbh->prepare_cached( $deleteMonitorSql ) or Fatal( "Can't prepare '$deleteMonitorSql': ".$dbh->errstr() ); + my $deleteMonitorSth = $dbh->prepare_cached( $deleteMonitorSql ) + or Fatal( "Can't prepare '$deleteMonitorSql': ".$dbh->errstr() ); my $deleteEventSql = "delete low_priority from Events where Id = ?"; - my $deleteEventSth = $dbh->prepare_cached( $deleteEventSql ) or Fatal( "Can't prepare '$deleteEventSql': ".$dbh->errstr() ); + my $deleteEventSth = $dbh->prepare_cached( $deleteEventSql ) + or Fatal( "Can't prepare '$deleteEventSql': ".$dbh->errstr() ); my $deleteFramesSql = "delete low_priority from Frames where EventId = ?"; - my $deleteFramesSth = $dbh->prepare_cached( $deleteFramesSql ) or Fatal( "Can't prepare '$deleteFramesSql': ".$dbh->errstr() ); + my $deleteFramesSth = $dbh->prepare_cached( $deleteFramesSql ) + or Fatal( "Can't prepare '$deleteFramesSql': ".$dbh->errstr() ); my $deleteStatsSql = "delete low_priority from Stats where EventId = ?"; - my $deleteStatsSth = $dbh->prepare_cached( $deleteStatsSql ) or Fatal( "Can't prepare '$deleteStatsSql': ".$dbh->errstr() ); + my $deleteStatsSth = $dbh->prepare_cached( $deleteStatsSql ) + or Fatal( "Can't prepare '$deleteStatsSql': ".$dbh->errstr() ); while ( my ( $db_monitor, $db_events ) = each(%$db_monitors) ) { if ( my $fs_events = $fs_monitors->{$db_monitor} ) @@ -289,27 +310,33 @@ MAIN: while( $loop ) { { while ( my ( $db_event, $age ) = each(%$db_events ) ) { - if ( !defined($fs_events->{$db_event}) && ($age > MIN_AGE) ) - { - aud_print( "Database event '$db_monitor/$db_event' does not exist in filesystem" ); - if ( confirm() ) - { - my $res = $deleteEventSth->execute( $db_event ) or Fatal( "Can't execute: ".$deleteEventSth->errstr() ); - $res = $deleteFramesSth->execute( $db_event ) or Fatal( "Can't execute: ".$deleteFramesSth->errstr() ); - $res = $deleteStatsSth->execute( $db_event ) or Fatal( "Can't execute: ".$deleteStatsSth->errstr() ); - $cleaned = 1; - } + if ( !defined($fs_events->{$db_event}) ) { + if ( $age > $Config{ZM_AUDIT_MIN_AGE} ) { + aud_print( "Database event '$db_monitor/$db_event' does not exist in filesystem" ); + if ( confirm() ) { + my $res = $deleteEventSth->execute( $db_event ) + or Fatal( "Can't execute: ".$deleteEventSth->errstr() ); + $res = $deleteFramesSth->execute( $db_event ) + or Fatal( "Can't execute: ".$deleteFramesSth->errstr() ); + $res = $deleteStatsSth->execute( $db_event ) + or Fatal( "Can't execute: ".$deleteStatsSth->errstr() ); + $cleaned = 1; + } + } else { + aud_print( "Database event '$db_monitor/$db_event' does not exist in filesystem but too young to delete." ); + } } } } } else { - #aud_print( "Database monitor '$db_monitor' does not exist in filesystem" ); + aud_print( "Database monitor '$db_monitor' does not exist in filesystem" ); #if ( confirm() ) #{ # We don't actually do this in case it's new - #my $res = $deleteMonitorSth->execute( $db_monitor ) or Fatal( "Can't execute: ".$deleteMonitorSth->errstr() ); + #my $res = $deleteMonitorSth->execute( $db_monitor ) + # or Fatal( "Can't execute: ".$deleteMonitorSth->errstr() ); #$cleaned = 1; #} } @@ -318,15 +345,20 @@ MAIN: while( $loop ) { # Remove orphaned events (with no monitor) $cleaned = 0; - my $selectOrphanedEventsSql = "select Events.Id, Events.Name from Events left join Monitors on (Events.MonitorId = Monitors.Id) where isnull(Monitors.Id)"; - my $selectOrphanedEventsSth = $dbh->prepare_cached( $selectOrphanedEventsSql ) or Fatal( "Can't prepare '$selectOrphanedEventsSql': ".$dbh->errstr() ); - $res = $selectOrphanedEventsSth->execute() or Fatal( "Can't execute: ".$selectOrphanedEventsSth->errstr() ); + my $selectOrphanedEventsSql = "SELECT Events.Id, Events.Name + FROM Events LEFT JOIN Monitors ON (Events.MonitorId = Monitors.Id) + WHERE isnull(Monitors.Id)"; + my $selectOrphanedEventsSth = $dbh->prepare_cached( $selectOrphanedEventsSql ) + or Fatal( "Can't prepare '$selectOrphanedEventsSql': ".$dbh->errstr() ); + $res = $selectOrphanedEventsSth->execute() + or Fatal( "Can't execute: ".$selectOrphanedEventsSth->errstr() ); while( my $event = $selectOrphanedEventsSth->fetchrow_hashref() ) { aud_print( "Found orphaned event with no monitor '$event->{Id}'" ); if ( confirm() ) { - $res = $deleteEventSth->execute( $event->{Id} ) or Fatal( "Can't execute: ".$deleteEventSth->errstr() ); + $res = $deleteEventSth->execute( $event->{Id} ) + or Fatal( "Can't execute: ".$deleteEventSth->errstr() ); $cleaned = 1; } } @@ -334,15 +366,19 @@ MAIN: while( $loop ) { # Remove empty events (with no frames) $cleaned = 0; - my $selectEmptyEventsSql = "select * from Events as E left join Frames as F on (E.Id = F.EventId) where isnull(F.EventId) and now() - interval ".MIN_AGE." second > E.StartTime"; - my $selectEmptyEventsSth = $dbh->prepare_cached( $selectEmptyEventsSql ) or Fatal( "Can't prepare '$selectEmptyEventsSql': ".$dbh->errstr() ); - $res = $selectEmptyEventsSth->execute() or Fatal( "Can't execute: ".$selectEmptyEventsSth->errstr() ); + my $selectEmptyEventsSql = "SELECT * FROM Events as E LEFT JOIN Frames as F ON (E.Id = F.EventId) + WHERE isnull(F.EventId) AND now() - interval ".$Config{ZM_AUDIT_MIN_AGE}." second > E.StartTime"; + my $selectEmptyEventsSth = $dbh->prepare_cached( $selectEmptyEventsSql ) + or Fatal( "Can't prepare '$selectEmptyEventsSql': ".$dbh->errstr() ); + $res = $selectEmptyEventsSth->execute() + or Fatal( "Can't execute: ".$selectEmptyEventsSth->errstr() ); while( my $event = $selectEmptyEventsSth->fetchrow_hashref() ) { aud_print( "Found empty event with no frame records '$event->{Id}'" ); if ( confirm() ) { - $res = $deleteEventSth->execute( $event->{Id} ) or Fatal( "Can't execute: ".$deleteEventSth->errstr() ); + $res = $deleteEventSth->execute( $event->{Id} ) + or Fatal( "Can't execute: ".$deleteEventSth->errstr() ); $cleaned = 1; } } @@ -350,15 +386,19 @@ MAIN: while( $loop ) { # Remove orphaned frame records $cleaned = 0; - my $selectOrphanedFramesSql = "select distinct EventId from Frames where EventId not in (select Id from Events)"; - my $selectOrphanedFramesSth = $dbh->prepare_cached( $selectOrphanedFramesSql ) or Fatal( "Can't prepare '$selectOrphanedFramesSql': ".$dbh->errstr() ); - $res = $selectOrphanedFramesSth->execute() or Fatal( "Can't execute: ".$selectOrphanedFramesSth->errstr() ); + my $selectOrphanedFramesSql = "SELECT DISTINCT EventId FROM Frames + WHERE EventId NOT IN (SELECT Id FROM Events)"; + my $selectOrphanedFramesSth = $dbh->prepare_cached( $selectOrphanedFramesSql ) + or Fatal( "Can't prepare '$selectOrphanedFramesSql': ".$dbh->errstr() ); + $res = $selectOrphanedFramesSth->execute() + or Fatal( "Can't execute: ".$selectOrphanedFramesSth->errstr() ); while( my $frame = $selectOrphanedFramesSth->fetchrow_hashref() ) { aud_print( "Found orphaned frame records for event '$frame->{EventId}'" ); if ( confirm() ) { - $res = $deleteFramesSth->execute( $frame->{EventId} ) or Fatal( "Can't execute: ".$deleteFramesSth->errstr() ); + $res = $deleteFramesSth->execute( $frame->{EventId} ) + or Fatal( "Can't execute: ".$deleteFramesSth->errstr() ); $cleaned = 1; } } @@ -366,32 +406,84 @@ MAIN: while( $loop ) { # Remove orphaned stats records $cleaned = 0; - my $selectOrphanedStatsSql = "select distinct EventId from Stats where EventId not in (select Id from Events)"; - my $selectOrphanedStatsSth = $dbh->prepare_cached( $selectOrphanedStatsSql ) or Fatal( "Can't prepare '$selectOrphanedStatsSql': ".$dbh->errstr() ); - $res = $selectOrphanedStatsSth->execute() or Fatal( "Can't execute: ".$selectOrphanedStatsSth->errstr() ); + my $selectOrphanedStatsSql = "SELECT DISTINCT EventId FROM Stats + WHERE EventId NOT IN (SELECT Id FROM Events)"; + my $selectOrphanedStatsSth = $dbh->prepare_cached( $selectOrphanedStatsSql ) + or Fatal( "Can't prepare '$selectOrphanedStatsSql': ".$dbh->errstr() ); + $res = $selectOrphanedStatsSth->execute() + or Fatal( "Can't execute: ".$selectOrphanedStatsSth->errstr() ); while( my $stat = $selectOrphanedStatsSth->fetchrow_hashref() ) { aud_print( "Found orphaned statistic records for event '$stat->{EventId}'" ); if ( confirm() ) { - $res = $deleteStatsSth->execute( $stat->{EventId} ) or Fatal( "Can't execute: ".$deleteStatsSth->errstr() ); + $res = $deleteStatsSth->execute( $stat->{EventId} ) + or Fatal( "Can't execute: ".$deleteStatsSth->errstr() ); $cleaned = 1; } } redo MAIN if ( $cleaned ); # New audit to close any events that were left open for longer than MIN_AGE seconds - my $selectUnclosedEventsSql = "select E.Id, max(F.TimeStamp) as EndTime, unix_timestamp(max(F.TimeStamp)) - unix_timestamp(E.StartTime) as Length, max(F.FrameId) as Frames, count(if(F.Score>0,1,NULL)) as AlarmFrames, sum(F.Score) as TotScore, max(F.Score) as MaxScore, M.EventPrefix as Prefix from Events as E left join Monitors as M on E.MonitorId = M.Id inner join Frames as F on E.Id = F.EventId where isnull(E.Frames) or isnull(E.EndTime) group by E.Id having EndTime < (now() - interval ".MIN_AGE." second)"; - my $selectUnclosedEventsSth = $dbh->prepare_cached( $selectUnclosedEventsSql ) or Fatal( "Can't prepare '$selectUnclosedEventsSql': ".$dbh->errstr() ); - my $updateUnclosedEventsSql = "update low_priority Events set Name = ?, EndTime = ?, Length = ?, Frames = ?, AlarmFrames = ?, TotScore = ?, AvgScore = ?, MaxScore = ?, Notes = concat_ws( ' ', Notes, ? ) where Id = ?"; - my $updateUnclosedEventsSth = $dbh->prepare_cached( $updateUnclosedEventsSql ) or Fatal( "Can't prepare '$updateUnclosedEventsSql': ".$dbh->errstr() ); - $res = $selectUnclosedEventsSth->execute() or Fatal( "Can't execute: ".$selectUnclosedEventsSth->errstr() ); + my $selectUnclosedEventsSql = + "SELECT E.Id, + max(F.TimeStamp) as EndTime, + unix_timestamp(max(F.TimeStamp)) - unix_timestamp(E.StartTime) as Length, + max(F.FrameId) as Frames, + count(if(F.Score>0,1,NULL)) as AlarmFrames, + sum(F.Score) as TotScore, + max(F.Score) as MaxScore, + M.EventPrefix as Prefix + FROM Events as E + LEFT JOIN Monitors as M on E.MonitorId = M.Id + INNER JOIN Frames as F on E.Id = F.EventId + WHERE isnull(E.Frames) or isnull(E.EndTime) + GROUP BY E.Id HAVING EndTime < (now() - interval ".$Config{ZM_AUDIT_MIN_AGE}." second)" + ; + my $selectUnclosedEventsSth = $dbh->prepare_cached( $selectUnclosedEventsSql ) + or Fatal( "Can't prepare '$selectUnclosedEventsSql': ".$dbh->errstr() ); + my $updateUnclosedEventsSql = + "UPDATE low_priority Events + SET Name = ?, + EndTime = ?, + Length = ?, + Frames = ?, + AlarmFrames = ?, + TotScore = ?, + AvgScore = ?, + MaxScore = ?, + Notes = concat_ws( ' ', Notes, ? ) + WHERE Id = ?" + ; + my $updateUnclosedEventsSth = $dbh->prepare_cached( $updateUnclosedEventsSql ) + or Fatal( "Can't prepare '$updateUnclosedEventsSql': ".$dbh->errstr() ); + $res = $selectUnclosedEventsSth->execute() + or Fatal( "Can't execute: ".$selectUnclosedEventsSth->errstr() ); while( my $event = $selectUnclosedEventsSth->fetchrow_hashref() ) { aud_print( "Found open event '$event->{Id}'" ); if ( confirm( 'close', 'closing' ) ) { - $res = $updateUnclosedEventsSth->execute( sprintf( "%s%d%s", $event->{Prefix}, $event->{Id}, RECOVER_TAG ), $event->{EndTime}, $event->{Length}, $event->{Frames}, $event->{AlarmFrames}, $event->{TotScore}, $event->{AlarmFrames}?int($event->{TotScore}/$event->{AlarmFrames}):0, $event->{MaxScore}, RECOVER_TEXT, $event->{Id} ) or Fatal( "Can't execute: ".$updateUnclosedEventsSth->errstr() ); + $res = $updateUnclosedEventsSth->execute + ( + sprintf("%s%d%s", + $event->{Prefix}, + $event->{Id}, + RECOVER_TAG + ), + $event->{EndTime}, + $event->{Length}, + $event->{Frames}, + $event->{AlarmFrames}, + $event->{TotScore}, + $event->{AlarmFrames} + ? int($event->{TotScore} / $event->{AlarmFrames}) + : 0 + , + $event->{MaxScore}, + RECOVER_TEXT, + $event->{Id} + ) or Fatal( "Can't execute: ".$updateUnclosedEventsSth->errstr() ); } } @@ -405,7 +497,7 @@ MAIN: while( $loop ) { } # Now delete any old swap files - ( my $swap_image_root ) = ( $swap_image_path =~ /^(.*)$/ ); # De-taint + ( my $swap_image_root ) = ( $Config{ZM_PATH_SWAP} =~ /^(.*)$/ ); # De-taint File::Find::find( { wanted=>\&deleteSwapImage, untaint=>1 }, $swap_image_root ); # Prune the Logs table if required @@ -414,26 +506,43 @@ MAIN: while( $loop ) { if ( $Config{ZM_LOG_DATABASE_LIMIT} =~ /^\d+$/ ) { # Number of rows - my $selectLogRowCountSql = "select count(*) as Rows from Logs"; - my $selectLogRowCountSth = $dbh->prepare_cached( $selectLogRowCountSql ) or Fatal( "Can't prepare '$selectLogRowCountSql': ".$dbh->errstr() ); - $res = $selectLogRowCountSth->execute() or Fatal( "Can't execute: ".$selectLogRowCountSth->errstr() ); + my $selectLogRowCountSql = "SELECT count(*) as Rows from Logs"; + my $selectLogRowCountSth = $dbh->prepare_cached( $selectLogRowCountSql ) + or Fatal( "Can't prepare '$selectLogRowCountSql': ".$dbh->errstr() ); + $res = $selectLogRowCountSth->execute() + or Fatal( "Can't execute: ".$selectLogRowCountSth->errstr() ); my $row = $selectLogRowCountSth->fetchrow_hashref(); my $logRows = $row->{Rows}; if ( $logRows > $Config{ZM_LOG_DATABASE_LIMIT} ) { - my $deleteLogByRowsSql = "delete low_priority from Logs order by TimeKey asc limit ?"; - my $deleteLogByRowsSth = $dbh->prepare_cached( $deleteLogByRowsSql ) or Fatal( "Can't prepare '$deleteLogByRowsSql': ".$dbh->errstr() ); - $res = $deleteLogByRowsSth->execute( $logRows - $Config{ZM_LOG_DATABASE_LIMIT} ) or Fatal( "Can't execute: ".$deleteLogByRowsSth->errstr() ); - aud_print( "Deleted ".$deleteLogByRowsSth->rows()." log table entries by count\n" ) if ( $deleteLogByRowsSth->rows() ); + my $deleteLogByRowsSql = "DELETE low_priority FROM Logs ORDER BY TimeKey ASC LIMIT ?"; + my $deleteLogByRowsSth = $dbh->prepare_cached( $deleteLogByRowsSql ) + or Fatal( "Can't prepare '$deleteLogByRowsSql': ".$dbh->errstr() ); + $res = $deleteLogByRowsSth->execute( $logRows - $Config{ZM_LOG_DATABASE_LIMIT} ) + or Fatal( "Can't execute: ".$deleteLogByRowsSth->errstr() ); + if ( $deleteLogByRowsSth->rows() ) + { + aud_print( "Deleted ".$deleteLogByRowsSth->rows() + ." log table entries by count\n" ) + ; + } } } else { # Time of record - my $deleteLogByTimeSql = "delete low_priority from Logs where TimeKey < unix_timestamp(now() - interval ".$Config{ZM_LOG_DATABASE_LIMIT}.")"; - my $deleteLogByTimeSth = $dbh->prepare_cached( $deleteLogByTimeSql ) or Fatal( "Can't prepare '$deleteLogByTimeSql': ".$dbh->errstr() ); - $res = $deleteLogByTimeSth->execute() or Fatal( "Can't execute: ".$deleteLogByTimeSth->errstr() ); - aud_print( "Deleted ".$deleteLogByTimeSth->rows()." log table entries by time\n" ) if ( $deleteLogByTimeSth->rows() ); + my $deleteLogByTimeSql = + "DELETE low_priority FROM Logs + WHERE TimeKey < unix_timestamp(now() - interval ".$Config{ZM_LOG_DATABASE_LIMIT}.")"; + my $deleteLogByTimeSth = $dbh->prepare_cached( $deleteLogByTimeSql ) + or Fatal( "Can't prepare '$deleteLogByTimeSql': ".$dbh->errstr() ); + $res = $deleteLogByTimeSth->execute() + or Fatal( "Can't execute: ".$deleteLogByTimeSth->errstr() ); + if ( $deleteLogByTimeSth->rows() ){ + aud_print( "Deleted ".$deleteLogByTimeSth->rows() + ." log table entries by time\n" ) + ; + } } } $loop = $continuous; @@ -443,7 +552,7 @@ MAIN: while( $loop ) { exit( 0 ); -sub aud_print( $ ) +sub aud_print { my $string = shift; if ( !$continuous ) @@ -456,7 +565,7 @@ sub aud_print( $ ) } } -sub confirm( ;$$ ) +sub confirm { my $prompt = shift || "delete"; my $action = shift || "deleting"; @@ -496,7 +605,7 @@ sub confirm( ;$$ ) return( $yesno ); } -sub deleteSwapImage() +sub deleteSwapImage { my $file = $_; diff --git a/scripts/zmcamtool.pl.in b/scripts/zmcamtool.pl.in index cb4e036a9..eaa32edef 100644 --- a/scripts/zmcamtool.pl.in +++ b/scripts/zmcamtool.pl.in @@ -20,12 +20,43 @@ # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # # ========================================================================== -# -# This script provides a way to import new ptz camera controls & camera presets -# into existing zoneminder systems. This script also provides a way to export -# ptz camera controls & camera presets from an existing zoneminder system into -# a sql file, which can then be easily imported to another zoneminder system. -# + +=head1 NAME + +zmcamtool.pl - ZoneMinder tool to import camera controls and presets + +=head1 SYNOPSIS + + zmcamtool.pl [--user= --pass=] + [--import [file.sql] [--overwrite]] + [--export [name]] + [--topreset id [--noregex]] + +=head1 DESCRIPTION + +This script provides a way to import new ptz camera controls & camera presets +into existing zoneminder systems. This script also provides a way to export +ptz camera controls & camera presets from an existing zoneminder system into +a sql file, which can then be easily imported to another zoneminder system. + +=head1 OPTIONS + + --export - Export all camera controls and presets to STDOUT. + Optionally specify a control or preset name. + --import [file.sql] - Import new camera controls and presets found in + zm_create.sql into the ZoneMinder dB. + Optionally specify an alternate sql file to read from. + --overwrite - Overwrite any existing controls or presets. + with the same name as the new controls or presets. + --topreset id - Copy a monitor to a Camera Preset given the monitor id. + --noregex - Do not try to find and replace fields such as usernames, + passwords, IP addresses, etc with generic placeholders + when converting a monitor to a preset. + --help - Print usage information. + --user= - Alternate dB user with privileges to alter dB. + --pass= - Password of alternate dB user with privileges to alter dB. + +=cut use strict; use bytes; @@ -35,6 +66,7 @@ use ZoneMinder::Logger qw(:all); use ZoneMinder::Database qw(:all); use DBI; use Getopt::Long; +use autouse 'Pod::Usage'=>qw(pod2usage); $ENV{PATH} = '/bin:/usr/bin:/usr/local/bin'; $ENV{SHELL} = '/bin/sh' if exists $ENV{SHELL}; @@ -57,256 +89,258 @@ my $dbUser = $Config{ZM_DB_USER}; my $dbPass = $Config{ZM_DB_PASS}; my $version = 0; -# Process commandline parameters with getopt long -if ( !GetOptions( 'export'=>\$export, 'import'=>\$import, 'overwrite'=>\$overwrite, 'help'=>\$help, 'topreset'=>\$topreset, 'noregex'=>\$noregex, 'user:s'=>\$dbUser, 'pass:s'=>\$dbPass, 'version'=>\$version ) ) { - Usage(); -} +GetOptions( + 'export' =>\$export, + 'import' =>\$import, + 'overwrite' =>\$overwrite, + 'help' =>\$help, + 'topreset' =>\$topreset, + 'noregex' =>\$noregex, + 'user:s' =>\$dbUser, + 'pass:s' =>\$dbPass, + 'version' =>\$version +) or pod2usage(-exitstatus => -1); $Config{ZM_DB_USER} = $dbUser; $Config{ZM_DB_PASS} = $dbPass; if ( $version ) { - print( ZoneMinder::Base::ZM_VERSION . "\n"); - exit(0); + print( ZoneMinder::Base::ZM_VERSION . "\n"); + exit(0); } # Check to make sure commandline params make sense if ( ((!$help) && ($import + $export + $topreset) != 1 )) { - print( STDERR qq/Please give only one of the following: "import", "export", or "topreset".\n/ ); - Usage(); + print( STDERR qq/Please give only one of the following: "import", "export", or "topreset".\n/ ); + pod2usage(-exitstatus => -1); } if ( ($export)&&($overwrite) ) { - print( "Warning: Overwrite parameter ignored during an export.\n"); + print( "Warning: Overwrite parameter ignored during an export.\n"); } if ( ($noregex)&&(!$topreset) ) { - print( qq/Warning: Noregex parameter only applies when "topreset" parameter is also set. Ignoring.\n/); + print( qq/Warning: Noregex parameter only applies when "topreset" parameter is also set. Ignoring.\n/); } if ( ($topreset)&&($ARGV[0] !~ /\d\d*/) ) { - print( STDERR qq/Parameter "topreset" requires a valid monitor ID.\n/ ); - Usage(); + print( STDERR qq/Parameter "topreset" requires a valid monitor ID.\n/ ); + pod2usage(-exitstatus => -1); } # Call the appropriate subroutine based on the params given on the commandline if ($help) { - Usage(); + pod2usage(-exitstatus => -1); } if ($export) { - exportsql(); + exportsql(); } if ($import) { - importsql(); + importsql(); } if ($topreset) { - toPreset(); + toPreset(); } ############### # SUBROUTINES # ############### -# Usage subroutine help text -sub Usage -{ -die(" -USAGE: -zmcamtool.pl [--user= --pass=] - [--import [file.sql] [--overwrite]] - [--export [name]] - [--topreset id [--noregex]] - -PARAMETERS: ---export - Export all camera controls and presets to STDOUT. - Optionally specify a control or preset name. ---import [file.sql] - Import new camera controls and presets found in - zm_create.sql into the ZoneMinder dB. - Optionally specify an alternate sql file to read from. ---overwrite - Overwrite any existing controls or presets. - with the same name as the new controls or presets. ---topreset id - Copy a monitor to a Camera Preset given the monitor id. ---noregex - Do not try to find and replace fields such as usernames, - passwords, ip addresses, etc with generic placeholders - when converting a monitor to a preset. ---help - Print usage information. ---user= - Alternate dB user with privileges to alter dB. ---pass= - Password of alternate dB user with privileges to alter dB. -\n"); -} - # Execute a pre-built sql select query sub selectQuery { - my $dbh = shift; - my $sql = shift; - my $monitorid = shift; + my $dbh = shift; + my $sql = shift; + my $monitorid = shift; - my $sth = $dbh->prepare_cached( $sql ) or die( "Can't prepare '$sql': ".$dbh->errstr() ); - my $res = $sth->execute($monitorid) or die( "Can't execute: ".$sth->errstr() ); + my $sth = $dbh->prepare_cached( $sql ) + or die( "Can't prepare '$sql': ".$dbh->errstr() ); + my $res = $sth->execute($monitorid) + or die( "Can't execute: ".$sth->errstr() ); - my @data = $sth->fetchrow_array(); - $sth->finish(); + my @data = $sth->fetchrow_array(); + $sth->finish(); - return @data; + return @data; } # Exectute a pre-built sql query sub runQuery { - my $dbh = shift; - my $sql = shift; - my $sth = $dbh->prepare_cached( $sql ) or die( "Can't prepare '$sql': ".$dbh->errstr() ); - my $res = $sth->execute() or die( "Can't execute: ".$sth->errstr() ); - $sth->finish(); + my $dbh = shift; + my $sql = shift; + my $sth = $dbh->prepare_cached( $sql ) + or die( "Can't prepare '$sql': ".$dbh->errstr() ); + my $res = $sth->execute() + or die( "Can't execute: ".$sth->errstr() ); + $sth->finish(); - return $res; + return $res; } # Build and execute a sql insert query sub insertQuery { - my $dbh = shift; - my $tablename = shift; - my @data = @_; + my $dbh = shift; + my $tablename = shift; + my @data = @_; - my $sql = "insert into $tablename values (NULL,".(join ", ", ("?") x @data).")"; # Add "?" for each array element + my $sql = "INSERT INTO $tablename VALUES (NULL," + .(join ", ", ("?") x @data).")"; # Add "?" for each array element - my $sth = $dbh->prepare_cached( $sql ) or die( "Can't prepare '$sql': ".$dbh->errstr() ); - my $res = $sth->execute(@data) or die( "Can't execute: ".$sth->errstr() ); - $sth->finish(); + my $sth = $dbh->prepare_cached( $sql ) + or die( "Can't prepare '$sql': ".$dbh->errstr() ); + my $res = $sth->execute(@data) + or die( "Can't execute: ".$sth->errstr() ); + $sth->finish(); - return $res; + return $res; } # Build and execute a sql delete query sub deleteQuery { - my $dbh = shift; - my $sqltable = shift; - my $sqlname = shift; + my $dbh = shift; + my $sqltable = shift; + my $sqlname = shift; - my $sql = "delete from $sqltable where Name = ?"; - my $sth = $dbh->prepare_cached( $sql ) or die( "Can't prepare '$sql': ".$dbh->errstr() ); - my $res = $sth->execute($sqlname) or die( "Can't execute: ".$sth->errstr() ); - $sth->finish(); + my $sql = "DELETE FROM $sqltable WHERE Name = ?"; + my $sth = $dbh->prepare_cached( $sql ) + or die( "Can't prepare '$sql': ".$dbh->errstr() ); + my $res = $sth->execute($sqlname) + or die( "Can't execute: ".$sth->errstr() ); + $sth->finish(); - return $res; + return $res; } # Build and execute a sql select count query sub checkExists { - my $dbh = shift; - my $sqltable = shift; - my $sqlname = shift; - my $result = 0; + my $dbh = shift; + my $sqltable = shift; + my $sqlname = shift; + my $result = 0; - my $sql = "select count(*) from $sqltable where Name = ?"; - my $sth = $dbh->prepare_cached( $sql ) or die( "Can't prepare '$sql': ".$dbh->errstr() ); - my $res = $sth->execute($sqlname) or die( "Can't execute: ".$sth->errstr() ); + my $sql = "SELECT count(*) FROM $sqltable WHERE Name = ?"; + my $sth = $dbh->prepare_cached( $sql ) + or die( "Can't prepare '$sql': ".$dbh->errstr() ); + my $res = $sth->execute($sqlname) + or die( "Can't execute: ".$sth->errstr() ); - my $rows = $sth->fetchrow_arrayref(); - $sth->finish(); + my $rows = $sth->fetchrow_arrayref(); + $sth->finish(); - if ($rows->[0] > 0) { - $result = 1; - } + if ($rows->[0] > 0) { + $result = 1; + } - return $result; + return $result; } # Import camera control & presets into the zoneminder dB sub importsql { - my @newcontrols; - my @overwritecontrols; - my @skippedcontrols; - my @newpresets; - my @overwritepresets; - my @skippedpresets; - my %controls; - my %monitorpresets; + my @newcontrols; + my @overwritecontrols; + my @skippedcontrols; + my @newpresets; + my @overwritepresets; + my @skippedpresets; + my %controls; + my %monitorpresets; - if ($ARGV[0]) { - $sqlfile = $ARGV[0]; - } else { - $sqlfile = $Config{ZM_PATH_DATA}.'/db/zm_create.sql'; - } + if ($ARGV[0]) { + $sqlfile = $ARGV[0]; + } else { + $sqlfile = $Config{ZM_PATH_DATA}.'/db/zm_create.sql'; + } - open(my $SQLFILE,"<",$sqlfile) or die( "Can't Open file: $!\n" ); + open(my $SQLFILE,"<",$sqlfile) + or die( "Can't Open file: $!\n" ); - # Find and extract ptz control and monitor preset records - while (<$SQLFILE>) { - # Our regex replaces the primary key with NULL - if (s/^(INSERT INTO .*?Controls.*? VALUES \().*?(,')(.*?)(',.*)/$1NULL$2$3$4/i) { - $controls{$3} = $_; - } elsif (s/^(INSERT INTO .*?MonitorPresets.*? VALUES \().*?(,')(.*?)(',.*)/$1NULL$2$3$4/i) { - $monitorpresets{$3} = $_; - } - } - close $SQLFILE; + # Find and extract ptz control and monitor preset records + while (<$SQLFILE>) { + # Our regex replaces the primary key with NULL + if (s/^(INSERT INTO .*?Controls.*? VALUES \().*?(,')(.*?)(',.*)/$1NULL$2$3$4/i) { + $controls{$3} = $_; + } elsif (s/^(INSERT INTO .*?MonitorPresets.*? VALUES \().*?(,')(.*?)(',.*)/$1NULL$2$3$4/i) { + $monitorpresets{$3} = $_; + } + } + close $SQLFILE; - if ( ! (%controls || %monitorpresets) ) { - die( "Error: No relevant data found in $sqlfile.\n" ); - } + if ( ! (%controls || %monitorpresets) ) { + die( "Error: No relevant data found in $sqlfile.\n" ); + } - # Now that we've got what we were looking for, compare to what is already in the dB + # Now that we've got what we were looking for, + # compare to what is already in the dB - my $dbh = zmDbConnect(); - foreach (keys %controls) { - if (!checkExists($dbh,"Controls",$_)) { - # No existing Control was found. Add new control to dB. - runQuery($dbh,$controls{$_}); - push @newcontrols, $_; - } elsif ($overwrite) { - # An existing Control was found and the overwrite flag is set. Overwrite the control. - deleteQuery($dbh,"Controls",$_); - runQuery($dbh,$controls{$_}); - push @overwritecontrols, $_; - } else { - # An existing Control was found and the overwrite flag was not set. Do nothing. - push @skippedcontrols, $_; - } - } + my $dbh = zmDbConnect(); + foreach (keys %controls) { + if (!checkExists($dbh,"Controls",$_)) { + # No existing Control was found. Add new control to dB. + runQuery($dbh,$controls{$_}); + push @newcontrols, $_; + } elsif ($overwrite) { + # An existing Control was found and the overwrite flag is set. + # Overwrite the control. + deleteQuery($dbh,"Controls",$_); + runQuery($dbh,$controls{$_}); + push @overwritecontrols, $_; + } else { + # An existing Control was found and the overwrite flag was not set. + # Do nothing. + push @skippedcontrols, $_; + } + } - foreach (keys %monitorpresets) { - if (!checkExists($dbh,"MonitorPresets",$_)) { - # No existing MonitorPreset was found. Add new MonitorPreset to dB. - runQuery($dbh,$monitorpresets{$_}); - push @newpresets, $_; - } elsif ($overwrite) { - # An existing MonitorPreset was found and the overwrite flag is set. Overwrite the MonitorPreset. - deleteQuery($dbh,"MonitorPresets",$_); - runQuery($dbh,$monitorpresets{$_}); - push @overwritepresets, $_; - } else { - # An existing MonitorPreset was found and the overwrite flag was not set. Do nothing. - push @skippedpresets, $_; - } - } + foreach (keys %monitorpresets) { + if (!checkExists($dbh,"MonitorPresets",$_)) { + # No existing MonitorPreset was found. Add new MonitorPreset to dB. + runQuery($dbh,$monitorpresets{$_}); + push @newpresets, $_; + } elsif ($overwrite) { + # An existing MonitorPreset was found and the overwrite flag is set. + # Overwrite the MonitorPreset. + deleteQuery($dbh,"MonitorPresets",$_); + runQuery($dbh,$monitorpresets{$_}); + push @overwritepresets, $_; + } else { + # An existing MonitorPreset was found and the overwrite flag was + # not set. Do nothing. + push @skippedpresets, $_; + } + } - if (@newcontrols) { - print "Number of ptz camera controls added: ".scalar(@newcontrols)."\n"; - } - if (@overwritecontrols) { - print "Number of existing ptz camera controls overwritten: ".scalar(@overwritecontrols)."\n"; - } - if (@skippedcontrols) { - print "Number of existing ptz camera controls skipped: ".scalar(@skippedcontrols)."\n"; - } + if (@newcontrols) { + print "Number of ptz camera controls added: " + .scalar(@newcontrols)."\n"; + } + if (@overwritecontrols) { + print "Number of existing ptz camera controls overwritten: " + .scalar(@overwritecontrols)."\n"; + } + if (@skippedcontrols) { + print "Number of existing ptz camera controls skipped: " + .scalar(@skippedcontrols)."\n"; + } - if (@newpresets) { - print "Number of monitor presets added: ".scalar(@newpresets)."\n"; - } - if (@overwritepresets) { - print "Number of existing monitor presets overwritten: ".scalar(@overwritepresets)."\n"; - } - if (@skippedpresets) { - print "Number of existing presets skipped: ".scalar(@skippedpresets)."\n"; - } + if (@newpresets) { + print "Number of monitor presets added: " + .scalar(@newpresets)."\n"; + } + if (@overwritepresets) { + print "Number of existing monitor presets overwritten: " + .scalar(@overwritepresets)."\n"; + } + if (@skippedpresets) { + print "Number of existing presets skipped: " + .scalar(@skippedpresets)."\n"; + } } # Export camera controls & presets from the zoneminder dB to STDOUT @@ -317,14 +351,14 @@ my ( $host, $port ) = ( $Config{ZM_DB_HOST} =~ /^([^:]+)(?::(.+))?$/ ); my $command = "mysqldump -t --skip-opt --compact -h".$host; $command .= " -P".$port if defined($port); if ( $dbUser ) { - $command .= " -u".$dbUser; - if ( $dbPass ) { - $command .= " -p".$dbPass; - } - } + $command .= " -u".$dbUser; + if ( $dbPass ) { + $command .= " -p".$dbPass; + } + } if ($ARGV[0]) { - $command .= qq( --where="Name = '$ARGV[0]'"); + $command .= qq( --where="Name = '$ARGV[0]'"); } $command .= " zm Controls MonitorPresets"; @@ -332,78 +366,81 @@ $command .= " zm Controls MonitorPresets"; my $output = qx($command); my $status = $? >> 8; if ( $status || logDebugging() ) { - chomp( $output ); - print( "Output: $output\n" ); + chomp( $output ); + print( "Output: $output\n" ); } if ( $status ) { - die( "Command '$command' exited with status: $status\n" ); + die( "Command '$command' exited with status: $status\n" ); } else { - # NULLify the primary keys before printing the output to STDOUT - $output =~ s/VALUES \((.*?),'/VALUES \(NULL,'/ig; - print $output; - } + # NULLify the primary keys before printing the output to STDOUT + $output =~ s/VALUES \((.*?),'/VALUES \(NULL,'/ig; + print $output; + } } sub toPreset { - my $dbh = zmDbConnect(); - my $monitorid = $ARGV[0]; + my $dbh = zmDbConnect(); + my $monitorid = $ARGV[0]; - # Grap the following fields from the Monitors table - my $sql = "select - Name, - Type, - Device, - Channel, - Format, - Protocol, - Method, - Host, - Port, - Path, - SubPath, - Width, - Height, - Palette, - MaxFPS, - Controllable, - ControlId, - ControlDevice, - ControlAddress, - DefaultRate, - DefaultScale - from Monitors where Id = ?"; - my @data = selectQuery($dbh,$sql,$monitorid); + # Grap the following fields from the Monitors table + my $sql = "SELECT + Name, + Type, + Device, + Channel, + Format, + Protocol, + Method, + Host, + Port, + Path, + SubPath, + Width, + Height, + Palette, + MaxFPS, + Controllable, + ControlId, + ControlDevice, + ControlAddress, + DefaultRate, + DefaultScale + FROM Monitors WHERE Id = ?"; + my @data = selectQuery($dbh,$sql,$monitorid); - if (!@data) { - die( "Error: Monitor Id $monitorid does not appear to exist in the database.\n" ); - } + if (!@data) { + die( "Error: Monitor Id $monitorid does not appear to exist in the database.\n" ); + } - # Attempt to search for and replace system specific values such as ip addresses, ports, usernames, etc. with generic placeholders - if (!$noregex) { - foreach (@data) { - s/\b(?:\d{1,3}\.){3}\d{1,3}\b//; # ip address - s/:(6553[0-5]|655[0-2]\d|65[0-4]\d\d|6[0-4]\d{3}|[1-5]\d{4}|[1-9]\d{0,3}|0)$/:/; # tcpip port - s/\/\/.*:.*@/\/\/:@/; # user & pwd preceeding an ip address - s/(&|\?)(user|username)=\w\w*(&|\?)/$1$2=$3/i; # username embeded in url - s/(&|\?)(pwd|password)=\w\w*(&|\?)/$1$2=$3/i; # password embeded in url - s/\w\w*:\w\w*/:/; # user & pwd in their own field - s/\/dev\/video\d\d*/\/dev\/video/; # local video devices - } - } + # Attempt to search for and replace system specific values such as + # ip addresses, ports, usernames, etc. with generic placeholders + if (!$noregex) { + foreach (@data) { + s/\b(?:\d{1,3}\.){3}\d{1,3}\b//; # ip address + s/:(6553[0-5]|655[0-2]\d|65[0-4]\d\d|6[0-4]\d{3}|[1-5]\d{4}|[1-9]\d{0,3}|0)$/:/; # tcpip port + s/\/\/.*:.*@/\/\/:@/; # user & pwd preceeding an ip address + s/(&|\?)(user|username)=\w\w*(&|\?)/$1$2=$3/i; # username embeded in url + s/(&|\?)(pwd|password)=\w\w*(&|\?)/$1$2=$3/i; # password embeded in url + s/\w\w*:\w\w*/:/; # user & pwd in their own field + s/\/dev\/video\d\d*/\/dev\/video/; # local video devices + } + } - if (!checkExists($dbh,"MonitorPresets",$data[0])) { - # No existing Preset was found. Add new Preset to dB. - print "Adding new preset: $data[0]\n"; - insertQuery($dbh,"MonitorPresets",@data); - } elsif ($overwrite) { - # An existing Control was found and the overwrite flag is set. Overwrite the control. - print "Existing preset $data[0] detected.\nOverwriting...\n"; - deleteQuery($dbh,"MonitorPresets",$data[0]); - insertQuery($dbh,"MonitorPresets",@data); - } else { - # An existing Control was found and the overwrite flag was not set. Do nothing. - print "Existing preset $data[0] detected and overwrite flag not set.\nSkipping...\n"; - } + if (!checkExists($dbh,"MonitorPresets",$data[0])) { + # No existing Preset was found. Add new Preset to dB. + print "Adding new preset: $data[0]\n"; + insertQuery($dbh,"MonitorPresets",@data); + } elsif ($overwrite) { + # An existing Control was found and the overwrite flag is set. + # Overwrite the control. + print "Existing preset $data[0] detected.\nOverwriting...\n"; + deleteQuery($dbh,"MonitorPresets",$data[0]); + insertQuery($dbh,"MonitorPresets",@data); + } else { + # An existing Control was found and the overwrite flag was not set. + # Do nothing. + print "Existing preset $data[0] detected and overwrite flag not set.\nSkipping...\n"; + } } diff --git a/scripts/zmcontrol.pl.in b/scripts/zmcontrol.pl.in index 817b80cf6..ee078f9a0 100644 --- a/scripts/zmcontrol.pl.in +++ b/scripts/zmcontrol.pl.in @@ -20,16 +20,39 @@ # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # # ========================================================================== -# -# This script continuously monitors the recorded events for the given -# monitor and applies any filters which would delete and/or upload -# matching events -# + +=head1 NAME + +zmcontrol.pl - ZoneMinder control script + +=head1 SYNOPSIS + + zmcontrol.pl --id {monitor_id} --command={command} [various options] + +=head1 DESCRIPTION + +FIXME FIXME + +=head1 OPTIONS + + --autostop - + --xcoord [ arg ] - X-coord + --ycoord [ arg ] - Y-coord + --speed [ arg ] - Speed + --step [ arg ] - + --panspeed [ arg ] - + --panstep [ arg ] - + --tiltspeed [ arg ] - + --tiltstep [ arg ] - + --preset [ arg ] - + +=cut use strict; @EXTRA_PERL_LIB@ use ZoneMinder; use Getopt::Long; +use autouse 'Pod::Usage'=>qw(pod2usage); use POSIX qw/strftime EPIPE/; use Socket; #use Data::Dumper; @@ -44,14 +67,6 @@ $ENV{PATH} = '/bin:/usr/bin'; $ENV{SHELL} = '/bin/sh' if exists $ENV{SHELL}; delete @ENV{qw(IFS CDPATH ENV BASH_ENV)}; -sub Usage -{ - print( " -Usage: zmcontrol.pl --id --command= -"); - exit(); -} - logInit(); my $arg_string = join( " ", @ARGV ); @@ -59,29 +74,25 @@ my $arg_string = join( " ", @ARGV ); my $id; my %options; -if ( !GetOptions( - 'id=i'=>\$id, - 'command=s'=>\$options{command}, - 'xcoord=i'=>\$options{xcoord}, - 'ycoord=i'=>\$options{ycoord}, - 'speed=i'=>\$options{speed}, - 'step=i'=>\$options{step}, - 'panspeed=i'=>\$options{panspeed}, - 'tiltspeed=i'=>\$options{tiltspeed}, - 'panstep=i'=>\$options{panstep}, - 'tiltstep=i'=>\$options{tiltstep}, - 'preset=i'=>\$options{preset}, - 'autostop'=>\$options{autostop}, - ) -) -{ - Usage(); -} +GetOptions( + 'id=i' =>\$id, + 'command=s' =>\$options{command}, + 'xcoord=i' =>\$options{xcoord}, + 'ycoord=i' =>\$options{ycoord}, + 'speed=i' =>\$options{speed}, + 'step=i' =>\$options{step}, + 'panspeed=i' =>\$options{panspeed}, + 'tiltspeed=i' =>\$options{tiltspeed}, + 'panstep=i' =>\$options{panstep}, + 'tiltstep=i' =>\$options{tiltstep}, + 'preset=i' =>\$options{preset}, + 'autostop' =>\$options{autostop}, +) or pod2usage(-exitstatus => -1); if ( !$id || !$options{command} ) { print( STDERR "Please give a valid monitor id and command\n" ); - Usage(); + pod2usage(-exitstatus => -1); } ( $id ) = $id =~ /^(\w+)$/; @@ -90,13 +101,14 @@ Debug( $arg_string ); my $sock_file = $Config{ZM_PATH_SOCKS}.'/zmcontrol-'.$id.'.sock'; -socket( CLIENT, PF_UNIX, SOCK_STREAM, 0 ) or Fatal( "Can't open socket: $!" ); +socket( CLIENT, PF_UNIX, SOCK_STREAM, 0 ) + or Fatal( "Can't open socket: $!" ); my $saddr = sockaddr_un( $sock_file ); my $server_up = connect( CLIENT, $saddr ); if ( !$server_up ) { - # The server isn't there + # The server isn't there my $monitor = zmDbGetMonitorAndControl( $id ); if ( !$monitor ) { @@ -129,16 +141,17 @@ if ( !$server_up ) Info( "Starting control server $id/$protocol" ); close( CLIENT ); - if ( ! can_load( modules => { "ZoneMinder::Control::$protocol" => undef } ) ) { - Fatal("Can't load ZoneMinder::Control::$protocol"); - } + if ( ! can_load( modules => { "ZoneMinder::Control::$protocol" => undef } ) ) { + Fatal("Can't load ZoneMinder::Control::$protocol"); + } if ( my $cpid = fork() ) { logReinit(); # Parent process just sleep and fall through - socket( CLIENT, PF_UNIX, SOCK_STREAM, 0 ) or die( "Can't open socket: $!" ); + socket( CLIENT, PF_UNIX, SOCK_STREAM, 0 ) + or die( "Can't open socket: $!" ); my $attempts = 0; while (!connect( CLIENT, $saddr )) { @@ -156,7 +169,9 @@ if ( !$server_up ) logReinit(); - Info( "Control server $id/$protocol starting at ".strftime( '%y/%m/%d %H:%M:%S', localtime() ) ); + Info( "Control server $id/$protocol starting at " + .strftime( '%y/%m/%d %H:%M:%S', localtime() ) + ); $0 = $0." --id $id"; @@ -166,7 +181,8 @@ if ( !$server_up ) $control->open(); - socket( SERVER, PF_UNIX, SOCK_STREAM, 0 ) or Fatal( "Can't open socket: $!" ); + socket( SERVER, PF_UNIX, SOCK_STREAM, 0 ) + or Fatal( "Can't open socket: $!" ); unlink( $sock_file ); bind( SERVER, $saddr ) or Fatal( "Can't bind: $!" ); listen( SERVER, SOMAXCONN ) or Fatal( "Can't listen: $!" ); @@ -193,9 +209,9 @@ if ( !$server_up ) my $command = $params->{command}; close( CLIENT ); - if ( $command eq 'quit' ) { - last; - } + if ( $command eq 'quit' ) { + last; + } $control->$command( $params ); } else @@ -220,7 +236,9 @@ if ( !$server_up ) last; } } - Info( "Control server $id/$protocol exiting at ".strftime( '%y/%m/%d %H:%M:%S', localtime() ) ); + Info( "Control server $id/$protocol exiting at " + .strftime( '%y/%m/%d %H:%M:%S', localtime() ) + ); unlink( $sock_file ); $control->close(); exit( 0 ); diff --git a/scripts/zmdc.pl.in b/scripts/zmdc.pl.in index c209ae63f..981f7364e 100644 --- a/scripts/zmdc.pl.in +++ b/scripts/zmdc.pl.in @@ -20,13 +20,30 @@ # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # # ========================================================================== -# -# This script is the gateway for controlling the various ZoneMinder -# daemons. All starting, stopping and restarting goes through here. -# On the first invocation it starts up a server which subsequently -# records what's running and what's not. Other invocations just -# connect to the server and pass instructions to it. -# + +=head1 NAME + +zmdc.pl - ZoneMinder Daemon Control script + +=head1 SYNOPSIS + + zmdc.pl {command} [daemon [options]] + +=head1 DESCRIPTION + +This script is the gateway for controlling the various ZoneMinder +daemons. All starting, stopping and restarting goes through here. +On the first invocation it starts up a server which subsequently +records what's running and what's not. Other invocations just +connect to the server and pass instructions to it. + +=head1 OPTIONS + + {command} - One of 'startup|shutdown|status|check|logrot' or + 'start|stop|restart|reload|version'. + [daemon [options]] - Daemon name and options, required for second group of commands + +=cut use strict; use bytes; @@ -49,6 +66,7 @@ use ZoneMinder; use POSIX; use Socket; use IO::Handle; +use autouse 'Pod::Usage'=>qw(pod2usage); #use Data::Dumper; use constant SOCK_FILE => $Config{ZM_PATH_SOCKS}.'/zmdc.sock'; @@ -72,34 +90,22 @@ my @daemons = ( 'zmtrack.pl' ); -sub Usage -{ - print( " -Usage: zmdc.pl [daemon [options]] -Parameters are :- - - One of 'startup|shutdown|status|check|logrot' or - 'start|stop|restart|reload|version'. -[daemon [options]] - Daemon name and options, required for second group of commands -"); - exit( -1 ); -} - my $command = shift @ARGV; if( !$command ) { print( STDERR "No command given\n" ); - Usage(); + pod2usage(-exitstatus => -1); } if ( $command eq 'version' ) { - print ZoneMinder::Base::ZM_VERSION."\n"; - exit( 0 ); + print ZoneMinder::Base::ZM_VERSION."\n"; + exit( 0 ); } my $needs_daemon = $command !~ /(?:startup|shutdown|status|check|logrot|version)/; my $daemon = shift( @ARGV ); if( $needs_daemon && !$daemon ) { print( STDERR "No daemon given\n" ); - Usage(); + pod2usage(-exitstatus => -1); } my @args; @@ -113,7 +119,7 @@ if ( $needs_daemon ) else { print( STDERR "Invalid daemon '$daemon' specified" ); - Usage(); + pod2usage(-exitstatus => -1); } } @@ -152,7 +158,7 @@ if ( !$server_up ) print( "Unable to connect to server\n" ); exit( -1 ); } - # The server isn't there + # The server isn't there print( "Starting server\n" ); close( CLIENT ); @@ -235,12 +241,15 @@ sub run logInit(); - dPrint( ZoneMinder::Logger::INFO, "Server starting at ".strftime( '%y/%m/%d %H:%M:%S', localtime() )."\n" ); + dPrint( ZoneMinder::Logger::INFO, "Server starting at " + .strftime( '%y/%m/%d %H:%M:%S', localtime() ) + ."\n" + ); - if ( open( PID, ">".ZM_PID ) ) + if ( open( my $PID, '>', ZM_PID ) ) { - print( PID $$ ); - close( PID ); + print( $PID $$ ); + close( $PID ); } killAll( 1 ); @@ -354,7 +363,10 @@ sub run restartPending(); } } - dPrint( ZoneMinder::Logger::INFO, "Server exiting at ".strftime( '%y/%m/%d %H:%M:%S', localtime() )."\n" ); + dPrint( ZoneMinder::Logger::INFO, "Server exiting at " + .strftime( '%y/%m/%d %H:%M:%S', localtime() ) + ."\n" + ); unlink( main::SOCK_FILE ); unlink( ZM_PID ); exit(); @@ -413,7 +425,10 @@ sub start } elsif ( $process->{pid} && $pid_hash{$process->{pid}} ) { - dPrint( ZoneMinder::Logger::INFO, "'$process->{command}' already running at ".strftime( '%y/%m/%d %H:%M:%S', localtime( $process->{started}) ).", pid = $process->{pid}\n" ); + dPrint( ZoneMinder::Logger::INFO, "'$process->{command}' already running at " + .strftime( '%y/%m/%d %H:%M:%S', localtime( $process->{started}) ) + .", pid = $process->{pid}\n" + ); return(); } @@ -428,7 +443,10 @@ sub start $process->{started} = time(); delete( $process->{pending} ); - dPrint( ZoneMinder::Logger::INFO, "'$command' starting at ".strftime( '%y/%m/%d %H:%M:%S', localtime( $process->{started}) ).", pid = $process->{pid}\n" ); + dPrint( ZoneMinder::Logger::INFO, "'$command' starting at " + .strftime( '%y/%m/%d %H:%M:%S', localtime( $process->{started}) ) + .", pid = $process->{pid}\n" + ); $cmd_hash{$process->{command}} = $pid_hash{$cpid} = $process; sigprocmask( SIG_SETMASK, $sigset ) or Fatal( "Can't restore SIGCHLD: $!" ); @@ -437,7 +455,11 @@ sub start { logReinit(); - dPrint( ZoneMinder::Logger::INFO, "'".join( ' ', ( $daemon, @args ) )."' started at ".strftime( '%y/%m/%d %H:%M:%S', localtime() )."\n" ); + dPrint( ZoneMinder::Logger::INFO, "'".join( ' ', ( $daemon, @args ) ) + ."' started at " + .strftime( '%y/%m/%d %H:%M:%S', localtime() ) + ."\n" + ); if ( $daemon =~ /^${daemon_patt}$/ ) { @@ -501,7 +523,10 @@ sub _stop elsif ( $process->{pending} ) { delete( $cmd_hash{$command} ); - dPrint( ZoneMinder::Logger::INFO, "Command '$command' removed from pending list at ".strftime( '%y/%m/%d %H:%M:%S', localtime() )."\n" ); + dPrint( ZoneMinder::Logger::INFO, "Command '$command' removed from pending list at " + .strftime( '%y/%m/%d %H:%M:%S', localtime() ) + ."\n" + ); return(); } @@ -512,7 +537,11 @@ sub _stop return(); } - dPrint( ZoneMinder::Logger::INFO, "'$daemon ".join( ' ', @args )."' stopping at ".strftime( '%y/%m/%d %H:%M:%S', localtime() )."\n" ); + dPrint( ZoneMinder::Logger::INFO, "'$daemon ".join( ' ', @args ) + ."' stopping at " + .strftime( '%y/%m/%d %H:%M:%S', localtime() ) + ."\n" + ); $process->{keepalive} = !$final; kill( 'TERM', $cpid ); delete( $cmd_hash{$command} ); @@ -694,7 +723,10 @@ sub shutdownAll stop( $process->{daemon}, @{$process->{args}} ); } killAll( 5 ); - dPrint( ZoneMinder::Logger::INFO, "Server shutdown at ".strftime( '%y/%m/%d %H:%M:%S', localtime() )."\n" ); + dPrint( ZoneMinder::Logger::INFO, "Server shutdown at " + .strftime( '%y/%m/%d %H:%M:%S', localtime() ) + ."\n" + ); unlink( main::SOCK_FILE ); unlink( ZM_PID ); close( CLIENT ); @@ -750,7 +782,10 @@ sub status if ( $process->{pending} ) { - dPrint( ZoneMinder::Logger::DEBUG, "'$process->{command}' pending at ".strftime( '%y/%m/%d %H:%M:%S', localtime( $process->{pending}) )."\n" ); + dPrint( ZoneMinder::Logger::DEBUG, "'$process->{command}' pending at " + .strftime( '%y/%m/%d %H:%M:%S', localtime( $process->{pending}) ) + ."\n" + ); } else { @@ -761,13 +796,19 @@ sub status return(); } } - dPrint( ZoneMinder::Logger::DEBUG, "'$process->{command}' running since ".strftime( '%y/%m/%d %H:%M:%S', localtime( $process->{started}) ).", pid = $process->{pid}" ); + dPrint( ZoneMinder::Logger::DEBUG, "'$process->{command}' running since " + .strftime( '%y/%m/%d %H:%M:%S', localtime( $process->{started}) ) + .", pid = $process->{pid}" + ); } else { foreach my $process ( values(%pid_hash) ) { - my $out_str = "'$process->{command}' running since ".strftime( '%y/%m/%d %H:%M:%S', localtime( $process->{started}) ).", pid = $process->{pid}"; + my $out_str = "'$process->{command}' running since " + .strftime( '%y/%m/%d %H:%M:%S', localtime( $process->{started}) ) + .", pid = $process->{pid}" + ; $out_str .= ", valid" if ( kill( 0, $process->{pid} ) ); $out_str .= "\n"; dPrint( ZoneMinder::Logger::DEBUG, $out_str ); @@ -776,7 +817,10 @@ sub status { if ( $process->{pending} ) { - dPrint( ZoneMinder::Logger::DEBUG, "'$process->{command}' pending at ".strftime( '%y/%m/%d %H:%M:%S', localtime( $process->{pending}) )."\n" ); + dPrint( ZoneMinder::Logger::DEBUG, "'$process->{command}' pending at " + .strftime( '%y/%m/%d %H:%M:%S', localtime( $process->{pending}) ) + ."\n" + ); } } } @@ -786,19 +830,23 @@ sub killAll { my $delay = shift; sleep( $delay ); - my $killall; - if ( '@HOST_OS@' eq 'BSD' ) { - $killall = 'killall -'; - } else { - $killall = 'killall -q -s '; - } - foreach my $daemon ( @daemons ) { + my $killall; + if ( '@HOST_OS@' eq 'BSD' ) + { + $killall = 'killall -'; + } elsif ( '@HOST_OS@' eq 'solaris' ) { + $killall = 'pkill -'; + } else { + $killall = 'killall -q -s '; + } + foreach my $daemon ( @daemons ) + { - my $cmd = $killall ."TERM $daemon"; - Debug( $cmd ); - qx( $cmd ); - } - sleep( $delay ); + my $cmd = $killall ."TERM $daemon"; + Debug( $cmd ); + qx( $cmd ); + } + sleep( $delay ); foreach my $daemon ( @daemons ) { my $cmd = $killall."KILL $daemon"; diff --git a/scripts/zmfilter.pl.in b/scripts/zmfilter.pl.in index e8f8d998f..54f372262 100755 --- a/scripts/zmfilter.pl.in +++ b/scripts/zmfilter.pl.in @@ -20,11 +20,27 @@ # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # # ========================================================================== -# -# This script continuously monitors the recorded events for the given -# monitor and applies any filters which would delete and/or upload -# matching events -# + +=head1 NAME + +zmfilter.pl - ZoneMinder tool to filter events + +=head1 SYNOPSIS + + zmfilter.pl [-f ,--filter=] | -v, --version + +=head1 DESCRIPTION + +This script continuously monitors the recorded events for the given +monitor and applies any filters which would delete and/or upload +matching events. + +=head1 OPTIONS + + -f{filter name}, --filter={filter name} - The name of a specific filter to run + -v, --version - Print ZoneMinder version + +=cut use strict; use bytes; @@ -49,9 +65,13 @@ use POSIX; use Time::HiRes qw/gettimeofday/; use Date::Manip; use Getopt::Long; -use Data::Dumper; +use autouse 'Pod::Usage'=>qw(pod2usage); +use autouse 'Data::Dumper'=>qw(Dumper); -use constant EVENT_PATH => ($Config{ZM_DIR_EVENTS}=~m|/|)?$Config{ZM_DIR_EVENTS}:($Config{ZM_PATH_WEB}.'/'.$Config{ZM_DIR_EVENTS}); +use constant EVENT_PATH => ($Config{ZM_DIR_EVENTS}=~m|/|) + ? $Config{ZM_DIR_EVENTS} + : ($Config{ZM_PATH_WEB}.'/'.$Config{ZM_DIR_EVENTS}) +; logInit(); logSetSignal(); @@ -105,7 +125,6 @@ if ( $Config{ZM_OPT_MESSAGE} ) } } - $| = 1; $ENV{PATH} = '/bin:/usr/bin'; @@ -117,16 +136,6 @@ my $event_id = 0; my $filter_parm = ""; my $version = 0; -sub Usage -{ - print( " -Usage: zmfilter.pl [-f ,--filter=] | -v, --version -Parameters are :- --f, --filter= - The name of a specific filter to run -"); - exit( -1 ); -} - # # More or less replicates the equivalent PHP function # @@ -159,13 +168,14 @@ sub DateTimeToSQL return( strftime( "%Y-%m-%d %H:%M:%S", localtime( $dt_val ) ) ); } -if ( !GetOptions( 'filter=s'=>\$filter_parm, version=>\$version ) ) -{ - Usage(); -} +GetOptions( + 'filter=s' =>\$filter_parm, + 'version' =>\$version +) or pod2usage(-exitstatus => -1); + if ( $version ) { - print ZoneMinder::Base::ZM_VERSION . "\n"; - exit(0); + print ZoneMinder::Base::ZM_VERSION . "\n"; + exit(0); } if ( ! EVENT_PATH ) { @@ -196,7 +206,7 @@ my $last_action = 0; while( 1 ) { - my $now = time; + my $now = time; if ( ($now - $last_action) > $Config{ZM_FILTER_RELOAD_DELAY} ) { Debug( "Reloading filters\n" ); @@ -257,7 +267,7 @@ sub getFilters my $filter_name = shift; my @filters; - my $sql = "select * from Filters where"; + my $sql = "SELECT * FROM Filters WHERE"; if ( $filter_name ) { $sql .= " Name = ? and"; @@ -266,22 +276,56 @@ sub getFilters { $sql .= " Background = 1 and"; } - $sql .= " (AutoArchive = 1 or AutoVideo = 1 or AutoUpload = 1 or AutoEmail = 1 or AutoMessage = 1 or AutoExecute = 1 or AutoDelete = 1) order by Name"; - my $sth = $dbh->prepare_cached( $sql ) or Fatal( "Can't prepare '$sql': ".$dbh->errstr() ); + $sql .= "( AutoArchive = 1 + or AutoVideo = 1 + or AutoUpload = 1 + or AutoEmail = 1 + or AutoMessage = 1 + or AutoExecute = 1 + or AutoDelete = 1 + ) ORDER BY Name"; + my $sth = $dbh->prepare_cached( $sql ) + or Fatal( "Can't prepare '$sql': ".$dbh->errstr() ); my $res; if ( $filter_name ) { - $res = $sth->execute( $filter_name ) or Fatal( "Can't execute '$sql': ".$sth->errstr() ); + $res = $sth->execute( $filter_name ) + or Fatal( "Can't execute '$sql': ".$sth->errstr() ); } else { - $res = $sth->execute() or Fatal( "Can't execute '$sql': ".$sth->errstr() ); + $res = $sth->execute() + or Fatal( "Can't execute '$sql': ".$sth->errstr() ); } FILTER: while( my $db_filter = $sth->fetchrow_hashref() ) { Debug( "Found filter '$db_filter->{Name}'\n" ); my $filter_expr = jsonDecode( $db_filter->{Query} ); - my $sql = "select E.Id,E.MonitorId,M.Name as MonitorName,M.DefaultRate,M.DefaultScale,E.Name,E.Cause,E.Notes,E.StartTime,unix_timestamp(E.StartTime) as Time,E.Length,E.Frames,E.AlarmFrames,E.TotScore,E.AvgScore,E.MaxScore,E.Archived,E.Videoed,E.Uploaded,E.Emailed,E.Messaged,E.Executed from Events as E inner join Monitors as M on M.Id = E.MonitorId"; + my $sql = "SELECT E.Id, + E.MonitorId, + M.Name as MonitorName, + M.DefaultRate, + M.DefaultScale, + E.Name, + E.Cause, + E.Notes, + E.StartTime, + unix_timestamp(E.StartTime) as Time, + E.Length, + E.Frames, + E.AlarmFrames, + E.TotScore, + E.AvgScore, + E.MaxScore, + E.Archived, + E.Videoed, + E.Uploaded, + E.Emailed, + E.Messaged, + E.Executed + FROM Events as E + INNER JOIN Monitors as M on M.Id = E.MonitorId + "; $db_filter->{Sql} = ''; if ( $filter_expr->{terms} ) @@ -348,7 +392,10 @@ sub getFilters { $value = "'$temp_value'"; } - elsif ( $filter_expr->{terms}[$i]->{attr} eq 'Name' || $filter_expr->{terms}[$i]->{attr} eq 'Cause' || $filter_expr->{terms}[$i]->{attr} eq 'Notes' ) + elsif ( $filter_expr->{terms}[$i]->{attr} eq 'Name' + || $filter_expr->{terms}[$i]->{attr} eq 'Cause' + || $filter_expr->{terms}[$i]->{attr} eq 'Notes' + ) { $value = "'$temp_value'"; } @@ -357,7 +404,8 @@ sub getFilters $value = DateTimeToSQL( $temp_value ); if ( !$value ) { - Error( "Error parsing date/time '$temp_value', skipping filter '$db_filter->{Name}'\n" ); + Error( "Error parsing date/time '$temp_value', " + ."skipping filter '$db_filter->{Name}'\n" ); next FILTER; } $value = "'$value'"; @@ -367,7 +415,8 @@ sub getFilters $value = DateTimeToSQL( $temp_value ); if ( !$value ) { - Error( "Error parsing date/time '$temp_value', skipping filter '$db_filter->{Name}'\n" ); + Error( "Error parsing date/time '$temp_value', " + ."skipping filter '$db_filter->{Name}'\n" ); next FILTER; } $value = "to_days( '$value' )"; @@ -377,7 +426,8 @@ sub getFilters $value = DateTimeToSQL( $temp_value ); if ( !$value ) { - Error( "Error parsing date/time '$temp_value', skipping filter '$db_filter->{Name}'\n" ); + Error( "Error parsing date/time '$temp_value', " + ."skipping filter '$db_filter->{Name}'\n" ); next FILTER; } $value = "extract( hour_second from '$value' )"; @@ -469,7 +519,7 @@ sub getFilters my $sort_column = ''; if ( $filter_expr->{sort_field} eq 'Id' ) { - $sort_column = "E.Id"; + $sort_column = "E.Id"; } elsif ( $filter_expr->{sort_field} eq 'MonitorName' ) { @@ -525,13 +575,15 @@ sub getFilters $script =~ s/\s.*$//; if ( !-e $script ) { - Error( "Auto execute script '$script' not found, skipping filter '$db_filter->{Name}'\n" ); + Error( "Auto execute script '$script' not found, " + ."skipping filter '$db_filter->{Name}'\n" ); next FILTER; } elsif ( !-x $script ) { - Error( "Auto execute script '$script' not executable, skipping filter '$db_filter->{Name}'\n" ); + Error( "Auto execute script '$script' not executable, " + ."skipping filter '$db_filter->{Name}'\n" ); next FILTER; } } @@ -557,7 +609,7 @@ sub checkFilter "\n" ); my $sql = $filter->{Sql}; - + if ( $filter->{HasDiskPercent} ) { my $disk_percent = getDiskPercent(); @@ -574,7 +626,8 @@ sub checkFilter $sql =~ s/zmSystemLoad/$load/g; } - my $sth = $dbh->prepare_cached( $sql ) or Fatal( "Can't prepare '$sql': ".$dbh->errstr() ); + my $sth = $dbh->prepare_cached( $sql ) + or Fatal( "Can't prepare '$sql': ".$dbh->errstr() ); my $res = $sth->execute(); if ( !$res ) { @@ -591,8 +644,10 @@ sub checkFilter Info( "Archiving event $event->{Id}\n" ); # Do it individually to avoid locking up the table for new events my $sql = "update Events set Archived = 1 where Id = ?"; - my $sth = $dbh->prepare_cached( $sql ) or Fatal( "Can't prepare '$sql': ".$dbh->errstr() ); - my $res = $sth->execute( $event->{Id} ) or Fatal( "Can't execute '$sql': ".$sth->errstr() ); + my $sth = $dbh->prepare_cached( $sql ) + or Fatal( "Can't prepare '$sql': ".$dbh->errstr() ); + my $res = $sth->execute( $event->{Id} ) + or Fatal( "Can't execute '$sql': ".$sth->errstr() ); } if ( $Config{ZM_OPT_FFMPEG} && $filter->{AutoVideo} ) { @@ -636,18 +691,24 @@ sub checkFilter Info( "Deleting event $event->{Id} from Monitor $event->{MonitorId}\n" ); # Do it individually to avoid locking up the table for new events my $sql = "delete from Events where Id = ?"; - my $sth = $dbh->prepare_cached( $sql ) or Fatal( "Can't prepare '$sql': ".$dbh->errstr() ); - my $res = $sth->execute( $event->{Id} ) or Fatal( "Can't execute '$sql': ".$sth->errstr() ); + my $sth = $dbh->prepare_cached( $sql ) + or Fatal( "Can't prepare '$sql': ".$dbh->errstr() ); + my $res = $sth->execute( $event->{Id} ) + or Fatal( "Can't execute '$sql': ".$sth->errstr() ); if ( ! $Config{ZM_OPT_FAST_DELETE} ) { my $sql = "delete from Frames where EventId = ?"; - my $sth = $dbh->prepare_cached( $sql ) or Fatal( "Can't prepare '$sql': ".$dbh->errstr() ); - my $res = $sth->execute( $event->{Id} ) or Fatal( "Can't execute '$sql': ".$sth->errstr() ); + my $sth = $dbh->prepare_cached( $sql ) + or Fatal( "Can't prepare '$sql': ".$dbh->errstr() ); + my $res = $sth->execute( $event->{Id} ) + or Fatal( "Can't execute '$sql': ".$sth->errstr() ); $sql = "delete from Stats where EventId = ?"; - $sth = $dbh->prepare_cached( $sql ) or Fatal( "Can't prepare '$sql': ".$dbh->errstr() ); - $res = $sth->execute( $event->{Id} ) or Fatal( "Can't execute '$sql': ".$sth->errstr() ); + $sth = $dbh->prepare_cached( $sql ) + or Fatal( "Can't prepare '$sql': ".$dbh->errstr() ); + $res = $sth->execute( $event->{Id} ) + or Fatal( "Can't execute '$sql': ".$sth->errstr() ); deleteEventFiles( $event->{Id}, $event->{MonitorId} ); } @@ -699,7 +760,8 @@ sub generateVideo $format = $ffmpeg_formats[0]; } - my $command = $Config{ZM_PATH_BIN}."/zmvideo.pl -e ".$event->{Id}." -r ".$rate." -s ".$scale." -f ".$format; + my $command = $Config{ZM_PATH_BIN}."/zmvideo.pl -e " + .$event->{Id}." -r ".$rate." -s ".$scale." -f ".$format; my $output = qx($command); chomp( $output ); my $status = $? >> 8; @@ -719,11 +781,13 @@ sub generateVideo else { my $sql = "update Events set Videoed = 1 where Id = ?"; - my $sth = $dbh->prepare_cached( $sql ) or Fatal( "Can't prepare '$sql': ".$dbh->errstr() ); - my $res = $sth->execute( $event->{Id} ) or Fatal( "Can't execute '$sql': ".$sth->errstr() ); + my $sth = $dbh->prepare_cached( $sql ) + or Fatal( "Can't prepare '$sql': ".$dbh->errstr() ); + my $res = $sth->execute( $event->{Id} ) + or Fatal( "Can't execute '$sql': ".$sth->errstr() ); if ( wantarray() ) { - return( $format, sprintf( "%s/%s", getEventPath( $event ), $output ) ); + return( $format, sprintf( "%s/%s", getEventPath( $event ), $output ) ); } } return( 1 ); @@ -741,7 +805,15 @@ sub uploadArchFile } my $archFile = $event->{MonitorName}.'-'.$event->{Id}; - my $archImagePath = getEventPath( $event )."/".(( $Config{ZM_UPLOAD_ARCH_ANALYSE} )?'{*analyse,*capture}':'*capture').".jpg"; + my $archImagePath = getEventPath( $event ) + ."/" + .( + ( $Config{ZM_UPLOAD_ARCH_ANALYSE} ) + ? '{*analyse,*capture}' + : '*capture' + ) + .".jpg" + ; my @archImageFiles = glob($archImagePath); my $archLocPath; @@ -764,7 +836,10 @@ sub uploadArchFile $archError = 1; last; } - $member->desiredCompressionMethod( $Config{ZM_UPLOAD_ARCH_COMPRESS} ? &COMPRESSION_DEFLATED : &COMPRESSION_STORED ); + $member->desiredCompressionMethod( $Config{ZM_UPLOAD_ARCH_COMPRESS} + ? &COMPRESSION_DEFLATED + : &COMPRESSION_STORED + ); } if ( !$archError ) { @@ -793,7 +868,12 @@ sub uploadArchFile $archLocPath = $Config{ZM_UPLOAD_LOC_DIR}.'/'.$archFile; Info( "Creating upload file '$archLocPath', ".int(@archImageFiles)." files\n" ); - if ( $archError = !Archive::Tar->create_archive( $archLocPath, $Config{ZM_UPLOAD_ARCH_COMPRESS}, @archImageFiles ) ) + if ( $archError = !Archive::Tar->create_archive( + $archLocPath, + $Config{ZM_UPLOAD_ARCH_COMPRESS}, + @archImageFiles + ) + ) { Error( "Tar error: ".Archive::Tar->error()."\n " ); } @@ -808,42 +888,63 @@ sub uploadArchFile if ( $Config{ZM_UPLOAD_PROTOCOL} eq "ftp" ) { Info( "Uploading to ".$Config{ZM_UPLOAD_HOST}." using FTP\n" ); - my $ftp = Net::FTP->new( $Config{ZM_UPLOAD_HOST}, Timeout=>$Config{ZM_UPLOAD_TIMEOUT}, Passive=>$Config{ZM_UPLOAD_FTP_PASSIVE}, Debug=>$Config{ZM_UPLOAD_DEBUG} ); + my $ftp = Net::FTP->new( + $Config{ZM_UPLOAD_HOST}, + Timeout=>$Config{ZM_UPLOAD_TIMEOUT}, + Passive=>$Config{ZM_UPLOAD_FTP_PASSIVE}, + Debug=>$Config{ZM_UPLOAD_DEBUG} + ); if ( !$ftp ) { Error( "Can't create FTP connection: $@" ); return( 0 ); } - $ftp->login( $Config{ZM_UPLOAD_USER}, $Config{ZM_UPLOAD_PASS} ) or Error( "FTP - Can't login" ); - $ftp->binary() or Error( "FTP - Can't go binary" ); - $ftp->cwd( $Config{ZM_UPLOAD_REM_DIR} ) or Error( "FTP - Can't cwd" ) if ( $Config{ZM_UPLOAD_REM_DIR} ); - $ftp->put( $archLocPath ) or Error( "FTP - Can't upload '$archLocPath'" ); - $ftp->quit() or Error( "FTP - Can't quit" ); + $ftp->login( $Config{ZM_UPLOAD_USER}, $Config{ZM_UPLOAD_PASS} ) + or Error( "FTP - Can't login" ); + $ftp->binary() + or Error( "FTP - Can't go binary" ); + $ftp->cwd( $Config{ZM_UPLOAD_REM_DIR} ) + or Error( "FTP - Can't cwd" ) + if ( $Config{ZM_UPLOAD_REM_DIR} ); + $ftp->put( $archLocPath ) + or Error( "FTP - Can't upload '$archLocPath'" ); + $ftp->quit() + or Error( "FTP - Can't quit" ); } else { my $host = $Config{ZM_UPLOAD_HOST}; - $host .= ":".$Config{ZM_UPLOAD_PORT} if $Config{ZM_UPLOAD_PORT}; + $host .= ":".$Config{ZM_UPLOAD_PORT} + if $Config{ZM_UPLOAD_PORT}; Info( "Uploading to ".$host." using SFTP\n" ); my %sftpOptions = ( host=>$Config{ZM_UPLOAD_HOST}, user=>$Config{ZM_UPLOAD_USER} ); - $sftpOptions{password} = $Config{ZM_UPLOAD_PASS} if $Config{ZM_UPLOAD_PASS}; - $sftpOptions{port} = $Config{ZM_UPLOAD_PORT} if $Config{ZM_UPLOAD_PORT}; - $sftpOptions{timeout} = $Config{ZM_UPLOAD_TIMEOUT} if $Config{ZM_UPLOAD_TIMEOUT}; + $sftpOptions{password} = $Config{ZM_UPLOAD_PASS} + if $Config{ZM_UPLOAD_PASS}; + $sftpOptions{port} = $Config{ZM_UPLOAD_PORT} + if $Config{ZM_UPLOAD_PORT}; + $sftpOptions{timeout} = $Config{ZM_UPLOAD_TIMEOUT} + if $Config{ZM_UPLOAD_TIMEOUT}; $sftpOptions{more} = [ '-o'=>'StrictHostKeyChecking=no' ]; - $Net::SFTP::Foreign::debug = -1 if $Config{ZM_UPLOAD_DEBUG}; + $Net::SFTP::Foreign::debug = -1 + if $Config{ZM_UPLOAD_DEBUG}; my $sftp = Net::SFTP::Foreign->new( $Config{ZM_UPLOAD_HOST}, %sftpOptions ); if ( $sftp->error ) { Error( "Can't create SFTP connection: ".$sftp->error ); return( 0 ); } - $sftp->setcwd( $Config{ZM_UPLOAD_REM_DIR} ) or Error( "SFTP - Can't setcwd: ".$sftp->error ) if $Config{ZM_UPLOAD_REM_DIR}; - $sftp->put( $archLocPath, $archFile ) or Error( "SFTP - Can't upload '$archLocPath': ".$sftp->error ); + $sftp->setcwd( $Config{ZM_UPLOAD_REM_DIR} ) + or Error( "SFTP - Can't setcwd: ".$sftp->error ) + if $Config{ZM_UPLOAD_REM_DIR}; + $sftp->put( $archLocPath, $archFile ) + or Error( "SFTP - Can't upload '$archLocPath': ".$sftp->error ); } unlink( $archLocPath ); my $sql = "update Events set Uploaded = 1 where Id = ?"; - my $sth = $dbh->prepare_cached( $sql ) or Fatal( "Can't prepare '$sql': ".$dbh->errstr() ); - my $res = $sth->execute( $event->{Id} ) or Fatal( "Can't execute '$sql': ".$sth->errstr() ); + my $sth = $dbh->prepare_cached( $sql ) + or Fatal( "Can't prepare '$sql': ".$dbh->errstr() ); + my $res = $sth->execute( $event->{Id} ) + or Fatal( "Can't execute '$sql': ".$sth->errstr() ); } return( 1 ); } @@ -864,9 +965,28 @@ sub substituteTags if ( $need_monitor ) { my $db_now = strftime( "%Y-%m-%d %H:%M:%S", localtime() ); - my $sql = "select M.Id, count(E.Id) as EventCount, count(if(E.Archived,1,NULL)) as ArchEventCount, count(if(E.StartTime>'$db_now' - INTERVAL 1 HOUR && E.Archived = 0,1,NULL)) as HourEventCount, count(if(E.StartTime>'$db_now' - INTERVAL 1 DAY && E.Archived = 0,1,NULL)) as DayEventCount, count(if(E.StartTime>'$db_now' - INTERVAL 7 DAY && E.Archived = 0,1,NULL)) as WeekEventCount, count(if(E.StartTime>'$db_now' - INTERVAL 1 MONTH && E.Archived = 0,1,NULL)) as MonthEventCount from Monitors as M left join Events as E on E.MonitorId = M.Id where MonitorId = ? group by E.MonitorId order by Id"; - my $sth = $dbh->prepare_cached( $sql ) or Fatal( "Can't prepare '$sql': ".$dbh->errstr() ); - my $res = $sth->execute( $event->{MonitorId} ) or Fatal( "Can't execute '$sql': ".$sth->errstr() ); + my $sql = "SELECT + M.Id, + count(E.Id) as EventCount, + count(if(E.Archived,1,NULL)) + as ArchEventCount, + count(if(E.StartTime>'$db_now' - INTERVAL 1 HOUR && E.Archived = 0,1,NULL)) + as HourEventCount, + count(if(E.StartTime>'$db_now' - INTERVAL 1 DAY && E.Archived = 0,1,NULL)) + as DayEventCount, + count(if(E.StartTime>'$db_now' - INTERVAL 7 DAY && E.Archived = 0,1,NULL)) + as WeekEventCount, + count(if(E.StartTime>'$db_now' - INTERVAL 1 MONTH && E.Archived = 0,1,NULL)) + as MonthEventCount + FROM Monitors as M LEFT JOIN Events as E on E.MonitorId = M.Id + WHERE MonitorId = ? + GROUP BY E.MonitorId + ORDER BY Id" + ; + my $sth = $dbh->prepare_cached( $sql ) + or Fatal( "Can't prepare '$sql': ".$dbh->errstr() ); + my $res = $sth->execute( $event->{MonitorId} ) + or Fatal( "Can't execute '$sql': ".$sth->errstr() ); $monitor = $sth->fetchrow_hashref(); $sth->finish(); return() if ( !$monitor ); @@ -879,9 +999,14 @@ sub substituteTags my $max_alarm_score = 0; if ( $need_images ) { - my $sql = "select * from Frames where EventId = ? and Type = 'Alarm' order by FrameId"; - my $sth = $dbh->prepare_cached( $sql ) or Fatal( "Can't prepare '$sql': ".$dbh->errstr() ); - my $res = $sth->execute( $event->{Id} ) or Fatal( "Can't execute '$sql': ".$sth->errstr() ); + my $sql = "SELECT * FROM Frames + WHERE EventId = ? AND Type = 'Alarm' + ORDER BY FrameId" + ; + my $sth = $dbh->prepare_cached( $sql ) + or Fatal( "Can't prepare '$sql': ".$dbh->errstr() ); + my $res = $sth->execute( $event->{Id} ) + or Fatal( "Can't execute '$sql': ".$sth->errstr() ); while( my $frame = $sth->fetchrow_hashref() ) { if ( !$first_alarm_frame ) @@ -929,14 +1054,34 @@ sub substituteTags $text =~ s/%EPIM%/$url?view=frame&mid=$event->{MonitorId}&eid=$event->{Id}&fid=$max_alarm_frame->{FrameId}/g; if ( $attachments_ref && $text =~ s/%EI1%//g ) { - push( @$attachments_ref, { type=>"image/jpeg", path=>sprintf( "%s/%0".$Config{ZM_EVENT_IMAGE_DIGITS}."d-capture.jpg", getEventPath( $event ), $first_alarm_frame->{FrameId} ) } ); + push( @$attachments_ref, + { + type=>"image/jpeg", + path=>sprintf( + "%s/%0".$Config{ZM_EVENT_IMAGE_DIGITS}."d-capture.jpg", + getEventPath( $event ), + $first_alarm_frame->{FrameId} + ) + } + ); } if ( $attachments_ref && $text =~ s/%EIM%//g ) { # Don't attach the same image twice - if ( !@$attachments_ref || ($first_alarm_frame->{FrameId} != $max_alarm_frame->{FrameId} ) ) + if ( !@$attachments_ref + || ($first_alarm_frame->{FrameId} != $max_alarm_frame->{FrameId} ) + ) { - push( @$attachments_ref, { type=>"image/jpeg", path=>sprintf( "%s/%0".$Config{ZM_EVENT_IMAGE_DIGITS}."d-capture.jpg", getEventPath( $event ), $max_alarm_frame->{FrameId} ) } ); + push( @$attachments_ref, + { + type=>"image/jpeg", + path=>sprintf( + "%s/%0".$Config{ZM_EVENT_IMAGE_DIGITS}."d-capture.jpg", + getEventPath( $event ), + $max_alarm_frame->{FrameId} + ) + } + ); } } } @@ -964,7 +1109,7 @@ sub substituteTags $text =~ s/%FN%/$filter->{Name}/g; ( my $filter_name = $filter->{Name} ) =~ s/ /+/g; $text =~ s/%FP%/$url?view=filter&mid=$event->{MonitorId}&filter_name=$filter_name/g; - + return( $text ); } @@ -1023,7 +1168,7 @@ sub sendEmail ### Send the Message MIME::Lite->send( "smtp", $Config{ZM_EMAIL_HOST}, Timeout=>60 ); $mail->send(); - } + } else { my $mail = MIME::Entity->build( @@ -1056,8 +1201,10 @@ sub sendEmail Info( "Notification email sent\n" ); } my $sql = "update Events set Emailed = 1 where Id = ?"; - my $sth = $dbh->prepare_cached( $sql ) or Fatal( "Can't prepare '$sql': ".$dbh->errstr() ); - my $res = $sth->execute( $event->{Id} ) or Fatal( "Can't execute '$sql': ".$sth->errstr() ); + my $sth = $dbh->prepare_cached( $sql ) + or Fatal( "Can't prepare '$sql': ".$dbh->errstr() ); + my $res = $sth->execute( $event->{Id} ) + or Fatal( "Can't execute '$sql': ".$sth->errstr() ); return( 1 ); } @@ -1117,7 +1264,7 @@ sub sendMessage ### Send the Message MIME::Lite->send( "smtp", $Config{ZM_EMAIL_HOST}, Timeout=>60 ); $mail->send(); - } + } else { my $mail = MIME::Entity->build( @@ -1137,7 +1284,9 @@ sub sendMessage Encoding => "base64" ); } - $mail->smtpsend( Host => $Config{ZM_EMAIL_HOST}, MailFrom => $Config{ZM_FROM_EMAIL} ); + $mail->smtpsend( Host => $Config{ZM_EMAIL_HOST}, + MailFrom => $Config{ZM_FROM_EMAIL} + ); } }; if ( $@ ) @@ -1150,8 +1299,10 @@ sub sendMessage Info( "Notification message sent\n" ); } my $sql = "update Events set Messaged = 1 where Id = ?"; - my $sth = $dbh->prepare_cached( $sql ) or Fatal( "Can't prepare '$sql': ".$dbh->errstr() ); - my $res = $sth->execute( $event->{Id} ) or Fatal( "Can't execute '$sql': ".$sth->errstr() ); + my $sth = $dbh->prepare_cached( $sql ) + or Fatal( "Can't prepare '$sql': ".$dbh->errstr() ); + my $res = $sth->execute( $event->{Id} ) + or Fatal( "Can't execute '$sql': ".$sth->errstr() ); return( 1 ); } @@ -1182,8 +1333,10 @@ sub executeCommand else { my $sql = "update Events set Executed = 1 where Id = ?"; - my $sth = $dbh->prepare_cached( $sql ) or Fatal( "Can't prepare '$sql': ".$dbh->errstr() ); - my $res = $sth->execute( $event->{Id} ) or Fatal( "Can't execute '$sql': ".$sth->errstr() ); + my $sth = $dbh->prepare_cached( $sql ) + or Fatal( "Can't prepare '$sql': ".$dbh->errstr() ); + my $res = $sth->execute( $event->{Id} ) + or Fatal( "Can't execute '$sql': ".$sth->errstr() ); } return( 1 ); } diff --git a/scripts/zmpkg.pl.in b/scripts/zmpkg.pl.in index 084747bad..362f4f6a6 100644 --- a/scripts/zmpkg.pl.in +++ b/scripts/zmpkg.pl.in @@ -20,10 +20,21 @@ # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # # ========================================================================== -# -# This script is used to start and stop the ZoneMinder package primarily to -# allow command line control for automatic restart on reboot (see zm script) -# + +=head1 NAME + +zmpkg.pl - ZoneMinder Package Control Script + +=head1 SYNOPSIS + + zmpkg.pl {start|stop|restart|status|logrot|'state'|version} + +=head1 DESCRIPTION + +This script is used to start and stop the ZoneMinder package primarily to +allow command line control for automatic restart on reboot (see zm script) + +=cut use strict; use bytes; @@ -38,6 +49,7 @@ use ZoneMinder; use DBI; use POSIX; use Time::HiRes qw/gettimeofday/; +use autouse 'Pod::Usage'=>qw(pod2usage); # Detaint our environment $ENV{PATH} = '/bin:/usr/bin'; @@ -46,10 +58,10 @@ delete @ENV{qw(IFS CDPATH ENV BASH_ENV)}; logInit(); -my $command = $ARGV[0]; +my $command = $ARGV[0]||''; if ( $command eq 'version' ) { - print ZoneMinder::Base::ZM_VERSION . "\n"; - exit(0); + print ZoneMinder::Base::ZM_VERSION . "\n"; + exit(0); } my $state; @@ -58,39 +70,43 @@ my $dbh; if ( !$command || $command !~ /^(?:start|stop|restart|status|logrot|version)$/ ) { - if ( $command ) - { - $dbh = zmDbConnect(); - # Check to see if it's a valid run state - my $sql = 'select * from States where Name = ?'; - my $sth = $dbh->prepare_cached( $sql ) or Fatal( "Can't prepare '$sql': ".$dbh->errstr() ); - my $res = $sth->execute( $command ) or Fatal( "Can't execute: ".$sth->errstr() ); - if ( $state = $sth->fetchrow_hashref() ) - { - $state->{Name} = $command; - $state->{Definitions} = []; - foreach( split( /,/, $state->{Definition} ) ) - { - my ( $id, $function, $enabled ) = split( /:/, $_ ); - push( @{$state->{Definitions}}, { Id=>$id, Function=>$function, Enabled=>$enabled } ); - } - $command = 'state'; - } - else - { - $command = undef; - } - } - if ( !$command ) - { - print( "Usage: zmpkg.pl \n" ); - exit( -1 ); - } + if ( $command ) + { + $dbh = zmDbConnect(); + # Check to see if it's a valid run state + my $sql = 'select * from States where Name = ?'; + my $sth = $dbh->prepare_cached( $sql ) + or Fatal( "Can't prepare '$sql': ".$dbh->errstr() ); + my $res = $sth->execute( $command ) + or Fatal( "Can't execute: ".$sth->errstr() ); + if ( $state = $sth->fetchrow_hashref() ) + { + $state->{Name} = $command; + $state->{Definitions} = []; + foreach( split( /,/, $state->{Definition} ) ) + { + my ( $id, $function, $enabled ) = split( /:/, $_ ); + push( @{$state->{Definitions}}, + { Id=>$id, Function=>$function, Enabled=>$enabled } + ); + } + $command = 'state'; + } + else + { + $command = undef; + } + } + if ( !$command ) + { + pod2usage(-exitstatus => -1); + } } $dbh = zmDbConnect() if ! $dbh; # Move to the right place -chdir( $Config{ZM_PATH_WEB} ) or Fatal( "Can't chdir to '".$Config{ZM_PATH_WEB}."': $!" ); +chdir( $Config{ZM_PATH_WEB} ) + or Fatal( "Can't chdir to '".$Config{ZM_PATH_WEB}."': $!" ); my $dbg_id = ""; @@ -100,209 +116,232 @@ my $retval = 0; if ( $command eq "state" ) { - Info( "Updating DB: $state->{Name}\n" ); - my $sql = "select * from Monitors order by Id asc"; - my $sth = $dbh->prepare_cached( $sql ) or Fatal( "Can't prepare '$sql': ".$dbh->errstr() ); - my $res = $sth->execute() or Fatal( "Can't execute: ".$sth->errstr() ); - while( my $monitor = $sth->fetchrow_hashref() ) - { - foreach my $definition ( @{$state->{Definitions}} ) - { - if ( $monitor->{Id} =~ /^$definition->{Id}$/ ) - { - $monitor->{NewFunction} = $definition->{Function}; - $monitor->{NewEnabled} = $definition->{Enabled}; - } - } - #next if ( !$monitor->{NewFunction} ); - $monitor->{NewFunction} = 'None' if ( !$monitor->{NewFunction} ); - $monitor->{NewEnabled} = 0 if ( !$monitor->{NewEnabled} ); - if ( $monitor->{Function} ne $monitor->{NewFunction} || $monitor->{Enabled} ne $monitor->{NewEnabled} ) - { - my $sql = "update Monitors set Function = ?, Enabled = ? where Id = ?"; - my $sth = $dbh->prepare_cached( $sql ) or Fatal( "Can't prepare '$sql': ".$dbh->errstr() ); - my $res = $sth->execute( $monitor->{NewFunction}, $monitor->{NewEnabled}, $monitor->{Id} ) or Fatal( "Can't execute: ".$sth->errstr() ); - } - } - $sth->finish(); + Info( "Updating DB: $state->{Name}\n" ); + my $sql = "select * from Monitors order by Id asc"; + my $sth = $dbh->prepare_cached( $sql ) + or Fatal( "Can't prepare '$sql': ".$dbh->errstr() ); + my $res = $sth->execute() + or Fatal( "Can't execute: ".$sth->errstr() ); + while( my $monitor = $sth->fetchrow_hashref() ) + { + foreach my $definition ( @{$state->{Definitions}} ) + { + if ( $monitor->{Id} =~ /^$definition->{Id}$/ ) + { + $monitor->{NewFunction} = $definition->{Function}; + $monitor->{NewEnabled} = $definition->{Enabled}; + } + } + #next if ( !$monitor->{NewFunction} ); + $monitor->{NewFunction} = 'None' + if ( !$monitor->{NewFunction} ); + $monitor->{NewEnabled} = 0 + if ( !$monitor->{NewEnabled} ); + if ( $monitor->{Function} ne $monitor->{NewFunction} + || $monitor->{Enabled} ne $monitor->{NewEnabled} + ) + { + my $sql = "update Monitors set Function = ?, Enabled = ? where Id = ?"; + my $sth = $dbh->prepare_cached( $sql ) + or Fatal( "Can't prepare '$sql': ".$dbh->errstr() ); + my $res = $sth->execute( $monitor->{NewFunction}, $monitor->{NewEnabled}, $monitor->{Id} ) + or Fatal( "Can't execute: ".$sth->errstr() ); + } + } + $sth->finish(); - $command = "restart"; + $command = "restart"; } # Check if we are running systemd and if we have been called by the system if ( $command =~ /^(start|stop|restart)$/ ) { - # We have to detaint to keep perl from complaining - $command = $1; + # We have to detaint to keep perl from complaining + $command = $1; - if ( systemdRunning() && !calledBysystem() ) { - qx(@BINDIR@/zmsystemctl.pl $command); - $command = ""; - } + if ( systemdRunning() && !calledBysystem() ) { + qx(@BINDIR@/zmsystemctl.pl $command); + $command = ""; + } } if ( $command =~ /^(?:stop|restart)$/ ) { - my $status = runCommand( "zmdc.pl check" ); + my $status = runCommand( "zmdc.pl check" ); - if ( $status eq "running" ) - { - runCommand( "zmdc.pl shutdown" ); - zmMemTidy(); - } - else - { - $retval = 1; - } + if ( $status eq "running" ) + { + runCommand( "zmdc.pl shutdown" ); + zmMemTidy(); + } + else + { + $retval = 1; + } } #runCommand( "zmupdate.pl -f" ); if ( $command =~ /^(?:start|restart)$/ ) { - my $status = runCommand( "zmdc.pl check" ); + my $status = runCommand( "zmdc.pl check" ); - if ( $status eq "stopped" ) - { - if ( $Config{ZM_DYN_DB_VERSION} and ( $Config{ZM_DYN_DB_VERSION} ne ZM_VERSION ) ) + if ( $status eq "stopped" ) + { + if ( $Config{ZM_DYN_DB_VERSION} + and ( $Config{ZM_DYN_DB_VERSION} ne ZM_VERSION ) + ) { - Fatal( "Version mismatch, system is version ".ZM_VERSION.", database is ".$Config{ZM_DYN_DB_VERSION}.", please run zmupdate.pl to update." ); + Fatal( "Version mismatch, system is version ".ZM_VERSION + .", database is ".$Config{ZM_DYN_DB_VERSION} + .", please run zmupdate.pl to update." + ); exit( -1 ); } # Recreate the temporary directory if it's been wiped - verifyFolder("@ZM_TMPDIR@"); + verifyFolder("@ZM_TMPDIR@"); # Recreate the run directory if it's been wiped - verifyFolder("@ZM_RUNDIR@"); + verifyFolder("@ZM_RUNDIR@"); # Recreate the sock directory if it's been wiped - verifyFolder("@ZM_SOCKDIR@"); + verifyFolder("@ZM_SOCKDIR@"); - zmMemTidy(); - runCommand( "zmdc.pl startup" ); + zmMemTidy(); + runCommand( "zmdc.pl startup" ); - my $sql = "select * from Monitors"; - my $sth = $dbh->prepare_cached( $sql ) or Fatal( "Can't prepare '$sql': ".$dbh->errstr() ); - my $res = $sth->execute() or Fatal( "Can't execute: ".$sth->errstr() ); - while( my $monitor = $sth->fetchrow_hashref() ) - { - if ( $monitor->{Function} ne 'None' ) - { - if ( $monitor->{Type} eq 'Local' ) - { - runCommand( "zmdc.pl start zmc -d $monitor->{Device}" ); - } - else - { - runCommand( "zmdc.pl start zmc -m $monitor->{Id}" ); - } - if ( $monitor->{Function} ne 'Monitor' ) - { - if ( $Config{ZM_OPT_FRAME_SERVER} ) - { - runCommand( "zmdc.pl start zmf -m $monitor->{Id}" ); - } - runCommand( "zmdc.pl start zma -m $monitor->{Id}" ); - } - if ( $Config{ZM_OPT_CONTROL} ) - { - if ( $monitor->{Function} eq 'Modect' || $monitor->{Function} eq 'Mocord' ) - { - if ( $monitor->{Controllable} && $monitor->{TrackMotion} ) - { - runCommand( "zmdc.pl start zmtrack.pl -m $monitor->{Id}" ); - } - } - } - } - } - $sth->finish(); + my $sql = "select * from Monitors"; + my $sth = $dbh->prepare_cached( $sql ) + or Fatal( "Can't prepare '$sql': ".$dbh->errstr() ); + my $res = $sth->execute() + or Fatal( "Can't execute: ".$sth->errstr() ); + while( my $monitor = $sth->fetchrow_hashref() ) + { + if ( $monitor->{Function} ne 'None' ) + { + if ( $monitor->{Type} eq 'Local' ) + { + runCommand( "zmdc.pl start zmc -d $monitor->{Device}" ); + } + else + { + runCommand( "zmdc.pl start zmc -m $monitor->{Id}" ); + } + if ( $monitor->{Function} ne 'Monitor' ) + { + if ( $Config{ZM_OPT_FRAME_SERVER} ) + { + runCommand( "zmdc.pl start zmf -m $monitor->{Id}" ); + } + runCommand( "zmdc.pl start zma -m $monitor->{Id}" ); + } + if ( $Config{ZM_OPT_CONTROL} ) + { + if ( $monitor->{Function} eq 'Modect' || $monitor->{Function} eq 'Mocord' ) + { + if ( $monitor->{Controllable} && $monitor->{TrackMotion} ) + { + runCommand( "zmdc.pl start zmtrack.pl -m $monitor->{Id}" ); + } + } + } + } + } + $sth->finish(); - # This is now started unconditionally - runCommand( "zmdc.pl start zmfilter.pl" ); - if ( $Config{ZM_RUN_AUDIT} ) - { - runCommand( "zmdc.pl start zmaudit.pl -c" ); - } - if ( $Config{ZM_OPT_TRIGGERS} ) - { - runCommand( "zmdc.pl start zmtrigger.pl" ); - } - if ( $Config{ZM_OPT_X10} ) - { - runCommand( "zmdc.pl start zmx10.pl -c start" ); - } - runCommand( "zmdc.pl start zmwatch.pl" ); - if ( $Config{ZM_CHECK_FOR_UPDATES} ) - { - runCommand( "zmdc.pl start zmupdate.pl -c" ); - } - } - else - { - $retval = 1; - } + # This is now started unconditionally + runCommand( "zmdc.pl start zmfilter.pl" ); + if ( $Config{ZM_RUN_AUDIT} ) + { + runCommand( "zmdc.pl start zmaudit.pl -c" ); + } + if ( $Config{ZM_OPT_TRIGGERS} ) + { + runCommand( "zmdc.pl start zmtrigger.pl" ); + } + if ( $Config{ZM_OPT_X10} ) + { + runCommand( "zmdc.pl start zmx10.pl -c start" ); + } + runCommand( "zmdc.pl start zmwatch.pl" ); + if ( $Config{ZM_CHECK_FOR_UPDATES} ) + { + runCommand( "zmdc.pl start zmupdate.pl -c" ); + } + } + else + { + $retval = 1; + } } if ( $command eq "status" ) { - my $status = runCommand( "zmdc.pl check" ); + my $status = runCommand( "zmdc.pl check" ); - print( STDOUT $status."\n" ); + print( STDOUT $status."\n" ); } if ( $command eq "logrot" ) { - runCommand( "zmdc.pl logrot" ); + runCommand( "zmdc.pl logrot" ); } exit( $retval ); sub systemdRunning { - my $result = 0; + my $result = 0; - my $output = qx(ps -o comm="" 1); - chomp( $output ); + my $output = qx(ps -o comm="" -p 1); + chomp( $output ); - if ($output =~ /systemd/) { - $result = 1; - } + if ($output =~ /systemd/) { + $result = 1; + } - return $result; + return $result; } sub calledBysystem { - my $result = 0; - my $ppid = getppid(); + my $result = 0; + my $ppid = getppid(); - my $output = qx(ps -o comm="" $ppid); - chomp( $output ); + my $output = qx(ps -o comm="" -p $ppid); + chomp( $output ); - if ($output =~ /^(?:systemd|init)$/) { - $result = 1; - } + if ($output =~ /^(?:systemd|init)$/) { + $result = 1; + } - return $result; + return $result; } sub verifyFolder { - my $folder = shift; + my $folder = shift; # Recreate the temporary directory if it's been wiped if ( !-e $folder ) { Debug( "Recreating directory '$folder'" ); - mkdir( "$folder", 0774 ) or Fatal( "Can't create missing temporary directory '$folder': $!" ); + mkdir( "$folder", 0774 ) + or Fatal( "Can't create missing temporary directory '$folder': $!" ); my ( $runName ) = getpwuid( $> ); if ( $runName ne $Config{ZM_WEB_USER} ) { - # Not running as web user, so should be root in which case chown the directory - my ( $webName, $webPass, $webUid, $webGid ) = getpwnam( $Config{ZM_WEB_USER} ) or Fatal( "Can't get user details for web user '".$Config{ZM_WEB_USER}."': $!" ); - chown( $webUid, $webGid, "$folder" ) or Fatal( "Can't change ownership of directory '$folder' to '".$Config{ZM_WEB_USER}.":".$Config{ZM_WEB_GROUP}."': $!" ); + # Not running as web user, so should be root in which case + # chown the directory + my ( $webName, $webPass, $webUid, $webGid ) = getpwnam( $Config{ZM_WEB_USER} ) + or Fatal( "Can't get user details for web user '" + .$Config{ZM_WEB_USER}."': $!" + ); + chown( $webUid, $webGid, "$folder" ) + or Fatal( "Can't change ownership of directory '$folder' to '" + .$Config{ZM_WEB_USER}.":".$Config{ZM_WEB_GROUP}."': $!" + ); } } } diff --git a/scripts/zmsystemctl.pl.in b/scripts/zmsystemctl.pl.in index 450fc2189..c825d891b 100644 --- a/scripts/zmsystemctl.pl.in +++ b/scripts/zmsystemctl.pl.in @@ -2,7 +2,7 @@ # # ========================================================================== # -# ZoneMinder Update Script, $Date$, $Revision$ +# ZoneMinder systemctl wrapper, $Date$, $Revision$ # Copyright (C) 2001-2008 Philip Coombes # # This program is free software; you can redistribute it and/or @@ -20,25 +20,39 @@ # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # # ========================================================================== -# -# This is a wrapper script that allows zoneminder to start and stop itself -# in a manner that keeps it in-sync with systemd. This script is intended -# to be called internally by zoneminder and may not give the desired results -# if run from the command line. -# + +=head1 NAME + +zmsystemctl.pl - ZoneMinder systemctl wrapper + +=head1 SYNOPSIS + + zmsystemctl.pl {start|stop|restart|version} + +=head1 DESCRIPTION + +This is a wrapper script that allows zoneminder to start and stop itself +in a manner that keeps it in-sync with systemd. This script is intended +to be called internally by zoneminder and may not give the desired results +if run from the command line. + +=cut use warnings; use strict; use bytes; +use autouse 'Pod::Usage'=>qw(pod2usage); @EXTRA_PERL_LIB@ use ZoneMinder::Logger qw(:all); my $command = $ARGV[0]; -if ( (scalar(@ARGV) == 1) && ($command =~ /^(start|stop|restart|version)$/ )) { - $command = $1; +if ( (scalar(@ARGV) == 1) + && ($command =~ /^(start|stop|restart|version)$/ ) +){ + $command = $1; } else { - die(" USAGE: zmsystemctl.pl \n"); + pod2usage(-exitstatus => -1); } my $path = qx(which systemctl); @@ -46,7 +60,7 @@ chomp($path); my $status = $? >> 8; if ( !$path || $status ) { - Fatal( "Unable to determine systemctl executable. Is systemd in use?" ); + Fatal( "Unable to determine systemctl executable. Is systemd in use?" ); } Info( "Redirecting command through systemctl\n" ); diff --git a/scripts/zmtrack.pl.in b/scripts/zmtrack.pl.in index f3a5a0e15..b1eec2d7e 100644 --- a/scripts/zmtrack.pl.in +++ b/scripts/zmtrack.pl.in @@ -20,10 +20,26 @@ # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # # ========================================================================== -# -# This script is used to trigger and cancel alarms from external sources -# using an arbitrary text based format -# + +=head1 NAME + +zmtrack.pl - ZoneMinder Experimental PTZ Tracking Script + +=head1 SYNOPSIS + + zmtrack.pl -m + zmtrack.pl --monitor= + +=head1 OPTIONS + + -m, --monitor= - Id of the monitor to track + +=head1 DESCRIPTION + +This script is used to trigger and cancel alarms from external sources +using an arbitrary text based format. + +=cut use strict; use bytes; @@ -45,8 +61,9 @@ use constant SLEEP_TIME => 10000; # In microseconds use ZoneMinder; use DBI; use POSIX; -use Data::Dumper; +use autouse 'Data::Dumper'=>qw(Dumper); use Getopt::Long; +use autouse 'Pod::Usage'=>qw(pod2usage); use Time::HiRes qw( usleep ); $| = 1; @@ -57,20 +74,8 @@ delete @ENV{qw(IFS CDPATH ENV BASH_ENV)}; my $mid = 0; -sub Usage -{ - print( " - Usage: zmtrack.pl -m ,--monitor=] - Parameters are :- - -m, --monitor= - Id of the monitor to track - "); - exit( -1 ); -} - -if ( !GetOptions( 'monitor=s'=>\$mid ) ) -{ - Usage(); -} +GetOptions( 'monitor=s'=>\$mid ) + or pod2usage(-exitstatus => -1); logInit(); logSetSignal(); @@ -78,44 +83,52 @@ logSetSignal(); my ( $detaint_mid ) = $mid =~ /^(\d+)$/; $mid = $detaint_mid; -print( "Tracker daemon $mid (experimental) starting at ".strftime( '%y/%m/%d %H:%M:%S', localtime() )."\n" ); +print( "Tracker daemon $mid (experimental) starting at " + .strftime( '%y/%m/%d %H:%M:%S', localtime() ) + ."\n" +); my $dbh = zmDbConnect(); -my $sql = "select C.*,M.* from Monitors as M left join Controls as C on M.ControlId = C.Id where M.Id = ?"; -my $sth = $dbh->prepare_cached( $sql ) or Fatal( "Can't prepare '$sql': ".$dbh->errstr() ); +my $sql = "SELECT C.*,M.* FROM Monitors as M + LEFT JOIN Controls as C on M.ControlId = C.Id + WHERE M.Id = ?" +; +my $sth = $dbh->prepare_cached( $sql ) + or Fatal( "Can't prepare '$sql': ".$dbh->errstr() ); -my $res = $sth->execute( $mid ) or Fatal( "Can't execute '$sql': ".$sth->errstr() ); +my $res = $sth->execute( $mid ) + or Fatal( "Can't execute '$sql': ".$sth->errstr() ); my $monitor = $sth->fetchrow_hashref(); if ( !$monitor ) { - print( "Can't find monitor '$mid'\n" ); - exit( -1 ); + print( "Can't find monitor '$mid'\n" ); + exit( -1 ); } if ( !$monitor->{Controllable} ) { - print( "Monitor '$mid' is not controllable\n" ); - exit( -1 ); + print( "Monitor '$mid' is not controllable\n" ); + exit( -1 ); } if ( !$monitor->{TrackMotion} ) { - print( "Monitor '$mid' is not configured to track motion\n" ); - exit( -1 ); + print( "Monitor '$mid' is not configured to track motion\n" ); + exit( -1 ); } if ( !$monitor->{CanMoveMap} ) { - print( "Monitor '$mid' cannot move in map mode" ); - if ( $monitor->{CanMoveRel} ) - { - print( ", falling back to pseudo map mode\n" ); - } - else - { - print( "\n" ); - exit( -1 ); - } + print( "Monitor '$mid' cannot move in map mode" ); + if ( $monitor->{CanMoveRel} ) + { + print( ", falling back to pseudo map mode\n" ); + } + else + { + print( "\n" ); + exit( -1 ); + } } Debug( "Found monitor for id '$monitor'\n" ); @@ -123,84 +136,100 @@ exit( -1 ) if ( !zmMemVerify( $monitor ) ); sub Suspend { - my $monitor = shift; - zmMonitorSuspend( $monitor ); + my $monitor = shift; + zmMonitorSuspend( $monitor ); } sub Resume { - my $monitor = shift; - sleep( $monitor->{TrackDelay} ); - zmMonitorResume( $monitor ); + my $monitor = shift; + sleep( $monitor->{TrackDelay} ); + zmMonitorResume( $monitor ); } sub Track { - my $monitor = shift; - my ( $x, $y ) = @_; - my ( $detaint_x ) = $x =~ /^(\d+)$/; $x = $detaint_x; - my ( $detaint_y ) = $y =~ /^(\d+)$/; $y = $detaint_y; + my $monitor = shift; + my ( $x, $y ) = @_; + my ( $detaint_x ) = $x =~ /^(\d+)$/; $x = $detaint_x; + my ( $detaint_y ) = $y =~ /^(\d+)$/; $y = $detaint_y; - my $ctrlCommand = $Config{ZM_PATH_BIN}."/zmcontrol.pl -i ".$monitor->{Id}; - $ctrlCommand .= " --command=".($monitor->{CanMoveMap}?"moveMap":"movePseudoMap")." --xcoord=$x --ycoord=$y"; - executeShellCommand( $ctrlCommand ); + my $ctrlCommand = $Config{ZM_PATH_BIN} + ."/zmcontrol.pl -i " + .$monitor->{Id} + ; + $ctrlCommand .= " --command=" + .( $monitor->{CanMoveMap} ? "moveMap" + : "movePseudoMap" + ) + ." --xcoord=$x --ycoord=$y" + ; + executeShellCommand( $ctrlCommand ); } sub Return { - my $monitor = shift; + my $monitor = shift; - my $ctrlCommand = $Config{ZM_PATH_BIN}."/zmcontrol.pl -i ".$monitor->{Id}; - if ( $monitor->{ReturnLocation} > 0 ) - { - $ctrlCommand .= " --command=presetGoto --preset=".$monitor->{ReturnLocation}; - } - else - { - $ctrlCommand .= " --command=presetHome"; - } - executeShellCommand( $ctrlCommand ); + my $ctrlCommand = $Config{ZM_PATH_BIN} + ."/zmcontrol.pl -i " + .$monitor->{Id} + ; + if ( $monitor->{ReturnLocation} > 0 ) + { + $ctrlCommand .= " --command=presetGoto --preset=" + .$monitor->{ReturnLocation} + ; + } + else + { + $ctrlCommand .= " --command=presetHome"; + } + executeShellCommand( $ctrlCommand ); } my $last_alarm = 0; if ( ($monitor->{ReturnLocation} >= 0) ) { - Suspend( $monitor ); - Return( $monitor ); - Resume( $monitor ); + Suspend( $monitor ); + Return( $monitor ); + Resume( $monitor ); } my $alarmed = undef; while( 1 ) { - if ( zmIsAlarmed( $monitor ) ) - { - my ( $alarm_x, $alarm_y ) = zmGetAlarmLocation( $monitor ); - if ( $alarm_x >= 0 && $alarm_y >= 0 ) - { - Debug( "Got alarm at $alarm_x, $alarm_y\n" ); - Suspend( $monitor ); - Track( $monitor, $alarm_x, $alarm_y ); - Resume( $monitor ); - $last_alarm = time(); - $alarmed = !undef; - } - } - else - { - if ( logDebugging() && $alarmed ) - { - print( "Left alarm state\n" ); - $alarmed = undef; - } - if ( ($monitor->{ReturnLocation} >= 0) && ($last_alarm > 0) && ((time()-$last_alarm) > $monitor->{ReturnDelay}) ) - { - Debug( "Returning to location ".$monitor->{ReturnLocation}."\n" ); - Suspend( $monitor ); - Return( $monitor ); - Resume( $monitor ); - $last_alarm = 0; - } - } - usleep( SLEEP_TIME ); + if ( zmIsAlarmed( $monitor ) ) + { + my ( $alarm_x, $alarm_y ) = zmGetAlarmLocation( $monitor ); + if ( $alarm_x >= 0 && $alarm_y >= 0 ) + { + Debug( "Got alarm at $alarm_x, $alarm_y\n" ); + Suspend( $monitor ); + Track( $monitor, $alarm_x, $alarm_y ); + Resume( $monitor ); + $last_alarm = time(); + $alarmed = !undef; + } + } + else + { + if ( logDebugging() && $alarmed ) + { + print( "Left alarm state\n" ); + $alarmed = undef; + } + if ( ($monitor->{ReturnLocation} >= 0) + && ($last_alarm > 0) + && ((time()-$last_alarm) > $monitor->{ReturnDelay}) + ) + { + Debug( "Returning to location ".$monitor->{ReturnLocation}."\n" ); + Suspend( $monitor ); + Return( $monitor ); + Resume( $monitor ); + $last_alarm = 0; + } + } + usleep( SLEEP_TIME ); } diff --git a/scripts/zmtrigger.pl.in b/scripts/zmtrigger.pl.in index 7dbca9898..e43b00bbb 100644 --- a/scripts/zmtrigger.pl.in +++ b/scripts/zmtrigger.pl.in @@ -20,11 +20,17 @@ # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # # ========================================================================== -# -# This script is used to trigger and cancel alarms from external connections -# using an arbitrary text based format -# -# ========================================================================== + +=head1 NAME + +zmtrigger.pl - ZoneMinder External Trigger Script + +=head1 DESCRIPTION + +This script is used to trigger and cancel alarms from external connections +using an arbitrary text based format + +=cut use strict; use bytes; @@ -52,8 +58,22 @@ use ZoneMinder::Trigger::Channel::Serial; use ZoneMinder::Trigger::Connection; my @connections; -push( @connections, ZoneMinder::Trigger::Connection->new( name=>"Chan1", channel=>ZoneMinder::Trigger::Channel::Inet->new( port=>6802 ), mode=>"rw" ) ); -push( @connections, ZoneMinder::Trigger::Connection->new( name=>"Chan2", channel=>ZoneMinder::Trigger::Channel::Unix->new( path=>$Config{ZM_PATH_SOCKS}.'/zmtrigger.sock' ), mode=>"rw" ) ); +push( @connections, + ZoneMinder::Trigger::Connection->new( + name=>"Chan1", + channel=>ZoneMinder::Trigger::Channel::Inet->new( port=>6802 ), + mode=>"rw" + ) +); +push( @connections, + ZoneMinder::Trigger::Connection->new( + name=>"Chan2", + channel=>ZoneMinder::Trigger::Channel::Unix->new( + path=>$Config{ZM_PATH_SOCKS}.'/zmtrigger.sock' + ), + mode=>"rw" + ) +); #push( @connections, ZoneMinder::Trigger::Connection->new( name=>"Chan3", channel=>ZoneMinder::Trigger::Channel::File->new( path=>'/tmp/zmtrigger.out' ), mode=>"w" ) ); #push( @connections, ZoneMinder::Trigger::Connection->new( name=>"Chan4", channel=>ZoneMinder::Trigger::Channel::Serial->new( path=>'/dev/ttyS0' ), mode=>"rw" ) ); @@ -65,7 +85,7 @@ push( @connections, ZoneMinder::Trigger::Connection->new( name=>"Chan2", channel use DBI; #use Socket; -use Data::Dumper; +use autouse 'Data::Dumper'=>qw(Dumper); use POSIX qw( EINTR ); use Time::HiRes qw( usleep ); @@ -85,8 +105,8 @@ my $dbh = zmDbConnect(); my $base_rin = ''; foreach my $connection ( @connections ) { - Info( "Opening connection '$connection->{name}'\n" ); - $connection->open(); + Info( "Opening connection '$connection->{name}'\n" ); + $connection->open(); } my @in_select_connections = grep { $_->input() && $_->selectable() } @connections; @@ -95,7 +115,7 @@ my @out_connections = grep { $_->output() } @connections; foreach my $connection ( @in_select_connections ) { - vec( $base_rin, $connection->fileno(), 1 ) = 1; + vec( $base_rin, $connection->fileno(), 1 ) = 1; } my %spawned_connections; @@ -111,332 +131,387 @@ my $timeout = SELECT_TIMEOUT; my %actions; while( 1 ) { - $rin = $base_rin; - # Add the file descriptors of any spawned connections - foreach my $fileno ( keys(%spawned_connections) ) - { - vec( $rin, $fileno, 1 ) = 1; - } + $rin = $base_rin; + # Add the file descriptors of any spawned connections + foreach my $fileno ( keys(%spawned_connections) ) + { + vec( $rin, $fileno, 1 ) = 1; + } - my $nfound = select( my $rout = $rin, undef, my $eout = $ein, $timeout ); - if ( $nfound > 0 ) - { - Debug( "Got input from $nfound connections\n" ); - foreach my $connection ( @in_select_connections ) - { - if ( vec( $rout, $connection->fileno(), 1 ) ) - { - Debug( "Got input from connection ".$connection->name()." (".$connection->fileno().")\n" ); - if ( $connection->spawns() ) - { - my $new_connection = $connection->accept(); - $spawned_connections{$new_connection->fileno()} = $new_connection; - Debug( "Added new spawned connection (".$new_connection->fileno()."), ".int(keys(%spawned_connections))." spawned connections\n" ); - } - else - { - my $messages = $connection->getMessages(); - if ( defined($messages) ) - { - foreach my $message ( @$messages ) - { - handleMessage( $connection, $message ); - } - } - } - } - } - foreach my $connection ( values(%spawned_connections) ) - { - if ( vec( $rout, $connection->fileno(), 1 ) ) - { - Debug( "Got input from spawned connection ".$connection->name()." (".$connection->fileno().")\n" ); - my $messages = $connection->getMessages(); - if ( defined($messages) ) - { - foreach my $message ( @$messages ) - { - handleMessage( $connection, $message ); - } - } - else - { - delete( $spawned_connections{$connection->fileno()} ); - Debug( "Removed spawned connection (".$connection->fileno()."), ".int(keys(%spawned_connections))." spawned connections\n" ); - $connection->close(); - } - } - } - } - elsif ( $nfound < 0 ) - { - if ( $! == EINTR ) - { - # Do nothing - } - else - { - Fatal( "Can't select: $!" ); - } - } + my $nfound = select( my $rout = $rin, undef, my $eout = $ein, $timeout ); + if ( $nfound > 0 ) + { + Debug( "Got input from $nfound connections\n" ); + foreach my $connection ( @in_select_connections ) + { + if ( vec( $rout, $connection->fileno(), 1 ) ) + { + Debug( "Got input from connection " + .$connection->name() + ." (" + .$connection->fileno() + .")\n" + ); + if ( $connection->spawns() ) + { + my $new_connection = $connection->accept(); + $spawned_connections{$new_connection->fileno()} = $new_connection; + Debug( "Added new spawned connection (" + .$new_connection->fileno() + ."), " + .int(keys(%spawned_connections)) + ." spawned connections\n" + ); + } + else + { + my $messages = $connection->getMessages(); + if ( defined($messages) ) + { + foreach my $message ( @$messages ) + { + handleMessage( $connection, $message ); + } + } + } + } + } + foreach my $connection ( values(%spawned_connections) ) + { + if ( vec( $rout, $connection->fileno(), 1 ) ) + { + Debug( "Got input from spawned connection " + .$connection->name() + ." (" + .$connection->fileno() + .")\n" + ); + my $messages = $connection->getMessages(); + if ( defined($messages) ) + { + foreach my $message ( @$messages ) + { + handleMessage( $connection, $message ); + } + } + else + { + delete( $spawned_connections{$connection->fileno()} ); + Debug( "Removed spawned connection (" + .$connection->fileno() + ."), " + .int(keys(%spawned_connections)) + ." spawned connections\n" + ); + $connection->close(); + } + } + } + } + elsif ( $nfound < 0 ) + { + if ( $! == EINTR ) + { + # Do nothing + } + else + { + Fatal( "Can't select: $!" ); + } + } - # Check polled connections - foreach my $connection ( @in_poll_connections ) - { - my $messages = $connection->getMessages(); - if ( defined($messages) ) - { - foreach my $message ( @$messages ) - { - handleMessage( $connection, $message ); - } - } - } + # Check polled connections + foreach my $connection ( @in_poll_connections ) + { + my $messages = $connection->getMessages(); + if ( defined($messages) ) + { + foreach my $message ( @$messages ) + { + handleMessage( $connection, $message ); + } + } + } - # Check for alarms that might have happened - my @out_messages; - foreach my $monitor ( values(%monitors) ) - { - my ( $state, $last_event ) = zmMemRead( $monitor, [ "shared_data:state", "shared_data:last_event" ] ); + # Check for alarms that might have happened + my @out_messages; + foreach my $monitor ( values(%monitors) ) + { + my ( $state, $last_event ) + = zmMemRead( $monitor, + [ "shared_data:state", + "shared_data:last_event" + ] + ); - #print( "$monitor->{Id}: S:$state, LE:$last_event\n" ); - #print( "$monitor->{Id}: mS:$monitor->{LastState}, mLE:$monitor->{LastEvent}\n" ); - if ( $state == STATE_ALARM || $state == STATE_ALERT ) # In alarm state - { - if ( !defined($monitor->{LastEvent}) || ($last_event != $monitor->{LastEvent}) ) # A new event - { - push( @out_messages, $monitor->{Id}."|on|".time()."|".$last_event ); - } - else # The same one as last time, so ignore it - { - # Do nothing - } - } - elsif ( ($state == STATE_IDLE && $monitor->{LastState} != STATE_IDLE) || ($state == STATE_TAPE && $monitor->{LastState} != STATE_TAPE) ) # Out of alarm state - { - push( @out_messages, $monitor->{Id}."|off|".time()."|".$last_event ); - } - elsif ( defined($monitor->{LastEvent}) && ($last_event != $monitor->{LastEvent}) ) # We've missed a whole event - { - push( @out_messages, $monitor->{Id}."|on|".time()."|".$last_event ); - push( @out_messages, $monitor->{Id}."|off|".time()."|".$last_event ); - } - $monitor->{LastState} = $state; - $monitor->{LastEvent} = $last_event; - } - foreach my $connection ( @out_connections ) - { - if ( $connection->canWrite() ) - { - $connection->putMessages( \@out_messages ); - } - } - foreach my $connection ( values(%spawned_connections) ) - { - if ( $connection->canWrite() ) - { - $connection->putMessages( \@out_messages ); - } - } + #print( "$monitor->{Id}: S:$state, LE:$last_event\n" ); + #print( "$monitor->{Id}: mS:$monitor->{LastState}, mLE:$monitor->{LastEvent}\n" ); + if ( $state == STATE_ALARM + || $state == STATE_ALERT + ) # In alarm state + { + if ( !defined($monitor->{LastEvent}) + || ($last_event != $monitor->{LastEvent}) + ) # A new event + { + push( @out_messages, $monitor->{Id}."|on|".time()."|".$last_event ); + } + else # The same one as last time, so ignore it + { + # Do nothing + } + } + elsif ( ($state == STATE_IDLE + && $monitor->{LastState} != STATE_IDLE + ) + || ($state == STATE_TAPE + && $monitor->{LastState} != STATE_TAPE + ) + ) # Out of alarm state + { + push( @out_messages, $monitor->{Id}."|off|".time()."|".$last_event ); + } + elsif ( defined($monitor->{LastEvent}) + && ($last_event != $monitor->{LastEvent}) + ) # We've missed a whole event + { + push( @out_messages, $monitor->{Id}."|on|".time()."|".$last_event ); + push( @out_messages, $monitor->{Id}."|off|".time()."|".$last_event ); + } + $monitor->{LastState} = $state; + $monitor->{LastEvent} = $last_event; + } + foreach my $connection ( @out_connections ) + { + if ( $connection->canWrite() ) + { + $connection->putMessages( \@out_messages ); + } + } + foreach my $connection ( values(%spawned_connections) ) + { + if ( $connection->canWrite() ) + { + $connection->putMessages( \@out_messages ); + } + } - Debug( "Checking for timed actions\n" ) if ( int(keys(%actions)) ); - my $now = time(); - foreach my $action_time ( sort( grep { $_ < $now } keys( %actions ) ) ) - { - Info( "Found actions expiring at $action_time\n" ); - foreach my $action ( @{$actions{$action_time}} ) - { - my $connection = $action->{connection}; - my $message = $action->{message}; - Info( "Found action '$message'\n" ); - handleMessage( $connection, $message ); - } - delete( $actions{$action_time} ); - } + Debug( "Checking for timed actions\n" ) + if ( int(keys(%actions)) ); + my $now = time(); + foreach my $action_time ( sort( grep { $_ < $now } keys( %actions ) ) ) + { + Info( "Found actions expiring at $action_time\n" ); + foreach my $action ( @{$actions{$action_time}} ) + { + my $connection = $action->{connection}; + my $message = $action->{message}; + Info( "Found action '$message'\n" ); + handleMessage( $connection, $message ); + } + delete( $actions{$action_time} ); + } # Allow connections to do their own timed actions - foreach my $connection ( @connections ) - { - my $messages = $connection->timedActions(); - if ( defined($messages) ) - { - foreach my $message ( @$messages ) - { - handleMessage( $connection, $message ); - } - } - } - foreach my $connection ( values(%spawned_connections) ) - { - my $messages = $connection->timedActions(); - if ( defined($messages) ) - { - foreach my $message ( @$messages ) - { - handleMessage( $connection, $message ); - } - } - } + foreach my $connection ( @connections ) + { + my $messages = $connection->timedActions(); + if ( defined($messages) ) + { + foreach my $message ( @$messages ) + { + handleMessage( $connection, $message ); + } + } + } + foreach my $connection ( values(%spawned_connections) ) + { + my $messages = $connection->timedActions(); + if ( defined($messages) ) + { + foreach my $message ( @$messages ) + { + handleMessage( $connection, $message ); + } + } + } - # If necessary reload monitors - if ( (time() - $monitor_reload_time) > MONITOR_RELOAD_INTERVAL ) - { - foreach my $monitor ( values(%monitors) ) + # If necessary reload monitors + if ( (time() - $monitor_reload_time) > MONITOR_RELOAD_INTERVAL ) + { + foreach my $monitor ( values(%monitors) ) { # Free up any used memory handle zmMemInvalidate( $monitor ); } - loadMonitors(); - } + loadMonitors(); + } } Info( "Trigger daemon exiting\n" ); exit; sub loadMonitors { - Debug( "Loading monitors\n" ); - $monitor_reload_time = time(); + Debug( "Loading monitors\n" ); + $monitor_reload_time = time(); - my %new_monitors = (); + my %new_monitors = (); - my $sql = "select * from Monitors where find_in_set( Function, 'Modect,Mocord,Nodect' )"; - my $sth = $dbh->prepare_cached( $sql ) or Fatal( "Can't prepare '$sql': ".$dbh->errstr() ); - my $res = $sth->execute() or Fatal( "Can't execute: ".$sth->errstr() ); - while( my $monitor = $sth->fetchrow_hashref() ) - { - next if ( !zmMemVerify( $monitor ) ); # Check shared memory ok + my $sql = "SELECT * FROM Monitors + WHERE find_in_set( Function, 'Modect,Mocord,Nodect' )" + ; + my $sth = $dbh->prepare_cached( $sql ) + or Fatal( "Can't prepare '$sql': ".$dbh->errstr() ); + my $res = $sth->execute() + or Fatal( "Can't execute: ".$sth->errstr() ); + while( my $monitor = $sth->fetchrow_hashref() ) + { + next if ( !zmMemVerify( $monitor ) ); # Check shared memory ok - if ( defined($monitors{$monitor->{Id}}->{LastState}) ) - { - $monitor->{LastState} = $monitors{$monitor->{Id}}->{LastState}; - } - else - { - $monitor->{LastState} = zmGetMonitorState( $monitor ); - } - if ( defined($monitors{$monitor->{Id}}->{LastEvent}) ) - { - $monitor->{LastEvent} = $monitors{$monitor->{Id}}->{LastEvent}; - } - else - { - $monitor->{LastEvent} = zmGetLastEvent( $monitor ); - } - $new_monitors{$monitor->{Id}} = $monitor; - } - %monitors = %new_monitors; + if ( defined($monitors{$monitor->{Id}}->{LastState}) ) + { + $monitor->{LastState} = $monitors{$monitor->{Id}}->{LastState}; + } + else + { + $monitor->{LastState} = zmGetMonitorState( $monitor ); + } + if ( defined($monitors{$monitor->{Id}}->{LastEvent}) ) + { + $monitor->{LastEvent} = $monitors{$monitor->{Id}}->{LastEvent}; + } + else + { + $monitor->{LastEvent} = zmGetLastEvent( $monitor ); + } + $new_monitors{$monitor->{Id}} = $monitor; + } + %monitors = %new_monitors; } sub handleMessage { - my $connection = shift; - my $message = shift; + my $connection = shift; + my $message = shift; - my ( $id, $action, $score, $cause, $text, $showtext ) = split( /\|/, $message ); - $score = 0 if ( !defined($score) ); - $cause = "" if ( !defined($cause) ); - $text = "" if ( !defined($text) ); + my ( $id, $action, $score, $cause, $text, $showtext ) + = split( /\|/, $message ); + $score = 0 if ( !defined($score) ); + $cause = "" if ( !defined($cause) ); + $text = "" if ( !defined($text) ); - my $monitor = $monitors{$id}; - if ( !$monitor ) - { - Warning( "Can't find monitor '$id' for message '$message'\n" ); - return; - } - Debug( "Found monitor for id '$id'\n" ); + my $monitor = $monitors{$id}; + if ( !$monitor ) + { + Warning( "Can't find monitor '$id' for message '$message'\n" ); + return; + } + Debug( "Found monitor for id '$id'\n" ); - next if ( !zmMemVerify( $monitor ) ); + next if ( !zmMemVerify( $monitor ) ); - Debug( "Handling action '$action'\n" ); - if ( $action =~ /^(enable|disable)(?:\+(\d+))?$/ ) - { - my $state = $1; - my $delay = $2; - if ( $state eq "enable" ) - { - zmMonitorEnable( $monitor ); - } - else - { - zmMonitorDisable( $monitor ); - } - # Force a reload - $monitor_reload_time = 0; - Info( "Set monitor to $state\n" ); - if ( $delay ) - { - my $action_time = time()+$delay; - my $action_text = $id."|".(($state eq "enable")?"disable":"enable"); - my $action_array = $actions{$action_time}; - if ( !$action_array ) - { - $action_array = $actions{$action_time} = []; - } - push( @$action_array, { connection=>$connection, message=>$action_text } ); - Debug( "Added timed event '$action_text', expires at $action_time (+$delay secs)\n" ); - } - } - elsif ( $action =~ /^(on|off)(?:\+(\d+))?$/ ) - { - next if ( !$monitor->{Enabled} ); + Debug( "Handling action '$action'\n" ); + if ( $action =~ /^(enable|disable)(?:\+(\d+))?$/ ) + { + my $state = $1; + my $delay = $2; + if ( $state eq "enable" ) + { + zmMonitorEnable( $monitor ); + } + else + { + zmMonitorDisable( $monitor ); + } + # Force a reload + $monitor_reload_time = 0; + Info( "Set monitor to $state\n" ); + if ( $delay ) + { + my $action_time = time()+$delay; + my $action_text = $id."|".( ($state eq "enable") + ? "disable" + : "enable" + ) + ; + my $action_array = $actions{$action_time}; + if ( !$action_array ) + { + $action_array = $actions{$action_time} = []; + } + push( @$action_array, { connection=>$connection, + message=>$action_text + } + ); + Debug( "Added timed event '$action_text', expires at $action_time (+$delay secs)\n" ); + } + } + elsif ( $action =~ /^(on|off)(?:\+(\d+))?$/ ) + { + next if ( !$monitor->{Enabled} ); - my $trigger = $1; - my $delay = $2; - my $trigger_data; - if ( $trigger eq "on" ) - { - zmTriggerEventOn( $monitor, $score, $cause, $text ); - zmTriggerShowtext( $monitor, $showtext ) if defined($showtext); - Info( "Trigger '$trigger' '$cause'\n" ); - } - elsif ( $trigger eq "off" ) - { + my $trigger = $1; + my $delay = $2; + my $trigger_data; + if ( $trigger eq "on" ) + { + zmTriggerEventOn( $monitor, $score, $cause, $text ); + zmTriggerShowtext( $monitor, $showtext ) if defined($showtext); + Info( "Trigger '$trigger' '$cause'\n" ); + } + elsif ( $trigger eq "off" ) + { my $last_event = zmGetLastEvent( $monitor ); - zmTriggerEventOff( $monitor ); - zmTriggerShowtext( $monitor, $showtext ) if defined($showtext); - Info( "Trigger '$trigger'\n" ); + zmTriggerEventOff( $monitor ); + zmTriggerShowtext( $monitor, $showtext ) if defined($showtext); + Info( "Trigger '$trigger'\n" ); # Wait til it's finished - while( zmInAlarm( $monitor ) && ($last_event == zmGetLastEvent( $monitor )) ) + while( zmInAlarm( $monitor ) + && ($last_event == zmGetLastEvent( $monitor )) + ) { # Tenth of a second usleep( 100000 ); } - zmTriggerEventCancel( $monitor ); - } - else - { - Info( "Trigger '$trigger'\n" ); - zmTriggerEventCancel( $monitor ); - } - if ( $delay ) - { - my $action_time = time()+$delay; - #my $action_text = $id."|cancel|0|".$cause."|".$text; - my $action_text = $id."|cancel"; - my $action_array = $actions{$action_time}; - if ( !$action_array ) - { - $action_array = $actions{$action_time} = []; - } - push( @$action_array, { connection=>$connection, message=>$action_text } ); - Debug( "Added timed event '$action_text', expires at $action_time (+$delay secs)\n" ); - } - } - elsif( $action eq "cancel" ) - { - zmTriggerEventCancel( $monitor ); - zmTriggerShowtext( $monitor, $showtext ) if defined($showtext); - Info( "Cancelled event\n" ); - } - elsif( $action eq "show" ) - { - zmTriggerShowtext( $monitor, $showtext ); - Info( "Updated show text to '$showtext'\n" ); - } - else - { - Error( "Unrecognised action '$action' in message '$message'\n" ); - } + zmTriggerEventCancel( $monitor ); + } + else + { + Info( "Trigger '$trigger'\n" ); + zmTriggerEventCancel( $monitor ); + } + if ( $delay ) + { + my $action_time = time()+$delay; + #my $action_text = $id."|cancel|0|".$cause."|".$text; + my $action_text = $id."|cancel"; + my $action_array = $actions{$action_time}; + if ( !$action_array ) + { + $action_array = $actions{$action_time} = []; + } + push( @$action_array, { connection=>$connection, + message=>$action_text + } + ); + Debug( "Added timed event '$action_text', expires at $action_time (+$delay secs)\n" ); + } + } + elsif( $action eq "cancel" ) + { + zmTriggerEventCancel( $monitor ); + zmTriggerShowtext( $monitor, $showtext ) if defined($showtext); + Info( "Cancelled event\n" ); + } + elsif( $action eq "show" ) + { + zmTriggerShowtext( $monitor, $showtext ); + Info( "Updated show text to '$showtext'\n" ); + } + else + { + Error( "Unrecognised action '$action' in message '$message'\n" ); + } } # end sub handleMessage 1; diff --git a/scripts/zmupdate.pl.in b/scripts/zmupdate.pl.in index 41a081fc1..75ac52fa0 100644 --- a/scripts/zmupdate.pl.in +++ b/scripts/zmupdate.pl.in @@ -20,11 +20,34 @@ # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # # ========================================================================== -# -# This script just checks what the most recent release of ZoneMinder is -# at the the moment. It will eventually be responsible for applying and -# configuring upgrades etc, including on the fly upgrades. -# + +=head1 NAME + +zmupdate.pl - check and upgrade Zoneminer database + +=head1 SYNOPSIS + + zmupdate.pl -c,--check | -f,--freshen | -v,--version= [-u -p] + +=head1 DESCRIPTION + +This script just checks what the most recent release of ZoneMinder is +at the the moment. It will eventually be responsible for applying and +configuring upgrades etc, including on the fly upgrades. + +=head1 OPTIONS + + -c, --check - Check for updated versions of ZoneMinder + -f, --freshen - Freshen the configuration in the database. Equivalent of old zmconfig.pl -noi + --migrate-events - Update database structures as per USE_DEEP_STORAGE setting. + -v, --version= - Force upgrade to the current version from + -u, --user= - Alternate DB user with privileges to alter DB + -p, --pass= - Password of alternate DB user with privileges to alter DB + -d,--dir= - Directory containing update files if not in default build location + -interactive - interact with the user + -nointeractive - do not interact with the user + +=cut use strict; use bytes; @@ -52,7 +75,8 @@ use ZoneMinder::ConfigAdmin qw( :functions ); use POSIX; use DBI; use Getopt::Long; -use Data::Dumper; +use autouse 'Pod::Usage'=>qw(pod2usage); +use autouse 'Data::Dumper'=>qw(Dumper); use constant EVENT_PATH => ($Config{ZM_DIR_EVENTS}=~m|/|)?$Config{ZM_DIR_EVENTS}:($Config{ZM_PATH_WEB}.'/'.$Config{ZM_DIR_EVENTS}); @@ -78,27 +102,19 @@ my $version = ''; my $dbUser = $Config{ZM_DB_USER}; my $dbPass = $Config{ZM_DB_PASS}; my $updateDir = ''; -sub Usage -{ - print( " -Usage: zmupdate.pl <-c,--check|-f,--freshen|-v,--version=> [-u -p]> -Parameters are :- --c, --check - Check for updated versions of ZoneMinder --f, --freshen - Freshen the configuration in the database. Equivalent of old zmconfig.pl -noi --v, --version= - Force upgrade to the current version from --u, --user= - Alternate DB user with privileges to alter DB --p, --pass= - Password of alternate DB user with privileges to alter DB --d,--dir= - Directory containing update files if not in default build location --interactive - interact with the user --nointeractive - do not interact with the user -"); - exit( -1 ); -} -if ( !GetOptions( 'check'=>\$check, 'freshen'=>\$freshen, 'rename'=>\$rename, 'zone-fix'=>\$zoneFix, 'migrate-events'=>\$migrateEvents, 'version=s'=>\$version, 'interactive!'=>\$interactive, 'user:s'=>\$dbUser, 'pass:s'=>\$dbPass, 'dir:s'=>\$updateDir ) ) -{ - Usage(); -} +GetOptions( + 'check' =>\$check, + 'freshen' =>\$freshen, + 'rename' =>\$rename, + 'zone-fix' =>\$zoneFix, + 'migrate-events' =>\$migrateEvents, + 'version=s' =>\$version, + 'interactive!' =>\$interactive, + 'user:s' =>\$dbUser, + 'pass:s' =>\$dbPass, + 'dir:s' =>\$updateDir +) or pod2usage(-exitstatus => -1); my $dbh = zmDbConnect(); $Config{ZM_DB_USER} = $dbUser; @@ -113,14 +129,14 @@ if ( ! ($check || $freshen || $rename || $zoneFix || $migrateEvents || $version) else { print( STDERR "Please give a valid option\n" ); - Usage(); + pod2usage(-exitstatus => -1); } } if ( ($check + $freshen + $rename + $zoneFix + $migrateEvents + ($version?1:0)) > 1 ) { print( STDERR "Please give only one option\n" ); - Usage(); + pod2usage(-exitstatus => -1); } if ( $check && $Config{ZM_CHECK_FOR_UPDATES} ) diff --git a/scripts/zmvideo.pl.in b/scripts/zmvideo.pl.in index 916b1c0ab..725477c15 100644 --- a/scripts/zmvideo.pl.in +++ b/scripts/zmvideo.pl.in @@ -20,10 +20,37 @@ # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # # ========================================================================== -# -# This script is used to create MPEG videos of events for the web pages -# or as email attachments. -# + +=head1 NAME + +zmvideo.pl - ZoneMinder Video Creation Script + +=head1 SYNOPSIS + + zmvideo.pl -e ,--event= [--format ] + [--rate=] + [--scale=] + [--fps=] + [--size=] + [--overwrite] + +=head1 DESCRIPTION + +This script is used to create MPEG videos of events for the web pages +or as email attachments. + +=head1 OPTIONS + + -e, --event= - What event to create the video for + -f, --format= - What format to create the video in, default is mpg. For ffmpeg only. + -r, --rate= - Relative rate, 1 = realtime, 2 = double speed, 0.5 = half speed etc. + -s, --scale= - Scale, 1 = normal, 2 = double size, 0.5 = half size etc. + -F, --fps= - Absolute frame rate, in frames per second + -S, --size= - Absolute video size, WxH or other specification supported by ffmpeg + -o, --overwrite - Whether to overwrite an existing file, off by default. + -v, --version - Outputs the currently installed version of ZoneMinder + +=cut use strict; use bytes; @@ -36,9 +63,10 @@ use bytes; @EXTRA_PERL_LIB@ use ZoneMinder; use DBI; -use Data::Dumper; +use autouse 'Data::Dumper'=>qw(Dumper); use POSIX qw(strftime); use Getopt::Long qw(:config no_ignore_case ); +use autouse 'Pod::Usage'=>qw(pod2usage); $| = 1; @@ -60,77 +88,66 @@ my $version = 0; my @formats = split( /\s+/, $Config{ZM_FFMPEG_FORMATS} ); for ( my $i = 0; $i < @formats; $i++ ) { - if ( $i =~ /^(.+)\*$/ ) - { - $format = $formats[$i] = $1; - } + if ( $i =~ /^(.+)\*$/ ) + { + $format = $formats[$i] = $1; + } } -sub Usage -{ - print( " -Usage: zmvideo.pl -e ,--event= [--format ] [--rate=] [--scale=] [--fps=] [--size=] [--overwrite] -Parameters are :- --e, --event= - What event to create the video for --f, --format= - What format to create the video in, default is mpg. For ffmpeg only. --r, --rate= - Relative rate , 1 = realtime, 2 = double speed , 0.5 = half speed etc --s, --scale= - Scale, 1 = normal, 2 = double size, 0.5 = half size etc --F, --fps= - Absolute frame rate, in frames per second --S, --size= - Absolute video size, WxH or other specification supported by ffmpeg --o, --overwrite - Whether to overwrite an existing file, off by default. --v, --version - Outputs the currently installed version of ZoneMinder -"); - exit( -1 ); -} - -if ( !GetOptions( 'event=i'=>\$event_id, 'format|f=s'=>\$format, 'rate|r=f'=>\$rate, 'scale|s=f'=>\$scale, 'fps|F=f'=>\$fps, 'size|S=s'=>\$size, 'overwrite'=>\$overwrite, version=>\$version ) ) -{ - Usage(); -} +GetOptions( + 'event=i' =>\$event_id, + 'format|f=s' =>\$format, + 'rate|r=f' =>\$rate, + 'scale|s=f' =>\$scale, + 'fps|F=f' =>\$fps, + 'size|S=s' =>\$size, + 'overwrite' =>\$overwrite, + 'version' =>\$version +) or pod2usage(-exitstatus => -1); if ( $version ) { - print ZoneMinder::Base::ZM_VERSION . "\n"; - exit(0); + print ZoneMinder::Base::ZM_VERSION . "\n"; + exit(0); } if ( !$event_id || $event_id < 0 ) { - print( STDERR "Please give a valid event id\n" ); - Usage(); + print( STDERR "Please give a valid event id\n" ); + pod2usage(-exitstatus => -1); } if ( ! $Config{ZM_OPT_FFMPEG} ) { - print( STDERR "Mpeg encoding is not currently enabled\n" ); - exit(-1); + print( STDERR "Mpeg encoding is not currently enabled\n" ); + exit(-1); } if ( !$rate && !$fps ) { - $rate = 1; + $rate = 1; } if ( !$scale && !$size ) { - $scale = 1; + $scale = 1; } if ( $rate && ($rate < 0.25 || $rate > 100) ) { - print( STDERR "Rate is out of range, 0.25 >= rate <= 100\n" ); - Usage(); + print( STDERR "Rate is out of range, 0.25 >= rate <= 100\n" ); + pod2usage(-exitstatus => -1); } if ( $scale && ($scale < 0.25 || $scale > 4) ) { - print( STDERR "Scale is out of range, 0.25 >= scale <= 4\n" ); - Usage(); + print( STDERR "Scale is out of range, 0.25 >= scale <= 4\n" ); + pod2usage(-exitstatus => -1); } if ( $fps && ($fps > 30) ) { - print( STDERR "FPS is out of range, <= 30\n" ); - Usage(); + print( STDERR "FPS is out of range, <= 30\n" ); + pod2usage(-exitstatus => -1); } my ( $detaint_format ) = $format =~ /^(\w+)$/; @@ -148,9 +165,23 @@ $size = $detaint_size; my $dbh = zmDbConnect(); my @filters; -my $sql = "select max(F.Delta)-min(F.Delta) as FullLength, E.*, unix_timestamp(E.StartTime) as Time, M.Name as MonitorName, M.Width as MonitorWidth, M.Height as MonitorHeight, M.Palette from Frames as F inner join Events as E on F.EventId = E.Id inner join Monitors as M on E.MonitorId = M.Id where EventId = '$event_id' group by F.EventId"; -my $sth = $dbh->prepare_cached( $sql ) or Fatal( "Can't prepare '$sql': ".$dbh->errstr() ); -my $res = $sth->execute() or Fatal( "Can't execute: ".$sth->errstr() ); +my $sql = " SELECT max(F.Delta)-min(F.Delta) as FullLength, + E.*, + unix_timestamp(E.StartTime) as Time, + M.Name as MonitorName, + M.Width as MonitorWidth, + M.Height as MonitorHeight, + M.Palette + FROM Frames as F + INNER JOIN Events as E on F.EventId = E.Id + INNER JOIN Monitors as M on E.MonitorId = M.Id + WHERE EventId = '$event_id' + GROUP BY F.EventId" +; +my $sth = $dbh->prepare_cached( $sql ) + or Fatal( "Can't prepare '$sql': ".$dbh->errstr() ); +my $res = $sth->execute() + or Fatal( "Can't execute: ".$sth->errstr() ); my $event = $sth->fetchrow_hashref(); $sth->finish(); my $event_path = getEventPath( $event ); @@ -160,42 +191,42 @@ chdir( $event_path ); my @file_parts; if ( $rate ) { - my $file_rate = $rate; - $file_rate =~ s/\./_/; - $file_rate =~ s/_00//; - $file_rate =~ s/(_\d+)0+$/$1/; - $file_rate = 'r'.$file_rate; - push( @file_parts, $file_rate ); + my $file_rate = $rate; + $file_rate =~ s/\./_/; + $file_rate =~ s/_00//; + $file_rate =~ s/(_\d+)0+$/$1/; + $file_rate = 'r'.$file_rate; + push( @file_parts, $file_rate ); } elsif ( $fps ) { - my $file_fps = $fps; - $file_fps =~ s/\./_/; - $file_fps =~ s/_00//; - $file_fps =~ s/(_\d+)0+$/$1/; - $file_fps = 'R'.$file_fps; - push( @file_parts, $file_fps ); + my $file_fps = $fps; + $file_fps =~ s/\./_/; + $file_fps =~ s/_00//; + $file_fps =~ s/(_\d+)0+$/$1/; + $file_fps = 'R'.$file_fps; + push( @file_parts, $file_fps ); } if ( $scale ) { - my $file_scale = $scale; - $file_scale =~ s/\./_/; - $file_scale =~ s/_00//; - $file_scale =~ s/(_\d+)0+$/$1/; - $file_scale = 's'.$file_scale; - push( @file_parts, $file_scale ); + my $file_scale = $scale; + $file_scale =~ s/\./_/; + $file_scale =~ s/_00//; + $file_scale =~ s/(_\d+)0+$/$1/; + $file_scale = 's'.$file_scale; + push( @file_parts, $file_scale ); } elsif ( $size ) { - my $file_size = 'S'.$size; - push( @file_parts, $file_size ); + my $file_size = 'S'.$size; + push( @file_parts, $file_size ); } my $video_file = "$video_name-".$file_parts[0]."-".$file_parts[1].".$format"; if ( $overwrite || !-s $video_file ) { - Info( "Creating video file $video_file for event $event->{Id}\n" ); + Info( "Creating video file $video_file for event $event->{Id}\n" ); my $frame_rate = sprintf( "%.2f", $event->{Frames}/$event->{FullLength} ); if ( $rate ) @@ -228,22 +259,32 @@ if ( $overwrite || !-s $video_file ) $video_size = $size; } - my $command = $Config{ZM_PATH_FFMPEG}." -y -r $frame_rate ".$Config{ZM_FFMPEG_INPUT_OPTIONS}." -i %0".$Config{ZM_EVENT_IMAGE_DIGITS}."d-capture.jpg -s $video_size ".$Config{ZM_FFMPEG_OUTPUT_OPTIONS}." '$video_file' > ffmpeg.log 2>&1"; + my $command = $Config{ZM_PATH_FFMPEG} + ." -y -r $frame_rate " + .$Config{ZM_FFMPEG_INPUT_OPTIONS} + ." -i %0" + .$Config{ZM_EVENT_IMAGE_DIGITS} + ."d-capture.jpg -s $video_size " + .$Config{ZM_FFMPEG_OUTPUT_OPTIONS} + ." '$video_file' > ffmpeg.log 2>&1" + ; Debug( $command."\n" ); my $output = qx($command); my $status = $? >> 8; if ( $status ) { - Error( "Unable to generate video, check ".$event_path."/ffmpeg.log for details" ); + Error( "Unable to generate video, check " + .$event_path."/ffmpeg.log for details" + ); exit( -1 ); } - - Info( "Finished $video_file\n" ); + + Info( "Finished $video_file\n" ); } else { - Info( "Video file $video_file already exists for event $event->{Id}\n" ); + Info( "Video file $video_file already exists for event $event->{Id}\n" ); } #print( STDOUT $event->{MonitorId}.'/'.$event->{Id}.'/'.$video_file."\n" ); print( STDOUT $event_path . '/' . $video_file ."\n" ); diff --git a/scripts/zmwatch.pl.in b/scripts/zmwatch.pl.in index bfa8b54bd..7d5193439 100644 --- a/scripts/zmwatch.pl.in +++ b/scripts/zmwatch.pl.in @@ -20,11 +20,22 @@ # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # # ========================================================================== -# -# This does some basic setup for ZoneMinder to run and then periodically -# checks the fps output of the active daemons to check they haven't -# locked up. If they have then they are killed and restarted -# + +=head1 NAME + +zmwatch.pl - ZoneMinder WatchDog Script + +=head1 SYNOPSIS + +zmwatch.pl + +=head1 DESCRIPTION + +This does some basic setup for ZoneMinder to run and then periodically +checks the fps output of the active daemons to check they haven't +locked up. If they have then they are killed and restarted + +=cut use strict; use bytes; @@ -46,7 +57,7 @@ use constant START_DELAY => 30; # To give everything else time to start use ZoneMinder; use POSIX; use DBI; -use Data::Dumper; +use autouse 'Data::Dumper'=>qw(Dumper); $| = 1; @@ -54,14 +65,6 @@ $ENV{PATH} = '/bin:/usr/bin'; $ENV{SHELL} = '/bin/sh' if exists $ENV{SHELL}; delete @ENV{qw(IFS CDPATH ENV BASH_ENV)}; -sub Usage -{ - print( " -Usage: zmwatch.pl -"); - exit( -1 ); -} - logInit(); logSetSignal(); @@ -72,38 +75,49 @@ sleep( START_DELAY ); my $dbh = zmDbConnect(); my $sql = "select * from Monitors"; -my $sth = $dbh->prepare_cached( $sql ) or Fatal( "Can't prepare '$sql': ".$dbh->errstr() ); +my $sth = $dbh->prepare_cached( $sql ) + or Fatal( "Can't prepare '$sql': ".$dbh->errstr() ); while( 1 ) { - my $now = time(); - my $res = $sth->execute() or Fatal( "Can't execute: ".$sth->errstr() ); - while( my $monitor = $sth->fetchrow_hashref() ) - { - if ( $monitor->{Function} ne 'None' ) - { + my $now = time(); + my $res = $sth->execute() + or Fatal( "Can't execute: ".$sth->errstr() ); + while( my $monitor = $sth->fetchrow_hashref() ) + { + if ( $monitor->{Function} ne 'None' ) + { my $restart = 0; - if ( zmMemVerify( $monitor ) && zmMemRead( $monitor, "shared_data:valid" ) ) - { - # Check we have got an image recently - my $image_time = zmGetLastWriteTime( $monitor ); - next if ( !defined($image_time) ); # Can't read from shared data - next if ( !$image_time ); # We can't get the last capture time so can't be sure it's died. + if ( zmMemVerify( $monitor ) + && zmMemRead( $monitor, "shared_data:valid" ) + ) + { + # Check we have got an image recently + my $image_time = zmGetLastWriteTime( $monitor ); + next if ( !defined($image_time) ); # Can't read from shared data + next if ( !$image_time ); # We can't get the last capture time so can't be sure it's died. - my $max_image_delay = ($monitor->{MaxFPS}&&($monitor->{MaxFPS}>0)&&($monitor->{MaxFPS}<1))?(3/$monitor->{MaxFPS}):$Config{ZM_WATCH_MAX_DELAY}; - my $image_delay = $now-$image_time; - Debug( "Monitor $monitor->{Id} last captured $image_delay seconds ago, max is $max_image_delay\n" ); - if ( $image_delay > $max_image_delay ) - { - Info( "Restarting capture daemon for ".$monitor->{Name}.", time since last capture $image_delay seconds ($now-$image_time)\n" ); + my $max_image_delay = ( $monitor->{MaxFPS} + &&($monitor->{MaxFPS}>0) + &&($monitor->{MaxFPS}<1) + ) ? (3/$monitor->{MaxFPS}) + : $Config{ZM_WATCH_MAX_DELAY} + ; + my $image_delay = $now-$image_time; + Debug( "Monitor $monitor->{Id} last captured $image_delay seconds ago, max is $max_image_delay\n" ); + if ( $image_delay > $max_image_delay ) + { + Info( "Restarting capture daemon for " + .$monitor->{Name}.", time since last capture $image_delay seconds ($now-$image_time)\n" + ); $restart = 1; } - } - else - { - #Info( "Restarting capture daemon for ".$monitor->{Name}.", shared data not valid\n" ); + } + else + { + #Info( "Restarting capture daemon for ".$monitor->{Name}.", shared data not valid\n" ); #$restart = 1; - } + } if ( $restart ) { @@ -120,19 +134,28 @@ while( 1 ) } elsif ( $monitor->{Function} ne 'Monitor' ) { - if ( zmMemVerify( $monitor ) && zmMemRead( $monitor, "shared_data:valid" ) ) + if ( zmMemVerify( $monitor ) + && zmMemRead( $monitor, "shared_data:valid" ) + ) { # Check we have got an image recently my $image_time = zmGetLastReadTime( $monitor ); next if ( !defined($image_time) ); # Can't read from shared data next if ( !$image_time ); # We can't get the last capture time so can't be sure it's died. - my $max_image_delay = ($monitor->{MaxFPS}&&($monitor->{MaxFPS}>0)&&($monitor->{MaxFPS}<1))?(3/$monitor->{MaxFPS}):$Config{ZM_WATCH_MAX_DELAY}; + my $max_image_delay = ( $monitor->{MaxFPS} + &&($monitor->{MaxFPS}>0) + &&($monitor->{MaxFPS}<1) + ) ? (3/$monitor->{MaxFPS}) + : $Config{ZM_WATCH_MAX_DELAY} + ; my $image_delay = $now-$image_time; Debug( "Monitor $monitor->{Id} last analysed $image_delay seconds ago, max is $max_image_delay\n" ); if ( $image_delay > $max_image_delay ) { - Info( "Restarting analysis daemon for ".$monitor->{Name}.", time since last analysis $image_delay seconds ($now-$image_time)\n" ); + Info( "Restarting analysis daemon for " + .$monitor->{Name}.", time since last analysis $image_delay seconds ($now-$image_time)\n" + ); my $command = "zmdc.pl restart zma -m ".$monitor->{Id}; runCommand( $command ); } @@ -141,8 +164,8 @@ while( 1 ) } # Prevent open handles building up if we have connect to shared memory zmMemInvalidate( $monitor ); - } - sleep( $Config{ZM_WATCH_CHECK_INTERVAL} ); + } + sleep( $Config{ZM_WATCH_CHECK_INTERVAL} ); } Info( "Watchdog exiting\n" ); exit(); diff --git a/scripts/zmx10.pl.in b/scripts/zmx10.pl.in index add59034d..d25e74c8a 100644 --- a/scripts/zmx10.pl.in +++ b/scripts/zmx10.pl.in @@ -20,10 +20,28 @@ # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # # ========================================================================== -# -# This script controls the monitoring of the X10 interface and the consequent -# management of the ZM daemons based on the receipt of X10 signals. -# + +=head1 NAME + +zmx10.pl - ZoneMinder X10 Control Script + +=head1 SYNOPSIS + + zmx10.pl -c ,--command= [-u ,--unit-code=] + +=head1 DESCRIPTION + +This script controls the monitoring of the X10 interface and the consequent +management of the ZM daemons based on the receipt of X10 signals. + +=head1 OPTIONS + + -c , --command= - Command to issue, one of 'on','off','dim','bright','status','shutdown' + -u , --unit-code= - Unit code to act on required for all commands + except 'status' (optional) and 'shutdown' + -v, --verison - Pirnts the currently installed version of ZoneMinder + +=cut use strict; use bytes; @@ -46,7 +64,8 @@ use ZoneMinder; use POSIX; use Socket; use Getopt::Long; -use Data::Dumper; +use autouse 'Pod::Usage'=>qw(pod2usage); +use autouse 'Data::Dumper'=>qw(Dumper); use constant SOCK_FILE => $Config{ZM_PATH_SOCKS}.'/zmx10.sock'; @@ -56,18 +75,6 @@ $ENV{PATH} = '/bin:/usr/bin'; $ENV{SHELL} = '/bin/sh' if exists $ENV{SHELL}; delete @ENV{qw(IFS CDPATH ENV BASH_ENV)}; -sub Usage -{ - print( " -Usage: zmx10.pl -c ,--command= [-u ,--unit-code=] -Parameters are :- --c , --command= - Command to issue, one of 'on','off','dim','bright','status','shutdown' --u , --unit-code= - Unit code to act on required for all commands except 'status' (optional) and 'shutdown' --v, --verison - Pirnts the currently installed version of ZoneMinder -"); - exit( -1 ); -} - logInit(); logSetSignal(); @@ -75,53 +82,59 @@ my $command; my $unit_code; my $version; -if ( !GetOptions( 'command=s'=>\$command, 'unit-code=i'=>\$unit_code, version=>\$version ) ) -{ - Usage(); -} +GetOptions( + 'command=s' =>\$command, + 'unit-code=i' =>\$unit_code, + 'version' =>\$version +) or pod2usage(-exitstatus => -1); + if ( $version ) { - print ZoneMinder::Base::ZM_VERSION; - exit(0); + print ZoneMinder::Base::ZM_VERSION; + exit(0); } die( "No command given" ) unless( $command ); -die( "No unit code given" ) unless( $unit_code || ($command =~ /(?:start|status|shutdown)/) ); +die( "No unit code given" ) + unless( $unit_code || ($command =~ /(?:start|status|shutdown)/) ); if ( $command eq "start" ) { - X10Server::runServer(); - exit(); + X10Server::runServer(); + exit(); } -socket( CLIENT, PF_UNIX, SOCK_STREAM, 0 ) or Fatal( "Can't open socket: $!" ); +socket( CLIENT, PF_UNIX, SOCK_STREAM, 0 ) + or Fatal( "Can't open socket: $!" ); my $saddr = sockaddr_un( SOCK_FILE ); if ( !connect( CLIENT, $saddr ) ) { - # The server isn't there - print( "Unable to connect, starting server\n" ); - close( CLIENT ); + # The server isn't there + print( "Unable to connect, starting server\n" ); + close( CLIENT ); - if ( my $cpid = fork() ) - { - # Parent process just sleep and fall through - sleep( 2 ); + if ( my $cpid = fork() ) + { + # Parent process just sleep and fall through + sleep( 2 ); logReinit(); - socket( CLIENT, PF_UNIX, SOCK_STREAM, 0 ) or Fatal( "Can't open socket: $!" ); - connect( CLIENT, $saddr ) or Fatal( "Can't connect: $!" ); - } - elsif ( defined($cpid) ) - { - setpgrp(); + socket( CLIENT, PF_UNIX, SOCK_STREAM, 0 ) + or Fatal( "Can't open socket: $!" ); + connect( CLIENT, $saddr ) + or Fatal( "Can't connect: $!" ); + } + elsif ( defined($cpid) ) + { + setpgrp(); logReinit(); - X10Server::runServer(); - } - else - { - Fatal( "Can't fork: $!" ); - } + X10Server::runServer(); + } + else + { + Fatal( "Can't fork: $!" ); + } } # The server is there, connect to it #print( "Writing commands\n" ); @@ -132,8 +145,8 @@ print( CLIENT $message ); shutdown( CLIENT, 1 ); while ( my $line = ) { - chomp( $line ); - print( "$line\n" ); + chomp( $line ); + print( "$line\n" ); } close( CLIENT ); #print( "Finished writing, bye\n" ); @@ -156,7 +169,7 @@ use POSIX; use DBI; use Socket; use X10::ActiveHome; -use Data::Dumper; +use autouse 'Data::Dumper'=>qw(Dumper); our $dbh; our $x10; @@ -167,515 +180,599 @@ our %pending_tasks; sub runServer { - Info( "X10 server starting\n" ); + Info( "X10 server starting\n" ); - socket( SERVER, PF_UNIX, SOCK_STREAM, 0 ) or Fatal( "Can't open socket: $!" ); - unlink( main::SOCK_FILE ); - my $saddr = sockaddr_un( main::SOCK_FILE ); - bind( SERVER, $saddr ) or Fatal( "Can't bind: $!" ); - listen( SERVER, SOMAXCONN ) or Fatal( "Can't listen: $!" ); + socket( SERVER, PF_UNIX, SOCK_STREAM, 0 ) + or Fatal( "Can't open socket: $!" ); + unlink( main::SOCK_FILE ); + my $saddr = sockaddr_un( main::SOCK_FILE ); + bind( SERVER, $saddr ) or Fatal( "Can't bind: $!" ); + listen( SERVER, SOMAXCONN ) or Fatal( "Can't listen: $!" ); - $dbh = zmDbConnect(); + $dbh = zmDbConnect(); - $x10 = new X10::ActiveHome( port=>ZM_X10_DEVICE, house_code=>ZM_X10_HOUSE_CODE, debug=>0 ); + $x10 = new X10::ActiveHome( port=>$Config{ZM_X10_DEVICE}, house_code=>$Config{ZM_X10_HOUSE_CODE}, debug=>0 ); - loadTasks(); + loadTasks(); - $x10->register_listener( \&x10listen ); + $x10->register_listener( \&x10listen ); - my $rin = ''; - vec( $rin, fileno(SERVER),1) = 1; - vec( $rin, $x10->select_fds(),1) = 1; - my $timeout = 0.2; - #print( "F:".fileno(SERVER)."\n" ); - my $reload = undef; - my $reload_count = 0; - my $reload_limit = &ZM_X10_DB_RELOAD_INTERVAL / $timeout; - while( 1 ) - { - my $nfound = select( my $rout = $rin, undef, undef, $timeout ); - #print( "Off select, NF:$nfound, ER:$!\n" ); - #print( vec( $rout, fileno(SERVER),1)."\n" ); - #print( vec( $rout, $x10->select_fds(),1)."\n" ); - if ( $nfound > 0 ) - { - if ( vec( $rout, fileno(SERVER),1) ) - { - my $paddr = accept( CLIENT, SERVER ); - my $message = ; + my $rin = ''; + vec( $rin, fileno(SERVER),1) = 1; + vec( $rin, $x10->select_fds(),1) = 1; + my $timeout = 0.2; + #print( "F:".fileno(SERVER)."\n" ); + my $reload = undef; + my $reload_count = 0; + my $reload_limit = $Config{ZM_X10_DB_RELOAD_INTERVAL} / $timeout; + while( 1 ) + { + my $nfound = select( my $rout = $rin, undef, undef, $timeout ); + #print( "Off select, NF:$nfound, ER:$!\n" ); + #print( vec( $rout, fileno(SERVER),1)."\n" ); + #print( vec( $rout, $x10->select_fds(),1)."\n" ); + if ( $nfound > 0 ) + { + if ( vec( $rout, fileno(SERVER),1) ) + { + my $paddr = accept( CLIENT, SERVER ); + my $message = ; - my ( $command, $unit_code ) = split( /;/, $message ); + my ( $command, $unit_code ) = split( /;/, $message ); - my $device; - if ( defined($unit_code) ) - { - if ( $unit_code < 1 || $unit_code > 16 ) - { - dPrint( ZoneMinder::Logger::ERROR, "Invalid unit code '$unit_code'\n" ); - next; - } + my $device; + if ( defined($unit_code) ) + { + if ( $unit_code < 1 || $unit_code > 16 ) + { + dPrint( ZoneMinder::Logger::ERROR, "Invalid unit code '$unit_code'\n" ); + next; + } - $device = $device_hash{$unit_code}; - if ( !$device ) - { - $device = $device_hash{$unit_code} = { appliance=>$x10->Appliance( unit_code=>$unit_code ), status=>'unknown' }; - } - } + $device = $device_hash{$unit_code}; + if ( !$device ) + { + $device = $device_hash{$unit_code} = { appliance=>$x10->Appliance( unit_code=>$unit_code ), + status=>'unknown' + }; + } + } - my $result; - if ( $command eq 'on' ) - { - $result = $device->{appliance}->on(); - } - elsif ( $command eq 'off' ) - { - $result = $device->{appliance}->off(); - } - #elsif ( $command eq 'dim' ) - #{ - #$result = $device->{appliance}->dim(); - #} - #elsif ( $command eq 'bright' ) - #{ - #$result = $device->{appliance}->bright(); - #} - elsif ( $command eq 'status' ) - { - if ( $device ) - { - dPrint( ZoneMinder::Logger::DEBUG, $unit_code." ".$device->{status}."\n" ); - } - else - { - foreach my $unit_code ( sort( keys(%device_hash) ) ) - { - my $device = $device_hash{$unit_code}; - dPrint( ZoneMinder::Logger::DEBUG, $unit_code." ".$device->{status}."\n" ); - } - } - } - elsif ( $command eq 'shutdown' ) - { - last; - } - else - { - dPrint( ZoneMinder::Logger::ERROR, "Invalid command '$command'\n" ); - } - if ( defined($result) ) - { - if ( 1 || $result ) - { - $device->{status} = uc($command); - dPrint( ZoneMinder::Logger::DEBUG, $device->{appliance}->address()." $command, ok\n" ); - #x10listen( new X10::Event( sprintf("%s %s", $device->{appliance}->address, uc($command) ) ) ); - } - else - { - dPrint( ZoneMinder::Logger::ERROR, $device->{appliance}->address()." $command, failed\n" ); - } - } - close( CLIENT ); - } - elsif ( vec( $rout, $x10->select_fds(),1) ) - { - $x10->handle_input(); - } - else - { - Fatal( "Bogus descriptor" ); - } - } - elsif ( $nfound < 0 ) - { - if ( $! != EINTR ) - { - Fatal( "Can't select: $!" ); - } - } - else - { - #print( "Select timed out\n" ); - # Check for state changes - foreach my $monitor_id ( sort(keys(%monitor_hash) ) ) - { - my $monitor = $monitor_hash{$monitor_id}; - my $state = zmGetMonitorState( $monitor ); - if ( !defined($state) ) - { - $reload = !undef; - next; - } - if ( defined( $monitor->{LastState} ) ) - { - my $task_list; - if ( ($state == STATE_ALARM || $state == STATE_ALERT) && ($monitor->{LastState} == STATE_IDLE || $monitor->{LastState} == STATE_TAPE) ) # Gone into alarm state - { - Debug( "Applying ON_list for $monitor_id\n" ); - $task_list = $monitor->{"ON_list"}; - } - elsif ( ($state == STATE_IDLE && $monitor->{LastState} != STATE_IDLE) || ($state == STATE_TAPE && $monitor->{LastState} != STATE_TAPE) ) # Come out of alarm state - { - Debug( "Applying OFF_list for $monitor_id\n" ); - $task_list = $monitor->{"OFF_list"}; - } - if ( $task_list ) - { - foreach my $task ( @$task_list ) - { - processTask( $task ); - } - } - } - $monitor->{LastState} = $state; - } + my $result; + if ( $command eq 'on' ) + { + $result = $device->{appliance}->on(); + } + elsif ( $command eq 'off' ) + { + $result = $device->{appliance}->off(); + } + #elsif ( $command eq 'dim' ) + #{ + #$result = $device->{appliance}->dim(); + #} + #elsif ( $command eq 'bright' ) + #{ + #$result = $device->{appliance}->bright(); + #} + elsif ( $command eq 'status' ) + { + if ( $device ) + { + dPrint( ZoneMinder::Logger::DEBUG, $unit_code." ".$device->{status}."\n" ); + } + else + { + foreach my $unit_code ( sort( keys(%device_hash) ) ) + { + my $device = $device_hash{$unit_code}; + dPrint( ZoneMinder::Logger::DEBUG, $unit_code." ".$device->{status}."\n" ); + } + } + } + elsif ( $command eq 'shutdown' ) + { + last; + } + else + { + dPrint( ZoneMinder::Logger::ERROR, "Invalid command '$command'\n" ); + } + if ( defined($result) ) + { + if ( 1 || $result ) + { + $device->{status} = uc($command); + dPrint( ZoneMinder::Logger::DEBUG, $device->{appliance}->address()." $command, ok\n" ); + #x10listen( new X10::Event( sprintf("%s %s", $device->{appliance}->address, uc($command) ) ) ); + } + else + { + dPrint( ZoneMinder::Logger::ERROR, $device->{appliance}->address()." $command, failed\n" ); + } + } + close( CLIENT ); + } + elsif ( vec( $rout, $x10->select_fds(),1) ) + { + $x10->handle_input(); + } + else + { + Fatal( "Bogus descriptor" ); + } + } + elsif ( $nfound < 0 ) + { + if ( $! != EINTR ) + { + Fatal( "Can't select: $!" ); + } + } + else + { + #print( "Select timed out\n" ); + # Check for state changes + foreach my $monitor_id ( sort(keys(%monitor_hash) ) ) + { + my $monitor = $monitor_hash{$monitor_id}; + my $state = zmGetMonitorState( $monitor ); + if ( !defined($state) ) + { + $reload = !undef; + next; + } + if ( defined( $monitor->{LastState} ) ) + { + my $task_list; + if ( ($state == STATE_ALARM || $state == STATE_ALERT) + && ($monitor->{LastState} == STATE_IDLE || $monitor->{LastState} == STATE_TAPE) + ) # Gone into alarm state + { + Debug( "Applying ON_list for $monitor_id\n" ); + $task_list = $monitor->{"ON_list"}; + } + elsif ( ($state == STATE_IDLE && $monitor->{LastState} != STATE_IDLE) + || ($state == STATE_TAPE && $monitor->{LastState} != STATE_TAPE) + ) # Come out of alarm state + { + Debug( "Applying OFF_list for $monitor_id\n" ); + $task_list = $monitor->{"OFF_list"}; + } + if ( $task_list ) + { + foreach my $task ( @$task_list ) + { + processTask( $task ); + } + } + } + $monitor->{LastState} = $state; + } - # Check for pending tasks - my $now = time(); - foreach my $activation_time ( sort(keys(%pending_tasks) ) ) - { - last if ( $activation_time > $now ); - my $pending_list = $pending_tasks{$activation_time}; - foreach my $task ( @$pending_list ) - { - processTask( $task ); - } - delete( $pending_tasks{$activation_time} ); - } - if ( $reload || ++$reload_count >= $reload_limit ) - { - loadTasks(); - $reload = undef; - $reload_count = 0; - } - } - } - Info( "X10 server exiting\n" ); - close( SERVER ); - exit(); + # Check for pending tasks + my $now = time(); + foreach my $activation_time ( sort(keys(%pending_tasks) ) ) + { + last if ( $activation_time > $now ); + my $pending_list = $pending_tasks{$activation_time}; + foreach my $task ( @$pending_list ) + { + processTask( $task ); + } + delete( $pending_tasks{$activation_time} ); + } + if ( $reload || ++$reload_count >= $reload_limit ) + { + loadTasks(); + $reload = undef; + $reload_count = 0; + } + } + } + Info( "X10 server exiting\n" ); + close( SERVER ); + exit(); } sub addToDeviceList { - my $unit_code = shift; - my $event = shift; - my $monitor = shift; - my $function = shift; - my $limit = shift; + my $unit_code = shift; + my $event = shift; + my $monitor = shift; + my $function = shift; + my $limit = shift; - Debug( "Adding to device list, uc:$unit_code, ev:$event, mo:".$monitor->{Id}.", fu:$function, li:$limit\n" ); - my $device = $device_hash{$unit_code}; - if ( !$device ) - { - $device = $device_hash{$unit_code} = { appliance=>$x10->Appliance( unit_code=>$unit_code ), status=>'unknown' }; - } + Debug( "Adding to device list, uc:$unit_code, ev:$event, mo:" + .$monitor->{Id}.", fu:$function, li:$limit\n" + ); + my $device = $device_hash{$unit_code}; + if ( !$device ) + { + $device = $device_hash{$unit_code} = { appliance=>$x10->Appliance( unit_code=>$unit_code ), + status=>'unknown' + }; + } - my $task = { type=>"device", monitor=>$monitor, address=>$device->{appliance}->address(), function=>$function }; - if ( $limit ) - { - $task->{limit} = $limit - } + my $task = { type=>"device", + monitor=>$monitor, + address=>$device->{appliance}->address(), + function=>$function + }; + if ( $limit ) + { + $task->{limit} = $limit + } - my $task_list = $device->{$event."_list"}; - if ( !$task_list ) - { - $task_list = $device->{$event."_list"} = []; - } - push( @$task_list, $task ); + my $task_list = $device->{$event."_list"}; + if ( !$task_list ) + { + $task_list = $device->{$event."_list"} = []; + } + push( @$task_list, $task ); } sub addToMonitorList { - my $monitor = shift; - my $event = shift; - my $unit_code = shift; - my $function = shift; - my $limit = shift; + my $monitor = shift; + my $event = shift; + my $unit_code = shift; + my $function = shift; + my $limit = shift; - Debug( "Adding to monitor list, uc:$unit_code, ev:$event, mo:".$monitor->{Id}.", fu:$function, li:$limit\n" ); - my $device = $device_hash{$unit_code}; - if ( !$device ) - { - $device = $device_hash{$unit_code} = { appliance=>$x10->Appliance( unit_code=>$unit_code ), status=>'unknown' }; - } + Debug( "Adding to monitor list, uc:$unit_code, ev:$event, mo:".$monitor->{Id} + .", fu:$function, li:$limit\n" + ); + my $device = $device_hash{$unit_code}; + if ( !$device ) + { + $device = $device_hash{$unit_code} = { appliance=>$x10->Appliance( unit_code=>$unit_code ), + status=>'unknown' + }; + } - my $task = { type=>"monitor", device=>$device, id=>$monitor->{Id}, function=>$function }; - if ( $limit ) - { - $task->{limit} = $limit; - } + my $task = { type=>"monitor", + device=>$device, + id=>$monitor->{Id}, + function=>$function + }; + if ( $limit ) + { + $task->{limit} = $limit; + } - my $task_list = $monitor->{$event."_list"}; - if ( !$task_list ) - { - $task_list = $monitor->{$event."_list"} = []; - } - push( @$task_list, $task ); + my $task_list = $monitor->{$event."_list"}; + if ( !$task_list ) + { + $task_list = $monitor->{$event."_list"} = []; + } + push( @$task_list, $task ); } sub loadTasks { - %monitor_hash = (); + %monitor_hash = (); - Debug( "Loading tasks\n" ); - # Clear out all old device task lists - foreach my $unit_code ( sort( keys(%device_hash) ) ) - { - my $device = $device_hash{$unit_code}; - $device->{ON_list} = []; - $device->{OFF_list} = []; - } + Debug( "Loading tasks\n" ); + # Clear out all old device task lists + foreach my $unit_code ( sort( keys(%device_hash) ) ) + { + my $device = $device_hash{$unit_code}; + $device->{ON_list} = []; + $device->{OFF_list} = []; + } - my $sql = "select M.*,T.* from Monitors as M inner join TriggersX10 as T on (M.Id = T.MonitorId) where find_in_set( M.Function, 'Modect,Record,Mocord,Nodect' ) and M.Enabled = 1 and find_in_set( 'X10', M.Triggers )"; - my $sth = $dbh->prepare_cached( $sql ) or Fatal( "Can't prepare '$sql': ".$dbh->errstr() ); - my $res = $sth->execute() or Fatal( "Can't execute: ".$sth->errstr() ); - while( my $monitor = $sth->fetchrow_hashref() ) - { - next if ( !zmMemVerify( $monitor ) ); # Check shared memory ok + my $sql = "SELECT M.*,T.* from Monitors as M + INNER JOIN TriggersX10 as T on (M.Id = T.MonitorId) + WHERE find_in_set( M.Function, 'Modect,Record,Mocord,Nodect' ) + AND M.Enabled = 1 + AND find_IN_set( 'X10', M.Triggers )" + ; + my $sth = $dbh->prepare_cached( $sql ) + or Fatal( "Can't prepare '$sql': ".$dbh->errstr() ); + my $res = $sth->execute() + or Fatal( "Can't execute: ".$sth->errstr() ); + while( my $monitor = $sth->fetchrow_hashref() ) + { + next if ( !zmMemVerify( $monitor ) ); # Check shared memory ok - $monitor_hash{$monitor->{Id}} = $monitor; + $monitor_hash{$monitor->{Id}} = $monitor; - if ( $monitor->{Activation} ) - { - Debug( "$monitor->{Name} has active string '$monitor->{Activation}'\n" ); - foreach my $code_string ( split( /,/, $monitor->{Activation} ) ) - { - #Debug( "Code string: $code_string\n" ); - my ( $invert, $unit_code, $modifier, $limit ) = ( $code_string =~ /^([!~])?(\d+)(?:([+-])(\d+)?)?$/ ); - $limit = 0 if ( !$limit ); - if ( $unit_code ) - { - if ( !$modifier || $modifier eq '+' ) - { - addToDeviceList( $unit_code, "ON", $monitor, !$invert?"start_active":"stop_active", $limit ); - } - if ( !$modifier || $modifier eq '-' ) - { - addToDeviceList( $unit_code, "OFF", $monitor, !$invert?"stop_active":"start_active", $limit ); - } - } - } - } - if ( $monitor->{AlarmInput} ) - { - Debug( "$monitor->{Name} has alarm input string '$monitor->{AlarmInput}'\n" ); - foreach my $code_string ( split( /,/, $monitor->{AlarmInput} ) ) - { - #Debug( "Code string: $code_string\n" ); - my ( $invert, $unit_code, $modifier, $limit ) = ( $code_string =~ /^([!~])?(\d+)(?:([+-])(\d+)?)?$/ ); - $limit = 0 if ( !$limit ); - if ( $unit_code ) - { - if ( !$modifier || $modifier eq '+' ) - { - addToDeviceList( $unit_code, "ON", $monitor, !$invert?"start_alarm":"stop_alarm", $limit ); - } - if ( !$modifier || $modifier eq '-' ) - { - addToDeviceList( $unit_code, "OFF", $monitor, !$invert?"stop_alarm":"start_alarm", $limit ); - } - } - } - } - if ( $monitor->{AlarmOutput} ) - { - Debug( "$monitor->{Name} has alarm output string '$monitor->{AlarmOutput}'\n" ); - foreach my $code_string ( split( /,/, $monitor->{AlarmOutput} ) ) - { - #Debug( "Code string: $code_string\n" ); - my ( $invert, $unit_code, $modifier, $limit ) = ( $code_string =~ /^([!~])?(\d+)(?:([+-])(\d+)?)?$/ ); - $limit = 0 if ( !$limit ); - if ( $unit_code ) - { - if ( !$modifier || $modifier eq '+' ) - { - addToMonitorList( $monitor, "ON", $unit_code, !$invert?"on":"off", $limit ); - } - if ( !$modifier || $modifier eq '-' ) - { - addToMonitorList( $monitor, "OFF", $unit_code, !$invert?"off":"on", $limit ); - } - } - } - } + if ( $monitor->{Activation} ) + { + Debug( "$monitor->{Name} has active string '$monitor->{Activation}'\n" ); + foreach my $code_string ( split( /,/, $monitor->{Activation} ) ) + { + #Debug( "Code string: $code_string\n" ); + my ( $invert, $unit_code, $modifier, $limit ) + = ( $code_string =~ /^([!~])?(\d+)(?:([+-])(\d+)?)?$/ ); + $limit = 0 if ( !$limit ); + if ( $unit_code ) + { + if ( !$modifier || $modifier eq '+' ) + { + addToDeviceList( $unit_code, + "ON", + $monitor, + !$invert ? "start_active" + : "stop_active", + $limit + ); + } + if ( !$modifier || $modifier eq '-' ) + { + addToDeviceList( $unit_code, + "OFF", + $monitor, + !$invert ? "stop_active" + : "start_active", + $limit + ); + } + } + } + } + if ( $monitor->{AlarmInput} ) + { + Debug( "$monitor->{Name} has alarm input string '$monitor->{AlarmInput}'\n" ); + foreach my $code_string ( split( /,/, $monitor->{AlarmInput} ) ) + { + #Debug( "Code string: $code_string\n" ); + my ( $invert, $unit_code, $modifier, $limit ) + = ( $code_string =~ /^([!~])?(\d+)(?:([+-])(\d+)?)?$/ ); + $limit = 0 if ( !$limit ); + if ( $unit_code ) + { + if ( !$modifier || $modifier eq '+' ) + { + addToDeviceList( $unit_code, + "ON", + $monitor, + !$invert ? "start_alarm" + : "stop_alarm", + $limit + ); + } + if ( !$modifier || $modifier eq '-' ) + { + addToDeviceList( $unit_code, + "OFF", + $monitor, + !$invert ? "stop_alarm" + : "start_alarm", + $limit + ); + } + } + } + } + if ( $monitor->{AlarmOutput} ) + { + Debug( "$monitor->{Name} has alarm output string '$monitor->{AlarmOutput}'\n" ); + foreach my $code_string ( split( /,/, $monitor->{AlarmOutput} ) ) + { + #Debug( "Code string: $code_string\n" ); + my ( $invert, $unit_code, $modifier, $limit ) + = ( $code_string =~ /^([!~])?(\d+)(?:([+-])(\d+)?)?$/ ); + $limit = 0 if ( !$limit ); + if ( $unit_code ) + { + if ( !$modifier || $modifier eq '+' ) + { + addToMonitorList( $monitor, + "ON", + $unit_code, + !$invert ? "on" + : "off", + $limit + ); + } + if ( !$modifier || $modifier eq '-' ) + { + addToMonitorList( $monitor, + "OFF", + $unit_code, + !$invert ? "off" + : "on", + $limit + ); + } + } + } + } zmMemInvalidate( $monitor ); - } + } } sub addPendingTask { - my $task = shift; + my $task = shift; - # Check whether we are just extending a previous pending task - # and remove it if it's there - foreach my $activation_time ( sort(keys(%pending_tasks) ) ) - { - my $pending_list = $pending_tasks{$activation_time}; - my $new_pending_list = []; - foreach my $pending_task ( @$pending_list ) - { - if ( $task->{type} ne $pending_task->{type} ) - { - push( @$new_pending_list, $pending_task ) - } - elsif ( $task->{type} eq "device" ) - { - if (( $task->{monitor}->{Id} != $pending_task->{monitor}->{Id} ) - || ( $task->{function} ne $pending_task->{function} )) - { - push( @$new_pending_list, $pending_task ) - } - } - elsif ( $task->{type} eq "monitor" ) - { - if (( $task->{device}->{appliance}->unit_code() != $pending_task->{device}->{appliance}->unit_code() ) - || ( $task->{function} ne $pending_task->{function} )) - { - push( @$new_pending_list, $pending_task ) - } - } - } - if ( @$new_pending_list ) - { - $pending_tasks{$activation_time} = $new_pending_list; - } - else - { - delete( $pending_tasks{$activation_time} ); - } - } + # Check whether we are just extending a previous pending task + # and remove it if it's there + foreach my $activation_time ( sort(keys(%pending_tasks) ) ) + { + my $pending_list = $pending_tasks{$activation_time}; + my $new_pending_list = []; + foreach my $pending_task ( @$pending_list ) + { + if ( $task->{type} ne $pending_task->{type} ) + { + push( @$new_pending_list, $pending_task ) + } + elsif ( $task->{type} eq "device" ) + { + if (( $task->{monitor}->{Id} != $pending_task->{monitor}->{Id} ) + || ( $task->{function} ne $pending_task->{function} )) + { + push( @$new_pending_list, $pending_task ) + } + } + elsif ( $task->{type} eq "monitor" ) + { + if (( $task->{device}->{appliance}->unit_code() + != $pending_task->{device}->{appliance}->unit_code() + ) + || ( $task->{function} ne $pending_task->{function} ) + ) + { + push( @$new_pending_list, $pending_task ) + } + } + } + if ( @$new_pending_list ) + { + $pending_tasks{$activation_time} = $new_pending_list; + } + else + { + delete( $pending_tasks{$activation_time} ); + } + } - my $end_time = time() + $task->{limit}; - my $pending_list = $pending_tasks{$end_time}; - if ( !$pending_list ) - { - $pending_list = $pending_tasks{$end_time} = []; - } - my $pending_task; - if ( $task->{type} eq "device" ) - { - $pending_task = { type=>$task->{type}, monitor=>$task->{monitor}, function=>$task->{function} }; - $pending_task->{function} =~ s/start/stop/; - } - elsif ( $task->{type} eq "monitor" ) - { - $pending_task = { type=>$task->{type}, device=>$task->{device}, function=>$task->{function} }; - $pending_task->{function} =~ s/on/off/; - } - push( @$pending_list, $pending_task ); + my $end_time = time() + $task->{limit}; + my $pending_list = $pending_tasks{$end_time}; + if ( !$pending_list ) + { + $pending_list = $pending_tasks{$end_time} = []; + } + my $pending_task; + if ( $task->{type} eq "device" ) + { + $pending_task = { type=>$task->{type}, + monitor=>$task->{monitor}, + function=>$task->{function} + }; + $pending_task->{function} =~ s/start/stop/; + } + elsif ( $task->{type} eq "monitor" ) + { + $pending_task = { type=>$task->{type}, + device=>$task->{device}, + function=>$task->{function} + }; + $pending_task->{function} =~ s/on/off/; + } + push( @$pending_list, $pending_task ); } sub processTask { - my $task = shift; + my $task = shift; - if ( $task->{type} eq "device" ) - { - my ( $instruction, $class ) = ( $task->{function} =~ /^(.+)_(.+)$/ ); + if ( $task->{type} eq "device" ) + { + my ( $instruction, $class ) = ( $task->{function} =~ /^(.+)_(.+)$/ ); - if ( $class eq "active" ) - { - if ( $instruction eq "start" ) - { - zmMonitorEnable( $task->{monitor} ); - if ( $task->{limit} ) - { - addPendingTask( $task ); - } - } - elsif( $instruction eq "stop" ) - { - zmMonitorDisable( $task->{monitor} ); - } - } - elsif( $class eq "alarm" ) - { - if ( $instruction eq "start" ) - { - zmTriggerEventOn( $task->{monitor}, 0, main::CAUSE_STRING, $task->{address} ); - if ( $task->{limit} ) - { - addPendingTask( $task ); - } - } - elsif( $instruction eq "stop" ) - { - zmTriggerEventCancel( $task->{monitor} ); - } - } - } - elsif( $task->{type} eq "monitor" ) - { - if ( $task->{function} eq "on" ) - { - $task->{device}->{appliance}->on(); - if ( $task->{limit} ) - { - addPendingTask( $task ); - } - } - elsif ( $task->{function} eq "off" ) - { - $task->{device}->{appliance}->off(); - } - } + if ( $class eq "active" ) + { + if ( $instruction eq "start" ) + { + zmMonitorEnable( $task->{monitor} ); + if ( $task->{limit} ) + { + addPendingTask( $task ); + } + } + elsif( $instruction eq "stop" ) + { + zmMonitorDisable( $task->{monitor} ); + } + } + elsif( $class eq "alarm" ) + { + if ( $instruction eq "start" ) + { + zmTriggerEventOn( $task->{monitor}, + 0, + main::CAUSE_STRING, + $task->{address} + ); + if ( $task->{limit} ) + { + addPendingTask( $task ); + } + } + elsif( $instruction eq "stop" ) + { + zmTriggerEventCancel( $task->{monitor} ); + } + } + } + elsif( $task->{type} eq "monitor" ) + { + if ( $task->{function} eq "on" ) + { + $task->{device}->{appliance}->on(); + if ( $task->{limit} ) + { + addPendingTask( $task ); + } + } + elsif ( $task->{function} eq "off" ) + { + $task->{device}->{appliance}->off(); + } + } } sub dPrint { - my $dbg_level = shift; - if ( fileno(CLIENT) ) - { - print CLIENT @_ - } - if ( $dbg_level == ZoneMinder::Logger::DEBUG ) - { - Debug( @_ ); - } - elsif ( $dbg_level == ZoneMinder::Logger::INFO ) - { - Info( @_ ); - } - elsif ( $dbg_level == ZoneMinder::Logger::WARNING ) - { - Warning( @_ ); - } - elsif ( $dbg_level == ZoneMinder::Logger::ERROR ) - { - Error( @_ ); - } - elsif ( $dbg_level == ZoneMinder::Logger::FATAL ) - { - Fatal( @_ ); - } + my $dbg_level = shift; + if ( fileno(CLIENT) ) + { + print CLIENT @_ + } + if ( $dbg_level == ZoneMinder::Logger::DEBUG ) + { + Debug( @_ ); + } + elsif ( $dbg_level == ZoneMinder::Logger::INFO ) + { + Info( @_ ); + } + elsif ( $dbg_level == ZoneMinder::Logger::WARNING ) + { + Warning( @_ ); + } + elsif ( $dbg_level == ZoneMinder::Logger::ERROR ) + { + Error( @_ ); + } + elsif ( $dbg_level == ZoneMinder::Logger::FATAL ) + { + Fatal( @_ ); + } } sub x10listen { - foreach my $event ( @_ ) - { - #print( Data::Dumper( $_ )."\n" ); - if ( $event->house_code() eq ZM_X10_HOUSE_CODE ) - { - my $unit_code = $event->unit_code(); - my $device = $device_hash{$unit_code}; - if ( !$device ) - { - $device = $device_hash{$unit_code} = { appliance=>$x10->Appliance( unit_code=>$unit_code ), status=>'unknown' }; - } - next if ( $event->func() !~ /(?:ON|OFF)/ ); - $device->{status} = $event->func(); - my $task_list = $device->{$event->func()."_list"}; - if ( $task_list ) - { - foreach my $task ( @$task_list ) - { - processTask( $task ); - } - } - } - Info( "Got event - ".$event->as_string()."\n" ); - } + foreach my $event ( @_ ) + { + #print( Data::Dumper( $_ )."\n" ); + if ( $event->house_code() eq $Config{ZM_X10_HOUSE_CODE} ) + { + my $unit_code = $event->unit_code(); + my $device = $device_hash{$unit_code}; + if ( !$device ) + { + $device = $device_hash{$unit_code} = { appliance=>$x10->Appliance( unit_code=>$unit_code ), + status=>'unknown' + }; + } + next if ( $event->func() !~ /(?:ON|OFF)/ ); + $device->{status} = $event->func(); + my $task_list = $device->{$event->func()."_list"}; + if ( $task_list ) + { + foreach my $task ( @$task_list ) + { + processTask( $task ); + } + } + } + Info( "Got event - ".$event->as_string()."\n" ); + } } 1; diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index b768d56fe..85f15dbe5 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -14,7 +14,6 @@ add_executable(zma zma.cpp) add_executable(zmu zmu.cpp) add_executable(zmf zmf.cpp) add_executable(zms zms.cpp) -add_executable(nph-zms zms.cpp) add_executable(zmstreamer zmstreamer.cpp) target_link_libraries(zmc zm ${ZM_EXTRA_LIBS} ${ZM_BIN_LIBS}) @@ -22,10 +21,9 @@ target_link_libraries(zma zm ${ZM_EXTRA_LIBS} ${ZM_BIN_LIBS}) target_link_libraries(zmu zm ${ZM_EXTRA_LIBS} ${ZM_BIN_LIBS}) target_link_libraries(zmf zm ${ZM_EXTRA_LIBS} ${ZM_BIN_LIBS}) target_link_libraries(zms zm ${ZM_EXTRA_LIBS} ${ZM_BIN_LIBS}) -target_link_libraries(nph-zms zm ${ZM_EXTRA_LIBS} ${ZM_BIN_LIBS}) target_link_libraries(zmstreamer zm ${ZM_EXTRA_LIBS} ${ZM_BIN_LIBS}) install(TARGETS zmc zma zmu zmf zmstreamer RUNTIME DESTINATION "${CMAKE_INSTALL_FULL_BINDIR}" PERMISSIONS OWNER_WRITE OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) -install(TARGETS zms nph-zms RUNTIME DESTINATION "${ZM_CGIDIR}" PERMISSIONS OWNER_WRITE OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) - +install(TARGETS zms RUNTIME DESTINATION "${ZM_CGIDIR}" PERMISSIONS OWNER_WRITE OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) +install(CODE "execute_process(COMMAND ln -sf zms nph-zms WORKING_DIRECTORY \"\$ENV{DESTDIR}${ZM_CGIDIR}\")") diff --git a/src/zm.h b/src/zm.h index 9e4f47b5d..a60ab655d 100644 --- a/src/zm.h +++ b/src/zm.h @@ -17,14 +17,24 @@ // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // +#if !defined(PATH_MAX) +#define PATH_MAX 1024 +#endif + #ifndef ZM_H #define ZM_H #include "zm_config.h" +#ifdef SOLARIS +#undef DEFAULT_TYPE // pthread defines this which breaks StreamType DEFAULT_TYPE +#include // define strerror() and friends +#endif #include "zm_logger.h" #include +#include + extern const char* self; #endif // ZM_H diff --git a/src/zm_box.h b/src/zm_box.h index 8a18b8847..8aa341d73 100644 --- a/src/zm_box.h +++ b/src/zm_box.h @@ -23,7 +23,11 @@ #include "zm.h" #include "zm_coord.h" +#ifndef SOLARIS #include +#else +#include +#endif // // Class used for storing a box, which is defined as a region diff --git a/src/zm_comms.cpp b/src/zm_comms.cpp index c42b7bd17..a109019bd 100644 --- a/src/zm_comms.cpp +++ b/src/zm_comms.cpp @@ -36,6 +36,10 @@ #include #include +#ifdef SOLARIS +#include // define FIONREAD +#endif + int CommsBase::readV( int iovcnt, /* const void *, int, */ ... ) { va_list arg_ptr; diff --git a/src/zm_event.cpp b/src/zm_event.cpp index 3908e43f8..8ea8f4a75 100755 --- a/src/zm_event.cpp +++ b/src/zm_event.cpp @@ -36,6 +36,12 @@ #include "zm_event.h" #include "zm_monitor.h" +// sendfile tricks +extern "C" +{ +#include "zm_sendfile.h" +} + #include "zmf.h" #if HAVE_SYS_SENDFILE_H @@ -1431,7 +1437,7 @@ bool EventStream::sendFrame( int delta_us ) if(send_raw) { #if HAVE_SENDFILE fprintf( stdout, "Content-Length: %d\r\n\r\n", (int)filestat.st_size ); - if(sendfile(fileno(stdout), fileno(fdj), 0, (int)filestat.st_size) != (int)filestat.st_size) { + if(zm_sendfile(fileno(stdout), fileno(fdj), 0, (int)filestat.st_size) != (int)filestat.st_size) { /* sendfile() failed, use standard way instead */ img_buffer_size = fread( img_buffer, 1, sizeof(temp_img_buffer), fdj ); if ( fwrite( img_buffer, img_buffer_size, 1, stdout ) != 1 ) { @@ -1544,8 +1550,10 @@ void EventStream::runStream() if ( ((curr_frame_id-1)%frame_mod) == 0 ) { delta_us = (unsigned int)(frame_data->delta * 1000000); - if ( effective_fps < base_fps ) - delta_us = (unsigned int)((delta_us * base_fps)/effective_fps); + // if effective > base we should speed up frame delivery + delta_us = (unsigned int)((delta_us * base_fps)/effective_fps); + // but must not exceed maxfps + delta_us = max(delta_us, 1000000 / maxfps); send_frame = true; } } diff --git a/src/zm_ffmpeg.cpp b/src/zm_ffmpeg.cpp index be1fac8f1..f1498d4a9 100644 --- a/src/zm_ffmpeg.cpp +++ b/src/zm_ffmpeg.cpp @@ -86,13 +86,21 @@ SWScale::SWScale() : gotdefaults(false), swscale_ctx(NULL), input_avframe(NULL), Debug(4,"SWScale object created"); /* Allocate AVFrame for the input */ +#if LIBAVCODEC_VERSION_CHECK(55, 28, 1, 45, 101) + input_avframe = av_frame_alloc(); +#else input_avframe = avcodec_alloc_frame(); +#endif if(input_avframe == NULL) { Fatal("Failed allocating AVFrame for the input"); } /* Allocate AVFrame for the output */ +#if LIBAVCODEC_VERSION_CHECK(55, 28, 1, 45, 101) + output_avframe = av_frame_alloc(); +#else output_avframe = avcodec_alloc_frame(); +#endif if(output_avframe == NULL) { Fatal("Failed allocating AVFrame for the output"); } @@ -140,7 +148,7 @@ int SWScale::Convert(const uint8_t* in_buffer, const size_t in_buffer_size, uint return -3; } -#if LIBSWSCALE_VERSION_INT >= AV_VERSION_INT(0, 8, 0) +#if LIBSWSCALE_VERSION_CHECK(0, 8, 0, 8, 0) /* Warn if the input or output pixelformat is not supported */ if(!sws_isSupportedInput(in_pf)) { Warning("swscale does not support the input format: %c%c%c%c",(in_pf)&0xff,((in_pf)&0xff),((in_pf>>16)&0xff),((in_pf>>24)&0xff)); diff --git a/src/zm_ffmpeg.h b/src/zm_ffmpeg.h index cee7187a9..33f9c7faf 100644 --- a/src/zm_ffmpeg.h +++ b/src/zm_ffmpeg.h @@ -32,7 +32,17 @@ extern "C" { #include #include #include -#if LIBAVUTIL_VERSION_INT > AV_VERSION_INT(50, 28, 0) + +/* LIBAVUTIL_VERSION_CHECK checks for the right version of libav and FFmpeg + * The original source is vlc (in modules/codec/avcodec/avcommon_compat.h) + * a is the major version + * b and c the minor and micro versions of libav + * d and e the minor and micro versions of FFmpeg */ +#define LIBAVUTIL_VERSION_CHECK(a, b, c, d, e) \ + ( (LIBAVUTIL_VERSION_MICRO < 100 && LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(a, b, c) ) || \ + (LIBAVUTIL_VERSION_MICRO >= 100 && LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(a, d, e) ) ) + +#if LIBAVUTIL_VERSION_CHECK(50, 29, 0, 29, 0) #include #else #include @@ -42,43 +52,82 @@ extern "C" { #include #include #include -#endif +#endif /* HAVE_LIBAVUTIL_AVUTIL_H */ // AVCODEC #if HAVE_LIBAVCODEC_AVCODEC_H #include + +/* + * LIBAVCODEC_VERSION_CHECK checks for the right version of libav and FFmpeg + * The original source is vlc (in modules/codec/avcodec/avcommon_compat.h) + * a is the major version + * b and c the minor and micro versions of libav + * d and e the minor and micro versions of FFmpeg */ +#define LIBAVCODEC_VERSION_CHECK(a, b, c, d, e) \ + ( (LIBAVCODEC_VERSION_MICRO < 100 && LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(a, b, c) ) || \ + (LIBAVCODEC_VERSION_MICRO >= 100 && LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(a, d, e) ) ) + #elif HAVE_FFMPEG_AVCODEC_H #include -#endif - +#endif /* HAVE_LIBAVCODEC_AVCODEC_H */ + #if defined(HAVE_LIBAVCODEC_AVCODEC_H) -#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(54,25,0) +#if LIBAVCODEC_VERSION_CHECK(54, 25, 0, 51, 100) #define _AVCODECID AVCodecID #else #define _AVCODECID CodecID #endif -#endif +#endif /* HAVE_LIBAVCODEC_AVCODEC_H */ // AVFORMAT #if HAVE_LIBAVFORMAT_AVFORMAT_H #include + +/* LIBAVFORMAT_VERSION_CHECK checks for the right version of libav and FFmpeg + * The original source is vlc (in modules/codec/avcodec/avcommon_compat.h) + * a is the major version + * b and c the minor and micro versions of libav + * d and e the minor and micro versions of FFmpeg */ +#define LIBAVFORMAT_VERSION_CHECK(a, b, c, d, e) \ + ( (LIBAVFORMAT_VERSION_MICRO < 100 && LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(a, b, c) ) || \ + (LIBAVFORMAT_VERSION_MICRO >= 100 && LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(a, d, e) ) ) + #elif HAVE_FFMPEG_AVFORMAT_H #include -#endif +#endif /* HAVE_LIBAVFORMAT_AVFORMAT_H */ // AVDEVICE #if HAVE_LIBAVDEVICE_AVDEVICE_H #include + +/* LIBAVDEVICE_VERSION_CHECK checks for the right version of libav and FFmpeg + * a is the major version + * b and c the minor and micro versions of libav + * d and e the minor and micro versions of FFmpeg */ +#define LIBAVDEVICE_VERSION_CHECK(a, b, c, d, e) \ + ( (LIBAVDEVICE_VERSION_MICRO < 100 && LIBAVDEVICE_VERSION_INT >= AV_VERSION_INT(a, b, c) ) || \ + (LIBAVDEVICE_VERSION_MICRO >= 100 && LIBAVDEVICE_VERSION_INT >= AV_VERSION_INT(a, d, e) ) ) + #elif HAVE_FFMPEG_AVDEVICE_H #include -#endif +#endif /* HAVE_LIBAVDEVICE_AVDEVICE_H */ // SWSCALE #if HAVE_LIBSWSCALE_SWSCALE_H #include + +/* LIBSWSCALE_VERSION_CHECK checks for the right version of libav and FFmpeg + * a is the major version + * b and c the minor and micro versions of libav + * d and e the minor and micro versions of FFmpeg */ +#define LIBSWSCALE_VERSION_CHECK(a, b, c, d, e) \ + ( (LIBSWSCALE_VERSION_MICRO < 100 && LIBSWSCALE_VERSION_INT >= AV_VERSION_INT(a, b, c) ) || \ + (LIBSWSCALE_VERSION_MICRO >= 100 && LIBSWSCALE_VERSION_INT >= AV_VERSION_INT(a, d, e) ) ) + #elif HAVE_FFMPEG_SWSCALE_H #include -#endif +#endif /* HAVE_LIBSWSCALE_SWSCALE_H */ #ifdef __cplusplus } @@ -86,7 +135,7 @@ extern "C" { #if ( HAVE_LIBAVUTIL_AVUTIL_H || HAVE_LIBAVCODEC_AVCODEC_H || HAVE_LIBAVFORMAT_AVFORMAT_H || HAVE_LIBAVDEVICE_AVDEVICE_H ) -#if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(53, 4, 0) +#if !LIBAVFORMAT_VERSION_CHECK(52, 107, 0, 107, 0) #if defined(AVIO_WRONLY) #define AVIO_FLAG_WRITE AVIO_WRONLY #else @@ -131,7 +180,7 @@ protected: }; #endif // HAVE_LIBSWSCALE && HAVE_LIBAVUTIL -#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(54, 25, 0) +#if !LIBAVCODEC_VERSION_CHECK(54, 25, 0, 51, 100) #define AV_CODEC_ID_NONE CODEC_ID_NONE #define AV_CODEC_ID_PCM_MULAW CODEC_ID_PCM_MULAW #define AV_CODEC_ID_PCM_ALAW CODEC_ID_PCM_ALAW @@ -167,18 +216,18 @@ protected: inline static const std::string av_make_error_string(int errnum) { char errbuf[AV_ERROR_MAX_STRING_SIZE]; -#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(50, 12, 13) +#if LIBAVUTIL_VERSION_CHECK(50, 13, 0, 13, 0) av_strerror(errnum, errbuf, AV_ERROR_MAX_STRING_SIZE); #else snprintf(errbuf, AV_ERROR_MAX_STRING_SIZE, "libav error %d", errnum); #endif return (std::string)errbuf; } - + #undef av_err2str #define av_err2str(errnum) av_make_error_string(errnum).c_str() - #endif // __cplusplus + #endif // __cplusplus #endif // ( HAVE_LIBAVUTIL_AVUTIL_H || HAVE_LIBAVCODEC_AVCODEC_H || HAVE_LIBAVFORMAT_AVFORMAT_H || HAVE_LIBAVDEVICE_AVDEVICE_H ) diff --git a/src/zm_ffmpeg_camera.cpp b/src/zm_ffmpeg_camera.cpp index 70869475d..b342d0ea8 100755 --- a/src/zm_ffmpeg_camera.cpp +++ b/src/zm_ffmpeg_camera.cpp @@ -30,6 +30,12 @@ extern "C"{ #define AV_ERROR_MAX_STRING_SIZE 64 #endif +#ifdef SOLARIS +#include // for ESRCH +#include +#include +#endif + FfmpegCamera::FfmpegCamera( int p_id, const std::string &p_path, const std::string &p_method, const std::string &p_options, int p_width, int p_height, int p_colours, int p_brightness, int p_contrast, int p_hue, int p_colour, bool p_capture ) : Camera( p_id, FFMPEG_SRC, p_width, p_height, p_colours, ZM_SUBPIX_ORDER_DEFAULT_FOR_COLOUR(p_colours), p_brightness, p_contrast, p_hue, p_colour, p_capture ), mPath( p_path ), @@ -128,7 +134,7 @@ int FfmpegCamera::Capture( Image &image ) void *retval = 0; int ret; - ret = pthread_tryjoin_np(mReopenThread, &retval); + ret = pthread_join(mReopenThread, &retval); if (ret != 0){ Error("Could not join reopen thread."); } @@ -172,7 +178,7 @@ int FfmpegCamera::Capture( Image &image ) Debug( 5, "Got packet from stream %d", packet.stream_index ); if ( packet.stream_index == mVideoStreamId ) { -#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(52, 25, 0) +#if LIBAVCODEC_VERSION_CHECK(52, 23, 0, 23, 0) if ( avcodec_decode_video2( mCodecContext, mRawFrame, &frameComplete, &packet ) < 0 ) #else if ( avcodec_decode_video( mCodecContext, mRawFrame, &frameComplete, packet.data, packet.size ) < 0 ) @@ -226,7 +232,7 @@ int FfmpegCamera::OpenFfmpeg() { mIsOpening = true; // Open the input, not necessarily a file -#if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(53, 4, 0) +#if !LIBAVFORMAT_VERSION_CHECK(53, 2, 0, 4, 0) Debug ( 1, "Calling av_open_input_file" ); if ( av_open_input_file( &mFormatContext, mPath.c_str(), NULL, 0, NULL ) !=0 ) #else @@ -283,7 +289,7 @@ int FfmpegCamera::OpenFfmpeg() { //mFormatContext->probesize = 32; //mFormatContext->max_analyze_duration = 32; // Locate stream info from avformat_open_input -#if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(53, 4, 0) +#if !LIBAVFORMAT_VERSION_CHECK(53, 6, 0, 6, 0) Debug ( 1, "Calling av_find_stream_info" ); if ( av_find_stream_info( mFormatContext ) < 0 ) #else @@ -291,15 +297,14 @@ int FfmpegCamera::OpenFfmpeg() { if ( avformat_find_stream_info( mFormatContext, 0 ) < 0 ) #endif Fatal( "Unable to find stream info from %s due to: %s", mPath.c_str(), strerror(errno) ); - - Info( "Find stream info complete %s", mPath.c_str() ); + Debug ( 1, "Got stream info" ); // Find first video stream present mVideoStreamId = -1; for (unsigned int i=0; i < mFormatContext->nb_streams; i++ ) { -#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(51,2,1) +#if (LIBAVCODEC_VERSION_CHECK(52, 64, 0, 64, 0) || LIBAVUTIL_VERSION_CHECK(50, 14, 0, 14, 0)) if ( mFormatContext->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO ) #else if ( mFormatContext->streams[i]->codec->codec_type == CODEC_TYPE_VIDEO ) @@ -310,7 +315,7 @@ int FfmpegCamera::OpenFfmpeg() { } if(mAudioStreamId == -1) //FIXME best way to copy all other streams? { -#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(51,2,1) +#if (LIBAVCODEC_VERSION_CHECK(52, 64, 0, 64, 0) || LIBAVUTIL_VERSION_CHECK(50, 14, 0, 14, 0)) if ( mFormatContext->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO ) #else if ( mFormatContext->streams[i]->codec->codec_type == CODEC_TYPE_AUDIO ) @@ -334,7 +339,7 @@ int FfmpegCamera::OpenFfmpeg() { Debug ( 1, "Found decoder" ); // Open the codec -#if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(53, 7, 0) +#if !LIBAVFORMAT_VERSION_CHECK(53, 8, 0, 8, 0) Debug ( 1, "Calling avcodec_open" ); if ( avcodec_open( mCodecContext, mCodec ) < 0 ) #else @@ -346,11 +351,19 @@ int FfmpegCamera::OpenFfmpeg() { Debug ( 1, "Opened codec" ); // Allocate space for the native video frame +#if LIBAVCODEC_VERSION_CHECK(55, 28, 1, 45, 101) + mRawFrame = av_frame_alloc(); +#else mRawFrame = avcodec_alloc_frame(); +#endif // Allocate space for the converted video frame +#if LIBAVCODEC_VERSION_CHECK(55, 28, 1, 45, 101) + mFrame = av_frame_alloc(); +#else mFrame = avcodec_alloc_frame(); - +#endif + if(mRawFrame == NULL || mFrame == NULL) Fatal( "Unable to allocate frame for %s", mPath.c_str() ); @@ -377,11 +390,9 @@ int FfmpegCamera::OpenFfmpeg() { Fatal( "You must compile ffmpeg with the --enable-swscale option to use ffmpeg cameras" ); #endif // HAVE_LIBSWSCALE - Info( "Primed capture from %s, video=%d, audio=%d", mPath.c_str(), mVideoStreamId, mAudioStreamId); + mCanCapture = true; - mCanCapture = true; - - return( 0 ); + return 0; } int FfmpegCamera::ReopenFfmpeg() { @@ -421,7 +432,7 @@ int FfmpegCamera::CloseFfmpeg(){ } if ( mFormatContext ) { -#if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(53, 4, 0) +#if !LIBAVFORMAT_VERSION_CHECK(53, 17, 0, 25, 0) av_close_input_file( mFormatContext ); #else avformat_close_input( &mFormatContext ); @@ -455,7 +466,7 @@ void *FfmpegCamera::ReopenFfmpegThreadCallback(void *ctx){ // Close current stream. camera->CloseFfmpeg(); - // Sleep if neccessary to not reconnect too fast. + // Sleep if necessary to not reconnect too fast. int wait = config.ffmpeg_open_timeout - (time(NULL) - camera->mOpenStart); wait = wait < 0 ? 0 : wait; if (wait > 0){ @@ -481,7 +492,7 @@ int FfmpegCamera::CaptureAndRecord( Image &image, bool recording, char* event_fi void *retval = 0; int ret; - ret = pthread_tryjoin_np(mReopenThread, &retval); + ret = pthread_join(mReopenThread, &retval); if (ret != 0){ Error("Could not join reopen thread."); } @@ -525,7 +536,7 @@ int FfmpegCamera::CaptureAndRecord( Image &image, bool recording, char* event_fi Debug( 5, "Got packet from stream %d", packet.stream_index ); if ( packet.stream_index == mVideoStreamId ) { -#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(52, 25, 0) +#if LIBAVCODEC_VERSION_CHECK(52, 23, 0, 23, 0) if ( avcodec_decode_video2( mCodecContext, mRawFrame, &frameComplete, &packet ) < 0 ) #else if ( avcodec_decode_video( mCodecContext, mRawFrame, &frameComplete, packet.data, packet.size ) < 0 ) diff --git a/src/zm_image.cpp b/src/zm_image.cpp index be5a50ce3..21e190ffb 100644 --- a/src/zm_image.cpp +++ b/src/zm_image.cpp @@ -104,13 +104,13 @@ Image::Image( int p_width, int p_height, int p_colours, int p_subpixelorder, uin pixels = width*height; colours = p_colours; subpixelorder = p_subpixelorder; - size = (width*height)*colours; + size = pixels*colours; buffer = 0; holdbuffer = 0; if ( p_buffer ) { - allocation = size; - buffertype = ZM_BUFTYPE_DONTFREE; + allocation = size; + buffertype = ZM_BUFTYPE_DONTFREE; buffer = p_buffer; } else @@ -129,10 +129,10 @@ Image::Image( const Image &p_image ) pixels = p_image.pixels; colours = p_image.colours; subpixelorder = p_image.subpixelorder; - size = allocation = p_image.size; + size = p_image.size; // allocation is set in AllocImgBuffer buffer = 0; holdbuffer = 0; - AllocImgBuffer(allocation); + AllocImgBuffer(size); (*fptr_imgbufcpy)(buffer, p_image.buffer, size); strncpy( text, p_image.text, sizeof(text) ); } @@ -305,7 +305,7 @@ void Image::Initialise() initialised = true; } -/* Requests a writeable buffer to the image. This is safer than buffer() because this way we can gurantee that a buffer of required size exists */ +/* Requests a writeable buffer to the image. This is safer than buffer() because this way we can guarantee that a buffer of required size exists */ uint8_t* Image::WriteBuffer(const unsigned int p_width, const unsigned int p_height, const unsigned int p_colours, const unsigned int p_subpixelorder) { unsigned int newsize; @@ -331,7 +331,7 @@ uint8_t* Image::WriteBuffer(const unsigned int p_width, const unsigned int p_hei return NULL; } else { /* Replace buffer with a bigger one */ - DumpImgBuffer(); + //DumpImgBuffer(); // Done in AllocImgBuffer too AllocImgBuffer(newsize); } } @@ -369,12 +369,12 @@ void Image::AssignDirect( const unsigned int p_width, const unsigned int p_heigh unsigned int new_buffer_size = ((p_width*p_height)*p_colours); if(buffer_size < new_buffer_size) { - Error("Attempt to directly assign buffer from an undersized buffer of size: %zu, needed %dx%d*%d colours = %zu",buffer_size, p_width, p_height, p_colours ); + Error("Attempt to directly assign buffer from an undersized buffer of size: %zu, needed %dx%d*%d colours = %zu",buffer_size, p_width, p_height, p_colours, new_buffer_size ); return; } if(holdbuffer && buffer) { - if((unsigned int)((p_height*p_width)*p_colours) > allocation) { + if(new_buffer_size > allocation) { Error("Held buffer is undersized for assigned buffer"); return; } else { @@ -482,7 +482,7 @@ void Image::Assign( const Image &image ) { } } else { if(new_size > allocation || !buffer) { - DumpImgBuffer(); + // DumpImgBuffer(); This is also done in AllocImgBuffer AllocImgBuffer(new_size); } } @@ -1580,7 +1580,11 @@ Image *Image::Highlight( unsigned int n_images, Image *images[], const Rgb thres { uint8_t *psrc = images[j]->buffer+c; +#ifndef SOLARIS if ( (unsigned)abs((*psrc)-RGB_VAL(ref_colour,c)) >= RGB_VAL(threshold,c) ) +#else + if ( (unsigned)std::abs((*psrc)-RGB_VAL(ref_colour,c)) >= RGB_VAL(threshold,c) ) +#endif { count++; } @@ -1593,7 +1597,7 @@ Image *Image::Highlight( unsigned int n_images, Image *images[], const Rgb thres return( result ); } -/* New function to allow buffer re-using instead of allocationg memory for the delta image everytime */ +/* New function to allow buffer re-using instead of allocationg memory for the delta image every time */ void Image::Delta( const Image &image, Image* targetimage) const { #ifdef ZM_IMAGE_PROFILING diff --git a/src/zm_image_analyser.h b/src/zm_image_analyser.h index d1d0c1da0..74cc7a73a 100644 --- a/src/zm_image_analyser.h +++ b/src/zm_image_analyser.h @@ -6,7 +6,6 @@ #include #include #include -#include #include #include "zm.h" diff --git a/src/zm_local_camera.cpp b/src/zm_local_camera.cpp index 7b6add421..e2efa3dfb 100644 --- a/src/zm_local_camera.cpp +++ b/src/zm_local_camera.cpp @@ -32,6 +32,13 @@ #include #include +/* Workaround for GNU/kFreeBSD */ +#if defined(__FreeBSD_kernel__) +#ifndef ENODATA +#define ENODATA ENOATTR +#endif +#endif + static unsigned int BigEndian; static int vidioctl( int fd, int request, void *arg ) @@ -255,7 +262,7 @@ static PixelFormat getFfPixFormatFromV4lPalette( int v4l_version, int palette ) #if ZM_HAS_V4L2 static char palette_desc[32]; -/* Automatic format selection prefered formats */ +/* Automatic format selection preferred formats */ static const uint32_t prefered_rgb32_formats[] = {V4L2_PIX_FMT_BGR32, V4L2_PIX_FMT_RGB32, V4L2_PIX_FMT_BGR24, V4L2_PIX_FMT_RGB24, V4L2_PIX_FMT_YUYV, V4L2_PIX_FMT_UYVY, V4L2_PIX_FMT_JPEG, V4L2_PIX_FMT_MJPEG, V4L2_PIX_FMT_YUV422P, V4L2_PIX_FMT_YUV420}; static const uint32_t prefered_rgb24_formats[] = {V4L2_PIX_FMT_BGR24, V4L2_PIX_FMT_RGB24, V4L2_PIX_FMT_YUYV, V4L2_PIX_FMT_UYVY, V4L2_PIX_FMT_JPEG, V4L2_PIX_FMT_MJPEG, V4L2_PIX_FMT_YUV422P, V4L2_PIX_FMT_YUV420}; static const uint32_t prefered_gray8_formats[] = {V4L2_PIX_FMT_GREY, V4L2_PIX_FMT_YUYV, V4L2_PIX_FMT_UYVY, V4L2_PIX_FMT_JPEG, V4L2_PIX_FMT_MJPEG, V4L2_PIX_FMT_YUV422P, V4L2_PIX_FMT_YUV420}; @@ -427,7 +434,7 @@ LocalCamera::LocalCamera( int p_id, const std::string &p_device, int p_channel, Panic("Unexpected colours: %d",colours); } if( capture ) { -#if LIBSWSCALE_VERSION_INT >= AV_VERSION_INT(0, 8, 0) +#if LIBSWSCALE_VERSION_CHECK(0, 8, 0, 8, 0) if(!sws_isSupportedInput(capturePixFormat)) { Error("swscale does not support the used capture format: %c%c%c%c",(capturePixFormat)&0xff,((capturePixFormat>>8)&0xff),((capturePixFormat>>16)&0xff),((capturePixFormat>>24)&0xff)); conversion_type = 2; /* Try ZM format conversions */ @@ -615,7 +622,11 @@ LocalCamera::LocalCamera( int p_id, const std::string &p_device, int p_channel, #if HAVE_LIBSWSCALE /* Initialize swscale stuff */ if(capture && conversion_type == 1) { +#if LIBAVCODEC_VERSION_CHECK(55, 28, 1, 45, 101) + tmpPicture = av_frame_alloc(); +#else tmpPicture = avcodec_alloc_frame(); +#endif if ( !tmpPicture ) Fatal( "Could not allocate temporary picture" ); @@ -845,7 +856,11 @@ void LocalCamera::Initialise() Fatal( "Can't map video buffer %d (%d bytes) to memory: %s(%d)", i, vid_buf.length, strerror(errno), errno ); #if HAVE_LIBSWSCALE +#if LIBAVCODEC_VERSION_CHECK(55, 28, 1, 45, 101) + capturePictures[i] = av_frame_alloc(); +#else capturePictures[i] = avcodec_alloc_frame(); +#endif if ( !capturePictures[i] ) Fatal( "Could not allocate picture" ); avpicture_fill( (AVPicture *)capturePictures[i], (uint8_t*)v4l2_data.buffers[i].start, capturePixFormat, v4l2_data.fmt.fmt.pix.width, v4l2_data.fmt.fmt.pix.height ); @@ -999,7 +1014,11 @@ void LocalCamera::Initialise() v4l1_data.buffers[i].height = height; v4l1_data.buffers[i].format = palette; +#if LIBAVCODEC_VERSION_CHECK(55, 28, 1, 45, 101) + capturePictures[i] = av_frame_alloc(); +#else capturePictures[i] = avcodec_alloc_frame(); +#endif if ( !capturePictures[i] ) Fatal( "Could not allocate picture" ); avpicture_fill( (AVPicture *)capturePictures[i], (unsigned char *)v4l1_data.bufptr+v4l1_data.frames.offsets[i], capturePixFormat, width, height ); diff --git a/src/zm_local_camera.h b/src/zm_local_camera.h index 5e9d4352a..c20118115 100644 --- a/src/zm_local_camera.h +++ b/src/zm_local_camera.h @@ -29,6 +29,9 @@ #ifdef HAVE_LINUX_VIDEODEV_H #include #endif // HAVE_LINUX_VIDEODEV_H +#ifdef HAVE_LIBV4L1_VIDEODEV_H +#include +#endif // HAVE_LIB4VL1_VIDEODEV_H #ifdef HAVE_LINUX_VIDEODEV2_H #include #endif // HAVE_LINUX_VIDEODEV2_H diff --git a/src/zm_logger.cpp b/src/zm_logger.cpp index c64f6e7c0..f6cc9523b 100644 --- a/src/zm_logger.cpp +++ b/src/zm_logger.cpp @@ -31,6 +31,9 @@ #include #include #include +#ifdef __FreeBSD__ +#include +#endif bool Logger::smInitialised = false; Logger *Logger::smInstance = 0; @@ -527,9 +530,25 @@ void Logger::logPrint( bool hex, const char * const file, const int line, const #endif pid_t tid; +#ifdef __FreeBSD__ + long lwpid; + thr_self(&lwpid); + tid = lwpid; + + if (tid < 0 ) // Thread/Process id +#else #ifdef HAVE_SYSCALL + #ifdef __FreeBSD_kernel__ + if ( (syscall(SYS_thr_self, &tid)) < 0 ) // Thread/Process id + + # else + // SOLARIS doesn't have SYS_gettid; don't assume + #ifdef SYS_gettid if ( (tid = syscall(SYS_gettid)) < 0 ) // Thread/Process id + #endif // SYS_gettid + #endif #endif // HAVE_SYSCALL +#endif tid = getpid(); // Process id char *logPtr = logString; diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index 5291e3b72..7fce3b642 100755 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -56,6 +56,11 @@ #include #endif // ZM_MEM_MAPPED +// SOLARIS - we don't have MAP_LOCKED on openSolaris/illumos +#ifndef MAP_LOCKED +#define MAP_LOCKED 0 +#endif + //============================================================================= std::vector split(const std::string &s, char delim) { std::vector elems; @@ -252,7 +257,6 @@ bool Monitor::MonitorLink::hasAlarmed() else if( shared_data->last_event != (unsigned int)last_event ) { last_event = shared_data->last_event; - return( true ); } return( false ); } @@ -442,7 +446,7 @@ Monitor::Monitor( } } - // Will this not happen everytime a monitor is instantiated? Seems like all the calls to the Monitor constructor pass a zero for n_zones, then load zones after.. + // Will this not happen every time a monitor is instantiated? Seems like all the calls to the Monitor constructor pass a zero for n_zones, then load zones after.. if ( !n_zones ) { Debug( 1, "Monitor %s has no zones, adding one.", name ); n_zones = 1; @@ -531,14 +535,18 @@ bool Monitor::connect() { Error( "Got unexpected memory map file size %ld, expected %d", map_stat.st_size, mem_size ); return false; } else { +#ifdef MAP_LOCKED mem_ptr = (unsigned char *)mmap( NULL, mem_size, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_LOCKED, map_fd, 0 ); if ( mem_ptr == MAP_FAILED ) { if ( errno == EAGAIN ) { Debug( 1, "Unable to map file %s (%d bytes) to locked memory, trying unlocked", mem_file, mem_size ); +#endif mem_ptr = (unsigned char *)mmap( NULL, mem_size, PROT_READ|PROT_WRITE, MAP_SHARED, map_fd, 0 ); Debug( 1, "Mapped file %s (%d bytes) to locked memory, unlocked", mem_file, mem_size ); +#ifdef MAP_LOCKED } } +#endif if ( mem_ptr == MAP_FAILED ) Fatal( "Can't map file %s (%d bytes) to memory: %s(%d)", mem_file, mem_size, strerror(errno), errno ); } @@ -3101,7 +3109,7 @@ bool Monitor::closeEvent() * comparing it with ZM_COLOUR_RGB24 or ZM_COLOUR_RGB32 is the way ), and then * manage che check using RGB_VAL_RED() and so on macros instead of just RED(). * - * Be carefull that in 32 bit images we need to check also where the alpha channel is, so, + * Be careful that in 32 bit images we need to check also where the alpha channel is, so, * (RGBA and BGRA) or (ABGR and ARGB) aren't the same! * * To check black pixels in 32 bit images i can do a more efficient way using diff --git a/src/zm_mpeg.cpp b/src/zm_mpeg.cpp index 2e29880ca..eaf0952af 100644 --- a/src/zm_mpeg.cpp +++ b/src/zm_mpeg.cpp @@ -43,12 +43,12 @@ VideoStream::MimeData VideoStream::mime_data[] = { void VideoStream::Initialise( ) { if ( logDebugging() ) - av_log_set_level( AV_LOG_DEBUG ); + av_log_set_level( AV_LOG_DEBUG ); else - av_log_set_level( AV_LOG_QUIET ); - + av_log_set_level( AV_LOG_QUIET ); + av_register_all( ); -#if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(53, 13, 0) +#if LIBAVFORMAT_VERSION_CHECK(53, 13, 0, 19, 0) avformat_network_init(); #endif initialised = true; @@ -58,18 +58,18 @@ void VideoStream::SetupFormat( ) { /* allocate the output media context */ ofc = NULL; -#if ((LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(53, 5, 0)) && (LIBAVFORMAT_VERSION_MICRO >= 100)) +#if (LIBAVFORMAT_VERSION_CHECK(53, 2, 0, 2, 0) && (LIBAVFORMAT_VERSION_MICRO >= 100)) avformat_alloc_output_context2( &ofc, NULL, format, filename ); #else AVFormatContext *s= avformat_alloc_context(); - if(!s) + if(!s) { Fatal( "avformat_alloc_context failed %d \"%s\"", (size_t)ofc, av_err2str((size_t)ofc) ); } - + AVOutputFormat *oformat; if (format) { -#if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(52, 45, 0) +#if LIBAVFORMAT_VERSION_CHECK(52, 45, 0, 45, 0) oformat = av_guess_format(format, NULL, NULL); #else oformat = guess_format(format, NULL, NULL); @@ -78,7 +78,7 @@ void VideoStream::SetupFormat( ) Fatal( "Requested output format '%s' is not a suitable output format", format ); } } else { -#if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(52, 45, 0) +#if LIBAVFORMAT_VERSION_CHECK(52, 45, 0, 45, 0) oformat = av_guess_format(NULL, filename, NULL); #else oformat = guess_format(NULL, filename, NULL); @@ -95,7 +95,7 @@ void VideoStream::SetupFormat( ) { Fatal( "Could not allocate private data for output format." ); } -#if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(52, 92, 0) +#if LIBAVFORMAT_VERSION_CHECK(52, 92, 0, 92, 0) if (s->oformat->priv_class) { *(const AVClass**)s->priv_data = s->oformat->priv_class; av_opt_set_defaults(s->priv_data); @@ -109,7 +109,7 @@ void VideoStream::SetupFormat( ) if(filename) { - snprintf( s->filename, sizeof(s->filename), filename ); + snprintf( s->filename, sizeof(s->filename), "%s", filename ); } ofc = s; @@ -186,7 +186,7 @@ void VideoStream::SetupCodec( int colours, int subpixelorder, int width, int hei } else { -#if ((LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(53, 11, 0)) && (LIBAVFORMAT_VERSION_MICRO >= 100)) +#if (LIBAVFORMAT_VERSION_CHECK(53, 8, 0, 11, 0) && (LIBAVFORMAT_VERSION_MICRO >= 100)) Debug( 1, "Could not find codec \"%s\". Using default \"%s\"", codec_name, avcodec_get_name( codec_id ) ); #else Debug( 1, "Could not find codec \"%s\". Using default \"%d\"", codec_name, codec_id ); @@ -202,20 +202,20 @@ void VideoStream::SetupCodec( int colours, int subpixelorder, int width, int hei codec = avcodec_find_encoder( codec_id ); if ( !codec ) { -#if ((LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(53, 11, 0)) && (LIBAVFORMAT_VERSION_MICRO >= 100)) +#if (LIBAVFORMAT_VERSION_CHECK(53, 8, 0, 11, 0) && (LIBAVFORMAT_VERSION_MICRO >= 100)) Fatal( "Could not find encoder for '%s'", avcodec_get_name( codec_id ) ); #else Fatal( "Could not find encoder for '%d'", codec_id ); #endif } -#if ((LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(53, 11, 0)) && (LIBAVFORMAT_VERSION_MICRO >= 100)) +#if (LIBAVFORMAT_VERSION_CHECK(53, 8, 0, 11, 0) && (LIBAVFORMAT_VERSION_MICRO >= 100)) Debug( 1, "Found encoder for '%s'", avcodec_get_name( codec_id ) ); #else Debug( 1, "Found encoder for '%d'", codec_id ); #endif -#if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(53, 10, 0) +#if LIBAVFORMAT_VERSION_CHECK(53, 10, 0, 17, 0) ost = avformat_new_stream( ofc, codec ); #else ost = av_new_stream( ofc, 0 ); @@ -262,7 +262,7 @@ void VideoStream::SetupCodec( int colours, int subpixelorder, int width, int hei /* emit one intra frame every second */ c->gop_size = frame_rate; - // some formats want stream headers to be seperate + // some formats want stream headers to be separate if ( of->flags & AVFMT_GLOBALHEADER ) c->flags |= CODEC_FLAG_GLOBAL_HEADER; } @@ -311,7 +311,7 @@ void VideoStream::OpenStream( ) AVCodecContext *c = ost->codec; /* open the codec */ -#if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(53, 7, 0) +#if !LIBAVFORMAT_VERSION_CHECK(53, 8, 0, 8, 0) if ( (avRet = avcodec_open( c, codec )) < 0 ) #else if ( (avRet = avcodec_open2( c, codec, 0 )) < 0 ) @@ -323,7 +323,11 @@ void VideoStream::OpenStream( ) Debug( 1, "Opened codec" ); /* allocate the encoded raw picture */ +#if LIBAVCODEC_VERSION_CHECK(55, 28, 1, 45, 101) + opicture = av_frame_alloc( ); +#else opicture = avcodec_alloc_frame( ); +#endif if ( !opicture ) { Panic( "Could not allocate opicture" ); @@ -344,7 +348,11 @@ void VideoStream::OpenStream( ) tmp_opicture = NULL; if ( c->pix_fmt != pf ) { +#if LIBAVCODEC_VERSION_CHECK(55, 28, 1, 45, 101) + tmp_opicture = av_frame_alloc( ); +#else tmp_opicture = avcodec_alloc_frame( ); +#endif if ( !tmp_opicture ) { Panic( "Could not allocate tmp_opicture" ); @@ -364,9 +372,9 @@ void VideoStream::OpenStream( ) if ( !(of->flags & AVFMT_NOFILE) ) { int ret; -#if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(53, 14, 0) +#if LIBAVFORMAT_VERSION_CHECK(53, 15, 0, 21, 0) ret = avio_open2( &ofc->pb, filename, AVIO_FLAG_WRITE, NULL, NULL ); -#elif LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(52, 102, 0) +#elif LIBAVFORMAT_VERSION_CHECK(52, 102, 0, 102, 0) ret = avio_open( &ofc->pb, filename, AVIO_FLAG_WRITE ); #else ret = url_fopen( &ofc->pb, filename, AVIO_FLAG_WRITE ); @@ -395,19 +403,19 @@ void VideoStream::OpenStream( ) Fatal("Unable to malloc memory for outbuf"); } } - -#if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(52, 100, 1) + +#if LIBAVFORMAT_VERSION_CHECK(52, 101, 0, 101, 0) av_dump_format(ofc, 0, filename, 1); #else dump_format(ofc, 0, filename, 1); #endif - -#if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(53, 4, 0) + +#if !LIBAVFORMAT_VERSION_CHECK(53, 2, 0, 4, 0) int ret = av_write_header( ofc ); #else int ret = avformat_write_header( ofc, NULL ); #endif - + if ( ret < 0 ) { Fatal( "?_write_header failed with error %d \"%s\"", ret, av_err2str( ret ) ); @@ -525,7 +533,7 @@ VideoStream::~VideoStream( ) if ( !(of->flags & AVFMT_NOFILE) ) { /* close the output file */ -#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(51,2,1) +#if LIBAVFORMAT_VERSION_CHECK(52, 105, 0, 105, 0) avio_close( ofc->pb ); #else url_fclose( ofc->pb ); @@ -625,7 +633,7 @@ double VideoStream::ActuallyEncodeFrame( const uint8_t *buffer, int buffer_size, int got_packet = 0; if ( of->flags & AVFMT_RAWPICTURE ) { -#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(51, 2, 1) +#if LIBAVCODEC_VERSION_CHECK(52, 30, 2, 30, 2) pkt->flags |= AV_PKT_FLAG_KEY; #else pkt->flags |= PKT_FLAG_KEY; @@ -640,7 +648,7 @@ double VideoStream::ActuallyEncodeFrame( const uint8_t *buffer, int buffer_size, opicture_ptr->pts = c->frame_number; opicture_ptr->quality = c->global_quality; -#if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(54, 0, 0) +#if LIBAVFORMAT_VERSION_CHECK(54, 1, 0, 2, 100) int ret = avcodec_encode_video2( c, pkt, opicture_ptr, &got_packet ); if ( ret != 0 ) { @@ -656,7 +664,7 @@ double VideoStream::ActuallyEncodeFrame( const uint8_t *buffer, int buffer_size, { if ( c->coded_frame->key_frame ) { -#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(51,2,1) +#if LIBAVCODEC_VERSION_CHECK(52, 30, 2, 30, 2) pkt->flags |= AV_PKT_FLAG_KEY; #else pkt->flags |= PKT_FLAG_KEY; diff --git a/src/zm_poly.cpp b/src/zm_poly.cpp index eef5dd56a..4eee73f46 100644 --- a/src/zm_poly.cpp +++ b/src/zm_poly.cpp @@ -20,7 +20,11 @@ #include "zm.h" #include "zm_poly.h" +#ifndef SOLARIS #include +#else +#include +#endif void Polygon::calcArea() { diff --git a/src/zm_remote_camera_http.cpp b/src/zm_remote_camera_http.cpp index fdbfd69a6..c6de64aed 100644 --- a/src/zm_remote_camera_http.cpp +++ b/src/zm_remote_camera_http.cpp @@ -26,6 +26,10 @@ #include #include +#ifdef SOLARIS +#include // FIONREAD and friends +#endif + RemoteCameraHttp::RemoteCameraHttp( int p_id, const std::string &p_method, const std::string &p_host, const std::string &p_port, const std::string &p_path, int p_width, int p_height, int p_colours, int p_brightness, int p_contrast, int p_hue, int p_colour, bool p_capture ) : RemoteCamera( p_id, "http", p_host, p_port, p_path, p_width, p_height, p_colours, p_brightness, p_contrast, p_hue, p_colour, p_capture ) { diff --git a/src/zm_remote_camera_rtsp.cpp b/src/zm_remote_camera_rtsp.cpp index 910b2ac42..9f7b39227 100644 --- a/src/zm_remote_camera_rtsp.cpp +++ b/src/zm_remote_camera_rtsp.cpp @@ -162,7 +162,7 @@ int RemoteCameraRtsp::PrimeCapture() mVideoStreamId = -1; for ( unsigned int i = 0; i < mFormatContext->nb_streams; i++ ) -#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(51,2,1) +#if (LIBAVCODEC_VERSION_CHECK(52, 64, 0, 64, 0) || LIBAVUTIL_VERSION_CHECK(50, 14, 0, 14, 0)) if ( mFormatContext->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO ) #else if ( mFormatContext->streams[i]->codec->codec_type == CODEC_TYPE_VIDEO ) @@ -183,7 +183,7 @@ int RemoteCameraRtsp::PrimeCapture() Panic( "Unable to locate codec %d decoder", mCodecContext->codec_id ); // Open codec -#if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(53, 7, 0) +#if !LIBAVFORMAT_VERSION_CHECK(53, 8, 0, 8, 0) if ( avcodec_open( mCodecContext, mCodec ) < 0 ) #else if ( avcodec_open2( mCodecContext, mCodec, 0 ) < 0 ) @@ -191,11 +191,19 @@ int RemoteCameraRtsp::PrimeCapture() Panic( "Can't open codec" ); // Allocate space for the native video frame +#if LIBAVCODEC_VERSION_CHECK(55, 28, 1, 45, 101) + mRawFrame = av_frame_alloc(); +#else mRawFrame = avcodec_alloc_frame(); +#endif // Allocate space for the converted video frame +#if LIBAVCODEC_VERSION_CHECK(55, 28, 1, 45, 101) + mFrame = av_frame_alloc(); +#else mFrame = avcodec_alloc_frame(); - +#endif + if(mRawFrame == NULL || mFrame == NULL) Fatal( "Unable to allocate frame(s)"); @@ -292,7 +300,7 @@ int RemoteCameraRtsp::Capture( Image &image ) { packet.data = buffer.head(); packet.size = buffer.size(); -#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(52, 25, 0) +#if LIBAVCODEC_VERSION_CHECK(52, 23, 0, 23, 0) int len = avcodec_decode_video2( mCodecContext, mRawFrame, &frameComplete, &packet ); #else int len = avcodec_decode_video( mCodecContext, mRawFrame, &frameComplete, packet.data, packet.size ); diff --git a/src/zm_rtsp.cpp b/src/zm_rtsp.cpp index 76b000c9d..02fdc4e22 100644 --- a/src/zm_rtsp.cpp +++ b/src/zm_rtsp.cpp @@ -211,7 +211,7 @@ RtspThread::~RtspThread() { if ( mFormatContext ) { -#if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(52, 96, 0) +#if LIBAVFORMAT_VERSION_CHECK(52, 96, 0, 96, 0) avformat_free_context( mFormatContext ); #else av_free_format_context( mFormatContext ); @@ -392,7 +392,7 @@ int RtspThread::run() if ( ( lines[i].size() > 13 ) && ( lines[i].substr( 0, 13 ) == "Content-Base:" ) ) { mUrl = trimSpaces( lines[i].substr( 13 ) ); - Info("Recieved new Content-Base in DESCRIBE reponse header. Updated device Url to: '%s'", mUrl.c_str() ); + Info("Received new Content-Base in DESCRIBE response header. Updated device Url to: '%s'", mUrl.c_str() ); break; } } @@ -437,7 +437,7 @@ int RtspThread::run() for ( unsigned int i = 0; i < mFormatContext->nb_streams; i++ ) { SessionDescriptor::MediaDescriptor *mediaDesc = mSessDesc->getStream( i ); -#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(51,2,1) +#if (LIBAVCODEC_VERSION_CHECK(52, 64, 0, 64, 0) || LIBAVUTIL_VERSION_CHECK(50, 14, 0, 14, 0)) if ( mFormatContext->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO ) #else if ( mFormatContext->streams[i]->codec->codec_type == CODEC_TYPE_VIDEO ) diff --git a/src/zm_sdp.cpp b/src/zm_sdp.cpp index 361b58850..dbc63a82f 100644 --- a/src/zm_sdp.cpp +++ b/src/zm_sdp.cpp @@ -23,7 +23,7 @@ #include "zm_sdp.h" -#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(51,2,1) +#if (LIBAVCODEC_VERSION_CHECK(52, 64, 0, 64, 0) || LIBAVUTIL_VERSION_CHECK(50, 14, 0, 14, 0)) SessionDescriptor::StaticPayloadDesc SessionDescriptor::smStaticPayloads[] = { { 0, "PCMU", AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_PCM_MULAW, 8000, 1 }, { 3, "GSM", AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_NONE, 8000, 1 }, @@ -372,7 +372,7 @@ AVFormatContext *SessionDescriptor::generateFormatContext() const for ( unsigned int i = 0; i < mMediaList.size(); i++ ) { const MediaDescriptor *mediaDesc = mMediaList[i]; -#if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(53, 8, 0) +#if !LIBAVFORMAT_VERSION_CHECK(53, 10, 0, 17, 0) AVStream *stream = av_new_stream( formatContext, i ); #else AVStream *stream = avformat_new_stream( formatContext, NULL ); @@ -380,7 +380,7 @@ AVFormatContext *SessionDescriptor::generateFormatContext() const #endif Debug( 1, "Looking for codec for %s payload type %d / %s", mediaDesc->getType().c_str(), mediaDesc->getPayloadType(), mediaDesc->getPayloadDesc().c_str() ); -#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(51,2,1) +#if (LIBAVCODEC_VERSION_CHECK(52, 64, 0, 64, 0) || LIBAVUTIL_VERSION_CHECK(50, 14, 0, 14, 0)) if ( mediaDesc->getType() == "video" ) stream->codec->codec_type = AVMEDIA_TYPE_VIDEO; else if ( mediaDesc->getType() == "audio" ) @@ -396,6 +396,9 @@ AVFormatContext *SessionDescriptor::generateFormatContext() const stream->codec->codec_type = CODEC_TYPE_DATA; #endif +#if LIBAVCODEC_VERSION_CHECK(55, 50, 3, 60, 103) + std::string codec_name; +#endif if ( mediaDesc->getPayloadType() < PAYLOAD_TYPE_DYNAMIC ) { // Look in static table @@ -404,7 +407,11 @@ AVFormatContext *SessionDescriptor::generateFormatContext() const if ( smStaticPayloads[i].payloadType == mediaDesc->getPayloadType() ) { Debug( 1, "Got static payload type %d, %s", smStaticPayloads[i].payloadType, smStaticPayloads[i].payloadName ); +#if LIBAVCODEC_VERSION_CHECK(55, 50, 3, 60, 103) + codec_name = std::string( smStaticPayloads[i].payloadName ); +#else strncpy( stream->codec->codec_name, smStaticPayloads[i].payloadName, sizeof(stream->codec->codec_name) );; +#endif stream->codec->codec_type = smStaticPayloads[i].codecType; stream->codec->codec_id = smStaticPayloads[i].codecId; stream->codec->sample_rate = smStaticPayloads[i].clockRate; @@ -420,7 +427,11 @@ AVFormatContext *SessionDescriptor::generateFormatContext() const if ( smDynamicPayloads[i].payloadName == mediaDesc->getPayloadDesc() ) { Debug( 1, "Got dynamic payload type %d, %s", mediaDesc->getPayloadType(), smDynamicPayloads[i].payloadName ); +#if LIBAVCODEC_VERSION_CHECK(55, 50, 3, 60, 103) + codec_name = std::string( smStaticPayloads[i].payloadName ); +#else strncpy( stream->codec->codec_name, smDynamicPayloads[i].payloadName, sizeof(stream->codec->codec_name) );; +#endif stream->codec->codec_type = smDynamicPayloads[i].codecType; stream->codec->codec_id = smDynamicPayloads[i].codecId; stream->codec->sample_rate = mediaDesc->getClock(); @@ -428,7 +439,12 @@ AVFormatContext *SessionDescriptor::generateFormatContext() const } } } + +#if LIBAVCODEC_VERSION_CHECK(55, 50, 3, 60, 103) + if ( codec_name.empty() ) +#else if ( !stream->codec->codec_name[0] ) +#endif { Warning( "Can't find payload details for %s payload type %d, name %s", mediaDesc->getType().c_str(), mediaDesc->getPayloadType(), mediaDesc->getPayloadDesc().c_str() ); //return( 0 ); diff --git a/src/zm_sdp.h b/src/zm_sdp.h index fb56a2886..21eb227c1 100644 --- a/src/zm_sdp.h +++ b/src/zm_sdp.h @@ -40,7 +40,7 @@ protected: { int payloadType; const char payloadName[6]; -#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(52, 64, 0) +#if (LIBAVCODEC_VERSION_CHECK(52, 64, 0, 64, 0) || LIBAVUTIL_VERSION_CHECK(50, 14, 0, 14, 0)) AVMediaType codecType; #else enum CodecType codecType; @@ -53,7 +53,7 @@ protected: struct DynamicPayloadDesc { const char payloadName[32]; -#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(52, 64, 0) +#if (LIBAVCODEC_VERSION_CHECK(52, 64, 0, 64, 0) || LIBAVUTIL_VERSION_CHECK(50, 14, 0, 14, 0)) AVMediaType codecType; #else enum CodecType codecType; diff --git a/src/zm_sendfile.h b/src/zm_sendfile.h new file mode 100644 index 000000000..ce3405d66 --- /dev/null +++ b/src/zm_sendfile.h @@ -0,0 +1,31 @@ +#ifdef HAVE_SENDFILE4_SUPPORT +#include +int zm_sendfile(int out_fd, int in_fd, off_t *offset, size_t size) { + int err; + + err = sendfile(out_fd, in_fd, offset, size); + if (err < 0) + return -errno; + + return err; +} +#elif HAVE_SENDFILE7_SUPPORT +#include +#include +#include +int zm_sendfile(int out_fd, int in_fd, off_t *offset, off_t size) { + int err; + err = sendfile(in_fd, out_fd, *offset, size, NULL, &size, 0); + if (err && errno != EAGAIN) + return -errno; + + if (size) { + *offset += size; + return size; + } + + return -EAGAIN; +} +#else +#error "Your platform does not support sendfile. Sorry." +#endif diff --git a/src/zm_signal.cpp b/src/zm_signal.cpp index 6db4697ed..91e1bc4ba 100644 --- a/src/zm_signal.cpp +++ b/src/zm_signal.cpp @@ -64,12 +64,19 @@ RETSIGTYPE zm_die_handler(int signal) info->si_uid, info->si_status); ucontext_t *uc = (ucontext_t *) context; + cr2 = info->si_addr; #if defined(__x86_64__) - cr2 = info->si_addr; + #ifdef __FreeBSD_kernel__ + ip = (void *)(uc->uc_mcontext.mc_rip); + #else ip = (void *)(uc->uc_mcontext.gregs[REG_RIP]); + #endif #else - cr2 = info->si_addr; + #ifdef __FreeBSD_kernel__ + ip = (void *)(uc->uc_mcontext.mc_eip); + #else ip = (void *)(uc->uc_mcontext.gregs[REG_EIP]); + #endif #endif // defined(__x86_64__) // Print the signal address and instruction pointer if available diff --git a/src/zm_thread.h b/src/zm_thread.h index 6a0d169f0..615bec6aa 100644 --- a/src/zm_thread.h +++ b/src/zm_thread.h @@ -28,12 +28,34 @@ #endif // HAVE_SYS_SYSCALL_H #include "zm_exception.h" #include "zm_utils.h" +#ifdef __FreeBSD__ +#include +#endif class ThreadException : public Exception { +private: +#ifndef SOLARIS +pid_t pid() { + pid_t tid; +#ifdef __FreeBSD__ + long lwpid; + thr_self(&lwpid); + tid = lwpid; +#else + #ifdef __FreeBSD_kernel__ + if ( (syscall(SYS_thr_self, &tid)) < 0 ) // Thread/Process id + # else + tid=syscall(SYS_gettid); + #endif +#endif + return tid; +} +#else +pthread_t pid() { return( pthread_self() ); } +#endif public: - ThreadException( const std::string &message ) : Exception( stringtf( "(%d) "+message, (long int)syscall(SYS_gettid) ) ) - { + ThreadException( const std::string &message ) : Exception( stringtf( "(%d) "+message, (long int)pid() ) ) { } }; @@ -195,7 +217,11 @@ protected: Mutex mThreadMutex; Condition mThreadCondition; +#ifndef SOLARIS pid_t mPid; +#else + pthread_t mPid; +#endif bool mStarted; bool mRunning; @@ -203,10 +229,30 @@ protected: Thread(); virtual ~Thread(); +#ifndef SOLARIS pid_t id() const { - return( (pid_t)syscall(SYS_gettid) ); + pid_t tid; +#ifdef __FreeBSD__ + long lwpid; + thr_self(&lwpid); + tid = lwpid; +#else + #ifdef __FreeBSD_kernel__ + if ( (syscall(SYS_thr_self, &tid)) < 0 ) // Thread/Process id + + #else + tid=syscall(SYS_gettid); + #endif +#endif +return tid; } +#else + pthread_t id() const + { + return( pthread_self() ); + } +#endif void exit( int status = 0 ) { //INFO( "Exiting" ); diff --git a/src/zm_timer.h b/src/zm_timer.h index 6c7663b87..7afe0a647 100644 --- a/src/zm_timer.h +++ b/src/zm_timer.h @@ -32,8 +32,28 @@ class Timer private: class TimerException : public Exception { + private: +#ifndef SOLARIS + pid_t pid() { + pid_t tid; +#ifdef __FreeBSD__ + long lwpid; + thr_self(&lwpid); + tid = lwpid; +#else + #ifdef __FreeBSD_kernel__ + if ( (syscall(SYS_thr_self, &tid)) < 0 ) // Thread/Process id + #else + tid=syscall(SYS_gettid); + #endif +#endif + return tid; + } +#else + pthread_t pid() { return( pthread_self() ); } +#endif public: - TimerException( const std::string &message ) : Exception( stringtf( "(%d) "+message, (long int)syscall(SYS_gettid) ) ) + TimerException( const std::string &message ) : Exception( stringtf( "(%d) "+message, (long int)pid() ) ) { } }; diff --git a/src/zma.cpp b/src/zma.cpp index cb6ddb4e8..e45327cc1 100644 --- a/src/zma.cpp +++ b/src/zma.cpp @@ -70,7 +70,7 @@ int main( int argc, char *argv[] ) Usage(); break; case 'v': - cout << ZM_VERSION << "\n"; + std::cout << ZM_VERSION << "\n"; exit(0); default: //fprintf( stderr, "?? getopt returned character code 0%o ??\n", c ); diff --git a/src/zmc.cpp b/src/zmc.cpp index 397468140..5be5ed8af 100644 --- a/src/zmc.cpp +++ b/src/zmc.cpp @@ -19,12 +19,16 @@ #include #include -#if defined(BSD) +#if defined(__FreeBSD__) #include #else #include #endif +#if !defined(MAXINT) +#define MAXINT INT_MAX +#endif + #include "zm.h" #include "zm_db.h" #include "zm_time.h" @@ -111,7 +115,7 @@ int main( int argc, char *argv[] ) Usage(); break; case 'v': - cout << ZM_VERSION << "\n"; + std::cout << ZM_VERSION << "\n"; exit(0); default: //fprintf( stderr, "?? getopt returned character code 0%o ??\n", c ); @@ -270,21 +274,21 @@ int main( int argc, char *argv[] ) { if ( monitors[i]->PreCapture() < 0 ) { - Error( "Failed to pre-capture monitor %d (%d/%d)", monitors[i]->Id(), i, n_monitors ); + Error( "Failed to pre-capture monitor %d %d (%d/%d)", monitors[i]->Id(), monitors[i]->Name(), i+1, n_monitors ); zm_terminate = true; result = -1; break; } if ( monitors[i]->Capture() < 0 ) { - Error( "Failed to capture image from monitor %d (%d/%d)", monitors[i]->Id(), i, n_monitors ); + Error( "Failed to capture image from monitor %d %s (%d/%d)", monitors[i]->Id(), monitors[i]->Name(), i+1, n_monitors ); zm_terminate = true; result = -1; break; } if ( monitors[i]->PostCapture() < 0 ) { - Error( "Failed to post-capture monitor %d (%d/%d)", monitors[i]->Id(), i, n_monitors ); + Error( "Failed to post-capture monitor %d %s (%d/%d)", monitors[i]->Id(), monitors[i]->Name(), i+1, n_monitors ); zm_terminate = true; result = -1; break; diff --git a/src/zmf.cpp b/src/zmf.cpp index d97a9e5d5..94bd0bdb5 100644 --- a/src/zmf.cpp +++ b/src/zmf.cpp @@ -138,7 +138,7 @@ int main( int argc, char *argv[] ) Usage(); break; case 'v': - cout << ZM_VERSION << "\n"; + std::cout << ZM_VERSION << "\n"; exit(0); default: //fprintf( stderr, "?? getopt returned character code 0%o ??\n", c ); diff --git a/src/zmstreamer.cpp b/src/zmstreamer.cpp index 5c11cfbea..7385accca 100644 --- a/src/zmstreamer.cpp +++ b/src/zmstreamer.cpp @@ -102,7 +102,7 @@ int main(int argc, char** argv) { printf("-v : This installed version of ZoneMinder\n"); return EXIT_SUCCESS; case 'v': - cout << ZM_VERSION << "\n"; + std::cout << ZM_VERSION << "\n"; exit(0); } } diff --git a/web/ajax/event.php b/web/ajax/event.php index d5cc2b09d..1953acab0 100644 --- a/web/ajax/event.php +++ b/web/ajax/event.php @@ -1,4 +1,6 @@ - '.$SLANG['ZoneMinderLog'].' + '.translate('ZoneMinderLog').' -

'.$SLANG['ZoneMinderLog'].'

+

'.translate('ZoneMinderLog').'

'.htmlspecialchars(preg_match( '/%/', DATE_FMT_CONSOLE_LONG )?strftime( DATE_FMT_CONSOLE_LONG ):date( DATE_FMT_CONSOLE_LONG )).'

-

'.count($logs).' '.$SLANG['Logs'].'

+

'.count($logs).' '.translate('Logs').'

- + ' ); foreach ( $logs as $log ) { @@ -288,7 +288,7 @@ tr.log-dbg td { { fwrite( $exportFP, ' - + '.$_POST['selector'].'' ); foreach ( $filter as $field=>$value ) if ( $value != '' ) @@ -298,7 +298,7 @@ tr.log-dbg td { ' ); fwrite( $exportFP, ' - '.$SLANG['DateTime'].''.$SLANG['Component'].''.$SLANG['Pid'].''.$SLANG['Level'].''.$SLANG['Message'].''.$SLANG['File'].''.$SLANG['Line'].' + '.translate('DateTime').''.translate('Component').''.translate('Pid').''.translate('Level').''.translate('Message').''.translate('File').''.translate('Line').' ' ); diff --git a/web/ajax/status.php b/web/ajax/status.php index bd334ead0..4d4ad8345 100644 --- a/web/ajax/status.php +++ b/web/ajax/status.php @@ -8,7 +8,7 @@ $statusData = array( "elements" => array( "MonitorCount" => array( "sql" => "count(*)" ), "ActiveMonitorCount" => array( "sql" => "count(if(Function != 'None',1,NULL))" ), - "State" => array( "func" => "daemonCheck()?".$SLANG['Running'].":".$SLANG['Stopped'] ), + "State" => array( "func" => "daemonCheck()?".translate('Running').":".translate('Stopped') ), "Load" => array( "func" => "getLoad()" ), "Disk" => array( "func" => "getDiskPercent()" ), ), diff --git a/web/includes/lang.php b/web/includes/lang.php index 94ebba530..30af6f4c0 100644 --- a/web/includes/lang.php +++ b/web/includes/lang.php @@ -18,6 +18,15 @@ // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // +function translate( $name ) +{ + global $SLANG; + if ( array_key_exists( $name, $SLANG ) ) + return $SLANG[$name]; + else + return $name; +} + function loadLanguage( $prefix="" ) { global $user; diff --git a/web/index.php b/web/index.php index 9303a26c8..6167dc4dc 100644 --- a/web/index.php +++ b/web/index.php @@ -63,30 +63,30 @@ if ( isset($_GET['skin']) ) $skin = $_GET['skin']; elseif ( isset($_COOKIE['zmSkin']) ) $skin = $_COOKIE['zmSkin']; -elseif ( defined(ZM_SKIN_DEFAULT) ) +elseif ( defined('ZM_SKIN_DEFAULT') ) $skin = ZM_SKIN_DEFAULT; else $skin = "classic"; $skins = array_map( 'basename', glob('skins/*',GLOB_ONLYDIR) ); if ( ! in_array( $skin, $skins ) ) { - Error( "Invalid skin '$skin'" ); - $skin = 'classic'; + Error( "Invalid skin '$skin' setting to " . $skins[0] ); + $skin = $skins[0]; } if ( isset($_GET['css']) ) $css = $_GET['css']; elseif ( isset($_COOKIE['zmCSS']) ) $css = $_COOKIE['zmCSS']; -elseif (defined(ZM_CSS_DEFAULT)) +elseif (defined('ZM_CSS_DEFAULT')) $css = ZM_CSS_DEFAULT; else $css = "classic"; $css_skins = array_map( 'basename', glob('skins/'.$skin.'/css/*',GLOB_ONLYDIR) ); if ( ! in_array( $css, $css_skins ) ) { - Error( "Invalid skin css '$css'" ); - $css = 'classic'; + Error( "Invalid skin css '$css' setting to " . $css_skins[0] ); + $css = $css_skins[0]; } define( "ZM_BASE_PATH", dirname( $_SERVER['REQUEST_URI'] ) ); @@ -102,13 +102,13 @@ ini_set( "session.name", "ZMSESSID" ); session_start(); -if ( !isset($_SESSION['skin']) || isset($_REQUEST['skin']) ) +if ( !isset($_SESSION['skin']) || isset($_REQUEST['skin']) || !isset($_COOKIE['zmSkin']) || $_COOKIE['zmSkin'] != $skin ) { $_SESSION['skin'] = $skin; setcookie( "zmSkin", $skin, time()+3600*24*30*12*10 ); } -if ( !isset($_SESSION['css']) || isset($_REQUEST['css']) ) { +if ( !isset($_SESSION['css']) || isset($_REQUEST['css']) || !isset($_COOKIE['zmCSS']) || $_COOKIE['zmCSS'] != $css ) { $_SESSION['css'] = $css; setcookie( "zmCSS", $css, time()+3600*24*30*12*10 ); } @@ -143,6 +143,10 @@ if ( ZM_OPT_USE_AUTH && ! isset($user) && $view != 'login' ) { $view = 'login'; } +# Only one request can open the session file at a time, so let's close the session here to improve concurrency. +# Any file/page that uses the session must re-open it. +session_write_close(); + if ( isset( $_REQUEST['request'] ) ) { foreach ( getSkinIncludes( 'ajax/'.$request.'.php', true, true ) as $includeFile ) diff --git a/web/lang/big5_big5.php b/web/lang/big5_big5.php index f218109c1..84da0f622 100644 --- a/web/lang/big5_big5.php +++ b/web/lang/big5_big5.php @@ -92,6 +92,7 @@ $SLANG = array( 'AlarmMaximumFPS' => 'Alarm Maximum FPS', 'AlarmPx' => 'Alarm Px', 'AlarmRGBUnset' => 'You must set an alarm RGB colour', + 'AlarmRefImageBlendPct'=> 'Alarm Reference Image Blend %ge', // Added - 2015-04-18 'Alert' => '警告', 'All' => '全部', 'Apply' => '確定', @@ -136,13 +137,13 @@ $SLANG = array( 'BadFPSReportInterval' => 'FPS report interval buffer count must be an integer of 0 or more', 'BadFormat' => 'Format must be set to an integer of zero or more', 'BadFrameSkip' => 'Frame skip count must be an integer of zero or more', - 'BadMotionFrameSkip' => 'Motion Frame skip count must be an integer of zero or more', 'BadHeight' => 'Height must be set to a valid value', 'BadHost' => 'Host must be set to a valid ip address or hostname, do not include http://', 'BadImageBufferCount' => 'Image buffer size must be an integer of 10 or more', 'BadLabelX' => 'Label X co-ordinate must be set to an integer of zero or more', 'BadLabelY' => 'Label Y co-ordinate must be set to an integer of zero or more', 'BadMaxFPS' => 'Maximum FPS must be a positive integer or floating point value', + 'BadMotionFrameSkip' => 'Motion Frame skip count must be an integer of zero or more', 'BadNameChars' => 'Names may only contain alphanumeric characters plus hyphen and underscore', 'BadPalette' => 'Palette must be set to a valid value', // Added - 2009-03-31 'BadPath' => 'Path must be set to a valid value', @@ -162,7 +163,9 @@ $SLANG = array( 'BlobSizes' => 'Blob Sizes', 'Blobs' => 'Blobs', 'Brightness' => '亮度', + 'Buffer' => 'Buffer', // Added - 2015-04-18 'Buffers' => '緩衝', + 'CSSDescription' => 'Change the default css for this computer', // Added - 2015-04-18 'CanAutoFocus' => 'Can Auto Focus', 'CanAutoGain' => 'Can Auto Gain', 'CanAutoIris' => 'Can Auto Iris', @@ -206,6 +209,7 @@ $SLANG = array( 'CaptureHeight' => '捕捉高度', 'CaptureMethod' => 'Capture Method', // Added - 2009-02-08 'CapturePalette' => '捕捉格式', + 'CaptureResolution' => 'Capture Resolution', // Added - 2015-04-18 'CaptureWidth' => '捕捉寬度', 'Cause' => '因素', 'CheckMethod' => 'Alarm Check Method', @@ -236,6 +240,7 @@ $SLANG = array( 'ControlDevice' => 'Control Device', 'ControlType' => 'Control Type', 'Controllable' => 'Controllable', + 'Current' => 'Current', // Added - 2015-04-18 'Cycle' => '分區輪流檢視', 'CycleWatch' => '分區輪流檢視', 'DateTime' => 'Date/Time', // Added - 2011-06-16 @@ -244,12 +249,15 @@ $SLANG = array( 'DefaultRate' => '預設速率', 'DefaultScale' => '預設尺寸', 'DefaultView' => 'Default View', + 'Deinterlacing' => 'Deinterlacing', // Added - 2015-04-18 + 'Delay' => 'Delay', // Added - 2015-04-18 'Delete' => '刪除', 'DeleteAndNext' => '刪除 & 下一事件', 'DeleteAndPrev' => '刪除 & 上一事件', 'DeleteSavedFilter' => '刪除儲存過濾', 'Description' => '描述', 'DetectedCameras' => 'Detected Cameras', // Added - 2009-03-31 + 'DetectedProfiles' => 'Detected Profiles', // Added - 2015-04-18 'Device' => 'Device', // Added - 2009-02-08 'DeviceChannel' => '裝置通道', 'DeviceFormat' => '裝置格式', @@ -261,6 +269,7 @@ $SLANG = array( 'Disk' => '磁碟', 'Display' => 'Display', // Added - 2011-01-30 'Displaying' => 'Displaying', // Added - 2011-06-16 + 'DoNativeMotionDetection'=> 'Do Native Motion Detection', 'Donate' => 'Please Donate', 'DonateAlready' => 'No, I\'ve already donated', 'DonateEnticement' => 'You\'ve been running ZoneMinder for a while now and hopefully are finding it a useful addition to your home or workplace security. Although ZoneMinder is, and will remain, free and open source, it costs money to develop and support. If you would like to help support future development and new features then please consider donating. Donating is, of course, optional but very much appreciated and you can donate as much or as little as you like.

If you would like to donate please select the option below or go to http://www.zoneminder.com/donate.html in your browser.

Thank you for using ZoneMinder and don\'t forget to visit the forums on ZoneMinder.com for support or suggestions about how to make your ZoneMinder experience even better.', @@ -270,7 +279,6 @@ $SLANG = array( 'DonateRemindNever' => 'No, I don\'t want to donate, never remind', 'DonateRemindWeek' => 'Not yet, remind again in 1 week', 'DonateYes' => 'Yes, I\'d like to donate now', - 'DoNativeMotionDetection'=> 'Do Native Motion Detection', 'Download' => '下載', 'DuplicateMonitorName' => 'Duplicate Monitor Name', // Added - 2009-03-31 'Duration' => '歷時', @@ -313,10 +321,12 @@ $SLANG = array( 'Feed' => 'Feed', 'Ffmpeg' => 'Ffmpeg', // Added - 2009-02-08 'File' => 'File', + 'Filter' => 'Filter', // Added - 2015-04-18 'FilterArchiveEvents' => '自動儲存符合項目', 'FilterDeleteEvents' => '自動刪除符合項目', 'FilterEmailEvents' => '自動寄出詳細符合項目', 'FilterExecuteEvents' => '自動執行符合指令', + 'FilterLog' => 'Filter log', // Added - 2015-04-18 'FilterMessageEvents' => '自動發出符合訊息', 'FilterPx' => 'Filter Px', 'FilterUnset' => '您必需設定濾鏡的寬度和高度', @@ -326,12 +336,12 @@ $SLANG = array( 'First' => 'First', 'FlippedHori' => '水平反轉', 'FlippedVert' => '垂直反轉', - 'FnNone' => 'None', // Added 2013.08.16. - 'FnMonitor' => 'Monitor', // Added 2013.08.16. - 'FnModect' => 'Modect', // Added 2013.08.16. - 'FnRecord' => 'Record', // Added 2013.08.16. 'FnMocord' => 'Mocord', // Added 2013.08.16. + 'FnModect' => 'Modect', // Added 2013.08.16. + 'FnMonitor' => 'Monitor', // Added 2013.08.16. 'FnNodect' => 'Nodect', // Added 2013.08.16. + 'FnNone' => 'None', // Added 2013.08.16. + 'FnRecord' => 'Record', // Added 2013.08.16. 'Focus' => 'Focus', 'ForceAlarm' => 'Force Alarm', 'Format' => '格式', @@ -339,7 +349,6 @@ $SLANG = array( 'FrameId' => '框架 Id', 'FrameRate' => '框架速率', 'FrameSkip' => '框架忽略', - 'MotionFrameSkip' => 'Motion Frame Skip', 'Frames' => '框架', 'Func' => 'Func', 'Function' => '功能', @@ -466,6 +475,7 @@ $SLANG = array( 'MinZoomSpeed' => 'Min Zoom Speed', 'MinZoomStep' => 'Min Zoom Step', 'Misc' => '細項', + 'Mode' => 'Mode', // Added - 2015-04-18 'Monitor' => '監視', 'MonitorIds' => 'Monitor Ids', 'MonitorPreset' => 'Monitor Preset', @@ -476,12 +486,13 @@ $SLANG = array( 'Montage' => '全部顯示', 'Month' => '月', 'More' => 'More', // Added - 2011-06-16 + 'MotionFrameSkip' => 'Motion Frame Skip', 'Move' => '移動', - 'MtgDefault' => 'Default', // Added 2013.08.15. 'Mtg2widgrd' => '2-wide grid', // Added 2013.08.15. 'Mtg3widgrd' => '3-wide grid', // Added 2013.08.15. - 'Mtg4widgrd' => '4-wide grid', // Added 2013.08.15. 'Mtg3widgrx' => '3-wide grid, scaled, enlarge on alarm', // Added 2013.08.15. + 'Mtg4widgrd' => '4-wide grid', // Added 2013.08.15. + 'MtgDefault' => 'Default', // Added 2013.08.15. 'MustBeGe' => '需大於或等於', 'MustBeLe' => '需小於或等於', 'MustConfirmPassword' => '您必需確認密碼', @@ -510,6 +521,9 @@ $SLANG = array( 'NumPresets' => 'Num Presets', 'Off' => 'Off', 'On' => 'On', + 'OnvifCredentialsIntro'=> 'Please supply user name and password for the selected camera.
If no user has been created for the camera then the user given here will be created with the given password.

', // Added - 2015-04-18 + 'OnvifProbe' => 'ONVIF', // Added - 2015-04-18 + 'OnvifProbeIntro' => 'The list below shows detected ONVIF cameras and whether they are already being used or available for selection.

Select the desired entry from the list below.

Please note that not all cameras may be detected and that choosing a camera here may overwrite any values you already have configured for the current monitor.

', // Added - 2015-04-18 'OpEq' => 'equal to', 'OpGt' => 'greater than', 'OpGtEq' => 'greater than or equal to', @@ -556,6 +570,9 @@ $SLANG = array( 'Presets' => 'Presets', 'Prev' => '上一事件', 'Probe' => 'Probe', // Added - 2009-03-31 + 'ProfileProbe' => 'Stream Probe', // Added - 2015-04-18 + 'ProfileProbeIntro' => 'The list below shows the existing stream profiles of the selected camera .

Select the desired entry from the list below.

Please note that ZoneMinder cannot configure additional profiles and that choosing a camera here may overwrite any values you already have configured for the current monitor.

', // Added - 2015-04-18 + 'Progress' => 'Progress', // Added - 2015-04-18 'Protocol' => 'Protocol', 'Rate' => 'Rate', 'Real' => 'Real', @@ -643,6 +660,7 @@ $SLANG = array( 'Submit' => 'Submit', 'System' => 'System', 'SystemLog' => 'System Log', // Added - 2011-06-16 + 'TargetColorspace' => 'Target colorspace', // Added - 2015-04-18 'Tele' => 'Tele', 'Thumbnail' => '小圖檢視', 'Tilt' => 'Tilt', @@ -677,13 +695,16 @@ $SLANG = array( 'UpdateNotNecessary' => 'No update is necessary.', 'Updated' => 'Updated', // Added - 2011-06-16 'Upload' => 'Upload', // Added - 2011-08-23 - 'UsedPlugins' => 'Used Plugins', 'UseFilter' => 'Use Filter', 'UseFilterExprsPost' => ' filter expressions', // This is used at the end of the phrase 'use N filter expressions' 'UseFilterExprsPre' => 'Use ', // This is used at the beginning of the phrase 'use N filter expressions' + 'UsedPlugins' => 'Used Plugins', 'User' => 'User', 'Username' => '使用者名稱', 'Users' => 'Users', + 'V4L' => 'V4L', // Added - 2015-04-18 + 'V4LCapturesPerFrame' => 'Captures Per Frame', // Added - 2015-04-18 + 'V4LMultiBuffer' => 'Multi Buffering', // Added - 2015-04-18 'Value' => '設定值', 'Version' => '版本', 'VersionIgnore' => 'Ignore this version', @@ -723,6 +744,7 @@ $SLANG = array( 'Zone' => 'Zone', 'ZoneAlarmColour' => 'Alarm Colour (RGB)', 'ZoneArea' => 'Zone Area', + 'ZoneExtendAlarmFrames' => 'Extend Alarm Frame Count', 'ZoneFilterSize' => 'Filter Width/Height (pixels)', 'ZoneMinMaxAlarmArea' => 'Min/Max Alarmed Area', 'ZoneMinMaxBlobArea' => 'Min/Max Blob Area', @@ -731,7 +753,6 @@ $SLANG = array( 'ZoneMinMaxPixelThres' => 'Min/Max Pixel Threshold (0-255)', 'ZoneMinderLog' => 'ZoneMinder Log', // Added - 2011-06-17 'ZoneOverloadFrames' => 'Overload Frame Ignore Count', - 'ZoneExtendAlarmFrames' => 'Extend Alarm Frame Count', 'Zones' => '監視區', 'Zoom' => 'Zoom', 'ZoomIn' => 'Zoom In', // Added - 2009-02-08 diff --git a/web/lang/cn_zh.php b/web/lang/cn_zh.php index b0b76ba93..21bd2f269 100644 --- a/web/lang/cn_zh.php +++ b/web/lang/cn_zh.php @@ -88,6 +88,7 @@ $SLANG = array( 'AlarmMaximumFPS' => '报警最大帧率FPS', 'AlarmPx' => '报警像素', 'AlarmRGBUnset' => '你必须设置一个报警颜色(RGB)', + 'AlarmRefImageBlendPct'=> 'Alarm Reference Image Blend %ge', // Added - 2015-04-18 'Alert' => '警报', 'All' => '全部', 'Apply' => '应用', @@ -132,13 +133,13 @@ $SLANG = array( 'BadFPSReportInterval' => 'FPS帧数报告间隔缓冲数必须是0以上整数', 'BadFormat' => '格式必须设为大于零的整数', 'BadFrameSkip' => '跳帧数必须设为大于零的整数', - 'BadMotionFrameSkip' => 'Motion Frame skip count must be an integer of zero or more', 'BadHeight' => '高度必须设为有效值', 'BadHost' => '主机必须设为有效IP地址或主机名,不要包含 http://', 'BadImageBufferCount' => '图像缓冲器大小必须设为大于10的整数', 'BadLabelX' => '标签 X 坐标必须设为大于零的整数', 'BadLabelY' => '标签 Y 坐标必须设为大于零的整数', 'BadMaxFPS' => '最大帧数FPS必须设为正整数或着浮点数', + 'BadMotionFrameSkip' => 'Motion Frame skip count must be an integer of zero or more', 'BadNameChars' => '名称只可以包含字母,数字,波折号和下划线', 'BadPalette' => 'Palette must be set to a valid value', // Added - 2009-03-31 'BadPath' => '路径必须设为有效值', @@ -158,7 +159,9 @@ $SLANG = array( 'BlobSizes' => 'Blob大小', 'Blobs' => 'Blobs', 'Brightness' => '亮度', + 'Buffer' => 'Buffer', // Added - 2015-04-18 'Buffers' => '缓冲器', + 'CSSDescription' => 'Change the default css for this computer', // Added - 2015-04-18 'CanAutoFocus' => '可以自动对焦', 'CanAutoGain' => '可以自动增益控制', 'CanAutoIris' => '可以自动光圈', @@ -202,6 +205,7 @@ $SLANG = array( 'CaptureHeight' => '捕获高度', 'CaptureMethod' => '捕获方式', 'CapturePalette' => '捕获调色板', + 'CaptureResolution' => 'Capture Resolution', // Added - 2015-04-18 'CaptureWidth' => '捕获宽度', 'Cause' => '原因', 'CheckMethod' => '报警检查方式', @@ -232,6 +236,7 @@ $SLANG = array( 'ControlDevice' => '控制设备', 'ControlType' => '控制类型', 'Controllable' => '可控', + 'Current' => 'Current', // Added - 2015-04-18 'Cycle' => '循环', 'CycleWatch' => '循环监视', 'DateTime' => 'Date/Time', // Added - 2011-06-16 @@ -240,12 +245,15 @@ $SLANG = array( 'DefaultRate' => '缺省速率', 'DefaultScale' => '缺省缩放', 'DefaultView' => '缺省视角', + 'Deinterlacing' => 'Deinterlacing', // Added - 2015-04-18 + 'Delay' => 'Delay', // Added - 2015-04-18 'Delete' => '删除', 'DeleteAndNext' => '删除并下一个', 'DeleteAndPrev' => '删除并前一个', 'DeleteSavedFilter' => '删除存储过滤器', 'Description' => '描述', 'DetectedCameras' => 'Detected Cameras', // Added - 2009-03-31 + 'DetectedProfiles' => 'Detected Profiles', // Added - 2015-04-18 'Device' => '设备', 'DeviceChannel' => '设备通道', 'DeviceFormat' => '设备格式', @@ -257,6 +265,7 @@ $SLANG = array( 'Disk' => '磁碟', 'Display' => 'Display', // Added - 2011-01-30 'Displaying' => 'Displaying', // Added - 2011-06-16 + 'DoNativeMotionDetection'=> 'Do Native Motion Detection', 'Donate' => '请捐款', 'DonateAlready' => '不,我已经捐赠过了', 'DonateEnticement' => '迄今,您已经运行ZoneMinder有一阵子了,希望它能够有助于增强您家或者办公区域的安全。尽管ZoneMinder是,并将保持免费和开源,该项目依然在研发和支持中投入了资金和精力。如果您愿意支持今后的开发和新功能,那么请考虑为该项目捐款。捐款不是必须的,任何数量的捐赠,我们都很感谢。

如果您愿意捐款,请选择下列选项,或者访问 http://www.zoneminder.com/donate.html 捐赠主页。

感谢您使用ZoneMinder,并且不要忘记访问访问ZoneMinder.com的论坛以获得支持或建议,这可以提升您的ZoneMinder的体验。', @@ -266,7 +275,6 @@ $SLANG = array( 'DonateRemindNever' => '不,我不打算捐款', 'DonateRemindWeek' => '现在不,1星期内再次提醒我', 'DonateYes' => '好,我现在就捐款', - 'DoNativeMotionDetection'=> 'Do Native Motion Detection', 'Download' => '下载', 'DuplicateMonitorName' => 'Duplicate Monitor Name', // Added - 2009-03-31 'Duration' => 'Duration', @@ -309,10 +317,12 @@ $SLANG = array( 'Feed' => '转送源', 'Ffmpeg' => 'Ffmpeg', 'File' => '文件', + 'Filter' => 'Filter', // Added - 2015-04-18 'FilterArchiveEvents' => '将全部匹配项存档', 'FilterDeleteEvents' => '将全部匹配项删除', 'FilterEmailEvents' => '将全部匹配项详情电邮出去', 'FilterExecuteEvents' => '执行全部匹配项命令', + 'FilterLog' => 'Filter log', // Added - 2015-04-18 'FilterMessageEvents' => '全部匹配项的信息详情', 'FilterPx' => '过滤器像素', 'FilterUnset' => '您必须指定过滤器宽度和高度', @@ -322,12 +332,12 @@ $SLANG = array( 'First' => '首先', 'FlippedHori' => '水平翻转', 'FlippedVert' => '垂直翻转', - 'FnNone' => 'None', // Added 2013.08.16. - 'FnMonitor' => 'Monitor', // Added 2013.08.16. - 'FnModect' => 'Modect', // Added 2013.08.16. - 'FnRecord' => 'Record', // Added 2013.08.16. 'FnMocord' => 'Mocord', // Added 2013.08.16. + 'FnModect' => 'Modect', // Added 2013.08.16. + 'FnMonitor' => 'Monitor', // Added 2013.08.16. 'FnNodect' => 'Nodect', // Added 2013.08.16. + 'FnNone' => 'None', // Added 2013.08.16. + 'FnRecord' => 'Record', // Added 2013.08.16. 'Focus' => '聚焦', 'ForceAlarm' => '强制报警', 'Format' => '格式', @@ -335,7 +345,6 @@ $SLANG = array( 'FrameId' => '帧 Id', 'FrameRate' => '帧率', 'FrameSkip' => '跳帧', - 'MotionFrameSkip' => 'Motion Frame Skip', 'Frames' => '帧', 'Func' => '功能', 'Function' => '功能', @@ -462,6 +471,7 @@ $SLANG = array( 'MinZoomSpeed' => '最小缩放速度', 'MinZoomStep' => '最小缩放步进', 'Misc' => '杂项', + 'Mode' => 'Mode', // Added - 2015-04-18 'Monitor' => '监视器', 'MonitorIds' => '监视器 Ids', 'MonitorPreset' => '监视器预设值', @@ -472,12 +482,13 @@ $SLANG = array( 'Montage' => '镜头组接', 'Month' => '月', 'More' => 'More', // Added - 2011-06-16 + 'MotionFrameSkip' => 'Motion Frame Skip', 'Move' => '移动', - 'MtgDefault' => 'Default', // Added 2013.08.15. 'Mtg2widgrd' => '2-wide grid', // Added 2013.08.15. 'Mtg3widgrd' => '3-wide grid', // Added 2013.08.15. - 'Mtg4widgrd' => '4-wide grid', // Added 2013.08.15. 'Mtg3widgrx' => '3-wide grid, scaled, enlarge on alarm', // Added 2013.08.15. + 'Mtg4widgrd' => '4-wide grid', // Added 2013.08.15. + 'MtgDefault' => 'Default', // Added 2013.08.15. 'MustBeGe' => '必须大于等于', 'MustBeLe' => '必须小于等于', 'MustConfirmPassword' => '您必须确认密码', @@ -506,6 +517,9 @@ $SLANG = array( 'NumPresets' => '数值预置', 'Off' => '关', 'On' => '开', + 'OnvifCredentialsIntro'=> 'Please supply user name and password for the selected camera.
If no user has been created for the camera then the user given here will be created with the given password.

', // Added - 2015-04-18 + 'OnvifProbe' => 'ONVIF', // Added - 2015-04-18 + 'OnvifProbeIntro' => 'The list below shows detected ONVIF cameras and whether they are already being used or available for selection.

Select the desired entry from the list below.

Please note that not all cameras may be detected and that choosing a camera here may overwrite any values you already have configured for the current monitor.

', // Added - 2015-04-18 'OpEq' => '等于', 'OpGt' => '大于', 'OpGtEq' => '大于等于', @@ -552,6 +566,9 @@ $SLANG = array( 'Presets' => '预置', 'Prev' => '前', 'Probe' => 'Probe', // Added - 2009-03-31 + 'ProfileProbe' => 'Stream Probe', // Added - 2015-04-18 + 'ProfileProbeIntro' => 'The list below shows the existing stream profiles of the selected camera .

Select the desired entry from the list below.

Please note that ZoneMinder cannot configure additional profiles and that choosing a camera here may overwrite any values you already have configured for the current monitor.

', // Added - 2015-04-18 + 'Progress' => 'Progress', // Added - 2015-04-18 'Protocol' => '协议', 'Rate' => '速率', 'Real' => '实际', @@ -639,6 +656,7 @@ $SLANG = array( 'Submit' => '发送', 'System' => '系统', 'SystemLog' => 'System Log', // Added - 2011-06-16 + 'TargetColorspace' => 'Target colorspace', // Added - 2015-04-18 'Tele' => 'Tele', 'Thumbnail' => '缩略图', 'Tilt' => '倾斜', @@ -673,13 +691,16 @@ $SLANG = array( 'UpdateNotNecessary' => '无须更新', 'Updated' => 'Updated', // Added - 2011-06-16 'Upload' => 'Upload', // Added - 2011-08-23 - 'UsedPlugins' => 'Used Plugins', 'UseFilter' => '使用筛选器', 'UseFilterExprsPost' => ' 筛选器 表达式', // This is used at the end of the phrase 'use N filter expressions' 'UseFilterExprsPre' => '使用 ', // This is used at the beginning of the phrase 'use N filter expressions' + 'UsedPlugins' => 'Used Plugins', 'User' => '用户', 'Username' => '用户名', 'Users' => '用户', + 'V4L' => 'V4L', // Added - 2015-04-18 + 'V4LCapturesPerFrame' => 'Captures Per Frame', // Added - 2015-04-18 + 'V4LMultiBuffer' => 'Multi Buffering', // Added - 2015-04-18 'Value' => '数值', 'Version' => '版本', 'VersionIgnore' => '忽略该版本', @@ -719,6 +740,7 @@ $SLANG = array( 'Zone' => '区域', 'ZoneAlarmColour' => '报警色彩 (红/绿/蓝)', 'ZoneArea' => '区域', + 'ZoneExtendAlarmFrames' => 'Extend Alarm Frame Count', 'ZoneFilterSize' => '过滤宽度/高度 (像素)', 'ZoneMinMaxAlarmArea' => '最小/最大报警区域', 'ZoneMinMaxBlobArea' => '最小/最大污渍区 Blob', @@ -727,7 +749,6 @@ $SLANG = array( 'ZoneMinMaxPixelThres' => '最小/最大像素阈值(0-255)', 'ZoneMinderLog' => 'ZoneMinder Log', // Added - 2011-06-17 'ZoneOverloadFrames' => '忽略过载帪数', - 'ZoneExtendAlarmFrames' => 'Extend Alarm Frame Count', 'Zones' => '区域', 'Zoom' => '缩放', 'ZoomIn' => '放大', diff --git a/web/lang/cs_cz.php b/web/lang/cs_cz.php index 3d996b003..ff0f6f260 100644 --- a/web/lang/cs_cz.php +++ b/web/lang/cs_cz.php @@ -88,6 +88,7 @@ $SLANG = array( 'AlarmMaximumFPS' => 'Alarm Maximum FPS', 'AlarmPx' => 'Alarm Px', 'AlarmRGBUnset' => 'You must set an alarm RGB colour', + 'AlarmRefImageBlendPct'=> 'Alarm Reference Image Blend %ge', // Added - 2015-04-18 'Alert' => 'Pozor', 'All' => 'Vechny', 'Apply' => 'Pout', @@ -132,13 +133,13 @@ $SLANG = array( 'BadFPSReportInterval' => 'FPS report interval buffer count must be an integer of 0 or more', 'BadFormat' => 'Format must be set to an integer of zero or more', 'BadFrameSkip' => 'Frame skip count must be an integer of zero or more', - 'BadMotionFrameSkip' => 'Motion Frame skip count must be an integer of zero or more', 'BadHeight' => 'Height must be set to a valid value', 'BadHost' => 'Host must be set to a valid ip address or hostname, do not include http://', 'BadImageBufferCount' => 'Image buffer size must be an integer of 10 or more', 'BadLabelX' => 'Label X co-ordinate must be set to an integer of zero or more', 'BadLabelY' => 'Label Y co-ordinate must be set to an integer of zero or more', 'BadMaxFPS' => 'Maximum FPS must be a positive integer or floating point value', + 'BadMotionFrameSkip' => 'Motion Frame skip count must be an integer of zero or more', 'BadNameChars' => 'Jmna moho obsahovat pouze alfanumerick znaky a podtrtko i pomlku', 'BadPalette' => 'Palette must be set to a valid value', // Added - 2009-03-31 'BadPath' => 'Path must be set to a valid value', @@ -158,7 +159,9 @@ $SLANG = array( 'BlobSizes' => 'Velikost znaky', 'Blobs' => 'Znaky', 'Brightness' => 'Svtlost', + 'Buffer' => 'Buffer', // Added - 2015-04-18 'Buffers' => 'Bufery', + 'CSSDescription' => 'Change the default css for this computer', // Added - 2015-04-18 'CanAutoFocus' => 'Um automaticky zaostit', 'CanAutoGain' => 'Um automatick zisk', 'CanAutoIris' => 'Um auto iris', @@ -202,6 +205,7 @@ $SLANG = array( 'CaptureHeight' => 'Vka zdrojovho snmku', 'CaptureMethod' => 'Capture Method', // Added - 2009-02-08 'CapturePalette' => 'Paleta zdrojovho snmku', + 'CaptureResolution' => 'Capture Resolution', // Added - 2015-04-18 'CaptureWidth' => 'ka zdrojovho snmku', 'Cause' => 'Pina', 'CheckMethod' => 'Metoda znakovn alarmem', @@ -232,6 +236,7 @@ $SLANG = array( 'ControlDevice' => 'Zazen zen', 'ControlType' => 'Typ zen', 'Controllable' => 'diteln', + 'Current' => 'Current', // Added - 2015-04-18 'Cycle' => 'Cyklus', 'CycleWatch' => 'Cyklick prohlen', 'DateTime' => 'Date/Time', // Added - 2011-06-16 @@ -240,12 +245,15 @@ $SLANG = array( 'DefaultRate' => 'Default Rate', 'DefaultScale' => 'Pednastaven velikost', 'DefaultView' => 'Default View', + 'Deinterlacing' => 'Deinterlacing', // Added - 2015-04-18 + 'Delay' => 'Delay', // Added - 2015-04-18 'Delete' => 'Smazat', 'DeleteAndNext' => 'Smazat & Dal', 'DeleteAndPrev' => 'Smazat & Pedchoz', 'DeleteSavedFilter' => 'Smazat filtr', 'Description' => 'Popis', 'DetectedCameras' => 'Detected Cameras', // Added - 2009-03-31 + 'DetectedProfiles' => 'Detected Profiles', // Added - 2015-04-18 'Device' => 'Device', // Added - 2009-02-08 'DeviceChannel' => 'Kanl zazen', 'DeviceFormat' => 'Formt zazen', @@ -257,6 +265,7 @@ $SLANG = array( 'Disk' => 'Disk', 'Display' => 'Display', // Added - 2011-01-30 'Displaying' => 'Displaying', // Added - 2011-06-16 + 'DoNativeMotionDetection'=> 'Do Native Motion Detection', 'Donate' => 'Prosm podpote', 'DonateAlready' => 'Ne, u jsem podpoil', 'DonateEnticement' => 'Ji njakou dobu pouvte software ZoneMinder k ochran svho majetku a pedpokldm, e jej shledvte uitenm. Pestoe je ZoneMinder, znovu pipomnm, zdarma a voln en software, stoj jeho vvoj a podpora njak penze. Pokud byste chtl/a podpoit budouc vvoj a nov monosti softwaru, prosm zvate darovn finann pomoci. Darovn je, samozejm, dobrovoln, ale zato velmi cenn mete pispt jakou stkou chcete.

Pokud mte zjem podpoit n tm, prosm, vyberte ne uvedenou monost, nebo navtivte http://www.zoneminder.com/donate.html.

Dkuji Vm e jste si vybral/a software ZoneMinder a nezapomete navtvit frum na ZoneMinder.com pro podporu a nvrhy jak udlat ZoneMinder jet lepm ne je dnes.', @@ -266,7 +275,6 @@ $SLANG = array( 'DonateRemindNever' => 'Ne, nechci podpoit ZoneMinder, nepipomnat', 'DonateRemindWeek' => 'Nyn ne, pipomenout za tden', 'DonateYes' => 'Ano, chcit podpoit ZoneMinder nyn', - 'DoNativeMotionDetection'=> 'Do Native Motion Detection', 'Download' => 'Sthnout', 'DuplicateMonitorName' => 'Duplicate Monitor Name', // Added - 2009-03-31 'Duration' => 'Prbh', @@ -309,10 +317,12 @@ $SLANG = array( 'Feed' => 'Nasytit', 'Ffmpeg' => 'Ffmpeg', // Added - 2009-02-08 'File' => 'Soubor', + 'Filter' => 'Filter', // Added - 2015-04-18 'FilterArchiveEvents' => 'Archivovat vechny nalezen', 'FilterDeleteEvents' => 'Smazat vechny nalezen', 'FilterEmailEvents' => 'Poslat email s detaily nalezench', 'FilterExecuteEvents' => 'Spustit pkaz na vech nalezench', + 'FilterLog' => 'Filter log', // Added - 2015-04-18 'FilterMessageEvents' => 'Podat zprvu o vech nalezench', 'FilterPx' => 'Filtr Px', 'FilterUnset' => 'You must specify a filter width and height', @@ -322,12 +332,12 @@ $SLANG = array( 'First' => 'Prvn', 'FlippedHori' => 'Peklopen vodorovn', 'FlippedVert' => 'Peklopen svisle', - 'FnNone' => 'None', // Added 2013.08.16. - 'FnMonitor' => 'Monitor', // Added 2013.08.16. - 'FnModect' => 'Modect', // Added 2013.08.16. - 'FnRecord' => 'Record', // Added 2013.08.16. 'FnMocord' => 'Mocord', // Added 2013.08.16. + 'FnModect' => 'Modect', // Added 2013.08.16. + 'FnMonitor' => 'Monitor', // Added 2013.08.16. 'FnNodect' => 'Nodect', // Added 2013.08.16. + 'FnNone' => 'None', // Added 2013.08.16. + 'FnRecord' => 'Record', // Added 2013.08.16. 'Focus' => 'Zaosten', 'ForceAlarm' => 'Spustit alarm', 'Format' => 'Formt', @@ -335,7 +345,6 @@ $SLANG = array( 'FrameId' => 'Snmek Id', 'FrameRate' => 'Rychlost snmk', 'FrameSkip' => 'Vynechat snmek', - 'MotionFrameSkip' => 'Motion Frame Skip', 'Frames' => 'Snmky', 'Func' => 'Funkce', 'Function' => 'Funkce', @@ -462,6 +471,7 @@ $SLANG = array( 'MinZoomSpeed' => 'Min rychlost zoomu', 'MinZoomStep' => 'Min krok zoomu', 'Misc' => 'Ostatn', + 'Mode' => 'Mode', // Added - 2015-04-18 'Monitor' => 'Kamera', 'MonitorIds' => 'Id kamer', 'MonitorPreset' => 'Monitor Preset', @@ -472,12 +482,13 @@ $SLANG = array( 'Montage' => 'Sestih', 'Month' => 'Msc', 'More' => 'More', // Added - 2011-06-16 + 'MotionFrameSkip' => 'Motion Frame Skip', 'Move' => 'Pohyb', - 'MtgDefault' => 'Default', // Added 2013.08.15. 'Mtg2widgrd' => '2-wide grid', // Added 2013.08.15. 'Mtg3widgrd' => '3-wide grid', // Added 2013.08.15. - 'Mtg4widgrd' => '4-wide grid', // Added 2013.08.15. 'Mtg3widgrx' => '3-wide grid, scaled, enlarge on alarm', // Added 2013.08.15. + 'Mtg4widgrd' => '4-wide grid', // Added 2013.08.15. + 'MtgDefault' => 'Default', // Added 2013.08.15. 'MustBeGe' => 'mus bt vt nebo rovno ne', 'MustBeLe' => 'mus bt men nebo rovno ne', 'MustConfirmPassword' => 'Muste potvrdit heslo', @@ -506,6 +517,9 @@ $SLANG = array( 'NumPresets' => 'Poet pedvoleb', 'Off' => 'Off', 'On' => 'On', + 'OnvifCredentialsIntro'=> 'Please supply user name and password for the selected camera.
If no user has been created for the camera then the user given here will be created with the given password.

', // Added - 2015-04-18 + 'OnvifProbe' => 'ONVIF', // Added - 2015-04-18 + 'OnvifProbeIntro' => 'The list below shows detected ONVIF cameras and whether they are already being used or available for selection.

Select the desired entry from the list below.

Please note that not all cameras may be detected and that choosing a camera here may overwrite any values you already have configured for the current monitor.

', // Added - 2015-04-18 'OpEq' => 'rovno', 'OpGt' => 'vt', 'OpGtEq' => 'vt nebo rovno', @@ -552,6 +566,9 @@ $SLANG = array( 'Presets' => 'Pedvolby', 'Prev' => 'Zpt', 'Probe' => 'Probe', // Added - 2009-03-31 + 'ProfileProbe' => 'Stream Probe', // Added - 2015-04-18 + 'ProfileProbeIntro' => 'The list below shows the existing stream profiles of the selected camera .

Select the desired entry from the list below.

Please note that ZoneMinder cannot configure additional profiles and that choosing a camera here may overwrite any values you already have configured for the current monitor.

', // Added - 2015-04-18 + 'Progress' => 'Progress', // Added - 2015-04-18 'Protocol' => 'Protocol', 'Rate' => 'Rychlost', 'Real' => 'Skuten', @@ -639,6 +656,7 @@ $SLANG = array( 'Submit' => 'Potvrdit', 'System' => 'System', 'SystemLog' => 'System Log', // Added - 2011-06-16 + 'TargetColorspace' => 'Target colorspace', // Added - 2015-04-18 'Tele' => 'Piblit', 'Thumbnail' => 'Miniatura', 'Tilt' => 'Nklon', @@ -673,13 +691,16 @@ $SLANG = array( 'UpdateNotNecessary' => 'Update nen poteba.', 'Updated' => 'Updated', // Added - 2011-06-16 'Upload' => 'Upload', // Added - 2011-08-23 - 'UsedPlugins' => 'Used Plugins', 'UseFilter' => 'Pout filtr', 'UseFilterExprsPost' => ' vraz', // This is used at the end of the phrase 'use N filter expressions' 'UseFilterExprsPre' => 'Pout ', // This is used at the beginning of the phrase 'use N filter expressions' + 'UsedPlugins' => 'Used Plugins', 'User' => 'Uivatel', 'Username' => 'Uivatelsk jmno', 'Users' => 'Uivatel', + 'V4L' => 'V4L', // Added - 2015-04-18 + 'V4LCapturesPerFrame' => 'Captures Per Frame', // Added - 2015-04-18 + 'V4LMultiBuffer' => 'Multi Buffering', // Added - 2015-04-18 'Value' => 'Hodnota', 'Version' => 'Verze', 'VersionIgnore' => 'Ignorovat tuto verzi', @@ -719,6 +740,7 @@ $SLANG = array( 'Zone' => 'Zna', 'ZoneAlarmColour' => 'Barva alarmu (Red/Green/Blue)', 'ZoneArea' => 'Zone Area', + 'ZoneExtendAlarmFrames' => 'Extend Alarm Frame Count', 'ZoneFilterSize' => 'Filter Width/Height (pixels)', 'ZoneMinMaxAlarmArea' => 'Min/Max Alarmed Area', 'ZoneMinMaxBlobArea' => 'Min/Max Blob Area', @@ -727,7 +749,6 @@ $SLANG = array( 'ZoneMinMaxPixelThres' => 'Min/Max Pixel Threshold (0-255)', 'ZoneMinderLog' => 'ZoneMinder Log', // Added - 2011-06-17 'ZoneOverloadFrames' => 'Overload Frame Ignore Count', - 'ZoneExtendAlarmFrames' => 'Extend Alarm Frame Count', 'Zones' => 'Zny', 'Zoom' => 'Zoom', 'ZoomIn' => 'Zvtit', diff --git a/web/lang/de_de.php b/web/lang/de_de.php index 28002aec8..9ad642173 100644 --- a/web/lang/de_de.php +++ b/web/lang/de_de.php @@ -19,6 +19,7 @@ // // ZoneMinder german Translation by Robert Schumann (rs at core82 dot de) +// ZoneMinder german Translation by Sebastian Kaminski (github @seeebek) // Notes for Translators // 0. Get some credit, put your name in the line above (optional) @@ -50,7 +51,7 @@ // do this by default, uncomment this if required. // // Example -// header( "Content-Type: text/html; charset=iso-8859-1" ); +header( "Content-Type: text/html; charset=utf-8" ); // You may need to change your locale here if your default one is incorrect for the // language described in this file, or if you have multiple languages supported. @@ -76,7 +77,7 @@ $SLANG = array( '8BitGrey' => '8-Bit-Grau', 'Action' => 'Aktion', 'Actual' => 'Original', - 'AddNewControl' => 'Neues Kontrollelement hinzufügen', + 'AddNewControl' => 'Neues Kontrollelement hinzufügen', 'AddNewMonitor' => 'Neuer Monitor', 'AddNewUser' => 'Neuer Benutzer', 'AddNewZone' => 'Neue Zone', @@ -87,10 +88,11 @@ $SLANG = array( 'AlarmLimits' => 'Alarm-Limits', 'AlarmMaximumFPS' => 'Alarm-Maximum-FPS', 'AlarmPx' => 'Alarm-Pixel', - 'AlarmRGBUnset' => 'Sie müssen eine RGB-Alarmfarbe setzen', + 'AlarmRGBUnset' => 'Sie müssen eine RGB-Alarmfarbe setzen', + 'AlarmRefImageBlendPct'=> 'Alarm Reference Image Blend %ge', // Added - 2015-04-18 'Alert' => 'Alarm', 'All' => 'Alle', - 'Apply' => 'OK', + 'Apply' => 'Anwenden', 'ApplyingStateChange' => 'Aktiviere neuen Status', 'ArchArchived' => 'Nur Archivierte', 'ArchUnarchived' => 'Nur Nichtarchivierte', @@ -119,156 +121,163 @@ $SLANG = array( 'AttrTotalScore' => 'Totale Punktzahl', 'AttrWeekday' => 'Wochentag', 'Auto' => 'Auto', - 'AutoStopTimeout' => 'Auto-Stopp-Zeitüberschreitung', - 'Available' => 'Available', // Added - 2009-03-31 + 'AutoStopTimeout' => 'Auto-Stopp-Zeitüberschreitung', + 'Available' => 'Vorhanden', // Added - 2009-03-31 'AvgBrScore' => 'Mittlere
Punktzahl', 'Background' => 'Hintergrund', 'BackgroundFilter' => 'Filter im Hintergrund laufen lassen', - 'BadAlarmFrameCount' => 'Die Bildanzahl muss ganzzahlig 1 oder größer sein', + 'BadAlarmFrameCount' => 'Die Bildanzahl muss ganzzahlig 1 oder größer sein', 'BadAlarmMaxFPS' => 'Alarm-Maximum-FPS muss eine positive Ganzzahl oder eine Gleitkommazahl sein', - 'BadChannel' => 'Der Kanal muss ganzzahlig 0 oder größer sein', - 'BadColours' => 'Target colour must be set to a valid value', // Added - 2011-06-15 - 'BadDevice' => 'Das Gerät muss eine gültige Systemresource sein', - 'BadFPSReportInterval' => 'Der FPS-Intervall-Puffer-Zähler muss ganzzahlig 0 oder größer sein', - 'BadFormat' => 'Das Format muss ganzzahlig 0 oder größer sein', - 'BadFrameSkip' => 'Der Auslasszähler für Frames muss ganzzahlig 0 oder größer sein', - 'BadMotionFrameSkip' => 'Motion Frame skip count must be an integer of zero or more', - 'BadHeight' => 'Die Höhe muss auf einen gültigen Wert eingestellt sein', - 'BadHost' => 'Der Host muss auf eine gültige IP-Adresse oder einen Hostnamen (ohne http://) eingestellt sein', - 'BadImageBufferCount' => 'Die Größe des Bildpuffers muss ganzzahlig 10 oder größer sein', - 'BadLabelX' => 'Die x-Koordinate der Bezeichnung muss ganzzahlig 0 oder größer sein', - 'BadLabelY' => 'Die y-Koordinate der Bezeichnung muss ganzzahlig 0 oder größer sein', + 'BadChannel' => 'Der Kanal muss ganzzahlig 0 oder größer sein', + 'BadColours' => 'Die Zielfarbe muss eine gültige Farbe sein.', // Added - 2011-06-15 + 'BadDevice' => 'Das Gerät muss eine gültige Systemresource sein', + 'BadFPSReportInterval' => 'Der FPS-Intervall-Puffer-Zähler muss ganzzahlig 0 oder größer sein', + 'BadFormat' => 'Das Format muss ganzzahlig 0 oder größer sein', + 'BadFrameSkip' => 'Der Auslasszähler für Frames muss ganzzahlig 0 oder größer sein', + 'BadHeight' => 'Die Höhe muss auf einen gültigen Wert eingestellt sein', + 'BadHost' => 'Der Host muss auf eine gültige IP-Adresse oder einen Hostnamen (ohne http://) eingestellt sein', + 'BadImageBufferCount' => 'Die Größe des Bildpuffers muss ganzzahlig 10 oder größer sein', + 'BadLabelX' => 'Die x-Koordinate der Bezeichnung muss ganzzahlig 0 oder größer sein', + 'BadLabelY' => 'Die y-Koordinate der Bezeichnung muss ganzzahlig 0 oder größer sein', 'BadMaxFPS' => 'Maximum-FPS muss eine positive Ganzzahl oder eine Gleitkommazahl sein', - 'BadNameChars' => 'Namen dürfen nur aus Buchstaben, Zahlen und Trenn- oder Unterstrichen bestehen', - 'BadPalette' => 'Palette must be set to a valid value', // Added - 2009-03-31 - 'BadPath' => 'Der Pfad muss auf einen gültigen Wert eingestellt sein', - 'BadPort' => 'Der Port muss auf eine gültige Zahl eingestellt sein', - 'BadPostEventCount' => 'Der Zähler für die Ereignisfolgebilder muss ganzzahlig 0 oder größer sein', - 'BadPreEventCount' => 'Der Zähler für die Ereignisvorlaufbilder muss mindestens ganzzahlig 0 und kleiner als die Bildpuffergröße sein', - 'BadRefBlendPerc' => 'Der Referenz-Blenden-Prozentwert muss ganzzahlig 0 oder größer sein', - 'BadSectionLength' => 'Die Bereichslänge muss ganzzahlig 0 oder größer sein', - 'BadSignalCheckColour' => 'Die Signalprüffarbe muss auf einen gültigen Farbwert eingestellt sein', + 'BadMotionFrameSkip' => 'Motion Frame skip count must be an integer of zero or more', + 'BadNameChars' => 'Namen dürfen nur aus Buchstaben, Zahlen und Trenn- oder Unterstrichen bestehen', + 'BadPalette' => 'Die Palette muss auf einen gültigen Wert eingestellt sein', // Added - 2009-03-31 + 'BadPath' => 'Der Pfad muss auf einen gültigen Wert eingestellt sein', + 'BadPort' => 'Der Port muss auf eine gültige Zahl eingestellt sein', + 'BadPostEventCount' => 'Der Zähler für die Ereignisfolgebilder muss ganzzahlig 0 oder größer sein', + 'BadPreEventCount' => 'Der Zähler für die Ereignisvorlaufbilder muss mindestens ganzzahlig 0 und kleiner als die Bildpuffergröße sein', + 'BadRefBlendPerc' => 'Der Referenz-Blenden-Prozentwert muss ganzzahlig 0 oder größer sein', + 'BadSectionLength' => 'Die Bereichslänge muss ganzzahlig 0 oder größer sein', + 'BadSignalCheckColour' => 'Die Signalprüffarbe muss auf einen gültigen Farbwert eingestellt sein', 'BadStreamReplayBuffer'=> 'Der Wiedergabestrompuffer tream replay buffer must be an integer of zero or more', - 'BadWarmupCount' => 'Die Anzahl der Vorwrmbilder muss ganzzahlig 0 oder größer sein', - 'BadWebColour' => 'Die Webfarbe muss auf einen gültigen Farbwert eingestellt sein', - 'BadWidth' => 'Die Breite muss auf einen gültigen Wert eingestellt sein', + 'BadWarmupCount' => 'Die Anzahl der Vorwärmbilder muss ganzzahlig 0 oder größer sein', + 'BadWebColour' => 'Die Webfarbe muss auf einen gültigen Farbwert eingestellt sein', + 'BadWidth' => 'Die Breite muss auf einen gültigen Wert eingestellt sein', 'Bandwidth' => 'Bandbreite', - 'BandwidthHead' => 'Bandwidth', // This is the end of the bandwidth status on the top of the console, different in many language due to phrasing + 'BandwidthHead' => 'Bandbreite', // This is the end of the bandwidth status on the top of the console, different in many language due to phrasing 'BlobPx' => 'Blob-Pixel', - 'BlobSizes' => 'Blobgröße', + 'BlobSizes' => 'Blobgröße', 'Blobs' => 'Blobs', 'Brightness' => 'Helligkeit', - 'Buffers' => 'Puffer', + 'Buffer' => 'Buffer', // Added - 2015-04-18 + 'Buffers' => 'Buffer', + 'CSSDescription' => 'Ändere das standard CSS für diesen Computer.', // Added - 2015-04-18 'CanAutoFocus' => 'Kann Autofokus', - 'CanAutoGain' => 'Kann Auto-Verstärkung', + 'CanAutoGain' => 'Kann Auto-Verstärkung', 'CanAutoIris' => 'Kann Auto-Iris', - 'CanAutoWhite' => 'Kann Auto-Weiß-Abgleich', + 'CanAutoWhite' => 'Kann Auto-Weiß-Abgleich', 'CanAutoZoom' => 'Kann Auto-Zoom', - 'CanFocus' => 'Kann Fokus', + 'CanFocus' => 'Kann Fokus', 'CanFocusAbs' => 'Kann absoluten Fokus', 'CanFocusCon' => 'Kann kontinuierlichen Fokus', 'CanFocusRel' => 'Kann relativen Fokus', - 'CanGain' => 'Kann Verstärkung', - 'CanGainAbs' => 'Kann absolute Verstärkung', - 'CanGainCon' => 'Kann kontinuierliche Verstärkung', - 'CanGainRel' => 'Kann relative Verstäkung', - 'CanIris' => 'Kann Iris', + 'CanGain' => 'Kann Verstärkung', + 'CanGainAbs' => 'Kann absolute Verstärkung', + 'CanGainCon' => 'Kann kontinuierliche Verstärkung', + 'CanGainRel' => 'Kann relative Verstäkung', + 'CanIris' => 'Kann Iris', 'CanIrisAbs' => 'Kann absolute Iris', 'CanIrisCon' => 'Kann kontinuierliche Iris', 'CanIrisRel' => 'Kann relative Iris', - 'CanMove' => 'Kann Bewegung', + 'CanMove' => 'Kann Bewegung', 'CanMoveAbs' => 'Kann absolute Bewegung', 'CanMoveCon' => 'Kann kontinuierliche Bewegung', 'CanMoveDiag' => 'Kann diagonale Bewegung', 'CanMoveMap' => 'Kann Mapped-Bewegung', 'CanMoveRel' => 'Kann relative Bewegung', - 'CanPan' => 'Kann Pan' , - 'CanReset' => 'Kann Reset', + 'CanPan' => 'Kann Pan' , + 'CanReset' => 'Kann Reset', 'CanSetPresets' => 'Kann Voreinstellungen setzen', - 'CanSleep' => 'Kann Sleep', - 'CanTilt' => 'Kann Neigung', - 'CanWake' => 'Kann Wake', - 'CanWhite' => 'Kann Weiß-Abgleich', - 'CanWhiteAbs' => 'Kann absoluten Weiß-Abgleich', - 'CanWhiteBal' => 'Kann Weiß-Abgleich', - 'CanWhiteCon' => 'Kann kontinuierlichen Weiß-Abgleich', - 'CanWhiteRel' => 'Kann relativen Weiß-Abgleich', - 'CanZoom' => 'Kann Zoom', + 'CanSleep' => 'Kann Sleep', + 'CanTilt' => 'Kann Neigung', + 'CanWake' => 'Kann Wake', + 'CanWhite' => 'Kann Weiß-Abgleich', + 'CanWhiteAbs' => 'Kann absoluten Weiß-Abgleich', + 'CanWhiteBal' => 'Kann Weiß-Abgleich', + 'CanWhiteCon' => 'Kann kontinuierlichen Weiß-Abgleich', + 'CanWhiteRel' => 'Kann relativen Weiß-Abgleich', + 'CanZoom' => 'Kann Zoom', 'CanZoomAbs' => 'Kann absoluten Zoom', 'CanZoomCon' => 'Kann kontinuierlichen Zoom', 'CanZoomRel' => 'Kann relativen Zoom', 'Cancel' => 'Abbruch', 'CancelForcedAlarm' => 'Abbruch des unbedingten Alarms', - 'CaptureHeight' => 'Erfasse Höhe', - 'CaptureMethod' => 'Capture Method', // Added - 2009-02-08 + 'CaptureHeight' => 'Erfasse Höhe', + 'CaptureMethod' => 'Aufnahmemethode', // Added - 2009-02-08 'CapturePalette' => 'Erfasse Farbpalette', + 'CaptureResolution' => 'Aufnahmeauflösung', // Added - 2015-04-18 'CaptureWidth' => 'Erfasse Breite', 'Cause' => 'Grund', - 'CheckMethod' => 'Alarm-Prüfmethode', - 'ChooseDetectedCamera' => 'Choose Detected Camera', // Added - 2009-03-31 + 'CheckMethod' => 'Alarm-Prüfmethode', + 'ChooseDetectedCamera' => 'Wähle erkannte Kamera', // Added - 2009-03-31 'ChooseFilter' => 'Filterauswahl', - 'ChooseLogFormat' => 'Choose a log format', // Added - 2011-06-17 - 'ChooseLogSelection' => 'Choose a log selection', // Added - 2011-06-17 - 'ChoosePreset' => 'Voreinstellung auswählen', - 'Clear' => 'Clear', // Added - 2011-06-16 - 'Close' => 'Schließen', + 'ChooseLogFormat' => 'Wähle ein Log-Format', // Added - 2011-06-17 + 'ChooseLogSelection' => 'Wähle eine Log-Auswahl', // Added - 2011-06-17 + 'ChoosePreset' => 'Voreinstellung auswählen', + 'Clear' => 'Leeren', // Added - 2011-06-16 + 'Close' => 'Schließen', 'Colour' => 'Farbe', 'Command' => 'Kommando', - 'Component' => 'Component', // Added - 2011-06-16 + 'Component' => 'Komponente', // Added - 2011-06-16 'Config' => 'Konfig.', - 'ConfiguredFor' => 'Konfiguriert für', - 'ConfirmDeleteEvents' => 'Sind Sie sicher, dass Sie die ausgewählten Ereignisse löschen wollen?', - 'ConfirmPassword' => 'Passwortbestätigung', + 'ConfiguredFor' => 'Konfiguriert für', + 'ConfirmDeleteEvents' => 'Sind Sie sicher, dass Sie die ausgewählten Ereignisse löschen wollen?', + 'ConfirmPassword' => 'Passwortbestätigung', 'ConjAnd' => 'und', 'ConjOr' => 'oder', 'Console' => 'Konsole', - 'ContactAdmin' => 'Bitte kontaktieren Sie den Administrator für weitere Details', + 'ContactAdmin' => 'Bitte kontaktieren Sie den Administrator für weitere Details', 'Continue' => 'Weiter', 'Contrast' => 'Kontrast', 'Control' => 'Kontrolle', 'ControlAddress' => 'Kontrolladresse', - 'ControlCap' => 'Kontrollmöglichkeit', - 'ControlCaps' => 'Kontrollmöglichkeiten', - 'ControlDevice' => 'Kontrollgerät', + 'ControlCap' => 'Kontrollmöglichkeit', + 'ControlCaps' => 'Kontrollmöglichkeiten', + 'ControlDevice' => 'Kontrollgerät', 'ControlType' => 'Kontrolltyp', 'Controllable' => 'Kontrollierbar', + 'Current' => 'Aktuell', // Added - 2015-04-18 'Cycle' => 'Zyklus', 'CycleWatch' => 'Zeitzyklus', - 'DateTime' => 'Date/Time', // Added - 2011-06-16 + 'DateTime' => 'Datum/Zeit', // Added - 2011-06-16 'Day' => 'Tag', 'Debug' => 'Debug', 'DefaultRate' => 'Standardrate', 'DefaultScale' => 'Standardskalierung', 'DefaultView' => 'Standardansicht', - 'Delete' => 'Löschen', - 'DeleteAndNext' => 'Löschen & Nächstes', - 'DeleteAndPrev' => 'Löschen & Vorheriges', - 'DeleteSavedFilter' => 'Lösche gespeichertes Filter', + 'Deinterlacing' => 'Deinterlacing', // Added - 2015-04-18 + 'Delay' => 'Verzögerung', // Added - 2015-04-18 + 'Delete' => 'Löschen', + 'DeleteAndNext' => 'Löschen & Nächstes', + 'DeleteAndPrev' => 'Löschen & Vorheriges', + 'DeleteSavedFilter' => 'Lösche gespeichertes Filter', 'Description' => 'Beschreibung', - 'DetectedCameras' => 'Detected Cameras', // Added - 2009-03-31 - 'Device' => 'Device', // Added - 2009-02-08 - 'DeviceChannel' => 'Gerätekanal', - 'DeviceFormat' => 'Geräteformat', - 'DeviceNumber' => 'Gerätenummer', - 'DevicePath' => 'Gerätepfad', - 'Devices' => 'Geräte', + 'DetectedCameras' => 'Erkannte Kameras', // Added - 2009-03-31 + 'DetectedProfiles' => 'Erkannte Profile', // Added - 2015-04-18 + 'Device' => 'Gerät', // Added - 2009-02-08 + 'DeviceChannel' => 'Gerätekanal', + 'DeviceFormat' => 'Geräteformat', + 'DeviceNumber' => 'Gerätenummer', + 'DevicePath' => 'Gerätepfad', + 'Devices' => 'Geräte', 'Dimensions' => 'Abmessungen', 'DisableAlarms' => 'Alarme abschalten', 'Disk' => 'Disk', - 'Display' => 'Display', // Added - 2011-01-30 - 'Displaying' => 'Displaying', // Added - 2011-06-16 + 'Display' => 'Anzeige', // Added - 2011-01-30 + 'Displaying' => 'Gezeigt', // Added - 2011-06-16 + 'DoNativeMotionDetection'=> 'Do Native Motion Detection', 'Donate' => 'Bitte spenden Sie.', 'DonateAlready' => 'Nein, ich habe schon gespendet', - 'DonateEnticement' => 'Sie benutzen ZoneMinder nun schon eine Weile und es ist hoffentlich eine nützliche Applikation zur Verbesserung Ihrer Heim- oder Arbeitssicherheit. Obwohl ZoneMinder eine freie Open-Source-Software ist und bleiben wird, entstehen Kosten bei der Entwicklung und dem Support.

Falls Sie ZoneMinder fr Weiterentwicklung in der Zukunft unterstützen möchten, denken Sie bitte ber eine Spende für das Projekt unter der Webadresse http://www.zoneminder.com/donate.html oder über nachfolgend stehende Option nach. Spenden sind, wie der Name schon sagt, immer freiwillig. Dem Projekt helfen kleine genauso wie größere Spenden sehr weiter und ein herzlicher Dank ist jedem Spender sicher.

Vielen Dank dafür, dass sie ZoneMinder benutzen. Vergessen Sie nicht die Foren unter ZoneMinder.com, um Support zu erhalten und Ihre Erfahrung mit ZoneMinder zu verbessern!', + 'DonateEnticement' => 'Sie benutzen ZoneMinder nun schon eine Weile und es ist hoffentlich eine nützliche Applikation zur Verbesserung Ihrer Heim- oder Arbeitssicherheit. Obwohl ZoneMinder eine freie Open-Source-Software ist und bleiben wird, entstehen Kosten bei der Entwicklung und dem Support.

Falls Sie ZoneMinder für Weiterentwicklung in der Zukunft unterstützen möchten, denken Sie bitte über eine Spende für das Projekt unter der Webadresse http://www.zoneminder.com/donate.html oder über nachfolgend stehende Option nach. Spenden sind, wie der Name schon sagt, immer freiwillig. Dem Projekt helfen kleine genauso wie größere Spenden sehr weiter und ein herzlicher Dank ist jedem Spender sicher.

Vielen Dank dafür, dass sie ZoneMinder benutzen. Vergessen Sie nicht die Foren unter ZoneMinder.com, um Support zu erhalten und Ihre Erfahrung mit ZoneMinder zu verbessern!', 'DonateRemindDay' => 'Noch nicht, erinnere mich in einem Tag noch mal.', 'DonateRemindHour' => 'Noch nicht, erinnere mich in einer Stunde noch mal.', 'DonateRemindMonth' => 'Noch nicht, erinnere mich in einem Monat noch mal.', - 'DonateRemindNever' => 'Nein, ich möchte nicht spenden, niemals erinnern.', + 'DonateRemindNever' => 'Nein, ich möchte nicht spenden, niemals erinnern.', 'DonateRemindWeek' => 'Noch nicht, erinnere mich in einer Woche noch mal.', - 'DonateYes' => 'Ja, ich möchte jetzt spenden.', - 'DoNativeMotionDetection'=> 'Do Native Motion Detection', + 'DonateYes' => 'Ja, ich möchte jetzt spenden.', 'Download' => 'Download', - 'DuplicateMonitorName' => 'Duplicate Monitor Name', // Added - 2009-03-31 + 'DuplicateMonitorName' => 'Duplizierter Monitorname', // Added - 2009-03-31 'Duration' => 'Dauer', 'Edit' => 'Bearbeiten', 'Email' => 'E-Mail', @@ -277,16 +286,16 @@ $SLANG = array( 'EnterNewFilterName' => 'Neuen Filternamen eingeben', 'Error' => 'Fehler', 'ErrorBrackets' => 'Fehler. Bitte nur gleiche Anzahl offener und geschlossener Klammern.', - 'ErrorValidValue' => 'Fehler. Bitte alle Werte auf richtige Eingabe prüfen', + 'ErrorValidValue' => 'Fehler. Bitte alle Werte auf richtige Eingabe prüfen', 'Etc' => 'etc.', 'Event' => 'Ereignis', 'EventFilter' => 'Ereignisfilter', 'EventId' => 'Ereignis-ID', 'EventName' => 'Ereignisname', - 'EventPrefix' => 'Ereignis-Präfix', + 'EventPrefix' => 'Ereignis-Präfix', 'Events' => 'Ereignisse', 'Exclude' => 'Ausschluss;', - 'Execute' => 'Ausführen', + 'Execute' => 'Ausführen', 'Export' => 'Exportieren', 'ExportDetails' => 'Exportiere Ereignis-Details', 'ExportFailed' => 'Exportieren fehlgeschlagen', @@ -298,48 +307,49 @@ $SLANG = array( 'ExportLog' => 'Export Log', // Added - 2011-06-17 'ExportMiscFiles' => 'Exportiere andere Dateien (falls vorhanden)', 'ExportOptions' => 'Exportierungsoptionen', - 'ExportSucceeded' => 'Export Succeeded', // Added - 2009-02-08 + 'ExportSucceeded' => 'Export erfolgreich', // Added - 2009-02-08 'ExportVideoFiles' => 'Exportiere Videodateien (falls vorhanden)', 'Exporting' => 'Exportiere', 'FPS' => 'fps', 'FPSReportInterval' => 'fps-Meldeintervall', 'FTP' => 'FTP', 'Far' => 'Weit', - 'FastForward' => 'Schnell vorwärts', + 'FastForward' => 'Schnell vorwärts', 'Feed' => 'Eingabe', 'Ffmpeg' => 'Ffmpeg', // Added - 2009-02-08 'File' => 'Datei', + 'Filter' => 'Filter', // Added - 2015-04-18 'FilterArchiveEvents' => 'Archivierung aller Treffer', - 'FilterDeleteEvents' => 'Löschen aller Treffer', + 'FilterDeleteEvents' => 'Löschen aller Treffer', 'FilterEmailEvents' => 'Detaillierte E-Mail zu allen Treffern', - 'FilterExecuteEvents' => 'Ausführen bei allen Treffern', + 'FilterExecuteEvents' => 'Ausführen bei allen Treffern', + 'FilterLog' => 'Log filtern', // Added - 2015-04-18 'FilterMessageEvents' => 'Detaillierte Nachricht zu allen Treffern', 'FilterPx' => 'Filter-Pixel', - 'FilterUnset' => 'Sie müssen eine Breite und Höhe für das Filter angeben', + 'FilterUnset' => 'Sie müssen eine Breite und Höhe für das Filter angeben', 'FilterUploadEvents' => 'Hochladen aller Treffer', - 'FilterVideoEvents' => 'Video für alle Treffer erstellen', + 'FilterVideoEvents' => 'Video für alle Treffer erstellen', 'Filters' => 'Filter', 'First' => 'Erstes', 'FlippedHori' => 'Horizontal gespiegelt', 'FlippedVert' => 'Vertikal gespiegelt', - 'FnNone' => 'None', // Added 2013.08.16. - 'FnMonitor' => 'Monitor', // Added 2013.08.16. - 'FnModect' => 'Modect', // Added 2013.08.16. - 'FnRecord' => 'Record', // Added 2013.08.16. 'FnMocord' => 'Mocord', // Added 2013.08.16. + 'FnModect' => 'Modect', // Added 2013.08.16. + 'FnMonitor' => 'Monitor', // Added 2013.08.16. 'FnNodect' => 'Nodect', // Added 2013.08.16. + 'FnNone' => 'Keine', // Added 2013.08.16. + 'FnRecord' => 'Record', // Added 2013.08.16. 'Focus' => 'Fokus', - 'ForceAlarm' => 'Unbedingter Alarm', + 'ForceAlarm' => 'Erzwinge Alarm', 'Format' => 'Format', 'Frame' => 'Bild', 'FrameId' => 'Bild-ID', 'FrameRate' => 'Abspielgeschwindigkeit', 'FrameSkip' => 'Bilder auslassen', - 'MotionFrameSkip' => 'Motion Frame Skip', 'Frames' => 'Bilder', 'Func' => 'Fkt.', 'Function' => 'Funktion', - 'Gain' => 'Verstärkung', + 'Gain' => 'Verstärkung', 'General' => 'Allgemeines', 'GenerateVideo' => 'Erzeuge Video', 'GeneratingVideo' => 'Erzeuge Video...', @@ -348,7 +358,7 @@ $SLANG = array( 'Group' => 'Gruppe', 'Groups' => 'Gruppen', 'HasFocusSpeed' => 'Hat Fokus-Geschwindigkeit', - 'HasGainSpeed' => 'Hat Verstäkungs-Geschwindigkeit', + 'HasGainSpeed' => 'Hat Verstäkungs-Geschwindigkeit', 'HasHomePreset' => 'Hat Standardvoreinstellungen', 'HasIrisSpeed' => 'Hat Irisgeschwindigkeit', 'HasPanSpeed' => 'Hat Pan-Geschwindigkeit', @@ -356,10 +366,10 @@ $SLANG = array( 'HasTiltSpeed' => 'Hat Neigungsgeschwindigkeit', 'HasTurboPan' => 'Hat Turbo-Pan', 'HasTurboTilt' => 'Hat Turbo-Neigung', - 'HasWhiteSpeed' => 'Hat Weiß-Abgleichgeschwindigkeit', + 'HasWhiteSpeed' => 'Hat Weiß-Abgleichgeschwindigkeit', 'HasZoomSpeed' => 'Hat Zoom-Geschwindigkeit', 'High' => 'hohe', - 'HighBW' => 'Hohe B/W', + 'HighBW' => 'Hohe B/W', 'Home' => 'Home', 'Hour' => 'Stunde', 'Hue' => 'Farbton', @@ -367,22 +377,22 @@ $SLANG = array( 'Idle' => 'Leerlauf', 'Ignore' => 'Ignoriere', 'Image' => 'Bild', - 'ImageBufferSize' => 'Bildpuffergröße', + 'ImageBufferSize' => 'Bildpuffergröße', 'Images' => 'Bilder', 'In' => 'In', 'Include' => 'Einschluss', 'Inverted' => 'Invertiert', 'Iris' => 'Iris', - 'KeyString' => 'Schlüsselwort', + 'KeyString' => 'Schlüsselwort', 'Label' => 'Bezeichnung', 'Language' => 'Sprache', 'Last' => 'Letztes', 'Layout' => 'Layout', // Added - 2009-02-08 - 'Level' => 'Level', // Added - 2011-06-16 + 'Level' => 'Stufe', // Added - 2011-06-16 'Libvlc' => 'Libvlc', 'LimitResultsPost' => 'Ergebnisse;', // This is used at the end of the phrase 'Limit to first N results only' 'LimitResultsPre' => 'Begrenze nur auf die ersten', // This is used at the beginning of the phrase 'Limit to first N results only' - 'Line' => 'Line', // Added - 2011-06-16 + 'Line' => 'Zeile', // Added - 2011-06-16 'LinkedMonitors' => 'Verbundene Monitore', 'List' => 'Liste', 'Load' => 'Last', @@ -395,7 +405,7 @@ $SLANG = array( 'Logout' => 'Abmelden', 'Logs' => 'Logs', // Added - 2011-06-17 'Low' => 'niedrige', - 'LowBW' => 'Niedrige B/W', + 'LowBW' => 'Niedrige B/W', 'Main' => 'Haupt', 'Man' => 'Man', 'Manual' => 'Manual', @@ -406,9 +416,9 @@ $SLANG = array( 'MaxFocusRange' => 'Maximaler Fokusbereich', 'MaxFocusSpeed' => 'Maximale Fokusgeschwindigkeit', 'MaxFocusStep' => 'Maximale Fokusstufe', - 'MaxGainRange' => 'Maximaler Verstärkungsbereich', - 'MaxGainSpeed' => 'Maximale Verstärkungsgeschwindigkeit', - 'MaxGainStep' => 'Maximale Verstärkungsstufe', + 'MaxGainRange' => 'Maximaler Verstärkungsbereich', + 'MaxGainSpeed' => 'Maximale Verstärkungsgeschwindigkeit', + 'MaxGainStep' => 'Maximale Verstärkungsstufe', 'MaxIrisRange' => 'Maximaler Irisbereich', 'MaxIrisSpeed' => 'Maximale Irisgeschwindigkeit', 'MaxIrisStep' => 'Maximale Irisstufe', @@ -418,32 +428,32 @@ $SLANG = array( 'MaxTiltRange' => 'Maximaler Neig.-Bereich', 'MaxTiltSpeed' => 'Maximale Neig.-Geschw.', 'MaxTiltStep' => 'Maximale Neig.-Stufe', - 'MaxWhiteRange' => 'Maximaler Weiß-Abgl.bereich', - 'MaxWhiteSpeed' => 'Maximale Weiß-Abgl.geschw.', - 'MaxWhiteStep' => 'Maximale Weiß-Abgl.stufe', + 'MaxWhiteRange' => 'Maximaler Weiß-Abgl.bereich', + 'MaxWhiteSpeed' => 'Maximale Weiß-Abgl.geschw.', + 'MaxWhiteStep' => 'Maximale Weiß-Abgl.stufe', 'MaxZoomRange' => 'Maximaler Zoom-Bereich', 'MaxZoomSpeed' => 'Maximale Zoom-Geschw.', 'MaxZoomStep' => 'Maximale Zoom-Stufe', 'MaximumFPS' => 'Maximale FPS', 'Medium' => 'mittlere', - 'MediumBW' => 'Mittlere B/W', - 'Message' => 'Message', // Added - 2011-06-16 + 'MediumBW' => 'Mittlere B/W', + 'Message' => 'Nachricht', // Added - 2011-06-16 'MinAlarmAreaLtMax' => 'Der minimale Alarmbereich sollte kleiner sein als der maximale', - 'MinAlarmAreaUnset' => 'Sie müssen einen Minimumwert an Alarmflächenpixeln angeben', - 'MinBlobAreaLtMax' => 'Die minimale Blob-Fläche muss kleiner sein als die maximale', - 'MinBlobAreaUnset' => 'Sie müssen einen Minimumwert an Blobflächenpixeln angeben', - 'MinBlobLtMinFilter' => 'Die minimale Blob-Fläche sollte kleiner oder gleich der minimalen Filterfläche sein', - 'MinBlobsLtMax' => 'Die minimalen Blobs müssen kleiner sein als die maximalen', - 'MinBlobsUnset' => 'Sie müssen einen Minimumwert an Blobs angeben', - 'MinFilterAreaLtMax' => 'Die minimale Filterfläche sollte kleiner sein als die maximale', - 'MinFilterAreaUnset' => 'Sie müssen einen Minimumwert an Filterpixeln angeben', - 'MinFilterLtMinAlarm' => 'Die minimale Filterfläche sollte kleiner oder gleich der minimalen Alarmfläche sein', + 'MinAlarmAreaUnset' => 'Sie müssen einen Minimumwert an Alarmflächenpixeln angeben', + 'MinBlobAreaLtMax' => 'Die minimale Blob-Fläche muss kleiner sein als die maximale', + 'MinBlobAreaUnset' => 'Sie müssen einen Minimumwert an Blobflächenpixeln angeben', + 'MinBlobLtMinFilter' => 'Die minimale Blob-Fläche sollte kleiner oder gleich der minimalen Filterfläche sein', + 'MinBlobsLtMax' => 'Die minimalen Blobs müssen kleiner sein als die maximalen', + 'MinBlobsUnset' => 'Sie müssen einen Minimumwert an Blobs angeben', + 'MinFilterAreaLtMax' => 'Die minimale Filterfläche sollte kleiner sein als die maximale', + 'MinFilterAreaUnset' => 'Sie müssen einen Minimumwert an Filterpixeln angeben', + 'MinFilterLtMinAlarm' => 'Die minimale Filterfläche sollte kleiner oder gleich der minimalen Alarmfläche sein', 'MinFocusRange' => 'Min. Fokusbereich', 'MinFocusSpeed' => 'Min. Fokusgeschw.', 'MinFocusStep' => 'Min. Fokusstufe', - 'MinGainRange' => 'Min. Verstärkungsbereich', - 'MinGainSpeed' => 'Min. Verstärkungsgeschwindigkeit', - 'MinGainStep' => 'Min. Verstärkungsstufe', + 'MinGainRange' => 'Min. Verstärkungsbereich', + 'MinGainSpeed' => 'Min. Verstärkungsgeschwindigkeit', + 'MinGainStep' => 'Min. Verstärkungsstufe', 'MinIrisRange' => 'Min. Irisbereich', 'MinIrisSpeed' => 'Min. Irisgeschwindigkeit', 'MinIrisStep' => 'Min. Irisstufe', @@ -451,38 +461,40 @@ $SLANG = array( 'MinPanSpeed' => 'Min. Pan-Geschwindigkeit', 'MinPanStep' => 'Min. Pan-Stufe', 'MinPixelThresLtMax' => 'Der minimale Pixelschwellwert muss kleiner sein als der maximale', - 'MinPixelThresUnset' => 'Sie müssen einen minimalen Pixel-Schwellenwert angeben', + 'MinPixelThresUnset' => 'Sie müssen einen minimalen Pixel-Schwellenwert angeben', 'MinTiltRange' => 'Min. Neigungsbereich', 'MinTiltSpeed' => 'Min. Neigungsgeschwindigkeit', 'MinTiltStep' => 'Min. Neigungsstufe', - 'MinWhiteRange' => 'Min. Weiß-Abgleichbereich', - 'MinWhiteSpeed' => 'Min. Weiß-Abgleichgeschwindigkeit', - 'MinWhiteStep' => 'Min. Weiß-Abgleichstufe', + 'MinWhiteRange' => 'Min. Weiß-Abgleichbereich', + 'MinWhiteSpeed' => 'Min. Weiß-Abgleichgeschwindigkeit', + 'MinWhiteStep' => 'Min. Weiß-Abgleichstufe', 'MinZoomRange' => 'Min. Zoom-Bereich', 'MinZoomSpeed' => 'Min. Zoom-Geschwindigkeit', 'MinZoomStep' => 'Min. Zoom-Stufe', 'Misc' => 'Verschiedenes', + 'Mode' => 'Modus', // Added - 2015-04-18 'Monitor' => 'Monitor', 'MonitorIds' => 'Monitor-ID', 'MonitorPreset' => 'Monitor-Voreinstellung', - 'MonitorPresetIntro' => 'Wählen Sie eine geeignete Voreinstellung aus der folgenden Liste.

Bitte beachten Sie, dass dies mögliche Einstellungen von Ihnen am Monitor überschreiben kann.

', - 'MonitorProbe' => 'Monitor Probe', // Added - 2009-03-31 - 'MonitorProbeIntro' => 'The list below shows detected analog and network cameras and whether they are already being used or available for selection.

Select the desired entry from the list below.

Please note that not all cameras may be detected and that choosing a camera here may overwrite any values you already have configured for the current monitor.

', // Added - 2009-03-31 + 'MonitorPresetIntro' => 'Wählen Sie eine geeignete Voreinstellung aus der folgenden Liste.

Bitte beachten Sie, dass dies mögliche Einstellungen von Ihnen am Monitor überschreiben kann.

', + 'MonitorProbe' => 'Kamera suche', // Added - 2009-03-31 + 'MonitorProbeIntro' => 'Die nachfolgende Liste zeigt erkannte Analog- und Netzwerkkameras, ob sie bereits genutzt werden und ob sie zur Auswahl verfügbar sind.

Wähle den gewünschten Eintrag aus der folgenden Liste.

Bitte Beachten: Nicht alle Kameras können erkannt werden. Die Auswahl einer Kamera kann bereits eingetragene Werte im aktuellen Monitor überschreiben.

', // Added - 2009-03-31 'Monitors' => 'Monitore', 'Montage' => 'Montage', 'Month' => 'Monat', - 'More' => 'More', // Added - 2011-06-16 + 'More' => 'Mehr', // Added - 2011-06-16 + 'MotionFrameSkip' => 'Motion Frame Skip', 'Move' => 'Bewegung', - 'MtgDefault' => 'Default', // Added 2013.08.15. - 'Mtg2widgrd' => '2-wide grid', // Added 2013.08.15. - 'Mtg3widgrd' => '3-wide grid', // Added 2013.08.15. - 'Mtg4widgrd' => '4-wide grid', // Added 2013.08.15. - 'Mtg3widgrx' => '3-wide grid, scaled, enlarge on alarm', // Added 2013.08.15. + 'Mtg2widgrd' => '2 Spalten', // Added 2013.08.15. + 'Mtg3widgrd' => '3 Spalten', // Added 2013.08.15. + 'Mtg3widgrx' => '3 Spalten, skaliert, vergr. bei Alarm', // Added 2013.08.15. + 'Mtg4widgrd' => '4 Spalten', // Added 2013.08.15. + 'MtgDefault' => 'Standard', // Added 2013.08.15. 'MustBeGe' => 'muss groesser oder gleich sein wie', 'MustBeLe' => 'muss kleiner oder gleich sein wie', - 'MustConfirmPassword' => 'Sie müssen das Passwort bestätigen.', - 'MustSupplyPassword' => 'Sie müssen ein Passwort vergeben.', - 'MustSupplyUsername' => 'Sie müssen einen Usernamen vergeben.', + 'MustConfirmPassword' => 'Sie müssen das Passwort bestätigen.', + 'MustSupplyPassword' => 'Sie müssen ein Passwort vergeben.', + 'MustSupplyUsername' => 'Sie müssen einen Usernamen vergeben.', 'Name' => 'Name', 'Near' => 'Nah', 'Network' => 'Netzwerk', @@ -492,20 +504,23 @@ $SLANG = array( 'NewPassword' => 'Neues Passwort', 'NewState' => 'Neuer Status', 'NewUser' => 'Neuer Benutzer', - 'Next' => 'Nächstes', + 'Next' => 'Nächstes', 'No' => 'Nein', - 'NoDetectedCameras' => 'No Detected Cameras', // Added - 2009-03-31 + 'NoDetectedCameras' => 'Keine Kameras erkannt', // Added - 2009-03-31 'NoFramesRecorded' => 'Es gibt keine Aufnahmen von diesem Ereignis.', 'NoGroup' => 'Keine Gruppe', 'NoSavedFilters' => 'Keine gespeicherten Filter', - 'NoStatisticsRecorded' => 'Keine Statistik für dieses Ereignis/diese Bilder', + 'NoStatisticsRecorded' => 'Keine Statistik für dieses Ereignis/diese Bilder', 'None' => 'ohne', - 'NoneAvailable' => 'Nichts verfügbar', + 'NoneAvailable' => 'Nichts verfügbar', 'Normal' => 'Normal', 'Notes' => 'Bemerkungen', 'NumPresets' => 'Nummerierte Voreinstellungen', 'Off' => 'Aus', 'On' => 'An', + 'OnvifCredentialsIntro'=> 'Bitte den Benutzernamen und das Passwort für die gewählte Kamera eintragen.
Der hier eingetragene Benutzer wird erstellt mitsamt des Passworts, falls kein Benutzer für diese Kamera erstellt wurde.

', // Added - 2015-04-18 + 'OnvifProbe' => 'ONVIF', // Added - 2015-04-18 + 'OnvifProbeIntro' => 'Die folgende Liste zeigt erkannte ONVIF Kameras, ob sie bereits genutzt werden und ob sie zur Auswahl verfügbar sind.

Wähle den gewünschten Eintrag aus der folgenden Liste.

Bitte Beachten: Nicht alle Kameras können erkannt werden. Die Auswahl einer Kamera kann bereits eingetragene Werte im aktuellen Monitor überschreiben.

', // Added - 2015-04-18 'OpEq' => 'gleich zu', 'OpGt' => 'groesser als', 'OpGtEq' => 'groesser oder gleich wie', @@ -516,15 +531,15 @@ $SLANG = array( 'OpNe' => 'nicht gleich', 'OpNotIn' => 'nicht im Satz', 'OpNotMatches' => 'nicht zutreffend', - 'Open' => 'Öffnen', + 'Open' => 'öffnen', 'OptionHelp' => 'Hilfe', - 'OptionRestartWarning' => 'Veränderungen werden erst nach einem Neustart des Programms aktiv.\nFür eine sofortige Änderung starten Sie das Programm bitte neu.', + 'OptionRestartWarning' => 'Veränderungen werden erst nach einem Neustart des Programms aktiv.\nFür eine sofortige änderung starten Sie das Programm bitte neu.', 'Options' => 'Optionen', 'OrEnterNewName' => 'oder neuen Namen eingeben', 'Order' => 'Reihenfolge', 'Orientation' => 'Ausrichtung', 'Out' => 'Aus', - 'OverwriteExisting' => 'Überschreibe bestehende', + 'OverwriteExisting' => 'überschreibe bestehende', 'Paged' => 'Seitennummeriert', 'Pan' => 'Pan', 'PanLeft' => 'Pan-Left', @@ -532,11 +547,11 @@ $SLANG = array( 'PanTilt' => 'Pan/Neigung', 'Parameter' => 'Parameter', 'Password' => 'Passwort', - 'PasswordsDifferent' => 'Die Passwörter sind unterschiedlich', + 'PasswordsDifferent' => 'Die Passwörter sind unterschiedlich', 'Paths' => 'Pfade', 'Pause' => 'Pause', 'Phone' => 'Telefon', - 'PhoneBW' => 'Tel. B/W', + 'PhoneBW' => 'Tel. B/W', 'Pid' => 'PID', // Added - 2011-06-16 'PixelDiff' => 'Pixel-Differenz', 'Pixels' => 'Pixel', @@ -547,57 +562,60 @@ $SLANG = array( 'Point' => 'Punkt', 'PostEventImageBuffer' => 'Nachereignispuffer', 'PreEventImageBuffer' => 'Vorereignispuffer', - 'PreserveAspect' => 'Seitenverhältnis beibehalten', + 'PreserveAspect' => 'Seitenverhältnis beibehalten', 'Preset' => 'Voreinstellung', 'Presets' => 'Voreinstellungen', 'Prev' => 'Vorheriges', - 'Probe' => 'Probe', // Added - 2009-03-31 + 'Probe' => 'Sonde', // Added - 2009-03-31 + 'ProfileProbe' => 'Streamsonde', // Added - 2015-04-18 + 'ProfileProbeIntro' => 'Die folgende Liste zeigt die verfügbaren Streamingprofile der ausgewählten Kamera.

Wähle den gewünschten Eintrag aus der folgenden Liste.

Bitte Beachten: Zoneminder kann keine zusätzlichen Profile konfigurieren. Die Auswahl einer Kamera kann bereits eingetragene Werte im aktuellen Monitor überschreiben.

', // Added - 2015-04-18 + 'Progress' => 'Fortschritt', // Added - 2015-04-18 'Protocol' => 'Protokoll', 'Rate' => 'Abspielgeschwindigkeit', 'Real' => 'Real', 'Record' => 'Aufnahme', 'RefImageBlendPct' => 'Referenz-Bildblende', 'Refresh' => 'Aktualisieren', - 'Remote' => 'Entfernt', - 'RemoteHostName' => 'Entfernter Hostname', - 'RemoteHostPath' => 'Entfernter Hostpfad', - 'RemoteHostPort' => 'Entfernter Hostport', - 'RemoteHostSubPath' => 'Remote Host SubPath', // Added - 2009-02-08 - 'RemoteImageColours' => 'Entfernte Bildfarbe', - 'RemoteMethod' => 'Remote Method', // Added - 2009-02-08 - 'RemoteProtocol' => 'Remote Protocol', // Added - 2009-02-08 + 'Remote' => 'Remote', + 'RemoteHostName' => 'Remote Hostname', + 'RemoteHostPath' => 'Remote Hostpfad', + 'RemoteHostPort' => 'Remote Hostport', + 'RemoteHostSubPath' => 'Remote Hostunterpfad', // Added - 2009-02-08 + 'RemoteImageColours' => 'Remote Bildfarbe', + 'RemoteMethod' => 'Remote Methode', // Added - 2009-02-08 + 'RemoteProtocol' => 'Remote Protokol', // Added - 2009-02-08 'Rename' => 'Umbenennen', 'Replay' => 'Wiederholung', 'ReplayAll' => 'Alle Ereignisse', - 'ReplayGapless' => 'Lückenlose Ereignisse', + 'ReplayGapless' => 'Lückenlose Ereignisse', 'ReplaySingle' => 'Einzelereignis', - 'Reset' => 'Zurücksetzen', - 'ResetEventCounts' => 'Lösche Ereignispunktzahl', + 'Reset' => 'Zurücksetzen', + 'ResetEventCounts' => 'Lösche Ereignispunktzahl', 'Restart' => 'Neustart', 'Restarting' => 'Neustarten', 'RestrictedCameraIds' => 'Verbotene Kamera-ID', - 'RestrictedMonitors' => 'Eingeschränkte Monitore', - 'ReturnDelay' => 'Rückkehr-Verzögerung', - 'ReturnLocation' => 'Rückkehrpunkt', - 'Rewind' => 'Zurückspulen', + 'RestrictedMonitors' => 'Eingeschränkte Monitore', + 'ReturnDelay' => 'Rückkehr-Verzögerung', + 'ReturnLocation' => 'Rückkehrpunkt', + 'Rewind' => 'Zurückspulen', 'RotateLeft' => 'Drehung links', 'RotateRight' => 'Drehung rechts', - 'RunLocalUpdate' => 'Please run zmupdate.pl to update', // Added - 2011-05-25 + 'RunLocalUpdate' => 'Bitte zmupdate.pl starten um upzudaten.', // Added - 2011-05-25 'RunMode' => 'Betriebsmodus', 'RunState' => 'Laufender Status', 'Running' => 'In Betrieb', - 'Save' => 'OK', + 'Save' => 'Speichern', 'SaveAs' => 'Speichere als', 'SaveFilter' => 'Speichere Filter', 'Scale' => 'Skalierung', 'Score' => 'Punktzahl', 'Secs' => 'Sekunden', - 'Sectionlength' => 'Sektionslänge', + 'Sectionlength' => 'Sektionslänge', 'Select' => 'Auswahl', - 'SelectFormat' => 'Select Format', // Added - 2011-06-17 - 'SelectLog' => 'Select Log', // Added - 2011-06-17 - 'SelectMonitors' => 'Wähle Monitore', - 'SelfIntersecting' => 'Die Polygonränder dürfen sich nicht überschneiden.', + 'SelectFormat' => 'Format Auswahl', // Added - 2011-06-17 + 'SelectLog' => 'Log Auswahl', // Added - 2011-06-17 + 'SelectMonitors' => 'Wähle Monitore', + 'SelfIntersecting' => 'Die Polygonränder dürfen sich nicht überschneiden.', 'Set' => 'Setze', 'SetNewBandwidth' => 'Setze neue Bandbreite', 'SetPreset' => 'Setze Voreinstellung', @@ -605,15 +623,15 @@ $SLANG = array( 'ShowFilterWindow' => 'Zeige Filterfenster', 'ShowTimeline' => 'Zeige Zeitlinie', 'SignalCheckColour' => 'Farbe des Signalchecks', - 'Size' => 'Größe', - 'SkinDescription' => 'Change the default skin for this computer', // Added - 2011-01-30 + 'Size' => 'Größe', + 'SkinDescription' => 'Wähle den standard Skin für diesen Computer.', // Added - 2011-01-30 'Sleep' => 'Schlaf', 'SortAsc' => 'aufsteigend', 'SortBy' => 'Sortieren nach', 'SortDesc' => 'absteigend', 'Source' => 'Quelle', - 'SourceColours' => 'Source Colours', // Added - 2009-02-08 - 'SourcePath' => 'Source Path', // Added - 2009-02-08 + 'SourceColours' => 'Quellenfarben', // Added - 2009-02-08 + 'SourcePath' => 'Quellenpfad', // Added - 2009-02-08 'SourceType' => 'Quellentyp', 'Speed' => 'Geschwindigkeit', 'SpeedHigh' => 'Hohe Geschwindigkeit', @@ -625,9 +643,9 @@ $SLANG = array( 'Stats' => 'Status', 'Status' => 'Status', 'Step' => 'Stufe', - 'StepBack' => 'Einen Schritt rückwärts', - 'StepForward' => 'Einen Schritt vorwärts', - 'StepLarge' => 'Große Stufe', + 'StepBack' => 'Einen Schritt rückwärts', + 'StepForward' => 'Einen Schritt vorwärts', + 'StepLarge' => 'Große Stufe', 'StepMedium' => 'Mittlere Stufe', 'StepNone' => 'Keine Stufe', 'StepSmall' => 'Kleine Stufe', @@ -639,6 +657,7 @@ $SLANG = array( 'Submit' => 'Absenden', 'System' => 'System', 'SystemLog' => 'System Log', // Added - 2011-06-16 + 'TargetColorspace' => 'Zielfarbbereich', // Added - 2015-04-18 'Tele' => 'Tele', 'Thumbnail' => 'Miniatur', 'Tilt' => 'Neigung', @@ -646,10 +665,10 @@ $SLANG = array( 'TimeDelta' => 'Zeitdifferenz', 'TimeStamp' => 'Zeitstempel', 'Timeline' => 'Zeitlinie', - 'TimelineTip1' => 'Pass your mouse over the graph to view a snapshot image and event details.', // Added 2013.08.15. - 'TimelineTip2' => 'Click on the coloured sections of the graph, or the image, to view the event.', // Added 2013.08.15. - 'TimelineTip3' => 'Click on the background to zoom in to a smaller time period based around your click.', // Added 2013.08.15. - 'TimelineTip4' => 'Use the controls below to zoom out or navigate back and forward through the time range.', // Added 2013.08.15. + 'TimelineTip1' => 'Bewege die Maus über dem Graphen um eine Vorschau und Ereignisdetails zu sehen.', // Added 2013.08.15. + 'TimelineTip2' => 'Clicke auf den farbigen Abschnitt des Graphen oder auf das Bild um den Ereignis zu betrachten', // Added 2013.08.15. + 'TimelineTip3' => 'Clicke auf den Hintergrund, um in den Zeitabschnitt um das Ereignis hereinzuzoomen.', // Added 2013.08.15. + 'TimelineTip4' => 'Benutze die unteren Bedienelemente um herauszuzoomen oder sich in der Zeitleiste zu bewegen.', // Added 2013.08.15. 'Timestamp' => 'Zeitstempel', 'TimestampLabelFormat' => 'Format des Zeitstempels', 'TimestampLabelX' => 'Zeitstempel-X', @@ -658,34 +677,37 @@ $SLANG = array( 'Tools' => 'Werkzeuge', 'Total' => 'Total', // Added - 2011-06-16 'TotalBrScore' => 'Totale
Punktzahl', - 'TrackDelay' => 'Nachführungsverzögerung', - 'TrackMotion' => 'Bewegungs-Nachführung', - 'Triggers' => 'Auslöser', + 'TrackDelay' => 'Nachführungsverzögerung', + 'TrackMotion' => 'Bewegungs-Nachführung', + 'Triggers' => 'Auslöser', 'TurboPanSpeed' => 'Turbo-Pan-Geschwindigkeit', 'TurboTiltSpeed' => 'Turbo-Neigungsgeschwindigkeit', 'Type' => 'Typ', 'Unarchive' => 'Aus Archiv entfernen', - 'Undefined' => 'Undefined', // Added - 2009-02-08 + 'Undefined' => 'Undefiniert', // Added - 2009-02-08 'Units' => 'Einheiten', 'Unknown' => 'Unbekannt', 'Update' => 'Aktualisieren', - 'UpdateAvailable' => 'Eine Aktualisierung für ZoneMinder ist verfügbar.', - 'UpdateNotNecessary' => 'Es ist keine Aktualisierung verfügbar.', - 'Updated' => 'Updated', // Added - 2011-06-16 - 'Upload' => 'Upload', // Added - 2011-08-23 - 'UsedPlugins' => 'Used Plugins', + 'UpdateAvailable' => 'Eine Aktualisierung für ZoneMinder ist verfügbar.', + 'UpdateNotNecessary' => 'Es ist keine Aktualisierung verfügbar.', + 'Updated' => 'Aktualisiert', // Added - 2011-06-16 + 'Upload' => 'Hochladen', // Added - 2011-08-23 'UseFilter' => 'Benutze Filter', - 'UseFilterExprsPost' => ' Filter Ausdrücke', // This is used at the end of the phrase 'use N filter expressions' - 'UseFilterExprsPre' => 'Benutze ', // This is used at the beginning of the phrase 'use N filter expressions' + 'UseFilterExprsPost' => ' Filter Ausdrücke', // This is used at the end of the phrase 'use N filter expressions' + 'UseFilterExprsPre' => 'Benutze ', // This is used at the beginning of the phrase 'use N filter expressions' + 'UsedPlugins' => 'Used Plugins', 'User' => 'Benutzer', 'Username' => 'Benutzername', 'Users' => 'Benutzer', + 'V4L' => 'V4L', // Added - 2015-04-18 + 'V4LCapturesPerFrame' => 'Aufnahmen pro Bild', // Added - 2015-04-18 + 'V4LMultiBuffer' => 'Multi Buffering', // Added - 2015-04-18 'Value' => 'Wert', 'Version' => 'Version', 'VersionIgnore' => 'Ignoriere diese Version', 'VersionRemindDay' => 'Erinnere mich wieder in 1 Tag.', 'VersionRemindHour' => 'Erinnere mich wieder in 1 Stunde.', - 'VersionRemindNever' => 'Informiere mich nicht mehr über neue Versionen.', + 'VersionRemindNever' => 'Informiere mich nicht mehr über neue Versionen.', 'VersionRemindWeek' => 'Erinnere mich wieder in 1 Woche.', 'Video' => 'Video', 'VideoFormat' => 'Videoformat', @@ -694,19 +716,19 @@ $SLANG = array( 'VideoGenNoFiles' => 'Keine Videodateien gefunden.', 'VideoGenParms' => 'Parameter der Videoerzeugung', 'VideoGenSucceeded' => 'Videoerzeugung erfolgreich!', - 'VideoSize' => 'Videogröße', + 'VideoSize' => 'Videogröße', 'View' => 'Ansicht', 'ViewAll' => 'Alles ansehen', 'ViewEvent' => 'Zeige Ereignis', 'ViewPaged' => 'Seitenansicht', 'Wake' => 'Aufwachen', - 'WarmupFrames' => 'Aufwärmbilder', + 'WarmupFrames' => 'Aufwärmbilder', 'Watch' => 'Beobachte', 'Web' => 'Web', 'WebColour' => 'Webfarbe', 'Week' => 'Woche', - 'White' => 'Weiß', - 'WhiteBalance' => 'Weiß-Abgleich', + 'White' => 'Weiß', + 'WhiteBalance' => 'Weiß-Abgleich', 'Wide' => 'Weit', 'X' => 'X', 'X10' => 'X10', @@ -717,17 +739,17 @@ $SLANG = array( 'Yes' => 'Ja', 'YouNoPerms' => 'Keine Erlaubnis zum Zugang dieser Resource.', 'Zone' => 'Zone', - 'ZoneAlarmColour' => 'Alarmfarbe (Rot/Grün/Blau)', + 'ZoneAlarmColour' => 'Alarmfarbe (Rot/Grün/Blau)', 'ZoneArea' => 'Zone Area', - 'ZoneFilterSize' => 'Filter-Breite/-Höhe (Pixel)', - 'ZoneMinMaxAlarmArea' => 'Min./max. Alarmfläche', - 'ZoneMinMaxBlobArea' => 'Min./max. Blobfläche', + 'ZoneExtendAlarmFrames' => 'Alarmstatus nach Ende für Frames aufrechterhalten', + 'ZoneFilterSize' => 'Filter-Breite/-Höhe (Pixel)', + 'ZoneMinMaxAlarmArea' => 'Min./max. Alarmfläche', + 'ZoneMinMaxBlobArea' => 'Min./max. Blobfläche', 'ZoneMinMaxBlobs' => 'Min./max. Blobs', - 'ZoneMinMaxFiltArea' => 'Min./max. Filterfläche', + 'ZoneMinMaxFiltArea' => 'Min./max. Filterfläche', 'ZoneMinMaxPixelThres' => 'Min./max. Pixelschwellwert', 'ZoneMinderLog' => 'ZoneMinder Log', // Added - 2011-06-17 - 'ZoneOverloadFrames' => 'Bildauslassrate bei Systemüberlastung', - 'ZoneExtendAlarmFrames' => 'Alarmstatus nach Ende für Frames aufrechterhalten', + 'ZoneOverloadFrames' => 'Bildauslassrate bei Systemüberlastung', 'Zones' => 'Zonen', 'Zoom' => 'Zoom', 'ZoomIn' => 'Hineinzoomen', diff --git a/web/lang/dk_dk.php b/web/lang/dk_dk.php index 927440513..08795edf4 100644 --- a/web/lang/dk_dk.php +++ b/web/lang/dk_dk.php @@ -89,6 +89,7 @@ $SLANG = array( 'AlarmMaximumFPS' => 'Alarm Maximum FPS', 'AlarmPx' => 'Alarm Px', 'AlarmRGBUnset' => 'You must set an alarm RGB colour', + 'AlarmRefImageBlendPct'=> 'Alarm Reference Image Blend %ge', // Added - 2015-04-18 'Alert' => 'Alarm', 'All' => 'Alle', 'Apply' => 'Aktiver', @@ -133,13 +134,13 @@ $SLANG = array( 'BadFPSReportInterval' => 'FPS report interval buffer count must be an integer of 0 or more', 'BadFormat' => 'Format must be set to an integer of zero or more', 'BadFrameSkip' => 'Frame skip count must be an integer of zero or more', - 'BadMotionFrameSkip' => 'Motion Frame skip count must be an integer of zero or more', 'BadHeight' => 'Height must be set to a valid value', 'BadHost' => 'Host must be set to a valid ip address or hostname, do not include http://', 'BadImageBufferCount' => 'Image buffer size must be an integer of 10 or more', 'BadLabelX' => 'Label X co-ordinate must be set to an integer of zero or more', 'BadLabelY' => 'Label Y co-ordinate must be set to an integer of zero or more', 'BadMaxFPS' => 'Maximum FPS must be a positive integer or floating point value', + 'BadMotionFrameSkip' => 'Motion Frame skip count must be an integer of zero or more', 'BadNameChars' => 'Navne m kun indeholde alphanumeric karaktere plus hyphen og underscore', 'BadPalette' => 'Palette must be set to a valid value', // Added - 2009-03-31 'BadPath' => 'Path must be set to a valid value', @@ -159,7 +160,9 @@ $SLANG = array( 'BlobSizes' => 'Blob Strelse', 'Blobs' => 'Blobs', 'Brightness' => 'Brightness', + 'Buffer' => 'Buffer', // Added - 2015-04-18 'Buffers' => 'Buffere', + 'CSSDescription' => 'Change the default css for this computer', // Added - 2015-04-18 'CanAutoFocus' => 'Kan Auto Focus', 'CanAutoGain' => 'Kan Auto Gain', 'CanAutoIris' => 'Kan Auto Iris', @@ -203,6 +206,7 @@ $SLANG = array( 'CaptureHeight' => 'Capture Height', 'CaptureMethod' => 'Capture Method', // Added - 2009-02-08 'CapturePalette' => 'Capture Palette', + 'CaptureResolution' => 'Capture Resolution', // Added - 2015-04-18 'CaptureWidth' => 'Capture Width', 'Cause' => 'rsag', 'CheckMethod' => 'Alarm Check Methode', @@ -233,6 +237,7 @@ $SLANG = array( 'ControlDevice' => 'Kontrol Enhed', 'ControlType' => 'Kontrol Type', 'Controllable' => 'Controllable', + 'Current' => 'Current', // Added - 2015-04-18 'Cycle' => 'Cycle', 'CycleWatch' => 'Cycle Watch', 'DateTime' => 'Date/Time', // Added - 2011-06-16 @@ -241,12 +246,15 @@ $SLANG = array( 'DefaultRate' => 'Default Rate', 'DefaultScale' => 'Default Scale', 'DefaultView' => 'Default View', + 'Deinterlacing' => 'Deinterlacing', // Added - 2015-04-18 + 'Delay' => 'Delay', // Added - 2015-04-18 'Delete' => 'Slet', 'DeleteAndNext' => 'Slet & Nste', 'DeleteAndPrev' => 'Slet & Forrige', 'DeleteSavedFilter' => 'Slet Gemte filter', 'Description' => 'Beskrivelse', 'DetectedCameras' => 'Detected Cameras', // Added - 2009-03-31 + 'DetectedProfiles' => 'Detected Profiles', // Added - 2015-04-18 'Device' => 'Device', // Added - 2009-02-08 'DeviceChannel' => 'Enheds Kanal', 'DeviceFormat' => 'Enheds Format', @@ -258,6 +266,7 @@ $SLANG = array( 'Disk' => 'Disk', 'Display' => 'Display', // Added - 2011-01-30 'Displaying' => 'Displaying', // Added - 2011-06-16 + 'DoNativeMotionDetection'=> 'Do Native Motion Detection', 'Donate' => 'Please Donate', 'DonateAlready' => 'No, I\'ve already donated', 'DonateEnticement' => 'You\'ve been running ZoneMinder for a while now and hopefully are finding it a useful addition to your home or workplace security. Although ZoneMinder is, and will remain, free and open source, it costs money to develop and support. If you would like to help support future development and new features then please consider donating. Donating is, of course, optional but very much appreciated and you can donate as much or as little as you like.

If you would like to donate please select the option below or go to http://www.zoneminder.com/donate.html in your browser.

Thank you for using ZoneMinder and don\'t forget to visit the forums on ZoneMinder.com for support or suggestions about how to make your ZoneMinder experience even better.', @@ -267,7 +276,6 @@ $SLANG = array( 'DonateRemindNever' => 'No, I don\'t want to donate, never remind', 'DonateRemindWeek' => 'Not yet, remind again in 1 week', 'DonateYes' => 'Yes, I\'d like to donate now', - 'DoNativeMotionDetection'=> 'Do Native Motion Detection', 'Download' => 'Download', 'DuplicateMonitorName' => 'Duplicate Monitor Name', // Added - 2009-03-31 'Duration' => 'Forlb', @@ -310,10 +318,12 @@ $SLANG = array( 'Feed' => 'Feed', 'Ffmpeg' => 'Ffmpeg', // Added - 2009-02-08 'File' => 'File', + 'Filter' => 'Filter', // Added - 2015-04-18 'FilterArchiveEvents' => 'Arkiver alle matchende', 'FilterDeleteEvents' => 'Slet alle matchende', 'FilterEmailEvents' => 'Email detalier af alle matchende', 'FilterExecuteEvents' => 'Kr kommando p alle matchende', + 'FilterLog' => 'Filter log', // Added - 2015-04-18 'FilterMessageEvents' => 'Send detalier af alle matchende', 'FilterPx' => 'Filter Px', 'FilterUnset' => 'You must specify a filter width and height', @@ -323,12 +333,12 @@ $SLANG = array( 'First' => 'Frste', 'FlippedHori' => 'Flipped Horizontally', 'FlippedVert' => 'Flipped Vertically', - 'FnNone' => 'None', // Added 2013.08.16. - 'FnMonitor' => 'Monitor', // Added 2013.08.16. - 'FnModect' => 'Modect', // Added 2013.08.16. - 'FnRecord' => 'Record', // Added 2013.08.16. 'FnMocord' => 'Mocord', // Added 2013.08.16. + 'FnModect' => 'Modect', // Added 2013.08.16. + 'FnMonitor' => 'Monitor', // Added 2013.08.16. 'FnNodect' => 'Nodect', // Added 2013.08.16. + 'FnNone' => 'None', // Added 2013.08.16. + 'FnRecord' => 'Record', // Added 2013.08.16. 'Focus' => 'Fokus', 'ForceAlarm' => 'Tving Alarm', 'Format' => 'Format', @@ -336,7 +346,6 @@ $SLANG = array( 'FrameId' => 'Billede Id', 'FrameRate' => 'Billede Rate', 'FrameSkip' => 'Billede Skip', - 'MotionFrameSkip' => 'Motion Frame Skip', 'Frames' => 'Billede', 'Func' => 'Func', 'Function' => 'Funktion', @@ -463,6 +472,7 @@ $SLANG = array( 'MinZoomSpeed' => 'Min Zoom Speed', 'MinZoomStep' => 'Min Zoom Step', 'Misc' => 'Misc', + 'Mode' => 'Mode', // Added - 2015-04-18 'Monitor' => 'Monitor', 'MonitorIds' => 'Monitor Ids', 'MonitorPreset' => 'Monitor Preset', @@ -473,12 +483,13 @@ $SLANG = array( 'Montage' => 'Montage', 'Month' => 'Mned', 'More' => 'More', // Added - 2011-06-16 + 'MotionFrameSkip' => 'Motion Frame Skip', 'Move' => 'Flyt', - 'MtgDefault' => 'Default', // Added 2013.08.15. 'Mtg2widgrd' => '2-wide grid', // Added 2013.08.15. 'Mtg3widgrd' => '3-wide grid', // Added 2013.08.15. - 'Mtg4widgrd' => '4-wide grid', // Added 2013.08.15. 'Mtg3widgrx' => '3-wide grid, scaled, enlarge on alarm', // Added 2013.08.15. + 'Mtg4widgrd' => '4-wide grid', // Added 2013.08.15. + 'MtgDefault' => 'Default', // Added 2013.08.15. 'MustBeGe' => 'skal vre stre end eller ligmed', 'MustBeLe' => 'Skal vre mindre end eller ligmed', 'MustConfirmPassword' => 'Du skal konfimere password', @@ -507,6 +518,9 @@ $SLANG = array( 'NumPresets' => 'Num Presets', 'Off' => 'Off', 'On' => 'On', + 'OnvifCredentialsIntro'=> 'Please supply user name and password for the selected camera.
If no user has been created for the camera then the user given here will be created with the given password.

', // Added - 2015-04-18 + 'OnvifProbe' => 'ONVIF', // Added - 2015-04-18 + 'OnvifProbeIntro' => 'The list below shows detected ONVIF cameras and whether they are already being used or available for selection.

Select the desired entry from the list below.

Please note that not all cameras may be detected and that choosing a camera here may overwrite any values you already have configured for the current monitor.

', // Added - 2015-04-18 'OpEq' => 'ligmed', 'OpGt' => 'stre end', 'OpGtEq' => 'stre end eller ligmed', @@ -553,6 +567,9 @@ $SLANG = array( 'Presets' => 'Presets', 'Prev' => 'Prev', 'Probe' => 'Probe', // Added - 2009-03-31 + 'ProfileProbe' => 'Stream Probe', // Added - 2015-04-18 + 'ProfileProbeIntro' => 'The list below shows the existing stream profiles of the selected camera .

Select the desired entry from the list below.

Please note that ZoneMinder cannot configure additional profiles and that choosing a camera here may overwrite any values you already have configured for the current monitor.

', // Added - 2015-04-18 + 'Progress' => 'Progress', // Added - 2015-04-18 'Protocol' => 'Protocol', 'Rate' => 'Rate', 'Real' => 'Real', @@ -640,6 +657,7 @@ $SLANG = array( 'Submit' => 'Submit', 'System' => 'System', 'SystemLog' => 'System Log', // Added - 2011-06-16 + 'TargetColorspace' => 'Target colorspace', // Added - 2015-04-18 'Tele' => 'Tele', 'Thumbnail' => 'Thumbnail', 'Tilt' => 'Tilt', @@ -674,13 +692,16 @@ $SLANG = array( 'UpdateNotNecessary' => 'Ingen updatering er ndvendig.', 'Updated' => 'Updated', // Added - 2011-06-16 'Upload' => 'Upload', // Added - 2011-08-23 - 'UsedPlugins' => 'Used Plugins', 'UseFilter' => 'Brug Filter', 'UseFilterExprsPost' => ' filter expressions', // This is used at the end of the phrase 'use N filter expressions' 'UseFilterExprsPre' => 'Brug ', // This is used at the beginning of the phrase 'use N filter expressions' + 'UsedPlugins' => 'Used Plugins', 'User' => 'Bruger', 'Username' => 'Bruger Navn', 'Users' => 'Brugere', + 'V4L' => 'V4L', // Added - 2015-04-18 + 'V4LCapturesPerFrame' => 'Captures Per Frame', // Added - 2015-04-18 + 'V4LMultiBuffer' => 'Multi Buffering', // Added - 2015-04-18 'Value' => 'Vrdig', 'Version' => 'Version', 'VersionIgnore' => 'Ignorer denne version', @@ -720,6 +741,7 @@ $SLANG = array( 'Zone' => 'Zone', 'ZoneAlarmColour' => 'Alarm Farve (Red/Green/Blue)', 'ZoneArea' => 'Zone Area', + 'ZoneExtendAlarmFrames' => 'Extend Alarm Frame Count', 'ZoneFilterSize' => 'Filter Width/Height (pixels)', 'ZoneMinMaxAlarmArea' => 'Min/Max Alarmed Area', 'ZoneMinMaxBlobArea' => 'Min/Max Blob Area', @@ -728,7 +750,6 @@ $SLANG = array( 'ZoneMinMaxPixelThres' => 'Min/Max Pixel Threshold (0-255)', 'ZoneMinderLog' => 'ZoneMinder Log', // Added - 2011-06-17 'ZoneOverloadFrames' => 'Overload Frame Ignore Count', - 'ZoneExtendAlarmFrames' => 'Extend Alarm Frame Count', 'Zones' => 'Zoner', 'Zoom' => 'Zoom', 'ZoomIn' => 'Zoom In', diff --git a/web/lang/en_gb.php b/web/lang/en_gb.php index 77c968645..ceaabad02 100644 --- a/web/lang/en_gb.php +++ b/web/lang/en_gb.php @@ -96,6 +96,7 @@ $SLANG = array( 'AlarmLimits' => 'Alarm Limits', 'AlarmMaximumFPS' => 'Alarm Maximum FPS', 'AlarmPx' => 'Alarm Px', + 'AlarmRefImageBlendPct' => 'Alarm Reference Image Blend %ge', 'AlarmRGBUnset' => 'You must set an alarm RGB colour', 'Alert' => 'Alert', 'All' => 'All', @@ -168,6 +169,7 @@ $SLANG = array( 'Blobs' => 'Blobs', 'BlobSizes' => 'Blob Sizes', 'Brightness' => 'Brightness', + 'Buffer' => 'Buffer', 'Buffers' => 'Buffers', 'CanAutoFocus' => 'Can Auto Focus', 'CanAutoGain' => 'Can Auto Gain', @@ -241,6 +243,7 @@ $SLANG = array( 'ControlDevice' => 'Control Device', 'Controllable' => 'Controllable', 'ControlType' => 'Control Type', + 'Current' => 'Current', 'Cycle' => 'Cycle', 'CycleWatch' => 'Cycle Watch', 'Day' => 'Day', @@ -248,6 +251,8 @@ $SLANG = array( 'DefaultRate' => 'Default Rate', 'DefaultScale' => 'Default Scale', 'DefaultView' => 'Default View', + 'Deinterlacing' => 'Deinterlacing', + 'Delay' => 'Delay', 'DeleteAndNext' => 'Delete & Next', 'DeleteAndPrev' => 'Delete & Prev', 'Delete' => 'Delete', @@ -319,8 +324,10 @@ $SLANG = array( 'FilterDeleteEvents' => 'Delete all matches', 'FilterEmailEvents' => 'Email details of all matches', 'FilterExecuteEvents' => 'Execute command on all matches', + 'FilterLog' => 'Filter log', 'FilterMessageEvents' => 'Message details of all matches', 'FilterPx' => 'Filter Px', + 'Filter' => 'Filter', 'Filters' => 'Filters', 'FilterUnset' => 'You must specify a filter width and height', 'FilterUploadEvents' => 'Upload all matches', @@ -468,6 +475,7 @@ $SLANG = array( 'MinZoomSpeed' => 'Min Zoom Speed', 'MinZoomStep' => 'Min Zoom Step', 'Misc' => 'Misc', + 'Mode' => 'Mode', 'MonitorIds' => 'Monitor Ids', 'Monitor' => 'Monitor', 'MonitorPresetIntro' => 'Select an appropriate preset from the list below.

Please note that this may overwrite any values you already have configured for the current monitor.

', @@ -561,6 +569,7 @@ $SLANG = array( 'Probe' => 'Probe', 'ProfileProbe' => 'Stream Probe', 'ProfileProbeIntro' => 'The list below shows the existing stream profiles of the selected camera .

Select the desired entry from the list below.

Please note that ZoneMinder cannot configure additional profiles and that choosing a camera here may overwrite any values you already have configured for the current monitor.

', + 'Progress' => 'Progress', 'Protocol' => 'Protocol', 'Rate' => 'Rate', 'Real' => 'Real', @@ -648,6 +657,7 @@ $SLANG = array( 'Stream' => 'Stream', 'Submit' => 'Submit', 'System' => 'System', + 'TargetColorspace' => 'Target colorspace', 'Tele' => 'Tele', 'Thumbnail' => 'Thumbnail', 'Tilt' => 'Tilt', @@ -879,7 +889,7 @@ $OLANG = array( "\"loglevel=debug\" Set verbosiy of FFmpeg (quiet, panic, fatal, error, warning, info, verbose, debug)" ), 'OPTIONS_LIBVLC' => array( - 'Help' => "Parameters in this field are passwd on to libVLC. Multiple parameters can be separated by ,~~ ". + 'Help' => "Parameters in this field are passed on to libVLC. Multiple parameters can be separated by ,~~ ". "Examples (do not enter quotes)~~~~". "\"--rtp-client-port=nnn\" Set local port to use for rtp data~~~~". "\"--verbose=2\" Set verbosity of libVLC" diff --git a/web/lang/es_ar.php b/web/lang/es_ar.php index ee1508723..1445437f6 100644 --- a/web/lang/es_ar.php +++ b/web/lang/es_ar.php @@ -39,6 +39,7 @@ $SLANG = array( 'AlarmMaximumFPS' => 'Alarm Maximum FPS', 'AlarmPx' => 'Alarm Px', 'AlarmRGBUnset' => 'You must set an alarm RGB colour', + 'AlarmRefImageBlendPct'=> 'Alarm Reference Image Blend %ge', // Added - 2015-04-18 'Alert' => 'Alerta', 'All' => 'Todo', 'Apply' => 'Aplicar', @@ -83,13 +84,13 @@ $SLANG = array( 'BadFPSReportInterval' => 'FPS report interval buffer count must be an integer of 0 or more', 'BadFormat' => 'Format must be set to an integer of zero or more', 'BadFrameSkip' => 'Frame skip count must be an integer of zero or more', - 'BadMotionFrameSkip' => 'Motion Frame skip count must be an integer of zero or more', 'BadHeight' => 'Height must be set to a valid value', 'BadHost' => 'Host must be set to a valid ip address or hostname, do not include http://', 'BadImageBufferCount' => 'Image buffer size must be an integer of 10 or more', 'BadLabelX' => 'Label X co-ordinate must be set to an integer of zero or more', 'BadLabelY' => 'Label Y co-ordinate must be set to an integer of zero or more', 'BadMaxFPS' => 'Maximum FPS must be a positive integer or floating point value', + 'BadMotionFrameSkip' => 'Motion Frame skip count must be an integer of zero or more', 'BadNameChars' => 'Los nombres pueden contener solamente caracteres alfanumricos ms el guin y la raya', 'BadPalette' => 'Palette must be set to a valid value', // Added - 2009-03-31 'BadPath' => 'Path must be set to a valid value', @@ -109,7 +110,9 @@ $SLANG = array( 'BlobSizes' => 'Blob Sizes', 'Blobs' => 'Blobs', 'Brightness' => 'Brillo', + 'Buffer' => 'Buffer', // Added - 2015-04-18 'Buffers' => 'Buffers', + 'CSSDescription' => 'Change the default css for this computer', // Added - 2015-04-18 'CanAutoFocus' => 'Can Auto Focus', 'CanAutoGain' => 'Can Auto Gain', 'CanAutoIris' => 'Can Auto Iris', @@ -153,6 +156,7 @@ $SLANG = array( 'CaptureHeight' => 'Captura Alto', 'CaptureMethod' => 'Capture Method', // Added - 2009-02-08 'CapturePalette' => 'Captura Paleta', + 'CaptureResolution' => 'Capture Resolution', // Added - 2015-04-18 'CaptureWidth' => 'Captura Ancho', 'Cause' => 'Cause', 'CheckMethod' => 'Alarm Check Method', @@ -183,6 +187,7 @@ $SLANG = array( 'ControlDevice' => 'Control Device', 'ControlType' => 'Control Type', 'Controllable' => 'Controllable', + 'Current' => 'Current', // Added - 2015-04-18 'Cycle' => 'Cycle', 'CycleWatch' => 'Cycle Watch', 'DateTime' => 'Date/Time', // Added - 2011-06-16 @@ -191,12 +196,15 @@ $SLANG = array( 'DefaultRate' => 'Default Rate', 'DefaultScale' => 'Default Scale', 'DefaultView' => 'Default View', + 'Deinterlacing' => 'Deinterlacing', // Added - 2015-04-18 + 'Delay' => 'Delay', // Added - 2015-04-18 'Delete' => 'Borrar', 'DeleteAndNext' => 'Borrar & Prximo', 'DeleteAndPrev' => 'Borrar & Anterior', 'DeleteSavedFilter' => 'Borrar Filtro Guardado', 'Description' => 'Descripcin', 'DetectedCameras' => 'Detected Cameras', // Added - 2009-03-31 + 'DetectedProfiles' => 'Detected Profiles', // Added - 2015-04-18 'Device' => 'Device', // Added - 2009-02-08 'DeviceChannel' => 'Canal', 'DeviceFormat' => 'Seal', @@ -208,6 +216,7 @@ $SLANG = array( 'Disk' => 'Disco', 'Display' => 'Display', // Added - 2011-01-30 'Displaying' => 'Displaying', // Added - 2011-06-16 + 'DoNativeMotionDetection'=> 'Do Native Motion Detection', 'Donate' => 'Please Donate', 'DonateAlready' => 'No, I\'ve already donated', 'DonateEnticement' => 'You\'ve been running ZoneMinder for a while now and hopefully are finding it a useful addition to your home or workplace security. Although ZoneMinder is, and will remain, free and open source, it costs money to develop and support. If you would like to help support future development and new features then please consider donating. Donating is, of course, optional but very much appreciated and you can donate as much or as little as you like.

If you would like to donate please select the option below or go to http://www.zoneminder.com/donate.html in your browser.

Thank you for using ZoneMinder and don\'t forget to visit the forums on ZoneMinder.com for support or suggestions about how to make your ZoneMinder experience even better.', @@ -217,7 +226,6 @@ $SLANG = array( 'DonateRemindNever' => 'No, I don\'t want to donate, never remind', 'DonateRemindWeek' => 'Not yet, remind again in 1 week', 'DonateYes' => 'Yes, I\'d like to donate now', - 'DoNativeMotionDetection'=> 'Do Native Motion Detection', 'Download' => 'Download', 'DuplicateMonitorName' => 'Duplicate Monitor Name', // Added - 2009-03-31 'Duration' => 'Duracin', @@ -260,10 +268,12 @@ $SLANG = array( 'Feed' => 'Vista', 'Ffmpeg' => 'Ffmpeg', // Added - 2009-02-08 'File' => 'File', + 'Filter' => 'Filter', // Added - 2015-04-18 'FilterArchiveEvents' => 'Archivar todos los eventos', 'FilterDeleteEvents' => 'Borrar todos los eventos', 'FilterEmailEvents' => 'Mandar un mail de todos los eventos', 'FilterExecuteEvents' => 'Ejecutar un comando en las coincidencias', + 'FilterLog' => 'Filter log', // Added - 2015-04-18 'FilterMessageEvents' => 'Mandar un mensaje de los eventos', 'FilterPx' => 'Filtro Px', 'FilterUnset' => 'You must specify a filter width and height', @@ -273,12 +283,12 @@ $SLANG = array( 'First' => 'Primero', 'FlippedHori' => 'Flipped Horizontally', 'FlippedVert' => 'Flipped Vertically', - 'FnNone' => 'None', // Added 2013.08.16. - 'FnMonitor' => 'Monitor', // Added 2013.08.16. - 'FnModect' => 'Modect', // Added 2013.08.16. - 'FnRecord' => 'Record', // Added 2013.08.16. 'FnMocord' => 'Mocord', // Added 2013.08.16. + 'FnModect' => 'Modect', // Added 2013.08.16. + 'FnMonitor' => 'Monitor', // Added 2013.08.16. 'FnNodect' => 'Nodect', // Added 2013.08.16. + 'FnNone' => 'None', // Added 2013.08.16. + 'FnRecord' => 'Record', // Added 2013.08.16. 'Focus' => 'Focus', 'ForceAlarm' => 'Forzar Alarma', 'Format' => 'Format', @@ -286,7 +296,6 @@ $SLANG = array( 'FrameId' => 'Id Cuadro', 'FrameRate' => 'Velocidad del video', 'FrameSkip' => 'Saltear Cuadro', - 'MotionFrameSkip' => 'Motion Frame Skip', 'Frames' => 'Cuadros', 'Func' => 'Func', 'Function' => 'Funcin', @@ -413,6 +422,7 @@ $SLANG = array( 'MinZoomSpeed' => 'Min Zoom Speed', 'MinZoomStep' => 'Min Zoom Step', 'Misc' => 'Otros', + 'Mode' => 'Mode', // Added - 2015-04-18 'Monitor' => 'Monitor', 'MonitorIds' => 'Ids Monitor', 'MonitorPreset' => 'Monitor Preset', @@ -423,12 +433,13 @@ $SLANG = array( 'Montage' => 'Cmara Mltiple', 'Month' => 'Mes', 'More' => 'More', // Added - 2011-06-16 + 'MotionFrameSkip' => 'Motion Frame Skip', 'Move' => 'Move', - 'MtgDefault' => 'Default', // Added 2013.08.15. 'Mtg2widgrd' => '2-wide grid', // Added 2013.08.15. 'Mtg3widgrd' => '3-wide grid', // Added 2013.08.15. - 'Mtg4widgrd' => '4-wide grid', // Added 2013.08.15. 'Mtg3widgrx' => '3-wide grid, scaled, enlarge on alarm', // Added 2013.08.15. + 'Mtg4widgrd' => '4-wide grid', // Added 2013.08.15. + 'MtgDefault' => 'Default', // Added 2013.08.15. 'MustBeGe' => 'Debe ser mayor o igual que', 'MustBeLe' => 'Debe ser menor o igual que', 'MustConfirmPassword' => 'Debe confirmar la contrasea', @@ -457,6 +468,9 @@ $SLANG = array( 'NumPresets' => 'Num Presets', 'Off' => 'Off', 'On' => 'On', + 'OnvifCredentialsIntro'=> 'Please supply user name and password for the selected camera.
If no user has been created for the camera then the user given here will be created with the given password.

', // Added - 2015-04-18 + 'OnvifProbe' => 'ONVIF', // Added - 2015-04-18 + 'OnvifProbeIntro' => 'The list below shows detected ONVIF cameras and whether they are already being used or available for selection.

Select the desired entry from the list below.

Please note that not all cameras may be detected and that choosing a camera here may overwrite any values you already have configured for the current monitor.

', // Added - 2015-04-18 'OpEq' => 'igual que', 'OpGt' => 'mayor que', 'OpGtEq' => 'mayor o igual que', @@ -503,6 +517,9 @@ $SLANG = array( 'Presets' => 'Presets', 'Prev' => 'Prev', 'Probe' => 'Probe', // Added - 2009-03-31 + 'ProfileProbe' => 'Stream Probe', // Added - 2015-04-18 + 'ProfileProbeIntro' => 'The list below shows the existing stream profiles of the selected camera .

Select the desired entry from the list below.

Please note that ZoneMinder cannot configure additional profiles and that choosing a camera here may overwrite any values you already have configured for the current monitor.

', // Added - 2015-04-18 + 'Progress' => 'Progress', // Added - 2015-04-18 'Protocol' => 'Protocol', 'Rate' => 'Ritmo', 'Real' => 'Real', @@ -590,6 +607,7 @@ $SLANG = array( 'Submit' => 'Submit', 'System' => 'Sistema', 'SystemLog' => 'System Log', // Added - 2011-06-16 + 'TargetColorspace' => 'Target colorspace', // Added - 2015-04-18 'Tele' => 'Tele', 'Thumbnail' => 'Thumbnail', 'Tilt' => 'Tilt', @@ -624,13 +642,16 @@ $SLANG = array( 'UpdateNotNecessary' => 'No se requiere Actualizacin', 'Updated' => 'Updated', // Added - 2011-06-16 'Upload' => 'Upload', // Added - 2011-08-23 - 'UsedPlugins' => 'Used Plugins', 'UseFilter' => 'Usar Filtro', 'UseFilterExprsPost' => ' filtrar sentencias', // This is used at the end of the phrase 'use N filter expressions' 'UseFilterExprsPre' => 'Utilizar ', // This is used at the beginning of the phrase 'use N filter expressions' + 'UsedPlugins' => 'Used Plugins', 'User' => 'Usuario', 'Username' => 'Nombre', 'Users' => 'Usuarios', + 'V4L' => 'V4L', // Added - 2015-04-18 + 'V4LCapturesPerFrame' => 'Captures Per Frame', // Added - 2015-04-18 + 'V4LMultiBuffer' => 'Multi Buffering', // Added - 2015-04-18 'Value' => 'Valor', 'Version' => 'Versin', 'VersionIgnore' => 'Ignore esta versin', @@ -670,6 +691,7 @@ $SLANG = array( 'Zone' => 'Zona', 'ZoneAlarmColour' => 'Color Alarma (Red/Green/Blue)', 'ZoneArea' => 'Zone Area', + 'ZoneExtendAlarmFrames' => 'Extend Alarm Frame Count', 'ZoneFilterSize' => 'Filter Width/Height (pixels)', 'ZoneMinMaxAlarmArea' => 'Min/Max Alarmed Area', 'ZoneMinMaxBlobArea' => 'Min/Max Blob Area', @@ -678,7 +700,6 @@ $SLANG = array( 'ZoneMinMaxPixelThres' => 'Min/Max Pixel Threshold (0-255)', 'ZoneMinderLog' => 'ZoneMinder Log', // Added - 2011-06-17 'ZoneOverloadFrames' => 'Overload Frame Ignore Count', - 'ZoneExtendAlarmFrames' => 'Extend Alarm Frame Count', 'Zones' => 'Zonas', 'Zoom' => 'Zoom', 'ZoomIn' => 'Zoom In', diff --git a/web/lang/es_es.php b/web/lang/es_es.php index 1e80f6500..38b879814 100644 --- a/web/lang/es_es.php +++ b/web/lang/es_es.php @@ -72,6 +72,7 @@ header ('Content-type: text/html; charset=utf-8'); // Simple String Replacements $SLANG = array( '24BitColour' => 'Color 24 bits', + '32BitColour' => '32 bit colour', // Added - 2015-04-18 '8BitGrey' => 'Grises 8 bits', 'Action' => 'Acción', 'Actual' => 'Actual', @@ -87,6 +88,7 @@ $SLANG = array( 'AlarmMaximumFPS' => 'Máximos MPS alarma', 'AlarmPx' => 'Px alarma', 'AlarmRGBUnset' => 'Debe establecer un color RGB para alarma', + 'AlarmRefImageBlendPct'=> 'Alarm Reference Image Blend %ge', // Added - 2015-04-18 'Alert' => 'Alerta', 'All' => 'Todo', 'Apply' => 'Aplicar', @@ -126,17 +128,18 @@ $SLANG = array( 'BadAlarmFrameCount' => 'El número de marcos de alarma debe tener un número entero de uno o más', 'BadAlarmMaxFPS' => 'Máximos MPS de alarma debe ser un valor entero positivo o de punto flotante', 'BadChannel' => 'El canal debe estar establecido en un entero de cero o más', + 'BadColours' => 'Target colour must be set to a valid value', // Added - 2015-04-18 'BadDevice' => 'El dispositivo debe tener un valor válido', 'BadFPSReportInterval' => 'El registro de intervalo de recuento búfer de MPS debe ser un entero de 100 o más', 'BadFormat' => 'El formato debe tener un valor válido', 'BadFrameSkip' => 'El número de omisión de marcos debe ser un entero de cero o más', - 'BadMotionFrameSkip' => 'Motion Frame skip count must be an integer of zero or more', 'BadHeight' => 'La altura debe tener un valor válido', 'BadHost' => 'El host debe tener una dirección ip o nombre de host válidos, no incluir http://', 'BadImageBufferCount' => 'El tamaño de búfer de imagen debe serun entero de 10 o más', 'BadLabelX' => 'La coordenada de la etiqueta X debe ser un entero de cero o más', 'BadLabelY' => 'La coordenada de la etiqueta Y debe ser un entero de cero o más', 'BadMaxFPS' => 'MPS máximos debe tener un valor entero positivo o de punto flotante', + 'BadMotionFrameSkip' => 'Motion Frame skip count must be an integer of zero or more', 'BadNameChars' => 'Los nombre sólo pueden contener carácteres alfanuméricos además de guiones y guiones bajos', 'BadPalette' => 'La paleta debe tener un valor válido', 'BadPath' => 'La ruta debe tener un valo válido', @@ -156,7 +159,9 @@ $SLANG = array( 'BlobSizes' => 'Tamaño gotas', 'Blobs' => 'Gotas', 'Brightness' => 'Brillo', + 'Buffer' => 'Buffer', // Added - 2015-04-18 'Buffers' => 'Búfers', + 'CSSDescription' => 'Change the default css for this computer', // Added - 2015-04-18 'CanAutoFocus' => 'Puede enfocar automáticamente', 'CanAutoGain' => 'Puede usar ganancia automática', 'CanAutoIris' => 'Puede ajustar el iris automáticamente', @@ -200,6 +205,7 @@ $SLANG = array( 'CaptureHeight' => 'Altura de captura', 'CaptureMethod' => 'Método de captura', 'CapturePalette' => 'Paleta de captura', + 'CaptureResolution' => 'Capture Resolution', // Added - 2015-04-18 'CaptureWidth' => 'Ancho de captura', 'Cause' => 'Causa', 'CheckMethod' => 'Método de comprobación de alarma', @@ -230,6 +236,7 @@ $SLANG = array( 'ControlDevice' => 'Controlar dispositivo', 'ControlType' => 'Tipo de control', 'Controllable' => 'Controlable', + 'Current' => 'Current', // Added - 2015-04-18 'Cycle' => 'Ciclo', 'CycleWatch' => 'Visión ciclo', 'DateTime' => 'Fecha/Hora', @@ -238,12 +245,15 @@ $SLANG = array( 'DefaultRate' => 'Tasa por defecto', 'DefaultScale' => 'Escala por defecto', 'DefaultView' => 'Vista por defecto', + 'Deinterlacing' => 'Deinterlacing', // Added - 2015-04-18 + 'Delay' => 'Delay', // Added - 2015-04-18 'Delete' => 'Borrar', 'DeleteAndNext' => 'Borrar & siguiente', 'DeleteAndPrev' => 'Borrar & anterior', 'DeleteSavedFilter' => 'Borrar filtro guardado', 'Description' => 'Descripción', 'DetectedCameras' => 'Cámaras detectadas', + 'DetectedProfiles' => 'Detected Profiles', // Added - 2015-04-18 'Device' => 'Dispositivo', 'DeviceChannel' => 'Canal de dispositivo', 'DeviceFormat' => 'Formato de dispositivo', @@ -255,6 +265,7 @@ $SLANG = array( 'Disk' => 'Disco', 'Display' => 'Visualizar', 'Displaying' => 'Visualizando', + 'DoNativeMotionDetection'=> 'Do Native Motion Detection', // Added - 2015-04-18 'Donate' => 'Por favor, done', 'DonateAlready' => 'No, ya he donado', 'DonateEnticement' => 'Ha estado ejecutando ZoneMinder por un tiempo y con suerte le resultará un útil complemento para su seguridad en hogar y trabajo. Aunque ZoneMinder es, y será, libre y de código abierto, cuesta dinero desarrollarlo y mantenerlo. Si quiere ayudar a mantener un futuro desarrollo y nuevas funciones entonces considere hacer un donativo por favor. Donar es, por supuesto, opcional pero muy apreciado y puede donar tanto como desee sin importar la cantidad.

Si desea hacer una donación por favor seleccione la opción de debajo o vaya a http://www.zoneminder.com/donate.html en su navegador.

Muchas gracias por usar ZoneMinder y no se olvide de vistar los foros en ZoneMinder.com para obtener soporte o hacer sugerencias sobre cómo mejorar su experiencia con ZoneMinder aún más.', @@ -306,10 +317,12 @@ $SLANG = array( 'Feed' => 'Feed', 'Ffmpeg' => 'Ffmpeg', 'File' => 'Archivo', + 'Filter' => 'Filter', // Added - 2015-04-18 'FilterArchiveEvents' => 'Archivar todas las coincidencias', 'FilterDeleteEvents' => 'Borrar todas las coincidencias', 'FilterEmailEvents' => 'Enviar detalles de todas las coincidencias por email', 'FilterExecuteEvents' => 'Ejecutar comando para todas las coincidencias', + 'FilterLog' => 'Filter log', // Added - 2015-04-18 'FilterMessageEvents' => 'Detalles de mensaje de todas las coincidencias', 'FilterPx' => 'Filtrar Px', 'FilterUnset' => 'Debe especificar un ancho y un alto para el filtro', @@ -319,12 +332,12 @@ $SLANG = array( 'First' => 'Primero', 'FlippedHori' => 'Girado horizontalmente', 'FlippedVert' => 'Girado verticalmente', - 'FnNone' => 'None', // Added 2013.08.16. - 'FnMonitor' => 'Monitor', // Added 2013.08.16. - 'FnModect' => 'Modect', // Added 2013.08.16. - 'FnRecord' => 'Record', // Added 2013.08.16. 'FnMocord' => 'Mocord', // Added 2013.08.16. + 'FnModect' => 'Modect', // Added 2013.08.16. + 'FnMonitor' => 'Monitor', // Added 2013.08.16. 'FnNodect' => 'Nodect', // Added 2013.08.16. + 'FnNone' => 'None', // Added 2013.08.16. + 'FnRecord' => 'Record', // Added 2013.08.16. 'Focus' => 'Enfoque', 'ForceAlarm' => 'Forzar alama', 'Format' => 'Formato', @@ -332,7 +345,6 @@ $SLANG = array( 'FrameId' => 'Id del marco', 'FrameRate' => 'Ratío del marco', 'FrameSkip' => 'Omisión de marcos', - 'MotionFrameSkip' => 'Motion Frame Skip', 'Frames' => 'Marcos', 'Func' => 'Func', 'Function' => 'Función', @@ -459,6 +471,7 @@ $SLANG = array( 'MinZoomSpeed' => 'Velocidad de zoom mínima', 'MinZoomStep' => 'Grado de zoom mínimo', 'Misc' => 'Misc', + 'Mode' => 'Mode', // Added - 2015-04-18 'Monitor' => 'Monitor', 'MonitorIds' => 'Ids monitor', 'MonitorPreset' => 'Programar monitor', @@ -469,12 +482,13 @@ $SLANG = array( 'Montage' => 'Montaje', 'Month' => 'Mes', 'More' => 'Más', + 'MotionFrameSkip' => 'Motion Frame Skip', 'Move' => 'Mover', - 'MtgDefault' => 'Default', // Added 2013.08.15. 'Mtg2widgrd' => '2-wide grid', // Added 2013.08.15. 'Mtg3widgrd' => '3-wide grid', // Added 2013.08.15. - 'Mtg4widgrd' => '4-wide grid', // Added 2013.08.15. 'Mtg3widgrx' => '3-wide grid, scaled, enlarge on alarm', // Added 2013.08.15. + 'Mtg4widgrd' => '4-wide grid', // Added 2013.08.15. + 'MtgDefault' => 'Default', // Added 2013.08.15. 'MustBeGe' => 'debe ser mayor o igual que', 'MustBeLe' => 'debe ser menor o igual que', 'MustConfirmPassword' => 'Debe confirmar la contraseña', @@ -503,6 +517,9 @@ $SLANG = array( 'NumPresets' => 'Número programa', 'Off' => 'Off', 'On' => 'On', + 'OnvifCredentialsIntro'=> 'Please supply user name and password for the selected camera.
If no user has been created for the camera then the user given here will be created with the given password.

', // Added - 2015-04-18 + 'OnvifProbe' => 'ONVIF', // Added - 2015-04-18 + 'OnvifProbeIntro' => 'The list below shows detected ONVIF cameras and whether they are already being used or available for selection.

Select the desired entry from the list below.

Please note that not all cameras may be detected and that choosing a camera here may overwrite any values you already have configured for the current monitor.

', // Added - 2015-04-18 'OpEq' => 'igual a', 'OpGt' => 'mayor que', 'OpGtEq' => 'mayor que o igual a', @@ -540,6 +557,7 @@ $SLANG = array( 'Play' => 'Reproducir', 'PlayAll' => 'Reproducir rodo', 'PleaseWait' => 'Espere por favor', + 'Plugins' => 'Plugins', // Added - 2015-04-18 'Point' => 'Punto', 'PostEventImageBuffer' => 'Cuenta de imagen post evento', 'PreEventImageBuffer' => 'Cuenta de imagen pre evento', @@ -548,6 +566,9 @@ $SLANG = array( 'Presets' => 'Programas', 'Prev' => 'Anterior', 'Probe' => 'Sondear', + 'ProfileProbe' => 'Stream Probe', // Added - 2015-04-18 + 'ProfileProbeIntro' => 'The list below shows the existing stream profiles of the selected camera .

Select the desired entry from the list below.

Please note that ZoneMinder cannot configure additional profiles and that choosing a camera here may overwrite any values you already have configured for the current monitor.

', // Added - 2015-04-18 + 'Progress' => 'Progress', // Added - 2015-04-18 'Protocol' => 'Protocolo', 'Rate' => 'Valorar', 'Real' => 'Real', @@ -635,6 +656,7 @@ $SLANG = array( 'Submit' => 'Enviar', 'System' => 'Sistema', 'SystemLog' => 'Registros del sistema', + 'TargetColorspace' => 'Target colorspace', // Added - 2015-04-18 'Tele' => 'Tele', 'Thumbnail' => 'Thumbnail', 'Tilt' => 'Inclinar', @@ -672,9 +694,13 @@ $SLANG = array( 'UseFilter' => 'Usar filtro', 'UseFilterExprsPost' => ' filtros de expresión', // This is used at the end of the phrase 'use N filter expressions' 'UseFilterExprsPre' => 'Usar ', // This is used at the beginning of the phrase 'use N filter expressions' + 'UsedPlugins' => 'Used Plugins', // Added - 2015-04-18 'User' => 'Usuario', 'Username' => 'Nombre de usuario', 'Users' => 'Usuarios', + 'V4L' => 'V4L', // Added - 2015-04-18 + 'V4LCapturesPerFrame' => 'Captures Per Frame', // Added - 2015-04-18 + 'V4LMultiBuffer' => 'Multi Buffering', // Added - 2015-04-18 'Value' => 'Valor', 'Version' => 'Versión', 'VersionIgnore' => 'Ignorar esta versión', @@ -714,6 +740,7 @@ $SLANG = array( 'Zone' => 'Zona', 'ZoneAlarmColour' => 'Color de alarma (rojo/verde/bzul)', 'ZoneArea' => 'Área de zona', + 'ZoneExtendAlarmFrames'=> 'Extend Alarm Frame Count', // Added - 2015-04-18 'ZoneFilterSize' => 'Filtrar anchura/altura (píxeles)', 'ZoneMinMaxAlarmArea' => 'Mín/Máx área de alarma', 'ZoneMinMaxBlobArea' => 'Mín/Máx área de goteo', diff --git a/web/lang/et_ee.php b/web/lang/et_ee.php index f328fb9e3..21274663d 100644 --- a/web/lang/et_ee.php +++ b/web/lang/et_ee.php @@ -89,6 +89,7 @@ $SLANG = array( 'AlarmMaximumFPS' => 'Alarmi Maksimaalne FPS', 'AlarmPx' => 'Alarm Px', 'AlarmRGBUnset' => 'Sa pead panema alarmi RGB värvi', + 'AlarmRefImageBlendPct'=> 'Alarm Reference Image Blend %ge', // Added - 2015-04-18 'Alert' => 'Hoiatus', 'All' => 'All', 'Apply' => 'Apply', @@ -133,13 +134,13 @@ $SLANG = array( 'BadFPSReportInterval' => 'FPS raporteerimise intervall puhvri hulk peab olema integer, null või rohkem', 'BadFormat' => 'Formaadiks peab olema pandud õige väärtus', 'BadFrameSkip' => 'Kaadri vahelejätmise hulk peab olema integer, null või rohkem', - 'BadMotionFrameSkip' => 'Liikumise kaadri vahelejätmise hulk peab olema integer, null või rohkem', 'BadHeight' => 'Kõrguseks peab olema valitud õige väärtus', 'BadHost' => 'Host ipeab olema õige. Ip aadress või hostinimi, ei tohi sisaldada http://', 'BadImageBufferCount' => 'Pildi puhvri suurus peab olema integer, 10 või rohkem', 'BadLabelX' => 'Label X co-ordinate must be set to an integer of zero or more', 'BadLabelY' => 'Label Y co-ordinate must be set to an integer of zero or more', 'BadMaxFPS' => 'Maximum FPS must be a positive integer or floating point value', + 'BadMotionFrameSkip' => 'Liikumise kaadri vahelejätmise hulk peab olema integer, null või rohkem', 'BadNameChars' => 'Names may only contain alphanumeric characters plus hyphen and underscore', 'BadPalette' => 'Palette must be set to a valid value', 'BadPath' => 'Path must be set to a valid value', @@ -159,7 +160,9 @@ $SLANG = array( 'BlobSizes' => 'Blob Sizes', 'Blobs' => 'Blobs', 'Brightness' => 'Heledus', + 'Buffer' => 'Buffer', // Added - 2015-04-18 'Buffers' => 'Puhver', + 'CSSDescription' => 'Change the default css for this computer', // Added - 2015-04-18 'CanAutoFocus' => 'Can Auto Focus', 'CanAutoGain' => 'Can Auto Gain', 'CanAutoIris' => 'Can Auto Iris', @@ -203,6 +206,7 @@ $SLANG = array( 'CaptureHeight' => 'Capture Height', 'CaptureMethod' => 'Capture Method', 'CapturePalette' => 'Capture Palette', + 'CaptureResolution' => 'Capture Resolution', // Added - 2015-04-18 'CaptureWidth' => 'Capture Width', 'Cause' => 'Cause', 'CheckMethod' => 'Alarm Check Method', @@ -233,6 +237,7 @@ $SLANG = array( 'ControlDevice' => 'Control Device', 'ControlType' => 'Control Type', 'Controllable' => 'Controllable', + 'Current' => 'Current', // Added - 2015-04-18 'Cycle' => 'Cycle', 'CycleWatch' => 'Cycle Watch', 'DateTime' => 'Kuupäev/Aeg', // Added - 2011-06-16 @@ -241,12 +246,15 @@ $SLANG = array( 'DefaultRate' => 'Default Kiirus', 'DefaultScale' => 'Default Suurus', 'DefaultView' => 'Default Vaade', + 'Deinterlacing' => 'Deinterlacing', // Added - 2015-04-18 + 'Delay' => 'Delay', // Added - 2015-04-18 'Delete' => 'Kustuta', 'DeleteAndNext' => 'Kustuta & Järgmine', 'DeleteAndPrev' => 'Kustuta & Eelmine', 'DeleteSavedFilter' => 'Kustuta salvestatud filter', 'Description' => 'Kirjeldus', 'DetectedCameras' => 'Tuvastatud kaamerad', + 'DetectedProfiles' => 'Detected Profiles', // Added - 2015-04-18 'Device' => 'Seade', 'DeviceChannel' => 'Seadme Kanal', 'DeviceFormat' => 'Seadme Formaat', @@ -258,6 +266,7 @@ $SLANG = array( 'Disk' => 'Ketas', 'Display' => 'Ekraan', // Added - 2011-03-02 'Displaying' => 'Väljapanek', // Added - 2011-06-16 + 'DoNativeMotionDetection'=> 'Do Native Motion Detection', // Added - 2015-04-18 'Donate' => 'Palun Anneta', 'DonateAlready' => 'EI, Ma olen juba annetanud', 'DonateEnticement' => 'Sa oled juba kasutanud ZoneMinderit juba mõnda aega. Nüüd kus sa oled leidnud, et see on kasulik lisa sinu kodule või sinu töökohale. Kuigi ZoneMinder on, jääb alatiseks, vabaks ja avatud lähtekoodiks, siiski selle arendamiseks kulub aega ja raha. Kui sa soovid meid aidata, siis toeta meid tuleviku arendusteks ja uute lisade loomiseks. Palun mõelge annetuse peale. Donating is, of course, optional but very much appreciated and you can donate as much or as little as you like.

If you would like to donate please select the option below or go to http://www.zoneminder.com/donate.html in your browser.

Thank you for using ZoneMinder and don\'t forget to visit the forums on ZoneMinder.com for support or suggestions about how to make your ZoneMinder experience even better.', @@ -309,10 +318,12 @@ $SLANG = array( 'Feed' => 'Feed', 'Ffmpeg' => 'Ffmpeg', 'File' => 'Fail', + 'Filter' => 'Filter', // Added - 2015-04-18 'FilterArchiveEvents' => 'Archive all matches', 'FilterDeleteEvents' => 'Delete all matches', 'FilterEmailEvents' => 'Email details of all matches', 'FilterExecuteEvents' => 'Execute command on all matches', + 'FilterLog' => 'Filter log', // Added - 2015-04-18 'FilterMessageEvents' => 'Message details of all matches', 'FilterPx' => 'Filter Px', 'FilterUnset' => 'You must specify a filter width and height', @@ -322,12 +333,12 @@ $SLANG = array( 'First' => 'Esimene', 'FlippedHori' => 'Flipped Horizontally', 'FlippedVert' => 'Flipped Vertically', - 'FnNone' => 'None', // Added 2013.08.16. - 'FnMonitor' => 'Monitor', // Added 2013.08.16. - 'FnModect' => 'Modect', // Added 2013.08.16. - 'FnRecord' => 'Record', // Added 2013.08.16. 'FnMocord' => 'Mocord', // Added 2013.08.16. + 'FnModect' => 'Modect', // Added 2013.08.16. + 'FnMonitor' => 'Monitor', // Added 2013.08.16. 'FnNodect' => 'Nodect', // Added 2013.08.16. + 'FnNone' => 'None', // Added 2013.08.16. + 'FnRecord' => 'Record', // Added 2013.08.16. 'Focus' => 'Fookus', 'ForceAlarm' => 'Force Alarm', 'Format' => 'Format', @@ -335,7 +346,6 @@ $SLANG = array( 'FrameId' => 'Frame Id', 'FrameRate' => 'Kaadri Sagedus', 'FrameSkip' => 'Frame Skip', - 'MotionFrameSkip' => 'Motion Frame Skip', 'Frames' => 'Kaadrid', 'Func' => 'Func', 'Function' => 'Funktsioon', @@ -462,6 +472,7 @@ $SLANG = array( 'MinZoomSpeed' => 'Min Zoom Speed', 'MinZoomStep' => 'Min Zoom Step', 'Misc' => 'Misc', + 'Mode' => 'Mode', // Added - 2015-04-18 'Monitor' => 'Monitor', 'MonitorIds' => 'Monitor Ids', 'MonitorPreset' => 'Monitor Preset', @@ -472,12 +483,13 @@ $SLANG = array( 'Montage' => 'Montage', 'Month' => 'Kuus', 'More' => 'Veel', // Added - 2011-06-16 + 'MotionFrameSkip' => 'Motion Frame Skip', 'Move' => 'Liiguta', - 'MtgDefault' => 'Default', // Added 2013.08.15. 'Mtg2widgrd' => '2-pildi ruudustik', // Added 2013.08.15. 'Mtg3widgrd' => '3-pildi ruudustik', // Added 2013.08.15. - 'Mtg4widgrd' => '4-pildi ruudustik', // Added 2013.08.15. 'Mtg3widgrx' => '3-pildi ruudustik, skaleeritud, suurenda kui on alarm', // Added 2013.08.15. + 'Mtg4widgrd' => '4-pildi ruudustik', // Added 2013.08.15. + 'MtgDefault' => 'Default', // Added 2013.08.15. 'MustBeGe' => 'peab olema suurem kui või võrdne ', 'MustBeLe' => 'peab olema väiksem kui või võrdne', 'MustConfirmPassword' => 'Sa pead kinnitama parooli', @@ -506,6 +518,9 @@ $SLANG = array( 'NumPresets' => 'Num Presets', 'Off' => 'Väljas', 'On' => 'Sees', + 'OnvifCredentialsIntro'=> 'Please supply user name and password for the selected camera.
If no user has been created for the camera then the user given here will be created with the given password.

', // Added - 2015-04-18 + 'OnvifProbe' => 'ONVIF', // Added - 2015-04-18 + 'OnvifProbeIntro' => 'The list below shows detected ONVIF cameras and whether they are already being used or available for selection.

Select the desired entry from the list below.

Please note that not all cameras may be detected and that choosing a camera here may overwrite any values you already have configured for the current monitor.

', // Added - 2015-04-18 'OpEq' => 'Võrdne', 'OpGt' => 'Suurem kui', 'OpGtEq' => 'suurem kui või võrdne', @@ -552,6 +567,9 @@ $SLANG = array( 'Presets' => 'Eelseaded', 'Prev' => 'Prev', 'Probe' => 'Probe', + 'ProfileProbe' => 'Stream Probe', // Added - 2015-04-18 + 'ProfileProbeIntro' => 'The list below shows the existing stream profiles of the selected camera .

Select the desired entry from the list below.

Please note that ZoneMinder cannot configure additional profiles and that choosing a camera here may overwrite any values you already have configured for the current monitor.

', // Added - 2015-04-18 + 'Progress' => 'Progress', // Added - 2015-04-18 'Protocol' => 'Protocol', 'Rate' => 'Rate', 'Real' => 'Reaaalne', @@ -639,6 +657,7 @@ $SLANG = array( 'Submit' => 'Submit', 'System' => 'Süsteem', 'SystemLog' => 'Süsteemi Logi', // Added - 2011-06-16 + 'TargetColorspace' => 'Target colorspace', // Added - 2015-04-18 'Tele' => 'Tele', 'Thumbnail' => 'Thumbnail', 'Tilt' => 'Tilt', @@ -676,9 +695,13 @@ $SLANG = array( 'UseFilter' => 'Kasuta Filtrit', 'UseFilterExprsPost' => ' filter expressions', // This is used at the end of the phrase 'use N filter expressions' 'UseFilterExprsPre' => 'Use ', // This is used at the beginning of the phrase 'use N filter expressions' + 'UsedPlugins' => 'Used Plugins', // Added - 2015-04-18 'User' => 'Kasutaja', 'Username' => 'Kasutajanimi', 'Users' => 'Kasutajad', + 'V4L' => 'V4L', // Added - 2015-04-18 + 'V4LCapturesPerFrame' => 'Captures Per Frame', // Added - 2015-04-18 + 'V4LMultiBuffer' => 'Multi Buffering', // Added - 2015-04-18 'Value' => 'Väärtus', 'Version' => 'Versioon', 'VersionIgnore' => 'Ignoreeri See Versioon', @@ -718,6 +741,7 @@ $SLANG = array( 'Zone' => 'Tsoon', 'ZoneAlarmColour' => 'Alarmi Värv (Red"Punane"/Green"Roheline"/Blue"Sinine")', 'ZoneArea' => 'Tsooni Ala', + 'ZoneExtendAlarmFrames' => 'Extend Alarm Frame Count', 'ZoneFilterSize' => 'Filter Width/Height (pixels)', 'ZoneMinMaxAlarmArea' => 'Min/Max Alarmed Area', 'ZoneMinMaxBlobArea' => 'Min/Max Blob Area', @@ -726,7 +750,6 @@ $SLANG = array( 'ZoneMinMaxPixelThres' => 'Min/Max Pixel Threshold (0-255)', 'ZoneMinderLog' => 'ZoneMinder Log', // Added - 2011-06-17 'ZoneOverloadFrames' => 'Overload Frame Ignore Count', - 'ZoneExtendAlarmFrames' => 'Extend Alarm Frame Count', 'Zones' => 'Tsoone', 'Zoom' => 'Suurenda', 'ZoomIn' => 'Suurenda lähemale', diff --git a/web/lang/fr_fr.php b/web/lang/fr_fr.php index 3ee74aa23..afab7db14 100644 --- a/web/lang/fr_fr.php +++ b/web/lang/fr_fr.php @@ -69,544 +69,567 @@ // setlocale( LC_CTYPE, 'en_GB' ); Character class settings 4.3.0 and after // setlocale( LC_TIME, 'en_GB' ); Date and time formatting 4.3.0 and after +// Set date and time format (example: sam. 18 avril, 19h02) +setlocale(LC_ALL, "fr_FR.UTF-8"); +define("DATE_FMT_CONSOLE_LONG", "%a %d %b, %Hh%M"); +define( "STRF_FMT_DATETIME_SHORT", "%d/%m/%y %H:%M:%S" ); +define( "STRF_FMT_DATETIME_SHORTER", "%d/%m %H:%M:%S" ); + // Simple String Replacements $SLANG = array( - '24BitColour' => 'Couleur 24 bit', - '32BitColour' => 'Couleur 32 bit', // Added - 2011-06-15 - '8BitGrey' => 'Gris 8 bit', + '24BitColour' => 'Couleur 24 bits', + '32BitColour' => 'Couleur 32 bits', // Added - 2011-06-15 + '8BitGrey' => 'Gris 8 bits', 'Action' => 'Action', - 'Actual' => 'RÈel', - 'AddNewControl' => 'Ajouter controle', - 'AddNewMonitor' => 'Ajouter camÈra', + 'Actual' => 'Réel', + 'AddNewControl' => 'Ajouter contrôle', + 'AddNewMonitor' => 'Ajouter caméra', 'AddNewUser' => 'Ajouter utilisateur', 'AddNewZone' => 'Ajouter zone', 'Alarm' => 'Alarme', 'AlarmBrFrames' => 'Images
alarme', 'AlarmFrame' => 'Image alarme', - 'AlarmFrameCount' => 'Nombre dimage alarme', + 'AlarmFrameCount' => 'Nb d\'image(s) en alarme', 'AlarmLimits' => 'Limites alarme', 'AlarmMaximumFPS' => 'i/s maximum pendant alarme', - 'AlarmPx' => 'Px Alarme', - 'AlarmRGBUnset' => 'You must set an alarm RGB colour', + 'AlarmPx' => 'Px alarme', + 'AlarmRGBUnset' => 'Vous devez définir une couleur RVB pour l\'alarme', + 'AlarmRefImageBlendPct'=> '% fusion image référence en alarme', // Added - 2015-04-18 'Alert' => 'Alerte', 'All' => 'Tous', 'Apply' => 'Appliquer', - 'ApplyingStateChange' => 'Appl. chgt Ètat', - 'ArchArchived' => 'ArchivÈ seul.', + 'ApplyingStateChange' => 'Appl. chgt état', + 'ArchArchived' => 'Archivé seul.', 'ArchUnarchived' => 'Non-arch. seul.', 'Archive' => 'Archiver', - 'Archived' => 'ArchivÈs', - 'Area' => 'Area', - 'AreaUnits' => 'Area (px/%)', + 'Archived' => 'Archivés', + 'Area' => 'Surface', + 'AreaUnits' => 'Surface (px/%)', 'AttrAlarmFrames' => 'Images alarme', 'AttrArchiveStatus' => 'Etat Archive', 'AttrAvgScore' => 'Score moy.', 'AttrCause' => 'Cause', 'AttrDate' => 'Date', 'AttrDateTime' => 'Date/Heure', - 'AttrDiskBlocks' => 'Disk Blocks', - 'AttrDiskPercent' => 'Disk Percent', - 'AttrDuration' => 'DurÈe', + 'AttrDiskBlocks' => 'Blocs disque', + 'AttrDiskPercent' => '% disque', + 'AttrDuration' => 'Durée', 'AttrFrames' => 'Images', 'AttrId' => 'Id', 'AttrMaxScore' => 'Score max.', - 'AttrMonitorId' => 'N∞ camÈra', - 'AttrMonitorName' => 'Nom camÈra', + 'AttrMonitorId' => 'N°', + 'AttrMonitorName' => 'Nom caméra', 'AttrName' => 'Nom', 'AttrNotes' => 'Notes', - 'AttrSystemLoad' => 'Charge SystËme', + 'AttrSystemLoad' => 'Charge système', 'AttrTime' => 'Heure', 'AttrTotalScore' => 'Score total', 'AttrWeekday' => 'Semaine', 'Auto' => 'Auto', - 'AutoStopTimeout' => 'Auto Stop Timeout', - 'Available' => 'Disponible', // Added - 2009-03-31 + 'AutoStopTimeout' => 'Temporisation arrêt', + 'Available' => 'Disponibles', // Added - 2009-03-31 'AvgBrScore' => 'Score
moy.', - 'Background' => 'ArriËre-plan', - 'BackgroundFilter' => 'Lancer les filtres en arriËre-plan', - 'BadAlarmFrameCount' => 'Alarm frame count must be an integer of one or more', - 'BadAlarmMaxFPS' => 'Alarm Maximum FPS must be a positive integer or floating point value', - 'BadChannel' => 'Channel must be set to an integer of zero or more', - 'BadColours' => 'Target colour must be set to a valid value', // Added - 2011-06-15 - 'BadDevice' => 'Device must be set to a valid value', - 'BadFPSReportInterval' => 'FPS report interval buffer count must be an integer of 0 or more', - 'BadFormat' => 'Format must be set to an integer of zero or more', - 'BadFrameSkip' => 'Frame skip count must be an integer of zero or more', - 'BadMotionFrameSkip' => 'Motion Frame skip count must be an integer of zero or more', - 'BadHeight' => 'Height must be set to a valid value', - 'BadHost' => 'Host must be set to a valid ip address or hostname, do not include http://', - 'BadImageBufferCount' => 'Image buffer size must be an integer of 10 or more', - 'BadLabelX' => 'Label X co-ordinate must be set to an integer of zero or more', - 'BadLabelY' => 'Label Y co-ordinate must be set to an integer of zero or more', - 'BadMaxFPS' => 'Maximum FPS must be a positive integer or floating point value', - 'BadNameChars' => 'Les noms ne peuvent contenir que des lettres, chiffres, trait d\'union ou soulignÈ', - 'BadPalette' => 'Palette must be set to a valid value', // Added - 2009-03-31 - 'BadPath' => 'Path must be set to a valid value', - 'BadPort' => 'Port must be set to a valid number', - 'BadPostEventCount' => 'Post event image count must be an integer of zero or more', - 'BadPreEventCount' => 'Pre event image count must be at least zero, and less than image buffer size', - 'BadRefBlendPerc' => 'Reference blend percentage must be a positive integer', - 'BadSectionLength' => 'Section length must be an integer of 30 or more', - 'BadSignalCheckColour' => 'Signal check colour must be a valid RGB colour string', - 'BadStreamReplayBuffer'=> 'Stream replay buffer must be an integer of zero or more', - 'BadWarmupCount' => 'Warmup frames must be an integer of zero or more', - 'BadWebColour' => 'Web colour must be a valid web colour string', - 'BadWidth' => 'Width must be set to a valid value', - 'Bandwidth' => 'dÈbit', - 'BandwidthHead' => 'dÈbit', // This is the end of the bandwidth status on the top of the console, different in many language due to phrasing - 'BlobPx' => 'Px forme', - 'BlobSizes' => 'Taille forme', + 'Background' => 'Arrière-plan', + 'BackgroundFilter' => 'Lancer les filtres en arrière-plan', + 'BadAlarmFrameCount' => 'Le nombre d\'images en alarme doit être un entier supérieur ou égal à 1', + 'BadAlarmMaxFPS' => 'Le nombre maximum d\'i/s en alarme doit être un entier ou un nombre à virgule flottante supérieur à 0', + 'BadChannel' => 'Le canal doit être un nombre entier supérieur ou égal à 0', + 'BadColours' => 'La valeur de la couleur cible est invalide', // Added - 2011-06-15 + 'BadDevice' => 'Le chemin de l\'équipement être défini', + 'BadFPSReportInterval' => 'L\'intervalle de rafraîchissement de l\'information i/s doit être un entier supérieur ou égal à 0', + 'BadFormat' => 'Le format doit être un nombre entier supérieur ou égal à 0', + 'BadFrameSkip' => 'Le nombre d\'images à sauter doit être un entier supérieur ou égal à 0', + 'BadHeight' => 'La valeur de la hauteur est invalide', + 'BadHost' => 'Le nom d\'hôte doit être une adresse ip ou un nom dns valide sans le préfixe http://', + 'BadImageBufferCount' => 'La taille du tampon d \'images doit être un entier supérieur ou égal à 10', + 'BadLabelX' => 'La coordonnée X pour l\'horodatage doit être un entier supérieur ou égal à 0', + 'BadLabelY' => 'La coordonnée Y pour l\'horodatage doit être un entier supérieur ou égal à 0', + 'BadMaxFPS' => 'Le nombre maximum d\'i/s doit être un entier ou un nombre à virgule flottante supérieur à 0', + 'BadMotionFrameSkip' => 'Le nombre d\'images à sauter en cas de détection doit être un entier supérieur ou égal à 0', + 'BadNameChars' => 'Les noms ne peuvent contenir que des lettres, chiffres, trait d\'union ou souligné', + 'BadPalette' => 'La palette doit être définie', // Added - 2009-03-31 + 'BadPath' => 'Le chemin doit être défini', + 'BadPort' => 'Le port doit être un nombre entier supérieur ou égal à 0', + 'BadPostEventCount' => 'Le nombre d\'images post-événements doit être un entier supérieur ou égal à 0', + 'BadPreEventCount' => 'Le nombre d\'images pré-événements doit être un entier supérieur ou égal à 0 et doit rester inférieur à la taille du tampon d\'images', + 'BadRefBlendPerc' => 'Le pourcentage de fusion de l\'image de référence doit être un entier supérieur à 0 et inférieur à 100', + 'BadSectionLength' => 'La longueur de la section doit être un entier supérieur ou égal à 30', + 'BadSignalCheckColour' => 'La chaîne de caractères pour la couleur d\'état du signal est invalide', + 'BadStreamReplayBuffer'=> 'Le tampon d\'images pour la relecture doit être un entier supérieur ou égal à 0', + 'BadWarmupCount' => 'Le nombre d\'images tests doit être un entier supérieur ou égal à 0', + 'BadWebColour' => 'La chaîne de caractères pour la couleur web est invalide', + 'BadWidth' => 'La valeur de la largeur est invalide', + 'Bandwidth' => 'Débit', + 'BandwidthHead' => 'Débit', // This is the end of the bandwidth status on the top of the console, different in many language due to phrasing + 'BlobPx' => 'Pix. forme', + 'BlobSizes' => 'Tailles de forme', 'Blobs' => 'Formes', - 'Brightness' => 'LuminositÈ;', + 'Brightness' => 'Luminosité;', + 'Buffer' => 'Tampon', // Added - 2015-04-18 'Buffers' => 'Tampons', - 'CanAutoFocus' => 'Can Auto Focus', - 'CanAutoGain' => 'Can Auto Gain', - 'CanAutoIris' => 'Can Auto Iris', - 'CanAutoWhite' => 'Can Auto White Bal.', - 'CanAutoZoom' => 'Can Auto Zoom', - 'CanFocus' => 'Can Focus', - 'CanFocusAbs' => 'Can Focus Absolute', - 'CanFocusCon' => 'Can Focus Continuous', - 'CanFocusRel' => 'Can Focus Relative', - 'CanGain' => 'Can Gain ', - 'CanGainAbs' => 'Can Gain Absolute', - 'CanGainCon' => 'Can Gain Continuous', - 'CanGainRel' => 'Can Gain Relative', - 'CanIris' => 'Can Iris', - 'CanIrisAbs' => 'Can Iris Absolute', - 'CanIrisCon' => 'Can Iris Continuous', - 'CanIrisRel' => 'Can Iris Relative', - 'CanMove' => 'Can Move', - 'CanMoveAbs' => 'Can Move Absolute', - 'CanMoveCon' => 'Can Move Continuous', - 'CanMoveDiag' => 'Can Move Diagonally', - 'CanMoveMap' => 'Can Move Mapped', - 'CanMoveRel' => 'Can Move Relative', - 'CanPan' => 'Can Pan' , - 'CanReset' => 'Can Reset', - 'CanSetPresets' => 'Can Set Presets', - 'CanSleep' => 'Can Sleep', - 'CanTilt' => 'Can Tilt', - 'CanWake' => 'Can Wake', - 'CanWhite' => 'Can White Balance', - 'CanWhiteAbs' => 'Can White Bal. Absolute', - 'CanWhiteBal' => 'Can White Bal.', - 'CanWhiteCon' => 'Can White Bal. Continuous', - 'CanWhiteRel' => 'Can White Bal. Relative', - 'CanZoom' => 'Can Zoom', - 'CanZoomAbs' => 'Can Zoom Absolute', - 'CanZoomCon' => 'Can Zoom Continuous', - 'CanZoomRel' => 'Can Zoom Relative', + 'CSSDescription' => 'Remplacer la feuille de style CSS par défaut', // Added - 2015-04-18 + 'CanAutoFocus' => 'Automatique', + 'CanAutoGain' => 'Automatique', + 'CanAutoIris' => 'Automatique', + 'CanAutoWhite' => 'Automatique', + 'CanAutoZoom' => 'Automatique', + 'CanFocus' => 'Focus', + 'CanFocusAbs' => 'Absolu', + 'CanFocusCon' => 'Continu', + 'CanFocusRel' => 'Relatif', + 'CanGain' => 'Gain', + 'CanGainAbs' => 'Absolu', + 'CanGainCon' => 'Continu', + 'CanGainRel' => 'Relatif', + 'CanIris' => 'Iris', + 'CanIrisAbs' => 'Absolu', + 'CanIrisCon' => 'Continu', + 'CanIrisRel' => 'Relatif', + 'CanMove' => 'Déplacer', + 'CanMoveAbs' => 'Absolu', + 'CanMoveCon' => 'Continu', + 'CanMoveDiag' => 'Diagonale', + 'CanMoveMap' => 'Sur plan', + 'CanMoveRel' => 'Relatif', + 'CanPan' => 'Panoramique' , + 'CanReset' => 'RàZ', + 'CanSetPresets' => 'Stockage prépos.', + 'CanSleep' => 'Veille', + 'CanTilt' => 'Inclinaison', + 'CanWake' => 'Réveil', + 'CanWhite' => 'Bal. des blancs', + 'CanWhiteAbs' => 'Absolu', + 'CanWhiteBal' => 'Bal. des blancs', + 'CanWhiteCon' => 'Continu', + 'CanWhiteRel' => 'Relatif', + 'CanZoom' => 'Zoom', + 'CanZoomAbs' => 'Absolu', + 'CanZoomCon' => 'Continu', + 'CanZoomRel' => 'Relatif', 'Cancel' => 'Annuler', - 'CancelForcedAlarm' => 'Annuler Alarme ForcÈe', + 'CancelForcedAlarm' => 'Annuler alarme forcée', 'CaptureHeight' => 'Hauteur', - 'CaptureMethod' => 'MÈthode', // Added - 2009-02-08 + 'CaptureMethod' => 'Méthode', // Added - 2009-02-08 'CapturePalette' => 'Palette', + 'CaptureResolution' => 'Résolution', // Added - 2015-04-18 'CaptureWidth' => 'Largeur', 'Cause' => 'Cause', - 'CheckMethod' => 'MÈthode vÈrif. alarme', - 'ChooseDetectedCamera' => 'Choose Detected Camera', // Added - 2009-03-31 + 'CheckMethod' => 'Méthode vérif. alarme', + 'ChooseDetectedCamera' => 'Choisir', // Added - 2009-03-31 'ChooseFilter' => 'Choisir filtre', - 'ChooseLogFormat' => 'Choose a log format', // Added - 2011-06-17 - 'ChooseLogSelection' => 'Choose a log selection', // Added - 2011-06-17 - 'ChoosePreset' => 'Choisir PrÈrÈglages', + 'ChooseLogFormat' => 'Choisir un format de journal', // Added - 2011-06-17 + 'ChooseLogSelection' => 'Choisir une sélection de journaux', // Added - 2011-06-17 + 'ChoosePreset' => 'Choisir préréglage', 'Clear' => 'Effacer', // Added - 2011-06-16 'Close' => 'Fermer', 'Colour' => 'Couleur', 'Command' => 'Commande', - 'Component' => 'Component', // Added - 2011-06-16 + 'Component' => 'Composant', // Added - 2011-06-16 'Config' => 'Config', - 'ConfiguredFor' => 'ConfigurÈ pour', - 'ConfirmDeleteEvents' => 'Are you sure you wish to delete the selected events?', - 'ConfirmPassword' => 'Confirmer mot de passe', + 'ConfiguredFor' => 'Configuré pour', + 'ConfirmDeleteEvents' => 'Etes-vous sûr de vouloir effacer le(s) événement(s) sélectionné(s)?', + 'ConfirmPassword' => 'Répéter mot de passe', 'ConjAnd' => 'et', 'ConjOr' => 'ou', 'Console' => 'Console', 'ContactAdmin' => 'Contactez votre administrateur SVP', 'Continue' => 'Continuer', 'Contrast' => 'Contraste', - 'Control' => 'Control', - 'ControlAddress' => 'Control Address', - 'ControlCap' => 'Control Capability', - 'ControlCaps' => 'Control Capabilities', - 'ControlDevice' => 'Control Device', - 'ControlType' => 'Control Type', - 'Controllable' => 'Controllable', + 'Control' => 'Contrôle', + 'ControlAddress' => 'Adresse', + 'ControlCap' => 'Capacité de contrôle', + 'ControlCaps' => 'Capacités de contrôle', + 'ControlDevice' => 'Equipement', + 'ControlType' => 'Type', + 'Controllable' => 'Controlâble', + 'Current' => 'En cours', // Added - 2015-04-18 'Cycle' => 'Cycle', - 'CycleWatch' => 'Cycle vision', - 'DateTime' => 'Date/Time', // Added - 2011-06-16 - 'Day' => 'Aujourd'hui', + 'CycleWatch' => 'Vision de cycle', + 'DateTime' => 'Date/Heure', // Added - 2011-06-16 + 'Day' => 'Aujourd\'hui', 'Debug' => 'Debug', - 'DefaultRate' => 'Vitesse par dÈfaut', - 'DefaultScale' => 'Echelle par dÈfaut', - 'DefaultView' => 'Vue par dÈfaut', + 'DefaultRate' => 'Vitesse par défaut', + 'DefaultScale' => 'Echelle par défaut', + 'DefaultView' => 'Vue par défaut', + 'Deinterlacing' => 'Désentrelacement', // Added - 2015-04-18 + 'Delay' => 'Délai', // Added - 2015-04-18 'Delete' => 'Effacer', 'DeleteAndNext' => 'Eff. & suiv.', 'DeleteAndPrev' => 'Eff. & prec.', - 'DeleteSavedFilter' => 'Eff. filtre sauvÈ', + 'DeleteSavedFilter' => 'Eff. filtre sauvé', 'Description' => 'Description', - 'DetectedCameras' => 'Detected Cameras', // Added - 2009-03-31 - 'Device' => 'CamÈra', // Added - 2009-02-08 - 'DeviceChannel' => 'Canal camÈra', - 'DeviceFormat' => 'Format camÈra', - 'DeviceNumber' => 'NumÈro camÈra', - 'DevicePath' => 'Chemin', - 'Devices' => 'CamÈras', + 'DetectedCameras' => 'Caméra(s) détectée(s)', // Added - 2009-03-31 + 'DetectedProfiles' => 'Profil(s) détecté(s)', // Added - 2015-04-18 + 'Device' => 'Equipement', // Added - 2009-02-08 + 'DeviceChannel' => 'Canal', + 'DeviceFormat' => 'Format vidéo', + 'DeviceNumber' => 'Numéro caméra', + 'DevicePath' => 'Chemin de l\'équipement', + 'Devices' => 'Caméras', 'Dimensions' => 'Dimensions', - 'DisableAlarms' => 'DÈsactiver les alarmes', + 'DisableAlarms' => 'Désactiver les alarmes', 'Disk' => 'Stockage', 'Display' => 'Affichage', // Added - 2011-01-30 - 'Displaying' => 'Displaying', // Added - 2011-06-16 - 'Donate' => 'Please Donate', - 'DonateAlready' => 'No, I\'ve already donated', - 'DonateEnticement' => 'You\'ve been running ZoneMinder for a while now and hopefully are finding it a useful addition to your home or workplace security. Although ZoneMinder is, and will remain, free and open source, it costs money to develop and support. If you would like to help support future development and new features then please consider donating. Donating is, of course, optional but very much appreciated and you can donate as much or as little as you like.

If you would like to donate please select the option below or go to http://www.zoneminder.com/donate.html in your browser.

Thank you for using ZoneMinder and don\'t forget to visit the forums on ZoneMinder.com for support or suggestions about how to make your ZoneMinder experience even better.', - 'DonateRemindDay' => 'Not yet, remind again in 1 day', - 'DonateRemindHour' => 'Not yet, remind again in 1 hour', - 'DonateRemindMonth' => 'Not yet, remind again in 1 month', - 'DonateRemindNever' => 'No, I don\'t want to donate, never remind', - 'DonateRemindWeek' => 'Not yet, remind again in 1 week', - 'DonateYes' => 'Yes, I\'d like to donate now', - 'DoNativeMotionDetection'=> 'Do Native Motion Detection', - 'Download' => 'TÈlÈcharger', - 'DuplicateMonitorName' => 'Duplicate Monitor Name', // Added - 2009-03-31 - 'Duration' => 'DurÈe', + 'Displaying' => 'Affichés', // Added - 2011-06-16 + 'DoNativeMotionDetection'=> 'Réaliser détection native', + 'Donate' => 'Veuillez faire un don', + 'DonateAlready' => 'Non, j\'ai déjà donné', + 'DonateEnticement' => 'Vous utilisez ZoneMinder depuis quelque temps et nous espérons que vous trouvez cette solution utile. Bien que ZoneMinder est, et restera, une solution libre et ouverte (open source), son développement et son maintien nécessitent des moyens financiers. Si vous voulez aider au développement et à l\'ajout de fonctionnalités, veuillez considérer la possibilité d\'effectuer un don. Les dons sont bien sûr optionnels mais grandement appréciés et vous pouvez donner le montant que vous désirez.

Si vous voulez effectuer un don, veuillez sélectionner l\'option ci-dessous ou veuillez vous rendre sur http://www.zoneminder.com/donate.html à l\'aide de votre navigateur internet.

Merci d\'utiliser ZoneMinder et n\'oubliez pas de visiter les forums sur ZoneMinder.com pour le support ou des suggestions pour rendre votre expérience de ZoneMinder encore meilleure.', + 'DonateRemindDay' => 'Pas encore, me rappeler dans 1 jour', + 'DonateRemindHour' => 'Pas encore, me rappeler dans 1 heure', + 'DonateRemindMonth' => 'Pas encore, me rappeler dans 1 mois', + 'DonateRemindNever' => 'Non, je ne veux pas faire de don, ne me rappeler pas', + 'DonateRemindWeek' => 'Pas encore, me rappeler dans 1 semaine', + 'DonateYes' => 'Oui, je souhaiterais faire un don maintenant', + 'Download' => 'Télécharger', + 'DuplicateMonitorName' => 'Dupliquer le nom de la caméra', // Added - 2009-03-31 + 'Duration' => 'Durée', 'Edit' => 'Editer', 'Email' => 'Email', 'EnableAlarms' => 'Activer les alarmes', - 'Enabled' => 'ActivÈ', + 'Enabled' => 'Activé', 'EnterNewFilterName' => 'Entrer nom nouv. filtre', 'Error' => 'Erreur', - 'ErrorBrackets' => 'Erreur, vÈrifiez que toutes les parenthËses ouvertes sont fermÈes', - 'ErrorValidValue' => 'Erreur, vÈrifiez que tous les termes ont une valeur valide', + 'ErrorBrackets' => 'Erreur, vérifiez que toutes les parenthèses ouvertes sont fermées', + 'ErrorValidValue' => 'Erreur, vérifiez que tous les termes ont une valeur valide', 'Etc' => 'etc', - 'Event' => 'ÈvÈnement', - 'EventFilter' => 'Filtre ÈvÈnement', + 'Event' => 'Evénement', + 'EventFilter' => 'Filtre événement', 'EventId' => 'Id', 'EventName' => 'Nom', - 'EventPrefix' => 'Prefix', - 'Events' => 'ÈvÈnements', + 'EventPrefix' => 'Préfixe', + 'Events' => 'Evénements', 'Exclude' => 'Exclure', - 'Execute' => 'Executer', + 'Execute' => 'Exécuter', 'Export' => 'Exporter', - 'ExportDetails' => 'Exporter dÈtails ÈvÈnement', - 'ExportFailed' => 'Exportation ÈchouÈe', + 'ExportDetails' => 'Exporter détails événements', + 'ExportFailed' => 'Exportation échouée', 'ExportFormat' => 'Format', 'ExportFormatTar' => 'Tar', 'ExportFormatZip' => 'Zip', - 'ExportFrames' => 'Exporter dÈtails image', - 'ExportImageFiles' => 'Exporter fichiers image', - 'ExportLog' => 'Exporter Log', // Added - 2011-06-17 + 'ExportFrames' => 'Exporter détails image', + 'ExportImageFiles' => 'Exporter fichiers images', + 'ExportLog' => 'Exporter fichiers journaux', // Added - 2011-06-17 'ExportMiscFiles' => 'Exporter autres fichiers', - 'ExportOptions' => 'Options d'exportation', - 'ExportSucceeded' => 'Exportation rÈussie', // Added - 2009-02-08 - 'ExportVideoFiles' => 'Exporter fichiers video', + 'ExportOptions' => 'Options d\'exportation', + 'ExportSucceeded' => 'Exportation réussie', // Added - 2009-02-08 + 'ExportVideoFiles' => 'Exporter fichiers vidéo', 'Exporting' => 'Exportation', 'FPS' => 'i/s', - 'FPSReportInterval' => 'FPS Report Interval', + 'FPSReportInterval' => 'Interv. de rafraîch. i/s', 'FTP' => 'FTP', 'Far' => 'Loin', 'FastForward' => 'Avance rapide', 'Feed' => 'Flux', 'Ffmpeg' => 'Ffmpeg', // Added - 2009-02-08 'File' => 'Fichier', + 'Filter' => 'Filtre', // Added - 2015-04-18 'FilterArchiveEvents' => 'Archiver', 'FilterDeleteEvents' => 'Effacer', - 'FilterEmailEvents' => 'Envoyer les dÈtails par mail', - 'FilterExecuteEvents' => 'Executer une commande', - 'FilterMessageEvents' => 'Envoyer les dÈtails par message', - 'FilterPx' => 'Filter Px', - 'FilterUnset' => 'You must specify a filter width and height', - 'FilterUploadEvents' => 'TransfÈrer', - 'FilterVideoEvents' => 'CrÈer video', + 'FilterEmailEvents' => 'Envoyer les détails par email', + 'FilterExecuteEvents' => 'Exécuter une commande', + 'FilterLog' => 'Filtre', // Added - 2015-04-18 + 'FilterMessageEvents' => 'Envoyer les détails par message', + 'FilterPx' => 'Filtre Px', + 'FilterUnset' => 'Vous devez spécifier une largeur et une hauteur de filtre', + 'FilterUploadEvents' => 'Transférer', + 'FilterVideoEvents' => 'Créer vidéo', 'Filters' => 'Filtres', 'First' => 'Prem.', - 'FlippedHori' => 'Flipped Horizontally', - 'FlippedVert' => 'Flipped Vertically', - 'FnNone' => 'None', // Added 2013.08.16. - 'FnMonitor' => 'Monitor', // Added 2013.08.16. - 'FnModect' => 'Modect', // Added 2013.08.16. - 'FnRecord' => 'Record', // Added 2013.08.16. + 'FlippedHori' => 'Inversé horizontalement', + 'FlippedVert' => 'Inversé verticalement', 'FnMocord' => 'Mocord', // Added 2013.08.16. + 'FnModect' => 'Modect', // Added 2013.08.16. + 'FnMonitor' => 'Monitor', // Added 2013.08.16. 'FnNodect' => 'Nodect', // Added 2013.08.16. + 'FnNone' => 'Aucun', // Added 2013.08.16. + 'FnRecord' => 'Record', // Added 2013.08.16. 'Focus' => 'Focus', - 'ForceAlarm' => 'Force Alarme', + 'ForceAlarm' => 'Forcer alarme', 'Format' => 'Format', 'Frame' => 'Image', - 'FrameId' => 'N∞ image', - 'FrameRate' => 'Cadence Image', + 'FrameId' => 'N°', + 'FrameRate' => 'Cadence image', 'FrameSkip' => 'Saut image', - 'MotionFrameSkip' => 'Motion Frame Skip', - 'Frames' => 'images', + 'Frames' => 'Images', 'Func' => 'Fct', 'Function' => 'Mode', 'Gain' => 'Gain', - 'General' => 'GÈnÈral', - 'GenerateVideo' => 'GÈnÈrer VidÈo', - 'GeneratingVideo' => 'GÈnÈration VidÈo', + 'General' => 'Général', + 'GenerateVideo' => 'Générer vidéo', + 'GeneratingVideo' => 'Génération vidéo', 'GoToZoneMinder' => 'Aller sur ZoneMinder.com', 'Grey' => 'Gris', 'Group' => 'Groupe', 'Groups' => 'Groupes', - 'HasFocusSpeed' => 'Has Focus Speed', - 'HasGainSpeed' => 'Has Gain Speed', - 'HasHomePreset' => 'Has Home Preset', - 'HasIrisSpeed' => 'Has Iris Speed', - 'HasPanSpeed' => 'Has Pan Speed', - 'HasPresets' => 'Has Presets', - 'HasTiltSpeed' => 'Has Tilt Speed', - 'HasTurboPan' => 'Has Turbo Pan', - 'HasTurboTilt' => 'Has Turbo Tilt', - 'HasWhiteSpeed' => 'Has White Bal. Speed', - 'HasZoomSpeed' => 'Has Zoom Speed', + 'HasFocusSpeed' => 'Vitesse', + 'HasGainSpeed' => 'Vitesse gain', + 'HasHomePreset' => 'Position par défaut', + 'HasIrisSpeed' => 'Vitesse', + 'HasPanSpeed' => 'Vitesse', + 'HasPresets' => 'Prépositions', + 'HasTiltSpeed' => 'Vitesse', + 'HasTurboPan' => 'Turbo', + 'HasTurboTilt' => 'Incl. turbo', + 'HasWhiteSpeed' => 'Vitesse', + 'HasZoomSpeed' => 'Vitesse', 'High' => 'Haut', - 'HighBW' => 'Haut N/B', - 'Home' => 'Home', + 'HighBW' => 'Haut débit', + 'Home' => 'Maison', 'Hour' => 'Heure', 'Hue' => 'Teinte', - 'Id' => 'N∞', + 'Id' => 'N°', 'Idle' => 'Vide', 'Ignore' => 'Ignorer', 'Image' => 'Image', 'ImageBufferSize' => 'Taille tampon image', 'Images' => 'Images', - 'In' => 'In', + 'In' => 'Dans', 'Include' => 'Inclure', - 'Inverted' => 'InversÈ', + 'Inverted' => 'Inversé', 'Iris' => 'Iris', - 'KeyString' => 'Key String', - 'Label' => 'Label', + 'KeyString' => 'Chaîne clé', + 'Label' => 'Etiquette', 'Language' => 'Langue', 'Last' => 'Dernier', 'Layout' => 'Disposition', // Added - 2009-02-08 'Level' => 'Niveau', // Added - 2011-06-16 'Libvlc' => 'Libvlc', - 'LimitResultsPost' => 'rÈsultats seulement;', // This is used at the end of the phrase 'Limit to first N results only' - 'LimitResultsPre' => 'Limite au premier', // This is used at the beginning of the phrase 'Limit to first N results only' + 'LimitResultsPost' => 'résultat(s) seulement', // This is used at the end of the phrase 'Limit to first N results only' + 'LimitResultsPre' => 'Limiter au(x) premier(s)', // This is used at the beginning of the phrase 'Limit to first N results only' 'Line' => 'Ligne', // Added - 2011-06-16 - 'LinkedMonitors' => 'CamÈra(s) liÈ(s)', + 'LinkedMonitors' => 'Caméra(s) liée(s)', 'List' => 'Liste', - 'Load' => 'CPU', + 'Load' => 'Charge', 'Local' => 'Local', - 'Log' => 'Log', // Added - 2011-06-16 - 'LoggedInAs' => 'ConnectÈ cÙ', - 'Logging' => 'Logging', // Added - 2011-06-16 + 'Log' => 'Journal', // Added - 2011-06-16 + 'LoggedInAs' => 'Connecté en tant que', + 'Logging' => 'Journalisation', // Added - 2011-06-16 'LoggingIn' => 'Connexion', - 'Login' => 'Login', - 'Logout' => 'DÈconnexion', - 'Logs' => 'Logs', // Added - 2011-06-17 + 'Login' => 'Connexion', + 'Logout' => 'Déconnexion', + 'Logs' => 'Journaux', // Added - 2011-06-17 'Low' => 'Bas', - 'LowBW' => 'Basse N/B', + 'LowBW' => 'Bas débit', 'Main' => 'Principal', 'Man' => 'Man', 'Manual' => 'Manuel', - 'Mark' => 'SÈlÈctionner', + 'Mark' => 'Sélectionner', 'Max' => 'Max', - 'MaxBandwidth' => 'Max Bandwidth', + 'MaxBandwidth' => 'Débit max', 'MaxBrScore' => 'Score
max', - 'MaxFocusRange' => 'Max Focus Range', - 'MaxFocusSpeed' => 'Max Focus Speed', - 'MaxFocusStep' => 'Max Focus Step', - 'MaxGainRange' => 'Max Gain Range', - 'MaxGainSpeed' => 'Max Gain Speed', - 'MaxGainStep' => 'Max Gain Step', - 'MaxIrisRange' => 'Max Iris Range', - 'MaxIrisSpeed' => 'Max Iris Speed', - 'MaxIrisStep' => 'Max Iris Step', - 'MaxPanRange' => 'Max Pan Range', - 'MaxPanSpeed' => 'Max Pan Speed', - 'MaxPanStep' => 'Max Pan Step', - 'MaxTiltRange' => 'Max Tilt Range', - 'MaxTiltSpeed' => 'Max Tilt Speed', - 'MaxTiltStep' => 'Max Tilt Step', - 'MaxWhiteRange' => 'Max White Bal. Range', - 'MaxWhiteSpeed' => 'Max White Bal. Speed', - 'MaxWhiteStep' => 'Max White Bal. Step', - 'MaxZoomRange' => 'Max Zoom Range', - 'MaxZoomSpeed' => 'Max Zoom Speed', - 'MaxZoomStep' => 'Max Zoom Step', + 'MaxFocusRange' => 'Plage max', + 'MaxFocusSpeed' => 'Vitesse max', + 'MaxFocusStep' => 'Pas max', + 'MaxGainRange' => 'Plage gain max', + 'MaxGainSpeed' => 'Vitesse gain max', + 'MaxGainStep' => 'Pas gain max', + 'MaxIrisRange' => 'Plage max', + 'MaxIrisSpeed' => 'Vitesse max', + 'MaxIrisStep' => 'Pas max', + 'MaxPanRange' => 'Plage max', + 'MaxPanSpeed' => 'Vitesse max', + 'MaxPanStep' => 'Pas max', + 'MaxTiltRange' => 'Plage max', + 'MaxTiltSpeed' => 'Vitesse max', + 'MaxTiltStep' => 'Pas max', + 'MaxWhiteRange' => 'Plage max', + 'MaxWhiteSpeed' => 'Vitesse max', + 'MaxWhiteStep' => 'Pas max', + 'MaxZoomRange' => 'Plage max', + 'MaxZoomSpeed' => 'Vitesse max', + 'MaxZoomStep' => 'Pas max', 'MaximumFPS' => 'i/s maximum', 'Medium' => 'Moyen', - 'MediumBW' => 'Moy. N/B', + 'MediumBW' => 'Moy. débit', 'Message' => 'Message', // Added - 2011-06-16 - 'MinAlarmAreaLtMax' => 'Minimum alarm area should be less than maximum', - 'MinAlarmAreaUnset' => 'You must specify the minimum alarm pixel count', - 'MinBlobAreaLtMax' => 'Aire blob min. doit Í < aire blob maximum', - 'MinBlobAreaUnset' => 'You must specify the minimum blob pixel count', - 'MinBlobLtMinFilter' => 'Minimum blob area should be less than or equal to minimum filter area', - 'MinBlobsLtMax' => 'Blobs min. doit Í < blobs max.', - 'MinBlobsUnset' => 'You must specify the minimum blob count', - 'MinFilterAreaLtMax' => 'Minimum filter area should be less than maximum', - 'MinFilterAreaUnset' => 'You must specify the minimum filter pixel count', - 'MinFilterLtMinAlarm' => 'Minimum filter area should be less than or equal to minimum alarm area', - 'MinFocusRange' => 'Min Focus Range', - 'MinFocusSpeed' => 'Min Focus Speed', - 'MinFocusStep' => 'Min Focus Step', - 'MinGainRange' => 'Min Gain Range', - 'MinGainSpeed' => 'Min Gain Speed', - 'MinGainStep' => 'Min Gain Step', - 'MinIrisRange' => 'Min Iris Range', - 'MinIrisSpeed' => 'Min Iris Speed', - 'MinIrisStep' => 'Min Iris Step', - 'MinPanRange' => 'Min Pan Range', - 'MinPanSpeed' => 'Min Pan Speed', - 'MinPanStep' => 'Min Pan Step', - 'MinPixelThresLtMax' => 'Seuil pixel min. doit Í < seuil pixel max.', - 'MinPixelThresUnset' => 'You must specify a minimum pixel threshold', - 'MinTiltRange' => 'Min Tilt Range', - 'MinTiltSpeed' => 'Min Tilt Speed', - 'MinTiltStep' => 'Min Tilt Step', - 'MinWhiteRange' => 'Min White Bal. Range', - 'MinWhiteSpeed' => 'Min White Bal. Speed', - 'MinWhiteStep' => 'Min White Bal. Step', - 'MinZoomRange' => 'Min Zoom Range', - 'MinZoomSpeed' => 'Min Zoom Speed', - 'MinZoomStep' => 'Min Zoom Step', + 'MinAlarmAreaLtMax' => 'La surface minimum en alarme doit être inférieure au maximum', + 'MinAlarmAreaUnset' => 'Vous devez spécifier la surface minimum en alarme (nb de pixels)', + 'MinBlobAreaLtMax' => 'La surface minimum des formes doit être inférieure au maximum', + 'MinBlobAreaUnset' => 'Vous devez spécifier la surface minimum des formes (nb de pixels)', + 'MinBlobLtMinFilter' => 'La surface minimum des formes doit être inférieure à la surface minimum filtrée', + 'MinBlobsLtMax' => 'Le nombre minimum de formes doit être inférieur au maximum', + 'MinBlobsUnset' => 'Vous devez spécifier le nombre minimum de formes', + 'MinFilterAreaLtMax' => 'La surface minimum filtrée doit être inférieure au maximum', + 'MinFilterAreaUnset' => 'Vous devez spécifier la surface minimum filtrée (nb de pixels)', + 'MinFilterLtMinAlarm' => 'La surface minimum filtrée doit être inférieure à la surface minimum en alarme', + 'MinFocusRange' => 'Plage min', + 'MinFocusSpeed' => 'Vitesse min', + 'MinFocusStep' => 'Pas min', + 'MinGainRange' => 'Plage gain min', + 'MinGainSpeed' => 'Vitesse gain min', + 'MinGainStep' => 'Pas gain min', + 'MinIrisRange' => 'Plage min', + 'MinIrisSpeed' => 'Vitesse min', + 'MinIrisStep' => 'Pas min', + 'MinPanRange' => 'Plage min', + 'MinPanSpeed' => 'Vitesse min', + 'MinPanStep' => 'Pas min', + 'MinPixelThresLtMax' => 'Le seuil minimum de pixels doit être inférieur au maximum', + 'MinPixelThresUnset' => 'Vous devez spécifier le seuil minimum de pixels', + 'MinTiltRange' => 'Plage min', + 'MinTiltSpeed' => 'Vitesse min', + 'MinTiltStep' => 'Pas min', + 'MinWhiteRange' => 'Plage min', + 'MinWhiteSpeed' => 'Vitesse min', + 'MinWhiteStep' => 'Pas min', + 'MinZoomRange' => 'Plage min', + 'MinZoomSpeed' => 'Vitesse min', + 'MinZoomStep' => 'Pas min', 'Misc' => 'Divers', - 'Monitor' => 'CamÈra', - 'MonitorIds' => 'N∞ camÈra', - 'MonitorPreset' => 'PrÈrÈglages camÈra', - 'MonitorPresetIntro' => 'Select an appropriate preset from the list below.

Please note that this may overwrite any values you already have configured for this monitor.

', - 'MonitorProbe' => 'Scanner CamÈra', // Added - 2009-03-31 - 'MonitorProbeIntro' => 'The list below shows detected analog and network cameras and whether they are already being used or available for selection.

Select the desired entry from the list below.

Please note that not all cameras may be detected and that choosing a camera here may overwrite any values you already have configured for the current monitor.

', // Added - 2009-03-31 - 'Monitors' => 'CamÈras', + 'Mode' => 'Mode', // Added - 2015-04-18 + 'Monitor' => 'Caméra', + 'MonitorIds' => 'N° caméra', + 'MonitorPreset' => 'Préréglage caméra', + 'MonitorPresetIntro' => 'Sélectionnez un préréglage dans la liste ci-dessous.

Veuillez noter que la sauvegarde entraînera l\'écrasement des paramètres déjà configurés pour la caméra en cours.

', + 'MonitorProbe' => 'Autodétection caméras', // Added - 2009-03-31 + 'MonitorProbeIntro' => 'La liste ci-dessous montre les caméras détectées localement ou sur le réseau, qu\'elles soient déjà configurées ou non.

Sélectionnez la caméra désirée dans la liste.

Veuillez noter que toutes les caméras ne sont pas forcément détectées et que la sauvegarde entraînera l\'écrasement des paramètres déjà configurés pour la caméra en cours.

', // Added - 2009-03-31 + 'Monitors' => 'Caméras', 'Montage' => 'Montage', 'Month' => 'Mois', 'More' => 'Plus', // Added - 2011-06-16 - 'Move' => 'DÈplacer', - 'MtgDefault' => 'Default', // Added 2013.08.15. - 'Mtg2widgrd' => '2-wide grid', // Added 2013.08.15. - 'Mtg3widgrd' => '3-wide grid', // Added 2013.08.15. - 'Mtg4widgrd' => '4-wide grid', // Added 2013.08.15. - 'Mtg3widgrx' => '3-wide grid, scaled, enlarge on alarm', // Added 2013.08.15. - 'MustBeGe' => 'doit Ítre sup. ou Ègal ‡', - 'MustBeLe' => 'doit Ítre inf. ou Ègal ‡', + 'MotionFrameSkip' => 'Saut image en alarme', + 'Move' => 'Déplacement', + 'Mtg2widgrd' => '2 colonnes', // Added 2013.08.15. + 'Mtg3widgrd' => '3 colonnes', // Added 2013.08.15. + 'Mtg3widgrx' => '3 colonnes, échelle auto, élargir sur alarme', // Added 2013.08.15. + 'Mtg4widgrd' => '4 colonnes', // Added 2013.08.15. + 'MtgDefault' => 'Défaut', // Added 2013.08.15. + 'MustBeGe' => 'doit être sup. ou égal à', + 'MustBeLe' => 'doit être inf. ou égal à', 'MustConfirmPassword' => 'Confirmez le mot de passe', 'MustSupplyPassword' => 'Entrez un mot de passe', 'MustSupplyUsername' => 'Entrez un nom d\'utilisateur', 'Name' => 'Nom', - 'Near' => 'PrËs', - 'Network' => 'RÈseau', + 'Near' => 'Près', + 'Network' => 'Réseau', 'New' => 'Nouv.', - 'NewGroup' => 'Nouv. Groupe', - 'NewLabel' => 'Nouv. Label', - 'NewPassword' => 'Nouv. mt de passe', - 'NewState' => 'Nv Ètat', - 'NewUser' => 'Nv util.', + 'NewGroup' => 'Nouv. groupe', + 'NewLabel' => 'Nouv. label', + 'NewPassword' => 'Mot de passe', + 'NewState' => 'Nouv. état', + 'NewUser' => 'Nouv. utilisateur', 'Next' => 'Suivant', 'No' => 'Non', - 'NoDetectedCameras' => 'Pas de caméras dÈtectÈ', // Added - 2009-03-31 - 'NoFramesRecorded' => 'Pas d\'image enregistrÈe pour cet ÈvÈnement', + 'NoDetectedCameras' => 'Pas de caméras détectées', // Added - 2009-03-31 + 'NoFramesRecorded' => 'Pas d\'images enregistrées pour cet événement', 'NoGroup' => 'Pas de groupe', - 'NoSavedFilters' => 'Pasfiltressauv', - 'NoStatisticsRecorded' => 'Pas de statistiques disponibles pour cet ÈvÈnmnt/imag.', + 'NoSavedFilters' => 'Pas de filtres sauvegardés', + 'NoStatisticsRecorded' => 'Pas de statistiques disponibles pour cet événmnt/imag.', 'None' => 'Aucun', 'NoneAvailable' => 'Aucun disponible', 'Normal' => 'Normal', 'Notes' => 'Notes', - 'NumPresets' => 'Num PrÈrÈglages', - 'Off' => 'Off', - 'On' => 'On', - 'OpEq' => 'Ègal ‡', - 'OpGt' => 'sup. ‡', - 'OpGtEq' => 'plus grand ou Ègal ‡', + 'NumPresets' => 'Nombre', + 'Off' => 'Désactiver', + 'On' => 'Activer', + 'OnvifCredentialsIntro'=> 'Veuillez fournir un nom d\'utilisateur et un mot de passe pour la caméra sélectionnée.
Si aucun utilisateur n\'a été créé pour la caméra alors l\'utilisateur saisi sera créé avec le mot de passe associé.

', // Added - 2015-04-18 + 'OnvifProbe' => 'ONVIF', // Added - 2015-04-18 + 'OnvifProbeIntro' => 'La liste ci-dessous montre les caméras ONVIF détectées et si elles sont déjà utilisées ou disponibles.

Sélectionnez la caméra souhaitée dans la liste ci-dessous.

Veuillez noter que toutes les caméras ne sont pas forcément détectées et que la sauvegarde entraînera l\'écrasement des paramètres déjà configurés pour la caméra en cours.

', // Added - 2015-04-18 + 'OpEq' => 'égal à', + 'OpGt' => 'sup. à', + 'OpGtEq' => 'plus grand ou égal à', 'OpIn' => 'en lot', - 'OpLt' => 'inf. ‡', - 'OpLtEq' => 'inf. ou Ègal ‡', + 'OpLt' => 'inf. à', + 'OpLtEq' => 'inf. ou égal à', 'OpMatches' => 'correspond', 'OpNe' => 'diff. de', 'OpNotIn' => 'pas en lot', 'OpNotMatches' => 'ne correspond pas', 'Open' => 'Ouvrir', 'OptionHelp' => 'Aide', - 'OptionRestartWarning' => 'These changes may not come into effect fully\nwhile the system is running. When you have\nfinished making your changes please ensure that\nyou restart ZoneMinder.', + 'OptionRestartWarning' => 'Ces changements peuvent nécessiter un redémarrage de ZoneMinder pour être pleinement opérationnels.', 'Options' => 'Options', - 'OrEnterNewName' => 'ou entrez nv nom', + 'OrEnterNewName' => 'ou entrez nouv. nom', 'Order' => 'Ordre', 'Orientation' => 'Orientation', - 'Out' => 'Out', + 'Out' => 'Arrière', 'OverwriteExisting' => 'Ecraser l\'existant', - 'Paged' => 'PaginÈe', - 'Pan' => 'Pan', - 'PanLeft' => 'Pan Left', - 'PanRight' => 'Pan Right', - 'PanTilt' => 'Pan/Tilt', - 'Parameter' => 'ParamËtre', - 'Password' => 'Mt de passe', - 'PasswordsDifferent' => 'Les 2 mots de passe sont diffÈrents', + 'Paged' => 'Paginée', + 'Pan' => 'Panoramique', + 'PanLeft' => 'Pano. gauche', + 'PanRight' => 'Pano. droite', + 'PanTilt' => 'Pano. / Incl.', + 'Parameter' => 'Paramètre', + 'Password' => 'Mot de passe', + 'PasswordsDifferent' => 'Les 2 mots de passe sont différents', 'Paths' => 'Chemins', 'Pause' => 'Pause', - 'Phone' => 'TÈlÈphone', - 'PhoneBW' => 'Phone B/W', + 'Phone' => 'Téléphone', + 'PhoneBW' => 'Débit tél.', 'Pid' => 'PID', // Added - 2011-06-16 - 'PixelDiff' => 'Pixel Diff', - 'Pixels' => 'pixels', + 'PixelDiff' => 'Diff. pixel', + 'Pixels' => 'nb pixels', 'Play' => 'Lire', 'PlayAll' => 'Tout lire', 'PleaseWait' => 'Attendez', - 'Plugins' => 'Plugins', + 'Plugins' => 'Greffons', 'Point' => 'Point', - 'PostEventImageBuffer' => 'Nombre dimage(s) post-ÈvÈnement', - 'PreEventImageBuffer' => 'Nombre dimage(s) prÈ-ÈvÈnement', - 'PreserveAspect' => 'Conserver les proportions', - 'Preset' => 'PrÈrÈglage', - 'Presets' => 'PrÈrÈglages', - 'Prev' => 'PrecÈdent', - 'Probe' => 'Scanner', // Added - 2009-03-31 + 'PostEventImageBuffer' => 'Nb d\'image(s) post-événement', + 'PreEventImageBuffer' => 'Nb d\'image(s) pré-événement', + 'PreserveAspect' => 'Préserver les proportions', + 'Preset' => 'Préréglage', + 'Presets' => 'Préréglages', + 'Prev' => 'Précédent', + 'Probe' => 'Autodétection', // Added - 2009-03-31 + 'ProfileProbe' => 'Détection de flux', // Added - 2015-04-18 + 'ProfileProbeIntro' => 'La liste ci-dessous montre les profils de flux existants pour la caméra sélectionnée.

Sélectionnez le profil désiré dans la liste ci-dessous.

Veuillez noter que ZoneMinder ne peut pas configurer de profils additionels et que la sauvegarde entraînera l\'écrasement des paramètres déjà configurés pour la caméra en cours.

', // Added - 2015-04-18 + 'Progress' => 'Progression', // Added - 2015-04-18 'Protocol' => 'Protocole', 'Rate' => 'Vitesse', - 'Real' => 'RÈel', + 'Real' => 'Réel', 'Record' => 'Enregistrer', - 'RefImageBlendPct' => 'Reference Image Blend %ge', - 'Refresh' => 'RafraÓchir', + 'RefImageBlendPct' => '% fusion image référence', + 'Refresh' => 'Rafraîchir', 'Remote' => 'Distant', - 'RemoteHostName' => 'IP/DNS', + 'RemoteHostName' => 'Nom d\'hôte', 'RemoteHostPath' => 'Chemin', 'RemoteHostPort' => 'Port', 'RemoteHostSubPath' => 'Sous-chemin', // Added - 2009-02-08 'RemoteImageColours' => 'Nombre de couleurs', - 'RemoteMethod' => 'MÈthode', // Added - 2009-02-08 + 'RemoteMethod' => 'Méthode', // Added - 2009-02-08 'RemoteProtocol' => 'Protocole', // Added - 2009-02-08 'Rename' => 'Renommer', 'Replay' => 'Relire', - 'ReplayAll' => 'Tous les ÈvÈnements', - 'ReplayGapless' => 'EvÈnement Gapless', - 'ReplaySingle' => 'EvÈnement unique', - 'Reset' => 'RAZ', - 'ResetEventCounts' => 'Rem. ‡ 0 comptage des Èvts', - 'Restart' => 'RedÈmarrer', - 'Restarting' => 'RedÈmarrage', - 'RestrictedCameraIds' => 'N∞ camÈras confid.', - 'RestrictedMonitors' => 'Restricted Monitors', - 'ReturnDelay' => 'Return Delay', - 'ReturnLocation' => 'Return Location', - 'Rewind' => 'Rembobiner', + 'ReplayAll' => 'Tous les événements', + 'ReplayGapless' => 'Rejouer sans blancs', + 'ReplaySingle' => 'Rejouer seul', + 'Reset' => 'RàZ', + 'ResetEventCounts' => 'RàZ compteur évts', + 'Restart' => 'Redémarrer', + 'Restarting' => 'Redémarrage', + 'RestrictedCameraIds' => 'N°', + 'RestrictedMonitors' => 'Caméra(s) uniquement visible(s)', + 'ReturnDelay' => 'Délai de retour', + 'ReturnLocation' => 'Position de retour', + 'Rewind' => 'Reculer', 'RotateLeft' => 'Rotation g.', 'RotateRight' => 'Rotation d.', - 'RunLocalUpdate' => 'Please run zmupdate.pl to update', // Added - 2011-05-25 + 'RunLocalUpdate' => 'Veuillez éxecuter zmupdate.pl pour mettre à jour', // Added - 2011-05-25 'RunMode' => 'Mode de lancement', - 'RunState' => 'Changer Ètat', - 'Running' => 'En Fonctionnement', - 'Save' => 'OK', + 'RunState' => 'Changer d\'état', + 'Running' => 'En marche', + 'Save' => 'Sauvegarder', 'SaveAs' => 'Sauvegarder sous', - 'SaveFilter' => 'Sauvegarder Filtre', + 'SaveFilter' => 'Sauvegarder filtre', 'Scale' => 'Echelle', 'Score' => 'Score', 'Secs' => 'Secs', 'Sectionlength' => 'Longueur section', - 'Select' => 'SÈlectionner', - 'SelectFormat' => 'SÈlectionner Format', // Added - 2011-06-17 - 'SelectLog' => 'SÈlectionner Log', // Added - 2011-06-17 - 'SelectMonitors' => 'SÈlectionner camÈras', - 'SelfIntersecting' => 'Polygon edges must not intersect', - 'Set' => 'DÉfinir', - 'SetNewBandwidth' => 'RÈgler le dÈbit', - 'SetPreset' => 'DÈfinir PrÈrÈglages', - 'Settings' => 'RÈglages', + 'Select' => 'Sélectionner', + 'SelectFormat' => 'Sélectionner format', // Added - 2011-06-17 + 'SelectLog' => 'Sélectionner journal', // Added - 2011-06-17 + 'SelectMonitors' => 'Sélectionner caméras', + 'SelfIntersecting' => 'Les bords du polygone ne doivent pas se croiser', + 'Set' => 'Définir', + 'SetNewBandwidth' => 'Régler le débit', + 'SetPreset' => 'Définir préréglage', + 'Settings' => 'Réglages', 'ShowFilterWindow' => 'Filtres', - 'ShowTimeline' => 'Afficher Chronologie', - 'SignalCheckColour' => 'Signal Check Colour', + 'ShowTimeline' => 'Afficher chronologie', + 'SignalCheckColour' => 'Couleur vérif. signal', 'Size' => 'Taille', - 'SkinDescription' => 'Change the default skin for this computer', // Added - 2011-01-30 + 'SkinDescription' => 'Remplacer le skin par défaut', // Added - 2011-01-30 'Sleep' => 'Veille', 'SortAsc' => 'Asc', 'SortBy' => 'Trier par', @@ -614,136 +637,140 @@ $SLANG = array( 'Source' => 'Source', 'SourceColours' => 'Couleurs', // Added - 2009-02-08 'SourcePath' => 'Chemin', // Added - 2009-02-08 - 'SourceType' => 'Type de Source', + 'SourceType' => 'Type de source', 'Speed' => 'Vitesse', 'SpeedHigh' => 'Rapide', 'SpeedLow' => 'Lent', 'SpeedMedium' => 'Moyen', 'SpeedTurbo' => 'Turbo', - 'Start' => 'DÈmarrer', + 'Start' => 'Démarrer', 'State' => 'Etat', 'Stats' => 'Stats', 'Status' => 'Statut', - 'Step' => 'Step', - 'StepBack' => 'Step Back', - 'StepForward' => 'Step Forward', - 'StepLarge' => 'Large Step', - 'StepMedium' => 'Medium Step', - 'StepNone' => 'No Step', - 'StepSmall' => 'Small Step', + 'Step' => 'Pas', + 'StepBack' => 'Reculer', + 'StepForward' => 'Avancer', + 'StepLarge' => 'Pas large', + 'StepMedium' => 'Pas moyen', + 'StepNone' => 'Pas nul', + 'StepSmall' => 'Pas faible', 'Stills' => 'Photos', - 'Stop' => 'ArrÍter', - 'Stopped' => 'ArrÍtÈ', + 'Stop' => 'Arrêter', + 'Stopped' => 'Arrêté', 'Stream' => 'Flux', - 'StreamReplayBuffer' => 'Stream Replay Image Buffer', + 'StreamReplayBuffer' => 'Nb d\'image(s) pour relecture', 'Submit' => 'Soumettre', - 'System' => 'SystËme', - 'SystemLog' => 'System Log', // Added - 2011-06-16 - 'Tele' => 'Tele', + 'System' => 'Système', + 'SystemLog' => 'Journal système', // Added - 2011-06-16 + 'TargetColorspace' => 'Espace de couleur cible', // Added - 2015-04-18 + 'Tele' => 'Télé', 'Thumbnail' => 'Miniature', - 'Tilt' => 'Tilt', + 'Tilt' => 'Incliner', 'Time' => 'Heure', - 'TimeDelta' => 'Time Delta', + 'TimeDelta' => 'Temps', 'TimeStamp' => 'Horodatage', 'Timeline' => 'Chronologie', - 'TimelineTip1' => 'Pass your mouse over the graph to view a snapshot image and event details.', // Added 2013.08.15. - 'TimelineTip2' => 'Click on the coloured sections of the graph, or the image, to view the event.', // Added 2013.08.15. - 'TimelineTip3' => 'Click on the background to zoom in to a smaller time period based around your click.', // Added 2013.08.15. - 'TimelineTip4' => 'Use the controls below to zoom out or navigate back and forward through the time range.', // Added 2013.08.15. + 'TimelineTip1' => 'Passez votre souris sur le graphique pour visualiser un aperçu de l\'image et les détails de l\'événement.', // Added 2013.08.15. + 'TimelineTip2' => 'Cliquez sur les sections colorées du graphique ou sur l\'image pour voir l\'événement.', // Added 2013.08.15. + 'TimelineTip3' => 'Cliquez sur le fond pour zoomer sur une plage de temps plus réduite autour de votre clic.', // Added 2013.08.15. + 'TimelineTip4' => 'Utilisez les contrôles ci-dessous pour faire un zoom arrière ou naviguer en arrière et avancer sur l\'intervalle de temps.', // Added 2013.08.15. 'Timestamp' => 'Horodatage', - 'TimestampLabelFormat' => 'Format Horodatage', - 'TimestampLabelX' => 'Label Horodatage X', - 'TimestampLabelY' => 'Label Horodatage Y', - 'Today' => 'Aujourd'hui', + 'TimestampLabelFormat' => 'Format', + 'TimestampLabelX' => 'Coordonnée X', + 'TimestampLabelY' => 'Coordonnée Y', + 'Today' => 'Aujourd\'hui', 'Tools' => 'Outils', 'Total' => 'Total', // Added - 2011-06-16 'TotalBrScore' => 'Score
total', - 'TrackDelay' => 'Track Delay', - 'TrackMotion' => 'Track Motion', - 'Triggers' => 'DÈclenchements', - 'TurboPanSpeed' => 'Turbo Pan Speed', - 'TurboTiltSpeed' => 'Turbo Tilt Speed', + 'TrackDelay' => 'Délai suivi', + 'TrackMotion' => 'Suivre détection', + 'Triggers' => 'Déclenchements', + 'TurboPanSpeed' => 'Vitesse turbo', + 'TurboTiltSpeed' => 'Vitesse turbo', 'Type' => 'Type', - 'Unarchive' => 'DÈsarchiver', - 'Undefined' => 'indÈfini', // Added - 2009-02-08 - 'Units' => 'UnitÈs', + 'Unarchive' => 'Désarchiver', + 'Undefined' => 'Indéfini', // Added - 2009-02-08 + 'Units' => 'Unité', 'Unknown' => 'Inconnu', - 'Update' => 'Actualiser', - 'UpdateAvailable' => 'Mise ‡ jour de ZM disponible', - 'UpdateNotNecessary' => 'Pas de mise ‡ jour disponible', - 'Updated' => 'ActualisÈ', // Added - 2011-06-16 - 'Upload' => 'TransfÈrer', // Added - 2011-08-23 - 'UsedPlugins' => 'Used Plugins', - 'UseFilter' => 'Utiliser Filtre', - 'UseFilterExprsPost' => ' filter expressions', // This is used at the end of the phrase 'use N filter expressions' - 'UseFilterExprsPre' => 'Util. ', // This is used at the beginning of the phrase 'use N filter expressions' + 'Update' => 'Mettre à jour', + 'UpdateAvailable' => 'Mise à jour dispo.', + 'UpdateNotNecessary' => 'Pas de mise à jour dispo.', + 'Updated' => 'Mis à jour', // Added - 2011-06-16 + 'Upload' => 'Transférer', // Added - 2011-08-23 + 'UseFilter' => 'Utiliser filtre', + 'UseFilterExprsPost' => ' filtre expressions', // This is used at the end of the phrase 'use N filter expressions' + 'UseFilterExprsPre' => 'Utiliser ', // This is used at the beginning of the phrase 'use N filter expressions' + 'UsedPlugins' => 'Filtres utilisés', 'User' => 'Utilisateur', - 'Username' => 'Login', + 'Username' => 'Nom', 'Users' => 'Utilisateurs', + 'V4L' => 'V4L', + 'V4LCapturesPerFrame' => 'Nb captures par image', + 'V4LMultiBuffer' => 'Mise en tampon multiple', 'Value' => 'Valeur', 'Version' => 'Version', 'VersionIgnore' => 'Ignorer cette version', - 'VersionRemindDay' => 'Me rappeler ds 1 j.', - 'VersionRemindHour' => 'Me rappleler dans 1 h.', + 'VersionRemindDay' => 'Me rappeler dans 1 jour', + 'VersionRemindHour' => 'Me rappeler dans 1 heure', 'VersionRemindNever' => 'Ne pas avertir des nvelles versions', - 'VersionRemindWeek' => 'Me rappeler ds 1 sem.', - 'Video' => 'VidÈo', - 'VideoFormat' => 'Format de la VidÈo', - 'VideoGenFailed' => 'Echec gÈnÈration vidÈo!', - 'VideoGenFiles' => 'Existing Video Files', + 'VersionRemindWeek' => 'Me rappeler dans 1 sem.', + 'Video' => 'Vidéo', + 'VideoFormat' => 'Format de la vidéo', + 'VideoGenFailed' => 'Echec génération vidéo !', + 'VideoGenFiles' => 'Fichiers vidéo existants', 'VideoGenNoFiles' => 'Aucun fichier vidéo trouvé', - 'VideoGenParms' => 'ParamËtres gÈnÈration vidÈo', - 'VideoGenSucceeded' => 'VidÈo gÈnÈrÈe avec succËs!', - 'VideoSize' => 'taille vidÈo', + 'VideoGenParms' => 'Paramètres génération vidéo', + 'VideoGenSucceeded' => 'Vidéo générée avec succès !', + 'VideoSize' => 'Taille vidéo', 'View' => 'Voir', 'ViewAll' => 'Tout voir', - 'ViewEvent' => 'Voir ÈvÈnement', - 'ViewPaged' => 'Vue paginÈe', - 'Wake' => 'RÈveiller', - 'WarmupFrames' => 'Images test', + 'ViewEvent' => 'Voir événement', + 'ViewPaged' => 'Vue paginée', + 'Wake' => 'Réveiller', + 'WarmupFrames' => 'Nb d\'image(s) tests', 'Watch' => 'Regarder', 'Web' => 'Web', - 'WebColour' => 'Web Colour', + 'WebColour' => 'Couleur web', 'Week' => 'Semaine', - 'White' => 'White', - 'WhiteBalance' => 'White Balance', + 'White' => 'Blanc', + 'WhiteBalance' => 'Balance des blancs', 'Wide' => 'Large', 'X' => 'X', 'X10' => 'X10', - 'X10ActivationString' => 'X10:chaÓne activation', - 'X10InputAlarmString' => 'X10:chaÓne alarme entrÈe', - 'X10OutputAlarmString' => 'X10:chaÓne alarme sortie', + 'X10ActivationString' => 'X10:chaîne activation', + 'X10InputAlarmString' => 'X10:chaîne alarme entrée', + 'X10OutputAlarmString' => 'X10:chaîne alarme sortie', 'Y' => 'Y', 'Yes' => 'Oui', - 'YouNoPerms' => 'Permissions nÈcessaires pour cette ressource.', + 'YouNoPerms' => 'Permissions nécessaires pour cette ressource.', 'Zone' => 'Zone', - 'ZoneAlarmColour' => 'Couleur alarme (Red/Green/Blue)', - 'ZoneArea' => 'Zone Area', - 'ZoneFilterSize' => 'Filter Width/Height (pixels)', - 'ZoneMinMaxAlarmArea' => 'Min/Max Alarmed Area', - 'ZoneMinMaxBlobArea' => 'Min/Max Blob Area', - 'ZoneMinMaxBlobs' => 'Min/Max Blobs', - 'ZoneMinMaxFiltArea' => 'Min/Max Filtered Area', - 'ZoneMinMaxPixelThres' => 'Min/Max Pixel Threshold (0-255)', - 'ZoneMinderLog' => 'ZoneMinder Log', // Added - 2011-06-17 - 'ZoneOverloadFrames' => 'Overload Frame Ignore Count', - 'ZoneExtendAlarmFrames' => 'Extend Alarm Frame Count', + 'ZoneAlarmColour' => 'Couleur alarme (Rouge/Vert/Bleu)', + 'ZoneArea' => 'Surface de la zone', + 'ZoneExtendAlarmFrames' => 'Nb image(s) pour extension alarme', + 'ZoneFilterSize' => 'Largeur/hauteur surface filtrée (nb pixels)', + 'ZoneMinMaxAlarmArea' => 'Surface en alarme min/max (nb pixels)', + 'ZoneMinMaxBlobArea' => 'Surface des formes min/max (nb pixels)', + 'ZoneMinMaxBlobs' => 'Nombre de formes min/max', + 'ZoneMinMaxFiltArea' => 'Surface filtrée min/max (nb pixels)', + 'ZoneMinMaxPixelThres' => 'Seuil pixels min/max (0-255)', + 'ZoneMinderLog' => 'Journal de ZoneMinder', // Added - 2011-06-17 + 'ZoneOverloadFrames' => 'Nb image(s) ignorée(s) après dépass. seuil', 'Zones' => 'Zones', 'Zoom' => 'Zoom', 'ZoomIn' => 'Zoom avant', - 'ZoomOut' => 'Zoom arriËre', + 'ZoomOut' => 'Zoom arrière', ); // Complex replacements with formatting and/or placements, must be passed through sprintf $CLANG = array( - 'CurrentLogin' => 'Util. Actuel: \'%1$s\'', - 'EventCount' => '%1$s %2$s', // par ex. '37 ÈvËnts' (voir Vlang ci-dessous) - 'LastEvents' => '%1$s derniers %2$s', // par ex. '37 derniers ÈvËnts' (voir Vlang ci-dessous) - 'LatestRelease' => 'La derniËre version est v%1$s, vous avez v%2$s.', - 'MonitorCount' => '%1$s %2$s', // par exemple '4 camÈras' (voir Vlang ci-dessous) - 'MonitorFunction' => 'CamÈra %1$s Fonction', - 'RunningRecentVer' => 'Vs avez la derniËre version de ZoneMinder, v%s.', - 'VersionMismatch' => 'Version mismatch, system is version %1$s, database is %2$s.', // Added - 2011-05-25 + 'CurrentLogin' => 'Utilisateur actuel: \'%1$s\'', + 'EventCount' => '%1$s %2$s', // par ex. '37 évènts' (voir Vlang ci-dessous) + 'LastEvents' => '%1$s derniers %2$s', // par ex. '37 derniers évènts' (voir Vlang ci-dessous) + 'LatestRelease' => 'La dernière version est v%1$s, vous avez v%2$s.', + 'MonitorCount' => '%1$s %2$s', // par exemple '4 caméras' (voir Vlang ci-dessous) + 'MonitorFunction' => 'Caméra %1$s Fonction', + 'RunningRecentVer' => 'Vous avez la dernière version de ZoneMinder, v%s.', + 'VersionMismatch' => 'Discordance entre version système (%1$s) et base de données (%2$s).', // Added - 2011-05-25 ); // The next section allows you to describe a series of word ending and counts used to @@ -780,8 +807,8 @@ $CLANG = array( // Variable arrays expressing plurality, see the zmVlang description above $VLANG = array( - 'Event' => array( 0=>'ÈvÈnements', 1=>'ÈvÈnement', 2=>'ÈvÈnements' ), - 'Monitor' => array( 0=>'camÈras', 1=>'camÈra', 2=>'camÈras' ), + 'Event' => array( 0=>'événements', 1=>'événement', 2=>'événements' ), + 'Monitor' => array( 0=>'caméras', 1=>'caméra', 2=>'caméras' ), ); // You will need to choose or write a function that can correlate the plurality string arrays @@ -800,7 +827,7 @@ function zmVlang( $langVarArray, $count ) return( $value ); } } - die( 'Error, unable to correlate variable language string' ); + die( 'Erreur, impossible de corréler la chaîne de caractères' ); } // This is an version that could be used in the Russian example above @@ -874,10 +901,10 @@ $OLANG = array( "\"--verbose=2\" Set verbosity of libVLC" ), -// 'LANG_DEFAULT' => array( -// 'Prompt' => "This is a new prompt for this option", -// 'Help' => "This is some new help for this option which will be displayed in the popup window when the ? is clicked" -// ), + 'LANG_DEFAULT' => array( + 'Prompt' => "Langage par défaut pour l'interface web", + 'Help' => "ZoneMinder est exploitable dans votre langue si le fichier de traduction approprié est disponible sur votre système. Cette option permet de changer la langue anglaise par défaut par la langue de votre choix dans la liste." + ), ); ?> diff --git a/web/lang/he_il.php b/web/lang/he_il.php index 83f165cef..b7e89858c 100644 --- a/web/lang/he_il.php +++ b/web/lang/he_il.php @@ -88,6 +88,7 @@ $SLANG = array( 'AlarmMaximumFPS' => 'Alarm Maximum FPS', 'AlarmPx' => ' Px', 'AlarmRGBUnset' => ' ', + 'AlarmRefImageBlendPct'=> 'Alarm Reference Image Blend %ge', // Added - 2015-04-18 'Alert' => '', 'All' => '', 'Apply' => '', @@ -132,13 +133,13 @@ $SLANG = array( 'BadFPSReportInterval' => 'FPS report interval buffer count must be an integer of 0 or more', 'BadFormat' => 'Format must be set to an integer of zero or more', 'BadFrameSkip' => 'Frame skip count must be an integer of zero or more', - 'BadMotionFrameSkip' => 'Motion Frame skip count must be an integer of zero or more', 'BadHeight' => 'Height must be set to a valid value', 'BadHost' => 'Host must be set to a valid ip address or hostname, do not include http://', 'BadImageBufferCount' => 'Image buffer size must be an integer of 10 or more', 'BadLabelX' => 'Label X co-ordinate must be set to an integer of zero or more', 'BadLabelY' => 'Label Y co-ordinate must be set to an integer of zero or more', 'BadMaxFPS' => 'Maximum FPS must be a positive integer or floating point value', + 'BadMotionFrameSkip' => 'Motion Frame skip count must be an integer of zero or more', 'BadNameChars' => 'Names may only contain alphanumeric characters plus hyphen and underscore', 'BadPalette' => 'Palette must be set to a valid value', // Added - 2009-03-31 'BadPath' => 'Path must be set to a valid value', @@ -158,7 +159,9 @@ $SLANG = array( 'BlobSizes' => 'Blob Sizes', 'Blobs' => 'Blobs', 'Brightness' => '', + 'Buffer' => 'Buffer', // Added - 2015-04-18 'Buffers' => 'Buffers', + 'CSSDescription' => 'Change the default css for this computer', // Added - 2015-04-18 'CanAutoFocus' => ' ', 'CanAutoGain' => 'Can Auto Gain', 'CanAutoIris' => 'Can Auto Iris', @@ -202,6 +205,7 @@ $SLANG = array( 'CaptureHeight' => 'Capture Height', 'CaptureMethod' => 'Capture Method', // Added - 2009-02-08 'CapturePalette' => 'Capture Palette', + 'CaptureResolution' => 'Capture Resolution', // Added - 2015-04-18 'CaptureWidth' => 'Capture Width', 'Cause' => '', 'CheckMethod' => 'Alarm Check Method', @@ -232,6 +236,7 @@ $SLANG = array( 'ControlDevice' => ' ', 'ControlType' => ' ', 'Controllable' => 'Controllable', + 'Current' => 'Current', // Added - 2015-04-18 'Cycle' => '', 'CycleWatch' => ' ', 'DateTime' => 'Date/Time', // Added - 2011-06-16 @@ -240,12 +245,15 @@ $SLANG = array( 'DefaultRate' => 'Default Rate', 'DefaultScale' => 'Default Scale', 'DefaultView' => 'Default View', + 'Deinterlacing' => 'Deinterlacing', // Added - 2015-04-18 + 'Delay' => 'Delay', // Added - 2015-04-18 'Delete' => '', 'DeleteAndNext' => ' & ', 'DeleteAndPrev' => ' & ', 'DeleteSavedFilter' => ' ', 'Description' => '', 'DetectedCameras' => 'Detected Cameras', // Added - 2009-03-31 + 'DetectedProfiles' => 'Detected Profiles', // Added - 2015-04-18 'Device' => 'Device', // Added - 2009-02-08 'DeviceChannel' => ' ', 'DeviceFormat' => ' ', @@ -257,6 +265,7 @@ $SLANG = array( 'Disk' => '', 'Display' => 'Display', // Added - 2011-01-30 'Displaying' => 'Displaying', // Added - 2011-06-16 + 'DoNativeMotionDetection'=> 'Do Native Motion Detection', 'Donate' => ' ', 'DonateAlready' => ', ', 'DonateEnticement' => 'You\'ve been running ZoneMinder for a while now and hopefully are finding it a useful addition to your home or workplace security. Although ZoneMinder is, and will remain, free and open source, it costs money to develop and support. If you would like to help support future development and new features then please consider donating. Donating is, of course, optional but very much appreciated and you can donate as much or as little as you like.

If you would like to donate please select the option below or go to http://www.zoneminder.com/donate.html in your browser.

Thank you for using ZoneMinder and don\'t forget to visit the forums on ZoneMinder.com for support or suggestions about how to make your ZoneMinder experience even better.', @@ -266,7 +275,6 @@ $SLANG = array( 'DonateRemindNever' => ', , ', 'DonateRemindWeek' => ' , ', 'DonateYes' => ', ', - 'DoNativeMotionDetection'=> 'Do Native Motion Detection', 'Download' => '', 'DuplicateMonitorName' => 'Duplicate Monitor Name', // Added - 2009-03-31 'Duration' => ' ', @@ -309,10 +317,12 @@ $SLANG = array( 'Feed' => 'Feed', 'Ffmpeg' => 'Ffmpeg', // Added - 2009-02-08 'File' => '', + 'Filter' => 'Filter', // Added - 2015-04-18 'FilterArchiveEvents' => ' ', 'FilterDeleteEvents' => ' ', 'FilterEmailEvents' => ' ', 'FilterExecuteEvents' => 'Execute command on all matches', + 'FilterLog' => 'Filter log', // Added - 2015-04-18 'FilterMessageEvents' => 'Message details of all matches', 'FilterPx' => 'Filter Px', 'FilterUnset' => ' ', @@ -322,12 +332,12 @@ $SLANG = array( 'First' => '', 'FlippedHori' => 'Flipped Horizontally', 'FlippedVert' => 'Flipped Vertically', - 'FnNone' => 'None', // Added 2013.08.16. - 'FnMonitor' => 'Monitor', // Added 2013.08.16. - 'FnModect' => 'Modect', // Added 2013.08.16. - 'FnRecord' => 'Record', // Added 2013.08.16. 'FnMocord' => 'Mocord', // Added 2013.08.16. + 'FnModect' => 'Modect', // Added 2013.08.16. + 'FnMonitor' => 'Monitor', // Added 2013.08.16. 'FnNodect' => 'Nodect', // Added 2013.08.16. + 'FnNone' => 'None', // Added 2013.08.16. + 'FnRecord' => 'Record', // Added 2013.08.16. 'Focus' => '', 'ForceAlarm' => ' ', 'Format' => '', @@ -335,7 +345,6 @@ $SLANG = array( 'FrameId' => 'Frame Id', 'FrameRate' => 'Frame Rate', 'FrameSkip' => ' ', - 'MotionFrameSkip' => 'Motion Frame Skip', 'Frames' => '', 'Func' => '', 'Function' => '', @@ -462,6 +471,7 @@ $SLANG = array( 'MinZoomSpeed' => 'Min Zoom Speed', 'MinZoomStep' => 'Min Zoom Step', 'Misc' => 'Misc', + 'Mode' => 'Mode', // Added - 2015-04-18 'Monitor' => '', 'MonitorIds' => 'Monitor Ids', 'MonitorPreset' => 'Monitor Preset', @@ -472,12 +482,13 @@ $SLANG = array( 'Montage' => 'Montage', 'Month' => '', 'More' => 'More', // Added - 2011-06-16 + 'MotionFrameSkip' => 'Motion Frame Skip', 'Move' => '', - 'MtgDefault' => 'Default', // Added 2013.08.15. 'Mtg2widgrd' => '2-wide grid', // Added 2013.08.15. 'Mtg3widgrd' => '3-wide grid', // Added 2013.08.15. - 'Mtg4widgrd' => '4-wide grid', // Added 2013.08.15. 'Mtg3widgrx' => '3-wide grid, scaled, enlarge on alarm', // Added 2013.08.15. + 'Mtg4widgrd' => '4-wide grid', // Added 2013.08.15. + 'MtgDefault' => 'Default', // Added 2013.08.15. 'MustBeGe' => 'must be greater than or equal to', 'MustBeLe' => 'must be less than or equal to', 'MustConfirmPassword' => 'You must confirm the password', @@ -506,6 +517,9 @@ $SLANG = array( 'NumPresets' => 'Num Presets', 'Off' => '', 'On' => '', + 'OnvifCredentialsIntro'=> 'Please supply user name and password for the selected camera.
If no user has been created for the camera then the user given here will be created with the given password.

', // Added - 2015-04-18 + 'OnvifProbe' => 'ONVIF', // Added - 2015-04-18 + 'OnvifProbeIntro' => 'The list below shows detected ONVIF cameras and whether they are already being used or available for selection.

Select the desired entry from the list below.

Please note that not all cameras may be detected and that choosing a camera here may overwrite any values you already have configured for the current monitor.

', // Added - 2015-04-18 'OpEq' => ' ', 'OpGt' => ' ', 'OpGtEq' => 'greater than or equal to', @@ -552,6 +566,9 @@ $SLANG = array( 'Presets' => 'Presets', 'Prev' => '', 'Probe' => 'Probe', // Added - 2009-03-31 + 'ProfileProbe' => 'Stream Probe', // Added - 2015-04-18 + 'ProfileProbeIntro' => 'The list below shows the existing stream profiles of the selected camera .

Select the desired entry from the list below.

Please note that ZoneMinder cannot configure additional profiles and that choosing a camera here may overwrite any values you already have configured for the current monitor.

', // Added - 2015-04-18 + 'Progress' => 'Progress', // Added - 2015-04-18 'Protocol' => 'Protocol', 'Rate' => '', 'Real' => '', @@ -639,6 +656,7 @@ $SLANG = array( 'Submit' => 'Submit', 'System' => '', 'SystemLog' => 'System Log', // Added - 2011-06-16 + 'TargetColorspace' => 'Target colorspace', // Added - 2015-04-18 'Tele' => '', 'Thumbnail' => 'Thumbnail', 'Tilt' => 'Tilt', @@ -673,13 +691,16 @@ $SLANG = array( 'UpdateNotNecessary' => ' .', 'Updated' => 'Updated', // Added - 2011-06-16 'Upload' => 'Upload', // Added - 2011-08-23 - 'UsedPlugins' => 'Used Plugins', 'UseFilter' => ' ', 'UseFilterExprsPost' => ' filter expressions', // This is used at the end of the phrase 'use N filter expressions' 'UseFilterExprsPre' => ' ', // This is used at the beginning of the phrase 'use N filter expressions' + 'UsedPlugins' => 'Used Plugins', 'User' => '', 'Username' => ' ', 'Users' => '', + 'V4L' => 'V4L', // Added - 2015-04-18 + 'V4LCapturesPerFrame' => 'Captures Per Frame', // Added - 2015-04-18 + 'V4LMultiBuffer' => 'Multi Buffering', // Added - 2015-04-18 'Value' => '', 'Version' => '', 'VersionIgnore' => ' ', @@ -719,6 +740,7 @@ $SLANG = array( 'Zone' => '', 'ZoneAlarmColour' => 'Alarm Colour (Red/Green/Blue)', 'ZoneArea' => 'Zone Area', + 'ZoneExtendAlarmFrames' => 'Extend Alarm Frame Count', 'ZoneFilterSize' => 'Filter Width/Height (pixels)', 'ZoneMinMaxAlarmArea' => 'Min/Max Alarmed Area', 'ZoneMinMaxBlobArea' => 'Min/Max Blob Area', @@ -727,7 +749,6 @@ $SLANG = array( 'ZoneMinMaxPixelThres' => 'Min/Max Pixel Threshold (0-255)', 'ZoneMinderLog' => 'ZoneMinder Log', // Added - 2011-06-17 'ZoneOverloadFrames' => 'Overload Frame Ignore Count', - 'ZoneExtendAlarmFrames' => 'Extend Alarm Frame Count', 'Zones' => '', 'Zoom' => '', 'ZoomIn' => ' ', diff --git a/web/lang/hu_hu.php b/web/lang/hu_hu.php index 130899a27..6c97fa150 100644 --- a/web/lang/hu_hu.php +++ b/web/lang/hu_hu.php @@ -115,6 +115,7 @@ define( "STRF_FMT_DATETIME_SHORTER", "%m.%d. %H:%M:%S" ); // Strftime shor // Simple String Replacements $SLANG = array( '24BitColour' => '24 bites szín', + '32BitColour' => '32 bit colour', // Added - 2015-04-18 '8BitGrey' => '8 bit szürkeárnyalat', 'Action' => 'Művelet', 'Actual' => 'Valós', @@ -130,6 +131,7 @@ $SLANG = array( 'AlarmMaximumFPS' => 'Maximális FPS riasztott állapotban', 'AlarmPx' => 'Riasztó képpont', 'AlarmRGBUnset' => 'Be kell állítani egy RGB színt a riasztáshoz', + 'AlarmRefImageBlendPct'=> 'Alarm Reference Image Blend %ge', // Added - 2015-04-18 'Alert' => 'Figyelem', 'All' => 'Mind', 'Apply' => 'Alkalmaz', @@ -169,17 +171,18 @@ $SLANG = array( 'BadAlarmFrameCount' => 'Riasztáshoz szükséges képkockák száma legyen legalább 1', 'BadAlarmMaxFPS' => 'Maximális FPS riasztott állapotban legyen megadva', 'BadChannel' => 'A csatorna száma legyen legalább 0', + 'BadColours' => 'Target colour must be set to a valid value', // Added - 2015-04-18 'BadDevice' => 'Az eszköz elérése valós legyen', 'BadFPSReportInterval' => 'Az FPS naplózásának gyakorisága legyen legalább 0', 'BadFormat' => 'A típus 0 vagy nagyobb egész szám legyen', 'BadFrameSkip' => 'Az eldobott képkockák száma legyen legalább 0', - 'BadMotionFrameSkip' => 'Motion Frame skip count must be an integer of zero or more', 'BadHeight' => 'A képmagasság legyen érvényes érték képpontban megadva', 'BadHost' => 'A hoszt legyen valós IP cím vagy hosztnév http:// nélkül', 'BadImageBufferCount' => 'A képkockák száma a pufferben legyen legalább 10', 'BadLabelX' => 'A cimke X koordinátája legyen legalább 0', 'BadLabelY' => 'A cimke Y koordinátája legyen legalább 0', 'BadMaxFPS' => 'Maximális FPS nyugalmi állapotban legyen megadva', + 'BadMotionFrameSkip' => 'Motion Frame skip count must be an integer of zero or more', 'BadNameChars' => 'A név csak betűket, számokat, plusz-, kötő-, és aláhúzásjelet tartalmazhat', 'BadPalette' => 'A szín-palettának válasszin egy helyes értéket', 'BadPath' => 'A kép elérési útvonala helytelen', @@ -199,7 +202,9 @@ $SLANG = array( 'BlobSizes' => 'Blob méretek', 'Blobs' => 'Blob-ok', 'Brightness' => 'Fényerő', + 'Buffer' => 'Buffer', // Added - 2015-04-18 'Buffers' => 'Pufferek', + 'CSSDescription' => 'Change the default css for this computer', // Added - 2015-04-18 'CanAutoFocus' => 'Van autofókusza', 'CanAutoGain' => 'Van AGC-je', 'CanAutoIris' => 'Van autoírisze', @@ -243,6 +248,7 @@ $SLANG = array( 'CaptureHeight' => 'Képmagasság', 'CaptureMethod' => 'Digitalizálás módszere', 'CapturePalette' => 'Digitalizálás szín-palettája', + 'CaptureResolution' => 'Capture Resolution', // Added - 2015-04-18 'CaptureWidth' => 'Képszélesség', 'Cause' => 'Okozó', 'CheckMethod' => 'A riasztás figyelésének módja', @@ -273,6 +279,7 @@ $SLANG = array( 'ControlDevice' => 'Vezérlő eszköz', 'ControlType' => 'Vezérlés típusa', 'Controllable' => 'Vezérelhető', + 'Current' => 'Current', // Added - 2015-04-18 'Cycle' => 'Ciklikus nézet', 'CycleWatch' => 'Ciklikus nézet', 'DateTime' => 'Dátum/Idő', @@ -281,12 +288,15 @@ $SLANG = array( 'DefaultRate' => 'Alapértelmezett sebesség', 'DefaultScale' => 'Alapértelmezett méret', 'DefaultView' => 'Alapértelmezett nézet', + 'Deinterlacing' => 'Deinterlacing', // Added - 2015-04-18 + 'Delay' => 'Delay', // Added - 2015-04-18 'Delete' => 'Törlés', 'DeleteAndNext' => 'Törlés &
következő', 'DeleteAndPrev' => 'Törlés &
előző', 'DeleteSavedFilter' => 'Mentett szűrő törlése', 'Description' => 'Leírás', 'DetectedCameras' => 'Érzékelt kamerák', + 'DetectedProfiles' => 'Detected Profiles', // Added - 2015-04-18 'Device' => 'Eszköz', 'DeviceChannel' => 'Eszköz csatornája', 'DeviceFormat' => 'Eszköz formátuma', @@ -298,6 +308,7 @@ $SLANG = array( 'Disk' => 'Tárhely', 'Display' => 'Megjelenés', 'Displaying' => 'Megjelenítés', + 'DoNativeMotionDetection'=> 'Do Native Motion Detection', // Added - 2015-04-18 'Donate' => 'Kérem támogasson', 'DonateAlready' => 'Nem, én már támogattam', 'DonateEnticement' => 'Ön már jó ideje használja a ZoneMindert, és reméljük hasznos eszköznek tartja háza vagy munkahelye biztonságában. Bár a ZoneMinder egy szabad, nyílt forráskódú termék és az is marad, a fejlesztése pénzbe kerül. Ha van lehetősége támogatni a jövőbeni fejlesztéseket és az új funkciókat kérem, tegye meg. A támogatás teljesen önkéntes, de nagyon megbecsült és mértéke is tetszőleges.

Ha támogatni szertne, kérem, válasszon az alábbi lehetőségekből vagy látogassa meg a http://www.zoneminder.com/donate.html oldalt.

Köszönjük, hogy használja a ZoneMinder-t és ne felejtse el meglátogatni a fórumokat a ZoneMinder.com oldalon támogatásért és ötletekért, hogy a jövőben is még jobban ki tudja használni a ZoneMinder lehetőségeit.', @@ -349,10 +360,12 @@ $SLANG = array( 'Feed' => 'Folyam', 'Ffmpeg' => 'ffmpeg', 'File' => 'Fájl', + 'Filter' => 'Filter', // Added - 2015-04-18 'FilterArchiveEvents' => 'Minden találat archiválása', 'FilterDeleteEvents' => 'Minden találat törlése', 'FilterEmailEvents' => 'Minden találat adatainak küldése E-mailben', 'FilterExecuteEvents' => 'Parancs futtatása minden találaton', + 'FilterLog' => 'Filter log', // Added - 2015-04-18 'FilterMessageEvents' => 'Minden találat adatainak üzenése', 'FilterPx' => 'Szűrt képkockák', 'FilterUnset' => 'Meg kell adnod a szűrő szélességét és magasságát', @@ -362,12 +375,12 @@ $SLANG = array( 'First' => 'Első', 'FlippedHori' => 'Vízszintes tükrözés', 'FlippedVert' => 'Függőleges tükrözés', - 'FnNone' => 'Letiltva', - 'FnMonitor' => 'Csak monitorozás', - 'FnModect' => 'Mozgásérzékelő', - 'FnRecord' => 'Folyamatos felvétel', 'FnMocord' => 'Folyamatos mozgással', + 'FnModect' => 'Mozgásérzékelő', + 'FnMonitor' => 'Csak monitorozás', 'FnNodect' => 'Külső érzékelő', + 'FnNone' => 'Letiltva', + 'FnRecord' => 'Folyamatos felvétel', 'Focus' => 'Fókusz', 'ForceAlarm' => 'Kézi riasztás', 'Format' => 'Formátum', @@ -375,7 +388,6 @@ $SLANG = array( 'FrameId' => 'Képkocka azonosító', 'FrameRate' => 'FPS', 'FrameSkip' => 'Képkocka kihagyás', - 'MotionFrameSkip' => 'Motion Frame Skip', 'Frames' => 'Képkocka', 'Func' => 'Funk.', 'Function' => 'Funkció', @@ -502,6 +514,7 @@ $SLANG = array( 'MinZoomSpeed' => 'Min. zoom sebesség', 'MinZoomStep' => 'Min. zoom lépték', 'Misc' => 'Egyéb', + 'Mode' => 'Mode', // Added - 2015-04-18 'Monitor' => 'Kamera', 'MonitorIds' => 'Kamera azonosítók', 'MonitorPreset' => 'Előre beállított kameraprofilok', @@ -512,12 +525,13 @@ $SLANG = array( 'Montage' => 'Többkamerás nézet', 'Month' => 'Hónapban', 'More' => 'Több', + 'MotionFrameSkip' => 'Motion Frame Skip', 'Move' => 'Mozgás', - 'MtgDefault' => 'Böngésző alapértelmezése szerint', 'Mtg2widgrd' => '2 oszlopban', 'Mtg3widgrd' => '3 oszlopban', - 'Mtg4widgrd' => '4 oszlopban', 'Mtg3widgrx' => '3 oszlopban skálázva, riasztás esetén kinagyítva', + 'Mtg4widgrd' => '4 oszlopban', + 'MtgDefault' => 'Böngésző alapértelmezése szerint', 'MustBeGe' => 'nagyobbnak vagy egyenlőnek kell lennie', 'MustBeLe' => 'kisebbnek vagy egyenlőnek kell lennie', 'MustConfirmPassword' => 'Meg kell erősítenie a jelszót', @@ -546,6 +560,9 @@ $SLANG = array( 'NumPresets' => 'Profilok száma', 'Off' => 'Ki', 'On' => 'Be', + 'OnvifCredentialsIntro'=> 'Please supply user name and password for the selected camera.
If no user has been created for the camera then the user given here will be created with the given password.

', // Added - 2015-04-18 + 'OnvifProbe' => 'ONVIF', // Added - 2015-04-18 + 'OnvifProbeIntro' => 'The list below shows detected ONVIF cameras and whether they are already being used or available for selection.

Select the desired entry from the list below.

Please note that not all cameras may be detected and that choosing a camera here may overwrite any values you already have configured for the current monitor.

', // Added - 2015-04-18 'OpEq' => 'egyenlő', 'OpGt' => 'nagyobb mint', 'OpGtEq' => 'nagyobb van egyenlő', @@ -583,6 +600,7 @@ $SLANG = array( 'Play' => 'Lejátszás', 'PlayAll' => 'Mind lejátszása', 'PleaseWait' => 'Kérlek várj...', + 'Plugins' => 'Plugins', // Added - 2015-04-18 'Point' => 'Pont', 'PostEventImageBuffer' => 'Esemény utáni képkockák a pufferben', 'PreEventImageBuffer' => 'Esemény elötti képkockák a pufferben', @@ -591,6 +609,9 @@ $SLANG = array( 'Presets' => 'Előre beállított profilok', 'Prev' => 'Előző', 'Probe' => 'Érzékelés', + 'ProfileProbe' => 'Stream Probe', // Added - 2015-04-18 + 'ProfileProbeIntro' => 'The list below shows the existing stream profiles of the selected camera .

Select the desired entry from the list below.

Please note that ZoneMinder cannot configure additional profiles and that choosing a camera here may overwrite any values you already have configured for the current monitor.

', // Added - 2015-04-18 + 'Progress' => 'Progress', // Added - 2015-04-18 'Protocol' => 'Protocol', 'Rate' => 'FPS', 'Real' => 'Valós', @@ -678,6 +699,7 @@ $SLANG = array( 'Submit' => 'Küldés', 'System' => 'Rendszer', 'SystemLog' => 'Rendszernapló', + 'TargetColorspace' => 'Target colorspace', // Added - 2015-04-18 'Tele' => 'Táv', 'Thumbnail' => 'Előnézet', 'Tilt' => 'Fel-le mozgás', @@ -715,9 +737,13 @@ $SLANG = array( 'UseFilter' => 'Szűrőt használ', 'UseFilterExprsPost' => ' szürés  használata', // This is used at the end of the phrase 'use N filter expressions' 'UseFilterExprsPre' => ' ', // This is used at the beginning of the phrase 'use N filter expressions' + 'UsedPlugins' => 'Used Plugins', // Added - 2015-04-18 'User' => 'Felhasználó', 'Username' => 'Felhasználónév', 'Users' => 'Felhasználók', + 'V4L' => 'V4L', // Added - 2015-04-18 + 'V4LCapturesPerFrame' => 'Captures Per Frame', // Added - 2015-04-18 + 'V4LMultiBuffer' => 'Multi Buffering', // Added - 2015-04-18 'Value' => 'Érték', 'Version' => 'Verzió', 'VersionIgnore' => 'Ezen verzió figyelmen kívül hagyása', @@ -757,6 +783,7 @@ $SLANG = array( 'Zone' => 'Zóna:', 'ZoneAlarmColour' => 'Riasztott terület
színezése (R/G/B)', 'ZoneArea' => 'Zóna lefedettsége', + 'ZoneExtendAlarmFrames' => 'Extend Alarm Frame Count', 'ZoneFilterSize' => 'Szélesség és magasság
szűrés képpontban', 'ZoneMinMaxAlarmArea' => 'Min/Max riasztó terület', 'ZoneMinMaxBlobArea' => 'Min/Max Blob terület', @@ -765,7 +792,6 @@ $SLANG = array( 'ZoneMinMaxPixelThres' => 'Min/Max képpont változási
küszöb (0-255)', 'ZoneMinderLog' => 'ZoneMinder Napló', 'ZoneOverloadFrames' => 'Túlterhelés esetén
ennyi képkocka hagyható ki', - 'ZoneExtendAlarmFrames' => 'Extend Alarm Frame Count', 'Zones' => 'Zónák', 'Zoom' => 'Zoom', 'ZoomIn' => 'Zoom be', diff --git a/web/lang/it_it.php b/web/lang/it_it.php index 8842cfacf..b367da15a 100644 --- a/web/lang/it_it.php +++ b/web/lang/it_it.php @@ -93,6 +93,7 @@ $SLANG = array( 'AlarmMaximumFPS' => 'FPS massimi durante l\'allarme', 'AlarmPx' => 'Pixel Allarme', 'AlarmRGBUnset' => 'Devi settare un colore RGB di allarme', + 'AlarmRefImageBlendPct'=> 'Alarm Reference Image Blend %ge', // Added - 2015-04-18 'Alert' => 'Attenzione', 'All' => 'Tutto', 'Apply' => 'Applica', @@ -137,13 +138,13 @@ $SLANG = array( 'BadFPSReportInterval' => 'L\'intervallo di FPS per i report deve essere un numero intero superiore a 0', 'BadFormat' => 'Il formato deve essere impostato con un numero intero come 0 o maggiore', 'BadFrameSkip' => 'Il numero di Frame da scartare deve essere un intero uguale a 0 o superiore', - 'BadMotionFrameSkip' => 'Motion Frame skip count must be an integer of zero or more', 'BadHeight' => 'L\'altezza deve essere impostata con un valore valido', 'BadHost' => 'L\'host deve essere impostato con un indirizzo ip valido o con un hostname, non includendo http://', 'BadImageBufferCount' => 'La dimensione del buffer dell\'immagine deve essere impostata con un numero intero pari a 10 o maggiore', 'BadLabelX' => 'L\'etichetta della coordinata X deve essere un numero intero pari a 0 o maggiore', 'BadLabelY' => 'L\'etichetta della coordinata Y deve essere un numero intero pari a 0 o maggiore', 'BadMaxFPS' => 'I frame per secondo (FPS) massimi devono essere un numero intero positivo o un valore in virgola mobile', + 'BadMotionFrameSkip' => 'Motion Frame skip count must be an integer of zero or more', 'BadNameChars' => 'I nomi possono contenere solo caratteri alfanumerici più i caratteri - e _', 'BadPalette' => 'La palette dei colori deve essere impostata ad un valore valido', // Added - 2009-03-31 'BadPath' => 'Il percorso deve essere impostato con un valore valido', @@ -163,7 +164,9 @@ $SLANG = array( 'BlobSizes' => 'Dimensioni Blob', 'Blobs' => 'Blobs', 'Brightness' => 'Luminosità', + 'Buffer' => 'Buffer', // Added - 2015-04-18 'Buffers' => 'Buffers', + 'CSSDescription' => 'Change the default css for this computer', // Added - 2015-04-18 'CanAutoFocus' => 'Puo\' Auto Focus', 'CanAutoGain' => 'Puo\' Auto Gains', 'CanAutoIris' => 'Puo\' Auto Iris', @@ -207,6 +210,7 @@ $SLANG = array( 'CaptureHeight' => 'Altezza img catturata', 'CaptureMethod' => 'Metodo di cattura', // Added - 2009-02-08 'CapturePalette' => 'Paletta img Catturata', + 'CaptureResolution' => 'Capture Resolution', // Added - 2015-04-18 'CaptureWidth' => 'Larghezza img Catturata', 'Cause' => 'Causa', 'CheckMethod' => 'Metodo di Controllo Allarme', @@ -237,6 +241,7 @@ $SLANG = array( 'ControlDevice' => 'Dispositivo di controllo', 'ControlType' => 'Tipo Controllo', 'Controllable' => 'Controllabile', + 'Current' => 'Current', // Added - 2015-04-18 'Cycle' => 'Cicla', 'CycleWatch' => 'Vista Ciclica', 'DateTime' => 'Date/Time', // Added - 2011-06-16 @@ -245,12 +250,15 @@ $SLANG = array( 'DefaultRate' => 'Default Rate', 'DefaultScale' => 'Scala di default', 'DefaultView' => 'Visualizzazione di default', + 'Deinterlacing' => 'Deinterlacing', // Added - 2015-04-18 + 'Delay' => 'Delay', // Added - 2015-04-18 'Delete' => 'Elimina', 'DeleteAndNext' => 'Elimina & Prossimo', 'DeleteAndPrev' => 'Elimina & Precedente', 'DeleteSavedFilter' => 'Elimina il filtro salvato', 'Description' => 'Descrizione', 'DetectedCameras' => 'Telecamere Rilevate', // Added - 2009-03-31 + 'DetectedProfiles' => 'Detected Profiles', // Added - 2015-04-18 'Device' => 'Periferica', // Added - 2009-02-08 'DeviceChannel' => 'Canale Periferica', 'DeviceFormat' => 'Formato', @@ -262,6 +270,7 @@ $SLANG = array( 'Disk' => 'Utilizzo Disco', 'Display' => 'Display', // Added - 2011-01-30 'Displaying' => 'Displaying', // Added - 2011-06-16 + 'DoNativeMotionDetection'=> 'Do Native Motion Detection', 'Donate' => 'Donate,per favore', 'DonateAlready' => 'No, ho gia donato... ', 'DonateEnticement' => 'Stai usando ZoneMinder da un po\' di tempo e spero che tu lo stia trovando utile per la sicurezza di casa tua o del tuo posto di lavoro..Anche se ZoneMinder e\' distribuito liberamente come software libero,costa soldi sia svilupparlo che supportarlo. Se preferisci che questo software continui ad avere supporto e sviluppo in futuro allora considera l\idea di fare una piccola donazione. Donare e\' ovviamente opzionale, ma apprezzato e puoi donare quanto vuoi,quel poco o tanto che tu desideri.

Se hai voglia per cortesia seleziona l\'opzione sotto o punta il tuo browser a http://www.zoneminder.com/donate.html .

Grazie per usare ZoneMinder e non dimenticare di visitare il forum in ZoneMinder.com se cerchi supporto o hai suggerimenti riguardo a come rendere migliore Zoneminder.', @@ -271,7 +280,6 @@ $SLANG = array( 'DonateRemindNever' => 'No, io non voglio donare, non lo faro\' mai', 'DonateRemindWeek' => 'Non ancora, ricordamelo ancora tra 1 settimana', 'DonateYes' => 'Si,mi piacerebbe donare qualcosa ora', - 'DoNativeMotionDetection'=> 'Do Native Motion Detection', 'Download' => 'Download', 'DuplicateMonitorName' => 'Il nome del monitor e\' gia\' presente', // Added - 2009-03-31 'Duration' => 'Durata', @@ -314,10 +322,12 @@ $SLANG = array( 'Feed' => 'Feed', 'Ffmpeg' => 'Ffmpeg', // Added - 2009-02-08 'File' => 'File', + 'Filter' => 'Filter', // Added - 2015-04-18 'FilterArchiveEvents' => 'Archivia gli eventi', 'FilterDeleteEvents' => 'Elimina gli eventi', 'FilterEmailEvents' => 'Invia dettagli via email', 'FilterExecuteEvents' => 'Esegui un comando', + 'FilterLog' => 'Filter log', // Added - 2015-04-18 'FilterMessageEvents' => 'Invia dettagli tramite messaggio', 'FilterPx' => 'Px Filtro', 'FilterUnset' => 'Devi specificare altezza e larghezza per il filtro', @@ -327,12 +337,12 @@ $SLANG = array( 'First' => 'Primo', 'FlippedHori' => 'ribaltato orizzontale', 'FlippedVert' => 'ribaltato verticale', - 'FnNone' => 'None', // Added 2013.08.16. - 'FnMonitor' => 'Monitor', // Added 2013.08.16. - 'FnModect' => 'Modect', // Added 2013.08.16. - 'FnRecord' => 'Record', // Added 2013.08.16. 'FnMocord' => 'Mocord', // Added 2013.08.16. + 'FnModect' => 'Modect', // Added 2013.08.16. + 'FnMonitor' => 'Monitor', // Added 2013.08.16. 'FnNodect' => 'Nodect', // Added 2013.08.16. + 'FnNone' => 'None', // Added 2013.08.16. + 'FnRecord' => 'Record', // Added 2013.08.16. 'Focus' => 'Focus', 'ForceAlarm' => 'Forza Allarme', 'Format' => 'Formato', @@ -340,7 +350,6 @@ $SLANG = array( 'FrameId' => 'Id Immagine', 'FrameRate' => 'Immagini al secondo', 'FrameSkip' => 'Immagini saltate', - 'MotionFrameSkip' => 'Motion Frame Skip', 'Frames' => 'Immagini', 'Func' => 'Funz', 'Function' => 'Funzione', @@ -467,6 +476,7 @@ $SLANG = array( 'MinZoomSpeed' => 'Velocita\' minima dello zoom', 'MinZoomStep' => 'Step minimo dello zoom', 'Misc' => 'Altro', + 'Mode' => 'Mode', // Added - 2015-04-18 'Monitor' => 'Monitor', 'MonitorIds' => 'Monitor Ids', 'MonitorPreset' => 'Monitor Presenti', @@ -477,12 +487,13 @@ $SLANG = array( 'Montage' => 'Montaggio', 'Month' => 'Mese', 'More' => 'More', // Added - 2011-06-16 + 'MotionFrameSkip' => 'Motion Frame Skip', 'Move' => 'Sposta', - 'MtgDefault' => 'Default', // Added 2013.08.15. 'Mtg2widgrd' => '2-wide grid', // Added 2013.08.15. 'Mtg3widgrd' => '3-wide grid', // Added 2013.08.15. - 'Mtg4widgrd' => '4-wide grid', // Added 2013.08.15. 'Mtg3widgrx' => '3-wide grid, scaled, enlarge on alarm', // Added 2013.08.15. + 'Mtg4widgrd' => '4-wide grid', // Added 2013.08.15. + 'MtgDefault' => 'Default', // Added 2013.08.15. 'MustBeGe' => 'deve essere superiore a', 'MustBeLe' => 'deve essere inferiore o pari a', 'MustConfirmPassword' => 'Devi confermare la password', @@ -511,6 +522,9 @@ $SLANG = array( 'NumPresets' => 'Num Presets', 'Off' => 'Off', 'On' => 'On', + 'OnvifCredentialsIntro'=> 'Please supply user name and password for the selected camera.
If no user has been created for the camera then the user given here will be created with the given password.

', // Added - 2015-04-18 + 'OnvifProbe' => 'ONVIF', // Added - 2015-04-18 + 'OnvifProbeIntro' => 'The list below shows detected ONVIF cameras and whether they are already being used or available for selection.

Select the desired entry from the list below.

Please note that not all cameras may be detected and that choosing a camera here may overwrite any values you already have configured for the current monitor.

', // Added - 2015-04-18 'OpEq' => 'uguale a', 'OpGt' => 'maggiore di', 'OpGtEq' => 'maggiore o uguale a', @@ -557,6 +571,9 @@ $SLANG = array( 'Presets' => 'Presets', 'Prev' => 'Prec', 'Probe' => 'Prova la telecamera', // Added - 2009-03-31 + 'ProfileProbe' => 'Stream Probe', // Added - 2015-04-18 + 'ProfileProbeIntro' => 'The list below shows the existing stream profiles of the selected camera .

Select the desired entry from the list below.

Please note that ZoneMinder cannot configure additional profiles and that choosing a camera here may overwrite any values you already have configured for the current monitor.

', // Added - 2015-04-18 + 'Progress' => 'Progress', // Added - 2015-04-18 'Protocol' => 'Protocol', 'Rate' => 'Velocita\'', 'Real' => 'Reale', @@ -644,6 +661,7 @@ $SLANG = array( 'Submit' => 'Accetta', 'System' => 'Sistema', 'SystemLog' => 'System Log', // Added - 2011-06-16 + 'TargetColorspace' => 'Target colorspace', // Added - 2015-04-18 'Tele' => 'Tele', 'Thumbnail' => 'Anteprima', 'Tilt' => 'Tilt', @@ -678,13 +696,16 @@ $SLANG = array( 'UpdateNotNecessary' => 'Nessun aggiornamento necessario.', 'Updated' => 'Updated', // Added - 2011-06-16 'Upload' => 'Upload', // Added - 2011-08-23 - 'UsedPlugins' => 'Used Plugins', 'UseFilter' => 'Usa Filtro', 'UseFilterExprsPost' => ' espressioni filtri', // This is used at the end of the phrase 'use N filter expressions' 'UseFilterExprsPre' => 'Usa ', // This is used at the beginning of the phrase 'use N filter expressions' + 'UsedPlugins' => 'Used Plugins', 'User' => 'Utente', 'Username' => 'Nome Utente', 'Users' => 'Utenti', + 'V4L' => 'V4L', // Added - 2015-04-18 + 'V4LCapturesPerFrame' => 'Captures Per Frame', // Added - 2015-04-18 + 'V4LMultiBuffer' => 'Multi Buffering', // Added - 2015-04-18 'Value' => 'Valore', 'Version' => 'Versione', 'VersionIgnore' => 'Ignora questa versione', @@ -724,6 +745,7 @@ $SLANG = array( 'Zone' => 'Zona', 'ZoneAlarmColour' => 'Colore Allarme (RGB)', 'ZoneArea' => 'Zone Area', + 'ZoneExtendAlarmFrames' => 'Extend Alarm Frame Count', 'ZoneFilterSize' => 'Larghezza/Altezza Filtro (pixels)', 'ZoneMinMaxAlarmArea' => 'Min/Max Area Allarmata', 'ZoneMinMaxBlobArea' => 'Min/Max Area di Blob', @@ -732,7 +754,6 @@ $SLANG = array( 'ZoneMinMaxPixelThres' => 'Min/Max Soglia Pixel (0-255)', 'ZoneMinderLog' => 'ZoneMinder Log', // Added - 2011-06-17 'ZoneOverloadFrames' => 'Overload Frame Ignore Count', - 'ZoneExtendAlarmFrames' => 'Extend Alarm Frame Count', 'Zones' => 'Zone', 'Zoom' => 'Zoom', 'ZoomIn' => 'Ingrandisci', diff --git a/web/lang/ja_jp.php b/web/lang/ja_jp.php index 89f19bb1d..9f0134f0a 100644 --- a/web/lang/ja_jp.php +++ b/web/lang/ja_jp.php @@ -88,6 +88,7 @@ $SLANG = array( 'AlarmMaximumFPS' => 'Alarm Maximum FPS', 'AlarmPx' => 'װ Px', 'AlarmRGBUnset' => 'You must set an alarm RGB colour', + 'AlarmRefImageBlendPct'=> 'Alarm Reference Image Blend %ge', // Added - 2015-04-18 'Alert' => 'x', 'All' => 'S', 'Apply' => 'Kp', @@ -132,13 +133,13 @@ $SLANG = array( 'BadFPSReportInterval' => 'FPS report interval buffer count must be an integer of 0 or more', 'BadFormat' => 'Format must be set to an integer of zero or more', 'BadFrameSkip' => 'Frame skip count must be an integer of zero or more', - 'BadMotionFrameSkip' => 'Motion Frame skip count must be an integer of zero or more', 'BadHeight' => 'Height must be set to a valid value', 'BadHost' => 'Host must be set to a valid ip address or hostname, do not include http://', 'BadImageBufferCount' => 'Image buffer size must be an integer of 10 or more', 'BadLabelX' => 'Label X co-ordinate must be set to an integer of zero or more', 'BadLabelY' => 'Label Y co-ordinate must be set to an integer of zero or more', 'BadMaxFPS' => 'Maximum FPS must be a positive integer or floating point value', + 'BadMotionFrameSkip' => 'Motion Frame skip count must be an integer of zero or more', 'BadNameChars' => 'Names may only contain alphanumeric characters plus hyphen and underscore', 'BadPalette' => 'Palette must be set to a valid value', // Added - 2009-03-31 'BadPath' => 'Path must be set to a valid value', @@ -158,7 +159,9 @@ $SLANG = array( 'BlobSizes' => ' ', 'Blobs' => '', 'Brightness' => 'Px', + 'Buffer' => 'Buffer', // Added - 2015-04-18 'Buffers' => 'ޯ̧', + 'CSSDescription' => 'Change the default css for this computer', // Added - 2015-04-18 'CanAutoFocus' => 'Can Auto Focus', 'CanAutoGain' => 'Can Auto Gain', 'CanAutoIris' => 'Can Auto Iris', @@ -202,6 +205,7 @@ $SLANG = array( 'CaptureHeight' => '荞ݍ', 'CaptureMethod' => 'Capture Method', // Added - 2009-02-08 'CapturePalette' => '荞گ', + 'CaptureResolution' => 'Capture Resolution', // Added - 2015-04-18 'CaptureWidth' => '荞ݕ', 'Cause' => 'Cause', 'CheckMethod' => 'װ @', @@ -232,6 +236,7 @@ $SLANG = array( 'ControlDevice' => 'Control Device', 'ControlType' => 'Control Type', 'Controllable' => 'Controllable', + 'Current' => 'Current', // Added - 2015-04-18 'Cycle' => 'Cycle', 'CycleWatch' => 'يώ@', 'DateTime' => 'Date/Time', // Added - 2011-06-16 @@ -240,12 +245,15 @@ $SLANG = array( 'DefaultRate' => 'Default Rate', 'DefaultScale' => 'Default Scale', 'DefaultView' => 'Default View', + 'Deinterlacing' => 'Deinterlacing', // Added - 2015-04-18 + 'Delay' => 'Delay', // Added - 2015-04-18 'Delete' => '폜', 'DeleteAndNext' => '폜', 'DeleteAndPrev' => 'O폜', 'DeleteSavedFilter' => 'ۑ̨̍폜', 'Description' => '', 'DetectedCameras' => 'Detected Cameras', // Added - 2009-03-31 + 'DetectedProfiles' => 'Detected Profiles', // Added - 2015-04-18 'Device' => 'Device', // Added - 2009-02-08 'DeviceChannel' => '޲ ', 'DeviceFormat' => '޲ ̫ϯ', @@ -257,6 +265,7 @@ $SLANG = array( 'Disk' => 'Disk', 'Display' => 'Display', // Added - 2011-01-30 'Displaying' => 'Displaying', // Added - 2011-06-16 + 'DoNativeMotionDetection'=> 'Do Native Motion Detection', 'Donate' => 'Please Donate', 'DonateAlready' => 'No, I\'ve already donated', 'DonateEnticement' => 'You\'ve been running ZoneMinder for a while now and hopefully are finding it a useful addition to your home or workplace security. Although ZoneMinder is, and will remain, free and open source, it costs money to develop and support. If you would like to help support future development and new features then please consider donating. Donating is, of course, optional but very much appreciated and you can donate as much or as little as you like.

If you would like to donate please select the option below or go to http://www.zoneminder.com/donate.html in your browser.

Thank you for using ZoneMinder and don\'t forget to visit the forums on ZoneMinder.com for support or suggestions about how to make your ZoneMinder experience even better.', @@ -266,7 +275,6 @@ $SLANG = array( 'DonateRemindNever' => 'No, I don\'t want to donate, never remind', 'DonateRemindWeek' => 'Not yet, remind again in 1 week', 'DonateYes' => 'Yes, I\'d like to donate now', - 'DoNativeMotionDetection'=> 'Do Native Motion Detection', 'Download' => 'Download', 'DuplicateMonitorName' => 'Duplicate Monitor Name', // Added - 2009-03-31 'Duration' => 'p', @@ -309,10 +317,12 @@ $SLANG = array( 'Feed' => '荞', 'Ffmpeg' => 'Ffmpeg', // Added - 2009-02-08 'File' => 'File', + 'Filter' => 'Filter', // Added - 2015-04-18 'FilterArchiveEvents' => 'Archive all matches', 'FilterDeleteEvents' => 'Delete all matches', 'FilterEmailEvents' => 'Email details of all matches', 'FilterExecuteEvents' => 'Execute command on all matches', + 'FilterLog' => 'Filter log', // Added - 2015-04-18 'FilterMessageEvents' => 'Message details of all matches', 'FilterPx' => '̨ Px', 'FilterUnset' => 'You must specify a filter width and height', @@ -322,12 +332,12 @@ $SLANG = array( 'First' => 'ŏ', 'FlippedHori' => 'Flipped Horizontally', 'FlippedVert' => 'Flipped Vertically', - 'FnNone' => 'None', // Added 2013.08.16. - 'FnMonitor' => 'Monitor', // Added 2013.08.16. - 'FnModect' => 'Modect', // Added 2013.08.16. - 'FnRecord' => 'Record', // Added 2013.08.16. 'FnMocord' => 'Mocord', // Added 2013.08.16. + 'FnModect' => 'Modect', // Added 2013.08.16. + 'FnMonitor' => 'Monitor', // Added 2013.08.16. 'FnNodect' => 'Nodect', // Added 2013.08.16. + 'FnNone' => 'None', // Added 2013.08.16. + 'FnRecord' => 'Record', // Added 2013.08.16. 'Focus' => 'Focus', 'ForceAlarm' => 'װ', 'Format' => 'Format', @@ -335,7 +345,6 @@ $SLANG = array( 'FrameId' => 'ڰ ID', 'FrameRate' => 'ڰڰ', 'FrameSkip' => 'ڰѽ', - 'MotionFrameSkip' => 'Motion Frame Skip', 'Frames' => 'ڰ', 'Func' => '@\\', 'Function' => '@\\', @@ -462,6 +471,7 @@ $SLANG = array( 'MinZoomSpeed' => 'Min Zoom Speed', 'MinZoomStep' => 'Min Zoom Step', 'Misc' => '̑', + 'Mode' => 'Mode', // Added - 2015-04-18 'Monitor' => '', 'MonitorIds' => ' ID', 'MonitorPreset' => 'Monitor Preset', @@ -472,12 +482,13 @@ $SLANG = array( 'Montage' => 'ޭ', 'Month' => '', 'More' => 'More', // Added - 2011-06-16 + 'MotionFrameSkip' => 'Motion Frame Skip', 'Move' => 'Move', - 'MtgDefault' => 'Default', // Added 2013.08.15. 'Mtg2widgrd' => '2-wide grid', // Added 2013.08.15. 'Mtg3widgrd' => '3-wide grid', // Added 2013.08.15. - 'Mtg4widgrd' => '4-wide grid', // Added 2013.08.15. 'Mtg3widgrx' => '3-wide grid, scaled, enlarge on alarm', // Added 2013.08.15. + 'Mtg4widgrd' => '4-wide grid', // Added 2013.08.15. + 'MtgDefault' => 'Default', // Added 2013.08.15. 'MustBeGe' => 'ȏłȂ΂Ȃ', 'MustBeLe' => 'ȉłȂ΂Ȃ', 'MustConfirmPassword' => 'pX[h̊mFĂ', @@ -506,6 +517,9 @@ $SLANG = array( 'NumPresets' => 'Num Presets', 'Off' => 'Off', 'On' => 'On', + 'OnvifCredentialsIntro'=> 'Please supply user name and password for the selected camera.
If no user has been created for the camera then the user given here will be created with the given password.

', // Added - 2015-04-18 + 'OnvifProbe' => 'ONVIF', // Added - 2015-04-18 + 'OnvifProbeIntro' => 'The list below shows detected ONVIF cameras and whether they are already being used or available for selection.

Select the desired entry from the list below.

Please note that not all cameras may be detected and that choosing a camera here may overwrite any values you already have configured for the current monitor.

', // Added - 2015-04-18 'OpEq' => '', 'OpGt' => 'ȉ', 'OpGtEq' => 'ȏ', @@ -552,6 +566,9 @@ $SLANG = array( 'Presets' => 'Presets', 'Prev' => 'O', 'Probe' => 'Probe', // Added - 2009-03-31 + 'ProfileProbe' => 'Stream Probe', // Added - 2015-04-18 + 'ProfileProbeIntro' => 'The list below shows the existing stream profiles of the selected camera .

Select the desired entry from the list below.

Please note that ZoneMinder cannot configure additional profiles and that choosing a camera here may overwrite any values you already have configured for the current monitor.

', // Added - 2015-04-18 + 'Progress' => 'Progress', // Added - 2015-04-18 'Protocol' => 'Protocol', 'Rate' => 'ڰ', 'Real' => 'p', @@ -639,6 +656,7 @@ $SLANG = array( 'Submit' => 'Submit', 'System' => '', 'SystemLog' => 'System Log', // Added - 2011-06-16 + 'TargetColorspace' => 'Target colorspace', // Added - 2015-04-18 'Tele' => 'Tele', 'Thumbnail' => 'Thumbnail', 'Tilt' => 'Tilt', @@ -673,13 +691,16 @@ $SLANG = array( 'UpdateNotNecessary' => 'ްĂ̕Kv͂܂', 'Updated' => 'Updated', // Added - 2011-06-16 'Upload' => 'Upload', // Added - 2011-08-23 - 'UsedPlugins' => 'Used Plugins', 'UseFilter' => '̨gpĂ', 'UseFilterExprsPost' => ' ̨', // This is used at the end of the phrase 'use N filter expressions' 'UseFilterExprsPre' => 'w肵Ă: ', // This is used at the beginning of the phrase 'use N filter expressions' + 'UsedPlugins' => 'Used Plugins', 'User' => 'հ', 'Username' => 'հޖ', 'Users' => 'հ', + 'V4L' => 'V4L', // Added - 2015-04-18 + 'V4LCapturesPerFrame' => 'Captures Per Frame', // Added - 2015-04-18 + 'V4LMultiBuffer' => 'Multi Buffering', // Added - 2015-04-18 'Value' => 'l', 'Version' => 'ްޮ', 'VersionIgnore' => 'ްޮ݂𖳎', @@ -719,6 +740,7 @@ $SLANG = array( 'Zone' => 'ް', 'ZoneAlarmColour' => 'װ װ (Red/Green/Blue)', 'ZoneArea' => 'Zone Area', + 'ZoneExtendAlarmFrames' => 'Extend Alarm Frame Count', 'ZoneFilterSize' => 'Filter Width/Height (pixels)', 'ZoneMinMaxAlarmArea' => 'Min/Max Alarmed Area', 'ZoneMinMaxBlobArea' => 'Min/Max Blob Area', @@ -727,7 +749,6 @@ $SLANG = array( 'ZoneMinMaxPixelThres' => 'Min/Max Pixel Threshold (0-255)', 'ZoneMinderLog' => 'ZoneMinder Log', // Added - 2011-06-17 'ZoneOverloadFrames' => 'Overload Frame Ignore Count', - 'ZoneExtendAlarmFrames' => 'Extend Alarm Frame Count', 'Zones' => 'ް', 'Zoom' => 'Zoom', 'ZoomIn' => 'Zoom In', diff --git a/web/lang/nl_nl.php b/web/lang/nl_nl.php index 877fddec0..298521b6a 100644 --- a/web/lang/nl_nl.php +++ b/web/lang/nl_nl.php @@ -1,877 +1,904 @@ - '24 bits kleuren', - '8BitGrey' => '8 bits grijstinten', - 'Action' => 'Actie', - 'Actual' => 'Aktueel', - 'AddNewControl' => 'Nieuwe controle toevoegen', - 'AddNewMonitor' => 'Nieuwe monitor toevoegen', - 'AddNewUser' => 'Nieuwe gebruiker toevoegen', - 'AddNewZone' => 'Nieuw gebied toevoegen', - 'Alarm' => 'Alarm', - 'AlarmBrFrames' => 'Alarm
Frames', - 'AlarmFrame' => 'Alarm Frame', - 'AlarmFrameCount' => 'Alarm Frame Aantal', - 'AlarmLimits' => 'Alarm Limieten', - 'AlarmMaximumFPS' => 'Alarm Maximum FPS', - 'AlarmPx' => 'Alarm Px', - 'AlarmRGBUnset' => 'U moet een RGB alarm kleur keizen', - 'Alert' => 'Waarschuwing', - 'All' => 'Alle', - 'Apply' => 'Voer uit', - 'ApplyingStateChange' => 'Status verandering aan het uitvoeren', - 'ArchArchived' => 'Alleen gearchiveerd', - 'ArchUnarchived' => 'Alleen ongearchiveerd', - 'Archive' => 'Archief', - 'Archived' => 'Archived', - 'Area' => 'Gebied', - 'AreaUnits' => 'Gebied (px/%)', - 'AttrAlarmFrames' => 'Alarm frames', - 'AttrArchiveStatus' => 'Archief status', - 'AttrAvgScore' => 'Gem. score', - 'AttrCause' => 'Oorzaak', - 'AttrDate' => 'Datum', - 'AttrDateTime' => 'Datum/tijd', - 'AttrDiskBlocks' => 'Disk Blocks', - 'AttrDiskPercent' => 'Disk Percent', - 'AttrDuration' => 'Duur', - 'AttrFrames' => 'Frames', - 'AttrId' => 'Id', - 'AttrMaxScore' => 'Max. Score', - 'AttrMonitorId' => 'Monitor Id', - 'AttrMonitorName' => 'Monitor Naam', - 'AttrName' => 'Naam', - 'AttrNotes' => 'Notities', - 'AttrSystemLoad' => 'System Belasting', - 'AttrTime' => 'Tijd', - 'AttrTotalScore' => 'Totale Score', - 'AttrWeekday' => 'Weekdag', - 'Auto' => 'Auto', - 'AutoStopTimeout' => 'Auto Stop Timeout', - 'Available' => 'Beschikbaar', // Added - 2009-03-31 - 'AvgBrScore' => 'Gem.
score', - 'Background' => 'Achtergrond', - 'BackgroundFilter' => 'Run filter in achtergrond', - 'BadAlarmFrameCount' => 'Alarm frame moet een getal zijn van 1 of meer', - 'BadAlarmMaxFPS' => 'Alarm Maximum FPS moet een positiev getal zijn of een floating point waarde', - 'BadChannel' => 'Kanaal moet een getal zijn van 1 of meer', - 'BadDevice' => 'Apparaat moet een bestaande waarde krijgen', - 'BadFPSReportInterval' => 'FPS rapport interval buffer en aantal moet een nummer groter dan nul zijn', - 'BadFormat' => 'Formaat moet een nummer nul of groter zijn', - 'BadFrameSkip' => 'Frame skip aantal moet een nummer nul of groter zijn', - 'BadMotionFrameSkip' => 'Motion Frame skip count must be an integer of zero or more', - 'BadHeight' => 'Hoogte moet een geldige waarde zijn', - 'BadHost' => 'Host moet een juiste address or hostname zijn, laat http:// weg ', - 'BadImageBufferCount' => 'Foto buffer groote moet een nummer 10 of groter zijn', - 'BadLabelX' => 'Label X co-ordinate moet een nummer nul of groter zijn', - 'BadLabelY' => 'Label Y co-ordinate moet een nummer nul of groter zijn', - 'BadMaxFPS' => 'Maximum FPS moet een positieve integer of floating point waarde zijn', - 'BadNameChars' => 'Namen mogen alleen alpha numerieke karakters bevatten plus hyphens en underscores', - 'BadPalette' => 'Palette moet een geldige waarde zijn', // Added - 2009-03-31 - 'BadPath' => 'Pad moet een geldige waarde zijn', - 'BadPort' => 'Port moet een geldige nummer zijn', - 'BadPostEventCount' => 'Post gebeurtenis foto aantal moet een geldige waarde van nul of groter zijn', - 'BadPreEventCount' => 'Pre gebeurtenis aantal moe minimaal nul en lager dan de buffert grote', - 'BadRefBlendPerc' => 'Reference blend percentage moet een geldige waarde van nul of groter zijn', - 'BadSectionLength' => 'Selectie lengte moet een integer van 30 of meer zijn', - 'BadSignalCheckColour' => 'Signaal controle kleur moet een geldige RGB waarde zijn', - 'BadStreamReplayBuffer'=> 'Stream replay buffer moet een geldige waarde van nul of groter zijn', - 'BadWarmupCount' => 'Warmop frames moet een geldige waarde van nul of groter zijn', - 'BadWebColour' => 'Web kleur moeten een geldige webkleurwaarde bevatten', - 'BadWidth' => 'Breedte moet ingevuld worden', - 'Bandwidth' => 'Bandbreedte', - 'BandwidthHead' => 'Bandwidth', // This is the end of the bandwidth status on the top of the console, different in many language due to phrasing - 'BlobPx' => 'Blob px', - 'BlobSizes' => 'Blob grootte', - 'Blobs' => 'Blobs', - 'Brightness' => 'Helderheid', - 'Buffers' => 'Buffers', - 'CanAutoFocus' => 'Can Auto Focus', - 'CanAutoGain' => 'Can Auto Gain', - 'CanAutoIris' => 'Can Auto Iris', - 'CanAutoWhite' => 'Can Auto White Bal.', - 'CanAutoZoom' => 'Can Auto Zoom', - 'CanFocus' => 'Can Focus', - 'CanFocusAbs' => 'Can Focus Absoluut', - 'CanFocusCon' => 'Can Focus Continue', - 'CanFocusRel' => 'Can Focus Relatief', - 'CanGain' => 'Can Gain ', - 'CanGainAbs' => 'Can Gain Absoluut', - 'CanGainCon' => 'Can Gain Continue', - 'CanGainRel' => 'Can Gain Relatief', - 'CanIris' => 'Can Iris', - 'CanIrisAbs' => 'Can Iris Absoluut', - 'CanIrisCon' => 'Can Iris Continue', - 'CanIrisRel' => 'Can Iris Relatief', - 'CanMove' => 'Can Move', - 'CanMoveAbs' => 'Can Move Absoluut', - 'CanMoveCon' => 'Can Move Continue', - 'CanMoveDiag' => 'Can Move Diagonaal', - 'CanMoveMap' => 'Can Move Mapped', - 'CanMoveRel' => 'Can Move Relatief', - 'CanPan' => 'Can Pan' , - 'CanReset' => 'Can Reset', - 'CanSetPresets' => 'Can Set Presets', - 'CanSleep' => 'Can Sleep', - 'CanTilt' => 'Can Tilt', - 'CanWake' => 'Can Wake', - 'CanWhite' => 'Can White Balance', - 'CanWhiteAbs' => 'Can White Bal. Absoluut', - 'CanWhiteBal' => 'Can White Bal.', - 'CanWhiteCon' => 'Can White Bal. Continue', - 'CanWhiteRel' => 'Can White Bal. Relatief', - 'CanZoom' => 'Can Zoom', - 'CanZoomAbs' => 'Can Zoom Absoluut', - 'CanZoomCon' => 'Can Zoom Continue', - 'CanZoomRel' => 'Can Zoom Relatief', - 'Cancel' => 'Afbreken', - 'CancelForcedAlarm' => 'Afbreken geforceerd alarm', - 'CaptureHeight' => 'Opname hoogte', - 'CaptureMethod' => 'Opname Methode', // Added - 2009-02-08 - 'CapturePalette' => 'Opname pallet', - 'CaptureWidth' => 'Opname breedte', - 'Cause' => 'Oorzaak', - 'CheckMethod' => 'Alarm controle Methode', - 'ChooseDetectedCamera' => 'Kies gedetecteerde Camera', // Added - 2009-03-31 - 'ChooseFilter' => 'Kies filter', - 'ChooseLogFormat' => 'Kies en log formaat', // Added - 2011-06-17 - 'ChooseLogSelection' => 'Kies een log selectie', // Added - 2011-06-17 - 'ChoosePreset' => 'Kies voorkeur', - 'Clear' => 'Leeg', // Added - 2011-06-16 - 'Close' => 'Sluit', - 'Colour' => 'Kleur', - 'Command' => 'Commando', - 'Component' => 'Component', // Added - 2011-06-16 - 'Config' => 'Configuratie', - 'ConfiguredFor' => 'Geconfigureerd voor', - 'ConfirmDeleteEvents' => 'Weet uw zeker dat uw deze gebeurtenissen wil verwijderen?', - 'ConfirmPassword' => 'Bevestig wachtwoord', - 'ConjAnd' => 'en', - 'ConjOr' => 'of', - 'Console' => 'Console', - 'ContactAdmin' => 'Neem A.U.B. contact op met uw beheerder voor details.', - 'Continue' => 'Continue', - 'Contrast' => 'Contrast', - 'Control' => 'Bestuur', - 'ControlAddress' => 'Bestuur adres', - 'ControlCap' => 'Bestuur mogelijkheid', - 'ControlCaps' => 'Bestuur mogelijkheden', - 'ControlDevice' => 'Bestuur apparaat', - 'ControlType' => 'Bestuur Type', - 'Controllable' => 'Bestuurbaar', - 'Cycle' => 'Cyclus', - 'CycleWatch' => 'Observeer cyclus', - 'DateTime' => 'Datum/Tijd', // Added - 2011-06-16 - 'Day' => 'Dag', - 'Debug' => 'Debug', - 'DefaultRate' => 'Standaard Radius', - 'DefaultScale' => 'Standaard Schaal', - 'DefaultView' => 'Standaard scherm', - 'Delete' => 'verwijder', - 'DeleteAndNext' => 'verwijder & volgende', - 'DeleteAndPrev' => 'verwijder & vorige', - 'DeleteSavedFilter' => 'verwijder opgeslagen filter', - 'Description' => 'Omschrijving', - 'DetectedCameras' => 'Gedetecteerde Cameras', // Added - 2009-03-31 - 'Device' => 'Apparaat', // Added - 2009-02-08 - 'DeviceChannel' => 'Apparaat kanaal', - 'DeviceFormat' => 'Apparaat formaat', - 'DeviceNumber' => 'Apparaat nummer', - 'DevicePath' => 'Apparaat pad', - 'Devices' => 'Apparaten', - 'Dimensions' => 'Afmetingen', - 'DisableAlarms' => 'Alarmen uitschakelen', - 'Disk' => 'Schijf', - 'Display' => 'Weergave', // Added - 2011-01-30 - 'Displaying' => 'Weergaven', // Added - 2011-06-16 - 'Donate' => 'A.U.B geef ons een donatie', - 'DonateAlready' => 'Nee, ik heb al gedoneerd', - 'DonateEnticement' => 'U gebruikt Zoneminder nu voor een geruime tijd, hopelijk vindt je het een nuttige toevoeging voor u huis of werkplek beveiliging. Natuurlijk is en blijft Zoneminder gratis en open source software. Maar het kost geld om te ontwikkelen en support te onderhouden. Ik vraag u dan ook om er over na te denken om een donatie te doen om zo de ontwikkeling en support te ondersteunen. Natuurlijk bent u hier vrij in, en elke donatie hoe klein dan ook wordt erg gewaardeerd.

Als u wilt donderen geef dat hier onder dan aan of ga naar http://www.zoneminder.com/dontate.html in uw browser.

Bedankt voor het gebruiken van Zoneminder en vergeet niet om ons forum op ZoneMinder.com te bezoeken voor ondersteuning of suggesties waarmee u ZoneMinder beleving nog beter wordt.', - 'DonateRemindDay' => 'Nu niet, herinner mij over 1 dag hieraan', - 'DonateRemindHour' => 'Nu niet, herinner mij over een uur hieraan', - 'DonateRemindMonth' => 'Nu niet, herinner mij over een maand hieraan', - 'DonateRemindNever' => 'Nee, ik hiervoor wil niet doneren', - 'DonateRemindWeek' => 'Nu niet, herinner mij over een week hieraan', - 'DonateYes' => 'Ja, ik wil nu doneren', - 'Download' => 'Download', - 'DuplicateMonitorName' => 'Duplicaat Monitor Naam', // Added - 2009-03-31 - 'Duration' => 'Duur', - 'Edit' => 'Bewerk', - 'Email' => 'Email', - 'EnableAlarms' => 'Enable Alarms', - 'Enabled' => 'Ingeschakeld', - 'EnterNewFilterName' => 'Voer nieuwe filter naam in', - 'Error' => 'Fout', - 'ErrorBrackets' => 'Fout, controleer of je even veel openings als afsluiting brackets hebt gebruikt', - 'ErrorValidValue' => 'Fout, Controleer of alle termen een geldige waarde hebben', - 'Etc' => 'etc', - 'Event' => 'Gebeurtenis', - 'EventFilter' => 'Gebeurtenis filter', - 'EventId' => 'Gebeurtenis Id', - 'EventName' => 'Gebeurtenis Name', - 'EventPrefix' => 'Gebeurtenis Prefix', - 'Events' => 'Gebeurtenissen', - 'Exclude' => 'Sluit uit', - 'Execute' => 'Execute', - 'Export' => 'Exporteer', - 'ExportDetails' => 'Exporteer Gebeurtenis Details', - 'ExportFailed' => 'Exporteer gefaald', - 'ExportFormat' => 'Exporteer File Formaat', - 'ExportFormatTar' => 'Tar', - 'ExportFormatZip' => 'Zip', - 'ExportFrames' => 'Exporteer Frame Details', - 'ExportImageFiles' => 'Exporteer foto bestanden', - 'ExportLog' => 'Exporteer Log', // Added - 2011-06-17 - 'ExportMiscFiles' => 'Exporteer andere bestanden (wanneer aanwezig)', - 'ExportOptions' => 'Exporteer Opties', - 'ExportSucceeded' => 'Exporteren geslaagd', // Added - 2009-02-08 - 'ExportVideoFiles' => 'Exporteer Video bestanden (wanneer aanwezig)', - 'Exporting' => 'Exporteerd', - 'FPS' => 'fps', - 'FPSReportInterval' => 'FPS rapportage interval', - 'FTP' => 'FTP', - 'Far' => 'Far', - 'FastForward' => 'Snel vooruit', - 'Feed' => 'toevoer', - 'Ffmpeg' => 'Ffmpeg', // Added - 2009-02-08 - 'File' => 'Bestand', - 'FilterArchiveEvents' => 'Archiveer alle overeenkomsten', - 'FilterDeleteEvents' => 'Verwijder alle overeenkomsten', - 'FilterEmailEvents' => 'Email de details van alle overeenkomsten', - 'FilterExecuteEvents' => 'Voer opdrachten op alle overeenkomsten uit', - 'FilterMessageEvents' => 'Bericht de details van alle overeenkomsten', - 'FilterPx' => 'Filter px', - 'FilterUnset' => 'Je moet de filter hoogte en breedte opgeven', - 'FilterUploadEvents' => 'Verstuur alle overeenkomsten', - 'FilterVideoEvents' => 'Maak video voor alle matches', - 'Filters' => 'Filters', - 'First' => 'Eerste', - 'FlippedHori' => 'Horizontaal gedraait', - 'FlippedVert' => 'Vertikaal gedraait', - 'FnNone' => 'None', // Added 2013.08.16. - 'FnMonitor' => 'Monitor', // Added 2013.08.16. - 'FnModect' => 'Modect', // Added 2013.08.16. - 'FnRecord' => 'Record', // Added 2013.08.16. - 'FnMocord' => 'Mocord', // Added 2013.08.16. - 'FnNodect' => 'Nodect', // Added 2013.08.16. - 'Focus' => 'Focus', - 'ForceAlarm' => 'Forceeer alarm', - 'Format' => 'Formaat', - 'Frame' => 'Frame', - 'FrameId' => 'Frame id', - 'FrameRate' => 'Frame rate', - 'FrameSkip' => 'Frame overgeslagen', - 'MotionFrameSkip' => 'Motion Frame Skip', - 'Frames' => 'Frames', - 'Func' => 'Func', - 'Function' => 'Functie', - 'Gain' => 'Gain', - 'General' => 'Generiek', - 'GenerateVideo' => 'Genereer Video', - 'GeneratingVideo' => 'Genereren Video', - 'GoToZoneMinder' => 'Ga naar ZoneMinder.com', - 'Grey' => 'Grijs', - 'Group' => 'Groep', - 'Groups' => 'Groepen', - 'HasFocusSpeed' => 'Heeft Focus Sneldheid', - 'HasGainSpeed' => 'Heeft Gain Snelheid', - 'HasHomePreset' => 'Heeft start Voorkeuren', - 'HasIrisSpeed' => 'Heeft Iris Snelheid', - 'HasPanSpeed' => 'Heeft Pan Snelheid', - 'HasPresets' => 'Heeft Voorkeuren', - 'HasTiltSpeed' => 'Heeft Tilt Snelheid', - 'HasTurboPan' => 'Heeft Turbo Pan', - 'HasTurboTilt' => 'Heeft Turbo Tilt', - 'HasWhiteSpeed' => 'Heeft White Bal. Snelheid', - 'HasZoomSpeed' => 'Heeft Zoom Snelheid', - 'High' => 'Hoog', - 'HighBW' => 'Hoog B/W', - 'Home' => 'Home', - 'Hour' => 'Uur', - 'Hue' => 'Hue', - 'Id' => 'Id', - 'Idle' => 'Ongebruikt', - 'Ignore' => 'Negeer', - 'Image' => 'Foto', - 'ImageBufferSize' => 'Foto buffer grootte (frames)', - 'Images' => 'Fotos', - 'In' => 'In', - 'Include' => 'voeg in', - 'Inverted' => 'Omgedraaid', - 'Iris' => 'Iris', - 'KeyString' => 'Sleutel waarde', - 'Label' => 'Label', - 'Language' => 'Taal', - 'Last' => 'Laatste', - 'Layout' => 'Layout', // Added - 2009-02-08 - 'Level' => 'Nivo', // Added - 2011-06-16 - 'Libvlc' => 'Libvlc', - 'LimitResultsPost' => 'resultaten;', // This is used at the end of the phrase 'Limit to first N results only' - 'LimitResultsPre' => 'beperk tot eerste', // This is used at the beginning of the phrase 'Limit to first N results only' - 'Line' => 'Lijn', // Added - 2011-06-16 - 'LinkedMonitors' => 'Gekoppelde monitoren', - 'List' => 'Lijst', - 'Load' => 'Belasting', - 'Local' => 'Lokaal', - 'Log' => 'Log', // Added - 2011-06-16 - 'LoggedInAs' => 'Aangemeld als', - 'Logging' => 'Logging', // Added - 2011-06-16 - 'LoggingIn' => 'Aanmelden..', - 'Login' => 'Aanmelden', - 'Logout' => 'Afmelden', - 'Logs' => 'Logs', // Added - 2011-06-17 - 'Low' => 'Laag', - 'LowBW' => 'Laag B/W', - 'Main' => 'Main', - 'Man' => 'Man', - 'Manual' => 'Handmatig', - 'Mark' => 'Markeer', - 'Max' => 'Max', - 'MaxBandwidth' => 'Max Bandbreedte', - 'MaxBrScore' => 'Max.
score', - 'MaxFocusRange' => 'Max Focus Bereik', - 'MaxFocusSpeed' => 'Max Focus Snelheid', - 'MaxFocusStep' => 'Max Focus Stap', - 'MaxGainRange' => 'Max Gain Bereik', - 'MaxGainSpeed' => 'Max Gain Snelheid', - 'MaxGainStep' => 'Max Gain Stap', - 'MaxIrisRange' => 'Max Iris Bereik', - 'MaxIrisSpeed' => 'Max Iris Snelheid', - 'MaxIrisStep' => 'Max Iris Stap', - 'MaxPanRange' => 'Max Pan Bereik', - 'MaxPanSpeed' => 'Max Pan Snelheid', - 'MaxPanStep' => 'Max Pan Stap', - 'MaxTiltRange' => 'Max Tilt Bereik', - 'MaxTiltSpeed' => 'Max Tilt Snelheid', - 'MaxTiltStep' => 'Max Tilt Stap', - 'MaxWhiteRange' => 'Max White Bal. Bereik', - 'MaxWhiteSpeed' => 'Max White Bal. Snelheid', - 'MaxWhiteStep' => 'Max White Bal. Stap', - 'MaxZoomRange' => 'Max Zoom Bereik', - 'MaxZoomSpeed' => 'Max Zoom Snelheid', - 'MaxZoomStep' => 'Max Zoom Stap', - 'MaximumFPS' => 'Maximum FPS', - 'Medium' => 'Medium', - 'MediumBW' => 'Medium B/W', - 'Message' => 'Message', // Added - 2011-06-16 - 'MinAlarmAreaLtMax' => 'Minimum alarm moet kleiner dan het maximum', - 'MinAlarmAreaUnset' => 'Specificeer het minimaal aantal alarm pixels', - 'MinBlobAreaLtMax' => 'minimum blob gebied moet kleiner zijn dan maximum blob gebied', - 'MinBlobAreaUnset' => 'Specificeer het minimaal aantal blob pixels', - 'MinBlobLtMinFilter' => 'Minimum blob gebied moet kleiner of gelijk aan het minimale filter gebied zijn', - 'MinBlobsLtMax' => 'Minimum blobs moet kleiner zijn dan maximum blobs', - 'MinBlobsUnset' => 'Specificeer het minimaal blob aantal', - 'MinFilterAreaLtMax' => 'Minimum filter gebied moet minder dan het maximum zijn', - 'MinFilterAreaUnset' => 'Specificeer het minimaal aantal filter pixels', - 'MinFilterLtMinAlarm' => 'Minimum filter gebied moet kleiner of gelijk aan het minimale alarm gebied zijn', - 'MinFocusRange' => 'Min Focus Bereik', - 'MinFocusSpeed' => 'Min Focus Snelheid', - 'MinFocusStep' => 'Min Focus Step', - 'MinGainRange' => 'Min Gain Bereik', - 'MinGainSpeed' => 'Min Gain Snelheid', - 'MinGainStep' => 'Min Gain Step', - 'MinIrisRange' => 'Min Iris Bereik', - 'MinIrisSpeed' => 'Min Iris Snelheid', - 'MinIrisStep' => 'Min Iris Step', - 'MinPanRange' => 'Min Draai Bereik', - 'MinPanSpeed' => 'Min Draai Snelheid', - 'MinPanStep' => 'Min Draai Step', - 'MinPixelThresLtMax' => 'Minimum pixel kleurdiepte moet kleiner zijn dan maximum pixel bereikwaarde', - 'MinPixelThresUnset' => 'Specificeer een minimale pixel bereikwaarde', - 'MinTiltRange' => 'Min Tilt Bereik', - 'MinTiltSpeed' => 'Min Tilt Snelheid', - 'MinTiltStep' => 'Min Tilt Step', - 'MinWhiteRange' => 'Min White Bal. Bereik', - 'MinWhiteSpeed' => 'Min White Bal. Snelheid', - 'MinWhiteStep' => 'Min White Bal. Step', - 'MinZoomRange' => 'Min Zoom Bereik', - 'MinZoomSpeed' => 'Min Zoom Snelheid', - 'MinZoomStep' => 'Min Zoom Step', - 'Misc' => 'Misc', - 'Monitor' => 'Monitor', - 'MonitorIds' => 'Monitor Ids', - 'MonitorPreset' => 'Monitor Preset', - 'MonitorPresetIntro' => 'Selecteer een preset uit de lijst.

let op dit overschrijft de reeds ingevoerde waarden voor deze monitor!

', - 'MonitorProbe' => 'Monitor Probe', // Added - 2009-03-31 - 'MonitorProbeIntro' => 'Deze lijst toont gedeteerde analoge en netwerk cameras en of deze al ingebruik of beschikbaar zijn.

Selecteer de gewenste waarde uit de lijst hier beneden.

Let er op dat het mogelijk is dat niet alle cameras hier worden weer gegeven, en dat alle ingevoerde waarden voor de huidige monitor worden overschreven.

', // Added - 2009-03-31 - 'Monitors' => 'Monitoren', - 'Montage' => 'Montage', - 'Month' => 'Maand', - 'More' => 'Meer', // Added - 2011-06-16 - 'Move' => 'Verplaats', - 'MtgDefault' => 'Default', // Added 2013.08.15. - 'Mtg2widgrd' => '2-wide grid', // Added 2013.08.15. - 'Mtg3widgrd' => '3-wide grid', // Added 2013.08.15. - 'Mtg4widgrd' => '4-wide grid', // Added 2013.08.15. - 'Mtg3widgrx' => '3-wide grid, scaled, enlarge on alarm', // Added 2013.08.15. - 'MustBeGe' => 'Moet groter zijn of gelijk aan', - 'MustBeLe' => 'Moet kleiner zijn of gelijk aan', - 'MustConfirmPassword' => 'Je moet je wachtwoord bevestigen', - 'MustSupplyPassword' => 'Je moet een wachtwoord geven', - 'MustSupplyUsername' => 'Je moet een gebruikersnaam geven', - 'Name' => 'Naam', - 'Near' => 'Dichtbij', - 'Network' => 'Netwerk', - 'New' => 'Nieuw', - 'NewGroup' => 'Niew Groep', - 'NewLabel' => 'Niew Label', - 'NewPassword' => 'Nieuw wachtwoord', - 'NewState' => 'Nieuwe status', - 'NewUser' => 'Nieuwe gebruiker', - 'Next' => 'Volgende', - 'No' => 'Nee', - 'NoDetectedCameras' => 'Geen cameras gedeteceerd', // Added - 2009-03-31 - 'NoFramesRecorded' => 'Er zijn geen frames opgenomen voor deze gebeurtenis', - 'NoGroup' => 'Geeb Groep', - 'NoSavedFilters' => 'Geen Opgeslagen Filters', - 'NoStatisticsRecorded' => 'Er zijn geen statistieken opgenomen voor deze gebeurenis', - 'None' => 'Geen', - 'NoneAvailable' => 'Geen beschikbaar', - 'Normal' => 'Normaal', - 'Notes' => 'Notities', - 'NumPresets' => 'Num Voorkeuren', - 'Off' => 'Uit', - 'On' => 'Aan', - 'OpEq' => 'gelijk aan', - 'OpGt' => 'groter dan', - 'OpGtEq' => 'groter dan of gelijk aan', - 'OpIn' => 'in set', - 'OpLt' => 'kleiner dan', - 'OpLtEq' => 'kleiner dan of gelijk aan', - 'OpMatches' => 'Komt overeen', - 'OpNe' => 'niet gelijk aan', - 'OpNotIn' => 'niet in set', - 'OpNotMatches' => 'Komt niet overeen', - 'Open' => 'Open', - 'OptionHelp' => 'OptieHelp', - 'OptionRestartWarning' => 'Deze veranderingen passen niet aan\nals het systeem loopt. Als je\nKlaar bent met veranderen vergeet dan niet dat\nje ZoneMinder herstart.', - 'Options' => 'Opties', - 'OrEnterNewName' => 'of voer een nieuwe naam in', - 'Order' => 'Sorteer', - 'Orientation' => 'Orientatie', - 'Out' => 'Uit', - 'OverwriteExisting' => 'Overschrijf bestaande', - 'Paged' => 'Paged', - 'Pan' => 'Pan', - 'PanLeft' => 'Pan Links', - 'PanRight' => 'Pan Rechts', - 'PanTilt' => 'Pan/Tilt', - 'Parameter' => 'Parameter', - 'Password' => 'Wachtwoord', - 'PasswordsDifferent' => 'Het nieuwe en bevestigde wachtwoord zijn verschillend', - 'Paths' => 'Paden', - 'Pause' => 'Pause', - 'Phone' => 'Telefoon', - 'PhoneBW' => 'Telefoon B/W', - 'Pid' => 'PID', // Added - 2011-06-16 - 'PixelDiff' => 'Pixel Diff', - 'Pixels' => 'pixels', - 'Play' => 'Speel', - 'PlayAll' => 'Speel Alles', - 'PleaseWait' => 'Wacht A.U.B.', - 'Point' => 'Punt', - 'PostEventImageBuffer' => 'Post gebeurtenis foto Buffer', - 'PreEventImageBuffer' => 'Pre gebeurtenis foto Buffer', - 'PreserveAspect' => 'Beeld verhouding bewaren', - 'Preset' => 'Voorkeur', - 'Presets' => 'Voorkeuren', - 'Prev' => 'Vorige', - 'Probe' => 'Scan', // Added - 2009-03-31 - 'Protocol' => 'Protocol', - 'Rate' => 'Waardering', - 'Real' => 'Echte', - 'Record' => 'Record', - 'RefImageBlendPct' => 'Referentie foto Blend %ge', - 'Refresh' => 'Ververs', - 'Remote' => 'Remote', - 'RemoteHostName' => 'Remote Host Naam', - 'RemoteHostPath' => 'Remote Host Pad', - 'RemoteHostPort' => 'Remote Host Poort', - 'RemoteHostSubPath' => 'Remote Host SubPad', // Added - 2009-02-08 - 'RemoteImageColours' => 'Remote foto kleuren', - 'RemoteMethod' => 'Remote Methode', // Added - 2009-02-08 - 'RemoteProtocol' => 'Remote Protocol', // Added - 2009-02-08 - 'Rename' => 'Hernoem', - 'Replay' => 'Opnieuw', - 'ReplayAll' => 'Alle Gebeurtenissen', - 'ReplayGapless' => 'Opvolgende Gebeurtenissen', - 'ReplaySingle' => 'Enkele Gebeurtenis', - 'Reset' => 'Herstel', - 'ResetEventCounts' => 'Herstel gebeurtenis teller', - 'Restart' => 'Herstart', - 'Restarting' => 'Herstarten', - 'RestrictedCameraIds' => 'Verboden Camera Ids', - 'RestrictedMonitors' => 'Beperkte Monitoren', - 'ReturnDelay' => 'Return Delay', - 'ReturnLocation' => 'Return Locatie', - 'Rewind' => 'Rewind', - 'RotateLeft' => 'Draai linksom', - 'RotateRight' => 'Draai rechtsom', - 'RunLocalUpdate' => 'Gebruik zmupdate.pl om up te daten', // Added - 2011-05-25 - 'RunMode' => 'Draai Modus', - 'RunState' => 'Draai Status', - 'Running' => 'Werkend', - 'Save' => 'Opslaan', - 'SaveAs' => 'Opslaan als', - 'SaveFilter' => 'Opslaan Filter', - 'Scale' => 'Schaal', - 'Score' => 'Score', - 'Secs' => 'Secs', - 'Sectionlength' => 'Sectie lengte', - 'Select' => 'Selecteer', - 'SelectFormat' => 'Selecteer Formaat', // Added - 2011-06-17 - 'SelectLog' => 'Selecteer Log', // Added - 2011-06-17 - 'SelectMonitors' => 'Selecteer Monitoren', - 'SelfIntersecting' => 'Polygon randen moeten niet overlappen', - 'Set' => 'Zet', - 'SetNewBandwidth' => 'Zet Nieuwe Bandbreedte', - 'SetPreset' => 'Zet Preset', - 'Settings' => 'Instellingen', - 'ShowFilterWindow' => 'Toon Filter Venster', - 'ShowTimeline' => 'Toon Tijdslijn', - 'SignalCheckColour' => 'Signaal controle kleur', - 'Size' => 'Groote', - 'SkinDescription' => 'Wijzig standaard uiterlijk voor deze computer', // Added - 2011-01-30 - 'Sleep' => 'Slaap', - 'SortAsc' => 'Opl.', - 'SortBy' => 'Sorteer op', - 'SortDesc' => 'Afl.', - 'Source' => 'Bron', - 'SourceColours' => 'Bron Colours', // Added - 2009-02-08 - 'SourcePath' => 'Bron Path', // Added - 2009-02-08 - 'SourceType' => 'Bron Type', - 'Speed' => 'Snelheid', - 'SpeedHigh' => 'Hoge Snelheid', - 'SpeedLow' => 'Lage Snelheid', - 'SpeedMedium' => 'Medium Snelheid', - 'SpeedTurbo' => 'Turbo Snelheid', - 'Start' => 'Start', - 'State' => 'Status', - 'Stats' => 'Stats', - 'Status' => 'Status', - 'Step' => 'Stap', - 'StepBack' => 'Stap Terug', - 'StepForward' => 'Stap Vooruit', - 'StepLarge' => 'Groten stap', - 'StepMedium' => 'Medium Stap', - 'StepNone' => 'Geen Stap', - 'StepSmall' => 'Smalle Stap', - 'Stills' => 'Plaatjes', - 'Stop' => 'Stop', - 'Stopped' => 'Gestopt', - 'Stream' => 'Stream', - 'StreamReplayBuffer' => 'Stream Replay foto Buffer', - 'Submit' => 'Verzenden', - 'System' => 'Systeem', - 'SystemLog' => 'Systeem Log', // Added - 2011-06-16 - 'Tele' => 'Tele', - 'Thumbnail' => 'Thumbnail', - 'Tilt' => 'Tilt', - 'Time' => 'Tijd', - 'TimeDelta' => 'Tijd Delta', - 'TimeStamp' => 'Tijdstempel', - 'Timeline' => 'Tijdslijn', - 'TimelineTip1' => 'Pass your mouse over the graph to view a snapshot image and event details.', // Added 2013.08.15. - 'TimelineTip2' => 'Click on the coloured sections of the graph, or the image, to view the event.', // Added 2013.08.15. - 'TimelineTip3' => 'Click on the background to zoom in to a smaller time period based around your click.', // Added 2013.08.15. - 'TimelineTip4' => 'Use the controls below to zoom out or navigate back and forward through the time range.', // Added 2013.08.15. - 'Timestamp' => 'Tijdstempel', - 'TimestampLabelFormat' => 'Tijdstempel Label Format', - 'TimestampLabelX' => 'Tijdstempel Label X', - 'TimestampLabelY' => 'Tijdstempel Label Y', - 'Today' => 'Vandaag', - 'Tools' => 'Gereedschappen', - 'Total' => 'Totaal', // Added - 2011-06-16 - 'TotalBrScore' => 'Totaal
Score', - 'TrackDelay' => 'Track Vertraging', - 'TrackMotion' => 'Track Beweging', - 'Triggers' => 'Triggers', - 'TurboPanSpeed' => 'Turbo Pan Snelheid', - 'TurboTiltSpeed' => 'Turbo Tilt Snelheid', - 'Type' => 'Type', - 'Unarchive' => 'Dearchiveer', - 'Undefined' => 'Ongedefineerd', // Added - 2009-02-08 - 'Units' => 'Eenheden', - 'Unknown' => 'Onbekend', - 'Update' => 'Ververs', - 'UpdateAvailable' => 'Een update voor ZoneMinder is beschikbaar', - 'UpdateNotNecessary' => 'Geen update noodzakelijk', - 'Updated' => 'Ververst', // Added - 2011-06-16 - 'UseFilter' => 'Gebruik Filter', - 'UseFilterExprsPost' => ' filter expressies', // This is used at the end of the phrase 'use N filter expressions' - 'UseFilterExprsPre' => 'Gebruik ', // This is used at the beginning of the phrase 'use N filter expressions' - 'User' => 'Gebruiker', - 'Username' => 'Gebruikersnaam', - 'Users' => 'Gebruikers', - 'Value' => 'Waarde', - 'Version' => 'Versie', - 'VersionIgnore' => 'Negeer deze versie', - 'VersionRemindDay' => 'Herinner mij na 1 dag', - 'VersionRemindHour' => 'Herinner mij na 1 uur', - 'VersionRemindNever' => 'Herinner mij niet aan nieuwe versies', - 'VersionRemindWeek' => 'Herinner mij na 1 week', - 'Video' => 'Video', - 'VideoFormat' => 'Video Formaat', - 'VideoGenFailed' => 'Video Generatie mislukt!', - 'VideoGenFiles' => 'Bestaande video bestanden', - 'VideoGenNoFiles' => 'Geen video bestanden gevonden', - 'VideoGenParms' => 'Video Generatie Parameters', - 'VideoGenSucceeded' => 'Video Generatie voltooid!', - 'VideoSize' => 'Video grootte', - 'View' => 'Bekijk', - 'ViewAll' => 'Bekijk Alles', - 'ViewEvent' => 'Bekijk Gebeurtenis', - 'ViewPaged' => 'Bekijk Pagina', - 'Wake' => 'Wakker', - 'WarmupFrames' => 'Warmop Frames', - 'Watch' => 'Observeer', - 'Web' => 'Web', - 'WebColour' => 'Web Kleur', - 'Week' => 'Week', - 'White' => 'Wit', - 'WhiteBalance' => 'Wit Balance', - 'Wide' => 'Wijd', - 'X' => 'X', - 'X10' => 'X10', - 'X10ActivationString' => 'X10 Activatie Waarde', - 'X10InputAlarmString' => 'X10 Input Alarm Waarde', - 'X10OutputAlarmString' => 'X10 Output Alarm Waarde', - 'Y' => 'Y', - 'Yes' => 'Ja', - 'YouNoPerms' => 'U heeft niet de rechten om toegang te krijgen tot deze bronnen.', - 'Zone' => 'Zone', - 'ZoneAlarmColour' => 'Alarm Kleur (Rood/Groen/Blauw)', - 'ZoneArea' => 'Zone Gebied', - 'ZoneFilterSize' => 'Filter Hoogte/Breedte (pixels)', - 'ZoneMinMaxAlarmArea' => 'Min/Max Alarmeer Gebied', - 'ZoneMinMaxBlobArea' => 'Min/Max Blob Gebied', - 'ZoneMinMaxBlobs' => 'Min/Max Blobs', - 'ZoneMinMaxFiltArea' => 'Min/Max Gefilterd Gebied', - 'ZoneMinMaxPixelThres' => 'Min/Max Pixel Threshold (0-255)', - 'ZoneMinderLog' => 'ZoneMinder Log', // Added - 2011-06-17 - 'ZoneOverloadFrames' => 'Overload Frame negeer aantal', - 'ZoneExtendAlarmFrames' => 'Extend Alarm Frame Count', - 'Zones' => 'Zones', - 'Zoom' => 'Zoom', - 'ZoomIn' => 'Zoom In', - 'ZoomOut' => 'Zoom Uit', -); - -// Complex replacements with formatting and/or placements, must be passed through sprintf -$CLANG = array( - 'CurrentLogin' => 'huidige login is \'%1$s\'', - 'EventCount' => '%1$s %2$s', // Als voorbeeld '37 gebeurtenissen' (from Vlang below) - 'LastEvents' => 'Last %1$s %2$s', // Als voorbeeld 'Laatste 37 gebeurtenissen' (from Vlang below) - 'LatestRelease' => 'de laatste release is v%1$s, jij hebt v%2$s.', - 'MonitorCount' => '%1$s %2$s', // Als voorbeeld '4 Monitoren' (from Vlang below) - 'MonitorFunction' => 'Monitor %1$s Functie', - 'RunningRecentVer' => 'U draait al met de laatste versie van ZoneMinder, v%s.', - 'VersionMismatch' => 'Versie verschil, systeem is versie %1$s, database is %2$s.', // Added - 2011-05-25 -); - -// The next section allows you to describe a series of word ending and counts used to -// generate the correctly conjugated forms of words depending on a count that is associated -// with that word. -// This intended to allow phrases such a '0 potatoes', '1 potato', '2 potatoes' etc to -// conjugate correctly with the associated count. -// In some languages such as English this is fairly simple and can be expressed by assigning -// a count with a singular or plural form of a word and then finding the nearest (lower) value. -// So '0' of something generally ends in 's', 1 of something is singular and has no extra -// ending and 2 or more is a plural and ends in 's' also. So to find the ending for '187' of -// something you would find the nearest lower count (2) and use that ending. -// -// So examples of this would be -// $zmVlangPotato = array( 0=>'Potatoes', 1=>'Potato', 2=>'Potatoes' ); -// $zmVlangSheep = array( 0=>'Sheep' ); -// -// where you can have as few or as many entries in the array as necessary -// If your language is similar in form to this then use the same format and choose the -// appropriate zmVlang function below. -// If however you have a language with a different format of plural endings then another -// approach is required . For instance in Russian the word endings change continuously -// depending on the last digit (or digits) of the numerator. In this case then zmVlang -// arrays could be written so that the array index just represents an arbitrary 'type' -// and the zmVlang function does the calculation about which version is appropriate. -// -// So an example in Russian might be (using English words, and made up endings as I -// don't know any Russian!!) -// $zmVlangPotato = array( 1=>'Potati', 2=>'Potaton', 3=>'Potaten' ); -// -// and the zmVlang function decides that the first form is used for counts ending in -// 0, 5-9 or 11-19 and the second form when ending in 1 etc. -// - -// Variable arrays expressing plurality, see the zmVlang description above -$VLANG = array( - 'Event' => array( 0=>'gebeurtenissen', 1=>'gebeurtenis', 2=>'gebeurtenissen' ), - 'Monitor' => array( 0=>'Monitoren', 1=>'Monitor', 2=>'Monitoren' ), -); - -// You will need to choose or write a function that can correlate the plurality string arrays -// with variable counts. This is used to conjugate the Vlang arrays above with a number passed -// in to generate the correct noun form. -// -// In languages such as English this is fairly simple -// Note this still has to be used with printf etc to get the right formating -function zmVlang( $langVarArray, $count ) -{ - krsort( $langVarArray ); - foreach ( $langVarArray as $key=>$value ) - { - if ( abs($count) >= $key ) - { - return( $value ); - } - } - die( 'Error, unable to correlate variable language string' ); -} - -// This is an version that could be used in the Russian example above -// The rules are that the first word form is used if the count ends in -// 0, 5-9 or 11-19. The second form is used then the count ends in 1 -// (not including 11 as above) and the third form is used when the -// count ends in 2-4, again excluding any values ending in 12-14. -// -// function zmVlang( $langVarArray, $count ) -// { -// $secondlastdigit = substr( $count, -2, 1 ); -// $lastdigit = substr( $count, -1, 1 ); -// // or -// // $secondlastdigit = ($count/10)%10; -// // $lastdigit = $count%10; -// -// // Get rid of the special cases first, the teens -// if ( $secondlastdigit == 1 && $lastdigit != 0 ) -// { -// return( $langVarArray[1] ); -// } -// switch ( $lastdigit ) -// { -// case 0 : -// case 5 : -// case 6 : -// case 7 : -// case 8 : -// case 9 : -// { -// return( $langVarArray[1] ); -// break; -// } -// case 1 : -// { -// return( $langVarArray[2] ); -// break; -// } -// case 2 : -// case 3 : -// case 4 : -// { -// return( $langVarArray[3] ); -// break; -// } -// } -// die( 'Error, unable to correlate variable language string' ); -// } - -// This is an example of how the function is used in the code which you can uncomment and -// use to test your custom function. -//$monitors = array(); -//$monitors[] = 1; // Choose any number -//echo sprintf( $zmClangMonitorCount, count($monitors), zmVlang( $zmVlangMonitor, count($monitors) ) ); - -// In this section you can override the default prompt and help texts for the options area -// These overrides are in the form show below where the array key represents the option name minus the initial ZM_ -// So for example, to override the help text for ZM_LANG_DEFAULT do -$OLANG = array( - 'OPTIONS_FFMPEG' => array( - 'Help' => "Parameters in this field are passwd on to FFmpeg. Multiple parameters can be separated by ,~~ ". - "Examples (do not enter quotes)~~~~". - "\"allowed_media_types=video\" Set datatype to request fromcam (audio, video, data)~~~~". - "\"reorder_queue_size=nnn\" Set number of packets to buffer for handling of reordered packets~~~~". - "\"loglevel=debug\" Set verbosiy of FFmpeg (quiet, panic, fatal, error, warning, info, verbose, debug)" - ), - 'OPTIONS_LIBVLC' => array( - 'Help' => "Parameters in this field are passwd on to libVLC. Multiple parameters can be separated by ,~~ ". - "Examples (do not enter quotes)~~~~". - "\"--rtp-client-port=nnn\" Set local port to use for rtp data~~~~". - "\"--verbose=2\" Set verbosity of libVLC" - ), - -// 'LANG_DEFAULT' => array( -// 'Prompt' => "This is a new prompt for this option", -// 'Help' => "This is some new help for this option which will be displayed in the popup window when the ? is clicked" -// ), -); - -?> + '24 bits kleuren', + '32BitColour' => '32 bit colour', // Added - 2015-04-18 + '8BitGrey' => '8 bits grijstinten', + 'Action' => 'Actie', + 'Actual' => 'Aktueel', + 'AddNewControl' => 'Nieuwe controle toevoegen', + 'AddNewMonitor' => 'Nieuwe monitor toevoegen', + 'AddNewUser' => 'Nieuwe gebruiker toevoegen', + 'AddNewZone' => 'Nieuw gebied toevoegen', + 'Alarm' => 'Alarm', + 'AlarmBrFrames' => 'Alarm
Frames', + 'AlarmFrame' => 'Alarm Frame', + 'AlarmFrameCount' => 'Alarm Frame Aantal', + 'AlarmLimits' => 'Alarm Limieten', + 'AlarmMaximumFPS' => 'Alarm Maximum FPS', + 'AlarmPx' => 'Alarm Px', + 'AlarmRGBUnset' => 'U moet een RGB alarm kleur keizen', + 'AlarmRefImageBlendPct'=> 'Alarm Reference Image Blend %ge', // Added - 2015-04-18 + 'Alert' => 'Waarschuwing', + 'All' => 'Alle', + 'Apply' => 'Voer uit', + 'ApplyingStateChange' => 'Status verandering aan het uitvoeren', + 'ArchArchived' => 'Alleen gearchiveerd', + 'ArchUnarchived' => 'Alleen ongearchiveerd', + 'Archive' => 'Archief', + 'Archived' => 'Archived', + 'Area' => 'Gebied', + 'AreaUnits' => 'Gebied (px/%)', + 'AttrAlarmFrames' => 'Alarm frames', + 'AttrArchiveStatus' => 'Archief status', + 'AttrAvgScore' => 'Gem. score', + 'AttrCause' => 'Oorzaak', + 'AttrDate' => 'Datum', + 'AttrDateTime' => 'Datum/tijd', + 'AttrDiskBlocks' => 'Disk Blocks', + 'AttrDiskPercent' => 'Disk Percent', + 'AttrDuration' => 'Duur', + 'AttrFrames' => 'Frames', + 'AttrId' => 'Id', + 'AttrMaxScore' => 'Max. Score', + 'AttrMonitorId' => 'Monitor Id', + 'AttrMonitorName' => 'Monitor Naam', + 'AttrName' => 'Naam', + 'AttrNotes' => 'Notities', + 'AttrSystemLoad' => 'System Belasting', + 'AttrTime' => 'Tijd', + 'AttrTotalScore' => 'Totale Score', + 'AttrWeekday' => 'Weekdag', + 'Auto' => 'Auto', + 'AutoStopTimeout' => 'Auto Stop Timeout', + 'Available' => 'Beschikbaar', // Added - 2009-03-31 + 'AvgBrScore' => 'Gem.
score', + 'Background' => 'Achtergrond', + 'BackgroundFilter' => 'Run filter in achtergrond', + 'BadAlarmFrameCount' => 'Alarm frame moet een getal zijn van 1 of meer', + 'BadAlarmMaxFPS' => 'Alarm Maximum FPS moet een positiev getal zijn of een floating point waarde', + 'BadChannel' => 'Kanaal moet een getal zijn van 1 of meer', + 'BadColours' => 'Target colour must be set to a valid value', // Added - 2015-04-18 + 'BadDevice' => 'Apparaat moet een bestaande waarde krijgen', + 'BadFPSReportInterval' => 'FPS rapport interval buffer en aantal moet een nummer groter dan nul zijn', + 'BadFormat' => 'Formaat moet een nummer nul of groter zijn', + 'BadFrameSkip' => 'Frame skip aantal moet een nummer nul of groter zijn', + 'BadHeight' => 'Hoogte moet een geldige waarde zijn', + 'BadHost' => 'Host moet een juiste address or hostname zijn, laat http:// weg ', + 'BadImageBufferCount' => 'Foto buffer groote moet een nummer 10 of groter zijn', + 'BadLabelX' => 'Label X co-ordinate moet een nummer nul of groter zijn', + 'BadLabelY' => 'Label Y co-ordinate moet een nummer nul of groter zijn', + 'BadMaxFPS' => 'Maximum FPS moet een positieve integer of floating point waarde zijn', + 'BadMotionFrameSkip' => 'Motion Frame skip count must be an integer of zero or more', + 'BadNameChars' => 'Namen mogen alleen alpha numerieke karakters bevatten plus hyphens en underscores', + 'BadPalette' => 'Palette moet een geldige waarde zijn', // Added - 2009-03-31 + 'BadPath' => 'Pad moet een geldige waarde zijn', + 'BadPort' => 'Port moet een geldige nummer zijn', + 'BadPostEventCount' => 'Post gebeurtenis foto aantal moet een geldige waarde van nul of groter zijn', + 'BadPreEventCount' => 'Pre gebeurtenis aantal moe minimaal nul en lager dan de buffert grote', + 'BadRefBlendPerc' => 'Reference blend percentage moet een geldige waarde van nul of groter zijn', + 'BadSectionLength' => 'Selectie lengte moet een integer van 30 of meer zijn', + 'BadSignalCheckColour' => 'Signaal controle kleur moet een geldige RGB waarde zijn', + 'BadStreamReplayBuffer'=> 'Stream replay buffer moet een geldige waarde van nul of groter zijn', + 'BadWarmupCount' => 'Warmop frames moet een geldige waarde van nul of groter zijn', + 'BadWebColour' => 'Web kleur moeten een geldige webkleurwaarde bevatten', + 'BadWidth' => 'Breedte moet ingevuld worden', + 'Bandwidth' => 'Bandbreedte', + 'BandwidthHead' => 'Bandwidth', // This is the end of the bandwidth status on the top of the console, different in many language due to phrasing + 'BlobPx' => 'Blob px', + 'BlobSizes' => 'Blob grootte', + 'Blobs' => 'Blobs', + 'Brightness' => 'Helderheid', + 'Buffer' => 'Buffer', // Added - 2015-04-18 + 'Buffers' => 'Buffers', + 'CSSDescription' => 'Change the default css for this computer', // Added - 2015-04-18 + 'CanAutoFocus' => 'Can Auto Focus', + 'CanAutoGain' => 'Can Auto Gain', + 'CanAutoIris' => 'Can Auto Iris', + 'CanAutoWhite' => 'Can Auto White Bal.', + 'CanAutoZoom' => 'Can Auto Zoom', + 'CanFocus' => 'Can Focus', + 'CanFocusAbs' => 'Can Focus Absoluut', + 'CanFocusCon' => 'Can Focus Continue', + 'CanFocusRel' => 'Can Focus Relatief', + 'CanGain' => 'Can Gain ', + 'CanGainAbs' => 'Can Gain Absoluut', + 'CanGainCon' => 'Can Gain Continue', + 'CanGainRel' => 'Can Gain Relatief', + 'CanIris' => 'Can Iris', + 'CanIrisAbs' => 'Can Iris Absoluut', + 'CanIrisCon' => 'Can Iris Continue', + 'CanIrisRel' => 'Can Iris Relatief', + 'CanMove' => 'Can Move', + 'CanMoveAbs' => 'Can Move Absoluut', + 'CanMoveCon' => 'Can Move Continue', + 'CanMoveDiag' => 'Can Move Diagonaal', + 'CanMoveMap' => 'Can Move Mapped', + 'CanMoveRel' => 'Can Move Relatief', + 'CanPan' => 'Can Pan' , + 'CanReset' => 'Can Reset', + 'CanSetPresets' => 'Can Set Presets', + 'CanSleep' => 'Can Sleep', + 'CanTilt' => 'Can Tilt', + 'CanWake' => 'Can Wake', + 'CanWhite' => 'Can White Balance', + 'CanWhiteAbs' => 'Can White Bal. Absoluut', + 'CanWhiteBal' => 'Can White Bal.', + 'CanWhiteCon' => 'Can White Bal. Continue', + 'CanWhiteRel' => 'Can White Bal. Relatief', + 'CanZoom' => 'Can Zoom', + 'CanZoomAbs' => 'Can Zoom Absoluut', + 'CanZoomCon' => 'Can Zoom Continue', + 'CanZoomRel' => 'Can Zoom Relatief', + 'Cancel' => 'Afbreken', + 'CancelForcedAlarm' => 'Afbreken geforceerd alarm', + 'CaptureHeight' => 'Opname hoogte', + 'CaptureMethod' => 'Opname Methode', // Added - 2009-02-08 + 'CapturePalette' => 'Opname pallet', + 'CaptureResolution' => 'Capture Resolution', // Added - 2015-04-18 + 'CaptureWidth' => 'Opname breedte', + 'Cause' => 'Oorzaak', + 'CheckMethod' => 'Alarm controle Methode', + 'ChooseDetectedCamera' => 'Kies gedetecteerde Camera', // Added - 2009-03-31 + 'ChooseFilter' => 'Kies filter', + 'ChooseLogFormat' => 'Kies en log formaat', // Added - 2011-06-17 + 'ChooseLogSelection' => 'Kies een log selectie', // Added - 2011-06-17 + 'ChoosePreset' => 'Kies voorkeur', + 'Clear' => 'Leeg', // Added - 2011-06-16 + 'Close' => 'Sluit', + 'Colour' => 'Kleur', + 'Command' => 'Commando', + 'Component' => 'Component', // Added - 2011-06-16 + 'Config' => 'Configuratie', + 'ConfiguredFor' => 'Geconfigureerd voor', + 'ConfirmDeleteEvents' => 'Weet uw zeker dat uw deze gebeurtenissen wil verwijderen?', + 'ConfirmPassword' => 'Bevestig wachtwoord', + 'ConjAnd' => 'en', + 'ConjOr' => 'of', + 'Console' => 'Console', + 'ContactAdmin' => 'Neem A.U.B. contact op met uw beheerder voor details.', + 'Continue' => 'Continue', + 'Contrast' => 'Contrast', + 'Control' => 'Bestuur', + 'ControlAddress' => 'Bestuur adres', + 'ControlCap' => 'Bestuur mogelijkheid', + 'ControlCaps' => 'Bestuur mogelijkheden', + 'ControlDevice' => 'Bestuur apparaat', + 'ControlType' => 'Bestuur Type', + 'Controllable' => 'Bestuurbaar', + 'Current' => 'Current', // Added - 2015-04-18 + 'Cycle' => 'Cyclus', + 'CycleWatch' => 'Observeer cyclus', + 'DateTime' => 'Datum/Tijd', // Added - 2011-06-16 + 'Day' => 'Dag', + 'Debug' => 'Debug', + 'DefaultRate' => 'Standaard Radius', + 'DefaultScale' => 'Standaard Schaal', + 'DefaultView' => 'Standaard scherm', + 'Deinterlacing' => 'Deinterlacing', // Added - 2015-04-18 + 'Delay' => 'Delay', // Added - 2015-04-18 + 'Delete' => 'verwijder', + 'DeleteAndNext' => 'verwijder & volgende', + 'DeleteAndPrev' => 'verwijder & vorige', + 'DeleteSavedFilter' => 'verwijder opgeslagen filter', + 'Description' => 'Omschrijving', + 'DetectedCameras' => 'Gedetecteerde Cameras', // Added - 2009-03-31 + 'DetectedProfiles' => 'Detected Profiles', // Added - 2015-04-18 + 'Device' => 'Apparaat', // Added - 2009-02-08 + 'DeviceChannel' => 'Apparaat kanaal', + 'DeviceFormat' => 'Apparaat formaat', + 'DeviceNumber' => 'Apparaat nummer', + 'DevicePath' => 'Apparaat pad', + 'Devices' => 'Apparaten', + 'Dimensions' => 'Afmetingen', + 'DisableAlarms' => 'Alarmen uitschakelen', + 'Disk' => 'Schijf', + 'Display' => 'Weergave', // Added - 2011-01-30 + 'Displaying' => 'Weergaven', // Added - 2011-06-16 + 'DoNativeMotionDetection'=> 'Do Native Motion Detection', // Added - 2015-04-18 + 'Donate' => 'A.U.B geef ons een donatie', + 'DonateAlready' => 'Nee, ik heb al gedoneerd', + 'DonateEnticement' => 'U gebruikt Zoneminder nu voor een geruime tijd, hopelijk vindt je het een nuttige toevoeging voor u huis of werkplek beveiliging. Natuurlijk is en blijft Zoneminder gratis en open source software. Maar het kost geld om te ontwikkelen en support te onderhouden. Ik vraag u dan ook om er over na te denken om een donatie te doen om zo de ontwikkeling en support te ondersteunen. Natuurlijk bent u hier vrij in, en elke donatie hoe klein dan ook wordt erg gewaardeerd.

Als u wilt donderen geef dat hier onder dan aan of ga naar http://www.zoneminder.com/dontate.html in uw browser.

Bedankt voor het gebruiken van Zoneminder en vergeet niet om ons forum op ZoneMinder.com te bezoeken voor ondersteuning of suggesties waarmee u ZoneMinder beleving nog beter wordt.', + 'DonateRemindDay' => 'Nu niet, herinner mij over 1 dag hieraan', + 'DonateRemindHour' => 'Nu niet, herinner mij over een uur hieraan', + 'DonateRemindMonth' => 'Nu niet, herinner mij over een maand hieraan', + 'DonateRemindNever' => 'Nee, ik hiervoor wil niet doneren', + 'DonateRemindWeek' => 'Nu niet, herinner mij over een week hieraan', + 'DonateYes' => 'Ja, ik wil nu doneren', + 'Download' => 'Download', + 'DuplicateMonitorName' => 'Duplicaat Monitor Naam', // Added - 2009-03-31 + 'Duration' => 'Duur', + 'Edit' => 'Bewerk', + 'Email' => 'Email', + 'EnableAlarms' => 'Enable Alarms', + 'Enabled' => 'Ingeschakeld', + 'EnterNewFilterName' => 'Voer nieuwe filter naam in', + 'Error' => 'Fout', + 'ErrorBrackets' => 'Fout, controleer of je even veel openings als afsluiting brackets hebt gebruikt', + 'ErrorValidValue' => 'Fout, Controleer of alle termen een geldige waarde hebben', + 'Etc' => 'etc', + 'Event' => 'Gebeurtenis', + 'EventFilter' => 'Gebeurtenis filter', + 'EventId' => 'Gebeurtenis Id', + 'EventName' => 'Gebeurtenis Name', + 'EventPrefix' => 'Gebeurtenis Prefix', + 'Events' => 'Gebeurtenissen', + 'Exclude' => 'Sluit uit', + 'Execute' => 'Execute', + 'Export' => 'Exporteer', + 'ExportDetails' => 'Exporteer Gebeurtenis Details', + 'ExportFailed' => 'Exporteer gefaald', + 'ExportFormat' => 'Exporteer File Formaat', + 'ExportFormatTar' => 'Tar', + 'ExportFormatZip' => 'Zip', + 'ExportFrames' => 'Exporteer Frame Details', + 'ExportImageFiles' => 'Exporteer foto bestanden', + 'ExportLog' => 'Exporteer Log', // Added - 2011-06-17 + 'ExportMiscFiles' => 'Exporteer andere bestanden (wanneer aanwezig)', + 'ExportOptions' => 'Exporteer Opties', + 'ExportSucceeded' => 'Exporteren geslaagd', // Added - 2009-02-08 + 'ExportVideoFiles' => 'Exporteer Video bestanden (wanneer aanwezig)', + 'Exporting' => 'Exporteerd', + 'FPS' => 'fps', + 'FPSReportInterval' => 'FPS rapportage interval', + 'FTP' => 'FTP', + 'Far' => 'Far', + 'FastForward' => 'Snel vooruit', + 'Feed' => 'toevoer', + 'Ffmpeg' => 'Ffmpeg', // Added - 2009-02-08 + 'File' => 'Bestand', + 'Filter' => 'Filter', // Added - 2015-04-18 + 'FilterArchiveEvents' => 'Archiveer alle overeenkomsten', + 'FilterDeleteEvents' => 'Verwijder alle overeenkomsten', + 'FilterEmailEvents' => 'Email de details van alle overeenkomsten', + 'FilterExecuteEvents' => 'Voer opdrachten op alle overeenkomsten uit', + 'FilterLog' => 'Filter log', // Added - 2015-04-18 + 'FilterMessageEvents' => 'Bericht de details van alle overeenkomsten', + 'FilterPx' => 'Filter px', + 'FilterUnset' => 'Je moet de filter hoogte en breedte opgeven', + 'FilterUploadEvents' => 'Verstuur alle overeenkomsten', + 'FilterVideoEvents' => 'Maak video voor alle matches', + 'Filters' => 'Filters', + 'First' => 'Eerste', + 'FlippedHori' => 'Horizontaal gedraait', + 'FlippedVert' => 'Vertikaal gedraait', + 'FnMocord' => 'Mocord', // Added 2013.08.16. + 'FnModect' => 'Modect', // Added 2013.08.16. + 'FnMonitor' => 'Monitor', // Added 2013.08.16. + 'FnNodect' => 'Nodect', // Added 2013.08.16. + 'FnNone' => 'None', // Added 2013.08.16. + 'FnRecord' => 'Record', // Added 2013.08.16. + 'Focus' => 'Focus', + 'ForceAlarm' => 'Forceeer alarm', + 'Format' => 'Formaat', + 'Frame' => 'Frame', + 'FrameId' => 'Frame id', + 'FrameRate' => 'Frame rate', + 'FrameSkip' => 'Frame overgeslagen', + 'Frames' => 'Frames', + 'Func' => 'Func', + 'Function' => 'Functie', + 'Gain' => 'Gain', + 'General' => 'Generiek', + 'GenerateVideo' => 'Genereer Video', + 'GeneratingVideo' => 'Genereren Video', + 'GoToZoneMinder' => 'Ga naar ZoneMinder.com', + 'Grey' => 'Grijs', + 'Group' => 'Groep', + 'Groups' => 'Groepen', + 'HasFocusSpeed' => 'Heeft Focus Sneldheid', + 'HasGainSpeed' => 'Heeft Gain Snelheid', + 'HasHomePreset' => 'Heeft start Voorkeuren', + 'HasIrisSpeed' => 'Heeft Iris Snelheid', + 'HasPanSpeed' => 'Heeft Pan Snelheid', + 'HasPresets' => 'Heeft Voorkeuren', + 'HasTiltSpeed' => 'Heeft Tilt Snelheid', + 'HasTurboPan' => 'Heeft Turbo Pan', + 'HasTurboTilt' => 'Heeft Turbo Tilt', + 'HasWhiteSpeed' => 'Heeft White Bal. Snelheid', + 'HasZoomSpeed' => 'Heeft Zoom Snelheid', + 'High' => 'Hoog', + 'HighBW' => 'Hoog B/W', + 'Home' => 'Home', + 'Hour' => 'Uur', + 'Hue' => 'Hue', + 'Id' => 'Id', + 'Idle' => 'Ongebruikt', + 'Ignore' => 'Negeer', + 'Image' => 'Foto', + 'ImageBufferSize' => 'Foto buffer grootte (frames)', + 'Images' => 'Fotos', + 'In' => 'In', + 'Include' => 'voeg in', + 'Inverted' => 'Omgedraaid', + 'Iris' => 'Iris', + 'KeyString' => 'Sleutel waarde', + 'Label' => 'Label', + 'Language' => 'Taal', + 'Last' => 'Laatste', + 'Layout' => 'Layout', // Added - 2009-02-08 + 'Level' => 'Nivo', // Added - 2011-06-16 + 'Libvlc' => 'Libvlc', + 'LimitResultsPost' => 'resultaten;', // This is used at the end of the phrase 'Limit to first N results only' + 'LimitResultsPre' => 'beperk tot eerste', // This is used at the beginning of the phrase 'Limit to first N results only' + 'Line' => 'Lijn', // Added - 2011-06-16 + 'LinkedMonitors' => 'Gekoppelde monitoren', + 'List' => 'Lijst', + 'Load' => 'Belasting', + 'Local' => 'Lokaal', + 'Log' => 'Log', // Added - 2011-06-16 + 'LoggedInAs' => 'Aangemeld als', + 'Logging' => 'Logging', // Added - 2011-06-16 + 'LoggingIn' => 'Aanmelden..', + 'Login' => 'Aanmelden', + 'Logout' => 'Afmelden', + 'Logs' => 'Logs', // Added - 2011-06-17 + 'Low' => 'Laag', + 'LowBW' => 'Laag B/W', + 'Main' => 'Main', + 'Man' => 'Man', + 'Manual' => 'Handmatig', + 'Mark' => 'Markeer', + 'Max' => 'Max', + 'MaxBandwidth' => 'Max Bandbreedte', + 'MaxBrScore' => 'Max.
score', + 'MaxFocusRange' => 'Max Focus Bereik', + 'MaxFocusSpeed' => 'Max Focus Snelheid', + 'MaxFocusStep' => 'Max Focus Stap', + 'MaxGainRange' => 'Max Gain Bereik', + 'MaxGainSpeed' => 'Max Gain Snelheid', + 'MaxGainStep' => 'Max Gain Stap', + 'MaxIrisRange' => 'Max Iris Bereik', + 'MaxIrisSpeed' => 'Max Iris Snelheid', + 'MaxIrisStep' => 'Max Iris Stap', + 'MaxPanRange' => 'Max Pan Bereik', + 'MaxPanSpeed' => 'Max Pan Snelheid', + 'MaxPanStep' => 'Max Pan Stap', + 'MaxTiltRange' => 'Max Tilt Bereik', + 'MaxTiltSpeed' => 'Max Tilt Snelheid', + 'MaxTiltStep' => 'Max Tilt Stap', + 'MaxWhiteRange' => 'Max White Bal. Bereik', + 'MaxWhiteSpeed' => 'Max White Bal. Snelheid', + 'MaxWhiteStep' => 'Max White Bal. Stap', + 'MaxZoomRange' => 'Max Zoom Bereik', + 'MaxZoomSpeed' => 'Max Zoom Snelheid', + 'MaxZoomStep' => 'Max Zoom Stap', + 'MaximumFPS' => 'Maximum FPS', + 'Medium' => 'Medium', + 'MediumBW' => 'Medium B/W', + 'Message' => 'Message', // Added - 2011-06-16 + 'MinAlarmAreaLtMax' => 'Minimum alarm moet kleiner dan het maximum', + 'MinAlarmAreaUnset' => 'Specificeer het minimaal aantal alarm pixels', + 'MinBlobAreaLtMax' => 'minimum blob gebied moet kleiner zijn dan maximum blob gebied', + 'MinBlobAreaUnset' => 'Specificeer het minimaal aantal blob pixels', + 'MinBlobLtMinFilter' => 'Minimum blob gebied moet kleiner of gelijk aan het minimale filter gebied zijn', + 'MinBlobsLtMax' => 'Minimum blobs moet kleiner zijn dan maximum blobs', + 'MinBlobsUnset' => 'Specificeer het minimaal blob aantal', + 'MinFilterAreaLtMax' => 'Minimum filter gebied moet minder dan het maximum zijn', + 'MinFilterAreaUnset' => 'Specificeer het minimaal aantal filter pixels', + 'MinFilterLtMinAlarm' => 'Minimum filter gebied moet kleiner of gelijk aan het minimale alarm gebied zijn', + 'MinFocusRange' => 'Min Focus Bereik', + 'MinFocusSpeed' => 'Min Focus Snelheid', + 'MinFocusStep' => 'Min Focus Step', + 'MinGainRange' => 'Min Gain Bereik', + 'MinGainSpeed' => 'Min Gain Snelheid', + 'MinGainStep' => 'Min Gain Step', + 'MinIrisRange' => 'Min Iris Bereik', + 'MinIrisSpeed' => 'Min Iris Snelheid', + 'MinIrisStep' => 'Min Iris Step', + 'MinPanRange' => 'Min Draai Bereik', + 'MinPanSpeed' => 'Min Draai Snelheid', + 'MinPanStep' => 'Min Draai Step', + 'MinPixelThresLtMax' => 'Minimum pixel kleurdiepte moet kleiner zijn dan maximum pixel bereikwaarde', + 'MinPixelThresUnset' => 'Specificeer een minimale pixel bereikwaarde', + 'MinTiltRange' => 'Min Tilt Bereik', + 'MinTiltSpeed' => 'Min Tilt Snelheid', + 'MinTiltStep' => 'Min Tilt Step', + 'MinWhiteRange' => 'Min White Bal. Bereik', + 'MinWhiteSpeed' => 'Min White Bal. Snelheid', + 'MinWhiteStep' => 'Min White Bal. Step', + 'MinZoomRange' => 'Min Zoom Bereik', + 'MinZoomSpeed' => 'Min Zoom Snelheid', + 'MinZoomStep' => 'Min Zoom Step', + 'Misc' => 'Misc', + 'Mode' => 'Mode', // Added - 2015-04-18 + 'Monitor' => 'Monitor', + 'MonitorIds' => 'Monitor Ids', + 'MonitorPreset' => 'Monitor Preset', + 'MonitorPresetIntro' => 'Selecteer een preset uit de lijst.

let op dit overschrijft de reeds ingevoerde waarden voor deze monitor!

', + 'MonitorProbe' => 'Monitor Probe', // Added - 2009-03-31 + 'MonitorProbeIntro' => 'Deze lijst toont gedeteerde analoge en netwerk cameras en of deze al ingebruik of beschikbaar zijn.

Selecteer de gewenste waarde uit de lijst hier beneden.

Let er op dat het mogelijk is dat niet alle cameras hier worden weer gegeven, en dat alle ingevoerde waarden voor de huidige monitor worden overschreven.

', // Added - 2009-03-31 + 'Monitors' => 'Monitoren', + 'Montage' => 'Montage', + 'Month' => 'Maand', + 'More' => 'Meer', // Added - 2011-06-16 + 'MotionFrameSkip' => 'Motion Frame Skip', + 'Move' => 'Verplaats', + 'Mtg2widgrd' => '2-wide grid', // Added 2013.08.15. + 'Mtg3widgrd' => '3-wide grid', // Added 2013.08.15. + 'Mtg3widgrx' => '3-wide grid, scaled, enlarge on alarm', // Added 2013.08.15. + 'Mtg4widgrd' => '4-wide grid', // Added 2013.08.15. + 'MtgDefault' => 'Default', // Added 2013.08.15. + 'MustBeGe' => 'Moet groter zijn of gelijk aan', + 'MustBeLe' => 'Moet kleiner zijn of gelijk aan', + 'MustConfirmPassword' => 'Je moet je wachtwoord bevestigen', + 'MustSupplyPassword' => 'Je moet een wachtwoord geven', + 'MustSupplyUsername' => 'Je moet een gebruikersnaam geven', + 'Name' => 'Naam', + 'Near' => 'Dichtbij', + 'Network' => 'Netwerk', + 'New' => 'Nieuw', + 'NewGroup' => 'Niew Groep', + 'NewLabel' => 'Niew Label', + 'NewPassword' => 'Nieuw wachtwoord', + 'NewState' => 'Nieuwe status', + 'NewUser' => 'Nieuwe gebruiker', + 'Next' => 'Volgende', + 'No' => 'Nee', + 'NoDetectedCameras' => 'Geen cameras gedeteceerd', // Added - 2009-03-31 + 'NoFramesRecorded' => 'Er zijn geen frames opgenomen voor deze gebeurtenis', + 'NoGroup' => 'Geeb Groep', + 'NoSavedFilters' => 'Geen Opgeslagen Filters', + 'NoStatisticsRecorded' => 'Er zijn geen statistieken opgenomen voor deze gebeurenis', + 'None' => 'Geen', + 'NoneAvailable' => 'Geen beschikbaar', + 'Normal' => 'Normaal', + 'Notes' => 'Notities', + 'NumPresets' => 'Num Voorkeuren', + 'Off' => 'Uit', + 'On' => 'Aan', + 'OnvifCredentialsIntro'=> 'Please supply user name and password for the selected camera.
If no user has been created for the camera then the user given here will be created with the given password.

', // Added - 2015-04-18 + 'OnvifProbe' => 'ONVIF', // Added - 2015-04-18 + 'OnvifProbeIntro' => 'The list below shows detected ONVIF cameras and whether they are already being used or available for selection.

Select the desired entry from the list below.

Please note that not all cameras may be detected and that choosing a camera here may overwrite any values you already have configured for the current monitor.

', // Added - 2015-04-18 + 'OpEq' => 'gelijk aan', + 'OpGt' => 'groter dan', + 'OpGtEq' => 'groter dan of gelijk aan', + 'OpIn' => 'in set', + 'OpLt' => 'kleiner dan', + 'OpLtEq' => 'kleiner dan of gelijk aan', + 'OpMatches' => 'Komt overeen', + 'OpNe' => 'niet gelijk aan', + 'OpNotIn' => 'niet in set', + 'OpNotMatches' => 'Komt niet overeen', + 'Open' => 'Open', + 'OptionHelp' => 'OptieHelp', + 'OptionRestartWarning' => 'Deze veranderingen passen niet aan\nals het systeem loopt. Als je\nKlaar bent met veranderen vergeet dan niet dat\nje ZoneMinder herstart.', + 'Options' => 'Opties', + 'OrEnterNewName' => 'of voer een nieuwe naam in', + 'Order' => 'Sorteer', + 'Orientation' => 'Orientatie', + 'Out' => 'Uit', + 'OverwriteExisting' => 'Overschrijf bestaande', + 'Paged' => 'Paged', + 'Pan' => 'Pan', + 'PanLeft' => 'Pan Links', + 'PanRight' => 'Pan Rechts', + 'PanTilt' => 'Pan/Tilt', + 'Parameter' => 'Parameter', + 'Password' => 'Wachtwoord', + 'PasswordsDifferent' => 'Het nieuwe en bevestigde wachtwoord zijn verschillend', + 'Paths' => 'Paden', + 'Pause' => 'Pause', + 'Phone' => 'Telefoon', + 'PhoneBW' => 'Telefoon B/W', + 'Pid' => 'PID', // Added - 2011-06-16 + 'PixelDiff' => 'Pixel Diff', + 'Pixels' => 'pixels', + 'Play' => 'Speel', + 'PlayAll' => 'Speel Alles', + 'PleaseWait' => 'Wacht A.U.B.', + 'Plugins' => 'Plugins', // Added - 2015-04-18 + 'Point' => 'Punt', + 'PostEventImageBuffer' => 'Post gebeurtenis foto Buffer', + 'PreEventImageBuffer' => 'Pre gebeurtenis foto Buffer', + 'PreserveAspect' => 'Beeld verhouding bewaren', + 'Preset' => 'Voorkeur', + 'Presets' => 'Voorkeuren', + 'Prev' => 'Vorige', + 'Probe' => 'Scan', // Added - 2009-03-31 + 'ProfileProbe' => 'Stream Probe', // Added - 2015-04-18 + 'ProfileProbeIntro' => 'The list below shows the existing stream profiles of the selected camera .

Select the desired entry from the list below.

Please note that ZoneMinder cannot configure additional profiles and that choosing a camera here may overwrite any values you already have configured for the current monitor.

', // Added - 2015-04-18 + 'Progress' => 'Progress', // Added - 2015-04-18 + 'Protocol' => 'Protocol', + 'Rate' => 'Waardering', + 'Real' => 'Echte', + 'Record' => 'Record', + 'RefImageBlendPct' => 'Referentie foto Blend %ge', + 'Refresh' => 'Ververs', + 'Remote' => 'Remote', + 'RemoteHostName' => 'Remote Host Naam', + 'RemoteHostPath' => 'Remote Host Pad', + 'RemoteHostPort' => 'Remote Host Poort', + 'RemoteHostSubPath' => 'Remote Host SubPad', // Added - 2009-02-08 + 'RemoteImageColours' => 'Remote foto kleuren', + 'RemoteMethod' => 'Remote Methode', // Added - 2009-02-08 + 'RemoteProtocol' => 'Remote Protocol', // Added - 2009-02-08 + 'Rename' => 'Hernoem', + 'Replay' => 'Opnieuw', + 'ReplayAll' => 'Alle Gebeurtenissen', + 'ReplayGapless' => 'Opvolgende Gebeurtenissen', + 'ReplaySingle' => 'Enkele Gebeurtenis', + 'Reset' => 'Herstel', + 'ResetEventCounts' => 'Herstel gebeurtenis teller', + 'Restart' => 'Herstart', + 'Restarting' => 'Herstarten', + 'RestrictedCameraIds' => 'Verboden Camera Ids', + 'RestrictedMonitors' => 'Beperkte Monitoren', + 'ReturnDelay' => 'Return Delay', + 'ReturnLocation' => 'Return Locatie', + 'Rewind' => 'Rewind', + 'RotateLeft' => 'Draai linksom', + 'RotateRight' => 'Draai rechtsom', + 'RunLocalUpdate' => 'Gebruik zmupdate.pl om up te daten', // Added - 2011-05-25 + 'RunMode' => 'Draai Modus', + 'RunState' => 'Draai Status', + 'Running' => 'Werkend', + 'Save' => 'Opslaan', + 'SaveAs' => 'Opslaan als', + 'SaveFilter' => 'Opslaan Filter', + 'Scale' => 'Schaal', + 'Score' => 'Score', + 'Secs' => 'Secs', + 'Sectionlength' => 'Sectie lengte', + 'Select' => 'Selecteer', + 'SelectFormat' => 'Selecteer Formaat', // Added - 2011-06-17 + 'SelectLog' => 'Selecteer Log', // Added - 2011-06-17 + 'SelectMonitors' => 'Selecteer Monitoren', + 'SelfIntersecting' => 'Polygon randen moeten niet overlappen', + 'Set' => 'Zet', + 'SetNewBandwidth' => 'Zet Nieuwe Bandbreedte', + 'SetPreset' => 'Zet Preset', + 'Settings' => 'Instellingen', + 'ShowFilterWindow' => 'Toon Filter Venster', + 'ShowTimeline' => 'Toon Tijdslijn', + 'SignalCheckColour' => 'Signaal controle kleur', + 'Size' => 'Groote', + 'SkinDescription' => 'Wijzig standaard uiterlijk voor deze computer', // Added - 2011-01-30 + 'Sleep' => 'Slaap', + 'SortAsc' => 'Opl.', + 'SortBy' => 'Sorteer op', + 'SortDesc' => 'Afl.', + 'Source' => 'Bron', + 'SourceColours' => 'Bron Colours', // Added - 2009-02-08 + 'SourcePath' => 'Bron Path', // Added - 2009-02-08 + 'SourceType' => 'Bron Type', + 'Speed' => 'Snelheid', + 'SpeedHigh' => 'Hoge Snelheid', + 'SpeedLow' => 'Lage Snelheid', + 'SpeedMedium' => 'Medium Snelheid', + 'SpeedTurbo' => 'Turbo Snelheid', + 'Start' => 'Start', + 'State' => 'Status', + 'Stats' => 'Stats', + 'Status' => 'Status', + 'Step' => 'Stap', + 'StepBack' => 'Stap Terug', + 'StepForward' => 'Stap Vooruit', + 'StepLarge' => 'Groten stap', + 'StepMedium' => 'Medium Stap', + 'StepNone' => 'Geen Stap', + 'StepSmall' => 'Smalle Stap', + 'Stills' => 'Plaatjes', + 'Stop' => 'Stop', + 'Stopped' => 'Gestopt', + 'Stream' => 'Stream', + 'StreamReplayBuffer' => 'Stream Replay foto Buffer', + 'Submit' => 'Verzenden', + 'System' => 'Systeem', + 'SystemLog' => 'Systeem Log', // Added - 2011-06-16 + 'TargetColorspace' => 'Target colorspace', // Added - 2015-04-18 + 'Tele' => 'Tele', + 'Thumbnail' => 'Thumbnail', + 'Tilt' => 'Tilt', + 'Time' => 'Tijd', + 'TimeDelta' => 'Tijd Delta', + 'TimeStamp' => 'Tijdstempel', + 'Timeline' => 'Tijdslijn', + 'TimelineTip1' => 'Pass your mouse over the graph to view a snapshot image and event details.', // Added 2013.08.15. + 'TimelineTip2' => 'Click on the coloured sections of the graph, or the image, to view the event.', // Added 2013.08.15. + 'TimelineTip3' => 'Click on the background to zoom in to a smaller time period based around your click.', // Added 2013.08.15. + 'TimelineTip4' => 'Use the controls below to zoom out or navigate back and forward through the time range.', // Added 2013.08.15. + 'Timestamp' => 'Tijdstempel', + 'TimestampLabelFormat' => 'Tijdstempel Label Format', + 'TimestampLabelX' => 'Tijdstempel Label X', + 'TimestampLabelY' => 'Tijdstempel Label Y', + 'Today' => 'Vandaag', + 'Tools' => 'Gereedschappen', + 'Total' => 'Totaal', // Added - 2011-06-16 + 'TotalBrScore' => 'Totaal
Score', + 'TrackDelay' => 'Track Vertraging', + 'TrackMotion' => 'Track Beweging', + 'Triggers' => 'Triggers', + 'TurboPanSpeed' => 'Turbo Pan Snelheid', + 'TurboTiltSpeed' => 'Turbo Tilt Snelheid', + 'Type' => 'Type', + 'Unarchive' => 'Dearchiveer', + 'Undefined' => 'Ongedefineerd', // Added - 2009-02-08 + 'Units' => 'Eenheden', + 'Unknown' => 'Onbekend', + 'Update' => 'Ververs', + 'UpdateAvailable' => 'Een update voor ZoneMinder is beschikbaar', + 'UpdateNotNecessary' => 'Geen update noodzakelijk', + 'Updated' => 'Ververst', // Added - 2011-06-16 + 'Upload' => 'Upload', // Added - 2015-04-18 + 'UseFilter' => 'Gebruik Filter', + 'UseFilterExprsPost' => ' filter expressies', // This is used at the end of the phrase 'use N filter expressions' + 'UseFilterExprsPre' => 'Gebruik ', // This is used at the beginning of the phrase 'use N filter expressions' + 'UsedPlugins' => 'Used Plugins', // Added - 2015-04-18 + 'User' => 'Gebruiker', + 'Username' => 'Gebruikersnaam', + 'Users' => 'Gebruikers', + 'V4L' => 'V4L', // Added - 2015-04-18 + 'V4LCapturesPerFrame' => 'Captures Per Frame', // Added - 2015-04-18 + 'V4LMultiBuffer' => 'Multi Buffering', // Added - 2015-04-18 + 'Value' => 'Waarde', + 'Version' => 'Versie', + 'VersionIgnore' => 'Negeer deze versie', + 'VersionRemindDay' => 'Herinner mij na 1 dag', + 'VersionRemindHour' => 'Herinner mij na 1 uur', + 'VersionRemindNever' => 'Herinner mij niet aan nieuwe versies', + 'VersionRemindWeek' => 'Herinner mij na 1 week', + 'Video' => 'Video', + 'VideoFormat' => 'Video Formaat', + 'VideoGenFailed' => 'Video Generatie mislukt!', + 'VideoGenFiles' => 'Bestaande video bestanden', + 'VideoGenNoFiles' => 'Geen video bestanden gevonden', + 'VideoGenParms' => 'Video Generatie Parameters', + 'VideoGenSucceeded' => 'Video Generatie voltooid!', + 'VideoSize' => 'Video grootte', + 'View' => 'Bekijk', + 'ViewAll' => 'Bekijk Alles', + 'ViewEvent' => 'Bekijk Gebeurtenis', + 'ViewPaged' => 'Bekijk Pagina', + 'Wake' => 'Wakker', + 'WarmupFrames' => 'Warmop Frames', + 'Watch' => 'Observeer', + 'Web' => 'Web', + 'WebColour' => 'Web Kleur', + 'Week' => 'Week', + 'White' => 'Wit', + 'WhiteBalance' => 'Wit Balance', + 'Wide' => 'Wijd', + 'X' => 'X', + 'X10' => 'X10', + 'X10ActivationString' => 'X10 Activatie Waarde', + 'X10InputAlarmString' => 'X10 Input Alarm Waarde', + 'X10OutputAlarmString' => 'X10 Output Alarm Waarde', + 'Y' => 'Y', + 'Yes' => 'Ja', + 'YouNoPerms' => 'U heeft niet de rechten om toegang te krijgen tot deze bronnen.', + 'Zone' => 'Zone', + 'ZoneAlarmColour' => 'Alarm Kleur (Rood/Groen/Blauw)', + 'ZoneArea' => 'Zone Gebied', + 'ZoneExtendAlarmFrames' => 'Extend Alarm Frame Count', + 'ZoneFilterSize' => 'Filter Hoogte/Breedte (pixels)', + 'ZoneMinMaxAlarmArea' => 'Min/Max Alarmeer Gebied', + 'ZoneMinMaxBlobArea' => 'Min/Max Blob Gebied', + 'ZoneMinMaxBlobs' => 'Min/Max Blobs', + 'ZoneMinMaxFiltArea' => 'Min/Max Gefilterd Gebied', + 'ZoneMinMaxPixelThres' => 'Min/Max Pixel Threshold (0-255)', + 'ZoneMinderLog' => 'ZoneMinder Log', // Added - 2011-06-17 + 'ZoneOverloadFrames' => 'Overload Frame negeer aantal', + 'Zones' => 'Zones', + 'Zoom' => 'Zoom', + 'ZoomIn' => 'Zoom In', + 'ZoomOut' => 'Zoom Uit', +); + +// Complex replacements with formatting and/or placements, must be passed through sprintf +$CLANG = array( + 'CurrentLogin' => 'huidige login is \'%1$s\'', + 'EventCount' => '%1$s %2$s', // Als voorbeeld '37 gebeurtenissen' (from Vlang below) + 'LastEvents' => 'Last %1$s %2$s', // Als voorbeeld 'Laatste 37 gebeurtenissen' (from Vlang below) + 'LatestRelease' => 'de laatste release is v%1$s, jij hebt v%2$s.', + 'MonitorCount' => '%1$s %2$s', // Als voorbeeld '4 Monitoren' (from Vlang below) + 'MonitorFunction' => 'Monitor %1$s Functie', + 'RunningRecentVer' => 'U draait al met de laatste versie van ZoneMinder, v%s.', + 'VersionMismatch' => 'Versie verschil, systeem is versie %1$s, database is %2$s.', // Added - 2011-05-25 +); + +// The next section allows you to describe a series of word ending and counts used to +// generate the correctly conjugated forms of words depending on a count that is associated +// with that word. +// This intended to allow phrases such a '0 potatoes', '1 potato', '2 potatoes' etc to +// conjugate correctly with the associated count. +// In some languages such as English this is fairly simple and can be expressed by assigning +// a count with a singular or plural form of a word and then finding the nearest (lower) value. +// So '0' of something generally ends in 's', 1 of something is singular and has no extra +// ending and 2 or more is a plural and ends in 's' also. So to find the ending for '187' of +// something you would find the nearest lower count (2) and use that ending. +// +// So examples of this would be +// $zmVlangPotato = array( 0=>'Potatoes', 1=>'Potato', 2=>'Potatoes' ); +// $zmVlangSheep = array( 0=>'Sheep' ); +// +// where you can have as few or as many entries in the array as necessary +// If your language is similar in form to this then use the same format and choose the +// appropriate zmVlang function below. +// If however you have a language with a different format of plural endings then another +// approach is required . For instance in Russian the word endings change continuously +// depending on the last digit (or digits) of the numerator. In this case then zmVlang +// arrays could be written so that the array index just represents an arbitrary 'type' +// and the zmVlang function does the calculation about which version is appropriate. +// +// So an example in Russian might be (using English words, and made up endings as I +// don't know any Russian!!) +// $zmVlangPotato = array( 1=>'Potati', 2=>'Potaton', 3=>'Potaten' ); +// +// and the zmVlang function decides that the first form is used for counts ending in +// 0, 5-9 or 11-19 and the second form when ending in 1 etc. +// + +// Variable arrays expressing plurality, see the zmVlang description above +$VLANG = array( + 'Event' => array( 0=>'gebeurtenissen', 1=>'gebeurtenis', 2=>'gebeurtenissen' ), + 'Monitor' => array( 0=>'Monitoren', 1=>'Monitor', 2=>'Monitoren' ), +); + +// You will need to choose or write a function that can correlate the plurality string arrays +// with variable counts. This is used to conjugate the Vlang arrays above with a number passed +// in to generate the correct noun form. +// +// In languages such as English this is fairly simple +// Note this still has to be used with printf etc to get the right formating +function zmVlang( $langVarArray, $count ) +{ + krsort( $langVarArray ); + foreach ( $langVarArray as $key=>$value ) + { + if ( abs($count) >= $key ) + { + return( $value ); + } + } + die( 'Error, unable to correlate variable language string' ); +} + +// This is an version that could be used in the Russian example above +// The rules are that the first word form is used if the count ends in +// 0, 5-9 or 11-19. The second form is used then the count ends in 1 +// (not including 11 as above) and the third form is used when the +// count ends in 2-4, again excluding any values ending in 12-14. +// +// function zmVlang( $langVarArray, $count ) +// { +// $secondlastdigit = substr( $count, -2, 1 ); +// $lastdigit = substr( $count, -1, 1 ); +// // or +// // $secondlastdigit = ($count/10)%10; +// // $lastdigit = $count%10; +// +// // Get rid of the special cases first, the teens +// if ( $secondlastdigit == 1 && $lastdigit != 0 ) +// { +// return( $langVarArray[1] ); +// } +// switch ( $lastdigit ) +// { +// case 0 : +// case 5 : +// case 6 : +// case 7 : +// case 8 : +// case 9 : +// { +// return( $langVarArray[1] ); +// break; +// } +// case 1 : +// { +// return( $langVarArray[2] ); +// break; +// } +// case 2 : +// case 3 : +// case 4 : +// { +// return( $langVarArray[3] ); +// break; +// } +// } +// die( 'Error, unable to correlate variable language string' ); +// } + +// This is an example of how the function is used in the code which you can uncomment and +// use to test your custom function. +//$monitors = array(); +//$monitors[] = 1; // Choose any number +//echo sprintf( $zmClangMonitorCount, count($monitors), zmVlang( $zmVlangMonitor, count($monitors) ) ); + +// In this section you can override the default prompt and help texts for the options area +// These overrides are in the form show below where the array key represents the option name minus the initial ZM_ +// So for example, to override the help text for ZM_LANG_DEFAULT do +$OLANG = array( + 'OPTIONS_FFMPEG' => array( + 'Help' => "Parameters in this field are passwd on to FFmpeg. Multiple parameters can be separated by ,~~ ". + "Examples (do not enter quotes)~~~~". + "\"allowed_media_types=video\" Set datatype to request fromcam (audio, video, data)~~~~". + "\"reorder_queue_size=nnn\" Set number of packets to buffer for handling of reordered packets~~~~". + "\"loglevel=debug\" Set verbosiy of FFmpeg (quiet, panic, fatal, error, warning, info, verbose, debug)" + ), + 'OPTIONS_LIBVLC' => array( + 'Help' => "Parameters in this field are passwd on to libVLC. Multiple parameters can be separated by ,~~ ". + "Examples (do not enter quotes)~~~~". + "\"--rtp-client-port=nnn\" Set local port to use for rtp data~~~~". + "\"--verbose=2\" Set verbosity of libVLC" + ), + +// 'LANG_DEFAULT' => array( +// 'Prompt' => "This is a new prompt for this option", +// 'Help' => "This is some new help for this option which will be displayed in the popup window when the ? is clicked" +// ), +); + +?> diff --git a/web/lang/pl_pl.php b/web/lang/pl_pl.php index 9ba171fcb..71c4bbac6 100644 --- a/web/lang/pl_pl.php +++ b/web/lang/pl_pl.php @@ -88,6 +88,7 @@ $SLANG = array( 'AlarmMaximumFPS' => 'Alarm Maximum FPS', 'AlarmPx' => 'Alarm Px', 'AlarmRGBUnset' => 'You must set an alarm RGB colour', + 'AlarmRefImageBlendPct'=> 'Alarm Reference Image Blend %ge', // Added - 2015-04-18 'Alert' => 'Gotowosc', 'All' => 'Wszystko', 'Apply' => 'Zastosuj', @@ -132,13 +133,13 @@ $SLANG = array( 'BadFPSReportInterval' => 'FPS report interval buffer count must be an integer of 0 or more', 'BadFormat' => 'Format must be set to an integer of zero or more', 'BadFrameSkip' => 'Frame skip count must be an integer of zero or more', - 'BadMotionFrameSkip' => 'Motion Frame skip count must be an integer of zero or more', 'BadHeight' => 'Height must be set to a valid value', 'BadHost' => 'Host must be set to a valid ip address or hostname, do not include http://', 'BadImageBufferCount' => 'Image buffer size must be an integer of 10 or more', 'BadLabelX' => 'Label X co-ordinate must be set to an integer of zero or more', 'BadLabelY' => 'Label Y co-ordinate must be set to an integer of zero or more', 'BadMaxFPS' => 'Maximum FPS must be a positive integer or floating point value', + 'BadMotionFrameSkip' => 'Motion Frame skip count must be an integer of zero or more', 'BadNameChars' => 'Nazwy mog zawiera tylko litery, cyfry oraz mylnik i podkrelenie', 'BadPalette' => 'Palette must be set to a valid value', // Added - 2009-03-31 'BadPath' => 'Path must be set to a valid value', @@ -158,7 +159,9 @@ $SLANG = array( 'BlobSizes' => 'Rozmiary plamek', 'Blobs' => 'Plamki', 'Brightness' => 'Jaskrawo', + 'Buffer' => 'Buffer', // Added - 2015-04-18 'Buffers' => 'Bufory', + 'CSSDescription' => 'Change the default css for this computer', // Added - 2015-04-18 'CanAutoFocus' => 'Can Auto Focus', 'CanAutoGain' => 'Can Auto Gain', 'CanAutoIris' => 'Can Auto Iris', @@ -202,6 +205,7 @@ $SLANG = array( 'CaptureHeight' => 'Wysoko obrazu', 'CaptureMethod' => 'Capture Method', // Added - 2009-02-08 'CapturePalette' => 'Paleta kolorw obrazu', + 'CaptureResolution' => 'Capture Resolution', // Added - 2015-04-18 'CaptureWidth' => 'Szeroko obrazu', 'Cause' => 'Cause', 'CheckMethod' => 'Metoda sprawdzenia alarmu', @@ -232,6 +236,7 @@ $SLANG = array( 'ControlDevice' => 'Control Device', 'ControlType' => 'Control Type', 'Controllable' => 'Controllable', + 'Current' => 'Current', // Added - 2015-04-18 'Cycle' => 'Cycle', 'CycleWatch' => 'Cykl podgldu', 'DateTime' => 'Date/Time', // Added - 2011-06-16 @@ -240,12 +245,15 @@ $SLANG = array( 'DefaultRate' => 'Default Rate', 'DefaultScale' => 'Default Scale', 'DefaultView' => 'Default View', + 'Deinterlacing' => 'Deinterlacing', // Added - 2015-04-18 + 'Delay' => 'Delay', // Added - 2015-04-18 'Delete' => 'Usu', 'DeleteAndNext' => 'Usu & nastpny', 'DeleteAndPrev' => 'Usu & poprzedni', 'DeleteSavedFilter' => 'Usu zapisany filtr', 'Description' => 'Opis', 'DetectedCameras' => 'Detected Cameras', // Added - 2009-03-31 + 'DetectedProfiles' => 'Detected Profiles', // Added - 2015-04-18 'Device' => 'Device', // Added - 2009-02-08 'DeviceChannel' => 'Numer wejcia w urzdzeniu', 'DeviceFormat' => 'System TV', @@ -257,6 +265,7 @@ $SLANG = array( 'Disk' => 'Dysk', 'Display' => 'Display', // Added - 2011-01-30 'Displaying' => 'Displaying', // Added - 2011-06-16 + 'DoNativeMotionDetection'=> 'Do Native Motion Detection', 'Donate' => 'Please Donate', 'DonateAlready' => 'No, I\'ve already donated', 'DonateEnticement' => 'You\'ve been running ZoneMinder for a while now and hopefully are finding it a useful addition to your home or workplace security. Although ZoneMinder is, and will remain, free and open source, it costs money to develop and support. If you would like to help support future development and new features then please consider donating. Donating is, of course, optional but very much appreciated and you can donate as much or as little as you like.

If you would like to donate please select the option below or go to http://www.zoneminder.com/donate.html in your browser.

Thank you for using ZoneMinder and don\'t forget to visit the forums on ZoneMinder.com for support or suggestions about how to make your ZoneMinder experience even better.', @@ -266,7 +275,6 @@ $SLANG = array( 'DonateRemindNever' => 'No, I don\'t want to donate, never remind', 'DonateRemindWeek' => 'Not yet, remind again in 1 week', 'DonateYes' => 'Yes, I\'d like to donate now', - 'DoNativeMotionDetection'=> 'Do Native Motion Detection', 'Download' => 'Download', 'DuplicateMonitorName' => 'Duplicate Monitor Name', // Added - 2009-03-31 'Duration' => 'Czas trwania', @@ -309,10 +317,12 @@ $SLANG = array( 'Feed' => 'Dostarcz', 'Ffmpeg' => 'Ffmpeg', // Added - 2009-02-08 'File' => 'File', + 'Filter' => 'Filter', // Added - 2015-04-18 'FilterArchiveEvents' => 'Archiwizuj wszystkie pasujce', 'FilterDeleteEvents' => 'Usuwaj wszystkie pasujce', 'FilterEmailEvents' => 'Wysyaj poczt wszystkie pasujce', 'FilterExecuteEvents' => 'Wywouj komend na wszystkie pasujce', + 'FilterLog' => 'Filter log', // Added - 2015-04-18 'FilterMessageEvents' => 'Wywietlaj komunikat na wszystkie pasujce', 'FilterPx' => 'Filtr Px', 'FilterUnset' => 'You must specify a filter width and height', @@ -322,12 +332,12 @@ $SLANG = array( 'First' => 'Pierwszy', 'FlippedHori' => 'Flipped Horizontally', 'FlippedVert' => 'Flipped Vertically', - 'FnNone' => 'None', // Added 2013.08.16. - 'FnMonitor' => 'Monitor', // Added 2013.08.16. - 'FnModect' => 'Modect', // Added 2013.08.16. - 'FnRecord' => 'Record', // Added 2013.08.16. 'FnMocord' => 'Mocord', // Added 2013.08.16. + 'FnModect' => 'Modect', // Added 2013.08.16. + 'FnMonitor' => 'Monitor', // Added 2013.08.16. 'FnNodect' => 'Nodect', // Added 2013.08.16. + 'FnNone' => 'None', // Added 2013.08.16. + 'FnRecord' => 'Record', // Added 2013.08.16. 'Focus' => 'Focus', 'ForceAlarm' => 'Wymu alarm', 'Format' => 'Format', @@ -335,7 +345,6 @@ $SLANG = array( 'FrameId' => 'Nr ramki', 'FrameRate' => 'Tempo ramek', 'FrameSkip' => 'Pomi ramk', - 'MotionFrameSkip' => 'Motion Frame Skip', 'Frames' => 'Ramek', 'Func' => 'Funkcja', 'Function' => 'Funkcja', @@ -462,6 +471,7 @@ $SLANG = array( 'MinZoomSpeed' => 'Min Zoom Speed', 'MinZoomStep' => 'Min Zoom Step', 'Misc' => 'Inne', + 'Mode' => 'Mode', // Added - 2015-04-18 'Monitor' => 'Monitor', 'MonitorIds' => 'Numery monitorw', 'MonitorPreset' => 'Monitor Preset', @@ -472,12 +482,13 @@ $SLANG = array( 'Montage' => 'Monta', 'Month' => 'Miesic', 'More' => 'More', // Added - 2011-06-16 + 'MotionFrameSkip' => 'Motion Frame Skip', 'Move' => 'Move', - 'MtgDefault' => 'Default', // Added 2013.08.15. 'Mtg2widgrd' => '2-wide grid', // Added 2013.08.15. 'Mtg3widgrd' => '3-wide grid', // Added 2013.08.15. - 'Mtg4widgrd' => '4-wide grid', // Added 2013.08.15. 'Mtg3widgrx' => '3-wide grid, scaled, enlarge on alarm', // Added 2013.08.15. + 'Mtg4widgrd' => '4-wide grid', // Added 2013.08.15. + 'MtgDefault' => 'Default', // Added 2013.08.15. 'MustBeGe' => 'musi by wiksze lub rwne od', 'MustBeLe' => 'musi by mniejsze lub rwne od', 'MustConfirmPassword' => 'Musisz potwierdzi haso', @@ -506,6 +517,9 @@ $SLANG = array( 'NumPresets' => 'Num Presets', 'Off' => 'Off', 'On' => 'On', + 'OnvifCredentialsIntro'=> 'Please supply user name and password for the selected camera.
If no user has been created for the camera then the user given here will be created with the given password.

', // Added - 2015-04-18 + 'OnvifProbe' => 'ONVIF', // Added - 2015-04-18 + 'OnvifProbeIntro' => 'The list below shows detected ONVIF cameras and whether they are already being used or available for selection.

Select the desired entry from the list below.

Please note that not all cameras may be detected and that choosing a camera here may overwrite any values you already have configured for the current monitor.

', // Added - 2015-04-18 'OpEq' => 'rwny', 'OpGt' => 'wiksze od', 'OpGtEq' => 'wiksze lub rwne od', @@ -552,6 +566,9 @@ $SLANG = array( 'Presets' => 'Presets', 'Prev' => 'Poprzedni', 'Probe' => 'Probe', // Added - 2009-03-31 + 'ProfileProbe' => 'Stream Probe', // Added - 2015-04-18 + 'ProfileProbeIntro' => 'The list below shows the existing stream profiles of the selected camera .

Select the desired entry from the list below.

Please note that ZoneMinder cannot configure additional profiles and that choosing a camera here may overwrite any values you already have configured for the current monitor.

', // Added - 2015-04-18 + 'Progress' => 'Progress', // Added - 2015-04-18 'Protocol' => 'Protocol', 'Rate' => 'Tempo', 'Real' => 'Rzeczywiste', @@ -639,6 +656,7 @@ $SLANG = array( 'Submit' => 'Submit', 'System' => 'System', 'SystemLog' => 'System Log', // Added - 2011-06-16 + 'TargetColorspace' => 'Target colorspace', // Added - 2015-04-18 'Tele' => 'Tele', 'Thumbnail' => 'Thumbnail', 'Tilt' => 'Tilt', @@ -673,13 +691,16 @@ $SLANG = array( 'UpdateNotNecessary' => 'Nie jest wymagane uaktualnienie', 'Updated' => 'Updated', // Added - 2011-06-16 'Upload' => 'Upload', // Added - 2011-08-23 - 'UsedPlugins' => 'Used Plugins', 'UseFilter' => 'Uyj filtru', 'UseFilterExprsPost' => ' wyraenie filtru', // This is used at the end of the phrase 'use N filter expressions' 'UseFilterExprsPre' => 'Uyj ', // This is used at the beginning of the phrase 'use N filter expressions' + 'UsedPlugins' => 'Used Plugins', 'User' => 'Uytkownik', 'Username' => 'Nazwa uytkownika', 'Users' => 'Uytkownicy', + 'V4L' => 'V4L', // Added - 2015-04-18 + 'V4LCapturesPerFrame' => 'Captures Per Frame', // Added - 2015-04-18 + 'V4LMultiBuffer' => 'Multi Buffering', // Added - 2015-04-18 'Value' => 'Warto', 'Version' => 'Wersja', 'VersionIgnore' => 'Zignoruj t wersj', @@ -719,6 +740,7 @@ $SLANG = array( 'Zone' => 'Strefa', 'ZoneAlarmColour' => 'Kolor alarmu (Red/Green/Blue)', 'ZoneArea' => 'Zone Area', + 'ZoneExtendAlarmFrames' => 'Extend Alarm Frame Count', 'ZoneFilterSize' => 'Filter Width/Height (pixels)', 'ZoneMinMaxAlarmArea' => 'Min/Max Alarmed Area', 'ZoneMinMaxBlobArea' => 'Min/Max Blob Area', @@ -727,7 +749,6 @@ $SLANG = array( 'ZoneMinMaxPixelThres' => 'Min/Max Pixel Threshold (0-255)', 'ZoneMinderLog' => 'ZoneMinder Log', // Added - 2011-06-17 'ZoneOverloadFrames' => 'Overload Frame Ignore Count', - 'ZoneExtendAlarmFrames' => 'Extend Alarm Frame Count', 'Zones' => 'Strefy', 'Zoom' => 'Zoom', 'ZoomIn' => 'Zoom In', diff --git a/web/lang/pt_br.php b/web/lang/pt_br.php index 91830ebf4..d079db359 100644 --- a/web/lang/pt_br.php +++ b/web/lang/pt_br.php @@ -28,6 +28,7 @@ $SLANG = array( 'AlarmMaximumFPS' => 'Alarm Maximum FPS', 'AlarmPx' => 'Pixel de Alarme', 'AlarmRGBUnset' => 'You must set an alarm RGB colour', + 'AlarmRefImageBlendPct'=> 'Alarm Reference Image Blend %ge', // Added - 2015-04-18 'Alert' => 'Alerta', 'All' => 'Tudo', 'Apply' => 'Aplicar', @@ -72,13 +73,13 @@ $SLANG = array( 'BadFPSReportInterval' => 'FPS report interval buffer count must be an integer of 0 or more', 'BadFormat' => 'Format must be set to an integer of zero or more', 'BadFrameSkip' => 'Frame skip count must be an integer of zero or more', - 'BadMotionFrameSkip' => 'Motion Frame skip count must be an integer of zero or more', 'BadHeight' => 'Height must be set to a valid value', 'BadHost' => 'Host must be set to a valid ip address or hostname, do not include http://', 'BadImageBufferCount' => 'Image buffer size must be an integer of 10 or more', 'BadLabelX' => 'Label X co-ordinate must be set to an integer of zero or more', 'BadLabelY' => 'Label Y co-ordinate must be set to an integer of zero or more', 'BadMaxFPS' => 'Maximum FPS must be a positive integer or floating point value', + 'BadMotionFrameSkip' => 'Motion Frame skip count must be an integer of zero or more', 'BadNameChars' => 'Nomes devem ser caracteres alfanumricos mais hfen e underscore', 'BadPalette' => 'Palette must be set to a valid value', // Added - 2009-03-31 'BadPath' => 'Path must be set to a valid value', @@ -98,7 +99,9 @@ $SLANG = array( 'BlobSizes' => 'Tam Blob', 'Blobs' => 'Blobs', 'Brightness' => 'Brilho', + 'Buffer' => 'Buffer', // Added - 2015-04-18 'Buffers' => 'Buffers', + 'CSSDescription' => 'Change the default css for this computer', // Added - 2015-04-18 'CanAutoFocus' => 'Can Auto Focus', 'CanAutoGain' => 'Can Auto Gain', 'CanAutoIris' => 'Can Auto Iris', @@ -142,6 +145,7 @@ $SLANG = array( 'CaptureHeight' => 'Altura da Captura', 'CaptureMethod' => 'Capture Method', // Added - 2009-02-08 'CapturePalette' => 'Paleta de Captura', + 'CaptureResolution' => 'Capture Resolution', // Added - 2015-04-18 'CaptureWidth' => 'Largura de Captura', 'Cause' => 'Cause', 'CheckMethod' => 'Metodo marcar por alarme', @@ -172,6 +176,7 @@ $SLANG = array( 'ControlDevice' => 'Control Device', 'ControlType' => 'Control Type', 'Controllable' => 'Controllable', + 'Current' => 'Current', // Added - 2015-04-18 'Cycle' => 'Cycle', 'CycleWatch' => 'Ciclo Monitor', 'DateTime' => 'Date/Time', // Added - 2011-06-16 @@ -180,12 +185,15 @@ $SLANG = array( 'DefaultRate' => 'Default Rate', 'DefaultScale' => 'Default Scale', 'DefaultView' => 'Default View', + 'Deinterlacing' => 'Deinterlacing', // Added - 2015-04-18 + 'Delay' => 'Delay', // Added - 2015-04-18 'Delete' => 'Deletar', 'DeleteAndNext' => 'Deletar & Prx', 'DeleteAndPrev' => 'Deletar & Ant', 'DeleteSavedFilter' => 'Deletar Filtros Salvos', 'Description' => 'Descrio', 'DetectedCameras' => 'Detected Cameras', // Added - 2009-03-31 + 'DetectedProfiles' => 'Detected Profiles', // Added - 2015-04-18 'Device' => 'Device', // Added - 2009-02-08 'DeviceChannel' => 'Canal do Dispositivo', 'DeviceFormat' => 'Formato do Dispos.', @@ -197,6 +205,7 @@ $SLANG = array( 'Disk' => 'Disco', 'Display' => 'Display', // Added - 2011-01-30 'Displaying' => 'Displaying', // Added - 2011-06-16 + 'DoNativeMotionDetection'=> 'Do Native Motion Detection', 'Donate' => 'Please Donate', 'DonateAlready' => 'No, I\'ve already donated', 'DonateEnticement' => 'You\'ve been running ZoneMinder for a while now and hopefully are finding it a useful addition to your home or workplace security. Although ZoneMinder is, and will remain, free and open source, it costs money to develop and support. If you would like to help support future development and new features then please consider donating. Donating is, of course, optional but very much appreciated and you can donate as much or as little as you like.

If you would like to donate please select the option below or go to http://www.zoneminder.com/donate.html in your browser.

Thank you for using ZoneMinder and don\'t forget to visit the forums on ZoneMinder.com for support or suggestions about how to make your ZoneMinder experience even better.', @@ -206,7 +215,6 @@ $SLANG = array( 'DonateRemindNever' => 'No, I don\'t want to donate, never remind', 'DonateRemindWeek' => 'Not yet, remind again in 1 week', 'DonateYes' => 'Yes, I\'d like to donate now', - 'DoNativeMotionDetection'=> 'Do Native Motion Detection', 'Download' => 'Download', 'DuplicateMonitorName' => 'Duplicate Monitor Name', // Added - 2009-03-31 'Duration' => 'Durao', @@ -249,10 +257,12 @@ $SLANG = array( 'Feed' => 'Alimentar', 'Ffmpeg' => 'Ffmpeg', // Added - 2009-02-08 'File' => 'File', + 'Filter' => 'Filter', // Added - 2015-04-18 'FilterArchiveEvents' => 'Arquivar resultados', 'FilterDeleteEvents' => 'Apagar resultados', 'FilterEmailEvents' => 'Enviar e-mail com detalhes dos resultados', 'FilterExecuteEvents' => 'Executar comando p/ resultados', + 'FilterLog' => 'Filter log', // Added - 2015-04-18 'FilterMessageEvents' => 'Enviar Mensagem dos resultados', 'FilterPx' => 'Px de Filtro', 'FilterUnset' => 'You must specify a filter width and height', @@ -262,12 +272,12 @@ $SLANG = array( 'First' => 'Primeiro', 'FlippedHori' => 'Flipped Horizontally', 'FlippedVert' => 'Flipped Vertically', - 'FnNone' => 'None', // Added 2013.08.16. - 'FnMonitor' => 'Monitor', // Added 2013.08.16. - 'FnModect' => 'Modect', // Added 2013.08.16. - 'FnRecord' => 'Record', // Added 2013.08.16. 'FnMocord' => 'Mocord', // Added 2013.08.16. + 'FnModect' => 'Modect', // Added 2013.08.16. + 'FnMonitor' => 'Monitor', // Added 2013.08.16. 'FnNodect' => 'Nodect', // Added 2013.08.16. + 'FnNone' => 'None', // Added 2013.08.16. + 'FnRecord' => 'Record', // Added 2013.08.16. 'Focus' => 'Focus', 'ForceAlarm' => 'Forar Alarme', 'Format' => 'Format', @@ -275,7 +285,6 @@ $SLANG = array( 'FrameId' => 'Id de Imagem', 'FrameRate' => 'Velocidade de Imagem', 'FrameSkip' => 'Salto de Imagem', - 'MotionFrameSkip' => 'Motion Frame Skip', 'Frames' => 'Imagens', 'Func' => 'Func', 'Function' => 'Funo', @@ -402,6 +411,7 @@ $SLANG = array( 'MinZoomSpeed' => 'Min Zoom Speed', 'MinZoomStep' => 'Min Zoom Step', 'Misc' => 'Misc', + 'Mode' => 'Mode', // Added - 2015-04-18 'Monitor' => 'Monitor', 'MonitorIds' => 'Ids de Monitor', 'MonitorPreset' => 'Monitor Preset', @@ -412,12 +422,13 @@ $SLANG = array( 'Montage' => 'Montagem', 'Month' => 'Ms', 'More' => 'More', // Added - 2011-06-16 + 'MotionFrameSkip' => 'Motion Frame Skip', 'Move' => 'Move', - 'MtgDefault' => 'Default', // Added 2013.08.15. 'Mtg2widgrd' => '2-wide grid', // Added 2013.08.15. 'Mtg3widgrd' => '3-wide grid', // Added 2013.08.15. - 'Mtg4widgrd' => '4-wide grid', // Added 2013.08.15. 'Mtg3widgrx' => '3-wide grid, scaled, enlarge on alarm', // Added 2013.08.15. + 'Mtg4widgrd' => '4-wide grid', // Added 2013.08.15. + 'MtgDefault' => 'Default', // Added 2013.08.15. 'MustBeGe' => 'deve ser maior ou igual a', 'MustBeLe' => 'deve ser menor ou igual a', 'MustConfirmPassword' => 'Voce deve Confirmar a senha', @@ -446,6 +457,9 @@ $SLANG = array( 'NumPresets' => 'Num Presets', 'Off' => 'Off', 'On' => 'On', + 'OnvifCredentialsIntro'=> 'Please supply user name and password for the selected camera.
If no user has been created for the camera then the user given here will be created with the given password.

', // Added - 2015-04-18 + 'OnvifProbe' => 'ONVIF', // Added - 2015-04-18 + 'OnvifProbeIntro' => 'The list below shows detected ONVIF cameras and whether they are already being used or available for selection.

Select the desired entry from the list below.

Please note that not all cameras may be detected and that choosing a camera here may overwrite any values you already have configured for the current monitor.

', // Added - 2015-04-18 'OpEq' => 'igual a', 'OpGt' => 'maior que', 'OpGtEq' => 'maior que ou igual a', @@ -492,6 +506,9 @@ $SLANG = array( 'Presets' => 'Presets', 'Prev' => 'Ant.', 'Probe' => 'Probe', // Added - 2009-03-31 + 'ProfileProbe' => 'Stream Probe', // Added - 2015-04-18 + 'ProfileProbeIntro' => 'The list below shows the existing stream profiles of the selected camera .

Select the desired entry from the list below.

Please note that ZoneMinder cannot configure additional profiles and that choosing a camera here may overwrite any values you already have configured for the current monitor.

', // Added - 2015-04-18 + 'Progress' => 'Progress', // Added - 2015-04-18 'Protocol' => 'Protocol', 'Rate' => 'Vel.', 'Real' => 'Real', @@ -579,6 +596,7 @@ $SLANG = array( 'Submit' => 'Submit', 'System' => 'Sistema', 'SystemLog' => 'System Log', // Added - 2011-06-16 + 'TargetColorspace' => 'Target colorspace', // Added - 2015-04-18 'Tele' => 'Tele', 'Thumbnail' => 'Thumbnail', 'Tilt' => 'Tilt', @@ -613,13 +631,16 @@ $SLANG = array( 'UpdateNotNecessary' => 'No necessrio update.', 'Updated' => 'Updated', // Added - 2011-06-16 'Upload' => 'Upload', // Added - 2011-08-23 - 'UsedPlugins' => 'Used Plugins', 'UseFilter' => 'Use Filtro', 'UseFilterExprsPost' => ' expresses de filtragem', // This is used at the end of the phrase 'use N filter expressions' 'UseFilterExprsPre' => 'Use ', // This is used at the beginning of the phrase 'use N filter expressions' + 'UsedPlugins' => 'Used Plugins', 'User' => 'Usurio', 'Username' => 'Nome de Usurio', 'Users' => 'Usurios', + 'V4L' => 'V4L', // Added - 2015-04-18 + 'V4LCapturesPerFrame' => 'Captures Per Frame', // Added - 2015-04-18 + 'V4LMultiBuffer' => 'Multi Buffering', // Added - 2015-04-18 'Value' => 'Valor', 'Version' => 'Verso', 'VersionIgnore' => 'Ignorar esta verso', @@ -659,6 +680,7 @@ $SLANG = array( 'Zone' => 'Zona', 'ZoneAlarmColour' => 'Cor de Alarme (Red/Green/Blue)', 'ZoneArea' => 'Zone Area', + 'ZoneExtendAlarmFrames' => 'Extend Alarm Frame Count', 'ZoneFilterSize' => 'Filter Width/Height (pixels)', 'ZoneMinMaxAlarmArea' => 'Min/Max Alarmed Area', 'ZoneMinMaxBlobArea' => 'Min/Max Blob Area', @@ -667,7 +689,6 @@ $SLANG = array( 'ZoneMinMaxPixelThres' => 'Min/Max Pixel Threshold (0-255)', 'ZoneMinderLog' => 'ZoneMinder Log', // Added - 2011-06-17 'ZoneOverloadFrames' => 'Overload Frame Ignore Count', - 'ZoneExtendAlarmFrames' => 'Extend Alarm Frame Count', 'Zones' => 'Zonas', 'Zoom' => 'Zoom', 'ZoomIn' => 'Zoom In', diff --git a/web/lang/ro_ro.php b/web/lang/ro_ro.php index 74da43406..1b1bcb6dc 100644 --- a/web/lang/ro_ro.php +++ b/web/lang/ro_ro.php @@ -59,6 +59,7 @@ $SLANG = array( 'AlarmMaximumFPS' => 'Alarm Maximum FPS', 'AlarmPx' => 'Alarm Px', 'AlarmRGBUnset' => 'You must set an alarm RGB colour', + 'AlarmRefImageBlendPct'=> 'Alarm Reference Image Blend %ge', // Added - 2015-04-18 'Alert' => 'Alert', 'All' => 'Toate', 'Apply' => 'Accept', @@ -103,13 +104,13 @@ $SLANG = array( 'BadFPSReportInterval' => 'FPS report interval buffer count must be an integer of 0 or more', 'BadFormat' => 'Format must be set to an integer of zero or more', 'BadFrameSkip' => 'Frame skip count must be an integer of zero or more', - 'BadMotionFrameSkip' => 'Motion Frame skip count must be an integer of zero or more', 'BadHeight' => 'Height must be set to a valid value', 'BadHost' => 'Host must be set to a valid ip address or hostname, do not include http://', 'BadImageBufferCount' => 'Image buffer size must be an integer of 10 or more', 'BadLabelX' => 'Label X co-ordinate must be set to an integer of zero or more', 'BadLabelY' => 'Label Y co-ordinate must be set to an integer of zero or more', 'BadMaxFPS' => 'Maximum FPS must be a positive integer or floating point value', + 'BadMotionFrameSkip' => 'Motion Frame skip count must be an integer of zero or more', 'BadNameChars' => 'Denumirea poate contine doar caractere alfanumerice, cratima si underline.', 'BadPalette' => 'Palette must be set to a valid value', // Added - 2009-03-31 'BadPath' => 'Path must be set to a valid value', @@ -129,7 +130,9 @@ $SLANG = array( 'BlobSizes' => 'Blob Sizes', 'Blobs' => 'Blobs', 'Brightness' => 'Luminozitate', + 'Buffer' => 'Buffer', // Added - 2015-04-18 'Buffers' => 'Zonă tampon', + 'CSSDescription' => 'Change the default css for this computer', // Added - 2015-04-18 'CanAutoFocus' => 'Focalizare automată', 'CanAutoGain' => 'Can Auto Gain', 'CanAutoIris' => 'Can Auto Iris', @@ -173,6 +176,7 @@ $SLANG = array( 'CaptureHeight' => 'Înălţime captură', 'CaptureMethod' => 'Capture Method', // Added - 2009-02-08 'CapturePalette' => 'Paletă captură', + 'CaptureResolution' => 'Capture Resolution', // Added - 2015-04-18 'CaptureWidth' => 'Lăţime captură', 'Cause' => 'Cauza', 'CheckMethod' => 'Alarm Check Method', @@ -203,6 +207,7 @@ $SLANG = array( 'ControlDevice' => 'Dispozitiv control', 'ControlType' => 'Tip control', 'Controllable' => 'Controlabil', + 'Current' => 'Current', // Added - 2015-04-18 'Cycle' => 'Ciclu', 'CycleWatch' => 'Vizual. ciclu', 'DateTime' => 'Date/Time', // Added - 2011-06-16 @@ -211,12 +216,15 @@ $SLANG = array( 'DefaultRate' => 'Default Rate', 'DefaultScale' => 'Default Scale', 'DefaultView' => 'Default View', + 'Deinterlacing' => 'Deinterlacing', // Added - 2015-04-18 + 'Delay' => 'Delay', // Added - 2015-04-18 'Delete' => 'Şterge', 'DeleteAndNext' => 'Şterge & Următor', 'DeleteAndPrev' => 'Şterge & Precedent', 'DeleteSavedFilter' => 'Şterge filtrul salvat', 'Description' => 'Descriere', 'DetectedCameras' => 'Detected Cameras', // Added - 2009-03-31 + 'DetectedProfiles' => 'Detected Profiles', // Added - 2015-04-18 'Device' => 'Device', // Added - 2009-02-08 'DeviceChannel' => 'Canal dispozitiv', 'DeviceFormat' => 'Format dispozitiv', @@ -228,6 +236,7 @@ $SLANG = array( 'Disk' => 'Disc', 'Display' => 'Display', // Added - 2011-01-30 'Displaying' => 'Displaying', // Added - 2011-06-16 + 'DoNativeMotionDetection'=> 'Do Native Motion Detection', 'Donate' => 'Please Donate', 'DonateAlready' => 'No, I\'ve already donated', 'DonateEnticement' => 'You\'ve been running ZoneMinder for a while now and hopefully are finding it a useful addition to your home or workplace security. Although ZoneMinder is, and will remain, free and open source, it costs money to develop and support. If you would like to help support future development and new features then please consider donating. Donating is, of course, optional but very much appreciated and you can donate as much or as little as you like.

If you would like to donate please select the option below or go to http://www.zoneminder.com/donate.html in your browser.

Thank you for using ZoneMinder and don\'t forget to visit the forums on ZoneMinder.com for support or suggestions about how to make your ZoneMinder experience even better.', @@ -237,7 +246,6 @@ $SLANG = array( 'DonateRemindNever' => 'No, I don\'t want to donate, never remind', 'DonateRemindWeek' => 'Not yet, remind again in 1 week', 'DonateYes' => 'Yes, I\'d like to donate now', - 'DoNativeMotionDetection'=> 'Do Native Motion Detection', 'Download' => 'Download', 'DuplicateMonitorName' => 'Duplicate Monitor Name', // Added - 2009-03-31 'Duration' => 'Durata', @@ -280,10 +288,12 @@ $SLANG = array( 'Feed' => 'Feed', 'Ffmpeg' => 'Ffmpeg', // Added - 2009-02-08 'File' => 'File', + 'Filter' => 'Filter', // Added - 2015-04-18 'FilterArchiveEvents' => 'Arhivează toate rezultatele', 'FilterDeleteEvents' => 'Şterge toate rezultatele', 'FilterEmailEvents' => 'Trimite email ale tuturor rezultatelor', 'FilterExecuteEvents' => 'Execută comanda pentru toate rezultatele', + 'FilterLog' => 'Filter log', // Added - 2015-04-18 'FilterMessageEvents' => 'Trimite mesaj pentru toate rezultatele', 'FilterPx' => 'Filter Px', 'FilterUnset' => 'You must specify a filter width and height', @@ -293,12 +303,12 @@ $SLANG = array( 'First' => 'First', 'FlippedHori' => 'Flipped Horizontally', 'FlippedVert' => 'Flipped Vertically', - 'FnNone' => 'None', // Added 2013.08.16. - 'FnMonitor' => 'Monitor', // Added 2013.08.16. - 'FnModect' => 'Modect', // Added 2013.08.16. - 'FnRecord' => 'Record', // Added 2013.08.16. 'FnMocord' => 'Mocord', // Added 2013.08.16. + 'FnModect' => 'Modect', // Added 2013.08.16. + 'FnMonitor' => 'Monitor', // Added 2013.08.16. 'FnNodect' => 'Nodect', // Added 2013.08.16. + 'FnNone' => 'None', // Added 2013.08.16. + 'FnRecord' => 'Record', // Added 2013.08.16. 'Focus' => 'Focalizare', 'ForceAlarm' => 'Alarmă forţată', 'Format' => 'Format', @@ -306,7 +316,6 @@ $SLANG = array( 'FrameId' => 'Nr. cadru', 'FrameRate' => 'Frecv. cadre', 'FrameSkip' => 'Omite cadre', - 'MotionFrameSkip' => 'Motion Frame Skip', 'Frames' => 'Cadre', 'Func' => 'Func', 'Function' => 'Funcţie', @@ -433,6 +442,7 @@ $SLANG = array( 'MinZoomSpeed' => 'Viteză zoom min', 'MinZoomStep' => 'Pas zoom min', 'Misc' => 'Divers', + 'Mode' => 'Mode', // Added - 2015-04-18 'Monitor' => 'Monitor', 'MonitorIds' => 'Nr. Monitor', 'MonitorPreset' => 'Monitor Preset', @@ -443,12 +453,13 @@ $SLANG = array( 'Montage' => 'Montage', 'Month' => 'Luna', 'More' => 'More', // Added - 2011-06-16 + 'MotionFrameSkip' => 'Motion Frame Skip', 'Move' => 'Mişcare', - 'MtgDefault' => 'Default', // Added 2013.08.15. 'Mtg2widgrd' => '2-wide grid', // Added 2013.08.15. 'Mtg3widgrd' => '3-wide grid', // Added 2013.08.15. - 'Mtg4widgrd' => '4-wide grid', // Added 2013.08.15. 'Mtg3widgrx' => '3-wide grid, scaled, enlarge on alarm', // Added 2013.08.15. + 'Mtg4widgrd' => '4-wide grid', // Added 2013.08.15. + 'MtgDefault' => 'Default', // Added 2013.08.15. 'MustBeGe' => 'trebuie sa fie mai mare sau egal cu', 'MustBeLe' => 'trebuie sa fie mai mic sau egal cu', 'MustConfirmPassword' => 'Trebuie sa confirmati parola', @@ -477,6 +488,9 @@ $SLANG = array( 'NumPresets' => 'Num Presets', 'Off' => 'Off', 'On' => 'On', + 'OnvifCredentialsIntro'=> 'Please supply user name and password for the selected camera.
If no user has been created for the camera then the user given here will be created with the given password.

', // Added - 2015-04-18 + 'OnvifProbe' => 'ONVIF', // Added - 2015-04-18 + 'OnvifProbeIntro' => 'The list below shows detected ONVIF cameras and whether they are already being used or available for selection.

Select the desired entry from the list below.

Please note that not all cameras may be detected and that choosing a camera here may overwrite any values you already have configured for the current monitor.

', // Added - 2015-04-18 'OpEq' => 'egal cu', 'OpGt' => 'mai mare ca', 'OpGtEq' => 'mai mare sau egal cu', @@ -523,6 +537,9 @@ $SLANG = array( 'Presets' => 'Presetări', 'Prev' => 'Prev', 'Probe' => 'Probe', // Added - 2009-03-31 + 'ProfileProbe' => 'Stream Probe', // Added - 2015-04-18 + 'ProfileProbeIntro' => 'The list below shows the existing stream profiles of the selected camera .

Select the desired entry from the list below.

Please note that ZoneMinder cannot configure additional profiles and that choosing a camera here may overwrite any values you already have configured for the current monitor.

', // Added - 2015-04-18 + 'Progress' => 'Progress', // Added - 2015-04-18 'Protocol' => 'Protocol', 'Rate' => 'Rate', 'Real' => 'Real', @@ -610,6 +627,7 @@ $SLANG = array( 'Submit' => 'Trimite', 'System' => 'Sistem', 'SystemLog' => 'System Log', // Added - 2011-06-16 + 'TargetColorspace' => 'Target colorspace', // Added - 2015-04-18 'Tele' => 'Tele', 'Thumbnail' => 'Miniatură', 'Tilt' => 'Înclinare', @@ -644,13 +662,16 @@ $SLANG = array( 'UpdateNotNecessary' => 'Actulizarea nu este necesară.', 'Updated' => 'Updated', // Added - 2011-06-16 'Upload' => 'Upload', // Added - 2011-08-23 - 'UsedPlugins' => 'Used Plugins', 'UseFilter' => 'Foloseşte filtru', 'UseFilterExprsPost' => ' expresii de filtrare ', 'UseFilterExprsPre' => 'Foloseşte ', + 'UsedPlugins' => 'Used Plugins', 'User' => 'Utilizator', 'Username' => 'Nume', 'Users' => 'Utilizatori', + 'V4L' => 'V4L', // Added - 2015-04-18 + 'V4LCapturesPerFrame' => 'Captures Per Frame', // Added - 2015-04-18 + 'V4LMultiBuffer' => 'Multi Buffering', // Added - 2015-04-18 'Value' => 'Valoare', 'Version' => 'Versiune', 'VersionIgnore' => 'Ignoră această versiune', @@ -690,6 +711,7 @@ $SLANG = array( 'Zone' => 'Zone', 'ZoneAlarmColour' => 'Alarm Colour (Red/Green/Blue)', 'ZoneArea' => 'Zone Area', + 'ZoneExtendAlarmFrames' => 'Extend Alarm Frame Count', 'ZoneFilterSize' => 'Filter Width/Height (pixels)', 'ZoneMinMaxAlarmArea' => 'Min/Max Alarmed Area', 'ZoneMinMaxBlobArea' => 'Min/Max Blob Area', @@ -698,7 +720,6 @@ $SLANG = array( 'ZoneMinMaxPixelThres' => 'Min/Max Pixel Threshold (0-255)', 'ZoneMinderLog' => 'ZoneMinder Log', // Added - 2011-06-17 'ZoneOverloadFrames' => 'Overload Frame Ignore Count', - 'ZoneExtendAlarmFrames' => 'Extend Alarm Frame Count', 'Zones' => 'Zona', 'Zoom' => 'Zoom', 'ZoomIn' => 'Zoom In', @@ -1144,14 +1165,6 @@ $OLANG = array( 'Prompt' => "Opţiuni adiţionale pentru ffmpeg", 'Help' => "Ffmpeg suportă multe opţiuni pentru controlul calităţii secvenţei video produse. Această opţiune vă permite să specificaţi propriile opţiuni. Citiţi documentaţia ffmpeg pentru mai multe detalii." ), - 'OPT_NETPBM' => array( - 'Prompt' => "Sunt instalate utilitarele Netpbm (opţional)", - 'Help' => "În cazul laţimii de bandă redusă ZoneMinder va miniaturiza imaginile înainte de a le direcţiona spre browser pentru a reduce traficul. Pentru aceasta foloseşte pachetul Netpbm; această opţiune ar trebuie să direcţioneze ZoneMinder spre binarele pachetului. Dacă nu aveţi pachetul Netpbm instalat imaginilor vor fi întotdeauna trimise la scară reală şi redimensionate în browser." - ), - 'PATH_NETPBM' => array( - 'Prompt' => "Cale la utilitarele Netpbm (opţional)", - 'Help' => "Calea la utilitarele Netpbm (opţional)" - ), 'OPT_TRIGGERS' => array( 'Prompt' => "Interacţionează cu declanşatoare externe via socket sau fişierele dispozitivelor", 'Help' => "ZoneMinder poate interacţiona cu sisteme externe care acţionează sau revocă o alarmă. Acest lucru este realizat prin intermediului script-ului zmtrigger.pl. Această opţiune indică folosirea declanşatoarelor externe, majoritatea vor alege nu aici." diff --git a/web/lang/ru_ru.php b/web/lang/ru_ru.php index 0c4bfbf3b..7c98e4f48 100644 --- a/web/lang/ru_ru.php +++ b/web/lang/ru_ru.php @@ -88,6 +88,7 @@ $SLANG = array( 'AlarmMaximumFPS' => 'Alarm Maximum FPS', 'AlarmPx' => ' .', 'AlarmRGBUnset' => 'You must set an alarm RGB colour', + 'AlarmRefImageBlendPct'=> 'Alarm Reference Image Blend %ge', // Added - 2015-04-18 'Alert' => '', 'All' => '', 'Apply' => '', @@ -132,13 +133,13 @@ $SLANG = array( 'BadFPSReportInterval' => 'FPS report interval buffer count must be an integer of 0 or more', 'BadFormat' => 'Format must be set to an integer of zero or more', 'BadFrameSkip' => 'Frame skip count must be an integer of zero or more', - 'BadMotionFrameSkip' => 'Motion Frame skip count must be an integer of zero or more', 'BadHeight' => 'Height must be set to a valid value', 'BadHost' => 'Host must be set to a valid ip address or hostname, do not include http://', 'BadImageBufferCount' => 'Image buffer size must be an integer of 10 or more', 'BadLabelX' => 'Label X co-ordinate must be set to an integer of zero or more', 'BadLabelY' => 'Label Y co-ordinate must be set to an integer of zero or more', 'BadMaxFPS' => 'Maximum FPS must be a positive integer or floating point value', + 'BadMotionFrameSkip' => 'Motion Frame skip count must be an integer of zero or more', 'BadNameChars' => 'Names may only contain alphanumeric characters plus hyphen and underscore', 'BadPalette' => 'Palette must be set to a valid value', // Added - 2009-03-31 'BadPath' => 'Path must be set to a valid value', @@ -158,7 +159,9 @@ $SLANG = array( 'BlobSizes' => ' ', 'Blobs' => '- ', 'Brightness' => '', + 'Buffer' => 'Buffer', // Added - 2015-04-18 'Buffers' => '', + 'CSSDescription' => 'Change the default css for this computer', // Added - 2015-04-18 'CanAutoFocus' => 'Can Auto Focus', 'CanAutoGain' => 'Can Auto Gain', 'CanAutoIris' => 'Can Auto Iris', @@ -202,6 +205,7 @@ $SLANG = array( 'CaptureHeight' => ' Y', 'CaptureMethod' => 'Capture Method', // Added - 2009-02-08 'CapturePalette' => ' ', + 'CaptureResolution' => 'Capture Resolution', // Added - 2015-04-18 'CaptureWidth' => ' X', 'Cause' => 'Cause', 'CheckMethod' => ' ', @@ -232,6 +236,7 @@ $SLANG = array( 'ControlDevice' => 'Control Device', 'ControlType' => 'Control Type', 'Controllable' => 'Controllable', + 'Current' => 'Current', // Added - 2015-04-18 'Cycle' => 'Cycle', 'CycleWatch' => ' ', 'DateTime' => 'Date/Time', // Added - 2011-06-16 @@ -240,12 +245,15 @@ $SLANG = array( 'DefaultRate' => 'Default Rate', 'DefaultScale' => 'Default Scale', 'DefaultView' => 'Default View', + 'Deinterlacing' => 'Deinterlacing', // Added - 2015-04-18 + 'Delay' => 'Delay', // Added - 2015-04-18 'Delete' => '', 'DeleteAndNext' => ' & .', 'DeleteAndPrev' => ' & .', 'DeleteSavedFilter' => ' ', 'Description' => '', 'DetectedCameras' => 'Detected Cameras', // Added - 2009-03-31 + 'DetectedProfiles' => 'Detected Profiles', // Added - 2015-04-18 'Device' => 'Device', // Added - 2009-02-08 'DeviceChannel' => '', 'DeviceFormat' => '', @@ -257,6 +265,7 @@ $SLANG = array( 'Disk' => 'Disk', 'Display' => 'Display', // Added - 2011-01-30 'Displaying' => 'Displaying', // Added - 2011-06-16 + 'DoNativeMotionDetection'=> 'Do Native Motion Detection', 'Donate' => 'Please Donate', 'DonateAlready' => 'No, I\'ve already donated', 'DonateEnticement' => 'You\'ve been running ZoneMinder for a while now and hopefully are finding it a useful addition to your home or workplace security. Although ZoneMinder is, and will remain, free and open source, it costs money to develop and support. If you would like to help support future development and new features then please consider donating. Donating is, of course, optional but very much appreciated and you can donate as much or as little as you like.

If you would like to donate please select the option below or go to http://www.zoneminder.com/donate.html in your browser.

Thank you for using ZoneMinder and don\'t forget to visit the forums on ZoneMinder.com for support or suggestions about how to make your ZoneMinder experience even better.', @@ -266,7 +275,6 @@ $SLANG = array( 'DonateRemindNever' => 'No, I don\'t want to donate, never remind', 'DonateRemindWeek' => 'Not yet, remind again in 1 week', 'DonateYes' => 'Yes, I\'d like to donate now', - 'DoNativeMotionDetection'=> 'Do Native Motion Detection', 'Download' => 'Download', 'DuplicateMonitorName' => 'Duplicate Monitor Name', // Added - 2009-03-31 'Duration' => '', @@ -309,10 +317,12 @@ $SLANG = array( 'Feed' => 'Feed', 'Ffmpeg' => 'Ffmpeg', // Added - 2009-02-08 'File' => 'File', + 'Filter' => 'Filter', // Added - 2015-04-18 'FilterArchiveEvents' => 'Archive all matches', 'FilterDeleteEvents' => 'Delete all matches', 'FilterEmailEvents' => 'Email details of all matches', 'FilterExecuteEvents' => 'Execute command on all matches', + 'FilterLog' => 'Filter log', // Added - 2015-04-18 'FilterMessageEvents' => 'Message details of all matches', 'FilterPx' => ' ', 'FilterUnset' => 'You must specify a filter width and height', @@ -322,12 +332,12 @@ $SLANG = array( 'First' => '', 'FlippedHori' => 'Flipped Horizontally', 'FlippedVert' => 'Flipped Vertically', - 'FnNone' => 'None', // Added 2013.08.16. - 'FnMonitor' => 'Monitor', // Added 2013.08.16. - 'FnModect' => 'Modect', // Added 2013.08.16. - 'FnRecord' => 'Record', // Added 2013.08.16. 'FnMocord' => 'Mocord', // Added 2013.08.16. + 'FnModect' => 'Modect', // Added 2013.08.16. + 'FnMonitor' => 'Monitor', // Added 2013.08.16. 'FnNodect' => 'Nodect', // Added 2013.08.16. + 'FnNone' => 'None', // Added 2013.08.16. + 'FnRecord' => 'Record', // Added 2013.08.16. 'Focus' => 'Focus', 'ForceAlarm' => ' ', 'Format' => 'Format', @@ -335,7 +345,6 @@ $SLANG = array( 'FrameId' => 'Id ', 'FrameRate' => '', 'FrameSkip' => ' ', - 'MotionFrameSkip' => 'Motion Frame Skip', 'Frames' => '', 'Func' => '.', 'Function' => '', @@ -462,6 +471,7 @@ $SLANG = array( 'MinZoomSpeed' => 'Min Zoom Speed', 'MinZoomStep' => 'Min Zoom Step', 'Misc' => '', + 'Mode' => 'Mode', // Added - 2015-04-18 'Monitor' => '', 'MonitorIds' => 'Id ', 'MonitorPreset' => 'Monitor Preset', @@ -472,12 +482,13 @@ $SLANG = array( 'Montage' => 'Montage', 'Month' => '', 'More' => 'More', // Added - 2011-06-16 + 'MotionFrameSkip' => 'Motion Frame Skip', 'Move' => 'Move', - 'MtgDefault' => 'Default', // Added 2013.08.15. 'Mtg2widgrd' => '2-wide grid', // Added 2013.08.15. 'Mtg3widgrd' => '3-wide grid', // Added 2013.08.15. - 'Mtg4widgrd' => '4-wide grid', // Added 2013.08.15. 'Mtg3widgrx' => '3-wide grid, scaled, enlarge on alarm', // Added 2013.08.15. + 'Mtg4widgrd' => '4-wide grid', // Added 2013.08.15. + 'MtgDefault' => 'Default', // Added 2013.08.15. 'MustBeGe' => ' ', 'MustBeLe' => ' ', 'MustConfirmPassword' => ' ', @@ -506,6 +517,9 @@ $SLANG = array( 'NumPresets' => 'Num Presets', 'Off' => 'Off', 'On' => 'On', + 'OnvifCredentialsIntro'=> 'Please supply user name and password for the selected camera.
If no user has been created for the camera then the user given here will be created with the given password.

', // Added - 2015-04-18 + 'OnvifProbe' => 'ONVIF', // Added - 2015-04-18 + 'OnvifProbeIntro' => 'The list below shows detected ONVIF cameras and whether they are already being used or available for selection.

Select the desired entry from the list below.

Please note that not all cameras may be detected and that choosing a camera here may overwrite any values you already have configured for the current monitor.

', // Added - 2015-04-18 'OpEq' => '', 'OpGt' => '', 'OpGtEq' => ' ', @@ -552,6 +566,9 @@ $SLANG = array( 'Presets' => 'Presets', 'Prev' => '.', 'Probe' => 'Probe', // Added - 2009-03-31 + 'ProfileProbe' => 'Stream Probe', // Added - 2015-04-18 + 'ProfileProbeIntro' => 'The list below shows the existing stream profiles of the selected camera .

Select the desired entry from the list below.

Please note that ZoneMinder cannot configure additional profiles and that choosing a camera here may overwrite any values you already have configured for the current monitor.

', // Added - 2015-04-18 + 'Progress' => 'Progress', // Added - 2015-04-18 'Protocol' => 'Protocol', 'Rate' => '', 'Real' => '', @@ -639,6 +656,7 @@ $SLANG = array( 'Submit' => 'Submit', 'System' => '', 'SystemLog' => 'System Log', // Added - 2011-06-16 + 'TargetColorspace' => 'Target colorspace', // Added - 2015-04-18 'Tele' => 'Tele', 'Thumbnail' => 'Thumbnail', 'Tilt' => 'Tilt', @@ -673,13 +691,16 @@ $SLANG = array( 'UpdateNotNecessary' => ' ', 'Updated' => 'Updated', // Added - 2011-06-16 'Upload' => 'Upload', // Added - 2011-08-23 - 'UsedPlugins' => 'Used Plugins', 'UseFilter' => ' ', 'UseFilterExprsPost' => '   ', // This is used at the end of the phrase 'use N filter expressions' 'UseFilterExprsPre' => '. ', // This is used at the beginning of the phrase 'use N filter expressions' + 'UsedPlugins' => 'Used Plugins', 'User' => '', 'Username' => ' ', 'Users' => '', + 'V4L' => 'V4L', // Added - 2015-04-18 + 'V4LCapturesPerFrame' => 'Captures Per Frame', // Added - 2015-04-18 + 'V4LMultiBuffer' => 'Multi Buffering', // Added - 2015-04-18 'Value' => '', 'Version' => '', 'VersionIgnore' => ' ', @@ -719,6 +740,7 @@ $SLANG = array( 'Zone' => '', 'ZoneAlarmColour' => ' (Red/Green/Blue)', 'ZoneArea' => 'Zone Area', + 'ZoneExtendAlarmFrames' => 'Extend Alarm Frame Count', 'ZoneFilterSize' => 'Filter Width/Height (pixels)', 'ZoneMinMaxAlarmArea' => 'Min/Max Alarmed Area', 'ZoneMinMaxBlobArea' => 'Min/Max Blob Area', @@ -727,7 +749,6 @@ $SLANG = array( 'ZoneMinMaxPixelThres' => 'Min/Max Pixel Threshold (0-255)', 'ZoneMinderLog' => 'ZoneMinder Log', // Added - 2011-06-17 'ZoneOverloadFrames' => 'Overload Frame Ignore Count', - 'ZoneExtendAlarmFrames' => 'Extend Alarm Frame Count', 'Zones' => '', 'Zoom' => 'Zoom', 'ZoomIn' => 'Zoom In', diff --git a/web/lang/se_se.php b/web/lang/se_se.php index 968804fed..ca4f05254 100644 --- a/web/lang/se_se.php +++ b/web/lang/se_se.php @@ -89,6 +89,7 @@ $SLANG = array( 'AlarmMaximumFPS' => 'Max. ramar/s fr larm', 'AlarmPx' => 'Larmpunkter', 'AlarmRGBUnset' => 'Du mste stta en frg fr RGB-larm', + 'AlarmRefImageBlendPct'=> 'Alarm Reference Image Blend %ge', // Added - 2015-04-18 'Alert' => 'Varning', 'All' => 'Alla', 'Apply' => 'Lgg till', @@ -133,13 +134,13 @@ $SLANG = array( 'BadFPSReportInterval' => 'Buffern fr ramintervallrapporten mste vara ett heltal p minst 0 eller hgre', 'BadFormat' => 'Formatet mste vara ett heltal, noll eller hgre', 'BadFrameSkip' => 'Vrdet fr ramverhopp mste vara ett heltal p 0 eller hgre', - 'BadMotionFrameSkip' => 'Motion Frame skip count must be an integer of zero or more', 'BadHeight' => 'Hjden mste sttas till ett giltigt vrde', 'BadHost' => 'Detta flt ska innehlla en giltig ip-adress eller vrdnamn, inkludera inte http://', 'BadImageBufferCount' => 'Bufferstorleken fr avbilden mste vara ett heltal p minst 10 eller hgre', 'BadLabelX' => 'Etiketten fr X koordinaten mste sttas till ett heltal, 0 eller hgre', 'BadLabelY' => 'Etiketten fr Y koordinaten mste sttas till ett heltal, 0 eller hgre', 'BadMaxFPS' => 'Max. ramar/s mste vara ett positivt heltal eller ett flyttal', + 'BadMotionFrameSkip' => 'Motion Frame skip count must be an integer of zero or more', 'BadNameChars' => 'Namn kan endast innehlla alfanumeriska tecken, bindestreck och understreck', 'BadPalette' => 'Palette must be set to a valid value', // Added - 2009-03-31 'BadPath' => 'Skvgen mste innehlla ett giltigt vrde', @@ -159,7 +160,9 @@ $SLANG = array( 'BlobSizes' => 'Blobstorlek', 'Blobs' => 'Blobbar', 'Brightness' => 'Ljusstyrka', + 'Buffer' => 'Buffer', // Added - 2015-04-18 'Buffers' => 'Buffrar', + 'CSSDescription' => 'Change the default css for this computer', // Added - 2015-04-18 'CanAutoFocus' => 'Har autofokus', 'CanAutoGain' => 'Har autoniv', 'CanAutoIris' => 'Har autoiris', @@ -203,6 +206,7 @@ $SLANG = array( 'CaptureHeight' => 'Fngsthjd', 'CaptureMethod' => 'Capture Method', // Added - 2009-02-08 'CapturePalette' => 'Fngstpalett', + 'CaptureResolution' => 'Capture Resolution', // Added - 2015-04-18 'CaptureWidth' => 'Fngstbredd', 'Cause' => 'Orsak', 'CheckMethod' => 'Larmkontrollmetod', @@ -233,6 +237,7 @@ $SLANG = array( 'ControlDevice' => 'Kontrollenhet', 'ControlType' => 'Kontrolltyp', 'Controllable' => 'Kontrollerbar', + 'Current' => 'Current', // Added - 2015-04-18 'Cycle' => 'Period', 'CycleWatch' => 'Cycle Watch', 'DateTime' => 'Date/Time', // Added - 2011-06-16 @@ -241,12 +246,15 @@ $SLANG = array( 'DefaultRate' => 'Standardhastighet', 'DefaultScale' => 'Standardskala', 'DefaultView' => 'Standardvy', + 'Deinterlacing' => 'Deinterlacing', // Added - 2015-04-18 + 'Delay' => 'Delay', // Added - 2015-04-18 'Delete' => 'Radera', 'DeleteAndNext' => 'Radera & Nsta', 'DeleteAndPrev' => 'Radera & Freg.', 'DeleteSavedFilter' => 'Radera sparade filter', 'Description' => 'Beskrivning', 'DetectedCameras' => 'Detected Cameras', // Added - 2009-03-31 + 'DetectedProfiles' => 'Detected Profiles', // Added - 2015-04-18 'Device' => 'Device', // Added - 2009-02-08 'DeviceChannel' => 'Enhetskanal', 'DeviceFormat' => 'Enhetsformat', @@ -258,6 +266,7 @@ $SLANG = array( 'Disk' => 'Disk', 'Display' => 'Display', // Added - 2011-01-30 'Displaying' => 'Displaying', // Added - 2011-06-16 + 'DoNativeMotionDetection'=> 'Do Native Motion Detection', 'Donate' => 'Var vnlig och donera', 'DonateAlready' => 'Nej, Jag har redan donerat', 'DonateEnticement' => 'Du har krt ZoneMinder ett tag nu och frhoppningsvis har du sett att det fungerar bra hemma eller p ditt fretag. ven om ZoneMinder r, och kommer att vara, fri programvara och ppen kallkod, s kostar det pengar att utveckla och underhlla. Om du vill hjlpa till med framtida utveckling och nya funktioner s var vanlig och bidrag med en slant. Bidragen r naturligtvis en option men mycket uppskattade och du kan bidra med precis hur mycket du vill.

Om du vill ge ett bidrag vljer du nedan eller surfar till http://www.zoneminder.com/donate.html.

Tack fr att du anvnder ZoneMinder, glm inte att beska forumen p ZoneMinder.com fr support och frslag om hur du fr din ZoneMinder att fungera lite bttre.', @@ -267,7 +276,6 @@ $SLANG = array( 'DonateRemindNever' => 'Nej, Jag vill inte donera, pminn mig inte mer', 'DonateRemindWeek' => 'Inte n, pminn om 1 vecka', 'DonateYes' => 'Ja, jag vill grna donera nu', - 'DoNativeMotionDetection'=> 'Do Native Motion Detection', 'Download' => 'Ladda ner', 'DuplicateMonitorName' => 'Duplicate Monitor Name', // Added - 2009-03-31 'Duration' => 'Lngd', @@ -310,10 +318,12 @@ $SLANG = array( 'Feed' => 'Matning', 'Ffmpeg' => 'Ffmpeg', // Added - 2009-02-08 'File' => 'Fil', + 'Filter' => 'Filter', // Added - 2015-04-18 'FilterArchiveEvents' => 'Arkivera alla trffar', 'FilterDeleteEvents' => 'Radera alla trffar', 'FilterEmailEvents' => 'Skicka e-post med detaljer om alla trffar', 'FilterExecuteEvents' => 'Utfr kommando p alla trffar', + 'FilterLog' => 'Filter log', // Added - 2015-04-18 'FilterMessageEvents' => 'Meddela detaljer om alla trffar', 'FilterPx' => 'Filter Px', 'FilterUnset' => 'Du mste specificera filtrets bredd och hjd', @@ -323,12 +333,12 @@ $SLANG = array( 'First' => 'Frst', 'FlippedHori' => 'Vnd horisontellt', 'FlippedVert' => 'Vnd vertikalt', - 'FnNone' => 'None', // Added 2013.08.16. - 'FnMonitor' => 'Monitor', // Added 2013.08.16. - 'FnModect' => 'Modect', // Added 2013.08.16. - 'FnRecord' => 'Record', // Added 2013.08.16. 'FnMocord' => 'Mocord', // Added 2013.08.16. + 'FnModect' => 'Modect', // Added 2013.08.16. + 'FnMonitor' => 'Monitor', // Added 2013.08.16. 'FnNodect' => 'Nodect', // Added 2013.08.16. + 'FnNone' => 'None', // Added 2013.08.16. + 'FnRecord' => 'Record', // Added 2013.08.16. 'Focus' => 'Fokus', 'ForceAlarm' => 'Tvinga larm', 'Format' => 'Format', @@ -336,7 +346,6 @@ $SLANG = array( 'FrameId' => 'Ram id', 'FrameRate' => 'Ram hastighet', 'FrameSkip' => 'Hoppa ver ram', - 'MotionFrameSkip' => 'Motion Frame Skip', 'Frames' => 'Ramar', 'Func' => 'Funk', 'Function' => 'Funktion', @@ -463,6 +472,7 @@ $SLANG = array( 'MinZoomSpeed' => 'Min zoomhastighet', 'MinZoomStep' => 'Min zoomsteg', 'Misc' => 'vrigt', + 'Mode' => 'Mode', // Added - 2015-04-18 'Monitor' => 'Bevakning', 'MonitorIds' => 'Bevakningsnr', 'MonitorPreset' => 'Frinstlld bevakning', @@ -473,12 +483,13 @@ $SLANG = array( 'Montage' => 'Montera', 'Month' => 'Mnad', 'More' => 'More', // Added - 2011-06-16 + 'MotionFrameSkip' => 'Motion Frame Skip', 'Move' => 'Flytta', - 'MtgDefault' => 'Default', // Added 2013.08.15. 'Mtg2widgrd' => '2-wide grid', // Added 2013.08.15. 'Mtg3widgrd' => '3-wide grid', // Added 2013.08.15. - 'Mtg4widgrd' => '4-wide grid', // Added 2013.08.15. 'Mtg3widgrx' => '3-wide grid, scaled, enlarge on alarm', // Added 2013.08.15. + 'Mtg4widgrd' => '4-wide grid', // Added 2013.08.15. + 'MtgDefault' => 'Default', // Added 2013.08.15. 'MustBeGe' => 'mste vara strre n eller lika med', 'MustBeLe' => 'mste vara mindre n eller lika med', 'MustConfirmPassword' => 'Du mste bekrfta lsenordet', @@ -507,6 +518,9 @@ $SLANG = array( 'NumPresets' => 'Antal frinstllningar', 'Off' => 'Av', 'On' => 'P', + 'OnvifCredentialsIntro'=> 'Please supply user name and password for the selected camera.
If no user has been created for the camera then the user given here will be created with the given password.

', // Added - 2015-04-18 + 'OnvifProbe' => 'ONVIF', // Added - 2015-04-18 + 'OnvifProbeIntro' => 'The list below shows detected ONVIF cameras and whether they are already being used or available for selection.

Select the desired entry from the list below.

Please note that not all cameras may be detected and that choosing a camera here may overwrite any values you already have configured for the current monitor.

', // Added - 2015-04-18 'OpEq' => 'lika med', 'OpGt' => 'strre n', 'OpGtEq' => 'strre n eller lika med', @@ -553,6 +567,9 @@ $SLANG = array( 'Presets' => 'Frinstllningar', 'Prev' => 'Freg.', 'Probe' => 'Probe', // Added - 2009-03-31 + 'ProfileProbe' => 'Stream Probe', // Added - 2015-04-18 + 'ProfileProbeIntro' => 'The list below shows the existing stream profiles of the selected camera .

Select the desired entry from the list below.

Please note that ZoneMinder cannot configure additional profiles and that choosing a camera here may overwrite any values you already have configured for the current monitor.

', // Added - 2015-04-18 + 'Progress' => 'Progress', // Added - 2015-04-18 'Protocol' => 'Protokol', 'Rate' => 'Hastighet', 'Real' => 'Verklig', @@ -640,6 +657,7 @@ $SLANG = array( 'Submit' => 'Skicka', 'System' => 'System', 'SystemLog' => 'System Log', // Added - 2011-06-16 + 'TargetColorspace' => 'Target colorspace', // Added - 2015-04-18 'Tele' => 'Tele', 'Thumbnail' => 'Miniatyrer', 'Tilt' => 'Tilt', @@ -674,13 +692,16 @@ $SLANG = array( 'UpdateNotNecessary' => 'Ingen uppdatering behvs.', 'Updated' => 'Updated', // Added - 2011-06-16 'Upload' => 'Upload', // Added - 2011-08-23 - 'UsedPlugins' => 'Used Plugins', 'UseFilter' => 'Anvnd filter', 'UseFilterExprsPost' => ' filter expressions', // This is used at the end of the phrase 'use N filter expressions' 'UseFilterExprsPre' => 'Anvnd ', // This is used at the beginning of the phrase 'use N filter expressions' + 'UsedPlugins' => 'Used Plugins', 'User' => 'Anvndare', 'Username' => 'Anvndarnamn', 'Users' => 'Anvndare', + 'V4L' => 'V4L', // Added - 2015-04-18 + 'V4LCapturesPerFrame' => 'Captures Per Frame', // Added - 2015-04-18 + 'V4LMultiBuffer' => 'Multi Buffering', // Added - 2015-04-18 'Value' => 'Vrde', 'Version' => 'Version', 'VersionIgnore' => 'Ignorera denna version', @@ -720,6 +741,7 @@ $SLANG = array( 'Zone' => 'Zon', 'ZoneAlarmColour' => 'Larmfrg (Rd/Grn/Bl)', 'ZoneArea' => 'Zonarea', + 'ZoneExtendAlarmFrames' => 'Extend Alarm Frame Count', 'ZoneFilterSize' => 'Filterbredd/hjd (pixlar)', 'ZoneMinMaxAlarmArea' => 'Min/Max larmarea', 'ZoneMinMaxBlobArea' => 'Min/Max blobbarea', @@ -728,7 +750,6 @@ $SLANG = array( 'ZoneMinMaxPixelThres' => 'Min/Max pixel Threshold (0-255)', 'ZoneMinderLog' => 'ZoneMinder Log', // Added - 2011-06-17 'ZoneOverloadFrames' => 'Overload Frame Ignore Count', - 'ZoneExtendAlarmFrames' => 'Extend Alarm Frame Count', 'Zones' => 'Zoner', 'Zoom' => 'Zoom', 'ZoomIn' => 'Zooma in', diff --git a/web/skins/classic/includes/config.php b/web/skins/classic/includes/config.php index 9599c6112..d586f90c8 100644 --- a/web/skins/classic/includes/config.php +++ b/web/skins/classic/includes/config.php @@ -25,7 +25,7 @@ $rates = array( "1000" => "10x", "400" => "4x", "200" => "2x", - "100" => $SLANG['Real'], + "100" => translate('Real'), "50" => "1/2x", "25" => "1/4x", ); @@ -35,7 +35,7 @@ $scales = array( "300" => "3x", "200" => "2x", "150" => "1.5x", - "100" => $SLANG['Actual'], + "100" => translate('Actual'), "75" => "3/4x", "50" => "1/2x", "33" => "1/3x", @@ -43,9 +43,9 @@ $scales = array( ); $bwArray = array( - "high" => $SLANG['High'], - "medium" => $SLANG['Medium'], - "low" => $SLANG['Low'] + "high" => translate('High'), + "medium" => translate('Medium'), + "low" => translate('Low') ); switch ( $_COOKIE['zmBandwidth'] ) diff --git a/web/skins/classic/includes/control_functions.php b/web/skins/classic/includes/control_functions.php index 6fc2cd72b..b09a53138 100644 --- a/web/skins/classic/includes/control_functions.php +++ b/web/skins/classic/includes/control_functions.php @@ -137,22 +137,20 @@ function getControlCommands( $monitor ) function controlFocus( $monitor, $cmds ) { - global $SLANG; - ob_start(); ?>
-
+
-
onclick="controlCmd('')">
+
onclick="controlCmd('')">
-
+
- - + + @@ -168,17 +166,17 @@ function controlZoom( $monitor, $cmds ) ob_start(); ?>
-
+
-
onclick="controlCmd('')">
+
onclick="controlCmd('')">
-
+
- - + + @@ -193,17 +191,17 @@ function controlIris( $monitor, $cmds ) ob_start(); ?>
-
+
-
onclick="controlCmd('')">
+
onclick="controlCmd('')">
-
+
- - + + @@ -219,17 +217,17 @@ function controlWhite( $monitor, $cmds ) ob_start(); ?>
-
+
-
onclick="controlCmd('')">
+
onclick="controlCmd('')">
-
+
- - + + @@ -245,7 +243,7 @@ function controlPanTilt( $monitor, $cmds ) ob_start(); ?>
-
+
- +
- + - + @@ -326,25 +324,25 @@ function controlPower( $monitor, $cmds ) ob_start(); ?>
-
+
- + - + - + diff --git a/web/skins/classic/includes/export_functions.php b/web/skins/classic/includes/export_functions.php index 42b03a8da..e604536e8 100644 --- a/web/skins/classic/includes/export_functions.php +++ b/web/skins/classic/includes/export_functions.php @@ -71,7 +71,7 @@ html ul.tabs li.active, html ul.tabs li.active a:hover { } --> - + + + )[^>]*$|^#([\w-]+)$/,Ua=/^.[^:#\[\.,]*$/,Va=/\S/, -Wa=/^(\s|\u00A0)+|(\s|\u00A0)+$/g,Xa=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,P=navigator.userAgent,xa=false,Q=[],L,$=Object.prototype.toString,aa=Object.prototype.hasOwnProperty,ba=Array.prototype.push,R=Array.prototype.slice,ya=Array.prototype.indexOf;c.fn=c.prototype={init:function(a,b){var d,f;if(!a)return this;if(a.nodeType){this.context=this[0]=a;this.length=1;return this}if(a==="body"&&!b){this.context=s;this[0]=s.body;this.selector="body";this.length=1;return this}if(typeof a==="string")if((d=Ta.exec(a))&& -(d[1]||!b))if(d[1]){f=b?b.ownerDocument||b:s;if(a=Xa.exec(a))if(c.isPlainObject(b)){a=[s.createElement(a[1])];c.fn.attr.call(a,b,true)}else a=[f.createElement(a[1])];else{a=sa([d[1]],[f]);a=(a.cacheable?a.fragment.cloneNode(true):a.fragment).childNodes}return c.merge(this,a)}else{if(b=s.getElementById(d[2])){if(b.id!==d[2])return T.find(a);this.length=1;this[0]=b}this.context=s;this.selector=a;return this}else if(!b&&/^\w+$/.test(a)){this.selector=a;this.context=s;a=s.getElementsByTagName(a);return c.merge(this, -a)}else return!b||b.jquery?(b||T).find(a):c(b).find(a);else if(c.isFunction(a))return T.ready(a);if(a.selector!==w){this.selector=a.selector;this.context=a.context}return c.makeArray(a,this)},selector:"",jquery:"1.4.2",length:0,size:function(){return this.length},toArray:function(){return R.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this.slice(a)[0]:this[a]},pushStack:function(a,b,d){var f=c();c.isArray(a)?ba.apply(f,a):c.merge(f,a);f.prevObject=this;f.context=this.context;if(b=== -"find")f.selector=this.selector+(this.selector?" ":"")+d;else if(b)f.selector=this.selector+"."+b+"("+d+")";return f},each:function(a,b){return c.each(this,a,b)},ready:function(a){c.bindReady();if(c.isReady)a.call(s,c);else Q&&Q.push(a);return this},eq:function(a){return a===-1?this.slice(a):this.slice(a,+a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(R.apply(this,arguments),"slice",R.call(arguments).join(","))},map:function(a){return this.pushStack(c.map(this, -function(b,d){return a.call(b,d,b)}))},end:function(){return this.prevObject||c(null)},push:ba,sort:[].sort,splice:[].splice};c.fn.init.prototype=c.fn;c.extend=c.fn.extend=function(){var a=arguments[0]||{},b=1,d=arguments.length,f=false,e,j,i,o;if(typeof a==="boolean"){f=a;a=arguments[1]||{};b=2}if(typeof a!=="object"&&!c.isFunction(a))a={};if(d===b){a=this;--b}for(;b
'.$SLANG['DateTime'].''.$SLANG['Component'].''.$SLANG['Pid'].''.$SLANG['Level'].''.$SLANG['Message'].''.$SLANG['File'].''.$SLANG['Line'].'
'.translate('DateTime').''.translate('Component').''.translate('Pid').''.translate('Level').''.translate('Message').''.translate('File').''.translate('Line').'
a"; -var e=d.getElementsByTagName("*"),j=d.getElementsByTagName("a")[0];if(!(!e||!e.length||!j)){c.support={leadingWhitespace:d.firstChild.nodeType===3,tbody:!d.getElementsByTagName("tbody").length,htmlSerialize:!!d.getElementsByTagName("link").length,style:/red/.test(j.getAttribute("style")),hrefNormalized:j.getAttribute("href")==="/a",opacity:/^0.55$/.test(j.style.opacity),cssFloat:!!j.style.cssFloat,checkOn:d.getElementsByTagName("input")[0].value==="on",optSelected:s.createElement("select").appendChild(s.createElement("option")).selected, -parentNode:d.removeChild(d.appendChild(s.createElement("div"))).parentNode===null,deleteExpando:true,checkClone:false,scriptEval:false,noCloneEvent:true,boxModel:null};b.type="text/javascript";try{b.appendChild(s.createTextNode("window."+f+"=1;"))}catch(i){}a.insertBefore(b,a.firstChild);if(A[f]){c.support.scriptEval=true;delete A[f]}try{delete b.test}catch(o){c.support.deleteExpando=false}a.removeChild(b);if(d.attachEvent&&d.fireEvent){d.attachEvent("onclick",function k(){c.support.noCloneEvent= -false;d.detachEvent("onclick",k)});d.cloneNode(true).fireEvent("onclick")}d=s.createElement("div");d.innerHTML="";a=s.createDocumentFragment();a.appendChild(d.firstChild);c.support.checkClone=a.cloneNode(true).cloneNode(true).lastChild.checked;c(function(){var k=s.createElement("div");k.style.width=k.style.paddingLeft="1px";s.body.appendChild(k);c.boxModel=c.support.boxModel=k.offsetWidth===2;s.body.removeChild(k).style.display="none"});a=function(k){var n= -s.createElement("div");k="on"+k;var r=k in n;if(!r){n.setAttribute(k,"return;");r=typeof n[k]==="function"}return r};c.support.submitBubbles=a("submit");c.support.changeBubbles=a("change");a=b=d=e=j=null}})();c.props={"for":"htmlFor","class":"className",readonly:"readOnly",maxlength:"maxLength",cellspacing:"cellSpacing",rowspan:"rowSpan",colspan:"colSpan",tabindex:"tabIndex",usemap:"useMap",frameborder:"frameBorder"};var G="jQuery"+J(),Ya=0,za={};c.extend({cache:{},expando:G,noData:{embed:true,object:true, -applet:true},data:function(a,b,d){if(!(a.nodeName&&c.noData[a.nodeName.toLowerCase()])){a=a==A?za:a;var f=a[G],e=c.cache;if(!f&&typeof b==="string"&&d===w)return null;f||(f=++Ya);if(typeof b==="object"){a[G]=f;e[f]=c.extend(true,{},b)}else if(!e[f]){a[G]=f;e[f]={}}a=e[f];if(d!==w)a[b]=d;return typeof b==="string"?a[b]:a}},removeData:function(a,b){if(!(a.nodeName&&c.noData[a.nodeName.toLowerCase()])){a=a==A?za:a;var d=a[G],f=c.cache,e=f[d];if(b){if(e){delete e[b];c.isEmptyObject(e)&&c.removeData(a)}}else{if(c.support.deleteExpando)delete a[c.expando]; -else a.removeAttribute&&a.removeAttribute(c.expando);delete f[d]}}}});c.fn.extend({data:function(a,b){if(typeof a==="undefined"&&this.length)return c.data(this[0]);else if(typeof a==="object")return this.each(function(){c.data(this,a)});var d=a.split(".");d[1]=d[1]?"."+d[1]:"";if(b===w){var f=this.triggerHandler("getData"+d[1]+"!",[d[0]]);if(f===w&&this.length)f=c.data(this[0],a);return f===w&&d[1]?this.data(d[0]):f}else return this.trigger("setData"+d[1]+"!",[d[0],b]).each(function(){c.data(this, -a,b)})},removeData:function(a){return this.each(function(){c.removeData(this,a)})}});c.extend({queue:function(a,b,d){if(a){b=(b||"fx")+"queue";var f=c.data(a,b);if(!d)return f||[];if(!f||c.isArray(d))f=c.data(a,b,c.makeArray(d));else f.push(d);return f}},dequeue:function(a,b){b=b||"fx";var d=c.queue(a,b),f=d.shift();if(f==="inprogress")f=d.shift();if(f){b==="fx"&&d.unshift("inprogress");f.call(a,function(){c.dequeue(a,b)})}}});c.fn.extend({queue:function(a,b){if(typeof a!=="string"){b=a;a="fx"}if(b=== -w)return c.queue(this[0],a);return this.each(function(){var d=c.queue(this,a,b);a==="fx"&&d[0]!=="inprogress"&&c.dequeue(this,a)})},dequeue:function(a){return this.each(function(){c.dequeue(this,a)})},delay:function(a,b){a=c.fx?c.fx.speeds[a]||a:a;b=b||"fx";return this.queue(b,function(){var d=this;setTimeout(function(){c.dequeue(d,b)},a)})},clearQueue:function(a){return this.queue(a||"fx",[])}});var Aa=/[\n\t]/g,ca=/\s+/,Za=/\r/g,$a=/href|src|style/,ab=/(button|input)/i,bb=/(button|input|object|select|textarea)/i, -cb=/^(a|area)$/i,Ba=/radio|checkbox/;c.fn.extend({attr:function(a,b){return X(this,a,b,true,c.attr)},removeAttr:function(a){return this.each(function(){c.attr(this,a,"");this.nodeType===1&&this.removeAttribute(a)})},addClass:function(a){if(c.isFunction(a))return this.each(function(n){var r=c(this);r.addClass(a.call(this,n,r.attr("class")))});if(a&&typeof a==="string")for(var b=(a||"").split(ca),d=0,f=this.length;d-1)return true;return false},val:function(a){if(a===w){var b=this[0];if(b){if(c.nodeName(b,"option"))return(b.attributes.value||{}).specified?b.value:b.text;if(c.nodeName(b,"select")){var d=b.selectedIndex,f=[],e=b.options;b=b.type==="select-one";if(d<0)return null;var j=b?d:0;for(d=b?d+1:e.length;j=0;else if(c.nodeName(this,"select")){var u=c.makeArray(r);c("option",this).each(function(){this.selected= -c.inArray(c(this).val(),u)>=0});if(!u.length)this.selectedIndex=-1}else this.value=r}})}});c.extend({attrFn:{val:true,css:true,html:true,text:true,data:true,width:true,height:true,offset:true},attr:function(a,b,d,f){if(!a||a.nodeType===3||a.nodeType===8)return w;if(f&&b in c.attrFn)return c(a)[b](d);f=a.nodeType!==1||!c.isXMLDoc(a);var e=d!==w;b=f&&c.props[b]||b;if(a.nodeType===1){var j=$a.test(b);if(b in a&&f&&!j){if(e){b==="type"&&ab.test(a.nodeName)&&a.parentNode&&c.error("type property can't be changed"); -a[b]=d}if(c.nodeName(a,"form")&&a.getAttributeNode(b))return a.getAttributeNode(b).nodeValue;if(b==="tabIndex")return(b=a.getAttributeNode("tabIndex"))&&b.specified?b.value:bb.test(a.nodeName)||cb.test(a.nodeName)&&a.href?0:w;return a[b]}if(!c.support.style&&f&&b==="style"){if(e)a.style.cssText=""+d;return a.style.cssText}e&&a.setAttribute(b,""+d);a=!c.support.hrefNormalized&&f&&j?a.getAttribute(b,2):a.getAttribute(b);return a===null?w:a}return c.style(a,b,d)}});var O=/\.(.*)$/,db=function(a){return a.replace(/[^\w\s\.\|`]/g, -function(b){return"\\"+b})};c.event={add:function(a,b,d,f){if(!(a.nodeType===3||a.nodeType===8)){if(a.setInterval&&a!==A&&!a.frameElement)a=A;var e,j;if(d.handler){e=d;d=e.handler}if(!d.guid)d.guid=c.guid++;if(j=c.data(a)){var i=j.events=j.events||{},o=j.handle;if(!o)j.handle=o=function(){return typeof c!=="undefined"&&!c.event.triggered?c.event.handle.apply(o.elem,arguments):w};o.elem=a;b=b.split(" ");for(var k,n=0,r;k=b[n++];){j=e?c.extend({},e):{handler:d,data:f};if(k.indexOf(".")>-1){r=k.split("."); -k=r.shift();j.namespace=r.slice(0).sort().join(".")}else{r=[];j.namespace=""}j.type=k;j.guid=d.guid;var u=i[k],z=c.event.special[k]||{};if(!u){u=i[k]=[];if(!z.setup||z.setup.call(a,f,r,o)===false)if(a.addEventListener)a.addEventListener(k,o,false);else a.attachEvent&&a.attachEvent("on"+k,o)}if(z.add){z.add.call(a,j);if(!j.handler.guid)j.handler.guid=d.guid}u.push(j);c.event.global[k]=true}a=null}}},global:{},remove:function(a,b,d,f){if(!(a.nodeType===3||a.nodeType===8)){var e,j=0,i,o,k,n,r,u,z=c.data(a), -C=z&&z.events;if(z&&C){if(b&&b.type){d=b.handler;b=b.type}if(!b||typeof b==="string"&&b.charAt(0)==="."){b=b||"";for(e in C)c.event.remove(a,e+b)}else{for(b=b.split(" ");e=b[j++];){n=e;i=e.indexOf(".")<0;o=[];if(!i){o=e.split(".");e=o.shift();k=new RegExp("(^|\\.)"+c.map(o.slice(0).sort(),db).join("\\.(?:.*\\.)?")+"(\\.|$)")}if(r=C[e])if(d){n=c.event.special[e]||{};for(B=f||0;B=0){a.type= -e=e.slice(0,-1);a.exclusive=true}if(!d){a.stopPropagation();c.event.global[e]&&c.each(c.cache,function(){this.events&&this.events[e]&&c.event.trigger(a,b,this.handle.elem)})}if(!d||d.nodeType===3||d.nodeType===8)return w;a.result=w;a.target=d;b=c.makeArray(b);b.unshift(a)}a.currentTarget=d;(f=c.data(d,"handle"))&&f.apply(d,b);f=d.parentNode||d.ownerDocument;try{if(!(d&&d.nodeName&&c.noData[d.nodeName.toLowerCase()]))if(d["on"+e]&&d["on"+e].apply(d,b)===false)a.result=false}catch(j){}if(!a.isPropagationStopped()&& -f)c.event.trigger(a,b,f,true);else if(!a.isDefaultPrevented()){f=a.target;var i,o=c.nodeName(f,"a")&&e==="click",k=c.event.special[e]||{};if((!k._default||k._default.call(d,a)===false)&&!o&&!(f&&f.nodeName&&c.noData[f.nodeName.toLowerCase()])){try{if(f[e]){if(i=f["on"+e])f["on"+e]=null;c.event.triggered=true;f[e]()}}catch(n){}if(i)f["on"+e]=i;c.event.triggered=false}}},handle:function(a){var b,d,f,e;a=arguments[0]=c.event.fix(a||A.event);a.currentTarget=this;b=a.type.indexOf(".")<0&&!a.exclusive; -if(!b){d=a.type.split(".");a.type=d.shift();f=new RegExp("(^|\\.)"+d.slice(0).sort().join("\\.(?:.*\\.)?")+"(\\.|$)")}e=c.data(this,"events");d=e[a.type];if(e&&d){d=d.slice(0);e=0;for(var j=d.length;e-1?c.map(a.options,function(f){return f.selected}).join("-"):"";else if(a.nodeName.toLowerCase()==="select")d=a.selectedIndex;return d},fa=function(a,b){var d=a.target,f,e;if(!(!da.test(d.nodeName)||d.readOnly)){f=c.data(d,"_change_data");e=Fa(d);if(a.type!=="focusout"||d.type!=="radio")c.data(d,"_change_data", -e);if(!(f===w||e===f))if(f!=null||e){a.type="change";return c.event.trigger(a,b,d)}}};c.event.special.change={filters:{focusout:fa,click:function(a){var b=a.target,d=b.type;if(d==="radio"||d==="checkbox"||b.nodeName.toLowerCase()==="select")return fa.call(this,a)},keydown:function(a){var b=a.target,d=b.type;if(a.keyCode===13&&b.nodeName.toLowerCase()!=="textarea"||a.keyCode===32&&(d==="checkbox"||d==="radio")||d==="select-multiple")return fa.call(this,a)},beforeactivate:function(a){a=a.target;c.data(a, -"_change_data",Fa(a))}},setup:function(){if(this.type==="file")return false;for(var a in ea)c.event.add(this,a+".specialChange",ea[a]);return da.test(this.nodeName)},teardown:function(){c.event.remove(this,".specialChange");return da.test(this.nodeName)}};ea=c.event.special.change.filters}s.addEventListener&&c.each({focus:"focusin",blur:"focusout"},function(a,b){function d(f){f=c.event.fix(f);f.type=b;return c.event.handle.call(this,f)}c.event.special[b]={setup:function(){this.addEventListener(a, -d,true)},teardown:function(){this.removeEventListener(a,d,true)}}});c.each(["bind","one"],function(a,b){c.fn[b]=function(d,f,e){if(typeof d==="object"){for(var j in d)this[b](j,f,d[j],e);return this}if(c.isFunction(f)){e=f;f=w}var i=b==="one"?c.proxy(e,function(k){c(this).unbind(k,i);return e.apply(this,arguments)}):e;if(d==="unload"&&b!=="one")this.one(d,f,e);else{j=0;for(var o=this.length;j0){y=t;break}}t=t[g]}m[q]=y}}}var f=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g, -e=0,j=Object.prototype.toString,i=false,o=true;[0,0].sort(function(){o=false;return 0});var k=function(g,h,l,m){l=l||[];var q=h=h||s;if(h.nodeType!==1&&h.nodeType!==9)return[];if(!g||typeof g!=="string")return l;for(var p=[],v,t,y,S,H=true,M=x(h),I=g;(f.exec(""),v=f.exec(I))!==null;){I=v[3];p.push(v[1]);if(v[2]){S=v[3];break}}if(p.length>1&&r.exec(g))if(p.length===2&&n.relative[p[0]])t=ga(p[0]+p[1],h);else for(t=n.relative[p[0]]?[h]:k(p.shift(),h);p.length;){g=p.shift();if(n.relative[g])g+=p.shift(); -t=ga(g,t)}else{if(!m&&p.length>1&&h.nodeType===9&&!M&&n.match.ID.test(p[0])&&!n.match.ID.test(p[p.length-1])){v=k.find(p.shift(),h,M);h=v.expr?k.filter(v.expr,v.set)[0]:v.set[0]}if(h){v=m?{expr:p.pop(),set:z(m)}:k.find(p.pop(),p.length===1&&(p[0]==="~"||p[0]==="+")&&h.parentNode?h.parentNode:h,M);t=v.expr?k.filter(v.expr,v.set):v.set;if(p.length>0)y=z(t);else H=false;for(;p.length;){var D=p.pop();v=D;if(n.relative[D])v=p.pop();else D="";if(v==null)v=h;n.relative[D](y,v,M)}}else y=[]}y||(y=t);y||k.error(D|| -g);if(j.call(y)==="[object Array]")if(H)if(h&&h.nodeType===1)for(g=0;y[g]!=null;g++){if(y[g]&&(y[g]===true||y[g].nodeType===1&&E(h,y[g])))l.push(t[g])}else for(g=0;y[g]!=null;g++)y[g]&&y[g].nodeType===1&&l.push(t[g]);else l.push.apply(l,y);else z(y,l);if(S){k(S,q,l,m);k.uniqueSort(l)}return l};k.uniqueSort=function(g){if(B){i=o;g.sort(B);if(i)for(var h=1;h":function(g,h){var l=typeof h==="string";if(l&&!/\W/.test(h)){h=h.toLowerCase();for(var m=0,q=g.length;m=0))l||m.push(v);else if(l)h[p]=false;return false},ID:function(g){return g[1].replace(/\\/g,"")},TAG:function(g){return g[1].toLowerCase()}, -CHILD:function(g){if(g[1]==="nth"){var h=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(g[2]==="even"&&"2n"||g[2]==="odd"&&"2n+1"||!/\D/.test(g[2])&&"0n+"+g[2]||g[2]);g[2]=h[1]+(h[2]||1)-0;g[3]=h[3]-0}g[0]=e++;return g},ATTR:function(g,h,l,m,q,p){h=g[1].replace(/\\/g,"");if(!p&&n.attrMap[h])g[1]=n.attrMap[h];if(g[2]==="~=")g[4]=" "+g[4]+" ";return g},PSEUDO:function(g,h,l,m,q){if(g[1]==="not")if((f.exec(g[3])||"").length>1||/^\w/.test(g[3]))g[3]=k(g[3],null,null,h);else{g=k.filter(g[3],h,l,true^q);l||m.push.apply(m, -g);return false}else if(n.match.POS.test(g[0])||n.match.CHILD.test(g[0]))return true;return g},POS:function(g){g.unshift(true);return g}},filters:{enabled:function(g){return g.disabled===false&&g.type!=="hidden"},disabled:function(g){return g.disabled===true},checked:function(g){return g.checked===true},selected:function(g){return g.selected===true},parent:function(g){return!!g.firstChild},empty:function(g){return!g.firstChild},has:function(g,h,l){return!!k(l[3],g).length},header:function(g){return/h\d/i.test(g.nodeName)}, -text:function(g){return"text"===g.type},radio:function(g){return"radio"===g.type},checkbox:function(g){return"checkbox"===g.type},file:function(g){return"file"===g.type},password:function(g){return"password"===g.type},submit:function(g){return"submit"===g.type},image:function(g){return"image"===g.type},reset:function(g){return"reset"===g.type},button:function(g){return"button"===g.type||g.nodeName.toLowerCase()==="button"},input:function(g){return/input|select|textarea|button/i.test(g.nodeName)}}, -setFilters:{first:function(g,h){return h===0},last:function(g,h,l,m){return h===m.length-1},even:function(g,h){return h%2===0},odd:function(g,h){return h%2===1},lt:function(g,h,l){return hl[3]-0},nth:function(g,h,l){return l[3]-0===h},eq:function(g,h,l){return l[3]-0===h}},filter:{PSEUDO:function(g,h,l,m){var q=h[1],p=n.filters[q];if(p)return p(g,l,h,m);else if(q==="contains")return(g.textContent||g.innerText||a([g])||"").indexOf(h[3])>=0;else if(q==="not"){h= -h[3];l=0;for(m=h.length;l=0}},ID:function(g,h){return g.nodeType===1&&g.getAttribute("id")===h},TAG:function(g,h){return h==="*"&&g.nodeType===1||g.nodeName.toLowerCase()===h},CLASS:function(g,h){return(" "+(g.className||g.getAttribute("class"))+" ").indexOf(h)>-1},ATTR:function(g,h){var l=h[1];g=n.attrHandle[l]?n.attrHandle[l](g):g[l]!=null?g[l]:g.getAttribute(l);l=g+"";var m=h[2];h=h[4];return g==null?m==="!=":m=== -"="?l===h:m==="*="?l.indexOf(h)>=0:m==="~="?(" "+l+" ").indexOf(h)>=0:!h?l&&g!==false:m==="!="?l!==h:m==="^="?l.indexOf(h)===0:m==="$="?l.substr(l.length-h.length)===h:m==="|="?l===h||l.substr(0,h.length+1)===h+"-":false},POS:function(g,h,l,m){var q=n.setFilters[h[2]];if(q)return q(g,l,h,m)}}},r=n.match.POS;for(var u in n.match){n.match[u]=new RegExp(n.match[u].source+/(?![^\[]*\])(?![^\(]*\))/.source);n.leftMatch[u]=new RegExp(/(^(?:.|\r|\n)*?)/.source+n.match[u].source.replace(/\\(\d+)/g,function(g, -h){return"\\"+(h-0+1)}))}var z=function(g,h){g=Array.prototype.slice.call(g,0);if(h){h.push.apply(h,g);return h}return g};try{Array.prototype.slice.call(s.documentElement.childNodes,0)}catch(C){z=function(g,h){h=h||[];if(j.call(g)==="[object Array]")Array.prototype.push.apply(h,g);else if(typeof g.length==="number")for(var l=0,m=g.length;l";var l=s.documentElement;l.insertBefore(g,l.firstChild);if(s.getElementById(h)){n.find.ID=function(m,q,p){if(typeof q.getElementById!=="undefined"&&!p)return(q=q.getElementById(m[1]))?q.id===m[1]||typeof q.getAttributeNode!=="undefined"&& -q.getAttributeNode("id").nodeValue===m[1]?[q]:w:[]};n.filter.ID=function(m,q){var p=typeof m.getAttributeNode!=="undefined"&&m.getAttributeNode("id");return m.nodeType===1&&p&&p.nodeValue===q}}l.removeChild(g);l=g=null})();(function(){var g=s.createElement("div");g.appendChild(s.createComment(""));if(g.getElementsByTagName("*").length>0)n.find.TAG=function(h,l){l=l.getElementsByTagName(h[1]);if(h[1]==="*"){h=[];for(var m=0;l[m];m++)l[m].nodeType===1&&h.push(l[m]);l=h}return l};g.innerHTML=""; -if(g.firstChild&&typeof g.firstChild.getAttribute!=="undefined"&&g.firstChild.getAttribute("href")!=="#")n.attrHandle.href=function(h){return h.getAttribute("href",2)};g=null})();s.querySelectorAll&&function(){var g=k,h=s.createElement("div");h.innerHTML="

";if(!(h.querySelectorAll&&h.querySelectorAll(".TEST").length===0)){k=function(m,q,p,v){q=q||s;if(!v&&q.nodeType===9&&!x(q))try{return z(q.querySelectorAll(m),p)}catch(t){}return g(m,q,p,v)};for(var l in g)k[l]=g[l];h=null}}(); -(function(){var g=s.createElement("div");g.innerHTML="
";if(!(!g.getElementsByClassName||g.getElementsByClassName("e").length===0)){g.lastChild.className="e";if(g.getElementsByClassName("e").length!==1){n.order.splice(1,0,"CLASS");n.find.CLASS=function(h,l,m){if(typeof l.getElementsByClassName!=="undefined"&&!m)return l.getElementsByClassName(h[1])};g=null}}})();var E=s.compareDocumentPosition?function(g,h){return!!(g.compareDocumentPosition(h)&16)}: -function(g,h){return g!==h&&(g.contains?g.contains(h):true)},x=function(g){return(g=(g?g.ownerDocument||g:0).documentElement)?g.nodeName!=="HTML":false},ga=function(g,h){var l=[],m="",q;for(h=h.nodeType?[h]:h;q=n.match.PSEUDO.exec(g);){m+=q[0];g=g.replace(n.match.PSEUDO,"")}g=n.relative[g]?g+"*":g;q=0;for(var p=h.length;q=0===d})};c.fn.extend({find:function(a){for(var b=this.pushStack("","find",a),d=0,f=0,e=this.length;f0)for(var j=d;j0},closest:function(a,b){if(c.isArray(a)){var d=[],f=this[0],e,j= -{},i;if(f&&a.length){e=0;for(var o=a.length;e-1:c(f).is(e)){d.push({selector:i,elem:f});delete j[i]}}f=f.parentNode}}return d}var k=c.expr.match.POS.test(a)?c(a,b||this.context):null;return this.map(function(n,r){for(;r&&r.ownerDocument&&r!==b;){if(k?k.index(r)>-1:c(r).is(a))return r;r=r.parentNode}return null})},index:function(a){if(!a||typeof a=== -"string")return c.inArray(this[0],a?c(a):this.parent().children());return c.inArray(a.jquery?a[0]:a,this)},add:function(a,b){a=typeof a==="string"?c(a,b||this.context):c.makeArray(a);b=c.merge(this.get(),a);return this.pushStack(qa(a[0])||qa(b[0])?b:c.unique(b))},andSelf:function(){return this.add(this.prevObject)}});c.each({parent:function(a){return(a=a.parentNode)&&a.nodeType!==11?a:null},parents:function(a){return c.dir(a,"parentNode")},parentsUntil:function(a,b,d){return c.dir(a,"parentNode", -d)},next:function(a){return c.nth(a,2,"nextSibling")},prev:function(a){return c.nth(a,2,"previousSibling")},nextAll:function(a){return c.dir(a,"nextSibling")},prevAll:function(a){return c.dir(a,"previousSibling")},nextUntil:function(a,b,d){return c.dir(a,"nextSibling",d)},prevUntil:function(a,b,d){return c.dir(a,"previousSibling",d)},siblings:function(a){return c.sibling(a.parentNode.firstChild,a)},children:function(a){return c.sibling(a.firstChild)},contents:function(a){return c.nodeName(a,"iframe")? -a.contentDocument||a.contentWindow.document:c.makeArray(a.childNodes)}},function(a,b){c.fn[a]=function(d,f){var e=c.map(this,b,d);eb.test(a)||(f=d);if(f&&typeof f==="string")e=c.filter(f,e);e=this.length>1?c.unique(e):e;if((this.length>1||gb.test(f))&&fb.test(a))e=e.reverse();return this.pushStack(e,a,R.call(arguments).join(","))}});c.extend({filter:function(a,b,d){if(d)a=":not("+a+")";return c.find.matches(a,b)},dir:function(a,b,d){var f=[];for(a=a[b];a&&a.nodeType!==9&&(d===w||a.nodeType!==1||!c(a).is(d));){a.nodeType=== -1&&f.push(a);a=a[b]}return f},nth:function(a,b,d){b=b||1;for(var f=0;a;a=a[d])if(a.nodeType===1&&++f===b)break;return a},sibling:function(a,b){for(var d=[];a;a=a.nextSibling)a.nodeType===1&&a!==b&&d.push(a);return d}});var Ja=/ jQuery\d+="(?:\d+|null)"/g,V=/^\s+/,Ka=/(<([\w:]+)[^>]*?)\/>/g,hb=/^(?:area|br|col|embed|hr|img|input|link|meta|param)$/i,La=/<([\w:]+)/,ib=/"},F={option:[1,""],legend:[1,"
","
"],thead:[1,"","
"],tr:[2,"","
"],td:[3,"","
"],col:[2,"","
"],area:[1,"",""],_default:[0,"",""]};F.optgroup=F.option;F.tbody=F.tfoot=F.colgroup=F.caption=F.thead;F.th=F.td;if(!c.support.htmlSerialize)F._default=[1,"div
","
"];c.fn.extend({text:function(a){if(c.isFunction(a))return this.each(function(b){var d= -c(this);d.text(a.call(this,b,d.text()))});if(typeof a!=="object"&&a!==w)return this.empty().append((this[0]&&this[0].ownerDocument||s).createTextNode(a));return c.text(this)},wrapAll:function(a){if(c.isFunction(a))return this.each(function(d){c(this).wrapAll(a.call(this,d))});if(this[0]){var b=c(a,this[0].ownerDocument).eq(0).clone(true);this[0].parentNode&&b.insertBefore(this[0]);b.map(function(){for(var d=this;d.firstChild&&d.firstChild.nodeType===1;)d=d.firstChild;return d}).append(this)}return this}, -wrapInner:function(a){if(c.isFunction(a))return this.each(function(b){c(this).wrapInner(a.call(this,b))});return this.each(function(){var b=c(this),d=b.contents();d.length?d.wrapAll(a):b.append(a)})},wrap:function(a){return this.each(function(){c(this).wrapAll(a)})},unwrap:function(){return this.parent().each(function(){c.nodeName(this,"body")||c(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.appendChild(a)})}, -prepend:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b,this)});else if(arguments.length){var a=c(arguments[0]);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b, -this.nextSibling)});else if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,c(arguments[0]).toArray());return a}},remove:function(a,b){for(var d=0,f;(f=this[d])!=null;d++)if(!a||c.filter(a,[f]).length){if(!b&&f.nodeType===1){c.cleanData(f.getElementsByTagName("*"));c.cleanData([f])}f.parentNode&&f.parentNode.removeChild(f)}return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++)for(b.nodeType===1&&c.cleanData(b.getElementsByTagName("*"));b.firstChild;)b.removeChild(b.firstChild); -return this},clone:function(a){var b=this.map(function(){if(!c.support.noCloneEvent&&!c.isXMLDoc(this)){var d=this.outerHTML,f=this.ownerDocument;if(!d){d=f.createElement("div");d.appendChild(this.cloneNode(true));d=d.innerHTML}return c.clean([d.replace(Ja,"").replace(/=([^="'>\s]+\/)>/g,'="$1">').replace(V,"")],f)[0]}else return this.cloneNode(true)});if(a===true){ra(this,b);ra(this.find("*"),b.find("*"))}return b},html:function(a){if(a===w)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(Ja, -""):null;else if(typeof a==="string"&&!ta.test(a)&&(c.support.leadingWhitespace||!V.test(a))&&!F[(La.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Ka,Ma);try{for(var b=0,d=this.length;b0||e.cacheable||this.length>1?k.cloneNode(true):k)}o.length&&c.each(o,Qa)}return this}});c.fragments={};c.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){c.fn[a]=function(d){var f=[];d=c(d);var e=this.length===1&&this[0].parentNode;if(e&&e.nodeType===11&&e.childNodes.length===1&&d.length===1){d[b](this[0]); -return this}else{e=0;for(var j=d.length;e0?this.clone(true):this).get();c.fn[b].apply(c(d[e]),i);f=f.concat(i)}return this.pushStack(f,a,d.selector)}}});c.extend({clean:function(a,b,d,f){b=b||s;if(typeof b.createElement==="undefined")b=b.ownerDocument||b[0]&&b[0].ownerDocument||s;for(var e=[],j=0,i;(i=a[j])!=null;j++){if(typeof i==="number")i+="";if(i){if(typeof i==="string"&&!jb.test(i))i=b.createTextNode(i);else if(typeof i==="string"){i=i.replace(Ka,Ma);var o=(La.exec(i)||["", -""])[1].toLowerCase(),k=F[o]||F._default,n=k[0],r=b.createElement("div");for(r.innerHTML=k[1]+i+k[2];n--;)r=r.lastChild;if(!c.support.tbody){n=ib.test(i);o=o==="table"&&!n?r.firstChild&&r.firstChild.childNodes:k[1]===""&&!n?r.childNodes:[];for(k=o.length-1;k>=0;--k)c.nodeName(o[k],"tbody")&&!o[k].childNodes.length&&o[k].parentNode.removeChild(o[k])}!c.support.leadingWhitespace&&V.test(i)&&r.insertBefore(b.createTextNode(V.exec(i)[0]),r.firstChild);i=r.childNodes}if(i.nodeType)e.push(i);else e= -c.merge(e,i)}}if(d)for(j=0;e[j];j++)if(f&&c.nodeName(e[j],"script")&&(!e[j].type||e[j].type.toLowerCase()==="text/javascript"))f.push(e[j].parentNode?e[j].parentNode.removeChild(e[j]):e[j]);else{e[j].nodeType===1&&e.splice.apply(e,[j+1,0].concat(c.makeArray(e[j].getElementsByTagName("script"))));d.appendChild(e[j])}return e},cleanData:function(a){for(var b,d,f=c.cache,e=c.event.special,j=c.support.deleteExpando,i=0,o;(o=a[i])!=null;i++)if(d=o[c.expando]){b=f[d];if(b.events)for(var k in b.events)e[k]? -c.event.remove(o,k):Ca(o,k,b.handle);if(j)delete o[c.expando];else o.removeAttribute&&o.removeAttribute(c.expando);delete f[d]}}});var kb=/z-?index|font-?weight|opacity|zoom|line-?height/i,Na=/alpha\([^)]*\)/,Oa=/opacity=([^)]*)/,ha=/float/i,ia=/-([a-z])/ig,lb=/([A-Z])/g,mb=/^-?\d+(?:px)?$/i,nb=/^-?\d/,ob={position:"absolute",visibility:"hidden",display:"block"},pb=["Left","Right"],qb=["Top","Bottom"],rb=s.defaultView&&s.defaultView.getComputedStyle,Pa=c.support.cssFloat?"cssFloat":"styleFloat",ja= -function(a,b){return b.toUpperCase()};c.fn.css=function(a,b){return X(this,a,b,true,function(d,f,e){if(e===w)return c.curCSS(d,f);if(typeof e==="number"&&!kb.test(f))e+="px";c.style(d,f,e)})};c.extend({style:function(a,b,d){if(!a||a.nodeType===3||a.nodeType===8)return w;if((b==="width"||b==="height")&&parseFloat(d)<0)d=w;var f=a.style||a,e=d!==w;if(!c.support.opacity&&b==="opacity"){if(e){f.zoom=1;b=parseInt(d,10)+""==="NaN"?"":"alpha(opacity="+d*100+")";a=f.filter||c.curCSS(a,"filter")||"";f.filter= -Na.test(a)?a.replace(Na,b):b}return f.filter&&f.filter.indexOf("opacity=")>=0?parseFloat(Oa.exec(f.filter)[1])/100+"":""}if(ha.test(b))b=Pa;b=b.replace(ia,ja);if(e)f[b]=d;return f[b]},css:function(a,b,d,f){if(b==="width"||b==="height"){var e,j=b==="width"?pb:qb;function i(){e=b==="width"?a.offsetWidth:a.offsetHeight;f!=="border"&&c.each(j,function(){f||(e-=parseFloat(c.curCSS(a,"padding"+this,true))||0);if(f==="margin")e+=parseFloat(c.curCSS(a,"margin"+this,true))||0;else e-=parseFloat(c.curCSS(a, -"border"+this+"Width",true))||0})}a.offsetWidth!==0?i():c.swap(a,ob,i);return Math.max(0,Math.round(e))}return c.curCSS(a,b,d)},curCSS:function(a,b,d){var f,e=a.style;if(!c.support.opacity&&b==="opacity"&&a.currentStyle){f=Oa.test(a.currentStyle.filter||"")?parseFloat(RegExp.$1)/100+"":"";return f===""?"1":f}if(ha.test(b))b=Pa;if(!d&&e&&e[b])f=e[b];else if(rb){if(ha.test(b))b="float";b=b.replace(lb,"-$1").toLowerCase();e=a.ownerDocument.defaultView;if(!e)return null;if(a=e.getComputedStyle(a,null))f= -a.getPropertyValue(b);if(b==="opacity"&&f==="")f="1"}else if(a.currentStyle){d=b.replace(ia,ja);f=a.currentStyle[b]||a.currentStyle[d];if(!mb.test(f)&&nb.test(f)){b=e.left;var j=a.runtimeStyle.left;a.runtimeStyle.left=a.currentStyle.left;e.left=d==="fontSize"?"1em":f||0;f=e.pixelLeft+"px";e.left=b;a.runtimeStyle.left=j}}return f},swap:function(a,b,d){var f={};for(var e in b){f[e]=a.style[e];a.style[e]=b[e]}d.call(a);for(e in b)a.style[e]=f[e]}});if(c.expr&&c.expr.filters){c.expr.filters.hidden=function(a){var b= -a.offsetWidth,d=a.offsetHeight,f=a.nodeName.toLowerCase()==="tr";return b===0&&d===0&&!f?true:b>0&&d>0&&!f?false:c.curCSS(a,"display")==="none"};c.expr.filters.visible=function(a){return!c.expr.filters.hidden(a)}}var sb=J(),tb=//gi,ub=/select|textarea/i,vb=/color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week/i,N=/=\?(&|$)/,ka=/\?/,wb=/(\?|&)_=.*?(&|$)/,xb=/^(\w+:)?\/\/([^\/?#]+)/,yb=/%20/g,zb=c.fn.load;c.fn.extend({load:function(a,b,d){if(typeof a!== -"string")return zb.call(this,a);else if(!this.length)return this;var f=a.indexOf(" ");if(f>=0){var e=a.slice(f,a.length);a=a.slice(0,f)}f="GET";if(b)if(c.isFunction(b)){d=b;b=null}else if(typeof b==="object"){b=c.param(b,c.ajaxSettings.traditional);f="POST"}var j=this;c.ajax({url:a,type:f,dataType:"html",data:b,complete:function(i,o){if(o==="success"||o==="notmodified")j.html(e?c("
").append(i.responseText.replace(tb,"")).find(e):i.responseText);d&&j.each(d,[i.responseText,o,i])}});return this}, -serialize:function(){return c.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?c.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||ub.test(this.nodeName)||vb.test(this.type))}).map(function(a,b){a=c(this).val();return a==null?null:c.isArray(a)?c.map(a,function(d){return{name:b.name,value:d}}):{name:b.name,value:a}}).get()}});c.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "), -function(a,b){c.fn[b]=function(d){return this.bind(b,d)}});c.extend({get:function(a,b,d,f){if(c.isFunction(b)){f=f||d;d=b;b=null}return c.ajax({type:"GET",url:a,data:b,success:d,dataType:f})},getScript:function(a,b){return c.get(a,null,b,"script")},getJSON:function(a,b,d){return c.get(a,b,d,"json")},post:function(a,b,d,f){if(c.isFunction(b)){f=f||d;d=b;b={}}return c.ajax({type:"POST",url:a,data:b,success:d,dataType:f})},ajaxSetup:function(a){c.extend(c.ajaxSettings,a)},ajaxSettings:{url:location.href, -global:true,type:"GET",contentType:"application/x-www-form-urlencoded",processData:true,async:true,xhr:A.XMLHttpRequest&&(A.location.protocol!=="file:"||!A.ActiveXObject)?function(){return new A.XMLHttpRequest}:function(){try{return new A.ActiveXObject("Microsoft.XMLHTTP")}catch(a){}},accepts:{xml:"application/xml, text/xml",html:"text/html",script:"text/javascript, application/javascript",json:"application/json, text/javascript",text:"text/plain",_default:"*/*"}},lastModified:{},etag:{},ajax:function(a){function b(){e.success&& -e.success.call(k,o,i,x);e.global&&f("ajaxSuccess",[x,e])}function d(){e.complete&&e.complete.call(k,x,i);e.global&&f("ajaxComplete",[x,e]);e.global&&!--c.active&&c.event.trigger("ajaxStop")}function f(q,p){(e.context?c(e.context):c.event).trigger(q,p)}var e=c.extend(true,{},c.ajaxSettings,a),j,i,o,k=a&&a.context||e,n=e.type.toUpperCase();if(e.data&&e.processData&&typeof e.data!=="string")e.data=c.param(e.data,e.traditional);if(e.dataType==="jsonp"){if(n==="GET")N.test(e.url)||(e.url+=(ka.test(e.url)? -"&":"?")+(e.jsonp||"callback")+"=?");else if(!e.data||!N.test(e.data))e.data=(e.data?e.data+"&":"")+(e.jsonp||"callback")+"=?";e.dataType="json"}if(e.dataType==="json"&&(e.data&&N.test(e.data)||N.test(e.url))){j=e.jsonpCallback||"jsonp"+sb++;if(e.data)e.data=(e.data+"").replace(N,"="+j+"$1");e.url=e.url.replace(N,"="+j+"$1");e.dataType="script";A[j]=A[j]||function(q){o=q;b();d();A[j]=w;try{delete A[j]}catch(p){}z&&z.removeChild(C)}}if(e.dataType==="script"&&e.cache===null)e.cache=false;if(e.cache=== -false&&n==="GET"){var r=J(),u=e.url.replace(wb,"$1_="+r+"$2");e.url=u+(u===e.url?(ka.test(e.url)?"&":"?")+"_="+r:"")}if(e.data&&n==="GET")e.url+=(ka.test(e.url)?"&":"?")+e.data;e.global&&!c.active++&&c.event.trigger("ajaxStart");r=(r=xb.exec(e.url))&&(r[1]&&r[1]!==location.protocol||r[2]!==location.host);if(e.dataType==="script"&&n==="GET"&&r){var z=s.getElementsByTagName("head")[0]||s.documentElement,C=s.createElement("script");C.src=e.url;if(e.scriptCharset)C.charset=e.scriptCharset;if(!j){var B= -false;C.onload=C.onreadystatechange=function(){if(!B&&(!this.readyState||this.readyState==="loaded"||this.readyState==="complete")){B=true;b();d();C.onload=C.onreadystatechange=null;z&&C.parentNode&&z.removeChild(C)}}}z.insertBefore(C,z.firstChild);return w}var E=false,x=e.xhr();if(x){e.username?x.open(n,e.url,e.async,e.username,e.password):x.open(n,e.url,e.async);try{if(e.data||a&&a.contentType)x.setRequestHeader("Content-Type",e.contentType);if(e.ifModified){c.lastModified[e.url]&&x.setRequestHeader("If-Modified-Since", -c.lastModified[e.url]);c.etag[e.url]&&x.setRequestHeader("If-None-Match",c.etag[e.url])}r||x.setRequestHeader("X-Requested-With","XMLHttpRequest");x.setRequestHeader("Accept",e.dataType&&e.accepts[e.dataType]?e.accepts[e.dataType]+", */*":e.accepts._default)}catch(ga){}if(e.beforeSend&&e.beforeSend.call(k,x,e)===false){e.global&&!--c.active&&c.event.trigger("ajaxStop");x.abort();return false}e.global&&f("ajaxSend",[x,e]);var g=x.onreadystatechange=function(q){if(!x||x.readyState===0||q==="abort"){E|| -d();E=true;if(x)x.onreadystatechange=c.noop}else if(!E&&x&&(x.readyState===4||q==="timeout")){E=true;x.onreadystatechange=c.noop;i=q==="timeout"?"timeout":!c.httpSuccess(x)?"error":e.ifModified&&c.httpNotModified(x,e.url)?"notmodified":"success";var p;if(i==="success")try{o=c.httpData(x,e.dataType,e)}catch(v){i="parsererror";p=v}if(i==="success"||i==="notmodified")j||b();else c.handleError(e,x,i,p);d();q==="timeout"&&x.abort();if(e.async)x=null}};try{var h=x.abort;x.abort=function(){x&&h.call(x); -g("abort")}}catch(l){}e.async&&e.timeout>0&&setTimeout(function(){x&&!E&&g("timeout")},e.timeout);try{x.send(n==="POST"||n==="PUT"||n==="DELETE"?e.data:null)}catch(m){c.handleError(e,x,null,m);d()}e.async||g();return x}},handleError:function(a,b,d,f){if(a.error)a.error.call(a.context||a,b,d,f);if(a.global)(a.context?c(a.context):c.event).trigger("ajaxError",[b,a,f])},active:0,httpSuccess:function(a){try{return!a.status&&location.protocol==="file:"||a.status>=200&&a.status<300||a.status===304||a.status=== -1223||a.status===0}catch(b){}return false},httpNotModified:function(a,b){var d=a.getResponseHeader("Last-Modified"),f=a.getResponseHeader("Etag");if(d)c.lastModified[b]=d;if(f)c.etag[b]=f;return a.status===304||a.status===0},httpData:function(a,b,d){var f=a.getResponseHeader("content-type")||"",e=b==="xml"||!b&&f.indexOf("xml")>=0;a=e?a.responseXML:a.responseText;e&&a.documentElement.nodeName==="parsererror"&&c.error("parsererror");if(d&&d.dataFilter)a=d.dataFilter(a,b);if(typeof a==="string")if(b=== -"json"||!b&&f.indexOf("json")>=0)a=c.parseJSON(a);else if(b==="script"||!b&&f.indexOf("javascript")>=0)c.globalEval(a);return a},param:function(a,b){function d(i,o){if(c.isArray(o))c.each(o,function(k,n){b||/\[\]$/.test(i)?f(i,n):d(i+"["+(typeof n==="object"||c.isArray(n)?k:"")+"]",n)});else!b&&o!=null&&typeof o==="object"?c.each(o,function(k,n){d(i+"["+k+"]",n)}):f(i,o)}function f(i,o){o=c.isFunction(o)?o():o;e[e.length]=encodeURIComponent(i)+"="+encodeURIComponent(o)}var e=[];if(b===w)b=c.ajaxSettings.traditional; -if(c.isArray(a)||a.jquery)c.each(a,function(){f(this.name,this.value)});else for(var j in a)d(j,a[j]);return e.join("&").replace(yb,"+")}});var la={},Ab=/toggle|show|hide/,Bb=/^([+-]=)?([\d+-.]+)(.*)$/,W,va=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]];c.fn.extend({show:function(a,b){if(a||a===0)return this.animate(K("show",3),a,b);else{a=0;for(b=this.length;a").appendTo("body");f=e.css("display");if(f==="none")f="block";e.remove();la[d]=f}c.data(this[a],"olddisplay",f)}}a=0;for(b=this.length;a=0;f--)if(d[f].elem===this){b&&d[f](true);d.splice(f,1)}});b||this.dequeue();return this}});c.each({slideDown:K("show",1),slideUp:K("hide",1),slideToggle:K("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"}},function(a,b){c.fn[a]=function(d,f){return this.animate(b,d,f)}});c.extend({speed:function(a,b,d){var f=a&&typeof a==="object"?a:{complete:d||!d&&b||c.isFunction(a)&&a,duration:a,easing:d&&b||b&&!c.isFunction(b)&&b};f.duration=c.fx.off?0:typeof f.duration=== -"number"?f.duration:c.fx.speeds[f.duration]||c.fx.speeds._default;f.old=f.complete;f.complete=function(){f.queue!==false&&c(this).dequeue();c.isFunction(f.old)&&f.old.call(this)};return f},easing:{linear:function(a,b,d,f){return d+f*a},swing:function(a,b,d,f){return(-Math.cos(a*Math.PI)/2+0.5)*f+d}},timers:[],fx:function(a,b,d){this.options=b;this.elem=a;this.prop=d;if(!b.orig)b.orig={}}});c.fx.prototype={update:function(){this.options.step&&this.options.step.call(this.elem,this.now,this);(c.fx.step[this.prop]|| -c.fx.step._default)(this);if((this.prop==="height"||this.prop==="width")&&this.elem.style)this.elem.style.display="block"},cur:function(a){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null))return this.elem[this.prop];return(a=parseFloat(c.css(this.elem,this.prop,a)))&&a>-10000?a:parseFloat(c.curCSS(this.elem,this.prop))||0},custom:function(a,b,d){function f(j){return e.step(j)}this.startTime=J();this.start=a;this.end=b;this.unit=d||this.unit||"px";this.now=this.start; -this.pos=this.state=0;var e=this;f.elem=this.elem;if(f()&&c.timers.push(f)&&!W)W=setInterval(c.fx.tick,13)},show:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.show=true;this.custom(this.prop==="width"||this.prop==="height"?1:0,this.cur());c(this.elem).show()},hide:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.hide=true;this.custom(this.cur(),0)},step:function(a){var b=J(),d=true;if(a||b>=this.options.duration+this.startTime){this.now= -this.end;this.pos=this.state=1;this.update();this.options.curAnim[this.prop]=true;for(var f in this.options.curAnim)if(this.options.curAnim[f]!==true)d=false;if(d){if(this.options.display!=null){this.elem.style.overflow=this.options.overflow;a=c.data(this.elem,"olddisplay");this.elem.style.display=a?a:this.options.display;if(c.css(this.elem,"display")==="none")this.elem.style.display="block"}this.options.hide&&c(this.elem).hide();if(this.options.hide||this.options.show)for(var e in this.options.curAnim)c.style(this.elem, -e,this.options.orig[e]);this.options.complete.call(this.elem)}return false}else{e=b-this.startTime;this.state=e/this.options.duration;a=this.options.easing||(c.easing.swing?"swing":"linear");this.pos=c.easing[this.options.specialEasing&&this.options.specialEasing[this.prop]||a](this.state,e,0,1,this.options.duration);this.now=this.start+(this.end-this.start)*this.pos;this.update()}return true}};c.extend(c.fx,{tick:function(){for(var a=c.timers,b=0;b
"; -a.insertBefore(b,a.firstChild);d=b.firstChild;f=d.firstChild;e=d.nextSibling.firstChild.firstChild;this.doesNotAddBorder=f.offsetTop!==5;this.doesAddBorderForTableAndCells=e.offsetTop===5;f.style.position="fixed";f.style.top="20px";this.supportsFixedPosition=f.offsetTop===20||f.offsetTop===15;f.style.position=f.style.top="";d.style.overflow="hidden";d.style.position="relative";this.subtractsBorderForOverflowNotVisible=f.offsetTop===-5;this.doesNotIncludeMarginInBodyOffset=a.offsetTop!==j;a.removeChild(b); -c.offset.initialize=c.noop},bodyOffset:function(a){var b=a.offsetTop,d=a.offsetLeft;c.offset.initialize();if(c.offset.doesNotIncludeMarginInBodyOffset){b+=parseFloat(c.curCSS(a,"marginTop",true))||0;d+=parseFloat(c.curCSS(a,"marginLeft",true))||0}return{top:b,left:d}},setOffset:function(a,b,d){if(/static/.test(c.curCSS(a,"position")))a.style.position="relative";var f=c(a),e=f.offset(),j=parseInt(c.curCSS(a,"top",true),10)||0,i=parseInt(c.curCSS(a,"left",true),10)||0;if(c.isFunction(b))b=b.call(a, -d,e);d={top:b.top-e.top+j,left:b.left-e.left+i};"using"in b?b.using.call(a,d):f.css(d)}};c.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),d=this.offset(),f=/^body|html$/i.test(b[0].nodeName)?{top:0,left:0}:b.offset();d.top-=parseFloat(c.curCSS(a,"marginTop",true))||0;d.left-=parseFloat(c.curCSS(a,"marginLeft",true))||0;f.top+=parseFloat(c.curCSS(b[0],"borderTopWidth",true))||0;f.left+=parseFloat(c.curCSS(b[0],"borderLeftWidth",true))||0;return{top:d.top- -f.top,left:d.left-f.left}},offsetParent:function(){return this.map(function(){for(var a=this.offsetParent||s.body;a&&!/^body|html$/i.test(a.nodeName)&&c.css(a,"position")==="static";)a=a.offsetParent;return a})}});c.each(["Left","Top"],function(a,b){var d="scroll"+b;c.fn[d]=function(f){var e=this[0],j;if(!e)return null;if(f!==w)return this.each(function(){if(j=wa(this))j.scrollTo(!a?f:c(j).scrollLeft(),a?f:c(j).scrollTop());else this[d]=f});else return(j=wa(e))?"pageXOffset"in j?j[a?"pageYOffset": -"pageXOffset"]:c.support.boxModel&&j.document.documentElement[d]||j.document.body[d]:e[d]}});c.each(["Height","Width"],function(a,b){var d=b.toLowerCase();c.fn["inner"+b]=function(){return this[0]?c.css(this[0],d,false,"padding"):null};c.fn["outer"+b]=function(f){return this[0]?c.css(this[0],d,false,f?"margin":"border"):null};c.fn[d]=function(f){var e=this[0];if(!e)return f==null?null:this;if(c.isFunction(f))return this.each(function(j){var i=c(this);i[d](f.call(this,j,i[d]()))});return"scrollTo"in -e&&e.document?e.document.compatMode==="CSS1Compat"&&e.document.documentElement["client"+b]||e.document.body["client"+b]:e.nodeType===9?Math.max(e.documentElement["client"+b],e.body["scroll"+b],e.documentElement["scroll"+b],e.body["offset"+b],e.documentElement["offset"+b]):f===w?c.css(e,d):this.css(d,typeof f==="string"?f:f+"px")}});A.jQuery=A.$=c})(window); diff --git a/web/skins/classic/js/jquery-1.7.2.js b/web/skins/classic/js/jquery-1.7.2.js new file mode 100644 index 000000000..3774ff986 --- /dev/null +++ b/web/skins/classic/js/jquery-1.7.2.js @@ -0,0 +1,9404 @@ +/*! + * jQuery JavaScript Library v1.7.2 + * http://jquery.com/ + * + * Copyright 2011, John Resig + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * Includes Sizzle.js + * http://sizzlejs.com/ + * Copyright 2011, The Dojo Foundation + * Released under the MIT, BSD, and GPL Licenses. + * + * Date: Wed Mar 21 12:46:34 2012 -0700 + */ +(function( window, undefined ) { + +// Use the correct document accordingly with window argument (sandbox) +var document = window.document, + navigator = window.navigator, + location = window.location; +var jQuery = (function() { + +// Define a local copy of jQuery +var jQuery = function( selector, context ) { + // The jQuery object is actually just the init constructor 'enhanced' + return new jQuery.fn.init( selector, context, rootjQuery ); + }, + + // Map over jQuery in case of overwrite + _jQuery = window.jQuery, + + // Map over the $ in case of overwrite + _$ = window.$, + + // A central reference to the root jQuery(document) + rootjQuery, + + // A simple way to check for HTML strings or ID strings + // Prioritize #id over to avoid XSS via location.hash (#9521) + quickExpr = /^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/, + + // Check if a string has a non-whitespace character in it + rnotwhite = /\S/, + + // Used for trimming whitespace + trimLeft = /^\s+/, + trimRight = /\s+$/, + + // Match a standalone tag + rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>)?$/, + + // JSON RegExp + rvalidchars = /^[\],:{}\s]*$/, + rvalidescape = /\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, + rvalidtokens = /"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, + rvalidbraces = /(?:^|:|,)(?:\s*\[)+/g, + + // Useragent RegExp + rwebkit = /(webkit)[ \/]([\w.]+)/, + ropera = /(opera)(?:.*version)?[ \/]([\w.]+)/, + rmsie = /(msie) ([\w.]+)/, + rmozilla = /(mozilla)(?:.*? rv:([\w.]+))?/, + + // Matches dashed string for camelizing + rdashAlpha = /-([a-z]|[0-9])/ig, + rmsPrefix = /^-ms-/, + + // Used by jQuery.camelCase as callback to replace() + fcamelCase = function( all, letter ) { + return ( letter + "" ).toUpperCase(); + }, + + // Keep a UserAgent string for use with jQuery.browser + userAgent = navigator.userAgent, + + // For matching the engine and version of the browser + browserMatch, + + // The deferred used on DOM ready + readyList, + + // The ready event handler + DOMContentLoaded, + + // Save a reference to some core methods + toString = Object.prototype.toString, + hasOwn = Object.prototype.hasOwnProperty, + push = Array.prototype.push, + slice = Array.prototype.slice, + trim = String.prototype.trim, + indexOf = Array.prototype.indexOf, + + // [[Class]] -> type pairs + class2type = {}; + +jQuery.fn = jQuery.prototype = { + constructor: jQuery, + init: function( selector, context, rootjQuery ) { + var match, elem, ret, doc; + + // Handle $(""), $(null), or $(undefined) + if ( !selector ) { + return this; + } + + // Handle $(DOMElement) + if ( selector.nodeType ) { + this.context = this[0] = selector; + this.length = 1; + return this; + } + + // The body element only exists once, optimize finding it + if ( selector === "body" && !context && document.body ) { + this.context = document; + this[0] = document.body; + this.selector = selector; + this.length = 1; + return this; + } + + // Handle HTML strings + if ( typeof selector === "string" ) { + // Are we dealing with HTML string or an ID? + if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) { + // Assume that strings that start and end with <> are HTML and skip the regex check + match = [ null, selector, null ]; + + } else { + match = quickExpr.exec( selector ); + } + + // Verify a match, and that no context was specified for #id + if ( match && (match[1] || !context) ) { + + // HANDLE: $(html) -> $(array) + if ( match[1] ) { + context = context instanceof jQuery ? context[0] : context; + doc = ( context ? context.ownerDocument || context : document ); + + // If a single string is passed in and it's a single tag + // just do a createElement and skip the rest + ret = rsingleTag.exec( selector ); + + if ( ret ) { + if ( jQuery.isPlainObject( context ) ) { + selector = [ document.createElement( ret[1] ) ]; + jQuery.fn.attr.call( selector, context, true ); + + } else { + selector = [ doc.createElement( ret[1] ) ]; + } + + } else { + ret = jQuery.buildFragment( [ match[1] ], [ doc ] ); + selector = ( ret.cacheable ? jQuery.clone(ret.fragment) : ret.fragment ).childNodes; + } + + return jQuery.merge( this, selector ); + + // HANDLE: $("#id") + } else { + elem = document.getElementById( match[2] ); + + // Check parentNode to catch when Blackberry 4.6 returns + // nodes that are no longer in the document #6963 + if ( elem && elem.parentNode ) { + // Handle the case where IE and Opera return items + // by name instead of ID + if ( elem.id !== match[2] ) { + return rootjQuery.find( selector ); + } + + // Otherwise, we inject the element directly into the jQuery object + this.length = 1; + this[0] = elem; + } + + this.context = document; + this.selector = selector; + return this; + } + + // HANDLE: $(expr, $(...)) + } else if ( !context || context.jquery ) { + return ( context || rootjQuery ).find( selector ); + + // HANDLE: $(expr, context) + // (which is just equivalent to: $(context).find(expr) + } else { + return this.constructor( context ).find( selector ); + } + + // HANDLE: $(function) + // Shortcut for document ready + } else if ( jQuery.isFunction( selector ) ) { + return rootjQuery.ready( selector ); + } + + if ( selector.selector !== undefined ) { + this.selector = selector.selector; + this.context = selector.context; + } + + return jQuery.makeArray( selector, this ); + }, + + // Start with an empty selector + selector: "", + + // The current version of jQuery being used + jquery: "1.7.2", + + // The default length of a jQuery object is 0 + length: 0, + + // The number of elements contained in the matched element set + size: function() { + return this.length; + }, + + toArray: function() { + return slice.call( this, 0 ); + }, + + // Get the Nth element in the matched element set OR + // Get the whole matched element set as a clean array + get: function( num ) { + return num == null ? + + // Return a 'clean' array + this.toArray() : + + // Return just the object + ( num < 0 ? this[ this.length + num ] : this[ num ] ); + }, + + // Take an array of elements and push it onto the stack + // (returning the new matched element set) + pushStack: function( elems, name, selector ) { + // Build a new jQuery matched element set + var ret = this.constructor(); + + if ( jQuery.isArray( elems ) ) { + push.apply( ret, elems ); + + } else { + jQuery.merge( ret, elems ); + } + + // Add the old object onto the stack (as a reference) + ret.prevObject = this; + + ret.context = this.context; + + if ( name === "find" ) { + ret.selector = this.selector + ( this.selector ? " " : "" ) + selector; + } else if ( name ) { + ret.selector = this.selector + "." + name + "(" + selector + ")"; + } + + // Return the newly-formed element set + return ret; + }, + + // Execute a callback for every element in the matched set. + // (You can seed the arguments with an array of args, but this is + // only used internally.) + each: function( callback, args ) { + return jQuery.each( this, callback, args ); + }, + + ready: function( fn ) { + // Attach the listeners + jQuery.bindReady(); + + // Add the callback + readyList.add( fn ); + + return this; + }, + + eq: function( i ) { + i = +i; + return i === -1 ? + this.slice( i ) : + this.slice( i, i + 1 ); + }, + + first: function() { + return this.eq( 0 ); + }, + + last: function() { + return this.eq( -1 ); + }, + + slice: function() { + return this.pushStack( slice.apply( this, arguments ), + "slice", slice.call(arguments).join(",") ); + }, + + map: function( callback ) { + return this.pushStack( jQuery.map(this, function( elem, i ) { + return callback.call( elem, i, elem ); + })); + }, + + end: function() { + return this.prevObject || this.constructor(null); + }, + + // For internal use only. + // Behaves like an Array's method, not like a jQuery method. + push: push, + sort: [].sort, + splice: [].splice +}; + +// Give the init function the jQuery prototype for later instantiation +jQuery.fn.init.prototype = jQuery.fn; + +jQuery.extend = jQuery.fn.extend = function() { + var options, name, src, copy, copyIsArray, clone, + target = arguments[0] || {}, + i = 1, + length = arguments.length, + deep = false; + + // Handle a deep copy situation + if ( typeof target === "boolean" ) { + deep = target; + target = arguments[1] || {}; + // skip the boolean and the target + i = 2; + } + + // Handle case when target is a string or something (possible in deep copy) + if ( typeof target !== "object" && !jQuery.isFunction(target) ) { + target = {}; + } + + // extend jQuery itself if only one argument is passed + if ( length === i ) { + target = this; + --i; + } + + for ( ; i < length; i++ ) { + // Only deal with non-null/undefined values + if ( (options = arguments[ i ]) != null ) { + // Extend the base object + for ( name in options ) { + src = target[ name ]; + copy = options[ name ]; + + // Prevent never-ending loop + if ( target === copy ) { + continue; + } + + // Recurse if we're merging plain objects or arrays + if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) { + if ( copyIsArray ) { + copyIsArray = false; + clone = src && jQuery.isArray(src) ? src : []; + + } else { + clone = src && jQuery.isPlainObject(src) ? src : {}; + } + + // Never move original objects, clone them + target[ name ] = jQuery.extend( deep, clone, copy ); + + // Don't bring in undefined values + } else if ( copy !== undefined ) { + target[ name ] = copy; + } + } + } + } + + // Return the modified object + return target; +}; + +jQuery.extend({ + noConflict: function( deep ) { + if ( window.$ === jQuery ) { + window.$ = _$; + } + + if ( deep && window.jQuery === jQuery ) { + window.jQuery = _jQuery; + } + + return jQuery; + }, + + // Is the DOM ready to be used? Set to true once it occurs. + isReady: false, + + // A counter to track how many items to wait for before + // the ready event fires. See #6781 + readyWait: 1, + + // Hold (or release) the ready event + holdReady: function( hold ) { + if ( hold ) { + jQuery.readyWait++; + } else { + jQuery.ready( true ); + } + }, + + // Handle when the DOM is ready + ready: function( wait ) { + // Either a released hold or an DOMready/load event and not yet ready + if ( (wait === true && !--jQuery.readyWait) || (wait !== true && !jQuery.isReady) ) { + // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443). + if ( !document.body ) { + return setTimeout( jQuery.ready, 1 ); + } + + // Remember that the DOM is ready + jQuery.isReady = true; + + // If a normal DOM Ready event fired, decrement, and wait if need be + if ( wait !== true && --jQuery.readyWait > 0 ) { + return; + } + + // If there are functions bound, to execute + readyList.fireWith( document, [ jQuery ] ); + + // Trigger any bound ready events + if ( jQuery.fn.trigger ) { + jQuery( document ).trigger( "ready" ).off( "ready" ); + } + } + }, + + bindReady: function() { + if ( readyList ) { + return; + } + + readyList = jQuery.Callbacks( "once memory" ); + + // Catch cases where $(document).ready() is called after the + // browser event has already occurred. + if ( document.readyState === "complete" ) { + // Handle it asynchronously to allow scripts the opportunity to delay ready + return setTimeout( jQuery.ready, 1 ); + } + + // Mozilla, Opera and webkit nightlies currently support this event + if ( document.addEventListener ) { + // Use the handy event callback + document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false ); + + // A fallback to window.onload, that will always work + window.addEventListener( "load", jQuery.ready, false ); + + // If IE event model is used + } else if ( document.attachEvent ) { + // ensure firing before onload, + // maybe late but safe also for iframes + document.attachEvent( "onreadystatechange", DOMContentLoaded ); + + // A fallback to window.onload, that will always work + window.attachEvent( "onload", jQuery.ready ); + + // If IE and not a frame + // continually check to see if the document is ready + var toplevel = false; + + try { + toplevel = window.frameElement == null; + } catch(e) {} + + if ( document.documentElement.doScroll && toplevel ) { + doScrollCheck(); + } + } + }, + + // See test/unit/core.js for details concerning isFunction. + // Since version 1.3, DOM methods and functions like alert + // aren't supported. They return false on IE (#2968). + isFunction: function( obj ) { + return jQuery.type(obj) === "function"; + }, + + isArray: Array.isArray || function( obj ) { + return jQuery.type(obj) === "array"; + }, + + isWindow: function( obj ) { + return obj != null && obj == obj.window; + }, + + isNumeric: function( obj ) { + return !isNaN( parseFloat(obj) ) && isFinite( obj ); + }, + + type: function( obj ) { + return obj == null ? + String( obj ) : + class2type[ toString.call(obj) ] || "object"; + }, + + isPlainObject: function( obj ) { + // Must be an Object. + // Because of IE, we also have to check the presence of the constructor property. + // Make sure that DOM nodes and window objects don't pass through, as well + if ( !obj || jQuery.type(obj) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) { + return false; + } + + try { + // Not own constructor property must be Object + if ( obj.constructor && + !hasOwn.call(obj, "constructor") && + !hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) { + return false; + } + } catch ( e ) { + // IE8,9 Will throw exceptions on certain host objects #9897 + return false; + } + + // Own properties are enumerated firstly, so to speed up, + // if last one is own, then all properties are own. + + var key; + for ( key in obj ) {} + + return key === undefined || hasOwn.call( obj, key ); + }, + + isEmptyObject: function( obj ) { + for ( var name in obj ) { + return false; + } + return true; + }, + + error: function( msg ) { + throw new Error( msg ); + }, + + parseJSON: function( data ) { + if ( typeof data !== "string" || !data ) { + return null; + } + + // Make sure leading/trailing whitespace is removed (IE can't handle it) + data = jQuery.trim( data ); + + // Attempt to parse using the native JSON parser first + if ( window.JSON && window.JSON.parse ) { + return window.JSON.parse( data ); + } + + // Make sure the incoming data is actual JSON + // Logic borrowed from http://json.org/json2.js + if ( rvalidchars.test( data.replace( rvalidescape, "@" ) + .replace( rvalidtokens, "]" ) + .replace( rvalidbraces, "")) ) { + + return ( new Function( "return " + data ) )(); + + } + jQuery.error( "Invalid JSON: " + data ); + }, + + // Cross-browser xml parsing + parseXML: function( data ) { + if ( typeof data !== "string" || !data ) { + return null; + } + var xml, tmp; + try { + if ( window.DOMParser ) { // Standard + tmp = new DOMParser(); + xml = tmp.parseFromString( data , "text/xml" ); + } else { // IE + xml = new ActiveXObject( "Microsoft.XMLDOM" ); + xml.async = "false"; + xml.loadXML( data ); + } + } catch( e ) { + xml = undefined; + } + if ( !xml || !xml.documentElement || xml.getElementsByTagName( "parsererror" ).length ) { + jQuery.error( "Invalid XML: " + data ); + } + return xml; + }, + + noop: function() {}, + + // Evaluates a script in a global context + // Workarounds based on findings by Jim Driscoll + // http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context + globalEval: function( data ) { + if ( data && rnotwhite.test( data ) ) { + // We use execScript on Internet Explorer + // We use an anonymous function so that context is window + // rather than jQuery in Firefox + ( window.execScript || function( data ) { + window[ "eval" ].call( window, data ); + } )( data ); + } + }, + + // Convert dashed to camelCase; used by the css and data modules + // Microsoft forgot to hump their vendor prefix (#9572) + camelCase: function( string ) { + return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); + }, + + nodeName: function( elem, name ) { + return elem.nodeName && elem.nodeName.toUpperCase() === name.toUpperCase(); + }, + + // args is for internal usage only + each: function( object, callback, args ) { + var name, i = 0, + length = object.length, + isObj = length === undefined || jQuery.isFunction( object ); + + if ( args ) { + if ( isObj ) { + for ( name in object ) { + if ( callback.apply( object[ name ], args ) === false ) { + break; + } + } + } else { + for ( ; i < length; ) { + if ( callback.apply( object[ i++ ], args ) === false ) { + break; + } + } + } + + // A special, fast, case for the most common use of each + } else { + if ( isObj ) { + for ( name in object ) { + if ( callback.call( object[ name ], name, object[ name ] ) === false ) { + break; + } + } + } else { + for ( ; i < length; ) { + if ( callback.call( object[ i ], i, object[ i++ ] ) === false ) { + break; + } + } + } + } + + return object; + }, + + // Use native String.trim function wherever possible + trim: trim ? + function( text ) { + return text == null ? + "" : + trim.call( text ); + } : + + // Otherwise use our own trimming functionality + function( text ) { + return text == null ? + "" : + text.toString().replace( trimLeft, "" ).replace( trimRight, "" ); + }, + + // results is for internal usage only + makeArray: function( array, results ) { + var ret = results || []; + + if ( array != null ) { + // The window, strings (and functions) also have 'length' + // Tweaked logic slightly to handle Blackberry 4.7 RegExp issues #6930 + var type = jQuery.type( array ); + + if ( array.length == null || type === "string" || type === "function" || type === "regexp" || jQuery.isWindow( array ) ) { + push.call( ret, array ); + } else { + jQuery.merge( ret, array ); + } + } + + return ret; + }, + + inArray: function( elem, array, i ) { + var len; + + if ( array ) { + if ( indexOf ) { + return indexOf.call( array, elem, i ); + } + + len = array.length; + i = i ? i < 0 ? Math.max( 0, len + i ) : i : 0; + + for ( ; i < len; i++ ) { + // Skip accessing in sparse arrays + if ( i in array && array[ i ] === elem ) { + return i; + } + } + } + + return -1; + }, + + merge: function( first, second ) { + var i = first.length, + j = 0; + + if ( typeof second.length === "number" ) { + for ( var l = second.length; j < l; j++ ) { + first[ i++ ] = second[ j ]; + } + + } else { + while ( second[j] !== undefined ) { + first[ i++ ] = second[ j++ ]; + } + } + + first.length = i; + + return first; + }, + + grep: function( elems, callback, inv ) { + var ret = [], retVal; + inv = !!inv; + + // Go through the array, only saving the items + // that pass the validator function + for ( var i = 0, length = elems.length; i < length; i++ ) { + retVal = !!callback( elems[ i ], i ); + if ( inv !== retVal ) { + ret.push( elems[ i ] ); + } + } + + return ret; + }, + + // arg is for internal usage only + map: function( elems, callback, arg ) { + var value, key, ret = [], + i = 0, + length = elems.length, + // jquery objects are treated as arrays + isArray = elems instanceof jQuery || length !== undefined && typeof length === "number" && ( ( length > 0 && elems[ 0 ] && elems[ length -1 ] ) || length === 0 || jQuery.isArray( elems ) ) ; + + // Go through the array, translating each of the items to their + if ( isArray ) { + for ( ; i < length; i++ ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret[ ret.length ] = value; + } + } + + // Go through every key on the object, + } else { + for ( key in elems ) { + value = callback( elems[ key ], key, arg ); + + if ( value != null ) { + ret[ ret.length ] = value; + } + } + } + + // Flatten any nested arrays + return ret.concat.apply( [], ret ); + }, + + // A global GUID counter for objects + guid: 1, + + // Bind a function to a context, optionally partially applying any + // arguments. + proxy: function( fn, context ) { + if ( typeof context === "string" ) { + var tmp = fn[ context ]; + context = fn; + fn = tmp; + } + + // Quick check to determine if target is callable, in the spec + // this throws a TypeError, but we will just return undefined. + if ( !jQuery.isFunction( fn ) ) { + return undefined; + } + + // Simulated bind + var args = slice.call( arguments, 2 ), + proxy = function() { + return fn.apply( context, args.concat( slice.call( arguments ) ) ); + }; + + // Set the guid of unique handler to the same of original handler, so it can be removed + proxy.guid = fn.guid = fn.guid || proxy.guid || jQuery.guid++; + + return proxy; + }, + + // Mutifunctional method to get and set values to a collection + // The value/s can optionally be executed if it's a function + access: function( elems, fn, key, value, chainable, emptyGet, pass ) { + var exec, + bulk = key == null, + i = 0, + length = elems.length; + + // Sets many values + if ( key && typeof key === "object" ) { + for ( i in key ) { + jQuery.access( elems, fn, i, key[i], 1, emptyGet, value ); + } + chainable = 1; + + // Sets one value + } else if ( value !== undefined ) { + // Optionally, function values get executed if exec is true + exec = pass === undefined && jQuery.isFunction( value ); + + if ( bulk ) { + // Bulk operations only iterate when executing function values + if ( exec ) { + exec = fn; + fn = function( elem, key, value ) { + return exec.call( jQuery( elem ), value ); + }; + + // Otherwise they run against the entire set + } else { + fn.call( elems, value ); + fn = null; + } + } + + if ( fn ) { + for (; i < length; i++ ) { + fn( elems[i], key, exec ? value.call( elems[i], i, fn( elems[i], key ) ) : value, pass ); + } + } + + chainable = 1; + } + + return chainable ? + elems : + + // Gets + bulk ? + fn.call( elems ) : + length ? fn( elems[0], key ) : emptyGet; + }, + + now: function() { + return ( new Date() ).getTime(); + }, + + // Use of jQuery.browser is frowned upon. + // More details: http://docs.jquery.com/Utilities/jQuery.browser + uaMatch: function( ua ) { + ua = ua.toLowerCase(); + + var match = rwebkit.exec( ua ) || + ropera.exec( ua ) || + rmsie.exec( ua ) || + ua.indexOf("compatible") < 0 && rmozilla.exec( ua ) || + []; + + return { browser: match[1] || "", version: match[2] || "0" }; + }, + + sub: function() { + function jQuerySub( selector, context ) { + return new jQuerySub.fn.init( selector, context ); + } + jQuery.extend( true, jQuerySub, this ); + jQuerySub.superclass = this; + jQuerySub.fn = jQuerySub.prototype = this(); + jQuerySub.fn.constructor = jQuerySub; + jQuerySub.sub = this.sub; + jQuerySub.fn.init = function init( selector, context ) { + if ( context && context instanceof jQuery && !(context instanceof jQuerySub) ) { + context = jQuerySub( context ); + } + + return jQuery.fn.init.call( this, selector, context, rootjQuerySub ); + }; + jQuerySub.fn.init.prototype = jQuerySub.fn; + var rootjQuerySub = jQuerySub(document); + return jQuerySub; + }, + + browser: {} +}); + +// Populate the class2type map +jQuery.each("Boolean Number String Function Array Date RegExp Object".split(" "), function(i, name) { + class2type[ "[object " + name + "]" ] = name.toLowerCase(); +}); + +browserMatch = jQuery.uaMatch( userAgent ); +if ( browserMatch.browser ) { + jQuery.browser[ browserMatch.browser ] = true; + jQuery.browser.version = browserMatch.version; +} + +// Deprecated, use jQuery.browser.webkit instead +if ( jQuery.browser.webkit ) { + jQuery.browser.safari = true; +} + +// IE doesn't match non-breaking spaces with \s +if ( rnotwhite.test( "\xA0" ) ) { + trimLeft = /^[\s\xA0]+/; + trimRight = /[\s\xA0]+$/; +} + +// All jQuery objects should point back to these +rootjQuery = jQuery(document); + +// Cleanup functions for the document ready method +if ( document.addEventListener ) { + DOMContentLoaded = function() { + document.removeEventListener( "DOMContentLoaded", DOMContentLoaded, false ); + jQuery.ready(); + }; + +} else if ( document.attachEvent ) { + DOMContentLoaded = function() { + // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443). + if ( document.readyState === "complete" ) { + document.detachEvent( "onreadystatechange", DOMContentLoaded ); + jQuery.ready(); + } + }; +} + +// The DOM ready check for Internet Explorer +function doScrollCheck() { + if ( jQuery.isReady ) { + return; + } + + try { + // If IE is used, use the trick by Diego Perini + // http://javascript.nwbox.com/IEContentLoaded/ + document.documentElement.doScroll("left"); + } catch(e) { + setTimeout( doScrollCheck, 1 ); + return; + } + + // and execute any waiting functions + jQuery.ready(); +} + +return jQuery; + +})(); + + +// String to Object flags format cache +var flagsCache = {}; + +// Convert String-formatted flags into Object-formatted ones and store in cache +function createFlags( flags ) { + var object = flagsCache[ flags ] = {}, + i, length; + flags = flags.split( /\s+/ ); + for ( i = 0, length = flags.length; i < length; i++ ) { + object[ flags[i] ] = true; + } + return object; +} + +/* + * Create a callback list using the following parameters: + * + * flags: an optional list of space-separated flags that will change how + * the callback list behaves + * + * By default a callback list will act like an event callback list and can be + * "fired" multiple times. + * + * Possible flags: + * + * once: will ensure the callback list can only be fired once (like a Deferred) + * + * memory: will keep track of previous values and will call any callback added + * after the list has been fired right away with the latest "memorized" + * values (like a Deferred) + * + * unique: will ensure a callback can only be added once (no duplicate in the list) + * + * stopOnFalse: interrupt callings when a callback returns false + * + */ +jQuery.Callbacks = function( flags ) { + + // Convert flags from String-formatted to Object-formatted + // (we check in cache first) + flags = flags ? ( flagsCache[ flags ] || createFlags( flags ) ) : {}; + + var // Actual callback list + list = [], + // Stack of fire calls for repeatable lists + stack = [], + // Last fire value (for non-forgettable lists) + memory, + // Flag to know if list was already fired + fired, + // Flag to know if list is currently firing + firing, + // First callback to fire (used internally by add and fireWith) + firingStart, + // End of the loop when firing + firingLength, + // Index of currently firing callback (modified by remove if needed) + firingIndex, + // Add one or several callbacks to the list + add = function( args ) { + var i, + length, + elem, + type, + actual; + for ( i = 0, length = args.length; i < length; i++ ) { + elem = args[ i ]; + type = jQuery.type( elem ); + if ( type === "array" ) { + // Inspect recursively + add( elem ); + } else if ( type === "function" ) { + // Add if not in unique mode and callback is not in + if ( !flags.unique || !self.has( elem ) ) { + list.push( elem ); + } + } + } + }, + // Fire callbacks + fire = function( context, args ) { + args = args || []; + memory = !flags.memory || [ context, args ]; + fired = true; + firing = true; + firingIndex = firingStart || 0; + firingStart = 0; + firingLength = list.length; + for ( ; list && firingIndex < firingLength; firingIndex++ ) { + if ( list[ firingIndex ].apply( context, args ) === false && flags.stopOnFalse ) { + memory = true; // Mark as halted + break; + } + } + firing = false; + if ( list ) { + if ( !flags.once ) { + if ( stack && stack.length ) { + memory = stack.shift(); + self.fireWith( memory[ 0 ], memory[ 1 ] ); + } + } else if ( memory === true ) { + self.disable(); + } else { + list = []; + } + } + }, + // Actual Callbacks object + self = { + // Add a callback or a collection of callbacks to the list + add: function() { + if ( list ) { + var length = list.length; + add( arguments ); + // Do we need to add the callbacks to the + // current firing batch? + if ( firing ) { + firingLength = list.length; + // With memory, if we're not firing then + // we should call right away, unless previous + // firing was halted (stopOnFalse) + } else if ( memory && memory !== true ) { + firingStart = length; + fire( memory[ 0 ], memory[ 1 ] ); + } + } + return this; + }, + // Remove a callback from the list + remove: function() { + if ( list ) { + var args = arguments, + argIndex = 0, + argLength = args.length; + for ( ; argIndex < argLength ; argIndex++ ) { + for ( var i = 0; i < list.length; i++ ) { + if ( args[ argIndex ] === list[ i ] ) { + // Handle firingIndex and firingLength + if ( firing ) { + if ( i <= firingLength ) { + firingLength--; + if ( i <= firingIndex ) { + firingIndex--; + } + } + } + // Remove the element + list.splice( i--, 1 ); + // If we have some unicity property then + // we only need to do this once + if ( flags.unique ) { + break; + } + } + } + } + } + return this; + }, + // Control if a given callback is in the list + has: function( fn ) { + if ( list ) { + var i = 0, + length = list.length; + for ( ; i < length; i++ ) { + if ( fn === list[ i ] ) { + return true; + } + } + } + return false; + }, + // Remove all callbacks from the list + empty: function() { + list = []; + return this; + }, + // Have the list do nothing anymore + disable: function() { + list = stack = memory = undefined; + return this; + }, + // Is it disabled? + disabled: function() { + return !list; + }, + // Lock the list in its current state + lock: function() { + stack = undefined; + if ( !memory || memory === true ) { + self.disable(); + } + return this; + }, + // Is it locked? + locked: function() { + return !stack; + }, + // Call all callbacks with the given context and arguments + fireWith: function( context, args ) { + if ( stack ) { + if ( firing ) { + if ( !flags.once ) { + stack.push( [ context, args ] ); + } + } else if ( !( flags.once && memory ) ) { + fire( context, args ); + } + } + return this; + }, + // Call all the callbacks with the given arguments + fire: function() { + self.fireWith( this, arguments ); + return this; + }, + // To know if the callbacks have already been called at least once + fired: function() { + return !!fired; + } + }; + + return self; +}; + + + + +var // Static reference to slice + sliceDeferred = [].slice; + +jQuery.extend({ + + Deferred: function( func ) { + var doneList = jQuery.Callbacks( "once memory" ), + failList = jQuery.Callbacks( "once memory" ), + progressList = jQuery.Callbacks( "memory" ), + state = "pending", + lists = { + resolve: doneList, + reject: failList, + notify: progressList + }, + promise = { + done: doneList.add, + fail: failList.add, + progress: progressList.add, + + state: function() { + return state; + }, + + // Deprecated + isResolved: doneList.fired, + isRejected: failList.fired, + + then: function( doneCallbacks, failCallbacks, progressCallbacks ) { + deferred.done( doneCallbacks ).fail( failCallbacks ).progress( progressCallbacks ); + return this; + }, + always: function() { + deferred.done.apply( deferred, arguments ).fail.apply( deferred, arguments ); + return this; + }, + pipe: function( fnDone, fnFail, fnProgress ) { + return jQuery.Deferred(function( newDefer ) { + jQuery.each( { + done: [ fnDone, "resolve" ], + fail: [ fnFail, "reject" ], + progress: [ fnProgress, "notify" ] + }, function( handler, data ) { + var fn = data[ 0 ], + action = data[ 1 ], + returned; + if ( jQuery.isFunction( fn ) ) { + deferred[ handler ](function() { + returned = fn.apply( this, arguments ); + if ( returned && jQuery.isFunction( returned.promise ) ) { + returned.promise().then( newDefer.resolve, newDefer.reject, newDefer.notify ); + } else { + newDefer[ action + "With" ]( this === deferred ? newDefer : this, [ returned ] ); + } + }); + } else { + deferred[ handler ]( newDefer[ action ] ); + } + }); + }).promise(); + }, + // Get a promise for this deferred + // If obj is provided, the promise aspect is added to the object + promise: function( obj ) { + if ( obj == null ) { + obj = promise; + } else { + for ( var key in promise ) { + obj[ key ] = promise[ key ]; + } + } + return obj; + } + }, + deferred = promise.promise({}), + key; + + for ( key in lists ) { + deferred[ key ] = lists[ key ].fire; + deferred[ key + "With" ] = lists[ key ].fireWith; + } + + // Handle state + deferred.done( function() { + state = "resolved"; + }, failList.disable, progressList.lock ).fail( function() { + state = "rejected"; + }, doneList.disable, progressList.lock ); + + // Call given func if any + if ( func ) { + func.call( deferred, deferred ); + } + + // All done! + return deferred; + }, + + // Deferred helper + when: function( firstParam ) { + var args = sliceDeferred.call( arguments, 0 ), + i = 0, + length = args.length, + pValues = new Array( length ), + count = length, + pCount = length, + deferred = length <= 1 && firstParam && jQuery.isFunction( firstParam.promise ) ? + firstParam : + jQuery.Deferred(), + promise = deferred.promise(); + function resolveFunc( i ) { + return function( value ) { + args[ i ] = arguments.length > 1 ? sliceDeferred.call( arguments, 0 ) : value; + if ( !( --count ) ) { + deferred.resolveWith( deferred, args ); + } + }; + } + function progressFunc( i ) { + return function( value ) { + pValues[ i ] = arguments.length > 1 ? sliceDeferred.call( arguments, 0 ) : value; + deferred.notifyWith( promise, pValues ); + }; + } + if ( length > 1 ) { + for ( ; i < length; i++ ) { + if ( args[ i ] && args[ i ].promise && jQuery.isFunction( args[ i ].promise ) ) { + args[ i ].promise().then( resolveFunc(i), deferred.reject, progressFunc(i) ); + } else { + --count; + } + } + if ( !count ) { + deferred.resolveWith( deferred, args ); + } + } else if ( deferred !== firstParam ) { + deferred.resolveWith( deferred, length ? [ firstParam ] : [] ); + } + return promise; + } +}); + + + + +jQuery.support = (function() { + + var support, + all, + a, + select, + opt, + input, + fragment, + tds, + events, + eventName, + i, + isSupported, + div = document.createElement( "div" ), + documentElement = document.documentElement; + + // Preliminary tests + div.setAttribute("className", "t"); + div.innerHTML = "
a"; + + all = div.getElementsByTagName( "*" ); + a = div.getElementsByTagName( "a" )[ 0 ]; + + // Can't get basic test support + if ( !all || !all.length || !a ) { + return {}; + } + + // First batch of supports tests + select = document.createElement( "select" ); + opt = select.appendChild( document.createElement("option") ); + input = div.getElementsByTagName( "input" )[ 0 ]; + + support = { + // IE strips leading whitespace when .innerHTML is used + leadingWhitespace: ( div.firstChild.nodeType === 3 ), + + // Make sure that tbody elements aren't automatically inserted + // IE will insert them into empty tables + tbody: !div.getElementsByTagName("tbody").length, + + // Make sure that link elements get serialized correctly by innerHTML + // This requires a wrapper element in IE + htmlSerialize: !!div.getElementsByTagName("link").length, + + // Get the style information from getAttribute + // (IE uses .cssText instead) + style: /top/.test( a.getAttribute("style") ), + + // Make sure that URLs aren't manipulated + // (IE normalizes it by default) + hrefNormalized: ( a.getAttribute("href") === "/a" ), + + // Make sure that element opacity exists + // (IE uses filter instead) + // Use a regex to work around a WebKit issue. See #5145 + opacity: /^0.55/.test( a.style.opacity ), + + // Verify style float existence + // (IE uses styleFloat instead of cssFloat) + cssFloat: !!a.style.cssFloat, + + // Make sure that if no value is specified for a checkbox + // that it defaults to "on". + // (WebKit defaults to "" instead) + checkOn: ( input.value === "on" ), + + // Make sure that a selected-by-default option has a working selected property. + // (WebKit defaults to false instead of true, IE too, if it's in an optgroup) + optSelected: opt.selected, + + // Test setAttribute on camelCase class. If it works, we need attrFixes when doing get/setAttribute (ie6/7) + getSetAttribute: div.className !== "t", + + // Tests for enctype support on a form(#6743) + enctype: !!document.createElement("form").enctype, + + // Makes sure cloning an html5 element does not cause problems + // Where outerHTML is undefined, this still works + html5Clone: document.createElement("nav").cloneNode( true ).outerHTML !== "<:nav>", + + // Will be defined later + submitBubbles: true, + changeBubbles: true, + focusinBubbles: false, + deleteExpando: true, + noCloneEvent: true, + inlineBlockNeedsLayout: false, + shrinkWrapBlocks: false, + reliableMarginRight: true, + pixelMargin: true + }; + + // jQuery.boxModel DEPRECATED in 1.3, use jQuery.support.boxModel instead + jQuery.boxModel = support.boxModel = (document.compatMode === "CSS1Compat"); + + // Make sure checked status is properly cloned + input.checked = true; + support.noCloneChecked = input.cloneNode( true ).checked; + + // Make sure that the options inside disabled selects aren't marked as disabled + // (WebKit marks them as disabled) + select.disabled = true; + support.optDisabled = !opt.disabled; + + // Test to see if it's possible to delete an expando from an element + // Fails in Internet Explorer + try { + delete div.test; + } catch( e ) { + support.deleteExpando = false; + } + + if ( !div.addEventListener && div.attachEvent && div.fireEvent ) { + div.attachEvent( "onclick", function() { + // Cloning a node shouldn't copy over any + // bound event handlers (IE does this) + support.noCloneEvent = false; + }); + div.cloneNode( true ).fireEvent( "onclick" ); + } + + // Check if a radio maintains its value + // after being appended to the DOM + input = document.createElement("input"); + input.value = "t"; + input.setAttribute("type", "radio"); + support.radioValue = input.value === "t"; + + input.setAttribute("checked", "checked"); + + // #11217 - WebKit loses check when the name is after the checked attribute + input.setAttribute( "name", "t" ); + + div.appendChild( input ); + fragment = document.createDocumentFragment(); + fragment.appendChild( div.lastChild ); + + // WebKit doesn't clone checked state correctly in fragments + support.checkClone = fragment.cloneNode( true ).cloneNode( true ).lastChild.checked; + + // Check if a disconnected checkbox will retain its checked + // value of true after appended to the DOM (IE6/7) + support.appendChecked = input.checked; + + fragment.removeChild( input ); + fragment.appendChild( div ); + + // Technique from Juriy Zaytsev + // http://perfectionkills.com/detecting-event-support-without-browser-sniffing/ + // We only care about the case where non-standard event systems + // are used, namely in IE. Short-circuiting here helps us to + // avoid an eval call (in setAttribute) which can cause CSP + // to go haywire. See: https://developer.mozilla.org/en/Security/CSP + if ( div.attachEvent ) { + for ( i in { + submit: 1, + change: 1, + focusin: 1 + }) { + eventName = "on" + i; + isSupported = ( eventName in div ); + if ( !isSupported ) { + div.setAttribute( eventName, "return;" ); + isSupported = ( typeof div[ eventName ] === "function" ); + } + support[ i + "Bubbles" ] = isSupported; + } + } + + fragment.removeChild( div ); + + // Null elements to avoid leaks in IE + fragment = select = opt = div = input = null; + + // Run tests that need a body at doc ready + jQuery(function() { + var container, outer, inner, table, td, offsetSupport, + marginDiv, conMarginTop, style, html, positionTopLeftWidthHeight, + paddingMarginBorderVisibility, paddingMarginBorder, + body = document.getElementsByTagName("body")[0]; + + if ( !body ) { + // Return for frameset docs that don't have a body + return; + } + + conMarginTop = 1; + paddingMarginBorder = "padding:0;margin:0;border:"; + positionTopLeftWidthHeight = "position:absolute;top:0;left:0;width:1px;height:1px;"; + paddingMarginBorderVisibility = paddingMarginBorder + "0;visibility:hidden;"; + style = "style='" + positionTopLeftWidthHeight + paddingMarginBorder + "5px solid #000;"; + html = "
" + + "" + + "
"; + + container = document.createElement("div"); + container.style.cssText = paddingMarginBorderVisibility + "width:0;height:0;position:static;top:0;margin-top:" + conMarginTop + "px"; + body.insertBefore( container, body.firstChild ); + + // Construct the test element + div = document.createElement("div"); + container.appendChild( div ); + + // Check if table cells still have offsetWidth/Height when they are set + // to display:none and there are still other visible table cells in a + // table row; if so, offsetWidth/Height are not reliable for use when + // determining if an element has been hidden directly using + // display:none (it is still safe to use offsets if a parent element is + // hidden; don safety goggles and see bug #4512 for more information). + // (only IE 8 fails this test) + div.innerHTML = "
t
"; + tds = div.getElementsByTagName( "td" ); + isSupported = ( tds[ 0 ].offsetHeight === 0 ); + + tds[ 0 ].style.display = ""; + tds[ 1 ].style.display = "none"; + + // Check if empty table cells still have offsetWidth/Height + // (IE <= 8 fail this test) + support.reliableHiddenOffsets = isSupported && ( tds[ 0 ].offsetHeight === 0 ); + + // Check if div with explicit width and no margin-right incorrectly + // gets computed margin-right based on width of container. For more + // info see bug #3333 + // Fails in WebKit before Feb 2011 nightlies + // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right + if ( window.getComputedStyle ) { + div.innerHTML = ""; + marginDiv = document.createElement( "div" ); + marginDiv.style.width = "0"; + marginDiv.style.marginRight = "0"; + div.style.width = "2px"; + div.appendChild( marginDiv ); + support.reliableMarginRight = + ( parseInt( ( window.getComputedStyle( marginDiv, null ) || { marginRight: 0 } ).marginRight, 10 ) || 0 ) === 0; + } + + if ( typeof div.style.zoom !== "undefined" ) { + // Check if natively block-level elements act like inline-block + // elements when setting their display to 'inline' and giving + // them layout + // (IE < 8 does this) + div.innerHTML = ""; + div.style.width = div.style.padding = "1px"; + div.style.border = 0; + div.style.overflow = "hidden"; + div.style.display = "inline"; + div.style.zoom = 1; + support.inlineBlockNeedsLayout = ( div.offsetWidth === 3 ); + + // Check if elements with layout shrink-wrap their children + // (IE 6 does this) + div.style.display = "block"; + div.style.overflow = "visible"; + div.innerHTML = "
"; + support.shrinkWrapBlocks = ( div.offsetWidth !== 3 ); + } + + div.style.cssText = positionTopLeftWidthHeight + paddingMarginBorderVisibility; + div.innerHTML = html; + + outer = div.firstChild; + inner = outer.firstChild; + td = outer.nextSibling.firstChild.firstChild; + + offsetSupport = { + doesNotAddBorder: ( inner.offsetTop !== 5 ), + doesAddBorderForTableAndCells: ( td.offsetTop === 5 ) + }; + + inner.style.position = "fixed"; + inner.style.top = "20px"; + + // safari subtracts parent border width here which is 5px + offsetSupport.fixedPosition = ( inner.offsetTop === 20 || inner.offsetTop === 15 ); + inner.style.position = inner.style.top = ""; + + outer.style.overflow = "hidden"; + outer.style.position = "relative"; + + offsetSupport.subtractsBorderForOverflowNotVisible = ( inner.offsetTop === -5 ); + offsetSupport.doesNotIncludeMarginInBodyOffset = ( body.offsetTop !== conMarginTop ); + + if ( window.getComputedStyle ) { + div.style.marginTop = "1%"; + support.pixelMargin = ( window.getComputedStyle( div, null ) || { marginTop: 0 } ).marginTop !== "1%"; + } + + if ( typeof container.style.zoom !== "undefined" ) { + container.style.zoom = 1; + } + + body.removeChild( container ); + marginDiv = div = container = null; + + jQuery.extend( support, offsetSupport ); + }); + + return support; +})(); + + + + +var rbrace = /^(?:\{.*\}|\[.*\])$/, + rmultiDash = /([A-Z])/g; + +jQuery.extend({ + cache: {}, + + // Please use with caution + uuid: 0, + + // Unique for each copy of jQuery on the page + // Non-digits removed to match rinlinejQuery + expando: "jQuery" + ( jQuery.fn.jquery + Math.random() ).replace( /\D/g, "" ), + + // The following elements throw uncatchable exceptions if you + // attempt to add expando properties to them. + noData: { + "embed": true, + // Ban all objects except for Flash (which handle expandos) + "object": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000", + "applet": true + }, + + hasData: function( elem ) { + elem = elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ]; + return !!elem && !isEmptyDataObject( elem ); + }, + + data: function( elem, name, data, pvt /* Internal Use Only */ ) { + if ( !jQuery.acceptData( elem ) ) { + return; + } + + var privateCache, thisCache, ret, + internalKey = jQuery.expando, + getByName = typeof name === "string", + + // We have to handle DOM nodes and JS objects differently because IE6-7 + // can't GC object references properly across the DOM-JS boundary + isNode = elem.nodeType, + + // Only DOM nodes need the global jQuery cache; JS object data is + // attached directly to the object so GC can occur automatically + cache = isNode ? jQuery.cache : elem, + + // Only defining an ID for JS objects if its cache already exists allows + // the code to shortcut on the same path as a DOM node with no cache + id = isNode ? elem[ internalKey ] : elem[ internalKey ] && internalKey, + isEvents = name === "events"; + + // Avoid doing any more work than we need to when trying to get data on an + // object that has no data at all + if ( (!id || !cache[id] || (!isEvents && !pvt && !cache[id].data)) && getByName && data === undefined ) { + return; + } + + if ( !id ) { + // Only DOM nodes need a new unique ID for each element since their data + // ends up in the global cache + if ( isNode ) { + elem[ internalKey ] = id = ++jQuery.uuid; + } else { + id = internalKey; + } + } + + if ( !cache[ id ] ) { + cache[ id ] = {}; + + // Avoids exposing jQuery metadata on plain JS objects when the object + // is serialized using JSON.stringify + if ( !isNode ) { + cache[ id ].toJSON = jQuery.noop; + } + } + + // An object can be passed to jQuery.data instead of a key/value pair; this gets + // shallow copied over onto the existing cache + if ( typeof name === "object" || typeof name === "function" ) { + if ( pvt ) { + cache[ id ] = jQuery.extend( cache[ id ], name ); + } else { + cache[ id ].data = jQuery.extend( cache[ id ].data, name ); + } + } + + privateCache = thisCache = cache[ id ]; + + // jQuery data() is stored in a separate object inside the object's internal data + // cache in order to avoid key collisions between internal data and user-defined + // data. + if ( !pvt ) { + if ( !thisCache.data ) { + thisCache.data = {}; + } + + thisCache = thisCache.data; + } + + if ( data !== undefined ) { + thisCache[ jQuery.camelCase( name ) ] = data; + } + + // Users should not attempt to inspect the internal events object using jQuery.data, + // it is undocumented and subject to change. But does anyone listen? No. + if ( isEvents && !thisCache[ name ] ) { + return privateCache.events; + } + + // Check for both converted-to-camel and non-converted data property names + // If a data property was specified + if ( getByName ) { + + // First Try to find as-is property data + ret = thisCache[ name ]; + + // Test for null|undefined property data + if ( ret == null ) { + + // Try to find the camelCased property + ret = thisCache[ jQuery.camelCase( name ) ]; + } + } else { + ret = thisCache; + } + + return ret; + }, + + removeData: function( elem, name, pvt /* Internal Use Only */ ) { + if ( !jQuery.acceptData( elem ) ) { + return; + } + + var thisCache, i, l, + + // Reference to internal data cache key + internalKey = jQuery.expando, + + isNode = elem.nodeType, + + // See jQuery.data for more information + cache = isNode ? jQuery.cache : elem, + + // See jQuery.data for more information + id = isNode ? elem[ internalKey ] : internalKey; + + // If there is already no cache entry for this object, there is no + // purpose in continuing + if ( !cache[ id ] ) { + return; + } + + if ( name ) { + + thisCache = pvt ? cache[ id ] : cache[ id ].data; + + if ( thisCache ) { + + // Support array or space separated string names for data keys + if ( !jQuery.isArray( name ) ) { + + // try the string as a key before any manipulation + if ( name in thisCache ) { + name = [ name ]; + } else { + + // split the camel cased version by spaces unless a key with the spaces exists + name = jQuery.camelCase( name ); + if ( name in thisCache ) { + name = [ name ]; + } else { + name = name.split( " " ); + } + } + } + + for ( i = 0, l = name.length; i < l; i++ ) { + delete thisCache[ name[i] ]; + } + + // If there is no data left in the cache, we want to continue + // and let the cache object itself get destroyed + if ( !( pvt ? isEmptyDataObject : jQuery.isEmptyObject )( thisCache ) ) { + return; + } + } + } + + // See jQuery.data for more information + if ( !pvt ) { + delete cache[ id ].data; + + // Don't destroy the parent cache unless the internal data object + // had been the only thing left in it + if ( !isEmptyDataObject(cache[ id ]) ) { + return; + } + } + + // Browsers that fail expando deletion also refuse to delete expandos on + // the window, but it will allow it on all other JS objects; other browsers + // don't care + // Ensure that `cache` is not a window object #10080 + if ( jQuery.support.deleteExpando || !cache.setInterval ) { + delete cache[ id ]; + } else { + cache[ id ] = null; + } + + // We destroyed the cache and need to eliminate the expando on the node to avoid + // false lookups in the cache for entries that no longer exist + if ( isNode ) { + // IE does not allow us to delete expando properties from nodes, + // nor does it have a removeAttribute function on Document nodes; + // we must handle all of these cases + if ( jQuery.support.deleteExpando ) { + delete elem[ internalKey ]; + } else if ( elem.removeAttribute ) { + elem.removeAttribute( internalKey ); + } else { + elem[ internalKey ] = null; + } + } + }, + + // For internal use only. + _data: function( elem, name, data ) { + return jQuery.data( elem, name, data, true ); + }, + + // A method for determining if a DOM node can handle the data expando + acceptData: function( elem ) { + if ( elem.nodeName ) { + var match = jQuery.noData[ elem.nodeName.toLowerCase() ]; + + if ( match ) { + return !(match === true || elem.getAttribute("classid") !== match); + } + } + + return true; + } +}); + +jQuery.fn.extend({ + data: function( key, value ) { + var parts, part, attr, name, l, + elem = this[0], + i = 0, + data = null; + + // Gets all values + if ( key === undefined ) { + if ( this.length ) { + data = jQuery.data( elem ); + + if ( elem.nodeType === 1 && !jQuery._data( elem, "parsedAttrs" ) ) { + attr = elem.attributes; + for ( l = attr.length; i < l; i++ ) { + name = attr[i].name; + + if ( name.indexOf( "data-" ) === 0 ) { + name = jQuery.camelCase( name.substring(5) ); + + dataAttr( elem, name, data[ name ] ); + } + } + jQuery._data( elem, "parsedAttrs", true ); + } + } + + return data; + } + + // Sets multiple values + if ( typeof key === "object" ) { + return this.each(function() { + jQuery.data( this, key ); + }); + } + + parts = key.split( ".", 2 ); + parts[1] = parts[1] ? "." + parts[1] : ""; + part = parts[1] + "!"; + + return jQuery.access( this, function( value ) { + + if ( value === undefined ) { + data = this.triggerHandler( "getData" + part, [ parts[0] ] ); + + // Try to fetch any internally stored data first + if ( data === undefined && elem ) { + data = jQuery.data( elem, key ); + data = dataAttr( elem, key, data ); + } + + return data === undefined && parts[1] ? + this.data( parts[0] ) : + data; + } + + parts[1] = value; + this.each(function() { + var self = jQuery( this ); + + self.triggerHandler( "setData" + part, parts ); + jQuery.data( this, key, value ); + self.triggerHandler( "changeData" + part, parts ); + }); + }, null, value, arguments.length > 1, null, false ); + }, + + removeData: function( key ) { + return this.each(function() { + jQuery.removeData( this, key ); + }); + } +}); + +function dataAttr( elem, key, data ) { + // If nothing was found internally, try to fetch any + // data from the HTML5 data-* attribute + if ( data === undefined && elem.nodeType === 1 ) { + + var name = "data-" + key.replace( rmultiDash, "-$1" ).toLowerCase(); + + data = elem.getAttribute( name ); + + if ( typeof data === "string" ) { + try { + data = data === "true" ? true : + data === "false" ? false : + data === "null" ? null : + jQuery.isNumeric( data ) ? +data : + rbrace.test( data ) ? jQuery.parseJSON( data ) : + data; + } catch( e ) {} + + // Make sure we set the data so it isn't changed later + jQuery.data( elem, key, data ); + + } else { + data = undefined; + } + } + + return data; +} + +// checks a cache object for emptiness +function isEmptyDataObject( obj ) { + for ( var name in obj ) { + + // if the public data object is empty, the private is still empty + if ( name === "data" && jQuery.isEmptyObject( obj[name] ) ) { + continue; + } + if ( name !== "toJSON" ) { + return false; + } + } + + return true; +} + + + + +function handleQueueMarkDefer( elem, type, src ) { + var deferDataKey = type + "defer", + queueDataKey = type + "queue", + markDataKey = type + "mark", + defer = jQuery._data( elem, deferDataKey ); + if ( defer && + ( src === "queue" || !jQuery._data(elem, queueDataKey) ) && + ( src === "mark" || !jQuery._data(elem, markDataKey) ) ) { + // Give room for hard-coded callbacks to fire first + // and eventually mark/queue something else on the element + setTimeout( function() { + if ( !jQuery._data( elem, queueDataKey ) && + !jQuery._data( elem, markDataKey ) ) { + jQuery.removeData( elem, deferDataKey, true ); + defer.fire(); + } + }, 0 ); + } +} + +jQuery.extend({ + + _mark: function( elem, type ) { + if ( elem ) { + type = ( type || "fx" ) + "mark"; + jQuery._data( elem, type, (jQuery._data( elem, type ) || 0) + 1 ); + } + }, + + _unmark: function( force, elem, type ) { + if ( force !== true ) { + type = elem; + elem = force; + force = false; + } + if ( elem ) { + type = type || "fx"; + var key = type + "mark", + count = force ? 0 : ( (jQuery._data( elem, key ) || 1) - 1 ); + if ( count ) { + jQuery._data( elem, key, count ); + } else { + jQuery.removeData( elem, key, true ); + handleQueueMarkDefer( elem, type, "mark" ); + } + } + }, + + queue: function( elem, type, data ) { + var q; + if ( elem ) { + type = ( type || "fx" ) + "queue"; + q = jQuery._data( elem, type ); + + // Speed up dequeue by getting out quickly if this is just a lookup + if ( data ) { + if ( !q || jQuery.isArray(data) ) { + q = jQuery._data( elem, type, jQuery.makeArray(data) ); + } else { + q.push( data ); + } + } + return q || []; + } + }, + + dequeue: function( elem, type ) { + type = type || "fx"; + + var queue = jQuery.queue( elem, type ), + fn = queue.shift(), + hooks = {}; + + // If the fx queue is dequeued, always remove the progress sentinel + if ( fn === "inprogress" ) { + fn = queue.shift(); + } + + if ( fn ) { + // Add a progress sentinel to prevent the fx queue from being + // automatically dequeued + if ( type === "fx" ) { + queue.unshift( "inprogress" ); + } + + jQuery._data( elem, type + ".run", hooks ); + fn.call( elem, function() { + jQuery.dequeue( elem, type ); + }, hooks ); + } + + if ( !queue.length ) { + jQuery.removeData( elem, type + "queue " + type + ".run", true ); + handleQueueMarkDefer( elem, type, "queue" ); + } + } +}); + +jQuery.fn.extend({ + queue: function( type, data ) { + var setter = 2; + + if ( typeof type !== "string" ) { + data = type; + type = "fx"; + setter--; + } + + if ( arguments.length < setter ) { + return jQuery.queue( this[0], type ); + } + + return data === undefined ? + this : + this.each(function() { + var queue = jQuery.queue( this, type, data ); + + if ( type === "fx" && queue[0] !== "inprogress" ) { + jQuery.dequeue( this, type ); + } + }); + }, + dequeue: function( type ) { + return this.each(function() { + jQuery.dequeue( this, type ); + }); + }, + // Based off of the plugin by Clint Helfers, with permission. + // http://blindsignals.com/index.php/2009/07/jquery-delay/ + delay: function( time, type ) { + time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time; + type = type || "fx"; + + return this.queue( type, function( next, hooks ) { + var timeout = setTimeout( next, time ); + hooks.stop = function() { + clearTimeout( timeout ); + }; + }); + }, + clearQueue: function( type ) { + return this.queue( type || "fx", [] ); + }, + // Get a promise resolved when queues of a certain type + // are emptied (fx is the type by default) + promise: function( type, object ) { + if ( typeof type !== "string" ) { + object = type; + type = undefined; + } + type = type || "fx"; + var defer = jQuery.Deferred(), + elements = this, + i = elements.length, + count = 1, + deferDataKey = type + "defer", + queueDataKey = type + "queue", + markDataKey = type + "mark", + tmp; + function resolve() { + if ( !( --count ) ) { + defer.resolveWith( elements, [ elements ] ); + } + } + while( i-- ) { + if (( tmp = jQuery.data( elements[ i ], deferDataKey, undefined, true ) || + ( jQuery.data( elements[ i ], queueDataKey, undefined, true ) || + jQuery.data( elements[ i ], markDataKey, undefined, true ) ) && + jQuery.data( elements[ i ], deferDataKey, jQuery.Callbacks( "once memory" ), true ) )) { + count++; + tmp.add( resolve ); + } + } + resolve(); + return defer.promise( object ); + } +}); + + + + +var rclass = /[\n\t\r]/g, + rspace = /\s+/, + rreturn = /\r/g, + rtype = /^(?:button|input)$/i, + rfocusable = /^(?:button|input|object|select|textarea)$/i, + rclickable = /^a(?:rea)?$/i, + rboolean = /^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i, + getSetAttribute = jQuery.support.getSetAttribute, + nodeHook, boolHook, fixSpecified; + +jQuery.fn.extend({ + attr: function( name, value ) { + return jQuery.access( this, jQuery.attr, name, value, arguments.length > 1 ); + }, + + removeAttr: function( name ) { + return this.each(function() { + jQuery.removeAttr( this, name ); + }); + }, + + prop: function( name, value ) { + return jQuery.access( this, jQuery.prop, name, value, arguments.length > 1 ); + }, + + removeProp: function( name ) { + name = jQuery.propFix[ name ] || name; + return this.each(function() { + // try/catch handles cases where IE balks (such as removing a property on window) + try { + this[ name ] = undefined; + delete this[ name ]; + } catch( e ) {} + }); + }, + + addClass: function( value ) { + var classNames, i, l, elem, + setClass, c, cl; + + if ( jQuery.isFunction( value ) ) { + return this.each(function( j ) { + jQuery( this ).addClass( value.call(this, j, this.className) ); + }); + } + + if ( value && typeof value === "string" ) { + classNames = value.split( rspace ); + + for ( i = 0, l = this.length; i < l; i++ ) { + elem = this[ i ]; + + if ( elem.nodeType === 1 ) { + if ( !elem.className && classNames.length === 1 ) { + elem.className = value; + + } else { + setClass = " " + elem.className + " "; + + for ( c = 0, cl = classNames.length; c < cl; c++ ) { + if ( !~setClass.indexOf( " " + classNames[ c ] + " " ) ) { + setClass += classNames[ c ] + " "; + } + } + elem.className = jQuery.trim( setClass ); + } + } + } + } + + return this; + }, + + removeClass: function( value ) { + var classNames, i, l, elem, className, c, cl; + + if ( jQuery.isFunction( value ) ) { + return this.each(function( j ) { + jQuery( this ).removeClass( value.call(this, j, this.className) ); + }); + } + + if ( (value && typeof value === "string") || value === undefined ) { + classNames = ( value || "" ).split( rspace ); + + for ( i = 0, l = this.length; i < l; i++ ) { + elem = this[ i ]; + + if ( elem.nodeType === 1 && elem.className ) { + if ( value ) { + className = (" " + elem.className + " ").replace( rclass, " " ); + for ( c = 0, cl = classNames.length; c < cl; c++ ) { + className = className.replace(" " + classNames[ c ] + " ", " "); + } + elem.className = jQuery.trim( className ); + + } else { + elem.className = ""; + } + } + } + } + + return this; + }, + + toggleClass: function( value, stateVal ) { + var type = typeof value, + isBool = typeof stateVal === "boolean"; + + if ( jQuery.isFunction( value ) ) { + return this.each(function( i ) { + jQuery( this ).toggleClass( value.call(this, i, this.className, stateVal), stateVal ); + }); + } + + return this.each(function() { + if ( type === "string" ) { + // toggle individual class names + var className, + i = 0, + self = jQuery( this ), + state = stateVal, + classNames = value.split( rspace ); + + while ( (className = classNames[ i++ ]) ) { + // check each className given, space seperated list + state = isBool ? state : !self.hasClass( className ); + self[ state ? "addClass" : "removeClass" ]( className ); + } + + } else if ( type === "undefined" || type === "boolean" ) { + if ( this.className ) { + // store className if set + jQuery._data( this, "__className__", this.className ); + } + + // toggle whole className + this.className = this.className || value === false ? "" : jQuery._data( this, "__className__" ) || ""; + } + }); + }, + + hasClass: function( selector ) { + var className = " " + selector + " ", + i = 0, + l = this.length; + for ( ; i < l; i++ ) { + if ( this[i].nodeType === 1 && (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) > -1 ) { + return true; + } + } + + return false; + }, + + val: function( value ) { + var hooks, ret, isFunction, + elem = this[0]; + + if ( !arguments.length ) { + if ( elem ) { + hooks = jQuery.valHooks[ elem.type ] || jQuery.valHooks[ elem.nodeName.toLowerCase() ]; + + if ( hooks && "get" in hooks && (ret = hooks.get( elem, "value" )) !== undefined ) { + return ret; + } + + ret = elem.value; + + return typeof ret === "string" ? + // handle most common string cases + ret.replace(rreturn, "") : + // handle cases where value is null/undef or number + ret == null ? "" : ret; + } + + return; + } + + isFunction = jQuery.isFunction( value ); + + return this.each(function( i ) { + var self = jQuery(this), val; + + if ( this.nodeType !== 1 ) { + return; + } + + if ( isFunction ) { + val = value.call( this, i, self.val() ); + } else { + val = value; + } + + // Treat null/undefined as ""; convert numbers to string + if ( val == null ) { + val = ""; + } else if ( typeof val === "number" ) { + val += ""; + } else if ( jQuery.isArray( val ) ) { + val = jQuery.map(val, function ( value ) { + return value == null ? "" : value + ""; + }); + } + + hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ]; + + // If set returns undefined, fall back to normal setting + if ( !hooks || !("set" in hooks) || hooks.set( this, val, "value" ) === undefined ) { + this.value = val; + } + }); + } +}); + +jQuery.extend({ + valHooks: { + option: { + get: function( elem ) { + // attributes.value is undefined in Blackberry 4.7 but + // uses .value. See #6932 + var val = elem.attributes.value; + return !val || val.specified ? elem.value : elem.text; + } + }, + select: { + get: function( elem ) { + var value, i, max, option, + index = elem.selectedIndex, + values = [], + options = elem.options, + one = elem.type === "select-one"; + + // Nothing was selected + if ( index < 0 ) { + return null; + } + + // Loop through all the selected options + i = one ? index : 0; + max = one ? index + 1 : options.length; + for ( ; i < max; i++ ) { + option = options[ i ]; + + // Don't return options that are disabled or in a disabled optgroup + if ( option.selected && (jQuery.support.optDisabled ? !option.disabled : option.getAttribute("disabled") === null) && + (!option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" )) ) { + + // Get the specific value for the option + value = jQuery( option ).val(); + + // We don't need an array for one selects + if ( one ) { + return value; + } + + // Multi-Selects return an array + values.push( value ); + } + } + + // Fixes Bug #2551 -- select.val() broken in IE after form.reset() + if ( one && !values.length && options.length ) { + return jQuery( options[ index ] ).val(); + } + + return values; + }, + + set: function( elem, value ) { + var values = jQuery.makeArray( value ); + + jQuery(elem).find("option").each(function() { + this.selected = jQuery.inArray( jQuery(this).val(), values ) >= 0; + }); + + if ( !values.length ) { + elem.selectedIndex = -1; + } + return values; + } + } + }, + + attrFn: { + val: true, + css: true, + html: true, + text: true, + data: true, + width: true, + height: true, + offset: true + }, + + attr: function( elem, name, value, pass ) { + var ret, hooks, notxml, + nType = elem.nodeType; + + // don't get/set attributes on text, comment and attribute nodes + if ( !elem || nType === 3 || nType === 8 || nType === 2 ) { + return; + } + + if ( pass && name in jQuery.attrFn ) { + return jQuery( elem )[ name ]( value ); + } + + // Fallback to prop when attributes are not supported + if ( typeof elem.getAttribute === "undefined" ) { + return jQuery.prop( elem, name, value ); + } + + notxml = nType !== 1 || !jQuery.isXMLDoc( elem ); + + // All attributes are lowercase + // Grab necessary hook if one is defined + if ( notxml ) { + name = name.toLowerCase(); + hooks = jQuery.attrHooks[ name ] || ( rboolean.test( name ) ? boolHook : nodeHook ); + } + + if ( value !== undefined ) { + + if ( value === null ) { + jQuery.removeAttr( elem, name ); + return; + + } else if ( hooks && "set" in hooks && notxml && (ret = hooks.set( elem, value, name )) !== undefined ) { + return ret; + + } else { + elem.setAttribute( name, "" + value ); + return value; + } + + } else if ( hooks && "get" in hooks && notxml && (ret = hooks.get( elem, name )) !== null ) { + return ret; + + } else { + + ret = elem.getAttribute( name ); + + // Non-existent attributes return null, we normalize to undefined + return ret === null ? + undefined : + ret; + } + }, + + removeAttr: function( elem, value ) { + var propName, attrNames, name, l, isBool, + i = 0; + + if ( value && elem.nodeType === 1 ) { + attrNames = value.toLowerCase().split( rspace ); + l = attrNames.length; + + for ( ; i < l; i++ ) { + name = attrNames[ i ]; + + if ( name ) { + propName = jQuery.propFix[ name ] || name; + isBool = rboolean.test( name ); + + // See #9699 for explanation of this approach (setting first, then removal) + // Do not do this for boolean attributes (see #10870) + if ( !isBool ) { + jQuery.attr( elem, name, "" ); + } + elem.removeAttribute( getSetAttribute ? name : propName ); + + // Set corresponding property to false for boolean attributes + if ( isBool && propName in elem ) { + elem[ propName ] = false; + } + } + } + } + }, + + attrHooks: { + type: { + set: function( elem, value ) { + // We can't allow the type property to be changed (since it causes problems in IE) + if ( rtype.test( elem.nodeName ) && elem.parentNode ) { + jQuery.error( "type property can't be changed" ); + } else if ( !jQuery.support.radioValue && value === "radio" && jQuery.nodeName(elem, "input") ) { + // Setting the type on a radio button after the value resets the value in IE6-9 + // Reset value to it's default in case type is set after value + // This is for element creation + var val = elem.value; + elem.setAttribute( "type", value ); + if ( val ) { + elem.value = val; + } + return value; + } + } + }, + // Use the value property for back compat + // Use the nodeHook for button elements in IE6/7 (#1954) + value: { + get: function( elem, name ) { + if ( nodeHook && jQuery.nodeName( elem, "button" ) ) { + return nodeHook.get( elem, name ); + } + return name in elem ? + elem.value : + null; + }, + set: function( elem, value, name ) { + if ( nodeHook && jQuery.nodeName( elem, "button" ) ) { + return nodeHook.set( elem, value, name ); + } + // Does not return so that setAttribute is also used + elem.value = value; + } + } + }, + + propFix: { + tabindex: "tabIndex", + readonly: "readOnly", + "for": "htmlFor", + "class": "className", + maxlength: "maxLength", + cellspacing: "cellSpacing", + cellpadding: "cellPadding", + rowspan: "rowSpan", + colspan: "colSpan", + usemap: "useMap", + frameborder: "frameBorder", + contenteditable: "contentEditable" + }, + + prop: function( elem, name, value ) { + var ret, hooks, notxml, + nType = elem.nodeType; + + // don't get/set properties on text, comment and attribute nodes + if ( !elem || nType === 3 || nType === 8 || nType === 2 ) { + return; + } + + notxml = nType !== 1 || !jQuery.isXMLDoc( elem ); + + if ( notxml ) { + // Fix name and attach hooks + name = jQuery.propFix[ name ] || name; + hooks = jQuery.propHooks[ name ]; + } + + if ( value !== undefined ) { + if ( hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) { + return ret; + + } else { + return ( elem[ name ] = value ); + } + + } else { + if ( hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) { + return ret; + + } else { + return elem[ name ]; + } + } + }, + + propHooks: { + tabIndex: { + get: function( elem ) { + // elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set + // http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/ + var attributeNode = elem.getAttributeNode("tabindex"); + + return attributeNode && attributeNode.specified ? + parseInt( attributeNode.value, 10 ) : + rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ? + 0 : + undefined; + } + } + } +}); + +// Add the tabIndex propHook to attrHooks for back-compat (different case is intentional) +jQuery.attrHooks.tabindex = jQuery.propHooks.tabIndex; + +// Hook for boolean attributes +boolHook = { + get: function( elem, name ) { + // Align boolean attributes with corresponding properties + // Fall back to attribute presence where some booleans are not supported + var attrNode, + property = jQuery.prop( elem, name ); + return property === true || typeof property !== "boolean" && ( attrNode = elem.getAttributeNode(name) ) && attrNode.nodeValue !== false ? + name.toLowerCase() : + undefined; + }, + set: function( elem, value, name ) { + var propName; + if ( value === false ) { + // Remove boolean attributes when set to false + jQuery.removeAttr( elem, name ); + } else { + // value is true since we know at this point it's type boolean and not false + // Set boolean attributes to the same name and set the DOM property + propName = jQuery.propFix[ name ] || name; + if ( propName in elem ) { + // Only set the IDL specifically if it already exists on the element + elem[ propName ] = true; + } + + elem.setAttribute( name, name.toLowerCase() ); + } + return name; + } +}; + +// IE6/7 do not support getting/setting some attributes with get/setAttribute +if ( !getSetAttribute ) { + + fixSpecified = { + name: true, + id: true, + coords: true + }; + + // Use this for any attribute in IE6/7 + // This fixes almost every IE6/7 issue + nodeHook = jQuery.valHooks.button = { + get: function( elem, name ) { + var ret; + ret = elem.getAttributeNode( name ); + return ret && ( fixSpecified[ name ] ? ret.nodeValue !== "" : ret.specified ) ? + ret.nodeValue : + undefined; + }, + set: function( elem, value, name ) { + // Set the existing or create a new attribute node + var ret = elem.getAttributeNode( name ); + if ( !ret ) { + ret = document.createAttribute( name ); + elem.setAttributeNode( ret ); + } + return ( ret.nodeValue = value + "" ); + } + }; + + // Apply the nodeHook to tabindex + jQuery.attrHooks.tabindex.set = nodeHook.set; + + // Set width and height to auto instead of 0 on empty string( Bug #8150 ) + // This is for removals + jQuery.each([ "width", "height" ], function( i, name ) { + jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], { + set: function( elem, value ) { + if ( value === "" ) { + elem.setAttribute( name, "auto" ); + return value; + } + } + }); + }); + + // Set contenteditable to false on removals(#10429) + // Setting to empty string throws an error as an invalid value + jQuery.attrHooks.contenteditable = { + get: nodeHook.get, + set: function( elem, value, name ) { + if ( value === "" ) { + value = "false"; + } + nodeHook.set( elem, value, name ); + } + }; +} + + +// Some attributes require a special call on IE +if ( !jQuery.support.hrefNormalized ) { + jQuery.each([ "href", "src", "width", "height" ], function( i, name ) { + jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], { + get: function( elem ) { + var ret = elem.getAttribute( name, 2 ); + return ret === null ? undefined : ret; + } + }); + }); +} + +if ( !jQuery.support.style ) { + jQuery.attrHooks.style = { + get: function( elem ) { + // Return undefined in the case of empty string + // Normalize to lowercase since IE uppercases css property names + return elem.style.cssText.toLowerCase() || undefined; + }, + set: function( elem, value ) { + return ( elem.style.cssText = "" + value ); + } + }; +} + +// Safari mis-reports the default selected property of an option +// Accessing the parent's selectedIndex property fixes it +if ( !jQuery.support.optSelected ) { + jQuery.propHooks.selected = jQuery.extend( jQuery.propHooks.selected, { + get: function( elem ) { + var parent = elem.parentNode; + + if ( parent ) { + parent.selectedIndex; + + // Make sure that it also works with optgroups, see #5701 + if ( parent.parentNode ) { + parent.parentNode.selectedIndex; + } + } + return null; + } + }); +} + +// IE6/7 call enctype encoding +if ( !jQuery.support.enctype ) { + jQuery.propFix.enctype = "encoding"; +} + +// Radios and checkboxes getter/setter +if ( !jQuery.support.checkOn ) { + jQuery.each([ "radio", "checkbox" ], function() { + jQuery.valHooks[ this ] = { + get: function( elem ) { + // Handle the case where in Webkit "" is returned instead of "on" if a value isn't specified + return elem.getAttribute("value") === null ? "on" : elem.value; + } + }; + }); +} +jQuery.each([ "radio", "checkbox" ], function() { + jQuery.valHooks[ this ] = jQuery.extend( jQuery.valHooks[ this ], { + set: function( elem, value ) { + if ( jQuery.isArray( value ) ) { + return ( elem.checked = jQuery.inArray( jQuery(elem).val(), value ) >= 0 ); + } + } + }); +}); + + + + +var rformElems = /^(?:textarea|input|select)$/i, + rtypenamespace = /^([^\.]*)?(?:\.(.+))?$/, + rhoverHack = /(?:^|\s)hover(\.\S+)?\b/, + rkeyEvent = /^key/, + rmouseEvent = /^(?:mouse|contextmenu)|click/, + rfocusMorph = /^(?:focusinfocus|focusoutblur)$/, + rquickIs = /^(\w*)(?:#([\w\-]+))?(?:\.([\w\-]+))?$/, + quickParse = function( selector ) { + var quick = rquickIs.exec( selector ); + if ( quick ) { + // 0 1 2 3 + // [ _, tag, id, class ] + quick[1] = ( quick[1] || "" ).toLowerCase(); + quick[3] = quick[3] && new RegExp( "(?:^|\\s)" + quick[3] + "(?:\\s|$)" ); + } + return quick; + }, + quickIs = function( elem, m ) { + var attrs = elem.attributes || {}; + return ( + (!m[1] || elem.nodeName.toLowerCase() === m[1]) && + (!m[2] || (attrs.id || {}).value === m[2]) && + (!m[3] || m[3].test( (attrs[ "class" ] || {}).value )) + ); + }, + hoverHack = function( events ) { + return jQuery.event.special.hover ? events : events.replace( rhoverHack, "mouseenter$1 mouseleave$1" ); + }; + +/* + * Helper functions for managing events -- not part of the public interface. + * Props to Dean Edwards' addEvent library for many of the ideas. + */ +jQuery.event = { + + add: function( elem, types, handler, data, selector ) { + + var elemData, eventHandle, events, + t, tns, type, namespaces, handleObj, + handleObjIn, quick, handlers, special; + + // Don't attach events to noData or text/comment nodes (allow plain objects tho) + if ( elem.nodeType === 3 || elem.nodeType === 8 || !types || !handler || !(elemData = jQuery._data( elem )) ) { + return; + } + + // Caller can pass in an object of custom data in lieu of the handler + if ( handler.handler ) { + handleObjIn = handler; + handler = handleObjIn.handler; + selector = handleObjIn.selector; + } + + // Make sure that the handler has a unique ID, used to find/remove it later + if ( !handler.guid ) { + handler.guid = jQuery.guid++; + } + + // Init the element's event structure and main handler, if this is the first + events = elemData.events; + if ( !events ) { + elemData.events = events = {}; + } + eventHandle = elemData.handle; + if ( !eventHandle ) { + elemData.handle = eventHandle = function( e ) { + // Discard the second event of a jQuery.event.trigger() and + // when an event is called after a page has unloaded + return typeof jQuery !== "undefined" && (!e || jQuery.event.triggered !== e.type) ? + jQuery.event.dispatch.apply( eventHandle.elem, arguments ) : + undefined; + }; + // Add elem as a property of the handle fn to prevent a memory leak with IE non-native events + eventHandle.elem = elem; + } + + // Handle multiple events separated by a space + // jQuery(...).bind("mouseover mouseout", fn); + types = jQuery.trim( hoverHack(types) ).split( " " ); + for ( t = 0; t < types.length; t++ ) { + + tns = rtypenamespace.exec( types[t] ) || []; + type = tns[1]; + namespaces = ( tns[2] || "" ).split( "." ).sort(); + + // If event changes its type, use the special event handlers for the changed type + special = jQuery.event.special[ type ] || {}; + + // If selector defined, determine special event api type, otherwise given type + type = ( selector ? special.delegateType : special.bindType ) || type; + + // Update special based on newly reset type + special = jQuery.event.special[ type ] || {}; + + // handleObj is passed to all event handlers + handleObj = jQuery.extend({ + type: type, + origType: tns[1], + data: data, + handler: handler, + guid: handler.guid, + selector: selector, + quick: selector && quickParse( selector ), + namespace: namespaces.join(".") + }, handleObjIn ); + + // Init the event handler queue if we're the first + handlers = events[ type ]; + if ( !handlers ) { + handlers = events[ type ] = []; + handlers.delegateCount = 0; + + // Only use addEventListener/attachEvent if the special events handler returns false + if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) { + // Bind the global event handler to the element + if ( elem.addEventListener ) { + elem.addEventListener( type, eventHandle, false ); + + } else if ( elem.attachEvent ) { + elem.attachEvent( "on" + type, eventHandle ); + } + } + } + + if ( special.add ) { + special.add.call( elem, handleObj ); + + if ( !handleObj.handler.guid ) { + handleObj.handler.guid = handler.guid; + } + } + + // Add to the element's handler list, delegates in front + if ( selector ) { + handlers.splice( handlers.delegateCount++, 0, handleObj ); + } else { + handlers.push( handleObj ); + } + + // Keep track of which events have ever been used, for event optimization + jQuery.event.global[ type ] = true; + } + + // Nullify elem to prevent memory leaks in IE + elem = null; + }, + + global: {}, + + // Detach an event or set of events from an element + remove: function( elem, types, handler, selector, mappedTypes ) { + + var elemData = jQuery.hasData( elem ) && jQuery._data( elem ), + t, tns, type, origType, namespaces, origCount, + j, events, special, handle, eventType, handleObj; + + if ( !elemData || !(events = elemData.events) ) { + return; + } + + // Once for each type.namespace in types; type may be omitted + types = jQuery.trim( hoverHack( types || "" ) ).split(" "); + for ( t = 0; t < types.length; t++ ) { + tns = rtypenamespace.exec( types[t] ) || []; + type = origType = tns[1]; + namespaces = tns[2]; + + // Unbind all events (on this namespace, if provided) for the element + if ( !type ) { + for ( type in events ) { + jQuery.event.remove( elem, type + types[ t ], handler, selector, true ); + } + continue; + } + + special = jQuery.event.special[ type ] || {}; + type = ( selector? special.delegateType : special.bindType ) || type; + eventType = events[ type ] || []; + origCount = eventType.length; + namespaces = namespaces ? new RegExp("(^|\\.)" + namespaces.split(".").sort().join("\\.(?:.*\\.)?") + "(\\.|$)") : null; + + // Remove matching events + for ( j = 0; j < eventType.length; j++ ) { + handleObj = eventType[ j ]; + + if ( ( mappedTypes || origType === handleObj.origType ) && + ( !handler || handler.guid === handleObj.guid ) && + ( !namespaces || namespaces.test( handleObj.namespace ) ) && + ( !selector || selector === handleObj.selector || selector === "**" && handleObj.selector ) ) { + eventType.splice( j--, 1 ); + + if ( handleObj.selector ) { + eventType.delegateCount--; + } + if ( special.remove ) { + special.remove.call( elem, handleObj ); + } + } + } + + // Remove generic event handler if we removed something and no more handlers exist + // (avoids potential for endless recursion during removal of special event handlers) + if ( eventType.length === 0 && origCount !== eventType.length ) { + if ( !special.teardown || special.teardown.call( elem, namespaces ) === false ) { + jQuery.removeEvent( elem, type, elemData.handle ); + } + + delete events[ type ]; + } + } + + // Remove the expando if it's no longer used + if ( jQuery.isEmptyObject( events ) ) { + handle = elemData.handle; + if ( handle ) { + handle.elem = null; + } + + // removeData also checks for emptiness and clears the expando if empty + // so use it instead of delete + jQuery.removeData( elem, [ "events", "handle" ], true ); + } + }, + + // Events that are safe to short-circuit if no handlers are attached. + // Native DOM events should not be added, they may have inline handlers. + customEvent: { + "getData": true, + "setData": true, + "changeData": true + }, + + trigger: function( event, data, elem, onlyHandlers ) { + // Don't do events on text and comment nodes + if ( elem && (elem.nodeType === 3 || elem.nodeType === 8) ) { + return; + } + + // Event object or event type + var type = event.type || event, + namespaces = [], + cache, exclusive, i, cur, old, ontype, special, handle, eventPath, bubbleType; + + // focus/blur morphs to focusin/out; ensure we're not firing them right now + if ( rfocusMorph.test( type + jQuery.event.triggered ) ) { + return; + } + + if ( type.indexOf( "!" ) >= 0 ) { + // Exclusive events trigger only for the exact event (no namespaces) + type = type.slice(0, -1); + exclusive = true; + } + + if ( type.indexOf( "." ) >= 0 ) { + // Namespaced trigger; create a regexp to match event type in handle() + namespaces = type.split("."); + type = namespaces.shift(); + namespaces.sort(); + } + + if ( (!elem || jQuery.event.customEvent[ type ]) && !jQuery.event.global[ type ] ) { + // No jQuery handlers for this event type, and it can't have inline handlers + return; + } + + // Caller can pass in an Event, Object, or just an event type string + event = typeof event === "object" ? + // jQuery.Event object + event[ jQuery.expando ] ? event : + // Object literal + new jQuery.Event( type, event ) : + // Just the event type (string) + new jQuery.Event( type ); + + event.type = type; + event.isTrigger = true; + event.exclusive = exclusive; + event.namespace = namespaces.join( "." ); + event.namespace_re = event.namespace? new RegExp("(^|\\.)" + namespaces.join("\\.(?:.*\\.)?") + "(\\.|$)") : null; + ontype = type.indexOf( ":" ) < 0 ? "on" + type : ""; + + // Handle a global trigger + if ( !elem ) { + + // TODO: Stop taunting the data cache; remove global events and always attach to document + cache = jQuery.cache; + for ( i in cache ) { + if ( cache[ i ].events && cache[ i ].events[ type ] ) { + jQuery.event.trigger( event, data, cache[ i ].handle.elem, true ); + } + } + return; + } + + // Clean up the event in case it is being reused + event.result = undefined; + if ( !event.target ) { + event.target = elem; + } + + // Clone any incoming data and prepend the event, creating the handler arg list + data = data != null ? jQuery.makeArray( data ) : []; + data.unshift( event ); + + // Allow special events to draw outside the lines + special = jQuery.event.special[ type ] || {}; + if ( special.trigger && special.trigger.apply( elem, data ) === false ) { + return; + } + + // Determine event propagation path in advance, per W3C events spec (#9951) + // Bubble up to document, then to window; watch for a global ownerDocument var (#9724) + eventPath = [[ elem, special.bindType || type ]]; + if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) { + + bubbleType = special.delegateType || type; + cur = rfocusMorph.test( bubbleType + type ) ? elem : elem.parentNode; + old = null; + for ( ; cur; cur = cur.parentNode ) { + eventPath.push([ cur, bubbleType ]); + old = cur; + } + + // Only add window if we got to document (e.g., not plain obj or detached DOM) + if ( old && old === elem.ownerDocument ) { + eventPath.push([ old.defaultView || old.parentWindow || window, bubbleType ]); + } + } + + // Fire handlers on the event path + for ( i = 0; i < eventPath.length && !event.isPropagationStopped(); i++ ) { + + cur = eventPath[i][0]; + event.type = eventPath[i][1]; + + handle = ( jQuery._data( cur, "events" ) || {} )[ event.type ] && jQuery._data( cur, "handle" ); + if ( handle ) { + handle.apply( cur, data ); + } + // Note that this is a bare JS function and not a jQuery handler + handle = ontype && cur[ ontype ]; + if ( handle && jQuery.acceptData( cur ) && handle.apply( cur, data ) === false ) { + event.preventDefault(); + } + } + event.type = type; + + // If nobody prevented the default action, do it now + if ( !onlyHandlers && !event.isDefaultPrevented() ) { + + if ( (!special._default || special._default.apply( elem.ownerDocument, data ) === false) && + !(type === "click" && jQuery.nodeName( elem, "a" )) && jQuery.acceptData( elem ) ) { + + // Call a native DOM method on the target with the same name name as the event. + // Can't use an .isFunction() check here because IE6/7 fails that test. + // Don't do default actions on window, that's where global variables be (#6170) + // IE<9 dies on focus/blur to hidden element (#1486) + if ( ontype && elem[ type ] && ((type !== "focus" && type !== "blur") || event.target.offsetWidth !== 0) && !jQuery.isWindow( elem ) ) { + + // Don't re-trigger an onFOO event when we call its FOO() method + old = elem[ ontype ]; + + if ( old ) { + elem[ ontype ] = null; + } + + // Prevent re-triggering of the same event, since we already bubbled it above + jQuery.event.triggered = type; + elem[ type ](); + jQuery.event.triggered = undefined; + + if ( old ) { + elem[ ontype ] = old; + } + } + } + } + + return event.result; + }, + + dispatch: function( event ) { + + // Make a writable jQuery.Event from the native event object + event = jQuery.event.fix( event || window.event ); + + var handlers = ( (jQuery._data( this, "events" ) || {} )[ event.type ] || []), + delegateCount = handlers.delegateCount, + args = [].slice.call( arguments, 0 ), + run_all = !event.exclusive && !event.namespace, + special = jQuery.event.special[ event.type ] || {}, + handlerQueue = [], + i, j, cur, jqcur, ret, selMatch, matched, matches, handleObj, sel, related; + + // Use the fix-ed jQuery.Event rather than the (read-only) native event + args[0] = event; + event.delegateTarget = this; + + // Call the preDispatch hook for the mapped type, and let it bail if desired + if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) { + return; + } + + // Determine handlers that should run if there are delegated events + // Avoid non-left-click bubbling in Firefox (#3861) + if ( delegateCount && !(event.button && event.type === "click") ) { + + // Pregenerate a single jQuery object for reuse with .is() + jqcur = jQuery(this); + jqcur.context = this.ownerDocument || this; + + for ( cur = event.target; cur != this; cur = cur.parentNode || this ) { + + // Don't process events on disabled elements (#6911, #8165) + if ( cur.disabled !== true ) { + selMatch = {}; + matches = []; + jqcur[0] = cur; + for ( i = 0; i < delegateCount; i++ ) { + handleObj = handlers[ i ]; + sel = handleObj.selector; + + if ( selMatch[ sel ] === undefined ) { + selMatch[ sel ] = ( + handleObj.quick ? quickIs( cur, handleObj.quick ) : jqcur.is( sel ) + ); + } + if ( selMatch[ sel ] ) { + matches.push( handleObj ); + } + } + if ( matches.length ) { + handlerQueue.push({ elem: cur, matches: matches }); + } + } + } + } + + // Add the remaining (directly-bound) handlers + if ( handlers.length > delegateCount ) { + handlerQueue.push({ elem: this, matches: handlers.slice( delegateCount ) }); + } + + // Run delegates first; they may want to stop propagation beneath us + for ( i = 0; i < handlerQueue.length && !event.isPropagationStopped(); i++ ) { + matched = handlerQueue[ i ]; + event.currentTarget = matched.elem; + + for ( j = 0; j < matched.matches.length && !event.isImmediatePropagationStopped(); j++ ) { + handleObj = matched.matches[ j ]; + + // Triggered event must either 1) be non-exclusive and have no namespace, or + // 2) have namespace(s) a subset or equal to those in the bound event (both can have no namespace). + if ( run_all || (!event.namespace && !handleObj.namespace) || event.namespace_re && event.namespace_re.test( handleObj.namespace ) ) { + + event.data = handleObj.data; + event.handleObj = handleObj; + + ret = ( (jQuery.event.special[ handleObj.origType ] || {}).handle || handleObj.handler ) + .apply( matched.elem, args ); + + if ( ret !== undefined ) { + event.result = ret; + if ( ret === false ) { + event.preventDefault(); + event.stopPropagation(); + } + } + } + } + } + + // Call the postDispatch hook for the mapped type + if ( special.postDispatch ) { + special.postDispatch.call( this, event ); + } + + return event.result; + }, + + // Includes some event props shared by KeyEvent and MouseEvent + // *** attrChange attrName relatedNode srcElement are not normalized, non-W3C, deprecated, will be removed in 1.8 *** + props: "attrChange attrName relatedNode srcElement altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "), + + fixHooks: {}, + + keyHooks: { + props: "char charCode key keyCode".split(" "), + filter: function( event, original ) { + + // Add which for key events + if ( event.which == null ) { + event.which = original.charCode != null ? original.charCode : original.keyCode; + } + + return event; + } + }, + + mouseHooks: { + props: "button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "), + filter: function( event, original ) { + var eventDoc, doc, body, + button = original.button, + fromElement = original.fromElement; + + // Calculate pageX/Y if missing and clientX/Y available + if ( event.pageX == null && original.clientX != null ) { + eventDoc = event.target.ownerDocument || document; + doc = eventDoc.documentElement; + body = eventDoc.body; + + event.pageX = original.clientX + ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - ( doc && doc.clientLeft || body && body.clientLeft || 0 ); + event.pageY = original.clientY + ( doc && doc.scrollTop || body && body.scrollTop || 0 ) - ( doc && doc.clientTop || body && body.clientTop || 0 ); + } + + // Add relatedTarget, if necessary + if ( !event.relatedTarget && fromElement ) { + event.relatedTarget = fromElement === event.target ? original.toElement : fromElement; + } + + // Add which for click: 1 === left; 2 === middle; 3 === right + // Note: button is not normalized, so don't use it + if ( !event.which && button !== undefined ) { + event.which = ( button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ) ); + } + + return event; + } + }, + + fix: function( event ) { + if ( event[ jQuery.expando ] ) { + return event; + } + + // Create a writable copy of the event object and normalize some properties + var i, prop, + originalEvent = event, + fixHook = jQuery.event.fixHooks[ event.type ] || {}, + copy = fixHook.props ? this.props.concat( fixHook.props ) : this.props; + + event = jQuery.Event( originalEvent ); + + for ( i = copy.length; i; ) { + prop = copy[ --i ]; + event[ prop ] = originalEvent[ prop ]; + } + + // Fix target property, if necessary (#1925, IE 6/7/8 & Safari2) + if ( !event.target ) { + event.target = originalEvent.srcElement || document; + } + + // Target should not be a text node (#504, Safari) + if ( event.target.nodeType === 3 ) { + event.target = event.target.parentNode; + } + + // For mouse/key events; add metaKey if it's not there (#3368, IE6/7/8) + if ( event.metaKey === undefined ) { + event.metaKey = event.ctrlKey; + } + + return fixHook.filter? fixHook.filter( event, originalEvent ) : event; + }, + + special: { + ready: { + // Make sure the ready event is setup + setup: jQuery.bindReady + }, + + load: { + // Prevent triggered image.load events from bubbling to window.load + noBubble: true + }, + + focus: { + delegateType: "focusin" + }, + blur: { + delegateType: "focusout" + }, + + beforeunload: { + setup: function( data, namespaces, eventHandle ) { + // We only want to do this special case on windows + if ( jQuery.isWindow( this ) ) { + this.onbeforeunload = eventHandle; + } + }, + + teardown: function( namespaces, eventHandle ) { + if ( this.onbeforeunload === eventHandle ) { + this.onbeforeunload = null; + } + } + } + }, + + simulate: function( type, elem, event, bubble ) { + // Piggyback on a donor event to simulate a different one. + // Fake originalEvent to avoid donor's stopPropagation, but if the + // simulated event prevents default then we do the same on the donor. + var e = jQuery.extend( + new jQuery.Event(), + event, + { type: type, + isSimulated: true, + originalEvent: {} + } + ); + if ( bubble ) { + jQuery.event.trigger( e, null, elem ); + } else { + jQuery.event.dispatch.call( elem, e ); + } + if ( e.isDefaultPrevented() ) { + event.preventDefault(); + } + } +}; + +// Some plugins are using, but it's undocumented/deprecated and will be removed. +// The 1.7 special event interface should provide all the hooks needed now. +jQuery.event.handle = jQuery.event.dispatch; + +jQuery.removeEvent = document.removeEventListener ? + function( elem, type, handle ) { + if ( elem.removeEventListener ) { + elem.removeEventListener( type, handle, false ); + } + } : + function( elem, type, handle ) { + if ( elem.detachEvent ) { + elem.detachEvent( "on" + type, handle ); + } + }; + +jQuery.Event = function( src, props ) { + // Allow instantiation without the 'new' keyword + if ( !(this instanceof jQuery.Event) ) { + return new jQuery.Event( src, props ); + } + + // Event object + if ( src && src.type ) { + this.originalEvent = src; + this.type = src.type; + + // Events bubbling up the document may have been marked as prevented + // by a handler lower down the tree; reflect the correct value. + this.isDefaultPrevented = ( src.defaultPrevented || src.returnValue === false || + src.getPreventDefault && src.getPreventDefault() ) ? returnTrue : returnFalse; + + // Event type + } else { + this.type = src; + } + + // Put explicitly provided properties onto the event object + if ( props ) { + jQuery.extend( this, props ); + } + + // Create a timestamp if incoming event doesn't have one + this.timeStamp = src && src.timeStamp || jQuery.now(); + + // Mark it as fixed + this[ jQuery.expando ] = true; +}; + +function returnFalse() { + return false; +} +function returnTrue() { + return true; +} + +// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding +// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html +jQuery.Event.prototype = { + preventDefault: function() { + this.isDefaultPrevented = returnTrue; + + var e = this.originalEvent; + if ( !e ) { + return; + } + + // if preventDefault exists run it on the original event + if ( e.preventDefault ) { + e.preventDefault(); + + // otherwise set the returnValue property of the original event to false (IE) + } else { + e.returnValue = false; + } + }, + stopPropagation: function() { + this.isPropagationStopped = returnTrue; + + var e = this.originalEvent; + if ( !e ) { + return; + } + // if stopPropagation exists run it on the original event + if ( e.stopPropagation ) { + e.stopPropagation(); + } + // otherwise set the cancelBubble property of the original event to true (IE) + e.cancelBubble = true; + }, + stopImmediatePropagation: function() { + this.isImmediatePropagationStopped = returnTrue; + this.stopPropagation(); + }, + isDefaultPrevented: returnFalse, + isPropagationStopped: returnFalse, + isImmediatePropagationStopped: returnFalse +}; + +// Create mouseenter/leave events using mouseover/out and event-time checks +jQuery.each({ + mouseenter: "mouseover", + mouseleave: "mouseout" +}, function( orig, fix ) { + jQuery.event.special[ orig ] = { + delegateType: fix, + bindType: fix, + + handle: function( event ) { + var target = this, + related = event.relatedTarget, + handleObj = event.handleObj, + selector = handleObj.selector, + ret; + + // For mousenter/leave call the handler if related is outside the target. + // NB: No relatedTarget if the mouse left/entered the browser window + if ( !related || (related !== target && !jQuery.contains( target, related )) ) { + event.type = handleObj.origType; + ret = handleObj.handler.apply( this, arguments ); + event.type = fix; + } + return ret; + } + }; +}); + +// IE submit delegation +if ( !jQuery.support.submitBubbles ) { + + jQuery.event.special.submit = { + setup: function() { + // Only need this for delegated form submit events + if ( jQuery.nodeName( this, "form" ) ) { + return false; + } + + // Lazy-add a submit handler when a descendant form may potentially be submitted + jQuery.event.add( this, "click._submit keypress._submit", function( e ) { + // Node name check avoids a VML-related crash in IE (#9807) + var elem = e.target, + form = jQuery.nodeName( elem, "input" ) || jQuery.nodeName( elem, "button" ) ? elem.form : undefined; + if ( form && !form._submit_attached ) { + jQuery.event.add( form, "submit._submit", function( event ) { + event._submit_bubble = true; + }); + form._submit_attached = true; + } + }); + // return undefined since we don't need an event listener + }, + + postDispatch: function( event ) { + // If form was submitted by the user, bubble the event up the tree + if ( event._submit_bubble ) { + delete event._submit_bubble; + if ( this.parentNode && !event.isTrigger ) { + jQuery.event.simulate( "submit", this.parentNode, event, true ); + } + } + }, + + teardown: function() { + // Only need this for delegated form submit events + if ( jQuery.nodeName( this, "form" ) ) { + return false; + } + + // Remove delegated handlers; cleanData eventually reaps submit handlers attached above + jQuery.event.remove( this, "._submit" ); + } + }; +} + +// IE change delegation and checkbox/radio fix +if ( !jQuery.support.changeBubbles ) { + + jQuery.event.special.change = { + + setup: function() { + + if ( rformElems.test( this.nodeName ) ) { + // IE doesn't fire change on a check/radio until blur; trigger it on click + // after a propertychange. Eat the blur-change in special.change.handle. + // This still fires onchange a second time for check/radio after blur. + if ( this.type === "checkbox" || this.type === "radio" ) { + jQuery.event.add( this, "propertychange._change", function( event ) { + if ( event.originalEvent.propertyName === "checked" ) { + this._just_changed = true; + } + }); + jQuery.event.add( this, "click._change", function( event ) { + if ( this._just_changed && !event.isTrigger ) { + this._just_changed = false; + jQuery.event.simulate( "change", this, event, true ); + } + }); + } + return false; + } + // Delegated event; lazy-add a change handler on descendant inputs + jQuery.event.add( this, "beforeactivate._change", function( e ) { + var elem = e.target; + + if ( rformElems.test( elem.nodeName ) && !elem._change_attached ) { + jQuery.event.add( elem, "change._change", function( event ) { + if ( this.parentNode && !event.isSimulated && !event.isTrigger ) { + jQuery.event.simulate( "change", this.parentNode, event, true ); + } + }); + elem._change_attached = true; + } + }); + }, + + handle: function( event ) { + var elem = event.target; + + // Swallow native change events from checkbox/radio, we already triggered them above + if ( this !== elem || event.isSimulated || event.isTrigger || (elem.type !== "radio" && elem.type !== "checkbox") ) { + return event.handleObj.handler.apply( this, arguments ); + } + }, + + teardown: function() { + jQuery.event.remove( this, "._change" ); + + return rformElems.test( this.nodeName ); + } + }; +} + +// Create "bubbling" focus and blur events +if ( !jQuery.support.focusinBubbles ) { + jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) { + + // Attach a single capturing handler while someone wants focusin/focusout + var attaches = 0, + handler = function( event ) { + jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ), true ); + }; + + jQuery.event.special[ fix ] = { + setup: function() { + if ( attaches++ === 0 ) { + document.addEventListener( orig, handler, true ); + } + }, + teardown: function() { + if ( --attaches === 0 ) { + document.removeEventListener( orig, handler, true ); + } + } + }; + }); +} + +jQuery.fn.extend({ + + on: function( types, selector, data, fn, /*INTERNAL*/ one ) { + var origFn, type; + + // Types can be a map of types/handlers + if ( typeof types === "object" ) { + // ( types-Object, selector, data ) + if ( typeof selector !== "string" ) { // && selector != null + // ( types-Object, data ) + data = data || selector; + selector = undefined; + } + for ( type in types ) { + this.on( type, selector, data, types[ type ], one ); + } + return this; + } + + if ( data == null && fn == null ) { + // ( types, fn ) + fn = selector; + data = selector = undefined; + } else if ( fn == null ) { + if ( typeof selector === "string" ) { + // ( types, selector, fn ) + fn = data; + data = undefined; + } else { + // ( types, data, fn ) + fn = data; + data = selector; + selector = undefined; + } + } + if ( fn === false ) { + fn = returnFalse; + } else if ( !fn ) { + return this; + } + + if ( one === 1 ) { + origFn = fn; + fn = function( event ) { + // Can use an empty set, since event contains the info + jQuery().off( event ); + return origFn.apply( this, arguments ); + }; + // Use same guid so caller can remove using origFn + fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ ); + } + return this.each( function() { + jQuery.event.add( this, types, fn, data, selector ); + }); + }, + one: function( types, selector, data, fn ) { + return this.on( types, selector, data, fn, 1 ); + }, + off: function( types, selector, fn ) { + if ( types && types.preventDefault && types.handleObj ) { + // ( event ) dispatched jQuery.Event + var handleObj = types.handleObj; + jQuery( types.delegateTarget ).off( + handleObj.namespace ? handleObj.origType + "." + handleObj.namespace : handleObj.origType, + handleObj.selector, + handleObj.handler + ); + return this; + } + if ( typeof types === "object" ) { + // ( types-object [, selector] ) + for ( var type in types ) { + this.off( type, selector, types[ type ] ); + } + return this; + } + if ( selector === false || typeof selector === "function" ) { + // ( types [, fn] ) + fn = selector; + selector = undefined; + } + if ( fn === false ) { + fn = returnFalse; + } + return this.each(function() { + jQuery.event.remove( this, types, fn, selector ); + }); + }, + + bind: function( types, data, fn ) { + return this.on( types, null, data, fn ); + }, + unbind: function( types, fn ) { + return this.off( types, null, fn ); + }, + + live: function( types, data, fn ) { + jQuery( this.context ).on( types, this.selector, data, fn ); + return this; + }, + die: function( types, fn ) { + jQuery( this.context ).off( types, this.selector || "**", fn ); + return this; + }, + + delegate: function( selector, types, data, fn ) { + return this.on( types, selector, data, fn ); + }, + undelegate: function( selector, types, fn ) { + // ( namespace ) or ( selector, types [, fn] ) + return arguments.length == 1? this.off( selector, "**" ) : this.off( types, selector, fn ); + }, + + trigger: function( type, data ) { + return this.each(function() { + jQuery.event.trigger( type, data, this ); + }); + }, + triggerHandler: function( type, data ) { + if ( this[0] ) { + return jQuery.event.trigger( type, data, this[0], true ); + } + }, + + toggle: function( fn ) { + // Save reference to arguments for access in closure + var args = arguments, + guid = fn.guid || jQuery.guid++, + i = 0, + toggler = function( event ) { + // Figure out which function to execute + var lastToggle = ( jQuery._data( this, "lastToggle" + fn.guid ) || 0 ) % i; + jQuery._data( this, "lastToggle" + fn.guid, lastToggle + 1 ); + + // Make sure that clicks stop + event.preventDefault(); + + // and execute the function + return args[ lastToggle ].apply( this, arguments ) || false; + }; + + // link all the functions, so any of them can unbind this click handler + toggler.guid = guid; + while ( i < args.length ) { + args[ i++ ].guid = guid; + } + + return this.click( toggler ); + }, + + hover: function( fnOver, fnOut ) { + return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver ); + } +}); + +jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " + + "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " + + "change select submit keydown keypress keyup error contextmenu").split(" "), function( i, name ) { + + // Handle event binding + jQuery.fn[ name ] = function( data, fn ) { + if ( fn == null ) { + fn = data; + data = null; + } + + return arguments.length > 0 ? + this.on( name, null, data, fn ) : + this.trigger( name ); + }; + + if ( jQuery.attrFn ) { + jQuery.attrFn[ name ] = true; + } + + if ( rkeyEvent.test( name ) ) { + jQuery.event.fixHooks[ name ] = jQuery.event.keyHooks; + } + + if ( rmouseEvent.test( name ) ) { + jQuery.event.fixHooks[ name ] = jQuery.event.mouseHooks; + } +}); + + + +/*! + * Sizzle CSS Selector Engine + * Copyright 2011, The Dojo Foundation + * Released under the MIT, BSD, and GPL Licenses. + * More information: http://sizzlejs.com/ + */ +(function(){ + +var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g, + expando = "sizcache" + (Math.random() + '').replace('.', ''), + done = 0, + toString = Object.prototype.toString, + hasDuplicate = false, + baseHasDuplicate = true, + rBackslash = /\\/g, + rReturn = /\r\n/g, + rNonWord = /\W/; + +// Here we check if the JavaScript engine is using some sort of +// optimization where it does not always call our comparision +// function. If that is the case, discard the hasDuplicate value. +// Thus far that includes Google Chrome. +[0, 0].sort(function() { + baseHasDuplicate = false; + return 0; +}); + +var Sizzle = function( selector, context, results, seed ) { + results = results || []; + context = context || document; + + var origContext = context; + + if ( context.nodeType !== 1 && context.nodeType !== 9 ) { + return []; + } + + if ( !selector || typeof selector !== "string" ) { + return results; + } + + var m, set, checkSet, extra, ret, cur, pop, i, + prune = true, + contextXML = Sizzle.isXML( context ), + parts = [], + soFar = selector; + + // Reset the position of the chunker regexp (start from head) + do { + chunker.exec( "" ); + m = chunker.exec( soFar ); + + if ( m ) { + soFar = m[3]; + + parts.push( m[1] ); + + if ( m[2] ) { + extra = m[3]; + break; + } + } + } while ( m ); + + if ( parts.length > 1 && origPOS.exec( selector ) ) { + + if ( parts.length === 2 && Expr.relative[ parts[0] ] ) { + set = posProcess( parts[0] + parts[1], context, seed ); + + } else { + set = Expr.relative[ parts[0] ] ? + [ context ] : + Sizzle( parts.shift(), context ); + + while ( parts.length ) { + selector = parts.shift(); + + if ( Expr.relative[ selector ] ) { + selector += parts.shift(); + } + + set = posProcess( selector, set, seed ); + } + } + + } else { + // Take a shortcut and set the context if the root selector is an ID + // (but not if it'll be faster if the inner selector is an ID) + if ( !seed && parts.length > 1 && context.nodeType === 9 && !contextXML && + Expr.match.ID.test(parts[0]) && !Expr.match.ID.test(parts[parts.length - 1]) ) { + + ret = Sizzle.find( parts.shift(), context, contextXML ); + context = ret.expr ? + Sizzle.filter( ret.expr, ret.set )[0] : + ret.set[0]; + } + + if ( context ) { + ret = seed ? + { expr: parts.pop(), set: makeArray(seed) } : + Sizzle.find( parts.pop(), parts.length === 1 && (parts[0] === "~" || parts[0] === "+") && context.parentNode ? context.parentNode : context, contextXML ); + + set = ret.expr ? + Sizzle.filter( ret.expr, ret.set ) : + ret.set; + + if ( parts.length > 0 ) { + checkSet = makeArray( set ); + + } else { + prune = false; + } + + while ( parts.length ) { + cur = parts.pop(); + pop = cur; + + if ( !Expr.relative[ cur ] ) { + cur = ""; + } else { + pop = parts.pop(); + } + + if ( pop == null ) { + pop = context; + } + + Expr.relative[ cur ]( checkSet, pop, contextXML ); + } + + } else { + checkSet = parts = []; + } + } + + if ( !checkSet ) { + checkSet = set; + } + + if ( !checkSet ) { + Sizzle.error( cur || selector ); + } + + if ( toString.call(checkSet) === "[object Array]" ) { + if ( !prune ) { + results.push.apply( results, checkSet ); + + } else if ( context && context.nodeType === 1 ) { + for ( i = 0; checkSet[i] != null; i++ ) { + if ( checkSet[i] && (checkSet[i] === true || checkSet[i].nodeType === 1 && Sizzle.contains(context, checkSet[i])) ) { + results.push( set[i] ); + } + } + + } else { + for ( i = 0; checkSet[i] != null; i++ ) { + if ( checkSet[i] && checkSet[i].nodeType === 1 ) { + results.push( set[i] ); + } + } + } + + } else { + makeArray( checkSet, results ); + } + + if ( extra ) { + Sizzle( extra, origContext, results, seed ); + Sizzle.uniqueSort( results ); + } + + return results; +}; + +Sizzle.uniqueSort = function( results ) { + if ( sortOrder ) { + hasDuplicate = baseHasDuplicate; + results.sort( sortOrder ); + + if ( hasDuplicate ) { + for ( var i = 1; i < results.length; i++ ) { + if ( results[i] === results[ i - 1 ] ) { + results.splice( i--, 1 ); + } + } + } + } + + return results; +}; + +Sizzle.matches = function( expr, set ) { + return Sizzle( expr, null, null, set ); +}; + +Sizzle.matchesSelector = function( node, expr ) { + return Sizzle( expr, null, null, [node] ).length > 0; +}; + +Sizzle.find = function( expr, context, isXML ) { + var set, i, len, match, type, left; + + if ( !expr ) { + return []; + } + + for ( i = 0, len = Expr.order.length; i < len; i++ ) { + type = Expr.order[i]; + + if ( (match = Expr.leftMatch[ type ].exec( expr )) ) { + left = match[1]; + match.splice( 1, 1 ); + + if ( left.substr( left.length - 1 ) !== "\\" ) { + match[1] = (match[1] || "").replace( rBackslash, "" ); + set = Expr.find[ type ]( match, context, isXML ); + + if ( set != null ) { + expr = expr.replace( Expr.match[ type ], "" ); + break; + } + } + } + } + + if ( !set ) { + set = typeof context.getElementsByTagName !== "undefined" ? + context.getElementsByTagName( "*" ) : + []; + } + + return { set: set, expr: expr }; +}; + +Sizzle.filter = function( expr, set, inplace, not ) { + var match, anyFound, + type, found, item, filter, left, + i, pass, + old = expr, + result = [], + curLoop = set, + isXMLFilter = set && set[0] && Sizzle.isXML( set[0] ); + + while ( expr && set.length ) { + for ( type in Expr.filter ) { + if ( (match = Expr.leftMatch[ type ].exec( expr )) != null && match[2] ) { + filter = Expr.filter[ type ]; + left = match[1]; + + anyFound = false; + + match.splice(1,1); + + if ( left.substr( left.length - 1 ) === "\\" ) { + continue; + } + + if ( curLoop === result ) { + result = []; + } + + if ( Expr.preFilter[ type ] ) { + match = Expr.preFilter[ type ]( match, curLoop, inplace, result, not, isXMLFilter ); + + if ( !match ) { + anyFound = found = true; + + } else if ( match === true ) { + continue; + } + } + + if ( match ) { + for ( i = 0; (item = curLoop[i]) != null; i++ ) { + if ( item ) { + found = filter( item, match, i, curLoop ); + pass = not ^ found; + + if ( inplace && found != null ) { + if ( pass ) { + anyFound = true; + + } else { + curLoop[i] = false; + } + + } else if ( pass ) { + result.push( item ); + anyFound = true; + } + } + } + } + + if ( found !== undefined ) { + if ( !inplace ) { + curLoop = result; + } + + expr = expr.replace( Expr.match[ type ], "" ); + + if ( !anyFound ) { + return []; + } + + break; + } + } + } + + // Improper expression + if ( expr === old ) { + if ( anyFound == null ) { + Sizzle.error( expr ); + + } else { + break; + } + } + + old = expr; + } + + return curLoop; +}; + +Sizzle.error = function( msg ) { + throw new Error( "Syntax error, unrecognized expression: " + msg ); +}; + +/** + * Utility function for retreiving the text value of an array of DOM nodes + * @param {Array|Element} elem + */ +var getText = Sizzle.getText = function( elem ) { + var i, node, + nodeType = elem.nodeType, + ret = ""; + + if ( nodeType ) { + if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) { + // Use textContent || innerText for elements + if ( typeof elem.textContent === 'string' ) { + return elem.textContent; + } else if ( typeof elem.innerText === 'string' ) { + // Replace IE's carriage returns + return elem.innerText.replace( rReturn, '' ); + } else { + // Traverse it's children + for ( elem = elem.firstChild; elem; elem = elem.nextSibling) { + ret += getText( elem ); + } + } + } else if ( nodeType === 3 || nodeType === 4 ) { + return elem.nodeValue; + } + } else { + + // If no nodeType, this is expected to be an array + for ( i = 0; (node = elem[i]); i++ ) { + // Do not traverse comment nodes + if ( node.nodeType !== 8 ) { + ret += getText( node ); + } + } + } + return ret; +}; + +var Expr = Sizzle.selectors = { + order: [ "ID", "NAME", "TAG" ], + + match: { + ID: /#((?:[\w\u00c0-\uFFFF\-]|\\.)+)/, + CLASS: /\.((?:[\w\u00c0-\uFFFF\-]|\\.)+)/, + NAME: /\[name=['"]*((?:[\w\u00c0-\uFFFF\-]|\\.)+)['"]*\]/, + ATTR: /\[\s*((?:[\w\u00c0-\uFFFF\-]|\\.)+)\s*(?:(\S?=)\s*(?:(['"])(.*?)\3|(#?(?:[\w\u00c0-\uFFFF\-]|\\.)*)|)|)\s*\]/, + TAG: /^((?:[\w\u00c0-\uFFFF\*\-]|\\.)+)/, + CHILD: /:(only|nth|last|first)-child(?:\(\s*(even|odd|(?:[+\-]?\d+|(?:[+\-]?\d*)?n\s*(?:[+\-]\s*\d+)?))\s*\))?/, + POS: /:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^\-]|$)/, + PSEUDO: /:((?:[\w\u00c0-\uFFFF\-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/ + }, + + leftMatch: {}, + + attrMap: { + "class": "className", + "for": "htmlFor" + }, + + attrHandle: { + href: function( elem ) { + return elem.getAttribute( "href" ); + }, + type: function( elem ) { + return elem.getAttribute( "type" ); + } + }, + + relative: { + "+": function(checkSet, part){ + var isPartStr = typeof part === "string", + isTag = isPartStr && !rNonWord.test( part ), + isPartStrNotTag = isPartStr && !isTag; + + if ( isTag ) { + part = part.toLowerCase(); + } + + for ( var i = 0, l = checkSet.length, elem; i < l; i++ ) { + if ( (elem = checkSet[i]) ) { + while ( (elem = elem.previousSibling) && elem.nodeType !== 1 ) {} + + checkSet[i] = isPartStrNotTag || elem && elem.nodeName.toLowerCase() === part ? + elem || false : + elem === part; + } + } + + if ( isPartStrNotTag ) { + Sizzle.filter( part, checkSet, true ); + } + }, + + ">": function( checkSet, part ) { + var elem, + isPartStr = typeof part === "string", + i = 0, + l = checkSet.length; + + if ( isPartStr && !rNonWord.test( part ) ) { + part = part.toLowerCase(); + + for ( ; i < l; i++ ) { + elem = checkSet[i]; + + if ( elem ) { + var parent = elem.parentNode; + checkSet[i] = parent.nodeName.toLowerCase() === part ? parent : false; + } + } + + } else { + for ( ; i < l; i++ ) { + elem = checkSet[i]; + + if ( elem ) { + checkSet[i] = isPartStr ? + elem.parentNode : + elem.parentNode === part; + } + } + + if ( isPartStr ) { + Sizzle.filter( part, checkSet, true ); + } + } + }, + + "": function(checkSet, part, isXML){ + var nodeCheck, + doneName = done++, + checkFn = dirCheck; + + if ( typeof part === "string" && !rNonWord.test( part ) ) { + part = part.toLowerCase(); + nodeCheck = part; + checkFn = dirNodeCheck; + } + + checkFn( "parentNode", part, doneName, checkSet, nodeCheck, isXML ); + }, + + "~": function( checkSet, part, isXML ) { + var nodeCheck, + doneName = done++, + checkFn = dirCheck; + + if ( typeof part === "string" && !rNonWord.test( part ) ) { + part = part.toLowerCase(); + nodeCheck = part; + checkFn = dirNodeCheck; + } + + checkFn( "previousSibling", part, doneName, checkSet, nodeCheck, isXML ); + } + }, + + find: { + ID: function( match, context, isXML ) { + if ( typeof context.getElementById !== "undefined" && !isXML ) { + var m = context.getElementById(match[1]); + // Check parentNode to catch when Blackberry 4.6 returns + // nodes that are no longer in the document #6963 + return m && m.parentNode ? [m] : []; + } + }, + + NAME: function( match, context ) { + if ( typeof context.getElementsByName !== "undefined" ) { + var ret = [], + results = context.getElementsByName( match[1] ); + + for ( var i = 0, l = results.length; i < l; i++ ) { + if ( results[i].getAttribute("name") === match[1] ) { + ret.push( results[i] ); + } + } + + return ret.length === 0 ? null : ret; + } + }, + + TAG: function( match, context ) { + if ( typeof context.getElementsByTagName !== "undefined" ) { + return context.getElementsByTagName( match[1] ); + } + } + }, + preFilter: { + CLASS: function( match, curLoop, inplace, result, not, isXML ) { + match = " " + match[1].replace( rBackslash, "" ) + " "; + + if ( isXML ) { + return match; + } + + for ( var i = 0, elem; (elem = curLoop[i]) != null; i++ ) { + if ( elem ) { + if ( not ^ (elem.className && (" " + elem.className + " ").replace(/[\t\n\r]/g, " ").indexOf(match) >= 0) ) { + if ( !inplace ) { + result.push( elem ); + } + + } else if ( inplace ) { + curLoop[i] = false; + } + } + } + + return false; + }, + + ID: function( match ) { + return match[1].replace( rBackslash, "" ); + }, + + TAG: function( match, curLoop ) { + return match[1].replace( rBackslash, "" ).toLowerCase(); + }, + + CHILD: function( match ) { + if ( match[1] === "nth" ) { + if ( !match[2] ) { + Sizzle.error( match[0] ); + } + + match[2] = match[2].replace(/^\+|\s*/g, ''); + + // parse equations like 'even', 'odd', '5', '2n', '3n+2', '4n-1', '-n+6' + var test = /(-?)(\d*)(?:n([+\-]?\d*))?/.exec( + match[2] === "even" && "2n" || match[2] === "odd" && "2n+1" || + !/\D/.test( match[2] ) && "0n+" + match[2] || match[2]); + + // calculate the numbers (first)n+(last) including if they are negative + match[2] = (test[1] + (test[2] || 1)) - 0; + match[3] = test[3] - 0; + } + else if ( match[2] ) { + Sizzle.error( match[0] ); + } + + // TODO: Move to normal caching system + match[0] = done++; + + return match; + }, + + ATTR: function( match, curLoop, inplace, result, not, isXML ) { + var name = match[1] = match[1].replace( rBackslash, "" ); + + if ( !isXML && Expr.attrMap[name] ) { + match[1] = Expr.attrMap[name]; + } + + // Handle if an un-quoted value was used + match[4] = ( match[4] || match[5] || "" ).replace( rBackslash, "" ); + + if ( match[2] === "~=" ) { + match[4] = " " + match[4] + " "; + } + + return match; + }, + + PSEUDO: function( match, curLoop, inplace, result, not ) { + if ( match[1] === "not" ) { + // If we're dealing with a complex expression, or a simple one + if ( ( chunker.exec(match[3]) || "" ).length > 1 || /^\w/.test(match[3]) ) { + match[3] = Sizzle(match[3], null, null, curLoop); + + } else { + var ret = Sizzle.filter(match[3], curLoop, inplace, true ^ not); + + if ( !inplace ) { + result.push.apply( result, ret ); + } + + return false; + } + + } else if ( Expr.match.POS.test( match[0] ) || Expr.match.CHILD.test( match[0] ) ) { + return true; + } + + return match; + }, + + POS: function( match ) { + match.unshift( true ); + + return match; + } + }, + + filters: { + enabled: function( elem ) { + return elem.disabled === false && elem.type !== "hidden"; + }, + + disabled: function( elem ) { + return elem.disabled === true; + }, + + checked: function( elem ) { + return elem.checked === true; + }, + + selected: function( elem ) { + // Accessing this property makes selected-by-default + // options in Safari work properly + if ( elem.parentNode ) { + elem.parentNode.selectedIndex; + } + + return elem.selected === true; + }, + + parent: function( elem ) { + return !!elem.firstChild; + }, + + empty: function( elem ) { + return !elem.firstChild; + }, + + has: function( elem, i, match ) { + return !!Sizzle( match[3], elem ).length; + }, + + header: function( elem ) { + return (/h\d/i).test( elem.nodeName ); + }, + + text: function( elem ) { + var attr = elem.getAttribute( "type" ), type = elem.type; + // IE6 and 7 will map elem.type to 'text' for new HTML5 types (search, etc) + // use getAttribute instead to test this case + return elem.nodeName.toLowerCase() === "input" && "text" === type && ( attr === type || attr === null ); + }, + + radio: function( elem ) { + return elem.nodeName.toLowerCase() === "input" && "radio" === elem.type; + }, + + checkbox: function( elem ) { + return elem.nodeName.toLowerCase() === "input" && "checkbox" === elem.type; + }, + + file: function( elem ) { + return elem.nodeName.toLowerCase() === "input" && "file" === elem.type; + }, + + password: function( elem ) { + return elem.nodeName.toLowerCase() === "input" && "password" === elem.type; + }, + + submit: function( elem ) { + var name = elem.nodeName.toLowerCase(); + return (name === "input" || name === "button") && "submit" === elem.type; + }, + + image: function( elem ) { + return elem.nodeName.toLowerCase() === "input" && "image" === elem.type; + }, + + reset: function( elem ) { + var name = elem.nodeName.toLowerCase(); + return (name === "input" || name === "button") && "reset" === elem.type; + }, + + button: function( elem ) { + var name = elem.nodeName.toLowerCase(); + return name === "input" && "button" === elem.type || name === "button"; + }, + + input: function( elem ) { + return (/input|select|textarea|button/i).test( elem.nodeName ); + }, + + focus: function( elem ) { + return elem === elem.ownerDocument.activeElement; + } + }, + setFilters: { + first: function( elem, i ) { + return i === 0; + }, + + last: function( elem, i, match, array ) { + return i === array.length - 1; + }, + + even: function( elem, i ) { + return i % 2 === 0; + }, + + odd: function( elem, i ) { + return i % 2 === 1; + }, + + lt: function( elem, i, match ) { + return i < match[3] - 0; + }, + + gt: function( elem, i, match ) { + return i > match[3] - 0; + }, + + nth: function( elem, i, match ) { + return match[3] - 0 === i; + }, + + eq: function( elem, i, match ) { + return match[3] - 0 === i; + } + }, + filter: { + PSEUDO: function( elem, match, i, array ) { + var name = match[1], + filter = Expr.filters[ name ]; + + if ( filter ) { + return filter( elem, i, match, array ); + + } else if ( name === "contains" ) { + return (elem.textContent || elem.innerText || getText([ elem ]) || "").indexOf(match[3]) >= 0; + + } else if ( name === "not" ) { + var not = match[3]; + + for ( var j = 0, l = not.length; j < l; j++ ) { + if ( not[j] === elem ) { + return false; + } + } + + return true; + + } else { + Sizzle.error( name ); + } + }, + + CHILD: function( elem, match ) { + var first, last, + doneName, parent, cache, + count, diff, + type = match[1], + node = elem; + + switch ( type ) { + case "only": + case "first": + while ( (node = node.previousSibling) ) { + if ( node.nodeType === 1 ) { + return false; + } + } + + if ( type === "first" ) { + return true; + } + + node = elem; + + /* falls through */ + case "last": + while ( (node = node.nextSibling) ) { + if ( node.nodeType === 1 ) { + return false; + } + } + + return true; + + case "nth": + first = match[2]; + last = match[3]; + + if ( first === 1 && last === 0 ) { + return true; + } + + doneName = match[0]; + parent = elem.parentNode; + + if ( parent && (parent[ expando ] !== doneName || !elem.nodeIndex) ) { + count = 0; + + for ( node = parent.firstChild; node; node = node.nextSibling ) { + if ( node.nodeType === 1 ) { + node.nodeIndex = ++count; + } + } + + parent[ expando ] = doneName; + } + + diff = elem.nodeIndex - last; + + if ( first === 0 ) { + return diff === 0; + + } else { + return ( diff % first === 0 && diff / first >= 0 ); + } + } + }, + + ID: function( elem, match ) { + return elem.nodeType === 1 && elem.getAttribute("id") === match; + }, + + TAG: function( elem, match ) { + return (match === "*" && elem.nodeType === 1) || !!elem.nodeName && elem.nodeName.toLowerCase() === match; + }, + + CLASS: function( elem, match ) { + return (" " + (elem.className || elem.getAttribute("class")) + " ") + .indexOf( match ) > -1; + }, + + ATTR: function( elem, match ) { + var name = match[1], + result = Sizzle.attr ? + Sizzle.attr( elem, name ) : + Expr.attrHandle[ name ] ? + Expr.attrHandle[ name ]( elem ) : + elem[ name ] != null ? + elem[ name ] : + elem.getAttribute( name ), + value = result + "", + type = match[2], + check = match[4]; + + return result == null ? + type === "!=" : + !type && Sizzle.attr ? + result != null : + type === "=" ? + value === check : + type === "*=" ? + value.indexOf(check) >= 0 : + type === "~=" ? + (" " + value + " ").indexOf(check) >= 0 : + !check ? + value && result !== false : + type === "!=" ? + value !== check : + type === "^=" ? + value.indexOf(check) === 0 : + type === "$=" ? + value.substr(value.length - check.length) === check : + type === "|=" ? + value === check || value.substr(0, check.length + 1) === check + "-" : + false; + }, + + POS: function( elem, match, i, array ) { + var name = match[2], + filter = Expr.setFilters[ name ]; + + if ( filter ) { + return filter( elem, i, match, array ); + } + } + } +}; + +var origPOS = Expr.match.POS, + fescape = function(all, num){ + return "\\" + (num - 0 + 1); + }; + +for ( var type in Expr.match ) { + Expr.match[ type ] = new RegExp( Expr.match[ type ].source + (/(?![^\[]*\])(?![^\(]*\))/.source) ); + Expr.leftMatch[ type ] = new RegExp( /(^(?:.|\r|\n)*?)/.source + Expr.match[ type ].source.replace(/\\(\d+)/g, fescape) ); +} +// Expose origPOS +// "global" as in regardless of relation to brackets/parens +Expr.match.globalPOS = origPOS; + +var makeArray = function( array, results ) { + array = Array.prototype.slice.call( array, 0 ); + + if ( results ) { + results.push.apply( results, array ); + return results; + } + + return array; +}; + +// Perform a simple check to determine if the browser is capable of +// converting a NodeList to an array using builtin methods. +// Also verifies that the returned array holds DOM nodes +// (which is not the case in the Blackberry browser) +try { + Array.prototype.slice.call( document.documentElement.childNodes, 0 )[0].nodeType; + +// Provide a fallback method if it does not work +} catch( e ) { + makeArray = function( array, results ) { + var i = 0, + ret = results || []; + + if ( toString.call(array) === "[object Array]" ) { + Array.prototype.push.apply( ret, array ); + + } else { + if ( typeof array.length === "number" ) { + for ( var l = array.length; i < l; i++ ) { + ret.push( array[i] ); + } + + } else { + for ( ; array[i]; i++ ) { + ret.push( array[i] ); + } + } + } + + return ret; + }; +} + +var sortOrder, siblingCheck; + +if ( document.documentElement.compareDocumentPosition ) { + sortOrder = function( a, b ) { + if ( a === b ) { + hasDuplicate = true; + return 0; + } + + if ( !a.compareDocumentPosition || !b.compareDocumentPosition ) { + return a.compareDocumentPosition ? -1 : 1; + } + + return a.compareDocumentPosition(b) & 4 ? -1 : 1; + }; + +} else { + sortOrder = function( a, b ) { + // The nodes are identical, we can exit early + if ( a === b ) { + hasDuplicate = true; + return 0; + + // Fallback to using sourceIndex (in IE) if it's available on both nodes + } else if ( a.sourceIndex && b.sourceIndex ) { + return a.sourceIndex - b.sourceIndex; + } + + var al, bl, + ap = [], + bp = [], + aup = a.parentNode, + bup = b.parentNode, + cur = aup; + + // If the nodes are siblings (or identical) we can do a quick check + if ( aup === bup ) { + return siblingCheck( a, b ); + + // If no parents were found then the nodes are disconnected + } else if ( !aup ) { + return -1; + + } else if ( !bup ) { + return 1; + } + + // Otherwise they're somewhere else in the tree so we need + // to build up a full list of the parentNodes for comparison + while ( cur ) { + ap.unshift( cur ); + cur = cur.parentNode; + } + + cur = bup; + + while ( cur ) { + bp.unshift( cur ); + cur = cur.parentNode; + } + + al = ap.length; + bl = bp.length; + + // Start walking down the tree looking for a discrepancy + for ( var i = 0; i < al && i < bl; i++ ) { + if ( ap[i] !== bp[i] ) { + return siblingCheck( ap[i], bp[i] ); + } + } + + // We ended someplace up the tree so do a sibling check + return i === al ? + siblingCheck( a, bp[i], -1 ) : + siblingCheck( ap[i], b, 1 ); + }; + + siblingCheck = function( a, b, ret ) { + if ( a === b ) { + return ret; + } + + var cur = a.nextSibling; + + while ( cur ) { + if ( cur === b ) { + return -1; + } + + cur = cur.nextSibling; + } + + return 1; + }; +} + +// Check to see if the browser returns elements by name when +// querying by getElementById (and provide a workaround) +(function(){ + // We're going to inject a fake input element with a specified name + var form = document.createElement("div"), + id = "script" + (new Date()).getTime(), + root = document.documentElement; + + form.innerHTML = ""; + + // Inject it into the root element, check its status, and remove it quickly + root.insertBefore( form, root.firstChild ); + + // The workaround has to do additional checks after a getElementById + // Which slows things down for other browsers (hence the branching) + if ( document.getElementById( id ) ) { + Expr.find.ID = function( match, context, isXML ) { + if ( typeof context.getElementById !== "undefined" && !isXML ) { + var m = context.getElementById(match[1]); + + return m ? + m.id === match[1] || typeof m.getAttributeNode !== "undefined" && m.getAttributeNode("id").nodeValue === match[1] ? + [m] : + undefined : + []; + } + }; + + Expr.filter.ID = function( elem, match ) { + var node = typeof elem.getAttributeNode !== "undefined" && elem.getAttributeNode("id"); + + return elem.nodeType === 1 && node && node.nodeValue === match; + }; + } + + root.removeChild( form ); + + // release memory in IE + root = form = null; +})(); + +(function(){ + // Check to see if the browser returns only elements + // when doing getElementsByTagName("*") + + // Create a fake element + var div = document.createElement("div"); + div.appendChild( document.createComment("") ); + + // Make sure no comments are found + if ( div.getElementsByTagName("*").length > 0 ) { + Expr.find.TAG = function( match, context ) { + var results = context.getElementsByTagName( match[1] ); + + // Filter out possible comments + if ( match[1] === "*" ) { + var tmp = []; + + for ( var i = 0; results[i]; i++ ) { + if ( results[i].nodeType === 1 ) { + tmp.push( results[i] ); + } + } + + results = tmp; + } + + return results; + }; + } + + // Check to see if an attribute returns normalized href attributes + div.innerHTML = ""; + + if ( div.firstChild && typeof div.firstChild.getAttribute !== "undefined" && + div.firstChild.getAttribute("href") !== "#" ) { + + Expr.attrHandle.href = function( elem ) { + return elem.getAttribute( "href", 2 ); + }; + } + + // release memory in IE + div = null; +})(); + +if ( document.querySelectorAll ) { + (function(){ + var oldSizzle = Sizzle, + div = document.createElement("div"), + id = "__sizzle__"; + + div.innerHTML = "

"; + + // Safari can't handle uppercase or unicode characters when + // in quirks mode. + if ( div.querySelectorAll && div.querySelectorAll(".TEST").length === 0 ) { + return; + } + + Sizzle = function( query, context, extra, seed ) { + context = context || document; + + // Only use querySelectorAll on non-XML documents + // (ID selectors don't work in non-HTML documents) + if ( !seed && !Sizzle.isXML(context) ) { + // See if we find a selector to speed up + var match = /^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec( query ); + + if ( match && (context.nodeType === 1 || context.nodeType === 9) ) { + // Speed-up: Sizzle("TAG") + if ( match[1] ) { + return makeArray( context.getElementsByTagName( query ), extra ); + + // Speed-up: Sizzle(".CLASS") + } else if ( match[2] && Expr.find.CLASS && context.getElementsByClassName ) { + return makeArray( context.getElementsByClassName( match[2] ), extra ); + } + } + + if ( context.nodeType === 9 ) { + // Speed-up: Sizzle("body") + // The body element only exists once, optimize finding it + if ( query === "body" && context.body ) { + return makeArray( [ context.body ], extra ); + + // Speed-up: Sizzle("#ID") + } else if ( match && match[3] ) { + var elem = context.getElementById( match[3] ); + + // Check parentNode to catch when Blackberry 4.6 returns + // nodes that are no longer in the document #6963 + if ( elem && elem.parentNode ) { + // Handle the case where IE and Opera return items + // by name instead of ID + if ( elem.id === match[3] ) { + return makeArray( [ elem ], extra ); + } + + } else { + return makeArray( [], extra ); + } + } + + try { + return makeArray( context.querySelectorAll(query), extra ); + } catch(qsaError) {} + + // qSA works strangely on Element-rooted queries + // We can work around this by specifying an extra ID on the root + // and working up from there (Thanks to Andrew Dupont for the technique) + // IE 8 doesn't work on object elements + } else if ( context.nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) { + var oldContext = context, + old = context.getAttribute( "id" ), + nid = old || id, + hasParent = context.parentNode, + relativeHierarchySelector = /^\s*[+~]/.test( query ); + + if ( !old ) { + context.setAttribute( "id", nid ); + } else { + nid = nid.replace( /'/g, "\\$&" ); + } + if ( relativeHierarchySelector && hasParent ) { + context = context.parentNode; + } + + try { + if ( !relativeHierarchySelector || hasParent ) { + return makeArray( context.querySelectorAll( "[id='" + nid + "'] " + query ), extra ); + } + + } catch(pseudoError) { + } finally { + if ( !old ) { + oldContext.removeAttribute( "id" ); + } + } + } + } + + return oldSizzle(query, context, extra, seed); + }; + + for ( var prop in oldSizzle ) { + Sizzle[ prop ] = oldSizzle[ prop ]; + } + + // release memory in IE + div = null; + })(); +} + +(function(){ + var html = document.documentElement, + matches = html.matchesSelector || html.mozMatchesSelector || html.webkitMatchesSelector || html.msMatchesSelector; + + if ( matches ) { + // Check to see if it's possible to do matchesSelector + // on a disconnected node (IE 9 fails this) + var disconnectedMatch = !matches.call( document.createElement( "div" ), "div" ), + pseudoWorks = false; + + try { + // This should fail with an exception + // Gecko does not error, returns false instead + matches.call( document.documentElement, "[test!='']:sizzle" ); + + } catch( pseudoError ) { + pseudoWorks = true; + } + + Sizzle.matchesSelector = function( node, expr ) { + // Make sure that attribute selectors are quoted + expr = expr.replace(/\=\s*([^'"\]]*)\s*\]/g, "='$1']"); + + if ( !Sizzle.isXML( node ) ) { + try { + if ( pseudoWorks || !Expr.match.PSEUDO.test( expr ) && !/!=/.test( expr ) ) { + var ret = matches.call( node, expr ); + + // IE 9's matchesSelector returns false on disconnected nodes + if ( ret || !disconnectedMatch || + // As well, disconnected nodes are said to be in a document + // fragment in IE 9, so check for that + node.document && node.document.nodeType !== 11 ) { + return ret; + } + } + } catch(e) {} + } + + return Sizzle(expr, null, null, [node]).length > 0; + }; + } +})(); + +(function(){ + var div = document.createElement("div"); + + div.innerHTML = "
"; + + // Opera can't find a second classname (in 9.6) + // Also, make sure that getElementsByClassName actually exists + if ( !div.getElementsByClassName || div.getElementsByClassName("e").length === 0 ) { + return; + } + + // Safari caches class attributes, doesn't catch changes (in 3.2) + div.lastChild.className = "e"; + + if ( div.getElementsByClassName("e").length === 1 ) { + return; + } + + Expr.order.splice(1, 0, "CLASS"); + Expr.find.CLASS = function( match, context, isXML ) { + if ( typeof context.getElementsByClassName !== "undefined" && !isXML ) { + return context.getElementsByClassName(match[1]); + } + }; + + // release memory in IE + div = null; +})(); + +function dirNodeCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) { + for ( var i = 0, l = checkSet.length; i < l; i++ ) { + var elem = checkSet[i]; + + if ( elem ) { + var match = false; + + elem = elem[dir]; + + while ( elem ) { + if ( elem[ expando ] === doneName ) { + match = checkSet[elem.sizset]; + break; + } + + if ( elem.nodeType === 1 && !isXML ){ + elem[ expando ] = doneName; + elem.sizset = i; + } + + if ( elem.nodeName.toLowerCase() === cur ) { + match = elem; + break; + } + + elem = elem[dir]; + } + + checkSet[i] = match; + } + } +} + +function dirCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) { + for ( var i = 0, l = checkSet.length; i < l; i++ ) { + var elem = checkSet[i]; + + if ( elem ) { + var match = false; + + elem = elem[dir]; + + while ( elem ) { + if ( elem[ expando ] === doneName ) { + match = checkSet[elem.sizset]; + break; + } + + if ( elem.nodeType === 1 ) { + if ( !isXML ) { + elem[ expando ] = doneName; + elem.sizset = i; + } + + if ( typeof cur !== "string" ) { + if ( elem === cur ) { + match = true; + break; + } + + } else if ( Sizzle.filter( cur, [elem] ).length > 0 ) { + match = elem; + break; + } + } + + elem = elem[dir]; + } + + checkSet[i] = match; + } + } +} + +if ( document.documentElement.contains ) { + Sizzle.contains = function( a, b ) { + return a !== b && (a.contains ? a.contains(b) : true); + }; + +} else if ( document.documentElement.compareDocumentPosition ) { + Sizzle.contains = function( a, b ) { + return !!(a.compareDocumentPosition(b) & 16); + }; + +} else { + Sizzle.contains = function() { + return false; + }; +} + +Sizzle.isXML = function( elem ) { + // documentElement is verified for cases where it doesn't yet exist + // (such as loading iframes in IE - #4833) + var documentElement = (elem ? elem.ownerDocument || elem : 0).documentElement; + + return documentElement ? documentElement.nodeName !== "HTML" : false; +}; + +var posProcess = function( selector, context, seed ) { + var match, + tmpSet = [], + later = "", + root = context.nodeType ? [context] : context; + + // Position selectors must be done after the filter + // And so must :not(positional) so we move all PSEUDOs to the end + while ( (match = Expr.match.PSEUDO.exec( selector )) ) { + later += match[0]; + selector = selector.replace( Expr.match.PSEUDO, "" ); + } + + selector = Expr.relative[selector] ? selector + "*" : selector; + + for ( var i = 0, l = root.length; i < l; i++ ) { + Sizzle( selector, root[i], tmpSet, seed ); + } + + return Sizzle.filter( later, tmpSet ); +}; + +// EXPOSE +// Override sizzle attribute retrieval +Sizzle.attr = jQuery.attr; +Sizzle.selectors.attrMap = {}; +jQuery.find = Sizzle; +jQuery.expr = Sizzle.selectors; +jQuery.expr[":"] = jQuery.expr.filters; +jQuery.unique = Sizzle.uniqueSort; +jQuery.text = Sizzle.getText; +jQuery.isXMLDoc = Sizzle.isXML; +jQuery.contains = Sizzle.contains; + + +})(); + + +var runtil = /Until$/, + rparentsprev = /^(?:parents|prevUntil|prevAll)/, + // Note: This RegExp should be improved, or likely pulled from Sizzle + rmultiselector = /,/, + isSimple = /^.[^:#\[\.,]*$/, + slice = Array.prototype.slice, + POS = jQuery.expr.match.globalPOS, + // methods guaranteed to produce a unique set when starting from a unique set + guaranteedUnique = { + children: true, + contents: true, + next: true, + prev: true + }; + +jQuery.fn.extend({ + find: function( selector ) { + var self = this, + i, l; + + if ( typeof selector !== "string" ) { + return jQuery( selector ).filter(function() { + for ( i = 0, l = self.length; i < l; i++ ) { + if ( jQuery.contains( self[ i ], this ) ) { + return true; + } + } + }); + } + + var ret = this.pushStack( "", "find", selector ), + length, n, r; + + for ( i = 0, l = this.length; i < l; i++ ) { + length = ret.length; + jQuery.find( selector, this[i], ret ); + + if ( i > 0 ) { + // Make sure that the results are unique + for ( n = length; n < ret.length; n++ ) { + for ( r = 0; r < length; r++ ) { + if ( ret[r] === ret[n] ) { + ret.splice(n--, 1); + break; + } + } + } + } + } + + return ret; + }, + + has: function( target ) { + var targets = jQuery( target ); + return this.filter(function() { + for ( var i = 0, l = targets.length; i < l; i++ ) { + if ( jQuery.contains( this, targets[i] ) ) { + return true; + } + } + }); + }, + + not: function( selector ) { + return this.pushStack( winnow(this, selector, false), "not", selector); + }, + + filter: function( selector ) { + return this.pushStack( winnow(this, selector, true), "filter", selector ); + }, + + is: function( selector ) { + return !!selector && ( + typeof selector === "string" ? + // If this is a positional selector, check membership in the returned set + // so $("p:first").is("p:last") won't return true for a doc with two "p". + POS.test( selector ) ? + jQuery( selector, this.context ).index( this[0] ) >= 0 : + jQuery.filter( selector, this ).length > 0 : + this.filter( selector ).length > 0 ); + }, + + closest: function( selectors, context ) { + var ret = [], i, l, cur = this[0]; + + // Array (deprecated as of jQuery 1.7) + if ( jQuery.isArray( selectors ) ) { + var level = 1; + + while ( cur && cur.ownerDocument && cur !== context ) { + for ( i = 0; i < selectors.length; i++ ) { + + if ( jQuery( cur ).is( selectors[ i ] ) ) { + ret.push({ selector: selectors[ i ], elem: cur, level: level }); + } + } + + cur = cur.parentNode; + level++; + } + + return ret; + } + + // String + var pos = POS.test( selectors ) || typeof selectors !== "string" ? + jQuery( selectors, context || this.context ) : + 0; + + for ( i = 0, l = this.length; i < l; i++ ) { + cur = this[i]; + + while ( cur ) { + if ( pos ? pos.index(cur) > -1 : jQuery.find.matchesSelector(cur, selectors) ) { + ret.push( cur ); + break; + + } else { + cur = cur.parentNode; + if ( !cur || !cur.ownerDocument || cur === context || cur.nodeType === 11 ) { + break; + } + } + } + } + + ret = ret.length > 1 ? jQuery.unique( ret ) : ret; + + return this.pushStack( ret, "closest", selectors ); + }, + + // Determine the position of an element within + // the matched set of elements + index: function( elem ) { + + // No argument, return index in parent + if ( !elem ) { + return ( this[0] && this[0].parentNode ) ? this.prevAll().length : -1; + } + + // index in selector + if ( typeof elem === "string" ) { + return jQuery.inArray( this[0], jQuery( elem ) ); + } + + // Locate the position of the desired element + return jQuery.inArray( + // If it receives a jQuery object, the first element is used + elem.jquery ? elem[0] : elem, this ); + }, + + add: function( selector, context ) { + var set = typeof selector === "string" ? + jQuery( selector, context ) : + jQuery.makeArray( selector && selector.nodeType ? [ selector ] : selector ), + all = jQuery.merge( this.get(), set ); + + return this.pushStack( isDisconnected( set[0] ) || isDisconnected( all[0] ) ? + all : + jQuery.unique( all ) ); + }, + + andSelf: function() { + return this.add( this.prevObject ); + } +}); + +// A painfully simple check to see if an element is disconnected +// from a document (should be improved, where feasible). +function isDisconnected( node ) { + return !node || !node.parentNode || node.parentNode.nodeType === 11; +} + +jQuery.each({ + parent: function( elem ) { + var parent = elem.parentNode; + return parent && parent.nodeType !== 11 ? parent : null; + }, + parents: function( elem ) { + return jQuery.dir( elem, "parentNode" ); + }, + parentsUntil: function( elem, i, until ) { + return jQuery.dir( elem, "parentNode", until ); + }, + next: function( elem ) { + return jQuery.nth( elem, 2, "nextSibling" ); + }, + prev: function( elem ) { + return jQuery.nth( elem, 2, "previousSibling" ); + }, + nextAll: function( elem ) { + return jQuery.dir( elem, "nextSibling" ); + }, + prevAll: function( elem ) { + return jQuery.dir( elem, "previousSibling" ); + }, + nextUntil: function( elem, i, until ) { + return jQuery.dir( elem, "nextSibling", until ); + }, + prevUntil: function( elem, i, until ) { + return jQuery.dir( elem, "previousSibling", until ); + }, + siblings: function( elem ) { + return jQuery.sibling( ( elem.parentNode || {} ).firstChild, elem ); + }, + children: function( elem ) { + return jQuery.sibling( elem.firstChild ); + }, + contents: function( elem ) { + return jQuery.nodeName( elem, "iframe" ) ? + elem.contentDocument || elem.contentWindow.document : + jQuery.makeArray( elem.childNodes ); + } +}, function( name, fn ) { + jQuery.fn[ name ] = function( until, selector ) { + var ret = jQuery.map( this, fn, until ); + + if ( !runtil.test( name ) ) { + selector = until; + } + + if ( selector && typeof selector === "string" ) { + ret = jQuery.filter( selector, ret ); + } + + ret = this.length > 1 && !guaranteedUnique[ name ] ? jQuery.unique( ret ) : ret; + + if ( (this.length > 1 || rmultiselector.test( selector )) && rparentsprev.test( name ) ) { + ret = ret.reverse(); + } + + return this.pushStack( ret, name, slice.call( arguments ).join(",") ); + }; +}); + +jQuery.extend({ + filter: function( expr, elems, not ) { + if ( not ) { + expr = ":not(" + expr + ")"; + } + + return elems.length === 1 ? + jQuery.find.matchesSelector(elems[0], expr) ? [ elems[0] ] : [] : + jQuery.find.matches(expr, elems); + }, + + dir: function( elem, dir, until ) { + var matched = [], + cur = elem[ dir ]; + + while ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) { + if ( cur.nodeType === 1 ) { + matched.push( cur ); + } + cur = cur[dir]; + } + return matched; + }, + + nth: function( cur, result, dir, elem ) { + result = result || 1; + var num = 0; + + for ( ; cur; cur = cur[dir] ) { + if ( cur.nodeType === 1 && ++num === result ) { + break; + } + } + + return cur; + }, + + sibling: function( n, elem ) { + var r = []; + + for ( ; n; n = n.nextSibling ) { + if ( n.nodeType === 1 && n !== elem ) { + r.push( n ); + } + } + + return r; + } +}); + +// Implement the identical functionality for filter and not +function winnow( elements, qualifier, keep ) { + + // Can't pass null or undefined to indexOf in Firefox 4 + // Set to 0 to skip string check + qualifier = qualifier || 0; + + if ( jQuery.isFunction( qualifier ) ) { + return jQuery.grep(elements, function( elem, i ) { + var retVal = !!qualifier.call( elem, i, elem ); + return retVal === keep; + }); + + } else if ( qualifier.nodeType ) { + return jQuery.grep(elements, function( elem, i ) { + return ( elem === qualifier ) === keep; + }); + + } else if ( typeof qualifier === "string" ) { + var filtered = jQuery.grep(elements, function( elem ) { + return elem.nodeType === 1; + }); + + if ( isSimple.test( qualifier ) ) { + return jQuery.filter(qualifier, filtered, !keep); + } else { + qualifier = jQuery.filter( qualifier, filtered ); + } + } + + return jQuery.grep(elements, function( elem, i ) { + return ( jQuery.inArray( elem, qualifier ) >= 0 ) === keep; + }); +} + + + + +function createSafeFragment( document ) { + var list = nodeNames.split( "|" ), + safeFrag = document.createDocumentFragment(); + + if ( safeFrag.createElement ) { + while ( list.length ) { + safeFrag.createElement( + list.pop() + ); + } + } + return safeFrag; +} + +var nodeNames = "abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|" + + "header|hgroup|mark|meter|nav|output|progress|section|summary|time|video", + rinlinejQuery = / jQuery\d+="(?:\d+|null)"/g, + rleadingWhitespace = /^\s+/, + rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig, + rtagName = /<([\w:]+)/, + rtbody = /]", "i"), + // checked="checked" or checked + rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i, + rscriptType = /\/(java|ecma)script/i, + rcleanScript = /^\s*", "" ], + legend: [ 1, "
", "
" ], + thead: [ 1, "", "
" ], + tr: [ 2, "", "
" ], + td: [ 3, "", "
" ], + col: [ 2, "", "
" ], + area: [ 1, "", "" ], + _default: [ 0, "", "" ] + }, + safeFragment = createSafeFragment( document ); + +wrapMap.optgroup = wrapMap.option; +wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; +wrapMap.th = wrapMap.td; + +// IE can't serialize and