From 4baf098a1242f860a209470f903d7144db2ab2b1 Mon Sep 17 00:00:00 2001 From: Oliver Date: Sat, 31 Dec 2022 16:33:32 +0100 Subject: [PATCH 01/13] =?UTF-8?q?Wie=20isch=20denn=20da=20inegrutscht=20&?= =?UTF-8?q?=20wieso=20n=C3=B6d=20gl=C3=B6scht=3F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- www/amavisd.conf | 223 ----------------------------------------------- 1 file changed, 223 deletions(-) delete mode 100644 www/amavisd.conf diff --git a/www/amavisd.conf b/www/amavisd.conf deleted file mode 100644 index 8c84fd5..0000000 --- a/www/amavisd.conf +++ /dev/null @@ -1,223 +0,0 @@ -use strict; - - -$max_servers = 15; # number of pre-forked children (2..15 is common) -$daemon_user = 'clamav'; # (no default; customary: vscan or amavis) -$daemon_group = 'clamav'; # (no default; customary: vscan or amavis) - -$mydomain = 'zooomclan.org'; # a convenient default for other settings - -$MYHOME = '/var/lib/amavis'; # a convenient default for other settings -$TEMPBASE = "$MYHOME/tmp"; # working directory, needs to be created manually -$ENV{TMPDIR} = $TEMPBASE; # environment variable TMPDIR -$QUARANTINEDIR = '/var/lib/amavis/quarantine'; - -@local_domains_maps = qw( zooomclan.org cedi.ch falky.ch ); -# @mynetworks = qw( 127.0.0.0/8 ::1 10.0.0.0/8 172.16.0.0/12 192.168.0.0/16 ); - -$log_level = 0; # verbosity 0..5 -$log_recip_templ = undef; # disable by-recipient level-0 log entries -$DO_SYSLOG = 1; # log via syslogd (preferred) -$SYSLOG_LEVEL = 'mail.debug'; - -$enable_db = 1; # enable use of BerkeleyDB/libdb (SNMP and nanny) -$enable_global_cache = 1; # enable use of libdb-based cache if $enable_db=1 - -$inet_socket_port = 10024; # listen on this local TCP port(s) (see $protocol) -# $unix_socketname = "$MYHOME/amavisd.sock"; # when using sendmail milter - -$sa_tag_level_deflt = 0.0; # add spam info headers if at, or above that level -$sa_tag2_level_deflt = 2.00; # add 'spam detected' headers at that level -$sa_kill_level_deflt = 6.31; # triggers spam evasive actions -$sa_dsn_cutoff_level = 10; # spam level beyond which a DSN is not sent - -$sa_mail_body_size_limit = 200*1024; # don't waste time on SA if mail is larger -$sa_local_tests_only = 0; # only tests which do not require internet access? -$sa_auto_whitelist = 1; # turn on AWL in SA 2.63 or older (irrelevant - # for SA 3.0, cf option is 'use_auto_whitelist') - -$virus_admin = "virusalert\@$mydomain"; # notifications recip. - -$mailfrom_notify_admin = "virusalert\@$mydomain"; # notifications sender -$mailfrom_notify_recip = "virusalert\@$mydomain"; # notifications sender -$mailfrom_notify_spamadmin = "spam.police\@$mydomain"; # notifications sender -$mailfrom_to_quarantine = ''; # null return path; uses original sender if undef - -@addr_extension_virus_maps = ('virus'); -@addr_extension_spam_maps = ('spam'); -@addr_extension_banned_maps = ('banned'); -@addr_extension_bad_header_maps = ('badh'); -$recipient_delimiter = undef; # undef disables address extensions altogether -# when enabling addr extensions do also Postfix/main.cf: recipient_delimiter=+ - -$path = '/usr/local/sbin:/usr/local/bin:/usr/sbin:/sbin:/usr/bin:/bin'; -$file = 'file'; # file(1) utility; use recent versions -$gzip = 'gzip'; -$bzip2 = 'bzip2'; -$lzop = 'lzop'; -$rpm2cpio = ['rpm2cpio.pl','rpm2cpio']; -$cabextract = 'cabextract'; -$uncompress = ['uncompress', 'gzip -d', 'zcat']; -$unfreeze = ['unfreeze', 'freeze -d', 'melt', 'fcat']; -$arc = ['nomarch', 'arc']; -$unarj = ['arj', 'unarj']; -$unrar = ['rar', 'unrar']; -$zoo = 'zoo'; -$lha = 'lha'; -$cpio = ['gcpio','cpio']; -$ar = 'ar'; -$dspam = 'dspam'; - -$MAXLEVELS = 14; -$MAXFILES = 1500; -$MIN_EXPANSION_QUOTA = 100*1024; # bytes (default undef, not enforced) -$MAX_EXPANSION_QUOTA = 300*1024*1024; # bytes (default undef, not enforced) - -$sa_spam_subject_tag = '***SPAM*** '; -$defang_virus = 1; # MIME-wrap passed infected mail -$defang_banned = 1; # MIME-wrap passed mail containing banned name - - -# OTHER MORE COMMON SETTINGS (defaults may suffice): - -# $myhostname = 'host.example.com'; # must be a fully-qualified domain name! - -$notify_method = 'smtp:[127.0.0.1]:10025'; -$forward_method = 'smtp:[127.0.0.1]:10025'; # set to undef with milter! - -$final_virus_destiny = D_DISCARD; -$final_banned_destiny = D_BOUNCE; -$final_spam_destiny = D_BOUNCE; -$final_bad_header_destiny = D_PASS; - - -@viruses_that_fake_sender_maps = (new_RE( - [qr'\bEICAR\b'i => 0], # av test pattern name - [qr'^(WM97|OF97|Joke\.)'i => 0], # adjust names to match your AV scanner - [qr/.*/ => 1], # true for everything else -)); - -@keep_decoded_original_maps = (new_RE( -# qr'^MAIL$', # retain full original message for virus checking (can be slow) - qr'^MAIL-UNDECIPHERABLE$', # recheck full mail if it contains undecipherables - qr'^(ASCII(?! cpio)|text|uuencoded|xxencoded|binhex)'i, -# qr'^Zip archive data', # don't trust Archive::Zip -)); - - -# for $banned_namepath_re, a new-style of banned table, see amavisd.conf-sample - -$banned_filename_re = new_RE( -# qr'^UNDECIPHERABLE$', # is or contains any undecipherable components - - # block certain double extensions anywhere in the base name - qr'\.[^./]*\.(exe|vbs|pif|scr|bat|cmd|com|cpl|dll)\.?$'i, - -# qr'[{}]', # curly braces in names (serve as Class ID extensions - CLSID) - - qr'^application/x-msdownload$'i, # block these MIME types - qr'^application/x-msdos-program$'i, - qr'^application/hta$'i, - -# qr'^message/partial$'i, qr'^message/external-body$'i, # rfc2046 MIME types - -# [ qr'^\.(Z|gz|bz2)$' => 0 ], # allow any type in Unix-compressed - [ qr'^\.(rpm|cpio|tar)$' => 0 ], # allow any type in Unix archives -# [ qr'^\.(zip|rar|arc|arj|zoo)$'=> 0 ], # allow any type within such archives - - qr'.\.(exe|vbs|pif|scr|bat|cmd|com|cpl)$'i, # banned extension - basic -# qr'.\.(ade|adp|app|bas|bat|chm|cmd|com|cpl|crt|exe|fxp|hlp|hta|inf|ins|isp| -# js|jse|lnk|mda|mdb|mde|mdw|mdt|mdz|msc|msi|msp|mst|ops|pcd|pif|prg| -# reg|scr|sct|shb|shs|vb|vbe|vbs|wsc|wsf|wsh)$'ix, # banned ext - long - -# qr'.\.(mim|b64|bhx|hqx|xxe|uu|uue)$'i, # banned extension - WinZip vulnerab. - - qr'^\.(exe-ms)$', # banned file(1) types -# qr'^\.(exe|lha|tnef|cab|dll)$', # banned file(1) types -); -# See http://support.microsoft.com/default.aspx?scid=kb;EN-US;q262631 -# and http://www.cknow.com/vtutor/vtextensions.htm - - -# ENVELOPE SENDER SOFT-WHITELISTING / SOFT-BLACKLISTING - -@score_sender_maps = ({ # a by-recipient hash lookup table, - # results from all matching recipient tables are summed - -# ## per-recipient personal tables (NOTE: positive: black, negative: white) -# 'user1@example.com' => [{'bla-mobile.press@example.com' => 10.0}], -# 'user3@example.com' => [{'.ebay.com' => -3.0}], -# 'user4@example.com' => [{'cleargreen@cleargreen.com' => -7.0, -# '.cleargreen.com' => -5.0}], - - ## site-wide opinions about senders (the '.' matches any recipient) - '.' => [ # the _first_ matching sender determines the score boost - - new_RE( # regexp-type lookup table, just happens to be all soft-blacklist - [qr'^(bulkmail|offers|cheapbenefits|earnmoney|foryou)@'i => 5.0], - [qr'^(greatcasino|investments|lose_weight_today|market\.alert)@'i=> 5.0], - [qr'^(money2you|MyGreenCard|new\.tld\.registry|opt-out|opt-in)@'i=> 5.0], - [qr'^(optin|saveonlsmoking2002k|specialoffer|specialoffers)@'i => 5.0], - [qr'^(stockalert|stopsnoring|wantsome|workathome|yesitsfree)@'i => 5.0], - [qr'^(your_friend|greatoffers)@'i => 5.0], - [qr'^(inkjetplanet|marketopt|MakeMoney)\d*@'i => 5.0], - ), - -# read_hash("/var/amavis/sender_scores_sitewide"), - - { # a hash-type lookup table (associative array) - 'nobody@cert.org' => -3.0, - 'cert-advisory@us-cert.gov' => -3.0, - 'owner-alert@iss.net' => -3.0, - 'slashdot@slashdot.org' => -3.0, - 'bugtraq@securityfocus.com' => -3.0, - 'ntbugtraq@listserv.ntbugtraq.com' => -3.0, - 'security-alerts@linuxsecurity.com' => -3.0, - 'mailman-announce-admin@python.org' => -3.0, - 'amavis-user-admin@lists.sourceforge.net'=> -3.0, - 'notification-return@lists.sophos.com' => -3.0, - 'owner-postfix-users@postfix.org' => -3.0, - 'owner-postfix-announce@postfix.org' => -3.0, - 'owner-sendmail-announce@lists.sendmail.org' => -3.0, - 'sendmail-announce-request@lists.sendmail.org' => -3.0, - 'donotreply@sendmail.org' => -3.0, - 'ca+envelope@sendmail.org' => -3.0, - 'noreply@freshmeat.net' => -3.0, - 'owner-technews@postel.acm.org' => -3.0, - 'ietf-123-owner@loki.ietf.org' => -3.0, - 'cvs-commits-list-admin@gnome.org' => -3.0, - 'rt-users-admin@lists.fsck.com' => -3.0, - 'clp-request@comp.nus.edu.sg' => -3.0, - 'surveys-errors@lists.nua.ie' => -3.0, - 'emailnews@genomeweb.com' => -5.0, - 'yahoo-dev-null@yahoo-inc.com' => -3.0, - 'returns.groups.yahoo.com' => -3.0, - 'clusternews@linuxnetworx.com' => -3.0, - lc('lvs-users-admin@LinuxVirtualServer.org') => -3.0, - lc('owner-textbreakingnews@CNNIMAIL12.CNN.COM') => -5.0, - - # soft-blacklisting (positive score) - 'sender@example.net' => 3.0, - '.example.net' => 1.0, - - }, - ], # end of site-wide tables -}); - - -@av_scanners = ( - ['ClamAV-clamd', - \&ask_daemon, ["CONTSCAN {}\n", "/var/run/clamav/clamav.sock"], - qr/\bOK$/, qr/\bFOUND$/, - qr/^.*?: (?!Infected Archive)(.*) FOUND$/ ], -); - - -@av_scanners_backup = ( - ['ClamAV-clamscan', 'clamscan', - "--stdout --disable-summary -r --tempdir=$TEMPBASE {}", [0], [1], - qr/^.*?: (?!Infected Archive)(.*) FOUND$/ ], -); - - -1; # insure a defined return From df423f308bf6f1430de5228565eced3b4927b98c Mon Sep 17 00:00:00 2001 From: Oliver Date: Sat, 31 Dec 2022 16:48:43 +0100 Subject: [PATCH 02/13] New .env + Docker! Copy .env.example to /approot/.env Plus some minor code fixes hie und da --- .env.example | 200 +++++++++++++++++++++++++++++ Docker/.env.docker | 34 ++--- Docker/README.md | 64 +++++---- Docker/docker-compose.yml | 36 +++--- Docker/docker-sync.yml | 27 ++-- Docker/sendmail/msmtprc | 12 ++ composer.lock | 40 +++--- www/.env.example | 7 - www/addle.php | 12 +- www/images/stats.php | 2 +- www/includes/.gitignore | 8 -- www/includes/mobilez/pdo.inc.php | 21 ++- www/includes/mysql.inc.php | 22 ++-- www/includes/pdo.inc.example.php | 38 +++--- www/includes/smarty.fnc.php | 9 +- www/includes/util.inc.php | 9 +- www/js/ajax/get-onlineuser.php | 12 +- www/js/ajax/get-unreadcomments.php | 10 +- www/js/ajax/get-userfiles.php | 2 +- www/js/ajax/get-usernames.php | 5 +- www/php-ircbot/config.example.php | 12 +- www/stl.php | 2 +- 22 files changed, 402 insertions(+), 182 deletions(-) create mode 100644 .env.example create mode 100644 Docker/sendmail/msmtprc delete mode 100644 www/.env.example diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..1f2b4ac --- /dev/null +++ b/.env.example @@ -0,0 +1,200 @@ +# PHP dotENV - https://github.com/vlucas/phpdotenv +# Copy this file as new /.env & adjust all settings to the corresponging Environment! +ENVIRONMENT="development" # Use "development" for any non-productive envs + +# Database connection (required): +MYSQL_HOST="localhost" # Required! Use "localhost" or Docker service hostname +MYSQL_DATABASE="" # Required! +MYSQL_USER="" # Required! +MYSQL_PASSWORD="" +MYSQL_CHARSET="utf8mb4" + +# Directory paths (required): +APP_ROOT="/var/www" # Absolute path to App root, no trailing /-slash +WWW_ROOT="${APP_ROOT}/html" # No trailing /-slash +INCLUDES_DIR="${WWW_ROOT}/includes/" +ERRORLOG_DIR="${APP_ROOT}/data/errlog/" +UPLOAD_DIR="${APP_ROOT}/data/upload/" +MODELS_DIR="${WWW_ROOT}/models/" +VIEWS_DIR="${WWW_ROOT}/templates/" +CONTROLLERS_DIR="${WWW_ROOT}/controller/" +FILES_DIR="${APP_ROOT}/data/files/" +GALLERY_DIR="${APP_ROOT}/data/gallery/" +GALLERY_UPLOAD_DIR="${UPLOAD_DIR}new-galleries/" +IMAGES_DIR="${WWW_ROOT}/images/" +APOD_TEMP_IMAGE_DIR="${APP_ROOT}/data/temp/" +GO_IMAGES_DIR="${IMAGES_DIR}go/" +HZ_MAPS_DIR="${APP_ROOT}/data/hz_maps" +HZ_MAPS_IMAGES_DIR="${IMAGES_DIR}hz/" +QRCODEIMAGES_DIR="${IMAGES_DIR}swissqrbill" +TAUSCHARTIKEL_IMGAGES_DIR="${APP_ROOT}/data/tauschboerse/" +USERIMAGES_DIR="${APP_ROOT}/data/userimages/" +USERIMAGES_ARCHIVE_DIR="${USERIMAGES_DIR}archiv/" + +# Application settings: +HOSTNAME="" +HTTP_PROTOCOL="https" # https or http +SITE_FQDN="${HTTP_PROTOCOL}://${HOSTNAME}" # No trailing slash +PAGETITLE_SUFFIX=" - ${HOSTNAME}" +LOCALE="de_CH" +TIMEZONE="Europe/Zurich" +ENCODING="UTF-8" +EMAILS_FROM="info@${HOSTNAME}" +ADMIN_EMAIL="root@${HOSTNAME}" +ERROR_REPORTING_LEVELS="E_ALL & ~E_DEPRECATED & ~E_STRICT" # Use E_ALL for development +ERRORLOG_FILETYPE=".log" # Extension with .-prefix +GIT_REPOSITORY_ROOT="${APP_ROOT}/" +GIT_REPOSITORY_USER="GITUSER" +GIT_REPOSITORY_REPO="REPONAME" +GIT_REPOSITORY_URL="https://github.com/${GIT_REPOSITORY_USER}/${GIT_REPOSITORY_REPO}/commit/" +TELEGRAM_CHATLINK="" # Full URL to a Telegram-Chat +TELEGRAM_PARSE_MODE="html" +TELEGRAM_DISABLE_WEBPAGE_PREVIEW="false" +TELEGRAM_DISABLE_NOTIFICATION="false" +TWITTER_NAME="" # Without prefixed @-char +FACEBOOK_APPID="" +FACEBOOK_PAGENAME="" +URLPATH_ACTIONS="/actions/" +URLPATH_AJAX="${URLPATH_JS}ajax/" +URLPATH_CSS="/css/" +URLPATH_HZ_IMAGES="${URLPATH_IMAGES}hz/" +URLPATH_IMAGES="/images/" +URLPATH_JS="/js/" +URLPATH_RSS="${SITE_FQDN}/?layout=rss" +URLPATH_SCRIPTS="/scripts/" +URLPATH_USERIMAGES="/data/userimages/" +URLPATH_UTILS="/util/" +USERLEVEL_ALLE="0" +USERLEVEL_USER="1" +USERLEVEL_MEMBER="2" +USERLEVEL_ADMIN="3" +USER_TIMEOUT="200" # In seconds: 3 Minutes +USER_OLD_AFTER="94608000" # In seconds: 3 Jahre +USER_USE_CURRENT_LOGIN="TRUE" +USER_USE_REGISTRATION_CODE="TRUE" +USER_USE_ONLINE_LIST="TRUE" +USERIMAGE_ENABLED="TRUE" +USERIMAGE_EXTENSION=".jpg" # Extension with .-prefix +USERIMAGE_SIZE_LARGE="500" +USERIMAGE_SIZE_SMALL="150" +USERIMAGE_DEFAULT="none${USERIMAGE_EXTENSION}" # Must be within USERIMAGES_DIR +ADDLE_MAX_GAMES="1" +ADDLE_BASE_POINTS="1600" +ADDLE_MAX_POINTS_TRANSFERABLE="32" +APOD_GALLERY_ID="41" # Match to gallery_albums-Table `id` +BUGTRACKER_FILTER_DEFAULT="?show[]=open&show[]=notdenied&show[]=assigned&show[]=unassigned" +CHESS_DWZ_BASE_POINTS="1600" +CHESS_DWZ_MAX_POINTS_TRANSFERABLE="32" +FORUM_DEFAULT_MAXDEPTH="10" +FORUM_THREAD_CLEARCACHE_AFTER="30" # In Tagen +GALLERY_MAX_PIC_SIZE="['width'=>800, 'height'=>800]" +GALLERY_MAX_THUMBNAIL_SIZE="['width'=>150, 'height'=>150]" +GALLERY_THUMBPAGE="['width'=>4, 'height'=>3, 'padding'=>10]" +GO_OFFSET_PIC="250" +GO_LINKRADIUS="15" +GO_FIELDSIZE="40" +GO_LINEWIDTH="2" +GO_STARDOTWIDTH="10" +GO_STONEBIGWIDTH="190" +GO_LASTSTONEWIDTH="10" +HZ_MAPS_EXTENSION=".gif" +HZ_MAX_GAMES="5" +HZ_TURN_TIME="259200" # In Sekunden: 3 Tage +HZ_TURN_COUNT="4" +HZ_TURN_ADD_MONEY="10" +SETI_TEAM_NAME="" +SETI_EMAIL="" +STRING_NOT_FOUND="Reference not found in String list" + +# Session settings: +SESSION_ID="z" +SESSION_LIFETIME="43200" # In seconds +ENABLE_COOKIES="TRUE" +COOKIE_DOMAIN=".${HOSTNAME}" # Prefixed .-dot is recommended +COOKIE_EXPIRATION="604800" # In seconds. Note: seconds to be added to current time()+COOKIE_EXPIRATION! +COOKIE_PATH="/" +COOKIE_SAMESITE="Lax" # Strict, None, or Lax (default/fallback) +COOKIE_HTTPONLY="true" # true or false (true is strongly recommended) +COOKIE_SECURE="" # Use true=https, false=http (corresponding to HTTP_PROTOCOL) +COOKIE_SESSION="${SESSION_ID}" +COOKIE_USERID="autologin_id" +COOKIE_USERPW="autologin_pw" + +# Smarty Templates settings: +SMARTY_CACHE="${APP_ROOT}/data/smartylib/cache/" +SMARTY_COMPILE="${APP_ROOT}/data/smartylib/templates_c/" +SMARTY_DIR="${WWW_ROOT}/smartylib/" +SMARTY_TRUSTED_DIRS="${WWW_ROOT}/scripts/" # (array) with strings +SMARTY_TEMPLATES_HTML="${VIEWS_DIR}" # (array) with strings +SMARTY_PACKAGES_DIR="${WWW_ROOT}/packages/" +SMARTY_PACKAGES_EXTENSION=".php" +SMARTY_DEFAULT_TPL_ID="23" +SMARTY_404PAGE_TPL_FILE="file:layout/pages/404_page.tpl" + +# Services, APIs, and API-Keys: +# - Facebook GraphAPI +FACEBOOK_API_KEY="" +# - Google APIs +GOOGLE_RECAPTCHA_LOCALE="de-CH" # reCAPTCHA supported languages: https://developers.google.com/recaptcha/docs/language +GOOGLE_RECAPTCHA_KEY="" +GOOGLE_RECAPTCHA_SECRET="" +GOOGLE_MAPS_API_KEY="" +GOOGLE_MAP_API="https://maps.googleapis.com/maps/api/geocode/json?key=${GOOGLE_MAPS_API_KEY}" +# - ipinfo.io API +IPINFO_API_KEY="" # API can be queried without Token (but has lower rate limit) +# - NASA APIs +SPACEWEATHER_SOURCE="https://www.spaceweather.com/" +NASA_API_KEY="DEMO_KEY" # API can be queried with the DEMO_KEY, but has rate limits +NASA_APOD_API="https://api.nasa.gov/planetary/apod?api_key=${NASA_API_KEY}" +NASA_APOD_SOURCE="https://apod.nasa.gov/apod/" +NASA_NEO_API="https://api.nasa.gov/neo/rest/v1/stats?api_key=${NASA_API_KEY}" +NASA_DONKI_API_CME="https://api.nasa.gov/DONKI/CME?startDate=yyyy-MM-dd&endDate=yyyy-MM-dd&api_key=${NASA_API_KEY}" +NASA_DONKI_API_CMEA="https://api.nasa.gov/DONKI/CMEAnalysis?startDate=2016-09-01&endDate=2016-09-30&mostAccurateOnly=true&speed=500&halfAngle=30&catalog=ALL&api_key=${NASA_API_KEY}" +NASA_DONKI_API_GST="https://api.nasa.gov/DONKI/GST?startDate=yyyy-MM-dd&endDate=yyyy-MM-dd&api_key=${NASA_API_KEY}" +NASA_DONKI_API_IPS="https://api.nasa.gov/DONKI/IPS?startDate=yyyy-MM-dd&endDate=yyyy-MM-dd&location=LOCATION&catalog=CATALOG&api_key=${NASA_API_KEY}" +NASA_DONKI_API_FLR="https://api.nasa.gov/DONKI/FLR?startDate=yyyy-MM-dd&endDate=yyyy-MM-dd&api_key=${NASA_API_KEY}" +NASA_DONKI_API_SEP="https://api.nasa.gov/DONKI/SEP?startDate=yyyy-MM-dd&endDate=yyyy-MM-dd&api_key=${NASA_API_KEY}" +NASA_DONKI_API_MPC="https://api.nasa.gov/DONKI/MPC?startDate=yyyy-MM-dd&endDate=yyyy-MM-dd&api_key=${NASA_API_KEY}" +NASA_DONKI_API_RBE="https://api.nasa.gov/DONKI/RBE?startDate=yyyy-MM-dd&endDate=yyyy-MM-dd&api_key=${NASA_API_KEY}" +NASA_DONKI_API_HSS="https://api.nasa.gov/DONKI/HSS?startDate=yyyy-MM-dd&endDate=yyyy-MM-dd&api_key=${NASA_API_KEY}" +NASA_DONKI_API_WSA="https://api.nasa.gov/DONKI/WSAEnlilSimulations?startDate=2016-01-06&endDate=2016-01-06&api_key=${NASA_API_KEY}" +NASA_DONKI_API_Notifications="https://api.nasa.gov/DONKI/notifications?startDate=2014-05-01&endDate=2014-05-08&type=all&api_key=${NASA_API_KEY}" +# - SETI +SETI_TEAM_URL="http://setiathome2.ssl.berkeley.edu/fcgi-bin/fcgi?cmd=team_lookup_xml&name=${SETI_TEAM_NAME}" # FIXME: no longer working +# - Telegram Bot API +TELEGRAM_BOT="" # as registered with @BotFather +TELEGRAM_BOT_API_KEY="" # as provided by @BotFather +TELEGRAM_BOT_API="https://api.telegram.org/bot${TELEGRAM_BOT_API_KEY}/" +TELEGRAM_BOT_API_AUTH_PASSWORD="" # (string) A secret password required to authorise access to the webhook +TELEGRAM_BOT_API_IPWHITELIST="[]" # (array) When using `validate_request`, like: [ '1.2.3.4', '1.1.1.1-2.2.2.2'] +TELEGRAM_BOT_API_USERWHITELIST="[]" # (array) An array of Telegram UserIDs that have admin access to your bot (must be integers) +TELEGRAM_BOT_API_SSLCERT_PATH="" # (string) Path to a self-signed certificate (if necessary), like: "/server.crt" +TELEGRAM_BOT_API_CHAT="" # (integer) Chat-ID where the Telegram Bot will post to +TELEGRAM_BOT_API_FILES_DIR="" # (array) List of configurable paths. +TELEGRAM_BOT_API_LOG_DIR="${ERRORLOG_DIR}" # (array) Paths where the log files should be put. +# - Twitter API +TWITTER_API_KEY="" +TWITTER_API_SECRET="" +TWITTER_API_TOKEN="" +TWITTER_API_TOKENSECRET="" +TWITTER_API_CALLBACK_URL="" + +# zorg settings: +VORSTAND_USER="451" # Match to user-Table `id` +BARBARA_HARRIS="59" # Match to user-Table `id` +ROSENVERKAEUFER="439" # Match to user-Table `id` +THE_ARCHITECT="582" # Match to user-Table `id` +ANFICKER_USER_ID="9999" +ZORG_VEREIN_NAME="zorg Verein" +ZORG_VEREIN_EMAIL="" +ZORG_VEREIN_STRASSE="" +ZORG_VEREIN_PLZ="9000" +ZORG_VEREIN_ORT="St. Gallen" +ZORG_VEREIN_LAND="Schweiz" +ZORG_VEREIN_LAND_ISO2="CH" +ZORG_VEREIN_KONTO_BANK="St. Galler Kantonalbank" +ZORG_VEREIN_KONTO_SWIFT="KBSGCH22" +ZORG_VEREIN_KONTO_IBAN="CH7500781622431172000" +ZORG_VEREIN_KONTO_IBAN_QRBILL="CH9730781622431172000" +ZORG_VEREIN_KONTO_CURRENCY="CHF" +ZORG_VEREIN_KONTO_BESRID="" diff --git a/Docker/.env.docker b/Docker/.env.docker index 0a1e6d8..41a426b 100644 --- a/Docker/.env.docker +++ b/Docker/.env.docker @@ -1,18 +1,18 @@ # === Docker === -COMPOSE_PROJECT_NAME=zorg -OS_PLATFORM=linux/x86_64 -HTTP_PORT=80 -HTTPS_PORT=443 -DOMAINNAME=zorg.local -APACHE_USER=www-data -APACHE_GROUP=www-data -APACHE_WEBROOT=/var/www -PHP_Version=7.4 -PHP_INI_DIR=/usr/local/etc/php -MYSQL_VERSION=5.7 -MYSQL_LOCAL_DATABASE_PATH=./Docker/mysql57 -MYSQL_PORT=3306 -MYSQL_DATABASE=zooomclan -MYSQL_USER=root -MYSQL_PASSWORD= -PHPMYADMIN_PORT=8080 +COMPOSE_PROJECT_NAME="zorg" +OS_PLATFORM="linux/x86_64" +HTTP_PORT="80" +HTTPS_PORT="443" +DOMAINNAME="zorg.local" +APACHE_USER="www-data" +APACHE_GROUP="www-data" +APACHE_WEBROOT="/var/www" +PHP_Version="7.4" +PHP_INI_DIR="/usr/local/etc/php" +MYSQL_VERSION="5.7" +MYSQL_LOCAL_DATABASE_PATH="./Docker/mysql57" +MYSQL_PORT="3306" +MYSQL_DATABASE="zooomclan" +MYSQL_USER="root" +MYSQL_PASSWORD="" +PHPMYADMIN_PORT="8080" diff --git a/Docker/README.md b/Docker/README.md index 4fd5a2c..a8f5b8e 100644 --- a/Docker/README.md +++ b/Docker/README.md @@ -4,13 +4,13 @@ ## Docker configs Edit the file: `.env.docker` -## Using docker-sync +### Using docker-sync `docker-sync` greatly improves the performance of synced volumes from the local file system to Docker, giving a nearly live-performance for read/write operations. -### On macOS +#### Setup on macOS (The following steps are copied from [this online documentation](https://reece.tech/posts/osx-docker-performance/)) -#### Install docker-sync +##### Install docker-sync ``` gem install --user-install docker-sync @@ -51,38 +51,49 @@ docker-sync-stack start -c ./Docker/docker-sync.yml docker compose --project-directory ./ --file ./Docker/docker-compose.yml --env-file ./Docker/.env.docker up ``` -### Using a pre-existing local database - -``` -MYSQL_LOCAL_DATABASE_PATH=/path/to/my/mysql57 docker compose --project-directory ./ --file ./Docker/docker-compose.yml --env-file ./Docker/.env.docker up -d -``` - -#### Fix possible "Tablespace missing"-errors -To fix the MySQL-Error 1812 `Tablespace is missing for table zooomclan . ` try the following command per affected ``: - -```ALTER TABLE zooomclan. IMPORT TABLESPACE``` - - -Usage +## Usage --- +### Service configurations #### MySQL connection config -Add the Docker's `zorg-db`-service IP-address to the file: `/www/.env` +The MySQL database host name is `zorg-db` and needs be added to the PHP environment config file `/www/.env`. + +#### sendmail SMTP config +Edit the msmtprc config file in the `./Docker/sendmail/` directory and replace the following placeholders with real values: +* SMTP_HOST => mail.mymailserver.com +* SMTP_EMAIL => myemail@mymailserver.com +* SMTP_PASSWORD => password for your SMTP_EMAIL account + +Further details on the sendmail / msmtprc integration can be found here: [Send email on testing docker container with php and sendmail](https://stackoverflow.com/a/63977888/5750030) -#### Show the website +### Show the website [http://localhost/](http://localhost/) -…or with a hosts entry pointing to `127.0.0.1` and SSL: [https://zorg.local/] +…or with a hosts entry pointing to `127.0.0.1` and SSL: [https://zorg.local/](https://zorg.local/) -#### Use PHPMyAdmin to manage the database +### Use PHPMyAdmin to manage the database [http://localhost:8080/](http://localhost:8080/) -…or with a hosts entry pointing to `127.0.0.1`: [http://zorg.local:8080/] +…or with a hosts entry pointing to `127.0.0.1`: [http://zorg.local:8080/](http://zorg.local:8080/) -* **Server**: use the Docker's `zorg-db`-service IP-address +* **Server**: use the Docker's `zorg-db`-service hostname or IP-address * **Username**: use the defined `MYSQL_USER`-environment value * **Password**: use the defined `MYSQL_PASSWORD`-environment value -#### Docker services inspection +#### Using a pre-existing local database +The best way is to import an SQL-dump using the phpmysql Docker service at [http://localhost:8080/](http://localhost:8080/). + +Alternatively the path to a local database folder can be provided by overriding the ENV var `MYSQL_LOCAL_DATABASE_PATH`: +``` +MYSQL_LOCAL_DATABASE_PATH=/path/to/my/mysql57 docker compose --project-directory ./ --file ./Docker/docker-compose.yml --env-file ./Docker/.env.docker up -d +``` + +#### Fix possible "Tablespace missing"-errors +To fix the MySQL-Error 1812 `Tablespace is missing for table zooomclan . ` try the following command per affected ``: + +```ALTER TABLE zooomclan. IMPORT TABLESPACE``` + + +## Docker services inspection Find IP of a container service (can also be seen in the network details) `docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' SERVICENAME` @@ -111,7 +122,7 @@ Enter into interactive shell mode for a container service `docker exec -it SERVICENAME sh` -#### docker-sync inspection +### docker-sync inspection !! Refresh docker-sync after updating the `docker-compose.yml`-file `docker-sync clean` @@ -119,3 +130,8 @@ Enter into interactive shell mode for a container service Inspect running docker-sync services: `docker volume ls | grep -sync` + +### sendmail Logfile +Inspect the logfile for sendmail / msmtprc: + +`docker exec -it zorg-web cat /var/log/sendmail.log` diff --git a/Docker/docker-compose.yml b/Docker/docker-compose.yml index 760bb3d..7392e57 100644 --- a/Docker/docker-compose.yml +++ b/Docker/docker-compose.yml @@ -10,8 +10,8 @@ services: restart: unless-stopped environment: - APACHE_DOCUMENT_ROOT=${APACHE_WEBROOT:-/var/www} - #- APACHE_RUN_USER=${APACHE_USER:-www-data} Causes issues with Session-Handling in /tmp - #- APACHE_RUN_GROUP=${APACHE_GROUP:-www-data} And causes issues with reading from ../.git + #- APACHE_RUN_USER=${APACHE_USER:-www-data} # Causes issues with Session-Handling in /tmp + #- APACHE_RUN_GROUP=${APACHE_GROUP:-www-data} # And causes issues with reading from ../.git hostname: webserver domainname: ${DOMAINNAME} networks: @@ -31,7 +31,10 @@ services: - ./Docker/ssl:/etc/apache2/ssl - ./Docker/apache2/000-default.conf:/etc/apache2/sites-available/000-default.conf - ./Docker/apache2/ssl-default.conf:/etc/apache2/sites-available/default-ssl.conf - - web-root-git-sync:${APACHE_WEBROOT:?err}/.git:nocopy + - ./Docker/sendmail/msmtprc:/etc/apache2/sites-available/default-ssl.conf + - ./.env:${APACHE_WEBROOT:?err}/.env + - ./.git:${APACHE_WEBROOT:?err}/.git + #- web-root-git-sync:${APACHE_WEBROOT:?err}/.git:nocopy - ./cron:${APACHE_WEBROOT:?err}/cron - ./data:${APACHE_WEBROOT:?err}/data #- web-root-data-sync:${APACHE_WEBROOT:?err}/data:nocopy Issue with modified Files not being synced @@ -45,7 +48,6 @@ services: entrypoint: ["/bin/sh","-c"] command: - | - echo "Mutex posixsem" >> /etc/apache2/apache2.conf a2enmod ssl a2ensite default-ssl a2enmod rewrite @@ -55,8 +57,8 @@ services: https://github.com/mlocati/docker-php-extension-installer/releases/latest/download/install-php-extensions && \ chmod +x /usr/local/bin/install-php-extensions && \ install-php-extensions mysqli pdo_mysql xdebug gd exif - apt-get -y update && apt-get -y install git - service apache2 restart + apt-get -y update && apt-get -y install git msmtp mailutils + grep -Fx -q 'Mutex posixsem' /etc/apache2/apache2.conf || echo 'Mutex posixsem' >> /etc/apache2/apache2.conf exec /usr/sbin/apache2ctl -D FOREGROUND # Additional install-php-extensions: intl, mbstring, gettext, curl, json, zip, exif @@ -70,8 +72,8 @@ services: - MYSQL_ALLOW_EMPTY_PASSWORD=yes - MYSQL_ROOT_PASSWORD=${MYSQL_PASSWORD:-dbpass} - MYSQL_DATABASE=${MYSQL_DATABASE?-zooomclan} - #- MYSQL_USER=${MYSQL_USER:-dbuser} - #- MYSQL_PASSWORD=${MYSQL_PASSWORD:-root} + #- MYSQL_USER=${MYSQL_USER-dbuser} + #- MYSQL_PASSWORD=${MYSQL_PASSWORD-root} #- MYSQL_ROOT_HOST="%" # in some scenarios this revokes Host IP connection restrictions networks: - frontend @@ -80,7 +82,7 @@ services: expose: - 3306 healthcheck: - test: mysql ${MYSQL_DATABASE} --user=${MYSQL_USER} --password='${MYSQL_PASSWORD}' --silent --execute "SELECT 1;" + test: mysql ${MYSQL_DATABASE} --user=${MYSQL_USER-root} --password='${MYSQL_PASSWORD-root}' --silent --execute "SELECT 1;" interval: 10s timeout: 3s retries: 5 @@ -99,21 +101,21 @@ services: environment: - PMA_ARBITRARY=1 #- PMA_HOST=db - #- MYSQL_USER={MYSQL_USER:-root} # phpMyAdmin connects using the MySQL credentials env - #- MYSQL_PASSWORD=${MYSQL_PASSWORD:-root} # phpMyAdmin connects using the MySQL credentials env + #- MYSQL_USER={MYSQL_USER-root} # phpMyAdmin connects using the MySQL credentials env + #- MYSQL_PASSWORD=${MYSQL_PASSWORD-root} # phpMyAdmin connects using the MySQL credentials env networks: - frontend ports: - ${PHPMYADMIN_PORT:-8080}:80 volumes: - web-root-git-sync: - external: true - web-root-data-sync: - external: true + #web-root-git-sync: + #external: true + #web-root-data-sync: + #external: true + #web-root-www-sync: + #external: true web-root-vendor-sync: external: true - web-root-www-sync: - external: true db-mysql-sync: external: true diff --git a/Docker/docker-sync.yml b/Docker/docker-sync.yml index 5b5ed55..5f78fab 100644 --- a/Docker/docker-sync.yml +++ b/Docker/docker-sync.yml @@ -5,28 +5,23 @@ options: verbose: true syncs: # sync_strategy: see https://docker-sync.readthedocs.io/en/latest/getting-started/configuration.html#sync-strategy - zorg-web-root-git-sync: - src: './.git' - sync_strategy: 'unison' - # sync_host_ip: 'auto' - # sync_host_port: 10872 - sync_excludes: [ ] - zorg-web-root-data-sync: - src: './data' - sync_strategy: 'unison' - sync_excludes: [ ] + #zorg-web-root-git-sync: + #src: './.git' + #sync_strategy: 'unison' + #zorg-web-root-data-sync: + #src: './data' + #sync_strategy: 'unison' + #sync_excludes: [ ] zorg-web-root-vendor-sync: src: './vendor' sync_strategy: 'unison' # sync_host_ip: 'auto' # sync_host_port: 10873 sync_excludes: [ ] - zorg-web-root-www-sync: - src: './www' - sync_strategy: 'unison' - # sync_host_ip: 'auto' - # sync_host_port: 10874 - sync_excludes: [ ] + #zorg-web-root-www-sync: + #src: './www' + #sync_strategy: 'unison' + #sync_excludes: [ ] zorg-db-mysql-sync: src: './Docker/mysql57' sync_strategy: 'unison' diff --git a/Docker/sendmail/msmtprc b/Docker/sendmail/msmtprc new file mode 100644 index 0000000..8d70670 --- /dev/null +++ b/Docker/sendmail/msmtprc @@ -0,0 +1,12 @@ +account default +host SMTP_HOST +port 587 +tls on +tls_starttls on +tls_trust_file /etc/apache2/ssl/cert.pem +tls_certcheck on +auth on +user SMTP_EMAIL +password "SMTP_PASSWORD" +from "SMTP_EMAIL" +logfile /var/log/sendmail.log diff --git a/composer.lock b/composer.lock index 9849f5f..61b3761 100644 --- a/composer.lock +++ b/composer.lock @@ -1580,16 +1580,16 @@ }, { "name": "symfony/property-info", - "version": "v5.4.16", + "version": "v5.4.17", "source": { "type": "git", "url": "https://github.com/symfony/property-info.git", - "reference": "9dd148c4fbfc231fa4bff00def8dc16a2cd89944" + "reference": "12e1f7b3d73b1f3690aa524b92b5de9937507361" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/property-info/zipball/9dd148c4fbfc231fa4bff00def8dc16a2cd89944", - "reference": "9dd148c4fbfc231fa4bff00def8dc16a2cd89944", + "url": "https://api.github.com/repos/symfony/property-info/zipball/12e1f7b3d73b1f3690aa524b92b5de9937507361", + "reference": "12e1f7b3d73b1f3690aa524b92b5de9937507361", "shasum": "" }, "require": { @@ -1604,7 +1604,7 @@ "symfony/dependency-injection": "<4.4" }, "require-dev": { - "doctrine/annotations": "^1.10.4", + "doctrine/annotations": "^1.10.4|^2", "phpdocumentor/reflection-docblock": "^3.0|^4.0|^5.0", "phpstan/phpdoc-parser": "^1.0", "symfony/cache": "^4.4|^5.0|^6.0", @@ -1651,7 +1651,7 @@ "validator" ], "support": { - "source": "https://github.com/symfony/property-info/tree/v5.4.16" + "source": "https://github.com/symfony/property-info/tree/v5.4.17" }, "funding": [ { @@ -1667,20 +1667,20 @@ "type": "tidelift" } ], - "time": "2022-11-19T17:41:50+00:00" + "time": "2022-12-20T11:10:57+00:00" }, { "name": "symfony/string", - "version": "v5.4.15", + "version": "v5.4.17", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "571334ce9f687e3e6af72db4d3b2a9431e4fd9ed" + "reference": "55733a8664b8853b003e70251c58bc8cb2d82a6b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/571334ce9f687e3e6af72db4d3b2a9431e4fd9ed", - "reference": "571334ce9f687e3e6af72db4d3b2a9431e4fd9ed", + "url": "https://api.github.com/repos/symfony/string/zipball/55733a8664b8853b003e70251c58bc8cb2d82a6b", + "reference": "55733a8664b8853b003e70251c58bc8cb2d82a6b", "shasum": "" }, "require": { @@ -1737,7 +1737,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v5.4.15" + "source": "https://github.com/symfony/string/tree/v5.4.17" }, "funding": [ { @@ -1753,7 +1753,7 @@ "type": "tidelift" } ], - "time": "2022-10-05T15:16:54+00:00" + "time": "2022-12-12T15:54:21+00:00" }, { "name": "symfony/translation-contracts", @@ -1835,16 +1835,16 @@ }, { "name": "symfony/validator", - "version": "v5.4.15", + "version": "v5.4.17", "source": { "type": "git", "url": "https://github.com/symfony/validator.git", - "reference": "0fb0c50f18f4517a8ea59d1cc87bff231402a7e3" + "reference": "621b820204a238d754f7f60241fcbdb1687641ea" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/validator/zipball/0fb0c50f18f4517a8ea59d1cc87bff231402a7e3", - "reference": "0fb0c50f18f4517a8ea59d1cc87bff231402a7e3", + "url": "https://api.github.com/repos/symfony/validator/zipball/621b820204a238d754f7f60241fcbdb1687641ea", + "reference": "621b820204a238d754f7f60241fcbdb1687641ea", "shasum": "" }, "require": { @@ -1871,7 +1871,7 @@ "symfony/yaml": "<4.4" }, "require-dev": { - "doctrine/annotations": "^1.13", + "doctrine/annotations": "^1.13|^2", "doctrine/cache": "^1.11|^2.0", "egulias/email-validator": "^2.1.10|^3", "symfony/cache": "^4.4|^5.0|^6.0", @@ -1928,7 +1928,7 @@ "description": "Provides tools to validate values", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/validator/tree/v5.4.15" + "source": "https://github.com/symfony/validator/tree/v5.4.17" }, "funding": [ { @@ -1944,7 +1944,7 @@ "type": "tidelift" } ], - "time": "2022-10-27T08:04:35+00:00" + "time": "2022-12-21T19:20:17+00:00" }, { "name": "vlucas/phpdotenv", diff --git a/www/.env.example b/www/.env.example deleted file mode 100644 index e261127..0000000 --- a/www/.env.example +++ /dev/null @@ -1,7 +0,0 @@ -# PHP dotENV - https://github.com/vlucas/phpdotenv -# - ENVIRONMENTS: 'development' or 'productive' -ENVIRONMENT=development -DOCKER_PHP_MYSQL_HOST=172.20.0.2 -DOCKER_PHP_MYSQL_DATABASE=zooomclan -DOCKER_PHP_MYSQL_USER=root -DOCKER_PHP_MYSQL_PASSWORD= diff --git a/www/addle.php b/www/addle.php index 5bd3b84..449feee 100644 --- a/www/addle.php +++ b/www/addle.php @@ -18,7 +18,8 @@ * @include addle.inc.php required * @include core.model.php required */ -require_once dirname(__FILE__).'/includes/main.inc.php'; +require_once __DIR__.'/includes/config.inc.php'; +require_once INCLUDES_DIR.'main.inc.php'; require_once INCLUDES_DIR.'addle.inc.php'; require_once MODELS_DIR.'core.model.php'; @@ -841,10 +842,11 @@ function archiv() { if ($user->is_loggedin()) { */ - /** Validate GET-Parameters */ - if (isset($_GET['id']) && !empty($_GET['id'])) $game_id = sanitize_userinput($_GET['id']); + /** Validate POST and GET-Parameters */ + if (isset($_POST['id']) && !empty($_POST['id']) && $_POST['id'] > 0) $vs_user_id = (int)sanitize_userinput($_POST['id']); + if (isset($_GET['id']) && !empty($_GET['id'])) $game_id = (int)sanitize_userinput($_GET['id']); if (isset($_GET['do']) && !empty($_GET['do'])) $addle_action = sanitize_userinput($_GET['do']); - if (isset($_GET['choose']) && !empty($_GET['choose'])) $addle_choose = sanitize_userinput($_GET['choose']); + if (isset($_GET['choose']) && is_numeric($_GET['choose'])) $addle_choose = (int)sanitize_userinput($_GET['choose']); $show_page = (isset($_GET['show']) && !empty($_GET['show']) ? sanitize_userinput($_GET['show']) : 'overview'); /** Addle Actions */ @@ -852,7 +854,7 @@ function archiv() { { switch ($addle_action) { - case 'new': newgame($_POST['id']); break; + case 'new': newgame($vs_user_id); break; case 'play': doplay($game_id, $addle_choose); break; } } diff --git a/www/images/stats.php b/www/images/stats.php index 0a3840d..645b58f 100644 --- a/www/images/stats.php +++ b/www/images/stats.php @@ -25,7 +25,7 @@ * File includes * @include config.inc.php */ -require_once dirname(__FILE__).'/../includes/config.inc.php'; +require_once __DIR__.'/../includes/main.inc.php'; require_once INCLUDES_DIR.'graph.inc.php'; /** diff --git a/www/includes/.gitignore b/www/includes/.gitignore index bd0cf77..1965f91 100644 --- a/www/includes/.gitignore +++ b/www/includes/.gitignore @@ -1,10 +1,2 @@ -# Ignore MySQL Database login information file -mysql_login.inc.php -mysql_login.inc.local.php - # Ignore local Development configuration development.config.php - -# Ignore Google API Key information file -googleapis_key.inc.php -googleapis_key.inc.local.php \ No newline at end of file diff --git a/www/includes/mobilez/pdo.inc.php b/www/includes/mobilez/pdo.inc.php index 21f2c36..a1671cc 100644 --- a/www/includes/mobilez/pdo.inc.php +++ b/www/includes/mobilez/pdo.inc.php @@ -9,11 +9,6 @@ * @ToDo [12-Jan-2016 23:59:29 Europe/Berlin] PHP Fatal error: Cannot redeclare class dbconn in /Users/oraduner/Sites/zooomclan/www/includes/mysql.inc.php on line 16 */ -/** - * Include MySQL Database login information file - */ -require_once (file_exists(INCLUDES_DIR.'mysql_login.inc.local.php') ? INCLUDES_DIR.'mysql_login.inc.local.php' : INCLUDES_DIR.'mysql_login.inc.php') ; - // class dbconn // { // /** @@ -29,23 +24,23 @@ // $db = new PDO('mysql:host='.MYSQL_HOST.';dbname='.MYSQL_DBNAME.';charset='.MYSQL_CHARSET, MYSQL_DBUSER, MYSQL_DBPASS); // $db->exec("set names utf8"); // $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); // Set Errorhandling to Exception -// +// // return $db; // } catch (PDOException $e) { // die("Error: " . $e->getMessage() . "
"); // } // } -// +// // } -// +// // // Instantiate new DB Connection Object // $db = new dbconn(); try { $PDO_OPTIONS = array(PDO::ATTR_PERSISTENT => true, PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION); - $PDO_DSN = 'mysql:host=' . MYSQL_HOST . ';dbname=' . MYSQL_DBNAME . ';charset=' . MYSQL_CHARSET; - $pdo_db = new PDO($PDO_DSN, MYSQL_DBUSER, MYSQL_DBPASS, $PDO_OPTIONS); - $pdo_db->exec('set names ' . MYSQL_CHARSET); // Execute an SQL statement and return the number of affected rows + $PDO_DSN = 'mysql:host=' . $_ENV['MYSQL_HOST'] . ';dbname=' . $_ENV['MYSQL_DATABASE'] . ';charset=' . MYSQL_CHARSET; + $pdo_db = new PDO($PDO_DSN, $_ENV['MYSQL_USER'], $_ENV['MYSQL_PASSWORD'], $PDO_OPTIONS); + $pdo_db->exec('set names ' . MYSQL_CHARSET); // Execute an SQL statement and return the number of affected rows } catch (PDOException $err) { - Error_Handler::addError('Error: '.$err->getMessage(), __FILE__, __LINE__, MYSQL_DBNAME, 'PDO'); -} \ No newline at end of file + Error_Handler::addError('Error: '.$err->getMessage(), __FILE__, __LINE__, $_ENV['MYSQL_DATABASE'], 'PDO'); +} diff --git a/www/includes/mysql.inc.php b/www/includes/mysql.inc.php index b86dd08..ff950ac 100644 --- a/www/includes/mysql.inc.php +++ b/www/includes/mysql.inc.php @@ -8,13 +8,13 @@ * * @package zorg\Database */ + /** * File includes + * @include config.inc.php REQUIRED for $_ENV vars to be available * @include mysql_login.inc.local.php Include MySQL Database login information file - * @include config.inc.php */ -//require_once __DIR__.'/config.inc.php'; --> causes Error in async AJAX-Requests (get-onlineuser) -require_once __DIR__.( file_exists( dirname(__FILE__).'/mysql_login.inc.local.php') ? '/mysql_login.inc.local.php' : '/mysql_login.inc.php') ; +require_once __DIR__.'/config.inc.php'; /** * MySQL Database Connection Class @@ -33,16 +33,17 @@ class dbconn /** * MySQL DB Verbindungsaufbau * - * @version 4.0 + * @version 5.0 * @since 3.0 `10.11.2017` `IneX` method code optimized * @since 4.0 `03.11.2019` `kassiopaia` method renamed from dbconn() (PHP 7.x compatibility) + * @since 5.0 `28.12.2022` `IneX` method relies now on $_ENV vars from .env file (mysql_login.inc.php is no longer needed) * - * @param $database MYSQL_DBNAME + * @uses $_ENV * @throws Exception */ - public function __construct($database) { + public function __construct() { try { - $this->conn = mysqli_connect(MYSQL_HOST, MYSQL_DBUSER, MYSQL_DBPASS); + $this->conn = mysqli_connect($_ENV['MYSQL_HOST'], $_ENV['MYSQL_USER'], $_ENV['MYSQL_PASSWORD']); /** MySQL: can't connect to server */ if (!$this->conn) @@ -52,7 +53,7 @@ public function __construct($database) { } /** MySQL: can't find or load database */ - if (!@mysqli_select_db($this->conn, $database)) + if (!@mysqli_select_db($this->conn, $_ENV['MYSQL_DATABASE'])) { die($this->msg()); } @@ -237,8 +238,7 @@ function numfields($result) { * @return array */ function tables() { - //$tables = @mysql_list_tables(MYSQL_DBNAME, $this->conn); // DEPRECATED - PHP5 only - $tables = @mysqli_list_tables($this->conn, 'SHOW TABLES FROM ' . MYSQL_DBNAME); + $tables = @mysqli_list_tables($this->conn, 'SHOW TABLES FROM ' . $_ENV['MYSQL_DATABASE']); $num = $this->num($tables); $tab = array(); for($i=0;$i<$num;$i++) { @@ -352,4 +352,4 @@ function update($table, $id, $values, $file='', $line='', $funktion='') } /** Grad eine Verbindung bauen, damit sie includet ist... */ -$db = new dbconn(MYSQL_DBNAME); +$db = new dbconn(); diff --git a/www/includes/pdo.inc.example.php b/www/includes/pdo.inc.example.php index 8d10610..db4ef30 100644 --- a/www/includes/pdo.inc.example.php +++ b/www/includes/pdo.inc.example.php @@ -1,19 +1,19 @@ error = $e->getMessage(); } } - + public function query($query) { $this->stmt = $this->dbh->prepare($query); } - + public function bind($param, $value, $type = null) { if (is_null($type)) { @@ -57,34 +57,34 @@ public function bind($param, $value, $type = null) } $this->stmt->bindValue($param, $value, $type); } - + public function execute() { return $this->stmt->execute(); } - + public function resultset() { $this->execute(); return $this->stmt->fetchAll(PDO::FETCH_ASSOC); } - + public function single() { $this->execute(); return $this->stmt->fetch(PDO::FETCH_ASSOC); } - + public function rowCount() { return $this->stmt->rowCount(); } - + public function lastInsertId() { return $this->dbh->lastInsertId(); } - + /** * Transactions allow multiple changes to a database all in one batch. */ @@ -92,17 +92,17 @@ public function beginTransaction() { return $this->dbh->beginTransaction(); } - + public function endTransaction() { return $this->dbh->commit(); } - + public function cancelTransaction() { return $this->dbh->rollBack(); } - + public function debugDumpParams() { return $this->stmt->debugDumpParams(); diff --git a/www/includes/smarty.fnc.php b/www/includes/smarty.fnc.php index 521f13d..3fb1f46 100644 --- a/www/includes/smarty.fnc.php +++ b/www/includes/smarty.fnc.php @@ -8,7 +8,8 @@ /** * File includes */ -require_once dirname(__FILE__).'/config.inc.php'; +require_once __DIR__.'/config.inc.php'; +require_once INCLUDES_DIR.'mysql.inc.php'; include_once INCLUDES_DIR.'addle.inc.php'; include_once INCLUDES_DIR.'apod.inc.php'; include_once INCLUDES_DIR.'bugtracker.inc.php'; @@ -26,6 +27,12 @@ include_once INCLUDES_DIR.'peter.inc.php'; include_once INCLUDES_DIR.'rezepte.inc.php'; +/** + * Define and include the MCV Controllers and initialise Layout related settings. + */ +require_once CONTROLLERS_DIR.'layout.controller.php'; +if (DEVELOPMENT === true) error_log(sprintf('[DEBUG] <%s:%d> new MVC\Controller\Layout()', __FILE__, __LINE__)); +$zorgLayout = new MVC\Controller\Layout(); /** * Arrays for Smarty diff --git a/www/includes/util.inc.php b/www/includes/util.inc.php index 563eca9..b6ca2ab 100644 --- a/www/includes/util.inc.php +++ b/www/includes/util.inc.php @@ -801,15 +801,14 @@ function gmt_diff($date) { /** * Funktion prüft, ob der Client ein Mobile-Client ist (iPhone, BB, etc.) * - * @deprecated - * @TODO Funktion entfernen, wird via JavaScript erledigt + * !! Matcht zu einem ENUM-Column in der User-Tabelle!! Änderungen hier können konflikt erzeugen + * * @link http://detectmobilebrowsers.com * @link https://deviceatlas.com/blog/mobile-browser-user-agent-strings * @author IneX * @version 2.1 * @since 1.0 `23.04.2009` `Inex` function added * @since 2.0 `19.07.2018` `Inex` Array foreach-loop replaced with faster array_filter-search, updated identifiers - * @since 2.1 `27.12.2022` `Inex` Added additional identifiers, particularly for Tablet Devices * * @see usersystem::usersystem() * @param string $userAgent @@ -856,10 +855,6 @@ function isMobileClient($userAgent) ,'iemobile' ,'windows phone' ,'mobile safari' - ,'mitsu' - ,'ipad' // Tablet - ,'playbook' // Tablet - ,'silk' // Tablet ); return array_filter($_mobileClients, function($match) use ($userAgent) { return ( strpos($userAgent, $match) !== false); diff --git a/www/js/ajax/get-onlineuser.php b/www/js/ajax/get-onlineuser.php index 823cdfe..44a157e 100644 --- a/www/js/ajax/get-onlineuser.php +++ b/www/js/ajax/get-onlineuser.php @@ -5,6 +5,12 @@ * @package zorg\Usersystem */ +/** + * FILE INCLUDES + * @include config.inc.php Required at top! (e.g. for ENV vars, and to validate 'nonce' in $_SESSION) + */ +require_once __DIR__.'/../../includes/config.inc.php'; + /** * AJAX Request validation */ @@ -28,7 +34,7 @@ { case 'image': /** Requires usersystem.inc.php */ - require_once __DIR__.'/../../includes/usersystem.inc.php'; + require_once INCLUDES_DIR.'usersystem.inc.php'; $onlineUserHtml = $user->online_users(true); if (!empty($onlineUserHtml)) @@ -50,8 +56,8 @@ * checks for any online users (updating the corresponding frontend) */ /** Requires mysql.inc.php */ - require_once dirname(__FILE__).'/../../includes/mysql.inc.php'; - $sql = 'SELECT id, username, clan_tag FROM user WHERE activity > (NOW()-200) ORDER by activity DESC'; + require_once INCLUDES_DIR.'mysql.inc.php'; + $sql = 'SELECT id, username, clan_tag FROM user WHERE activity > (NOW()-'.USER_TIMEOUT.') ORDER by activity DESC'; $result = $db->query($sql, __FILE__, __LINE__, 'SELECT FROM user'); /** Check if at least 1 user is online */ $num_online = (false !== $result && !empty($result) ? (int)$db->num($result) : 0); diff --git a/www/js/ajax/get-unreadcomments.php b/www/js/ajax/get-unreadcomments.php index fcbbbea..af86af4 100644 --- a/www/js/ajax/get-unreadcomments.php +++ b/www/js/ajax/get-unreadcomments.php @@ -5,6 +5,12 @@ * @package zorg\Forum */ +/** + * FILE INCLUDES + * @include config.inc.php Required at top! (e.g. for ENV vars, and to validate 'nonce' in $_SESSION) + */ +require_once __DIR__.'/../../includes/config.inc.php'; + /** * AJAX Request validation */ @@ -16,7 +22,7 @@ if(!isset($_GET['user']) || empty($_GET['user']) || false === filter_var(trim($_GET['user']), FILTER_SANITIZE_NUMBER_INT)) { http_response_code(400); // Set response code 400 (bad request) and exit. - die('Invalid or missing GET-Parameter'); + exit('Invalid or missing GET-Parameter'); } $user_id = (int)filter_var(trim($_GET['user']), FILTER_SANITIZE_NUMBER_INT); @@ -31,7 +37,7 @@ if (!empty($user_id) && $user_id > 0) { /** Requires mysql.inc.php */ - require_once __DIR__.'/../../includes/mysql.inc.php'; + require_once INCLUDES_DIR.'mysql.inc.php'; /** Unread Comments are only valid while a User is online... for minimum external exposure. */ $sql = 'SELECT COUNT(*) AS numunread FROM comments_unread WHERE user_id='.$user_id; $rs = $db->fetch($db->query($sql, __FILE__, __LINE__, 'SELECT FROM comments_unread')); diff --git a/www/js/ajax/get-userfiles.php b/www/js/ajax/get-userfiles.php index 94eb3d7..69721c0 100644 --- a/www/js/ajax/get-userfiles.php +++ b/www/js/ajax/get-userfiles.php @@ -11,7 +11,7 @@ /** * FILE INCLUDES */ -require_once dirname(__FILE__).'/../../includes/config.inc.php'; +require_once __DIR__.'/../../includes/config.inc.php'; require_once INCLUDES_DIR.'mysql.inc.php'; /** diff --git a/www/js/ajax/get-usernames.php b/www/js/ajax/get-usernames.php index ccc26a5..da62dcb 100644 --- a/www/js/ajax/get-usernames.php +++ b/www/js/ajax/get-usernames.php @@ -6,7 +6,6 @@ /** * AJAX Request validation */ -//if(!isset($_POST['action']) || empty($_POST['action']) || $_POST['action'] != 'userlist') if(!isset($_GET['action']) || empty($_GET['action']) || $_GET['action'] !== 'userlist') { http_response_code(400); // Set response code 400 (bad request) and exit. @@ -17,8 +16,8 @@ /** * FILE INCLUDES */ -//require_once dirname(__FILE__).'/../../includes/config.inc.php'; // OBSOLETE -require_once dirname(__FILE__).'/../../includes/mysql.inc.php'; +require_once __DIR__.'/../../includes/config.inc.php'; +require_once INCLUDES_DIR.'mysql.inc.php'; /** * Get records from database diff --git a/www/php-ircbot/config.example.php b/www/php-ircbot/config.example.php index fe25c22..6560656 100644 --- a/www/php-ircbot/config.example.php +++ b/www/php-ircbot/config.example.php @@ -1,6 +1,6 @@ '', @@ -17,10 +17,10 @@ 'log_file' => '/data/errlog/php_ircbot-log_', 'timezone' => 'Europe/Zurich', 'quit_message' => '', - 'db_server' => MYSQL_HOST, - 'db_name' => MYSQL_DBNAME, - 'db_user' => MYSQL_DBUSER, - 'db_pass' => MYSQL_DBPASS, + 'db_server' => $_ENV['MYSQL_HOST'], + 'db_name' => $_ENV['MYSQL_DATABASE'], + 'db_user' => $_ENV['MYSQL_USER'], + 'db_pass' => $_ENV['MYSQL_PASSWORD'], 'commands' => array( 'Command\Say' => array(), 'Command\Joke' => array(), diff --git a/www/stl.php b/www/stl.php index 27a9a15..50f0ebf 100644 --- a/www/stl.php +++ b/www/stl.php @@ -45,7 +45,7 @@ if ($game_id > 0) { /** Action */ - if($_GET['shoot']) $stl->shoot(); + if($_GET['shoot']) $stl->shoot(); // FIXME PHP Notice: Undefined index: shoot in /srv/zorg.ch/www/public/stl.php on line 48 /** Layout */ //printStlPageHeader(); From cbfa863627a28af9862ee4afb9ba4e5f7cae6a19 Mon Sep 17 00:00:00 2001 From: Oliver Date: Sat, 31 Dec 2022 17:42:28 +0100 Subject: [PATCH 03/13] =?UTF-8?q?dotEnv=20for=20king!=20config.inc.php=20n?= =?UTF-8?q?ow=20.env=C2=B4ed?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- www/includes/config.inc.php | 427 +++++++++++---------- www/includes/forum.inc.php | 3 +- www/includes/hz_map.inc.php | 147 +++---- www/includes/main.inc.php | 35 +- www/includes/notifications.inc.php | 2 +- www/includes/smarty.inc.php | 16 +- www/includes/spaceweather.inc.php | 39 +- www/includes/stl.inc.php | 66 ++++ www/includes/strings.inc.php | 18 +- www/includes/usersystem.inc.php | 120 +++--- www/index.php | 15 +- www/js/ajax/verein_mailer/set-mailsend.php | 12 +- www/seti_example.php | 13 +- www/templates/layout/head.tpl | 13 +- 14 files changed, 507 insertions(+), 419 deletions(-) diff --git a/www/includes/config.inc.php b/www/includes/config.inc.php index 30b6dfe..fa7b321 100644 --- a/www/includes/config.inc.php +++ b/www/includes/config.inc.php @@ -1,164 +1,157 @@ required(). + * @link https://github.com/vlucas/phpdotenv + */ + try { + $dotenv = Dotenv\Dotenv::createImmutable(APP_ROOT); + $dotenv->load(); + $dotenv->required(['MYSQL_HOST', 'MYSQL_DATABASE', 'MYSQL_USER'])->notEmpty(); + $dotenv->required(['HOSTNAME', 'HTTP_PROTOCOL', 'SITE_FQDN'])->notEmpty(); + $dotenv->required(['LOCALE'])->allowedRegexValues('([[:lower:]]{2}_[[:upper:]]{2})'); + $dotenv->required(['TIMEZONE'])->allowedRegexValues('([a-zA-Z0-9]+([\/|+-][a-zA-Z0-9_]+)?(\/[a-zA-Z0-9_]+)?)'); + } catch (Exception $e) { + exit(sprintf('[ERROR] <%s:%d> %s', __FILE__, __LINE__, $e->getMessage())); + } +} + +/** Set locale to German, Switzerland & Timezone to Europe/Zurich */ +setlocale(LC_TIME, $_ENV['LOCALE']); +setlocale(LC_MONETARY, $_ENV['LOCALE']); +date_default_timezone_set($_ENV['TIMEZONE']); + +/** Start execution time measurement */ $parsetime_start = microtime(true); $sqltracker_numqueries = 0; -/** - * Set a constant for the Site's Web Root. - * @const SITE_ROOT Set the Site Root WITHOUT a trailing slash "/". IMPORTANT: relative to the config.inc.php File! - */ -if (!defined('SITE_ROOT')) define('SITE_ROOT', rtrim(dirname(__FILE__), '/\\').'/..'); /** - * Environment-specific configurations: can be set in the Apache config using - * SetEnv environment 'development' - * - * @const COMPOSER_AUTOLOAD Composer Autoloader for third-party Vendor libraries - * @const DEVELOPMENT Contains either 'true' or 'false' (boolean) - Default: false - * @include development.config.php If DEVELOPMENT, load a corresponding config file containing DEV-specific settings. Was already checked to exist at define('DEVELOPMENT', true/false) + * Development Environment: early inject special development.config.php - if applicable. + * @const DEVELOPMENT Contains either 'true' or 'false' (boolean). Default: false + * @include development.config.php If DEVELOPMENT===true, load a corresponding config file containing DEV-specific settings. */ -if (file_exists(SITE_ROOT.'/../vendor/autoload.php')) +$isDevelopmentEnv = false; // Generally it's assumed we're running Production +if ((isset($_ENV['ENVIRONMENT']) && $_ENV['ENVIRONMENT'] === 'development') || + (isset($_SERVER['environment']) && $_SERVER['environment'] === 'development')) { - if (!defined('COMPOSER_AUTOLOAD')) define('COMPOSER_AUTOLOAD', SITE_ROOT.'/../vendor/autoload.php'); - require_once COMPOSER_AUTOLOAD; - - /** Load PHP dotENV library*/ - $dotenv = Dotenv\Dotenv::createImmutable(SITE_ROOT)->load(); + $isDevelopmentEnv = true; // $_ENV has priority, $_SERVER for backwards-compatibility before Dotenv } -if (!defined('DEVELOPMENT')) define('DEVELOPMENT', ( (isset($_SERVER['environment']) && $_SERVER['environment'] === 'development') || file_exists( dirname(__FILE__).'/development.config.php') ? true : false )); -if (DEVELOPMENT === true) include_once dirname(__FILE__).'/development.config.php'; +if (!defined('DEVELOPMENT')) define('DEVELOPMENT', (true === $isDevelopmentEnv ? true : false)); // Kept for backwards-compatibility (before Dotenv) +if (true === $isDevelopmentEnv && true === file_exists(__DIR__.'/development.config.php')) include_once __DIR__.'/development.config.php'; /** - * Define preferred Protocol that zorg.ch is running on. - * @const SITE_PROTOCOL https or http, required for building links like http(s)://... - Default: true + * Define preferred Hostname where website is accessible on. * @link https://stackoverflow.com/questions/1175096/how-to-find-out-if-youre-using-https-without-serverhttps + * + * @const SITE_PROTOCOL HTTP Protocol: https or http, required for building links like http(s)://... Default: false + * @const SITE_HOSTNAME e.g. zorg.ch WITHOUT trailing slash! (no ".../"). Default: zorg.ch + * @const SITE_URL Preferred base URL where zorg.ch is accessible through. Generated using SITE_PROTOCOL and SITE_HOSTNAME. + * @const PAGETITLE_SUFFIX General suffix for ...[suffix] on every page. Default: (empty) */ $isSecure = false; -if (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on') { - $isSecure = true; -} -elseif (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https' || isset($_SERVER['HTTP_X_FORWARDED_SSL']) && $_SERVER['HTTP_X_FORWARDED_SSL'] === 'on') { +if ((isset($_ENV['HTTP_PROTOCOL']) && $_ENV['HTTP_PROTOCOL'] === 'https') || + (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on') || + (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https') || + (isset($_SERVER['HTTP_X_FORWARDED_SSL']) && $_SERVER['HTTP_X_FORWARDED_SSL'] === 'on')) +{ $isSecure = true; } -if (!defined('SITE_PROTOCOL')) define('SITE_PROTOCOL', ($isSecure ? 'https' : 'http')); - -/** - * Define preferred Hostname where zorg.ch is accessible on. - * @const SITE_HOSTNAME e.g. zorg.ch WITHOUT trailing slash! (no ".../") - Default: zorg.ch - */ -if (empty($_SERVER['SERVER_NAME'])) $_SERVER['SERVER_NAME'] = 'zorg.ch'; +if (!defined('SITE_PROTOCOL')) define('SITE_PROTOCOL', (false === $isSecure ? 'http' : 'https')); +if (!isset($_ENV['HOSTNAME']) || empty($_ENV['HOSTNAME']) || empty($_SERVER['SERVER_NAME'])) $_SERVER['SERVER_NAME'] = 'zorg.ch'; +elseif (isset($_ENV['HOSTNAME']) || !empty($_ENV['HOSTNAME'])) $_SERVER['SERVER_NAME'] = $_ENV['HOSTNAME']; if (!defined('SITE_HOSTNAME')) define('SITE_HOSTNAME', $_SERVER['SERVER_NAME']); - -/** - * Define preferred base URL where zorg.ch is accessible through. - * @const SITE_URL Don't edit! Is generated using SITE_PROTOCOL and SITE_HOSTNAME - */ if (!defined('SITE_URL')) define('SITE_URL', SITE_PROTOCOL . '://' . SITE_HOSTNAME); - - -/** - * @const PAGETITLE_SUFFIX General suffix for ...[suffix] on every page. - */ -if (!defined('PAGETITLE_SUFFIX')) define('PAGETITLE_SUFFIX', ' - ' . SITE_HOSTNAME); +if (!defined('PAGETITLE_SUFFIX')) define('PAGETITLE_SUFFIX', (isset($_ENV['PAGETITLE_SUFFIX']) && !empty($_ENV['PAGETITLE_SUFFIX']) ? $_ENV['PAGETITLE_SUFFIX'] : '')); /** * Define global Contact points, such as e-mail addresses (From:) * - * @const ZORG_EMAIL Sets valid sender e-mailadress such as info@zooomclan.org - * @const ZORG_ADMIN_EMAIL Don't edit! This grabs the Admin E-Mail from the apache2 config - * @const ZORG_VEREIN_EMAIL Zorg Verein E-Mail address - * @const VORSTAND_USER User-ID of the Zorg Verein Vorstand-User - * @const BARBARA_HARRIS User-ID of [z]Barbara Harris - * @const ROSENVERKAEUFER User-ID des Rosenverkäufer's (für Peter-Spiele) - * @const THE_ARCHITECT User-ID des [z]architect - * @const TWITTER_NAME A Twitter-profile username which can be linked, e.g. ZorgCH (no "@") + * @const SENDMAIL_EMAIL Sets valid sender e-mailadress such as info@zooomclan.org + * @const ADMIN_EMAIL E-mailaddress to send stuff like application alerts to, may be used from the apache2 config (Fallback: SENDMAIL_EMAIL) + * @const GIT_REPOSITORY_ROOT zorg Code Git-Repository on the server (for code version info). For dev adjust in development.config.php + * @const GIT_REPOSITORY_URL zorg Code Git-Repository public URL * @const FACEBOOK_APPID A Facebook App-ID which can be linked, see developers.facebook.com/apps/ * @const FACEBOOK_PAGENAME Facebook page name (as in the group url) of the Zorg Facebook group * @const TELEGRAM_CHATLINK Telegram Messenger Group-Chat link to join the Zorg Community group - * @const GIT_REPOSITORY_ROOT zorg Code Git-Repository on the server (for code version info). For dev adjust in development.config.php - * @const GIT_REPOSITORY_URL zorg Code Git-Repository public URL - * @const ZORG_VEREIN_NAME Bezeichnung des Vereins (z.B. für Swiss QR Bill) - * @const ZORG_VEREIN_STRASSE Strasse der Adresse des Vereins (z.B. für Swiss QR Bill) - * @const ZORG_VEREIN_PLZ PLZ der Adresse des Vereins (z.B. für Swiss QR Bill) - * @const ZORG_VEREIN_ORT Ort der Adresse des Vereins (z.B. für Swiss QR Bill) - * @const ZORG_VEREIN_LAND Zorg Land der Adresse des Vereins (z.B. für Swiss QR Bill) - * @const ZORG_VEREIN_LAND_ISO2 2-stelliger ISO-Code des Land des Vereins (z.B. für Swiss QR Bill) - * @const ZORG_VEREIN_KONTO_BANK Bankname des Vereinskontos (z.B. für Swiss QR Bill) - * @const ZORG_VEREIN_KONTO_SWIFT SWIFT-Identifikation des Vereinskontos (z.B. für Swiss QR Bill) - * @const ZORG_VEREIN_KONTO_IBAN IBAN-Nummer des Vereinskontos (z.B. für Swiss QR Bill) - * @const ZORG_VEREIN_KONTO_IBAN_QRBILL Swiss QR-Bill IBAN-Nummer des Vereinskontos (z.B. für Swiss QR Bill) - * @const ZORG_VEREIN_KONTO_CURRENCY Akzeptierte Währung des Vereinskontos (z.B. für Swiss QR Bill) - * @const ZORG_VEREIN_KONTO_BESRID Diese Identifikationsnummer (BESR-ID) wird von der Bank vergeben (nicht bei Post Finance). Wird nur benötigt in Zusammenhang mit Referenznummern auf Rechnungen. + * @const TWITTER_NAME A Twitter-profile username which can be linked, e.g. ZorgCH (no "@") */ -if (!defined('ZORG_EMAIL')) define('ZORG_EMAIL', 'info@'.SITE_HOSTNAME); -if (!defined('ZORG_ADMIN_EMAIL') && isset($_SERVER['SERVER_ADMIN'])) define('ZORG_ADMIN_EMAIL', $_SERVER['SERVER_ADMIN']); -if (!defined('ZORG_VEREIN_EMAIL')) define('ZORG_VEREIN_EMAIL', 'zorg-vorstand@googlegroups.com'); -if (!defined('VORSTAND_USER')) define('VORSTAND_USER', 451); -if (!defined('BARBARA_HARRIS')) define('BARBARA_HARRIS', 59); -if (!defined('ROSENVERKAEUFER')) define('ROSENVERKAEUFER', 439); -if (!defined('THE_ARCHITECT')) define('THE_ARCHITECT', 582); -if (!defined('TWITTER_NAME')) define('TWITTER_NAME', 'ZorgCH'); -if (!defined('FACEBOOK_APPID')) define('FACEBOOK_APPID', '110932998937967'); -if (!defined('FACEBOOK_PAGENAME')) define('FACEBOOK_PAGENAME', 'zorgch'); -if (!defined('TELEGRAM_CHATLINK')) define('TELEGRAM_CHATLINK', 'https://t.me/joinchat/AbPXbRIhBf3PSG0ujGzY4g'); -if (!defined('TWITTER_NAME')) define('TWITTER_NAME', 'ZorgCH'); -if (!defined('GIT_REPOSITORY_ROOT')) define('GIT_REPOSITORY_ROOT', SITE_ROOT.'/../zorg-code/'); -if (!defined('GIT_REPOSITORY_URL')) define('GIT_REPOSITORY_URL', 'https://github.com/zorgch/zorg-code/commit/'); -if (!defined('ZORG_VEREIN_NAME')) define('ZORG_VEREIN_NAME', 'zorg Verein'); -if (!defined('ZORG_VEREIN_STRASSE')) define('ZORG_VEREIN_STRASSE', null); -if (!defined('ZORG_VEREIN_PLZ')) define('ZORG_VEREIN_PLZ', '9000'); -if (!defined('ZORG_VEREIN_ORT')) define('ZORG_VEREIN_ORT', 'St. Gallen'); -if (!defined('ZORG_VEREIN_LAND')) define('ZORG_VEREIN_LAND', 'Schweiz'); -if (!defined('ZORG_VEREIN_LAND_ISO2')) define('ZORG_VEREIN_LAND_ISO2', 'CH'); -if (!defined('ZORG_VEREIN_KONTO_BANK')) define('ZORG_VEREIN_KONTO_BANK', 'St. Galler Kantonalbank'); -if (!defined('ZORG_VEREIN_KONTO_SWIFT')) define('ZORG_VEREIN_KONTO_SWIFT', 'KBSGCH22'); -if (!defined('ZORG_VEREIN_KONTO_IBAN')) define('ZORG_VEREIN_KONTO_IBAN', 'CH7500781622431172000'); -if (!defined('ZORG_VEREIN_KONTO_IBAN_QRBILL')) define('ZORG_VEREIN_KONTO_IBAN_QRBILL', 'CH9730781622431172000'); -if (!defined('ZORG_VEREIN_KONTO_CURRENCY')) define('ZORG_VEREIN_KONTO_CURRENCY', 'CHF'); -if (!defined('ZORG_VEREIN_KONTO_BESRID')) define('ZORG_VEREIN_KONTO_BESRID', null); +if (!defined('SENDMAIL_EMAIL') && isset($_ENV['EMAILS_FROM'])) define('SENDMAIL_EMAIL', $_ENV['EMAILS_FROM']); +if (!defined('ADMIN_EMAIL') && (isset($_SERVER['SERVER_ADMIN']) || isset($_ENV['ADMIN_EMAIL']))) define('ADMIN_EMAIL', (isset($_ENV['ADMIN_EMAIL']) && !empty($_ENV['ADMIN_EMAIL']) ? $_ENV['ADMIN_EMAIL'] : (isset($_SERVER['SERVER_ADMIN']) || !empty($_SERVER['SERVER_ADMIN']) ? $_SERVER['SERVER_ADMIN'] : SENDMAIL_EMAIL))); +if (!defined('GIT_REPOSITORY_ROOT')) define('GIT_REPOSITORY_ROOT', (isset($_ENV['GIT_REPOSITORY_ROOT']) ? $_ENV['GIT_REPOSITORY_ROOT'] : null)); +if (!defined('GIT_REPOSITORY_URL')) define('GIT_REPOSITORY_URL', (isset($_ENV['GIT_REPOSITORY_URL']) ? $_ENV['GIT_REPOSITORY_URL'] : null)); +if (!defined('FACEBOOK_APPID')) define('FACEBOOK_APPID', (isset($_ENV['FACEBOOK_APPID']) ? $_ENV['FACEBOOK_APPID'] : null)); +if (!defined('FACEBOOK_PAGENAME')) define('FACEBOOK_PAGENAME', (isset($_ENV['FACEBOOK_PAGENAME']) ? $_ENV['FACEBOOK_PAGENAME'] : null)); +if (!defined('TELEGRAM_CHATLINK')) define('TELEGRAM_CHATLINK', (isset($_ENV['TELEGRAM_CHATLINK']) ? $_ENV['TELEGRAM_CHATLINK'] : null)); +if (!defined('TWITTER_NAME')) define('TWITTER_NAME', (isset($_ENV['TWITTER_NAME']) ? $_ENV['TWITTER_NAME'] : null)); /** - * Define paths to directories where HTML web resources will be referenced from + * Define internal Application paths to where scripts and resources will be loaded from * * @const INCLUDES_DIR PHP-Script includes directory for using in PHP-Scripts - * @const APIKEYS_DIR Base directory for various API key files required. No trailing slash / * @const MODELS_DIR MVC-Models directory + * @const VIEWS_DIR MVC-Views directory (Smarty templates, see also: SMARTY_TEMPLATES_HTML) * @const CONTROLLERS_DIR MVC-Controllers directory - * @const IMAGES_DIR Images directory for Frontend-Resources (don't use in PHP Scripts! Refer to PHP_IMAGES_DIR) - * @const PHP_IMAGES_DIR Images directory for including Images in PHP-Scripts * @const FILES_DIR Files directory (local server path) * @const GALLERY_DIR Gallery directory (local server path) + * @const GALLERY_UPLOAD_DIR Path to the Upload directory for new Galleries / Gallery Pics on the Server + * @const PHP_IMAGES_DIR Images directory for including Images in PHP-Scripts * @const TAUSCHARTIKEL_IMGPATH Path to store uploaded images for Tauschbörse-Angebote + * @const USER_IMGPATH Interner PHP-Pfad zum Userpics Ordner + * @const USER_IMGPATH_ARCHIVE Interner PHP-Pfad zum Userpics Archiv-Ordner + */ +if (!defined('INCLUDES_DIR')) define('INCLUDES_DIR', (isset($_ENV['INCLUDES_DIR']) ? $_ENV['INCLUDES_DIR'] : null)); +if (!defined('MODELS_DIR')) define('MODELS_DIR', (isset($_ENV['MODELS_DIR']) ? $_ENV['MODELS_DIR'] : null)); +if (!defined('VIEWS_DIR')) define('VIEWS_DIR', (isset($_ENV['VIEWS_DIR']) ? $_ENV['VIEWS_DIR'] : null)); +if (!defined('CONTROLLERS_DIR')) define('CONTROLLERS_DIR', (isset($_ENV['CONTROLLERS_DIR']) ? $_ENV['CONTROLLERS_DIR'] : null)); +if (!defined('FILES_DIR')) define('FILES_DIR', (isset($_ENV['FILES_DIR']) ? $_ENV['FILES_DIR'] : null)); +if (!defined('GALLERY_DIR')) define('GALLERY_DIR', (isset($_ENV['GALLERY_DIR']) ? $_ENV['GALLERY_DIR'] : null)); +if (!defined('GALLERY_UPLOAD_DIR')) define('GALLERY_UPLOAD_DIR', (isset($_ENV['GALLERY_UPLOAD_DIR']) ? $_ENV['GALLERY_UPLOAD_DIR'] : null)); +if (!defined('PHP_IMAGES_DIR')) define('PHP_IMAGES_DIR', (isset($_ENV['IMAGES_DIR']) ? $_ENV['IMAGES_DIR'] : null)); +if (!defined('TAUSCHARTIKEL_IMGPATH')) define('TAUSCHARTIKEL_IMGPATH', (isset($_ENV['TAUSCHARTIKEL_IMGAGES_DIR']) ? $_ENV['TAUSCHARTIKEL_IMGAGES_DIR'] : null)); +if (!defined('USER_IMGPATH')) define('USER_IMGPATH', (isset($_ENV['USERIMAGES_DIR']) ? $_ENV['USERIMAGES_DIR'] : null)); +if (!defined('USER_IMGPATH_ARCHIVE')) define('USER_IMGPATH_ARCHIVE', (isset($_ENV['USERIMAGES_ARCHIVE_DIR']) ? $_ENV['USERIMAGES_ARCHIVE_DIR'] : null)); + +/** + * Define external frontend paths to where certain resources are retrieved from by webbrowsers + * * @const ACTIONS_DIR Actions directory for Frontend-Resources + * @const CSS_DIR CSS directory for Frontend-Resources + * @const IMAGES_DIR Images directory for Frontend-Resources (don't use in PHP Scripts! Refer to PHP_IMAGES_DIR) + * @const JS_DIR JavaScripts directory for Frontend-Resources * @const SCRIPTS_DIR Scripts directory for Frontend-Resources * @const UTIL_DIR Utilities directory for Frontend-Resources - * @const JS_DIR JavaScripts directory for Frontend-Resources - * @const CSS_DIR CSS directory for Frontend-Resources - * @const GALLERY_UPLOAD_DIR Path to the Upload directory for new Galleries / Gallery Pics on the Server + * @const USER_IMGPATH_PUBLIC Externer Pfad zu den Userpics */ -if (!defined('INCLUDES_DIR')) define('INCLUDES_DIR', SITE_ROOT . '/includes/'); -if (!defined('APIKEYS_DIR')) define('APIKEYS_DIR', SITE_ROOT . '/../keys'); // No trailing slash / -if (!defined('MODELS_DIR')) define('MODELS_DIR', SITE_ROOT . '/models/'); -if (!defined('CONTROLLERS_DIR')) define('CONTROLLERS_DIR', SITE_ROOT . '/controller/'); -if (!defined('IMAGES_DIR')) define('IMAGES_DIR', '/images/'); -if (!defined('PHP_IMAGES_DIR')) define('PHP_IMAGES_DIR', SITE_ROOT . '/images/'); -if (!defined('FILES_DIR')) define('FILES_DIR', SITE_ROOT . '/../data/files/'); -if (!defined('GALLERY_DIR')) define('GALLERY_DIR', SITE_ROOT . '/../data/gallery/'); -if (!defined('TAUSCHARTIKEL_IMGPATH')) define('TAUSCHARTIKEL_IMGPATH', SITE_ROOT.'/../data/tauschboerse/'); -if (!defined('ACTIONS_DIR')) define('ACTIONS_DIR', '/actions/'); -if (!defined('SCRIPTS_DIR')) define('SCRIPTS_DIR', '/scripts/'); -if (!defined('UTIL_DIR')) define('UTIL_DIR', '/util/'); -if (!defined('JS_DIR')) define('JS_DIR', '/js/'); -if (!defined('CSS_DIR')) define('CSS_DIR', '/css/'); -if (!defined('GALLERY_UPLOAD_DIR')) define('GALLERY_UPLOAD_DIR', SITE_ROOT . '/../data/upload/new-galleries/'); +if (!defined('ACTIONS_DIR')) define('ACTIONS_DIR', (isset($_ENV['URLPATH_ACTIONS']) ? $_ENV['URLPATH_ACTIONS'] : null)); +if (!defined('CSS_DIR')) define('CSS_DIR', (isset($_ENV['URLPATH_CSS']) ? $_ENV['URLPATH_CSS'] : null)); +if (!defined('IMAGES_DIR')) define('IMAGES_DIR', (isset($_ENV['URLPATH_IMAGES']) ? $_ENV['URLPATH_IMAGES'] : null)); +if (!defined('JS_DIR')) define('JS_DIR', (isset($_ENV['URLPATH_JS']) ? $_ENV['URLPATH_JS'] : null)); +if (!defined('SCRIPTS_DIR')) define('SCRIPTS_DIR', (isset($_ENV['URLPATH_SCRIPTS']) ? $_ENV['URLPATH_SCRIPTS'] : null)); +if (!defined('UTIL_DIR')) define('UTIL_DIR', (isset($_ENV['URLPATH_UTILS']) ? $_ENV['URLPATH_UTILS'] : null)); +if (!defined('USER_IMGPATH_PUBLIC')) define('USER_IMGPATH_PUBLIC', (isset($_ENV['URLPATH_USERIMAGES']) ? $_ENV['URLPATH_USERIMAGES'] : null)); /** * Define User & Usersystem constants @@ -173,71 +166,56 @@ * @const ZORG_COOKIE_DOMAIN Domain where Cookie is valid. Add leading dot '.zorg.ch' for better compatibility * @const ZORG_COOKIE_PATH Site Path where the Cookie is valid. '/' = all pages * @const ZORG_COOKIE_SAMESITE Cookie strictness. Valid is only "Lax" or "Strict". Strict is problematic in Cross-Site Requests. + * @const COOKIE_HTTPONLY Cookie allowed only in HTTP requests. Valid values: 'true' or 'false' ('true' is strongly recommended) * @const USER_ALLE Wert für nicht eingeloggte User * @const USER_USER Wert für normale eingeloggte User * @const USER_MEMBER Wert für [z]member & schöne * @const USER_SPECIAL Wert für Admins & Coder * @const USER_IMGEXTENSION File-Extension/Format von Userpics - * @const USER_IMGPATH Interner PHP-Pfad zum Userpics Ordner - * @const USER_IMGPATH_PUBLIC Externer Pfad zu den Userpics * @const USER_IMGSIZE_LARGE Grösse in Pixel der normalen Userpics * @const USER_IMGSIZE_SMALL Grösse in Pixel der Userpic-Thumbnails - * @const USER_IMGPATH_DEFAULT Externer Pfad zum Standard-Userpic + * @const USER_IMGPATH_DEFAULT Filename des Standard-Userpic im USER_IMGPATH * @const USER_TIMEOUT Session Timeout für eingeloggte User * @const USER_OLD_AFTER Zeit bis ein User als "alt" gilt -> 3 Monate * @const DEFAULT_MAXDEPTH Standard Setting für die Anzeigetiefe von Comments in Forum-Threads */ -if (!defined('ZORG_SESSION_ID')) define('ZORG_SESSION_ID', 'z'); -if (!defined('ZORG_SESSION_LIFETIME')) define('ZORG_SESSION_LIFETIME', 60*60*12); -if (!defined('ZORG_COOKIE_SESSION')) define('ZORG_COOKIE_SESSION', ZORG_SESSION_ID); -if (!defined('ZORG_COOKIE_USERID')) define('ZORG_COOKIE_USERID', 'autologin_id'); -if (!defined('ZORG_COOKIE_USERPW')) define('ZORG_COOKIE_USERPW', 'autologin_pw'); -if (!defined('ZORG_COOKIE_SECURE')) define('ZORG_COOKIE_SECURE', ($isSecure ? 1 : 0)); -if (!defined('ZORG_COOKIE_EXPIRATION')) define('ZORG_COOKIE_EXPIRATION', time()+60*60*24*7); -if (!defined('ZORG_COOKIE_DOMAIN')) define('ZORG_COOKIE_DOMAIN', '.'.SITE_HOSTNAME); -if (!defined('ZORG_COOKIE_PATH')) define('ZORG_COOKIE_PATH', '/'); -if (!defined('ZORG_COOKIE_SAMESITE')) define('ZORG_COOKIE_SAMESITE', 'Lax'); -if (!defined('USER_ALLE')) define('USER_ALLE', 0); -if (!defined('USER_USER')) define('USER_USER', 1); -if (!defined('USER_MEMBER')) define('USER_MEMBER', 2); -if (!defined('USER_SPECIAL')) define('USER_SPECIAL', 3); -if (!defined('USER_IMGEXTENSION')) define('USER_IMGEXTENSION', '.jpg'); -if (!defined('USER_IMGPATH')) define('USER_IMGPATH', SITE_ROOT.'/../data/userimages/'); -if (!defined('USER_IMGPATH_PUBLIC')) define('USER_IMGPATH_PUBLIC', '/data/userimages/'); -if (!defined('USER_IMGPATH_ARCHIVE')) define('USER_IMGPATH_ARCHIVE', SITE_ROOT.'/../data/userimages/archiv/'); -if (!defined('USER_IMGSIZE_LARGE')) define('USER_IMGSIZE_LARGE', 500); -if (!defined('USER_IMGSIZE_SMALL')) define('USER_IMGSIZE_SMALL', 150); -if (!defined('USER_IMGPATH_DEFAULT')) define('USER_IMGPATH_DEFAULT', 'none.jpg'); -if (!defined('USER_TIMEOUT')) define('USER_TIMEOUT', 200); -if (!defined('USER_OLD_AFTER')) define('USER_OLD_AFTER', 60*60*24*30*12*3); // 3 Jahre | 3 Monate: 60*60*24*30*3 -if (!defined('DEFAULT_MAXDEPTH')) define('DEFAULT_MAXDEPTH', 10); +if (!defined('ZORG_SESSION_ID')) define('ZORG_SESSION_ID', (isset($_ENV['SESSION_ID']) ? $_ENV['SESSION_ID'] : 'sess')); +if (!defined('ZORG_SESSION_LIFETIME')) define('ZORG_SESSION_LIFETIME', (isset($_ENV['SESSION_LIFETIME']) ? (int)$_ENV['SESSION_LIFETIME'] : 0)); +if (!defined('ZORG_COOKIE_SESSION')) define('ZORG_COOKIE_SESSION', (isset($_ENV['COOKIE_SESSION']) ? $_ENV['COOKIE_SESSION'] : ZORG_SESSION_ID)); +if (!defined('ZORG_COOKIE_USERID')) define('ZORG_COOKIE_USERID', (isset($_ENV['COOKIE_USERID']) ? $_ENV['COOKIE_USERID'] : null)); +if (!defined('ZORG_COOKIE_USERPW')) define('ZORG_COOKIE_USERPW', (isset($_ENV['COOKIE_USERPW']) ? $_ENV['COOKIE_USERPW'] : null)); +if (!defined('ZORG_COOKIE_SECURE')) define('ZORG_COOKIE_SECURE', (false === $isSecure ? null : true)); +if (!defined('ZORG_COOKIE_DOMAIN')) define('ZORG_COOKIE_DOMAIN', (isset($_ENV['COOKIE_DOMAIN']) ? $_ENV['COOKIE_DOMAIN'] : SITE_HOSTNAME)); +if (!defined('ZORG_COOKIE_EXPIRATION')) define('ZORG_COOKIE_EXPIRATION', (isset($_ENV['COOKIE_EXPIRATION']) ? time()+(int)$_ENV['COOKIE_EXPIRATION'] : time())); +if (!defined('ZORG_COOKIE_PATH')) define('ZORG_COOKIE_PATH', (isset($_ENV['COOKIE_PATH']) ? $_ENV['COOKIE_PATH'] : '/')); +if (!defined('ZORG_COOKIE_SAMESITE')) define('ZORG_COOKIE_SAMESITE', (isset($_ENV['COOKIE_SAMESITE']) ? $_ENV['COOKIE_SAMESITE'] : 'Lax')); +if (!defined('COOKIE_HTTPONLY')) define('COOKIE_HTTPONLY', (isset($_ENV['COOKIE_HTTPONLY']) ? (bool)$_ENV['COOKIE_HTTPONLY'] : true)); +if (!defined('USER_ALLE')) define('USER_ALLE', (isset($_ENV['USERLEVEL_ALLE']) ? (int)$_ENV['USERLEVEL_ALLE'] : 0)); +if (!defined('USER_USER')) define('USER_USER', (isset($_ENV['USERLEVEL_USER']) ? (int)$_ENV['USERLEVEL_USER'] : 1)); +if (!defined('USER_MEMBER')) define('USER_MEMBER', (isset($_ENV['USERLEVEL_MEMBER']) ? (int)$_ENV['USERLEVEL_MEMBER'] : 2)); +if (!defined('USER_SPECIAL')) define('USER_SPECIAL', (isset($_ENV['USERLEVEL_ADMIN']) ? (int)$_ENV['USERLEVEL_ADMIN'] : 3)); +if (!defined('USER_IMGEXTENSION')) define('USER_IMGEXTENSION', (isset($_ENV['USERIMAGE_EXTENSION']) ? $_ENV['USERIMAGE_EXTENSION'] : '.jpg')); +if (!defined('USER_IMGSIZE_LARGE')) define('USER_IMGSIZE_LARGE', (isset($_ENV['USERIMAGE_SIZE_LARGE']) ? (int)$_ENV['USERIMAGE_SIZE_LARGE'] : null)); +if (!defined('USER_IMGSIZE_SMALL')) define('USER_IMGSIZE_SMALL', (isset($_ENV['USERIMAGE_SIZE_SMALL']) ? (int)$_ENV['USERIMAGE_SIZE_SMALL'] : null)); +if (!defined('USER_IMGPATH_DEFAULT')) define('USER_IMGPATH_DEFAULT', (isset($_ENV['USERIMAGE_DEFAULT']) ? $_ENV['USERIMAGE_DEFAULT'] : null)); +if (!defined('USER_TIMEOUT')) define('USER_TIMEOUT', (isset($_ENV['USER_TIMEOUT']) ? (int)$_ENV['USER_TIMEOUT'] : null)); +if (!defined('USER_OLD_AFTER')) define('USER_OLD_AFTER', (isset($_ENV['USER_OLD_AFTER']) ? (int)$_ENV['USER_OLD_AFTER'] : null)); +if (!defined('DEFAULT_MAXDEPTH')) define('DEFAULT_MAXDEPTH', (isset($_ENV['FORUM_DEFAULT_MAXDEPTH']) ? (int)$_ENV['FORUM_DEFAULT_MAXDEPTH'] : 7)); /** * Define Smarty constants + * @const SMARTY_DEFAULT_TPL Default (fallback) Smarty-Template tpl:- or file:-ID/Name + * @const SMARTY_404PAGE_TPL 404 "Page not found" Smarty-Template reference */ -if (!defined('SMARTY_DIR')) define('SMARTY_DIR', SITE_ROOT.'/smartylib/'); -if (!defined('SMARTY_TRUSTED_DIRS')) define('SMARTY_TRUSTED_DIRS', SITE_ROOT.'/scripts/'); // TODO PHP7.x: make this an array -if (!defined('SMARTY_TEMPLATES_HTML')) define('SMARTY_TEMPLATES_HTML', SITE_ROOT.'/templates/'); -if (!defined('SMARTY_CACHE')) define('SMARTY_CACHE', SITE_ROOT.'/../data/smartylib/cache/'); -if (!defined('SMARTY_COMPILE')) define('SMARTY_COMPILE', SITE_ROOT.'/../data/smartylib/templates_c/'); -if (!defined('SMARTY_PACKAGES_DIR')) define('SMARTY_PACKAGES_DIR', SITE_ROOT.'/packages/'); -if (!defined('SMARTY_PACKAGES_EXTENSION')) define('SMARTY_PACKAGES_EXTENSION', '.php'); - -/** - * Set a constant for the custom Error Log path - * - * @see zorgErrorHandler(), user_error(), trigger_error() - * @link https://github.com/zorgch/zorg-code/blob/master/www/includes/errlog.inc.php errlog.inc.php - * @const ERRORLOG_FILETYPE sets the file extension used for the error log file - * @const ERRORLOG_DIR sets the directory for logging the custom user_errors - * @const ERRORLOG_FILEPATH sets the directory & file path for logging the custom user_errors to - * @include errlog.inc.php Errorlogging Class: Load the zorg Error Handling - */ -if (!defined('ERRORLOG_FILETYPE')) define('ERRORLOG_FILETYPE', '.log'); -if (!defined('ERRORLOG_DIR')) define('ERRORLOG_DIR', SITE_ROOT . '/../data/errlog/'); -if (!defined('ERRORLOG_FILE')) define('ERRORLOG_FILE', ERRORLOG_DIR . date('Y-m-d') . ERRORLOG_FILETYPE); -require_once INCLUDES_DIR.'errlog.inc.php'; -//set_error_handler('zorgErrorHandler'); +if (!defined('SMARTY_DIR')) define('SMARTY_DIR', (isset($_ENV['SMARTY_DIR']) ? $_ENV['SMARTY_DIR'] : null)); +if (!defined('SMARTY_TRUSTED_DIRS')) define('SMARTY_TRUSTED_DIRS', (isset($_ENV['SMARTY_TRUSTED_DIRS']) ? (array)$_ENV['SMARTY_TRUSTED_DIRS'] : null)); +if (!defined('SMARTY_TEMPLATES_HTML')) define('SMARTY_TEMPLATES_HTML', (isset($_ENV['SMARTY_TEMPLATES_HTML']) ? (array)$_ENV['SMARTY_TEMPLATES_HTML'] : null)); +if (!defined('SMARTY_CACHE')) define('SMARTY_CACHE', (isset($_ENV['SMARTY_CACHE']) ? $_ENV['SMARTY_CACHE'] : null)); +if (!defined('SMARTY_COMPILE')) define('SMARTY_COMPILE', (isset($_ENV['SMARTY_COMPILE']) ? $_ENV['SMARTY_COMPILE'] : null)); +if (!defined('SMARTY_PACKAGES_DIR')) define('SMARTY_PACKAGES_DIR', (isset($_ENV['SMARTY_PACKAGES_DIR']) ? $_ENV['SMARTY_PACKAGES_DIR'] : null)); +if (!defined('SMARTY_PACKAGES_EXTENSION')) define('SMARTY_PACKAGES_EXTENSION', (isset($_ENV['SMARTY_PACKAGES_EXTENSION']) ? $_ENV['SMARTY_PACKAGES_EXTENSION'] : '.php')); +if (!defined('SMARTY_DEFAULT_TPL')) define('SMARTY_DEFAULT_TPL', (isset($_ENV['SMARTY_DEFAULT_TPL_ID']) ? (int)$_ENV['SMARTY_DEFAULT_TPL_ID'] : null)); +if (!defined('SMARTY_404PAGE_TPL')) define('SMARTY_404PAGE_TPL', (isset($_ENV['SMARTY_404PAGE_TPL_FILE']) ? $_ENV['SMARTY_404PAGE_TPL_FILE'] : null)); /** * Define various Gallery related constants. @@ -245,63 +223,98 @@ * @const MAX_THUMBNAIL_SIZE The maximum width & height for pic thumbnails * @const THUMBPAGE The image size for Thumbnail pictures */ -if (!defined('MAX_PIC_SIZE')) define('MAX_PIC_SIZE', ['width'=>800, 'height'=>800]); -if (!defined('MAX_THUMBNAIL_SIZE')) define('MAX_THUMBNAIL_SIZE', ['width'=>150, 'height'=>150]); -if (!defined('THUMBPAGE')) define('THUMBPAGE', ['width'=>4, 'height'=>3, 'padding'=>10]); +if (!defined('MAX_PIC_SIZE')) define('MAX_PIC_SIZE', (isset($_ENV['GALLERY_MAX_PIC_SIZE']) ? (array)$_ENV['GALLERY_MAX_PIC_SIZE'] : null)); +if (!defined('MAX_THUMBNAIL_SIZE')) define('MAX_THUMBNAIL_SIZE', (isset($_ENV['GALLERY_MAX_THUMBNAIL_SIZE']) ? (array)$_ENV['GALLERY_MAX_THUMBNAIL_SIZE'] : null)); +if (!defined('THUMBPAGE')) define('THUMBPAGE', (isset($_ENV['GALLERY_THUMBPAGE']) ? (array)$_ENV['GALLERY_THUMBPAGE'] : null)); /** - * Grab the NASA API Key. - * @include nasaapis_key.inc.php Include a String containing a valid NASA API Key + * Define various NASA API and APOD related constants. * @const NASA_API_KEY A constant holding the NASA API Key, can be used optionally (!) for requests to NASA's APIs such as the APOD - */ -if (!defined('NASA_API_KEY')) define('NASA_API_KEY', include APIKEYS_DIR.'/nasa/'.(file_exists(APIKEYS_DIR.'/nasa/nasaapis_key.inc.local.php') ? 'nasaapis_key.inc.local.php' : 'nasaapis_key.inc.php') ); - -/** - * Define various APOD related constants. * @const APOD_GALLERY_ID ID der APOD-Gallery in der Datenbank * @const APOD_TEMP_IMGPATH Pfad zum initialen Download des aktuellen APOD-Bildes * @const APOD_SOURCE Source-URL für die APOD-Bilder Archiv-Links * @const APOD_API NASA APOD API-URL von wo das tägliche APOD-Bild mit dem NASA_API_KEY geholt werden kann, mittels ?apod_date=yyyy-mm-dd kann ein spezifisches APOD geholt werden */ -if (!defined('APOD_GALLERY_ID')) define('APOD_GALLERY_ID', 41); -if (!defined('APOD_TEMP_IMGPATH')) define('APOD_TEMP_IMGPATH', SITE_ROOT.'/../data/temp/'); -if (!defined('APOD_SOURCE')) define('APOD_SOURCE', 'https://apod.nasa.gov/apod/'); -if (!defined('APOD_API')) define('APOD_API', 'https://api.nasa.gov/planetary/apod?api_key='.NASA_API_KEY); - -/** - * Define and include various Placeholder-Strings related constants and files. - * @include strings.inc.php - */ -include_once INCLUDES_DIR.'strings.inc.php'; +if (!defined('NASA_API_KEY') && isset($_ENV['NASA_API_KEY'])) define('NASA_API_KEY', $_ENV['NASA_API_KEY']); +if (!defined('APOD_GALLERY_ID')) define('APOD_GALLERY_ID', (isset($_ENV['APOD_GALLERY_ID']) ? $_ENV['APOD_GALLERY_ID'] : null)); +if (!defined('APOD_TEMP_IMGPATH')) define('APOD_TEMP_IMGPATH', (isset($_ENV['APOD_TEMP_IMAGE_DIR']) ? $_ENV['APOD_TEMP_IMAGE_DIR'] : null)); +if (!defined('APOD_SOURCE')) define('APOD_SOURCE', (isset($_ENV['NASA_APOD_SOURCE']) ? $_ENV['NASA_APOD_SOURCE'] : null)); +if (!defined('APOD_API')) define('APOD_API', (isset($_ENV['NASA_APOD_API']) ? $_ENV['NASA_APOD_API'] : null)); /** - * Define and include various Notification System-related constants and files. - * @include notifications.inc.php + * Define various Addle related constants. + * @const MAX_ADDLE_GAMES Anzahl der erlaubten gleichzeitig offenen Addle-Spiele eines Users + * @const MAX_ADDLE_GAMES Anzahl der erlaubten gleichzeitig offenen Addle-Spiele eines Users + * @const MAX_ADDLE_GAMES Anzahl der erlaubten gleichzeitig offenen Addle-Spiele eines Users */ -include_once INCLUDES_DIR.'notifications.inc.php'; +define('MAX_ADDLE_GAMES', (isset($_ENV['ADDLE_MAX_GAMES']) ? (int)$_ENV['ADDLE_MAX_GAMES'] : 0)); +define('ADDLE_BASE_POINTS', (isset($_ENV['ADDLE_BASE_POINTS']) ? (int)$_ENV['ADDLE_BASE_POINTS'] : 0)); +define('ADDLE_MAX_POINTS_TRANSFERABLE', (isset($_ENV['ADDLE_MAX_POINTS_TRANSFERABLE']) ? (int)$_ENV['ADDLE_MAX_POINTS_TRANSFERABLE'] : 0)); /** - * Define and include various Telegram-Bot/Telegram-Messaging related constants and files. - * @include telegrambot.inc.php Required to send Telegram-Notifications + * Define zorg-specific global constants + * + * @const VORSTAND_USER User-ID of the Zorg Verein Vorstand-User + * @const BARBARA_HARRIS User-ID of [z]Barbara Harris + * @const ROSENVERKAEUFER User-ID des Rosenverkäufer's (für Peter-Spiele) + * @const THE_ARCHITECT User-ID des [z]architect + * @const ZORG_VEREIN_NAME Bezeichnung des Vereins (z.B. für Swiss QR Bill) + * @const ZORG_VEREIN_EMAIL Zorg Verein E-Mail address + * @const ZORG_VEREIN_STRASSE Strasse der Adresse des Vereins (z.B. für Swiss QR Bill) + * @const ZORG_VEREIN_PLZ PLZ der Adresse des Vereins (z.B. für Swiss QR Bill) + * @const ZORG_VEREIN_ORT Ort der Adresse des Vereins (z.B. für Swiss QR Bill) + * @const ZORG_VEREIN_LAND Zorg Land der Adresse des Vereins (z.B. für Swiss QR Bill) + * @const ZORG_VEREIN_LAND_ISO2 2-stelliger ISO-Code des Land des Vereins (z.B. für Swiss QR Bill) + * @const ZORG_VEREIN_KONTO_BANK Bankname des Vereinskontos (z.B. für Swiss QR Bill) + * @const ZORG_VEREIN_KONTO_SWIFT SWIFT-Identifikation des Vereinskontos (z.B. für Swiss QR Bill) + * @const ZORG_VEREIN_KONTO_IBAN IBAN-Nummer des Vereinskontos (z.B. für Swiss QR Bill) + * @const ZORG_VEREIN_KONTO_IBAN_QRBILL Swiss QR-Bill IBAN-Nummer des Vereinskontos (z.B. für Swiss QR Bill) + * @const ZORG_VEREIN_KONTO_CURRENCY Akzeptierte Währung des Vereinskontos (z.B. für Swiss QR Bill) + * @const ZORG_VEREIN_KONTO_BESRID Diese Identifikationsnummer (BESR-ID) wird von der Bank vergeben (nicht bei Post Finance). Benötigt für Referenznummern auf Rechnungen. */ -include_once INCLUDES_DIR.'telegrambot.inc.php'; +if (!defined('VORSTAND_USER')) define('VORSTAND_USER', (isset($_ENV['VORSTAND_USER']) ? (int)$_ENV['VORSTAND_USER'] : null)); +if (!defined('BARBARA_HARRIS')) define('BARBARA_HARRIS', (isset($_ENV['BARBARA_HARRIS']) ? (int)$_ENV['BARBARA_HARRIS'] : null)); +if (!defined('ROSENVERKAEUFER')) define('ROSENVERKAEUFER', (isset($_ENV['ROSENVERKAEUFER']) ? (int)$_ENV['ROSENVERKAEUFER'] : null)); +if (!defined('THE_ARCHITECT')) define('THE_ARCHITECT', (isset($_ENV['THE_ARCHITECT']) ? (int)$_ENV['THE_ARCHITECT'] : null)); +if (!defined('ZORG_VEREIN_NAME')) define('ZORG_VEREIN_NAME', (isset($_ENV['ZORG_VEREIN_NAME']) ? $_ENV['ZORG_VEREIN_NAME'] : null)); +if (!defined('ZORG_VEREIN_EMAIL')) define('ZORG_VEREIN_EMAIL', (isset($_ENV['ZORG_VEREIN_EMAIL']) ? $_ENV['ZORG_VEREIN_EMAIL'] : null)); +if (!defined('ZORG_VEREIN_STRASSE')) define('ZORG_VEREIN_STRASSE', (isset($_ENV['ZORG_VEREIN_STRASSE']) ? $_ENV['ZORG_VEREIN_STRASSE'] : null)); +if (!defined('ZORG_VEREIN_PLZ')) define('ZORG_VEREIN_PLZ', (isset($_ENV['ZORG_VEREIN_PLZ']) ? (int)$_ENV['ZORG_VEREIN_PLZ'] : null)); +if (!defined('ZORG_VEREIN_ORT')) define('ZORG_VEREIN_ORT', (isset($_ENV['ZORG_VEREIN_ORT']) ? $_ENV['ZORG_VEREIN_ORT'] : null)); +if (!defined('ZORG_VEREIN_LAND')) define('ZORG_VEREIN_LAND', (isset($_ENV['ZORG_VEREIN_LAND']) ? $_ENV['ZORG_VEREIN_LAND'] : null)); +if (!defined('ZORG_VEREIN_LAND_ISO2')) define('ZORG_VEREIN_LAND_ISO2', (isset($_ENV['ZORG_VEREIN_LAND_ISO2']) ? $_ENV['ZORG_VEREIN_LAND_ISO2'] : null)); +if (!defined('ZORG_VEREIN_KONTO_BANK')) define('ZORG_VEREIN_KONTO_BANK', (isset($_ENV['ZORG_VEREIN_KONTO_BANK']) ? $_ENV['ZORG_VEREIN_KONTO_BANK'] : null)); +if (!defined('ZORG_VEREIN_KONTO_SWIFT')) define('ZORG_VEREIN_KONTO_SWIFT', (isset($_ENV['ZORG_VEREIN_KONTO_SWIFT']) ? $_ENV['ZORG_VEREIN_KONTO_SWIFT'] : null)); +if (!defined('ZORG_VEREIN_KONTO_IBAN')) define('ZORG_VEREIN_KONTO_IBAN', (isset($_ENV['ZORG_VEREIN_KONTO_IBAN']) ? $_ENV['ZORG_VEREIN_KONTO_IBAN'] : null)); +if (!defined('ZORG_VEREIN_KONTO_IBAN_QRBILL')) define('ZORG_VEREIN_KONTO_IBAN_QRBILL', (isset($_ENV['ZORG_VEREIN_KONTO_IBAN_QRBILL']) ? $_ENV['ZORG_VEREIN_KONTO_IBAN_QRBILL'] : null)); +if (!defined('ZORG_VEREIN_KONTO_CURRENCY')) define('ZORG_VEREIN_KONTO_CURRENCY', (isset($_ENV['ZORG_VEREIN_KONTO_CURRENCY']) ? $_ENV['ZORG_VEREIN_KONTO_CURRENCY'] : null)); +if (!defined('ZORG_VEREIN_KONTO_BESRID')) define('ZORG_VEREIN_KONTO_BESRID', (isset($_ENV['ZORG_VEREIN_KONTO_BESRID']) ? $_ENV['ZORG_VEREIN_KONTO_BESRID'] : null)); /** - * Define various Addle related constants. - * @const MAX_ADDLE_GAMES Anzahl der erlaubten gleichzeitig offenen Addle-Spiele eines Users - * @const MAX_ADDLE_GAMES Anzahl der erlaubten gleichzeitig offenen Addle-Spiele eines Users - * @const MAX_ADDLE_GAMES Anzahl der erlaubten gleichzeitig offenen Addle-Spiele eines Users + * Set a constant for the custom Error Log path. + * @see zorgErrorHandler(), user_error(), trigger_error() + * @link https://github.com/zorgch/zorg-code/blob/master/www/includes/errlog.inc.php errlog.inc.php + * + * @const ERRORLOG_FILETYPE sets the file extension used for the error log file + * @const ERRORLOG_DIR sets the directory for logging the custom user_errors + * @const ERRORLOG_FILEPATH sets the directory & file path for logging the custom user_errors to + * @include errlog.inc.php Errorlogging Class: Load the zorg Error Handling */ -define('MAX_ADDLE_GAMES', 1); -define('ADDLE_BASE_POINTS', 1600); -define('ADDLE_MAX_POINTS_TRANSFERABLE', 32); +if (!defined('ERRORLOG_FILETYPE')) define('ERRORLOG_FILETYPE', (isset($_ENV['ERRORLOG_FILETYPE']) ? $_ENV['ERRORLOG_FILETYPE'] : '.log')); +if (!defined('ERRORLOG_DIR')) define('ERRORLOG_DIR', (isset($_ENV['ERRORLOG_DIR']) ? $_ENV['ERRORLOG_DIR'] : null)); +if (!defined('ERRORLOG_FILE')) define('ERRORLOG_FILE', ERRORLOG_DIR.date('Y-m-d').ERRORLOG_FILETYPE); +require_once INCLUDES_DIR.'errlog.inc.php'; +//set_error_handler('zorgErrorHandler'); +error_reporting($_ENV['ERROR_REPORTING_LEVELS']); /** - * Define and include the MCV Controllers and initialise Layout related settings. - * @include core.model.php MCV Models -> FIXME requires namespace & use cleanup first - * @include layout.controller.php MVC Controller for Layout + * Include some generic files and functions to make them globally available by default. + * (keep this at the end of the config.inc.php!) + * + * @include strings.inc.php Various Placeholder-Strings related constants and files. + * @include notifications.inc.php Various Notification System-related constants and files + * @include telegrambot.inc.php Required to send Telegram-Notifications */ -//require_once MODELS_DIR.'core.model.php'; // FIXME requires namespace & use cleanup first -require_once CONTROLLERS_DIR.'layout.controller.php'; -if (DEVELOPMENT === true) error_log(sprintf('[DEBUG] <%s:%d> new MVC\Controller\Layout()', __FILE__, __LINE__)); -$zorgLayout = new MVC\Controller\Layout(); +include_once INCLUDES_DIR.'strings.inc.php'; +include_once INCLUDES_DIR.'notifications.inc.php'; +include_once INCLUDES_DIR.'telegrambot.inc.php'; diff --git a/www/includes/forum.inc.php b/www/includes/forum.inc.php index 6f3be69..ecb1d9b 100644 --- a/www/includes/forum.inc.php +++ b/www/includes/forum.inc.php @@ -1915,8 +1915,9 @@ static function getHTML($showboards, $pagesize, $sortby='last_post_date') } /** RSS Feed-Link für Thread anzeigen */ + $feedURLbase = (isset($_ENV['URLPATH_RSS']) ? $_ENV['URLPATH_RSS'] : ''); $html .= - ' '.t('forum-rss-thread-action', 'commenting').''; /** rechtsbündig-span & td-element schliessen */ diff --git a/www/includes/hz_map.inc.php b/www/includes/hz_map.inc.php index 6dd0390..51c2e9b 100644 --- a/www/includes/hz_map.inc.php +++ b/www/includes/hz_map.inc.php @@ -6,80 +6,81 @@ /** * File includes */ -require_once dirname(__FILE__).'/config.inc.php'; +require_once __DIR__.'/config.inc.php'; +require_once INCLUDES_DIR.'main.inc.php'; include_once INCLUDES_DIR.'util.inc.php'; /** Hunting Z-Maps special Constants */ -define("MAPIMGPATH", PHP_IMAGES_DIR.'hz/'); -define("HZMAPS_DIR", FILES_DIR.'../hz_maps/'); +define("MAPIMGPATH", (isset($_ENV['HZ_MAPS_IMAGES_DIR']) ? $_ENV['HZ_MAPS_IMAGES_DIR'] : null)); +define("HZMAPS_DIR", (isset($_ENV['HZ_MAPS_DIR']) ? $_ENV['HZ_MAPS_DIR'] : null)); function create_map ($mapfile, &$map_config, &$error, &$img_map) { global $user, $map_stations, $map_routes; - $imgfile = HZMAPS_DIR.$user->id.'.gif'; - + $imgfile = HZMAPS_DIR.$user->id.(isset($_ENV['HZ_MAPS_EXTENSION']) ? $_ENV['HZ_MAPS_EXTENSION'] : '.gif'); + $cfg = read_config($mapfile); if ($err = check_config ($cfg)) { $error = $err; } - + $im = draw_map_base($cfg['map']['width'], $cfg['map']['height']); - - foreach ($map_routes['ubahn'] as $it) + + foreach ($map_routes['ubahn'] as $it) draw_route( - $im, - "ubahn", - array($map_stations[$it['start']]['x'], $map_stations[$it['start']]['y']), + $im, + "ubahn", + array($map_stations[$it['start']]['x'], $map_stations[$it['start']]['y']), array($map_stations[$it['end']]['x'], $map_stations[$it['end']]['y']), $it['transit'], $_GET['station_checker'] ); - foreach ($map_routes['bus'] as $it) + foreach ($map_routes['bus'] as $it) draw_route( - $im, - "bus", - array($map_stations[$it['start']]['x'], $map_stations[$it['start']]['y']), + $im, + "bus", + array($map_stations[$it['start']]['x'], $map_stations[$it['start']]['y']), array($map_stations[$it['end']]['x'], $map_stations[$it['end']]['y']), $it['transit'], $_GET['station_checker'] ); - foreach ($map_routes['taxi'] as $it) + foreach ($map_routes['taxi'] as $it) draw_route( - $im, - "taxi", - array($map_stations[$it['start']]['x'], $map_stations[$it['start']]['y']), + $im, + "taxi", + array($map_stations[$it['start']]['x'], $map_stations[$it['start']]['y']), array($map_stations[$it['end']]['x'], $map_stations[$it['end']]['y']), $it['transit'], $_GET['station_checker'] ); - + foreach ($map_routes['black'] as $it) draw_route( - $im, - "black", - array($map_stations[$it['start']]['x'], $map_stations[$it['start']]['y']), + $im, + "black", + array($map_stations[$it['start']]['x'], $map_stations[$it['start']]['y']), array($map_stations[$it['end']]['x'], $map_stations[$it['end']]['y']), $it['transit'], $_GET['station_checker'] ); - + unset($_GET['station_checker']); - + foreach ($cfg['aims'] as $it) draw_aim($im, $map_stations[$it['station']]['x'], $map_stations[$it['station']]['y'], $it['score']); $img_map; - + foreach ($cfg['stations'] as $it) { draw_station($im, $it['id'], $it['x'], $it['y'], $it['bus'], $it['ubahn']); - + $img_map .= '' ; } - - + + $map_config = $cfg['map']; - + imagegif($im, $imgfile); return $imgfile; } @@ -87,7 +88,7 @@ function create_map ($mapfile, &$map_config, &$error, &$img_map) { function save_map ($mapfile) { global $db, $user; - + $cfg = read_config($mapfile); if ($err = check_config($cfg)) { return $err; @@ -119,9 +120,9 @@ function save_map ($mapfile) { function change_map_state ($map, $state) { global $db, $user; - + if (!in_array($state, array("active", "inactive"))) user_error("Invalid map state '$state'", E_USER_ERROR); - + $e = $db->query("SELECT * FROM hz_maps WHERE id=$map", __FILE__, __LINE__); $d = $db->fetch($e); if ($d['user'] == $user->id) { @@ -136,7 +137,7 @@ function change_map_state ($map, $state) { function station_pos ($map, $id) { global $db; - + $e = $db->query("SELECT * FROM hz_stations WHERE map='$map' AND id='$id'", __FILE__, __LINE__); $d = $db->fetch($e); if ($d) { @@ -163,16 +164,16 @@ function transit_string2array ($transit, $map) { } } } - + return $ret; } function read_config ($mapfile) { global $map_stations, $map_routes; - + if (!isset($map_stations)) $map_stations = array(); if (!isset($map_routes)) $map_routes = array("taxi"=>array(), "bus"=>array(), "ubahn"=>array(), "black"=>array()); - + $ret = array("map"=>array(), "stations"=>array(), "routes"=>array(), "aims"=>array()); $section = ""; $config = file($mapfile); @@ -200,7 +201,7 @@ function read_config ($mapfile) { $entry['y'] = trim($_entry[2]); $entry['ubahn'] = trim($_entry[3]); $entry['bus'] = trim($_entry[4]); - + $ret['stations'][] = $entry; $map_stations[$entry['id']] = $entry; } @@ -222,7 +223,7 @@ function read_config ($mapfile) { $ent['transit'][] = trim($b[0]); } } - + $ret['routes'][] = $ent; $map_routes[$ent['type']][] = $ent; $map_stations[$ent['start']]["has_$ent[type]"] = 1; @@ -242,12 +243,12 @@ function read_config ($mapfile) { function check_config ($cfg) { global $db, $map_stations; - + if (!$cfg['map']['name']) return "Missing 'name' in section [MAP]"; $e = $db->query("SELECT * FROM hz_maps WHERE name='".$cfg['map']['name']."'", __FILE__, __LINE__); $d = $db->fetch($e); if ($d) return ("Es gibt schon eine Map mit diesem Namen. Bitte einen anderen Namen wählen."); - + if (!$cfg['map']['width']) return "Missing 'width' in section [MAP]"; if (!is_numeric($cfg['map']['width']) || $cfg['map']['width']>5000 || $cfg['map']['width']<200) return "'width' in section [Map] must be between 200 and 5000."; if (!$cfg['map']['height']) return "Missing 'height' in section [MAP]"; @@ -258,9 +259,9 @@ function check_config ($cfg) { foreach ($cfg['map'] as $key=>$val) { if (!in_array($key, $valid_map_keys)) return "Invalid option '$key' in section [MAP]."; } - + $station_ids = array(); - + foreach ($map_stations as $it) { if (!is_numeric($it['id']) || $it['id']<1 || $it['id']>999) return "Invalid Station id: '$it[id]' (must be between 1 and 999)"; if (in_array($it['id'], $station_ids)) return "Dublicate Station id: $it[id]"; @@ -273,16 +274,16 @@ function check_config ($cfg) { if ($it['bus'] && !$it['has_bus']) return "Station $it[id]: Bus Route required."; if ($it['ubahn'] && !$it['has_ubahn']) return "Station $it[id]: Underground Route required."; } - + foreach ($cfg['routes'] as $it) { if (!$map_stations[$it['start']]['id']) return "$it[type]-Route $it[start] - $it[end]: Start Station doesn't exist."; - if ($it['type'] != "taxi" && $it['type'] != "black" && !$map_stations[$it['start']][$it['type']]) + if ($it['type'] != "taxi" && $it['type'] != "black" && !$map_stations[$it['start']][$it['type']]) return "$it[type]-Route $it[start] - $it[end]: Start Station doesn't support $it[type]-Routes."; if (!$map_stations[$it['end']]['id']) return "$it[type]-Route $it[start] - $it[end]: End Station doesn't exist."; - if ($it['type'] != "taxi" && $it['type'] != "black" && !$map_stations[$it['end']][$it['type']]) + if ($it['type'] != "taxi" && $it['type'] != "black" && !$map_stations[$it['end']][$it['type']]) return "$it[type]-Route $it[start] - $it[end]: End Station doesn't support $it[type]-Routes."; if ($it['start'] == $it['end']) return "$it[type]-Route $it[start] - $it[end]: Start and End Station must not be the same."; - foreach ($it['transit'] as $tr) { + foreach ($it['transit'] as $tr) { if (is_array($tr)) { if (!is_numeric($tr[0]) || $tr[0]<1 || $tr[0]>5000) return "$it[type]-Route $it[start] - $it[end]: Points (x) must be between 1 and 5000)."; if (!is_numeric($tr[1]) || $tr[1]<1 || $tr[1]>5000) return "$it[type]-Route $it[start] - $it[end]: Points (y) must be between 1 and 5000)."; @@ -292,7 +293,7 @@ function check_config ($cfg) { } } } - + $aim_ids = array(); foreach ($cfg['aims'] as $it) { if (in_array($it['station'], $aim_ids)) return "Duplicate aims on station '$it[station]'."; @@ -300,37 +301,37 @@ function check_config ($cfg) { if ($it['score'] < 1 || $it['score'] > 999) return "Aim on station '$it[station]': Invalid score (must be between 1 and 999)."; $aim_ids[] = $it['station']; } - + return 0; } function draw_map_base ($x, $y) { $im = @ImageCreate ($x,$y); if (!$im) return array("error"=>__LINE__); - + $bg = htmlcolor2array(HZ_BG_COLOR); - $background_color = ImageColorAllocate ($im, $bg['r'], $bg['g'], $bg['b']); - + $background_color = ImageColorAllocate ($im, $bg['r'], $bg['g'], $bg['b']); + define("COLOR_TAXI", imagecolorallocate($im, 255,255,0)); define("COLOR_UBAHN", imagecolorallocate($im, 255,0,0)); define("COLOR_BUS", imagecolorallocate($im, 0,200,0)); define("COLOR_BLACK", imagecolorallocate($im, 0,0,0)); define("COLOR_BORDER", imagecolorallocate($im, 0,0,0)); define("COLOR_TEXT", imagecolorallocate($im, 0,0,0)); - + define("STATION_TAXI", imagecreatefromgif(MAPIMGPATH."station_taxi.gif")); define("STATION_TAXI_BUS", imagecreatefromgif(MAPIMGPATH."station_taxi_bus.gif")); define("STATION_UBAHN_TAXI", imagecreatefromgif(MAPIMGPATH."station_ubahn_taxi.gif")); define("STATION_UBAHN_TAXI_BUS", imagecreatefromgif(MAPIMGPATH."station_ubahn_taxi_bus.gif")); - + define("ROUTE_UBAHN", imagecreatefromgif(MAPIMGPATH."route_ubahn.gif")); define("ROUTE_BUS", imagecreatefromgif(MAPIMGPATH."route_bus.gif")); define("ROUTE_TAXI", imagecreatefromgif(MAPIMGPATH."route_taxi.gif")); define("ROUTE_BLACK", imagecreatefromgif(MAPIMGPATH."route_black.gif")); - + define("AIM", imagecreatefromgif(MAPIMGPATH."aim.gif")); define("AIM_CAUGHT", imagecreatefromgif(MAPIMGPATH."aim_caught.gif")); - + define("PLAYER_1", imagecreatefromgif(MAPIMGPATH."player_1.gif")); define("PLAYER_2", imagecreatefromgif(MAPIMGPATH."player_2.gif")); define("PLAYER_3", imagecreatefromgif(MAPIMGPATH."player_3.gif")); @@ -342,24 +343,24 @@ function draw_map_base ($x, $y) { define("PLAYER_Z", imagecreatefromgif(MAPIMGPATH."player_z.gif")); define("PLAYER_Z_SEEN", imagecreatefromgif(MAPIMGPATH."player_z_seen.gif")); define("PLAYER_ME", imagecreatefromgif(MAPIMGPATH."player_me.gif")); - + define("SENTINEL", imagecreatefromgif(MAPIMGPATH."sentinel.gif")); - + imagerectangle($im, 0, 0, $x-1, $y-1, COLOR_BORDER); - + return $im; } -function draw_station (&$im, $id, $x, $y, $bus, $ubahn) { +function draw_station (&$im, $id, $x, $y, $bus, $ubahn) { if ($bus && $ubahn) $type = STATION_UBAHN_TAXI_BUS; elseif ($bus) $type = STATION_TAXI_BUS; elseif ($ubahn) $type = STATION_UBAHN_TAXI; else $type = STATION_TAXI; - + if (floor($id / 100)) $str_x = $x-10; // 3-stellig elseif (floor($id / 10)) $str_x = $x-6; // 2-stellig else $str_x = $x-2; // 1-stellig - + imagecopy($im, $type, $x-15,$y-10, 0,0, 30, 20); ImageString ($im, 3, $str_x,$y-7, $id, COLOR_TEXT); } @@ -367,11 +368,11 @@ function draw_station (&$im, $id, $x, $y, $bus, $ubahn) { function draw_aim (&$im, $x, $y, $score, $not_caught = true) { if ($not_caught) $pic = AIM; else $pic = AIM_CAUGHT; - + if (floor($score / 100)) $str_x = $x-8; // 3-stellig elseif (floor($score / 10)) $str_x = $x-5; // 2-stellig else $str_x = $x-2; // 1-stellig - + imagecopy($im, $pic, $x-20, $y-25, 0,0, 40,40); imagestring($im, 2, $str_x, $y-23, $score, COLOR_TEXT); } @@ -389,7 +390,7 @@ function draw_player (&$im, $x, $y, $type) { case 'z': $pic = PLAYER_Z; break; default: user_error("Invalid player type '$type'", E_USER_ERROR); } - + imagecopy($im, $pic, $x+5, $y-23, 0, 0, 30,40); } @@ -400,7 +401,7 @@ function draw_player_me (&$im, $x, $y) { function draw_z_seen (&$im, $x, $y, $final=0) { if ($final) $pic = PLAYER_Z; else $pic = PLAYER_Z_SEEN; - + imagecopy($im, $pic, $x-35, $y-23, 0,0, 30,40); } @@ -411,21 +412,21 @@ function draw_sentinel (&$im, $x, $y) { function draw_route (&$im, $type, $start, $end, $transit = array(), $station_checker=0) { global $map_stations, $map_routes; - + if ($station_checker) { $s = $station_checker; $station_checker = array($map_stations[$s]['x'], $map_stations[$s]['y']); } - + if ($station_checker && ($start==$station_checker || $end==$station_checker) || !$station_checker) { switch ($type) { - case "ubahn": + case "ubahn": imagesetbrush($im, ROUTE_UBAHN); break; - case "bus": + case "bus": imagesetbrush($im, ROUTE_BUS); break; - case "taxi": + case "taxi": imagesetbrush($im, ROUTE_TAXI); break; case "black": @@ -433,7 +434,7 @@ function draw_route (&$im, $type, $start, $end, $transit = array(), $station_che break; default: user_error("Invalid route type", E_USER_ERROR); } - + for ($i=0; $i FIXME requires namespace & use cleanup first */ -//require_once INCLUDES_DIR.'strings.inc.php'; +require_once __DIR__.'/config.inc.php'; require_once INCLUDES_DIR.'mysql.inc.php'; require_once INCLUDES_DIR.'usersystem.inc.php'; require_once INCLUDES_DIR.'util.inc.php'; require_once INCLUDES_DIR.'smarty.inc.php'; -//require_once INCLUDES_DIR.'sunrise.inc.php'; @DEPRECATED + +/** + * Define and include the MCV Controllers and initialise Layout related settings. + * @include layout.controller.php MVC Controller for Layout + */ +//require_once MODELS_DIR.'core.model.php'; // FIXME requires namespace & use cleanup first +require_once CONTROLLERS_DIR.'layout.controller.php'; +if (DEVELOPMENT === true) error_log(sprintf('[DEBUG] <%s:%d> new MVC\Controller\Layout()', __FILE__, __LINE__)); +$zorgLayout = new MVC\Controller\Layout(); /** * Include other scripts @@ -70,11 +63,7 @@ /** * Smarty assign variables * Variables can be accessed in Smarty-Templates using {$variable} - * @const SMARTY_DEFAULT_TPL Default (fallback) Smarty-Template tpl:- or file:-ID/Name - * @const SMARTY_404PAGE_TPL 404 "Page not found" Smarty-Template reference */ -if (!defined('SMARTY_DEFAULT_TPL')) define('SMARTY_DEFAULT_TPL', 23); -if (!defined('SMARTY_404PAGE_TPL')) define('SMARTY_404PAGE_TPL', 'file:layout/pages/404_page.tpl'); $smarty->register_function('sqltracker', 'dbcon::sqltracker'); $smarty->register_modifier('rendertime', 'smarty_modifier_rendertime'); $smarty->assign('spaceweather', spaceweather_ticker()); diff --git a/www/includes/notifications.inc.php b/www/includes/notifications.inc.php index 707b7b3..bf393aa 100644 --- a/www/includes/notifications.inc.php +++ b/www/includes/notifications.inc.php @@ -275,7 +275,7 @@ private function sendEmailNotification($from_user_id, $to_user_id, $titel, $text $empfaengerName = $user->id2user($to_user_id, TRUE); $senderName = $user->id2user($from_user_id, TRUE); - $header = t('email-notification-header', 'messagesystem', [ SITE_HOSTNAME, ZORG_EMAIL, phpversion() ]); + $header = t('email-notification-header', 'messagesystem', [ SITE_HOSTNAME, SENDMAIL_EMAIL, phpversion() ]); $subject = sprintf('=?UTF-8?Q?%s?=', quoted_printable_encode(remove_html(t('email-notification-subject', 'messagesystem', [ $senderName, SITE_HOSTNAME ]), ENT_DISALLOWED, 'UTF-8'))); diff --git a/www/includes/smarty.inc.php b/www/includes/smarty.inc.php index e0b219f..358cdce 100644 --- a/www/includes/smarty.inc.php +++ b/www/includes/smarty.inc.php @@ -17,7 +17,7 @@ * @include usersystem.inc.php Include * @include comments.res.php Include */ -require_once dirname(__FILE__).'/config.inc.php'; +require_once __DIR__.'/config.inc.php'; require_once SMARTY_DIR.'Smarty.class.php'; include_once INCLUDES_DIR.'usersystem.inc.php'; include_once INCLUDES_DIR.'comments.res.php'; @@ -84,7 +84,7 @@ function hasTplAccess ($group, $owner, $userid, $usertyp) /** member und schöne */ if ($group == USER_MEMBER) { - if ($usertyp == USER_MEMBER) + if ($usertyp == USER_MEMBER) { return true; } else { @@ -164,7 +164,7 @@ function _tpl_assigns ($params, $content, &$smarty, &$repeat) { * @param object $smarty Pass by reference: Smarty Class-object * @global object $db Globales Class-Object mit allen MySQL-Methoden * @global object $user Globales Class-Object mit den User-Methoden & Variablen - * @return bool Returns true/false depening on if a successful execution was possible, or not + * @return bool Returns true/false depening on if a successful execution was possible, or not */ function smartyresource_tpl_get_template($tpl_name, &$tpl_source, &$smarty) { @@ -247,7 +247,7 @@ function smartyresource_tpl_get_template($tpl_name, &$tpl_source, &$smarty) * @param object $smarty Pass by reference: Smarty Class-object * @global object $db Globales Class-Object mit allen MySQL-Methoden * @global array $_tpl_stack Globales Array mit allen Template-Variablen - * @return bool Returns true/false depening on if a successful execution was possible, or not + * @return bool Returns true/false depening on if a successful execution was possible, or not */ function smartyresource_tpl_get_timestamp($tpl_name, &$tpl_timestamp, &$smarty) { @@ -255,8 +255,8 @@ function smartyresource_tpl_get_timestamp($tpl_name, &$tpl_timestamp, &$smarty) if (!empty($tpl_name) && is_numeric($tpl_name)) { - $e = $db->query('SELECT id, title, word, LENGTH(tpl) size, owner, update_user, - UNIX_TIMESTAMP(last_update) last_update, UNIX_TIMESTAMP(created) created, read_rights, + $e = $db->query('SELECT id, title, word, LENGTH(tpl) size, owner, update_user, + UNIX_TIMESTAMP(last_update) last_update, UNIX_TIMESTAMP(created) created, read_rights, write_rights, force_compile, border, sidebar_tpl, allow_comments FROM templates WHERE id='.$tpl_name, __FILE__, __LINE__, __FUNCTION__); $d = $db->fetch($e); } else { @@ -556,8 +556,8 @@ function startSmarty() $smarty->template_dir = SMARTY_TEMPLATES_HTML; $smarty->compile_dir = SMARTY_COMPILE; $smarty->cache_dir = SMARTY_CACHE; - $smarty->trusted_dir = array(SMARTY_TRUSTED_DIRS); - $smarty->secure_dir = array(SMARTY_TEMPLATES_HTML); + $smarty->trusted_dir = SMARTY_TRUSTED_DIRS; + $smarty->secure_dir = SMARTY_TEMPLATES_HTML; // don't execute {php} tag $smarty->php_handling = SMARTY_PHP_QUOTE; diff --git a/www/includes/spaceweather.inc.php b/www/includes/spaceweather.inc.php index 09f0775..dbc2353 100644 --- a/www/includes/spaceweather.inc.php +++ b/www/includes/spaceweather.inc.php @@ -1,33 +1,28 @@ '; } + + /* FIXME + PHP Notice: Undefined offset: 9 in /srv/zorg.ch/www/public/includes/stl.inc.php on line 697 + PHP Notice: Trying to access array offset on value of type null in /srv/zorg.ch/www/public/includes/stl.inc.php $ + PHP Notice: Undefined offset: 9 in /srv/zorg.ch/www/public/includes/stl.inc.php on line 710 + PHP Notice: Trying to access array offset on value of type null in /srv/zorg.ch/www/public/includes/stl.inc.php $ + PHP Notice: Undefined offset: 9 in /srv/zorg.ch/www/public/includes/stl.inc.php on line 711 + PHP Notice: Trying to access array offset on value of type null in /srv/zorg.ch/www/public/includes/stl.inc.php $ + PHP Notice: Undefined offset: 9 in /srv/zorg.ch/www/public/includes/stl.inc.php on line 712 + PHP Notice: Trying to access array offset on value of type null in /srv/zorg.ch/www/public/includes/stl.inc.php $ + PHP Notice: Undefined offset: 9 in /srv/zorg.ch/www/public/includes/stl.inc.php on line 723 + PHP Notice: Trying to access array offset on value of type null in /srv/zorg.ch/www/public/includes/stl.inc.php $ + PHP Notice: Undefined offset: 9 in /srv/zorg.ch/www/public/includes/stl.inc.php on line 724 + PHP Notice: Trying to access array offset on value of type null in /srv/zorg.ch/www/public/includes/stl.inc.php $ + PHP Notice: Undefined offset: 9 in /srv/zorg.ch/www/public/includes/stl.inc.php on line 737 + PHP Notice: Trying to access array offset on value of type null in /srv/zorg.ch/www/public/includes/stl.inc.php $ + PHP Notice: Undefined offset: 9 in /srv/zorg.ch/www/public/includes/stl.inc.php on line 738 + PHP Notice: Trying to access array offset on value of type null in /srv/zorg.ch/www/public/includes/stl.inc.php $ + PHP Notice: Undefined offset: 10 in /srv/zorg.ch/www/public/includes/stl.inc.php on line 650 + PHP Notice: Undefined offset: 10 in /srv/zorg.ch/www/public/includes/stl.inc.php on line 659 + PHP Notice: Trying to access array offset on value of type null in /srv/zorg.ch/www/public/includes/stl.inc.php $ + PHP Notice: Undefined offset: 10 in /srv/zorg.ch/www/public/includes/stl.inc.php on line 671 + PHP Notice: Trying to access array offset on value of type null in /srv/zorg.ch/www/public/includes/stl.inc.php $ + PHP Notice: Undefined offset: 10 in /srv/zorg.ch/www/public/includes/stl.inc.php on line 686 + PHP Notice: Trying to access array offset on value of type null in /srv/zorg.ch/www/public/includes/stl.inc.php $ + PHP Notice: Undefined offset: 10 in /srv/zorg.ch/www/public/includes/stl.inc.php on line 697 + PHP Notice: Trying to access array offset on value of type null in /srv/zorg.ch/www/public/includes/stl.inc.php $ + PHP Notice: Undefined offset: 10 in /srv/zorg.ch/www/public/includes/stl.inc.php on line 710 + PHP Notice: Trying to access array offset on value of type null in /srv/zorg.ch/www/public/includes/stl.inc.php $ + PHP Notice: Undefined offset: 10 in /srv/zorg.ch/www/public/includes/stl.inc.php on line 711 + PHP Notice: Trying to access array offset on value of type null in /srv/zorg.ch/www/public/includes/stl.inc.php $ + PHP Notice: Undefined offset: 10 in /srv/zorg.ch/www/public/includes/stl.inc.php on line 712 + PHP Notice: Trying to access array offset on value of type null in /srv/zorg.ch/www/public/includes/stl.inc.php $ + PHP Notice: Undefined offset: 10 in /srv/zorg.ch/www/public/includes/stl.inc.php on line 723 + PHP Notice: Trying to access array offset on value of type null in /srv/zorg.ch/www/public/includes/stl.inc.php $ + PHP Notice: Undefined offset: 10 in /srv/zorg.ch/www/public/includes/stl.inc.php on line 724 + PHP Notice: Trying to access array offset on value of type null in /srv/zorg.ch/www/public/includes/stl.inc.php $ + PHP Notice: Undefined offset: 10 in /srv/zorg.ch/www/public/includes/stl.inc.php on line 737 + PHP Notice: Trying to access array offset on value of type null in /srv/zorg.ch/www/public/includes/stl.inc.php $ + PHP Notice: Undefined offset: 10 in /srv/zorg.ch/www/public/includes/stl.inc.php on line 738 + PHP Notice: Trying to access array offset on value of type null in /srv/zorg.ch/www/public/includes/stl.inc.php $ + PHP Notice: Undefined offset: 11 in /srv/zorg.ch/www/public/includes/stl.inc.php on line 650 + PHP Notice: Trying to access array offset on value of type null in /srv/zorg.ch/www/public/includes/stl.inc.php $ + PHP Notice: Undefined offset: 11 in /srv/zorg.ch/www/public/includes/stl.inc.php on line 659 + PHP Notice: Trying to access array offset on value of type null in /srv/zorg.ch/www/public/includes/stl.inc.php $ + PHP Notice: Undefined offset: 11 in /srv/zorg.ch/www/public/includes/stl.inc.php on line 671 + PHP Notice: Trying to access array offset on value of type null in /srv/zorg.ch/www/public/includes/stl.inc.php $ + PHP Notice: Undefined offset: 11 in /srv/zorg.ch/www/public/includes/stl.inc.php on line 686 + PHP Notice: Trying to access array offset on value of type null in /srv/zorg.ch/www/public/includes/stl.inc.php $ + PHP Notice: Undefined offset: 11 in /srv/zorg.ch/www/public/includes/stl.inc.php on line 697 + PHP Notice: Trying to access array offset on value of type null in /srv/zorg.ch/www/public/includes/stl.inc.php $ + PHP Notice: Undefined offset: 11 in /srv/zorg.ch/www/public/includes/stl.inc.php on line 710 + PHP Notice: Trying to access array offset on value of type null in /srv/zorg.ch/www/public/includes/stl.inc.php $ + PHP Notice: Undefined offset: 11 in /srv/zorg.ch/www/public/includes/stl.inc.php on line 711 + PHP Notice: Trying to access array offset on value of type null in /srv/zorg.ch/www/public/includes/stl.inc.php $ + PHP Notice: Undefined offset: 11 in /srv/zorg.ch/www/public/includes/stl.inc.php on line 712 + PHP Notice: Trying to access array offset on value of type null in /srv/zorg.ch/www/public/includes/stl.inc.php $ + PHP Notice: Undefined offset: 11 in /srv/zorg.ch/www/public/includes/stl.inc.php on line 723 + PHP Notice: Trying to access array offset on value of type null in /srv/zorg.ch/www/public/includes/stl.inc.php $ + PHP Notice: Undefined offset: 11 in /srv/zorg.ch/www/public/includes/stl.inc.php on line 724 + PHP Notice: Trying to access array offset on value of type null in /srv/zorg.ch/www/public/includes/stl.inc.php $ + PHP Notice: Undefined offset: 11 in /srv/zorg.ch/www/public/includes/stl.inc.php on line 737 + PHP Notice: Trying to access array offset on value of type null in /srv/zorg.ch/www/public/includes/stl.inc.php $ + PHP Notice: Undefined offset: 11 in /srv/zorg.ch/www/public/includes/stl.inc.php on line 738 + PHP Notice: Trying to access array offset on value of type null in /srv/zorg.ch/www/public/includes/stl.inc.php $ + */ } } $this->data['game'] .= ""; diff --git a/www/includes/strings.inc.php b/www/includes/strings.inc.php index a3d1968..9cc72d5 100644 --- a/www/includes/strings.inc.php +++ b/www/includes/strings.inc.php @@ -7,7 +7,7 @@ /** * @const NO_STRING_FOUND String for empty / not found references to be replaced */ -if (!defined('NO_STRING_FOUND')) define('NO_STRING_FOUND', 'Reference not found in String list'); +if (!defined('NO_STRING_FOUND')) define('NO_STRING_FOUND', (isset($_ENV['STRING_NOT_FOUND']) ? $_ENV['STRING_NOT_FOUND'] : null)); /** * Import an Array with strings and make it globally available @@ -53,11 +53,11 @@ function t($reference, $context='global', $values=NULL, $tploutput=NULL) { /** Check if any of the $values is empty */ foreach ($values as $key=>$value) { - if (empty($value)) error_log(sprintf('[WARN] strings.inc.php: Value %s for string "%s" was passed but is empty!', $key+1, $reference)); + if (empty($value)) error_log(sprintf('[WARN] <%s:%d> Value %s for string "%s" was passed but is empty!', __FILE__, __LINE__, $key+1, $reference)); } $values_count = count($values); } elseif (isset($values) && $values == '') { - error_log('[WARN] strings.inc.php: a value was passed but it is empty!'); + error_log(sprintf('[WARN] <%s:%d> A value was passed but it is empty!', __FILE__, __LINE__)); } @@ -68,7 +68,7 @@ function t($reference, $context='global', $values=NULL, $tploutput=NULL) { /** Check if the number of $values matches the sprintf-placeholders */ $sprintf_count = substr_count($found_string, '%'); - if ($values_count != $sprintf_count) error_log(sprintf('[NOTICE] strings.inc.php: possible mismatch between values (num: %d) & sprintf (num: %d) for string "%s"', $values_count, $sprintf_count, $found_string)); + if ($values_count != $sprintf_count) error_log(sprintf('[NOTICE] <%s:%d> Possible mismatch between values (num: %d) & sprintf (num: %d) for string "%s"', __FILE__, __LINE__, $values_count, $sprintf_count, $found_string)); /** * Replace & return - or return only - a matched string @@ -77,7 +77,7 @@ function t($reference, $context='global', $values=NULL, $tploutput=NULL) $string = ( !empty($values) && $values_count > 0 ? vsprintf($found_string, $values) : $found_string ); } else { - $string = sprintf('[WARN] %s: %s in %s', NO_STRING_FOUND, $reference, $context); + $string = sprintf('[WARN] <%s:%d> %s: %s in %s', __FILE__, __LINE__, NO_STRING_FOUND, $reference, $context); error_log($string); } @@ -123,19 +123,19 @@ function findReferenceInArray($context, $reference) { return $found_string; } else { - error_log('[WARN] Reference text is empty or invalid'); + error_log(sprintf('[WARN] <%s:%d> Reference text is empty or invalid', __FILE__, __LINE__)); return false; } } else { - error_log('[WARN] Reference not found in $strings: ' . $context); + error_log(sprintf('[WARN] <%s:%d> Reference not found in $strings: %s', __FILE__, __LINE__, $context)); return false; } } else { - error_log('[WARN] Topic not found in $strings: ' . $context); + error_log(sprintf('[WARN] <%s:%d> Topic not found in $strings: %s', __FILE__, __LINE__, $context)); return false; } } else { - error_log('[WARN] Strings Array could not be loaded'); + error_log(sprintf('[WARN] <%s:%d> Strings Array could not be loaded', __FILE__, __LINE__)); return false; } } diff --git a/www/includes/usersystem.inc.php b/www/includes/usersystem.inc.php index 101d67f..6e79059 100644 --- a/www/includes/usersystem.inc.php +++ b/www/includes/usersystem.inc.php @@ -14,7 +14,7 @@ * @include mysql.inc.php MySQL-DB Connection and Functions * @include activities.inc.php Activities Functions and Stream */ -require_once dirname(__FILE__).'/config.inc.php'; +require_once __DIR__.'/config.inc.php'; require_once INCLUDES_DIR.'util.inc.php'; require_once INCLUDES_DIR.'mysql.inc.php'; require_once INCLUDES_DIR.'activities.inc.php'; @@ -62,6 +62,7 @@ class usersystem /** * Var to map User Fields */ + var $field_userid = 'id'; var $field_activities_allow = 'activities_allow'; var $field_activity = 'activity'; var $field_addle = 'addle'; @@ -165,7 +166,7 @@ function __construct() /** * User Session (re-)starten */ - if (isset($_COOKIE[ZORG_COOKIE_SESSION]) && session_status() === PHP_SESSION_NONE) + if (session_status() === PHP_SESSION_NONE && isset($_COOKIE[ZORG_COOKIE_SESSION])) { /** Session init'en */ session_start(); @@ -174,10 +175,10 @@ function __construct() /** $_SESSION[user_id] not yet available -> if not on forced Login / Logout try to Autologin */ if (!isset($_SESSION['user_id']) && !isset($_POST['username']) && !isset($_POST['logout'])) { + /** We got Cookies --> Autologin! */ if (DEVELOPMENT === true) error_log(sprintf('[DEBUG] <%s:%d> $_SESSION[user_id] missing & no login/logout...', __METHOD__, __LINE__)); if (!empty($_COOKIE[ZORG_COOKIE_USERID]) && !empty($_COOKIE[ZORG_COOKIE_USERPW])) { - /** We got Cookies --> Autologin! */ if (DEVELOPMENT === true) error_log(sprintf('[DEBUG] <%s:%d> Autologin-Cookies existieren -> Login-Passthrough', __METHOD__, __LINE__)); $this->login($_COOKIE[ZORG_COOKIE_USERID]); // Do NOT send $_COOKIE[ZORG_COOKIE_USERPW] here - because it only contains the PW-Hash! } @@ -189,16 +190,16 @@ function __construct() * Wenn bereits usersystem::login() erfolgreich triggered wurde, * dann wurde nach session_start() die User-ID in die Session geschrieben */ - if (isset($_SESSION['user_id']) && !empty($_SESSION['user_id'])) // empty() nur zur Sicherheit, falls user_id zwar gesetzt, aber dennoch leer ist + if (session_status() === PHP_SESSION_ACTIVE && + isset($_SESSION['user_id']) && !empty($_SESSION['user_id']) && $_SESSION['user_id'] > 0) { /** Query User Infos in der DB */ if (DEVELOPMENT === true) error_log(sprintf('[DEBUG] <%s:%d> Session re-started inkl. $_SESSION[user_id]!', __METHOD__, __LINE__)); - $sql = 'SELECT *, - UNIX_TIMESTAMP('.$this->field_activity.') as '.$this->field_activity.', - UNIX_TIMESTAMP('.$this->field_lastlogin.') as '.$this->field_lastlogin.', - UNIX_TIMESTAMP('.$this->field_currentlogin.') as '.$this->field_currentlogin.' - FROM '.$this->table_name.' - WHERE id = '.$_SESSION['user_id']; + $sql = 'SELECT *'. + ',UNIX_TIMESTAMP('.$this->field_activity.') as '.$this->field_activity. + ',UNIX_TIMESTAMP('.$this->field_lastlogin.') as '.$this->field_lastlogin. + ',UNIX_TIMESTAMP('.$this->field_currentlogin.') as '.$this->field_currentlogin. + ' FROM '.$this->table_name.' WHERE id = '.$_SESSION['user_id']; $result = $db->query($sql, __FILE__, __LINE__); $rs = $db->fetch($result); @@ -275,9 +276,8 @@ function __construct() * @TODO Activity nur updaten wenn vorherige & aktuelle Page-URL (z.B. Referrer vs. ...) nicht identisch sind? */ $db->update($this->table_name, ['id', $this->id], [ - $this->field_activity => timestamp(true), - //$this->field_last_ip => $_SERVER['REMOTE_ADDR'], // @DEPRECATED - $this->field_from_mobile => ($this->from_mobile === false ? '' : $this->from_mobile), // because 'ENUM'-fieldtype + $this->field_activity => timestamp(true) + ,$this->field_from_mobile => ($this->from_mobile === false ? '' : (string)$this->from_mobile), // because 'ENUM'-fieldtype ], __FILE__, __LINE__, __METHOD__); } } @@ -369,18 +369,8 @@ function login($username, $password=null, $user_wants_cookies=false) if (isset($crypted_pw) && !empty($crypted_pw)) { /** Erstell SQL-Query auf Basis User+Passworthash-Kombi */ - $sql = sprintf('SELECT - id, - %1$s, - UNIX_TIMESTAMP(%2$s) %2$s, - UNIX_TIMESTAMP(%3$s) %3$s, - UNIX_TIMESTAMP(%4$s) %4$s - FROM - %5$s - WHERE - %6$s = "%7$s" - AND %8$s = "%9$s" - LIMIT 0,1', + $sql = sprintf('SELECT %10$s, %1$s, UNIX_TIMESTAMP(%2$s) %2$s, UNIX_TIMESTAMP(%3$s) %3$s, UNIX_TIMESTAMP(%4$s) %4$s FROM %5$s'. + ' WHERE %6$s = "%7$s" AND %8$s = "%9$s" LIMIT 0,1', $this->field_user_active, $this->field_ausgesperrt_bis, $this->field_currentlogin, @@ -389,7 +379,8 @@ function login($username, $password=null, $user_wants_cookies=false) $this->field_username, $username, $this->field_userpw, - $crypted_pw + $crypted_pw, + $this->field_userid ); if (DEVELOPMENT) error_log(sprintf('[DEBUG] <%s:%d> login: $db->query($sql) => %s', __METHOD__, __LINE__, print_r($sql,true))); $result = $db->query($sql, __FILE__, __LINE__, __METHOD__); @@ -423,13 +414,46 @@ function login($username, $password=null, $user_wants_cookies=false) * @link http://php.net/manual/de/function.setcookie.php * @link http://php.net/manual/de/function.setcookie.php#73107 */ - if (DEVELOPMENT) error_log(sprintf('[DEBUG] <%s:%d> Enabling & setting Cookies. Use cookies: %s', __METHOD__, __LINE__, ($user_wants_cookies ? 'true' : 'false'))); - if (session_status() === PHP_SESSION_NONE) session_set_cookie_params(['lifetime' => 60*60*24*7, 'path' => ZORG_COOKIE_PATH, 'domain' => ZORG_COOKIE_DOMAIN, 'secure' => ZORG_COOKIE_SECURE, 'httponly' => true, 'samesite' => ZORG_COOKIE_SAMESITE]); - setcookie(ZORG_COOKIE_SESSION, session_id(), ['expires' => ZORG_COOKIE_EXPIRATION, 'path' => ZORG_COOKIE_PATH, 'domain' => ZORG_COOKIE_DOMAIN, 'secure' => ZORG_COOKIE_SECURE, 'httponly' => true, 'samesite' => ZORG_COOKIE_SAMESITE]); - setcookie(ZORG_COOKIE_USERID, $username, ['expires' => ZORG_COOKIE_EXPIRATION, 'path' => ZORG_COOKIE_PATH, 'domain' => ZORG_COOKIE_DOMAIN, 'secure' => ZORG_COOKIE_SECURE, 'httponly' => true, 'samesite' => ZORG_COOKIE_SAMESITE]); - setcookie(ZORG_COOKIE_USERPW, $crypted_pw, ['expires' => ZORG_COOKIE_EXPIRATION, 'path' => ZORG_COOKIE_PATH, 'domain' => ZORG_COOKIE_DOMAIN, 'secure' => ZORG_COOKIE_SECURE, 'httponly' => true, 'samesite' => ZORG_COOKIE_SAMESITE]); - } else { - /** No Cookies wanted - Session/Login will expire on Browser close */ + if (DEVELOPMENT) error_log(sprintf('[DEBUG] <%s:%d> Use cookies: %s | Session state: %d', __METHOD__, __LINE__, ($user_wants_cookies ? 'true --> enabling & setting Cookies' : 'false'), session_status())); + if (session_status() === PHP_SESSION_NONE) + { + session_set_cookie_params([ + 'lifetime' => (isset($_ENV['COOKIE_EXPIRATION']) ? $_ENV['COOKIE_EXPIRATION'] : 60*60*24*7) + ,'path' => ZORG_COOKIE_PATH + ,'domain' => ZORG_COOKIE_DOMAIN + ,'secure' => ZORG_COOKIE_SECURE + ,'httponly' => COOKIE_HTTPONLY + ,'samesite' => ZORG_COOKIE_SAMESITE + ]); + setcookie(ZORG_COOKIE_SESSION, session_id(), [ + 'expires' => ZORG_COOKIE_EXPIRATION + ,'path' => ZORG_COOKIE_PATH + ,'domain' => ZORG_COOKIE_DOMAIN + ,'secure' => ZORG_COOKIE_SECURE + ,'httponly' => COOKIE_HTTPONLY + ,'samesite' => ZORG_COOKIE_SAMESITE + ]); + setcookie(ZORG_COOKIE_USERID, $username, [ + 'expires' => ZORG_COOKIE_EXPIRATION + ,'path' => ZORG_COOKIE_PATH + ,'domain' => ZORG_COOKIE_DOMAIN + ,'secure' => ZORG_COOKIE_SECURE + ,'httponly' => COOKIE_HTTPONLY + ,'samesite' => ZORG_COOKIE_SAMESITE + ]); + setcookie(ZORG_COOKIE_USERPW, $crypted_pw, [ + 'expires' => ZORG_COOKIE_EXPIRATION + ,'path' => ZORG_COOKIE_PATH + ,'domain' => ZORG_COOKIE_DOMAIN + ,'secure' => ZORG_COOKIE_SECURE + ,'httponly' => COOKIE_HTTPONLY + ,'samesite' => ZORG_COOKIE_SAMESITE + ]); + } + } + + /** No Cookies wanted - Session/Login will expire on Browser close */ + else { if (session_status() === PHP_SESSION_NONE) session_set_cookie_params(['path' => ZORG_COOKIE_PATH, 'domain' => ZORG_COOKIE_DOMAIN, 'secure' => ZORG_COOKIE_SECURE, 'httponly' => true, 'samesite' => ZORG_COOKIE_SAMESITE]); // DISABLED: 'lifetime' => ZORG_SESSION_LIFETIME, } @@ -592,20 +616,14 @@ static function invalidate_session() * @param boolean $zorg Zorg-Layout * @param boolean $zooomclan Zooomclan-Layout */ - function set_page_style($user_id, $zorg=TRUE, $zooomclan=FALSE) { + function set_page_style($user_id, $zorg=TRUE, $zooomclan=FALSE) + { global $db, $zorg, $zooomclan; - if ($zorg == true) { - $sql = "UPDATE ".$this->table_name." - set ".$this->field_zorger." = 1 - WHERE id = '".$user_id."'"; - $db->query($sql, __FILE__, __LINE__, __METHOD__); - } elseif ($zooomclan == true) { - $sql = "UPDATE ".$this->table_name." - set ".$this->field_zorger." = 0 - WHERE id = '".$user_id."'"; - $db->query($sql, __FILE__, __LINE__, __METHOD__); - } + if ($zorg == true) $sql = sprintf('UPDATE %s SET %s="%s" WHERE id=%d', $this->table_name, $this->field_zorger, "1", $user_id); + elseif ($zooomclan == true) $sql = sprintf('UPDATE %s SET %s="%s" WHERE id=%d', $this->table_name, $this->field_zorger, "0", $user_id); + + $db->query($sql, __FILE__, __LINE__, __METHOD__); } /** @@ -623,7 +641,7 @@ function set_page_style($user_id, $zorg=TRUE, $zooomclan=FALSE) { * * @uses usersystem::password_gen() * @uses usersystem::crypt_pw() - * @uses ZORG_EMAIL + * @uses SITE_HOSTNAME, SENDMAIL_EMAIL * @param string $email E-Mailadresse für deren User das PW geändert werden soll * @global object $db Globales Class-Object mit allen MySQL-Methoden * @return string Error-Message @@ -664,7 +682,7 @@ function new_pass($email) { if ($result !== false) { /** 5. versende email mit neuem passwort */ - $mail_header = t('email-notification-header', 'messagesystem', [ SITE_HOSTNAME, ZORG_EMAIL, phpversion() ]); + $mail_header = t('email-notification-header', 'messagesystem', [ SITE_HOSTNAME, SENDMAIL_EMAIL, phpversion() ]); $mail_subject = sprintf('=?UTF-8?Q?%s?=', quoted_printable_encode(remove_html(t('message-newpass-subject', 'user'), ENT_DISALLOWED, 'UTF-8'))); $mail_body = t('message-newpass', 'user', [$rs['username'], $new_pass]); $new_pass_mail_status = mail($email, $mail_subject, $mail_body, $mail_header); @@ -699,8 +717,8 @@ function new_pass($email) { * @since 2.0 replaced messages with Translation-String solution t() * @since 3.0 `04.12.2018` removed IMAP-code, code & query optimizations * - * @uses usersystem::crypt_pw() - * @uses t() + * @uses usersystem::crypt_pw(), t() + * @uses SITE_URL, SENDMAIL_EMAIL * @param string $username Benutzername * @param string $pw Passwort * @param string $pw2 Passwortwiederholung @@ -748,7 +766,7 @@ function create_newuser($username, $pw, $pw2, $email) { $db->query($sql, __FILE__, __LINE__, __METHOD__); /** email versenden */ - $sendNewaccountConfirmation = mail($email, t('message-newaccount-subject', 'user'), t('message-newaccount', 'user', [ $username, SITE_URL, $key ]), 'From: '.ZORG_EMAIL."\n"); + $sendNewaccountConfirmation = mail($email, t('message-newaccount-subject', 'user'), t('message-newaccount', 'user', [ $username, SITE_URL, $key ]), 'From: '.SENDMAIL_EMAIL."\n"); if ($sendNewaccountConfirmation !== true) { error_log(sprintf('[NOTICE] <%s:%d> Account confirmation e-mail could NOT be sent', __FILE__, __LINE__)); @@ -2233,7 +2251,7 @@ function exec_aussperren($user_id, $date_array) */ if (isset($_POST['do']) && $_POST['do'] === 'login') { - if (DEVELOPMENT) error_log(sprintf('[DEBUG] <%s:%d> exec User login (Form)', 'LOGIN mit Login-Formular', __LINE__)); + if (DEVELOPMENT) error_log(sprintf('[DEBUG] <%s:%d> exec User login (Form): %s', 'LOGIN mit Login-Formular', __LINE__, print_r($_POST, true))); if (!empty($_POST['username']) && !empty($_POST['password'])) { $login_username = (string)$_POST['username']; diff --git a/www/index.php b/www/index.php index 13e4f87..0fa5086 100644 --- a/www/index.php +++ b/www/index.php @@ -7,9 +7,11 @@ */ /** * File Includes - * @include zorg Master Include File + * @include config.inc.php Global Configs + * @include main.inc.php Layout Stuff */ -require_once dirname(__FILE__).'/includes/main.inc.php'; +require_once __DIR__.'/includes/config.inc.php'; +require_once INCLUDES_DIR.'main.inc.php'; /** * Parse URL-Routes & Query Parameters @@ -86,6 +88,7 @@ $smarty->assign('feeddesc', SITE_HOSTNAME . ' RSS Feed'); $smarty->assign('feedlang', 'de-DE'); $smarty->assign('feeddate', date('D, d M Y H:i:s').' GMT'); + $feedURLbase = $_ENV['URLPATH_RSS']; switch ($_GET['type']) { @@ -99,7 +102,7 @@ { /** RSS Feed für einen einzelnen Thread */ $smarty->assign('feedtitle', remove_html(Comment::getLinkThread($_GET['board'], $_GET['thread_id']) . PAGETITLE_SUFFIX) ); - $smarty->assign('feedlink', RSS_URL . '&amp;type=forum&amp;board=' . $_GET['board'] . '&amp;thread_id=' . $_GET['thread_id']); + $smarty->assign('feedlink', $feedURLbase . '&amp;type=forum&amp;board=' . $_GET['board'] . '&amp;thread_id=' . $_GET['thread_id']); $smarty->assign('feeditems', Forum::printRSS($_GET['board'], (isset($_SESSION['user_id']) && $_SESSION['user_id'] > 0 ? $_SESSION['user_id'] : null), $_GET['thread_id'])); /** keine thread_id vorhanden */ @@ -109,7 +112,7 @@ * @TODO Fix "unknown feed" (broken RSS-feed) für Gallery-Comments: ?layout=rss&type=forum&board=i */ $smarty->assign('feedtitle', remove_html(Forum::getBoardTitle($_GET['board']) . PAGETITLE_SUFFIX) ); - $smarty->assign('feedlink', RSS_URL . '&amp;type=forum&amp;board=' . $_GET['board']); + $smarty->assign('feedlink', $feedURLbase . '&amp;type=forum&amp;board=' . $_GET['board']); $smarty->assign('feeditems', Forum::printRSS($_GET['board'], (isset($_SESSION['user_id']) && $_SESSION['user_id'] > 0 ? $_SESSION['user_id'] : null))); } @@ -117,7 +120,7 @@ } else { /** genereller Forum RSS Feed */ $smarty->assign('feedtitle', 'Forum RSS' . PAGETITLE_SUFFIX); - $smarty->assign('feedlink', RSS_URL . '&amp;type=forum'); + $smarty->assign('feedlink', $feedURLbase . '&amp;type=forum'); $smarty->assign('feeditems', Forum::printRSS(null, (isset($_SESSION['user_id']) && $_SESSION['user_id'] > 0 ? $_SESSION['user_id'] : null))); } break; @@ -125,7 +128,7 @@ /** Activities RSS */ case 'activities': $smarty->assign('feedtitle', remove_html('Activities' . PAGETITLE_SUFFIX)); - $smarty->assign('feedlink', RSS_URL . '&amp;type=activities'); + $smarty->assign('feedlink', $feedURLbase . '&amp;type=activities'); $smarty->assign('feeditems', Activities::getActivitiesRSS(25)); break; } diff --git a/www/js/ajax/verein_mailer/set-mailsend.php b/www/js/ajax/verein_mailer/set-mailsend.php index 1026d83..64b6028 100644 --- a/www/js/ajax/verein_mailer/set-mailsend.php +++ b/www/js/ajax/verein_mailer/set-mailsend.php @@ -117,15 +117,15 @@ /** @TODO Make a Q Encoding: convert every non ASCII character to an equivalent char understandable by MIME or quoted printable http://php.net/manual/de/function.mb-encode-mimeheader.php#90242 */ /** - * From:-Address Format "From: Präsident|Aktuar|Kassier|Event Manager \r\n" + * From:-Address Format "From: Präsident|Aktuar|Kassier|Event Manager \r\n" * @link https://stackoverflow.com/a/10381429/5750030 * @link https://www.php.net/manual/en/function.mail.php#124291 for PHP mail() TO: encoding */ - if ($_POST['topic'] === 'president') $senderEmail = '=?UTF-8?B?'.base64_encode('Präsident').'?= <'.ZORG_EMAIL.'>'; - elseif ($_POST['topic'] === 'actuary') $senderEmail = '=?UTF-8?B?'.base64_encode('Aktuar').'?= <'.ZORG_EMAIL.'>'; - elseif ($_POST['topic'] === 'treasurer') $senderEmail = '=?UTF-8?B?'.base64_encode('Kassier').'?= <'.ZORG_EMAIL.'>'; - elseif ($_POST['topic'] === 'eventmanager') $senderEmail = '=?UTF-8?B?'.base64_encode('Event Manager').'?= <'.ZORG_EMAIL.'>'; - else $senderEmail = ZORG_EMAIL; + if ($_POST['topic'] === 'president') $senderEmail = '=?UTF-8?B?'.base64_encode('Präsident').'?= <'.SENDMAIL_EMAIL.'>'; + elseif ($_POST['topic'] === 'actuary') $senderEmail = '=?UTF-8?B?'.base64_encode('Aktuar').'?= <'.SENDMAIL_EMAIL.'>'; + elseif ($_POST['topic'] === 'treasurer') $senderEmail = '=?UTF-8?B?'.base64_encode('Kassier').'?= <'.SENDMAIL_EMAIL.'>'; + elseif ($_POST['topic'] === 'eventmanager') $senderEmail = '=?UTF-8?B?'.base64_encode('Event Manager').'?= <'.SENDMAIL_EMAIL.'>'; + else $senderEmail = SENDMAIL_EMAIL; /** * Build E-Mail diff --git a/www/seti_example.php b/www/seti_example.php index 21d1f4b..b124742 100644 --- a/www/seti_example.php +++ b/www/seti_example.php @@ -10,7 +10,8 @@ /** * File includes */ -require_once dirname(__FILE__).'/includes/main.inc.php'; +require_once __DIR__.'/includes/config.inc.php'; +require_once INCLUDES_DIR.'main.inc.php'; require_once INCLUDES_DIR.'setistats.inc.php'; require_once MODELS_DIR.'core.model.php'; @@ -26,16 +27,16 @@ * Initialise SETI Stats Class-Object */ $seti = new SetiStats(); - $seti->setEmail('keep3r@seti.zooomclan.org'); + $seti->setEmail($_ENV['SETI_EMAIL']); $seti->Init(); - + print '' .'' .'setistats' .'' .''; ?> - + UserEmail: email ?>
ServerUrl1: server1 ?>
ServerUrl2: server2 ?>
@@ -56,7 +57,7 @@ ResultsPerWeek: AverageResultsPerWeek() ?>
ResultsPerMonth: AverageResultsPerMonth() ?>
RegistrationClass: viewStats('RegistrationClass') ?>
- ResultInterval: ResultInt() ?>
+ ResultInterval: ResultInt() ?>
ResultInterval['days'].' Days ' .$seti->ResultInterval['hours'].' Hours ' .$seti->ResultInterval['minutes'].' Minutes ' @@ -69,6 +70,6 @@ else { http_response_code(403); // Set response code 403 (access denied) and exit. $smarty->assign('error', ['type' => 'warn', 'dismissable' => 'false', 'title' => 'Access denied', 'message' => 'Hier dürfen nur Member was machen. Tschau.']); - $smarty->display('file:layout/head.tpl'); + $smarty->display('file:layout/head.tpl'); $smarty->display('file:layout/footer.tpl'); } diff --git a/www/templates/layout/head.tpl b/www/templates/layout/head.tpl index e55a500..92e5228 100644 --- a/www/templates/layout/head.tpl +++ b/www/templates/layout/head.tpl @@ -54,12 +54,13 @@ - - - - - - + {assign var=feedURLbase value=$smarty.env.URLPATH_RSS} + + + + + + {* Wenn es ein eingeloggter User ist, wird im Fenstertitel die Anzahl Unreads angezeigt... *} From e2f4186f50b0215b1e594854b610129d68e495a8 Mon Sep 17 00:00:00 2001 From: Oliver Date: Sun, 1 Jan 2023 10:45:32 +0100 Subject: [PATCH 04/13] Changes to API Keys from .env - Removes /keys/ dir --- README.md | 94 +++++++++++++----- keys/README.md | 112 ---------------------- keys/facebook/.gitignore | 5 - keys/google/.gitignore | 5 - keys/ipinfo/ipinfo_key.inc.example.php | 11 --- keys/nasa/.gitignore | 5 - keys/nasa/nasaapis_key.inc.example.php | 12 --- keys/telegram_bot/.gitignore | 5 - keys/telegram_bot/telegramexample_bot.php | 26 ----- keys/twitter/.gitignore | 5 - www/actions/events.php | 21 ++-- www/includes/googleapis.inc.php | 22 +++-- www/includes/telegrambot.inc.php | 63 +++++++----- www/profil.php | 5 +- 14 files changed, 136 insertions(+), 255 deletions(-) delete mode 100644 keys/README.md delete mode 100644 keys/facebook/.gitignore delete mode 100644 keys/google/.gitignore delete mode 100644 keys/ipinfo/ipinfo_key.inc.example.php delete mode 100644 keys/nasa/.gitignore delete mode 100644 keys/nasa/nasaapis_key.inc.example.php delete mode 100644 keys/telegram_bot/.gitignore delete mode 100644 keys/telegram_bot/telegramexample_bot.php delete mode 100644 keys/twitter/.gitignore diff --git a/README.md b/README.md index cb02bc0..fee311e 100644 --- a/README.md +++ b/README.md @@ -12,19 +12,23 @@ - [Pull-Request mit Code-Änderungen erstellen](#pull-request-mit-code-änderungen-erstellen) - [Deployments](#deployments) - [Initiales Server-Setup](#initiales-setup-repo-einmalig-auf-den-server-runterladen) +- [Services- und API Integrationen](#services-und-api-integrationen) # zorg Code standalone lokal einrichten ## Voraussetzungen -Lokal muss ein Apache-Webserver mit [**PHP**](#php) sowie [**MySQL**](#mysql) vorhanden sein. -Am einfachsten geht das mittels [MAMP (macOS)][1], [WAMP (Windows)][2] und [LAMP (Linux)][3]. -Zukünftig geplant ist ein Docker Container, aber der [[z]keep3r][6] macht nicht fürschi damit... +### Docker Container +Rundum sorglos Paket: siehe separates [zorg on Docker how-to](Docker/README.md) im `/Docker`-dir. + +### Apache-PHP-MySQL Stack +Was auch geht ist lokal mittels einem Apache-Webserver mit [**PHP**](#php) sowie [**MySQL**](#mysql). +Am effizientesten direkt mittels [MAMP (macOS)][1], [WAMP (Windows)][2] und [LAMP (Linux)][3]. -### PHP +#### PHP * [Current][14]: **PHP 7.4.x** * für <= [zorg Code 4.0.1][16]: PHP 5.6.37 -### MySQL +#### MySQL * Current: **MySQL 5.7.x** * für <= [zorg Code 4.0.1][16]: MySQL 5.6 @@ -49,8 +53,6 @@ Am einfachsten und mit eingebauten Git ist die Arbeit/Bezug des zorg Codes mit e \* *Um in das zorg Code Repository comitten zu können muss Du mindestens die gleiche E-Mailadresse, wie verlinkt in deinem GitHub-Account, verwenden!* -### Docker Container -WIP [[z]keep3r][6], ## Clone des zorg Codes Am einfachsten klickst Du auf der GitHub Repository-Seite einfach oben rechts auf den grünen "Clone or download"-button – oder Du ziehst Dir den neusten Release von [hier][16] und verschiebst alle Files lokal in das gewünschte Webroot vom Apache. @@ -72,24 +74,29 @@ Das `/data/`-Verzeichnis ist unverzichtbar für zorg.ch, aber unterliegt nicht d ``` /zorg-code/ <-- Cloned Git-Repo + .env <-- von .env.example adaptieren + Docker/ <-- Cloned www/ <-- Cloned cron/ <-- Cloned - keys/ <-- Cloned migration/ <-- Cloned scripts/ <-- Cloned - data/ <-- this+ff CREATE! - errlog/ - files/ - gallery/ - 41/ - hz_maps/ - smartylib/ - cache/ - templates_c/ - tauschboerse/ - temp/ - upload/ - userimages/ + .composer.json + .composer.lock + vendor/ <-- via composer install + data/ <-- Cloned > all Pathes can be configured/changed in .env + errlog/ <-- CREATE! + files/ <-- CREATE! + gallery/ <-- CREATE! + 41/ <-- APOD Gallery ID + hz_maps/ <-- Cloned + smartylib/ <-- CREATE! + cache/ <-- CREATE! + templates_c/ <-- CREATE! + tauschboerse/ <-- CREATE! + temp/ <-- CREATE! + upload/ <-- CREATE! + new-galleries/ <-- CREATE! + userimages/ <-- CREATE! ``` ### Berechtigungen richtig setzen @@ -394,9 +401,9 @@ class MeineKlasse function MeineFunktion($user_id, $params=null) { global $db, $user; - + $code = '...'; - + /** Kurzer inline Kommentar */ if ($code === '...') echo 'Yarak'; } @@ -441,6 +448,47 @@ Jetzt noch apache2 konfigurieren mit den notwendigen Konfigurationsdateien: **That's it** - zorg.ch sollte nun laufen & ausgeliefert werden. +# Services- und API Integrationen + +# API Keys +Im `.env` können diverse API Keys verschiedener Services eingetragen werden, welche die zorg-code Plattform braucht um Daten zu aggregieren oder an externe APIs zu pushen. + +* [Google APIs](#google-apis) + + [reCaptcha](#google-recaptcha) + + [Google Maps](#google-maps) +* [NASA API](#nasa-api) +* [Telegram Bot API](#telegram-bot-api) +* [Twitter API](#twitter-api) + +## Google APIs + +### Google reCaptcha +Das [Google reCaptcha](https://www.google.com/recaptcha/intro/v3.html) wird in der User Registration benötigt, um Bots am Erstellen von Fake Usern abzuhalten. + +### Google Maps +z.B. für [Google Maps API](https://developers.google.com/maps/documentation) Abfragen + +## NASA API +Die [NASA API](https://api.nasa.gov) wird benötigt um folgende Daten zu aggregieren: +* [APOD](https://api.nasa.gov/#apod) - Astronomy Picture of the Day +* Spaceweather APIs: + + [Near Earth Objects](https://api.nasa.gov/#NeoWS) + + [Space Weather Database DONKI](https://api.nasa.gov/#DONKI) + +#### Demo +* Request: [https://api.nasa.gov/planetary/apod?api_key=DEMO_KEY] +* Result +``` +{"date":"2020-04-18","explanation":"It was just another day on aerosol Earth. For August 23, 2018, the identification and distribution of aerosols in the Earth's atmosphere is shown in this dramatic, planet-wide digital visualization. Produced in real time, the Goddard Earth Observing System Forward Processing (GEOS FP) model relies on a combination of Earth-observing satellite and ground-based data to calculate the presence of types of aerosols, tiny solid particles and liquid droplets, as they circulate above the entire planet. This August 23rd model shows black carbon particles in red from combustion processes, like smoke from the fires in the United States and Canada, spreading across large stretches of North America and Africa. Sea salt aerosols are in blue, swirling above threatening typhoons near South Korea and Japan, and the hurricane looming near Hawaii. Dust shown in purple hues is blowing over African and Asian deserts. The location of cities and towns can be found from the concentrations of lights based on satellite image data of the Earth at night. Celebrate: Earth Day at Home","hdurl":"https://apod.nasa.gov/apod/image/2004/atmosphere_geo5_2018235_eq2400.jpg","media_type":"image","service_version":"v1","title":"Just Another Day on Aerosol Earth","url":"https://apod.nasa.gov/apod/image/2004/atmosphere_geo5_2018235_eq1200.jpg"} +``` + +## Telegram Bot API +Dank der [Telegram Bot API](https://core.telegram.org/bots) - und einem custom Bot - lassen sich diverse Messages an Telegram User oder Gruppen pushen. + +## Twitter API +Mit der [Twitter API](https://developer.twitter.com/en/docs/tweets/post-and-engage/overview) lassen sich Daten mittels eine [Twitter App ID](https://developer.twitter.com/en/apps) an einen Twitter-Account pushen oder aggregieren. z.B. Für das Absetzen von neuen Tweets. + + [1]: https://www.mamp.info/ "MAMP for macOS" [2]: https://www.wampserver.com/ "WAMP for Windows" [3]: https://www.turnkeylinux.org/lampstack "LAMP for Linux" diff --git a/keys/README.md b/keys/README.md deleted file mode 100644 index 40ca7fc..0000000 --- a/keys/README.md +++ /dev/null @@ -1,112 +0,0 @@ -# API Keys -Unter dem `/keys/`-Verzeichnis sind diverse API Keys verschiedener Services abgelegt, welche das zorg Backend braucht um Daten zu aggregieren oder an externe APIs zu pushen. - -* [Google API](#google-api) - + [reCaptcha](#recaptcha) - + [Google API](#google-api-1) -* [NASA API](#nasa-api) -* [Telegram Bot API](#telegram-bot-api) -* [Twitter API](#twitter-api) - -## Google API - -### reCaptcha -Das [Google reCaptcha](https://www.google.com/recaptcha/intro/v3.html) wird in der User Registration benötigt, um Bots am Erstellen von Fake Usern abzuhalten. -``` - - [ - 'key' => 'myGoogleReCaptchaDevPublicKey' - ,'secret' => 'myGoogleReCaptchaDevKeySecret' - ] -]; - -``` - - -### Google API -z.B. für [Google Maps API](https://developers.google.com/maps/documentation) Abfragen - -#### Example -``` - '' // as provided by @BotFather - ,'my_secret' => '' // (string) A secret password required to authorise access to the webhook. - ,'valid_ips' => [ // (array) When using `validate_request`, also allow these IPs. - //'1.2.3.4', // single - //'192.168.1.0/24', // CIDR - //'10/8', // CIDR (short) - //'5.6.*', // wildcard - //'1.1.1.1-2.2.2.2', // range - '*' // Any - ] - ,'admins' => [] // (array) An array of user ids that have admin access to your bot (must be integers). - ,'ssl_certificate' => __DIR__ . '/server.crt' // (string) Path to a self-signed certificate (if necessary). - ,'logging_dirroot' => [ __DIR__ . '/data/errlog/telegramexample_bot' ] // (array) Paths where the log files should be put. - ,'files_dirroot' => [ __DIR__ . '/data/files/telegram/telegramexample_bot' ] // (array) List of configurable paths. - ]; - -if (!defined('TELEGRAM_API_URI')) define('TELEGRAM_API_URI', 'https://api.telegram.org/bot' . $botconfigs['api_key']); -if (!defined('TELEGRAM_GROUPCHAT_ID')) define('TELEGRAM_GROUPCHAT_ID', ''); // Telegram-Group Chat-ID to post generic messages to -``` - - -## Twitter API -Mit der [Twitter API](https://developer.twitter.com/en/docs/tweets/post-and-engage/overview) lassen sich Daten mittels eine [Twitter App ID](https://developer.twitter.com/en/apps) an einen Twitter-Account pushen oder aggregieren. z.B. Für das Absetzen von neuen Tweets. - -### Example -``` - - [ - 'key' => 'myTwitterAPIdevPublicKey' - ,'secret' => 'mySuperSecretTwitterAPIdevKeySecret' - ,'token' => 'myVeryFancyTwitterAPIdevToken' - ,'tokensecret' => 'myVeryFancyYetSecureTwitterAPIdevTokenSecret' - ,'callback_url' => '' - ] -]; -``` diff --git a/keys/facebook/.gitignore b/keys/facebook/.gitignore deleted file mode 100644 index 1638722..0000000 --- a/keys/facebook/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -# Ignore everything in this directory -* - -# Except example files -!*example* diff --git a/keys/google/.gitignore b/keys/google/.gitignore deleted file mode 100644 index 1638722..0000000 --- a/keys/google/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -# Ignore everything in this directory -* - -# Except example files -!*example* diff --git a/keys/ipinfo/ipinfo_key.inc.example.php b/keys/ipinfo/ipinfo_key.inc.example.php deleted file mode 100644 index ec5e9a4..0000000 --- a/keys/ipinfo/ipinfo_key.inc.example.php +++ /dev/null @@ -1,11 +0,0 @@ - '' // as provided by @BotFather - ,'my_secret' => '' // (string) A secret password required to authorise access to the webhook. - ,'valid_ips' => [ // (array) When using `validate_request`, also allow these IPs. - //'1.2.3.4', // single - //'192.168.1.0/24', // CIDR - //'10/8', // CIDR (short) - //'5.6.*', // wildcard - //'1.1.1.1-2.2.2.2', // range - '*' // Any - ] - ,'admins' => [] // (array) An array of user ids that have admin access to your bot (must be integers). - ,'ssl_certificate' => __DIR__ . '/server.crt' // (string) Path to a self-signed certificate (if necessary). - ,'logging_dirroot' => [ __DIR__ . '/data/errlog/telegramexample_bot' ] // (array) Paths where the log files should be put. - ,'files_dirroot' => [ __DIR__ . '/data/files/telegram/telegramexample_bot' ] // (array) List of configurable paths. - ]; - -if (!defined('TELEGRAM_API_URI')) define('TELEGRAM_API_URI', 'https://api.telegram.org/bot' . $botconfigs['api_key']); -if (!defined('TELEGRAM_GROUPCHAT_ID')) define('TELEGRAM_GROUPCHAT_ID', ''); // Telegram-Group Chat-ID to post generic messages to diff --git a/keys/twitter/.gitignore b/keys/twitter/.gitignore deleted file mode 100644 index 1638722..0000000 --- a/keys/twitter/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -# Ignore everything in this directory -* - -# Except example files -!*example* diff --git a/www/actions/events.php b/www/actions/events.php index b24a86e..de755bb 100644 --- a/www/actions/events.php +++ b/www/actions/events.php @@ -4,12 +4,15 @@ * * @package zorg\Events */ + /** * File includes + * @include config.inc.php * @include main.inc.php Includes the Main Zorg Configs and Methods * @include events.inc.php Includes the Event Class and Methods */ -require_once dirname(__FILE__).'/../includes/main.inc.php'; +require_once __DIR__.'/../includes/config.inc.php'; +require_once INCLUDES_DIR.'/../includes/main.inc.php'; require_once INCLUDES_DIR.'events.inc.php'; /** Validate $_GET & $_POST variables */ @@ -133,18 +136,20 @@ /** * Load Twitter Class & Grab the Twitter API Keys + * * @include twitter.class.php Include Twitter API PHP-Class and Methods - * @include twitterapis_key.inc.php Include an Array containing valid Twitter API Keys * @see Twitter::send() */ require_once INCLUDES_DIR.'twitter-php/twitter.class.php'; - $twitterApiKeysFile = APIKEYS_DIR.'/twitter/twitterapis_key.inc.php'; - if (file_exists($twitterApiKeysFile)) + $twitterApiKey = ['key' => $_ENV['TWITTER_API_KEY'] + ,'secret' => $_ENV['TWITTER_API_SECRET'] + ,'token' => $_ENV['TWITTER_API_TOKEN'] + ,'tokensecret' => $_ENV['TWITTER_API_TOKENSECRET'] + ,'callback' => $_ENV['TWITTER_API_CALLBACK_URL'] + ]; + if (DEVELOPMENT) error_log(sprintf('[DEBUG] <%s:%d> Twitter API Keys found: %s', __FILE__, __LINE__, print_r($twitterApiKey, true))); + if (!empty($twitterApiKey['key']) && !empty($twitterApiKey['secret']) && !empty($twitterApiKey['token']) && !empty($twitterApiKey['tokensecret'])) { - $twitterApiKeys = require_once $twitterApiKeysFile; - $twitterApiKey = (DEVELOPMENT ? $twitterApiKeys['DEVELOPMENT'] : $twitterApiKeys['PRODUCTION']); - if (DEVELOPMENT) error_log(sprintf('[DEBUG] <%s:%d> Twitter API Keys found: %s', __FILE__, __LINE__, print_r($twitterApiKeys, true))); - /** Instantiate new Twitter Class */ try { $twitter = new Twitter($twitterApiKey['key'], $twitterApiKey['secret'], $twitterApiKey['token'], $twitterApiKey['tokensecret']); diff --git a/www/includes/googleapis.inc.php b/www/includes/googleapis.inc.php index 5c7bb05..5bc6844 100644 --- a/www/includes/googleapis.inc.php +++ b/www/includes/googleapis.inc.php @@ -7,15 +7,15 @@ * @author IneX * @package zorg\Vendor\Google */ + /** * File includes * @include config.inc.php - * @include googleapis_key.inc.php Grab the Google API Key: include an Array containing a valid Google API Key * @const GOOGLE_API_KEY A constant holding the Google API Key required for requests to Google's APIs */ -require_once dirname(__FILE__).'/config.inc.php'; -if (!defined('GOOGLE_API_KEY')) define('GOOGLE_API_KEY', include_once APIKEYS_DIR.'/google/'.(file_exists(APIKEYS_DIR.'/google/googleapis_key.inc.local.php') ? 'googleapis_key.inc.local.php' : 'googleapis_key.inc.php') ); -if (DEVELOPMENT && !empty(GOOGLE_API_KEY)) error_log(sprintf('[DEBUG] <%s:%d> GOOGLE_API_KEY: found', __FILE__, __LINE__)); +require_once __DIR__.'/config.inc.php'; +if (!defined('GOOGLE_API_KEY') && isset($_ENV['GOOGLE_MAPS_API_KEY'])) define('GOOGLE_API_KEY', $_ENV['GOOGLE_MAPS_API_KEY']); +if (DEVELOPMENT) error_log(sprintf('[DEBUG] <%s:%d> GOOGLE_API_KEY: %s', __FILE__, __LINE__, (!empty(GOOGLE_API_KEY) ? 'found' : 'MISSING'))); /** * Google Maps API Class @@ -25,7 +25,8 @@ * - /maps/api/geocode * * @author IneX - * @date 12.06.2018 + * @version 1.0 + * @since 1.0 `12.06.2018` `IneX` Initial integration */ class GoogleMapsApi { @@ -33,14 +34,15 @@ class GoogleMapsApi * Google Maps Geocoding API * * Geocoding is the process of converting addresses (like "1600 Amphitheatre Parkway, Mountain View, CA") - * into geographic coordinates (like latitude 37.423021 and longitude -122.083739), which you can + * into geographic coordinates (like latitude 37.423021 and longitude -122.083739), which you can * use to place markers on a map, or position the map. (Latitude/Longitude Lookup) * * @author IneX - * @date 12.06.2018 - * @version 1.0 - * @since 1.0 Initial integration + * @version 1.1 + * @since 1.0 `12.06.2018` `IneX` Method added + * @since 1.1 `29.12.2022` `IneX` Updated to use $_ENV vars for GOOGLE_API_KEY & GOOGLE_MAP_API URL * + * @uses GOOGLE_API_KEY, $_ENV * @param string $address A Postal Address string, which should be resolved to a Google Maps Object using the Geocoding API * @return array|null Returns either an Array representing the resolved Google Maps Object, or NULL if resolving or API request failed */ @@ -48,7 +50,7 @@ public function geocode($address) { if (!empty(GOOGLE_API_KEY)) { - $googleGeocodingAPIrequest = sprintf('https://maps.googleapis.com/maps/api/geocode/json?key=%s&address=%s', GOOGLE_API_KEY, urlencode($address)); + $googleGeocodingAPIrequest = $_ENV['GOOGLE_MAP_API'].'&address='.urlencode($address); if (DEVELOPMENT) error_log(sprintf('[DEBUG] <%s:%d> %s', __METHOD__, __LINE__, $googleGeocodingAPIrequest)); $request = file_get_contents($googleGeocodingAPIrequest); $response = get_object_vars(json_decode($request)); diff --git a/www/includes/telegrambot.inc.php b/www/includes/telegrambot.inc.php index 4f6c4e0..8c74331 100644 --- a/www/includes/telegrambot.inc.php +++ b/www/includes/telegrambot.inc.php @@ -16,14 +16,15 @@ * @package zorg * @subpackage Messagesystem */ + /** * Load up the Telegram Bot +* +* @include config.inc.php * @const TELEGRAM_BOT Name of the Telegram Bot to use (Attention: use same name for the bot's config file!) -* @include TELEGRAM_BOT.php Include Telegram Bot Configs */ -if (!defined('TELEGRAM_BOT') && file_exists(APIKEYS_DIR.'/telegram_bot/zthearchitect_bot.php') ) define('TELEGRAM_BOT', 'zthearchitect_bot'); -elseif (!defined('TELEGRAM_BOT')) define('TELEGRAM_BOT', 'zbarbaraharris_bot'); -if ( file_exists(APIKEYS_DIR.'/telegram_bot/'.TELEGRAM_BOT.'.php') ) require_once APIKEYS_DIR.'/telegram_bot/'.TELEGRAM_BOT.'.php' ; +require_once __DIR__.'/config.inc.php'; +if (!defined('TELEGRAM_BOT') && isset($_ENV['TELEGRAM_BOT'])) define('TELEGRAM_BOT', $_ENV['TELEGRAM_BOT']); /** * Telegram Messaging Class @@ -48,36 +49,46 @@ class Telegram * @const TELEGRAM_BOT_DISABLE_WEB_PAGE_PREVIEW Specifies whether link previews for links in the message should be enabled or disabled * @const TELEGRAM_BOT_DISABLE_NOTIFICATION Specifies whether the Bot's messages should be silent or regular notifications */ - const PARSE_MODE = 'html'; - const DISABLE_WEB_PAGE_PREVIEW = 'false'; - const DISABLE_NOTIFICATION = 'false'; + const PARSE_MODE = 'html'; // TODO Replace with $_ENV['TELEGRAM_PARSE_MODE'] + const DISABLE_WEB_PAGE_PREVIEW = 'false'; // TODO Replace with $_ENV['TELEGRAM_DISABLE_WEBPAGE_PREVIEW'] + const DISABLE_NOTIFICATION = 'false'; // TODO Replace with $_ENV['TELEGRAM_DISABLE_NOTIFICATION'] /** * Send a Message via Telegram Messenger * Schickt eine Notification an die Telegram Chats von Usern * * @author IneX - * @date 17.03.2018 - * @version 4.0 - * @since 1.0 + * @version 4.1 + * @since 1.0 `17.03.2018` `IneX` Method added + * @since 4.1 `29.12.2022` `IneX` Updated to use $_ENV for $botconfigs, instead of including keys/botname_bot.php * * @TODO implement this with TelegramBot\TelegramBotManager\BotManager? * * @link https://core.telegram.org/bots/api - * @var $botconfigs Array mit aktuellen Telegram-Bot Settings * @uses usersystem::userHasTelegram() - * @uses Telegram::formatText() - * @uses Telegram::validateData() + * @uses Telegram::formatText(), Telegram::validateData() * @param integer|string $userScope Scope to whom to send the message to: User = User-ID integer, Group = 'group' string. * @param string $messageType Type of Message to be sent (e.g. 'sendMessage', 'sendPhoto', 'sendLocation',...) * @param array $content Array mit Content welcher an die Telegram Chats geschickt wird * @global object $user Globales Class-Object mit den User-Methoden & Variablen - * @global array $botconfigs Array mit allen Telegram Bot-Configs * @return boolean Returns true or false */ public function send($userScope, $messageType, $content) { - global $user, $botconfigs; + global $user; + + /** Parse $_ENV vars into $botconfigs */ + $botconfigs = [ 'api_key' => $_ENV['TELEGRAM_BOT_API_KEY'] + ,'my_secret' => $_ENV['TELEGRAM_BOT_API_AUTH_PASSWORD'] + ,'valid_ips' => (array)$_ENV['TELEGRAM_BOT_API_IPWHITELIST'] + ,'admins' => (array)$_ENV['TELEGRAM_BOT_API_USERWHITELIST'] + ,'ssl_certificate' => $_ENV['TELEGRAM_BOT_API_SSLCERT_PATH'] + ,'chat_id' => $_ENV['TELEGRAM_BOT_API_CHAT'] + ,'logging_dirroot' => $_ENV['TELEGRAM_BOT_API_FILES_DIR'] + ,'files_dirroot' => $_ENV['TELEGRAM_BOT_API_LOG_DIR'] + ,'TELEGRAM_API_URI' => $_ENV['TELEGRAM_BOT_API_CHAT'] + ,'TELEGRAM_GROUPCHAT_ID' => $_ENV['TELEGRAM_BOT_API_CHAT'] + ]; /** First of all: make sure the Telegram Bot-Configs exist */ if (isset($botconfigs) && is_array($botconfigs)) @@ -95,7 +106,7 @@ public function send($userScope, $messageType, $content) /** GROUP: If $userScope = 'group': get the Telegram Groupchat-ID */ case 'group': if (DEVELOPMENT) error_log(sprintf('[DEBUG] <%s:%d> Checking for Group Telegram Chat-ID...', __METHOD__, __LINE__)); - $telegramChatId = TELEGRAM_GROUPCHAT_ID; + $telegramChatId = $botconfigs['TELEGRAM_GROUPCHAT_ID']; break; /** DEFAULT: stop execution */ @@ -118,7 +129,7 @@ public function send($userScope, $messageType, $content) /** Validate & compose the Parameter-Query for the API Call */ $data = $this->validateData($messageType, $parameters); $telegramAPIcallParameters = http_build_query($data); - $telegramAPIcall = TELEGRAM_API_URI . "/$messageType?" . $telegramAPIcallParameters; + $telegramAPIcall = $botconfigs['TELEGRAM_API_URI'].$messageType.'?'.$telegramAPIcallParameters; /** * Sending the Telegram message @@ -183,7 +194,7 @@ public function send($userScope, $messageType, $content) * @link https://core.telegram.org/bots/api#html-style * @see usersystem::id2user() * @param integer $userid User-ID (numeric String) dessen Telegram User mentioned werden soll - * @global object $db Globales Class-Object mit allen MySQL-Methoden + * @global object $db Globales Class-Object mit allen MySQL-Methoden * @global object $user Globales Class-Object mit den User-Methoden & Variablen * @return string Returns HTML href-link formatted as Telegram readable User-IDs mention */ @@ -297,7 +308,7 @@ public function formatText($notificationText) * * Check for valid parameters and returns Array with key:value pairs assigned * This function is related (but no depending!) to the following MySQL-table: - * - Table: messages_telegram_queue + * - Table: messages_telegram_queue * - Column: :method * - Column: :content * - Column: :content_additional @@ -317,6 +328,8 @@ public function formatText($notificationText) * @link https://core.telegram.org/bots/api#sendvoice * @link https://core.telegram.org/bots/api#sendlocation * @link https://core.telegram.org/bots/api#sendpoll + * + * @uses self::PARSE_MODE, self::DISABLE_WEB_PAGE_PREVIEW, self::DISABLE_NOTIFICATION * @param string $messageType A valid Telegram Message Type, see Telegram Bot API docu * @param array $parameters A Multidimensional Array containing the key:value parameter-pairs that should be passed to the Message Type Model * @return array|boolean Returns an Array (or "false" on error...) with key:value pairs assigned for the specified Message Type @@ -330,8 +343,8 @@ private function validateData($messageType, array $parameters) 'optional' => [ 'parse_mode', 'disable_web_page_preview', 'disable_notification', 'reply_to_message_id', 'reply_markup' ] ] ,'sendMessage' => [ - 'required' => [ 'text' ] - ] + 'required' => [ 'text' ] + ] ,'sendPhoto' => [ 'required' => [ 'photo' ], @@ -420,7 +433,7 @@ private function validateData($messageType, array $parameters) * * Example: * $data = [ - * 'chat_id' => $chatId, + * 'chat_id' => $chatId, * 'parse_mode' => $telegramParseMode, * 'text' => $notificationText, * ]; @@ -436,9 +449,9 @@ private function validateData($messageType, array $parameters) error_log(sprintf('[WARN] <%s:%d> Value "%s" is required but was not passed!', __METHOD__, __LINE__, 'chat_id')); return false; } - $data['parse_mode'] = ( isset($parameters['parse_mode']) ? $parameters['parse_mode'] : self::PARSE_MODE ); - $data['disable_web_page_preview'] = ( isset($parameters['disable_web_page_preview']) ? $parameters['disable_web_page_preview'] : self::DISABLE_WEB_PAGE_PREVIEW ); - $data['disable_notification'] = ( isset($parameters['disable_notification']) ? $parameters['disable_notification'] : self::DISABLE_NOTIFICATION ); + $data['parse_mode'] = ( isset($parameters['parse_mode']) ? $parameters['parse_mode'] : self::PARSE_MODE ); // TODO Replace with $_ENV['TELEGRAM_PARSE_MODE'] + $data['disable_web_page_preview'] = ( isset($parameters['disable_web_page_preview']) ? $parameters['disable_web_page_preview'] : self::DISABLE_WEB_PAGE_PREVIEW ); // TODO Replace with $_ENV['TELEGRAM_DISABLE_WEBPAGE_PREVIEW'] + $data['disable_notification'] = ( isset($parameters['disable_notification']) ? $parameters['disable_notification'] : self::DISABLE_NOTIFICATION ); // TODO Replace with $_ENV['TELEGRAM_DISABLE_NOTIFICATION'] if ( isset($parameters['reply_to_message_id']) ) $data['reply_to_message_id'] = $parameters['reply_to_message_id']; if ( isset($parameters['reply_markup']) ) $data['reply_markup'] = $parameters['reply_markup']; diff --git a/www/profil.php b/www/profil.php index 2b7d627..95247b1 100644 --- a/www/profil.php +++ b/www/profil.php @@ -256,9 +256,8 @@ if (fileExists(INCLUDES_DIR.'g-recaptcha-src/autoload.php')) { require_once INCLUDES_DIR.'g-recaptcha-src/autoload.php'; - $reCaptchaApiKeysFile = require_once APIKEYS_DIR.'/google/googlerecaptchaapi_key.inc.php'; - $reCaptchaApiKeys = (DEVELOPMENT ? $reCaptchaApiKeysFile['DEVELOPMENT'] : $reCaptchaApiKeysFile['PRODUCTION']); - $reCaptchaLang = 'de-CH'; // reCAPTCHA supported 40+ languages listed here: https://developers.google.com/recaptcha/docs/language + $reCaptchaApiKeys = ['key' => $_ENV['GOOGLE_RECAPTCHA_KEY'],'secret' => $_ENV['GOOGLE_RECAPTCHA_SECRET']]; + $reCaptchaLang = $_ENV['GOOGLE_RECAPTCHA_LOCALE']; try { $reCaptcha = new \ReCaptcha\ReCaptcha($reCaptchaApiKeys['secret']); } catch(Exception $e) { From c7e07e5efd2da75e154a74cf7720d45f98de49e6 Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 31 May 2023 20:59:44 +0200 Subject: [PATCH 05/13] Fixes Dependabot alerts #3 and #4 --- www/js/mobilez/jquery-1.10.1.min.js | 6 ------ www/js/mobilez/jquery-1.10.1.min.map | 1 - www/js/mobilez/jquery-1.12.4.min.js | 5 +++++ www/js/mobilez/jquery-3.2.1.min.js | 4 ---- www/js/mobilez/jquery-3.2.1.min.map | 1 - www/templates/mobilez/main.tpl | 7 ++++++- 6 files changed, 11 insertions(+), 13 deletions(-) delete mode 100644 www/js/mobilez/jquery-1.10.1.min.js delete mode 100644 www/js/mobilez/jquery-1.10.1.min.map create mode 100644 www/js/mobilez/jquery-1.12.4.min.js delete mode 100644 www/js/mobilez/jquery-3.2.1.min.js delete mode 100644 www/js/mobilez/jquery-3.2.1.min.map diff --git a/www/js/mobilez/jquery-1.10.1.min.js b/www/js/mobilez/jquery-1.10.1.min.js deleted file mode 100644 index e407e76..0000000 --- a/www/js/mobilez/jquery-1.10.1.min.js +++ /dev/null @@ -1,6 +0,0 @@ -/*! jQuery v1.10.1 | (c) 2005, 2013 jQuery Foundation, Inc. | jquery.org/license -//@ sourceMappingURL=jquery-1.10.1.min.map -*/ -(function(e,t){var n,r,i=typeof t,o=e.location,a=e.document,s=a.documentElement,l=e.jQuery,u=e.$,c={},p=[],f="1.10.1",d=p.concat,h=p.push,g=p.slice,m=p.indexOf,y=c.toString,v=c.hasOwnProperty,b=f.trim,x=function(e,t){return new x.fn.init(e,t,r)},w=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,T=/\S+/g,C=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,N=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,k=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,E=/^[\],:{}\s]*$/,S=/(?:^|:|,)(?:\s*\[)+/g,A=/\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g,j=/"[^"\\\r\n]*"|true|false|null|-?(?:\d+\.|)\d+(?:[eE][+-]?\d+|)/g,D=/^-ms-/,L=/-([\da-z])/gi,H=function(e,t){return t.toUpperCase()},q=function(e){(a.addEventListener||"load"===e.type||"complete"===a.readyState)&&(_(),x.ready())},_=function(){a.addEventListener?(a.removeEventListener("DOMContentLoaded",q,!1),e.removeEventListener("load",q,!1)):(a.detachEvent("onreadystatechange",q),e.detachEvent("onload",q))};x.fn=x.prototype={jquery:f,constructor:x,init:function(e,n,r){var i,o;if(!e)return this;if("string"==typeof e){if(i="<"===e.charAt(0)&&">"===e.charAt(e.length-1)&&e.length>=3?[null,e,null]:N.exec(e),!i||!i[1]&&n)return!n||n.jquery?(n||r).find(e):this.constructor(n).find(e);if(i[1]){if(n=n instanceof x?n[0]:n,x.merge(this,x.parseHTML(i[1],n&&n.nodeType?n.ownerDocument||n:a,!0)),k.test(i[1])&&x.isPlainObject(n))for(i in n)x.isFunction(this[i])?this[i](n[i]):this.attr(i,n[i]);return this}if(o=a.getElementById(i[2]),o&&o.parentNode){if(o.id!==i[2])return r.find(e);this.length=1,this[0]=o}return this.context=a,this.selector=e,this}return e.nodeType?(this.context=this[0]=e,this.length=1,this):x.isFunction(e)?r.ready(e):(e.selector!==t&&(this.selector=e.selector,this.context=e.context),x.makeArray(e,this))},selector:"",length:0,toArray:function(){return g.call(this)},get:function(e){return null==e?this.toArray():0>e?this[this.length+e]:this[e]},pushStack:function(e){var t=x.merge(this.constructor(),e);return t.prevObject=this,t.context=this.context,t},each:function(e,t){return x.each(this,e,t)},ready:function(e){return x.ready.promise().done(e),this},slice:function(){return this.pushStack(g.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(e){var t=this.length,n=+e+(0>e?t:0);return this.pushStack(n>=0&&t>n?[this[n]]:[])},map:function(e){return this.pushStack(x.map(this,function(t,n){return e.call(t,n,t)}))},end:function(){return this.prevObject||this.constructor(null)},push:h,sort:[].sort,splice:[].splice},x.fn.init.prototype=x.fn,x.extend=x.fn.extend=function(){var e,n,r,i,o,a,s=arguments[0]||{},l=1,u=arguments.length,c=!1;for("boolean"==typeof s&&(c=s,s=arguments[1]||{},l=2),"object"==typeof s||x.isFunction(s)||(s={}),u===l&&(s=this,--l);u>l;l++)if(null!=(o=arguments[l]))for(i in o)e=s[i],r=o[i],s!==r&&(c&&r&&(x.isPlainObject(r)||(n=x.isArray(r)))?(n?(n=!1,a=e&&x.isArray(e)?e:[]):a=e&&x.isPlainObject(e)?e:{},s[i]=x.extend(c,a,r)):r!==t&&(s[i]=r));return s},x.extend({expando:"jQuery"+(f+Math.random()).replace(/\D/g,""),noConflict:function(t){return e.$===x&&(e.$=u),t&&e.jQuery===x&&(e.jQuery=l),x},isReady:!1,readyWait:1,holdReady:function(e){e?x.readyWait++:x.ready(!0)},ready:function(e){if(e===!0?!--x.readyWait:!x.isReady){if(!a.body)return setTimeout(x.ready);x.isReady=!0,e!==!0&&--x.readyWait>0||(n.resolveWith(a,[x]),x.fn.trigger&&x(a).trigger("ready").off("ready"))}},isFunction:function(e){return"function"===x.type(e)},isArray:Array.isArray||function(e){return"array"===x.type(e)},isWindow:function(e){return null!=e&&e==e.window},isNumeric:function(e){return!isNaN(parseFloat(e))&&isFinite(e)},type:function(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?c[y.call(e)]||"object":typeof e},isPlainObject:function(e){var n;if(!e||"object"!==x.type(e)||e.nodeType||x.isWindow(e))return!1;try{if(e.constructor&&!v.call(e,"constructor")&&!v.call(e.constructor.prototype,"isPrototypeOf"))return!1}catch(r){return!1}if(x.support.ownLast)for(n in e)return v.call(e,n);for(n in e);return n===t||v.call(e,n)},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},error:function(e){throw Error(e)},parseHTML:function(e,t,n){if(!e||"string"!=typeof e)return null;"boolean"==typeof t&&(n=t,t=!1),t=t||a;var r=k.exec(e),i=!n&&[];return r?[t.createElement(r[1])]:(r=x.buildFragment([e],t,i),i&&x(i).remove(),x.merge([],r.childNodes))},parseJSON:function(n){return e.JSON&&e.JSON.parse?e.JSON.parse(n):null===n?n:"string"==typeof n&&(n=x.trim(n),n&&E.test(n.replace(A,"@").replace(j,"]").replace(S,"")))?Function("return "+n)():(x.error("Invalid JSON: "+n),t)},parseXML:function(n){var r,i;if(!n||"string"!=typeof n)return null;try{e.DOMParser?(i=new DOMParser,r=i.parseFromString(n,"text/xml")):(r=new ActiveXObject("Microsoft.XMLDOM"),r.async="false",r.loadXML(n))}catch(o){r=t}return r&&r.documentElement&&!r.getElementsByTagName("parsererror").length||x.error("Invalid XML: "+n),r},noop:function(){},globalEval:function(t){t&&x.trim(t)&&(e.execScript||function(t){e.eval.call(e,t)})(t)},camelCase:function(e){return e.replace(D,"ms-").replace(L,H)},nodeName:function(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()},each:function(e,t,n){var r,i=0,o=e.length,a=M(e);if(n){if(a){for(;o>i;i++)if(r=t.apply(e[i],n),r===!1)break}else for(i in e)if(r=t.apply(e[i],n),r===!1)break}else if(a){for(;o>i;i++)if(r=t.call(e[i],i,e[i]),r===!1)break}else for(i in e)if(r=t.call(e[i],i,e[i]),r===!1)break;return e},trim:b&&!b.call("\ufeff\u00a0")?function(e){return null==e?"":b.call(e)}:function(e){return null==e?"":(e+"").replace(C,"")},makeArray:function(e,t){var n=t||[];return null!=e&&(M(Object(e))?x.merge(n,"string"==typeof e?[e]:e):h.call(n,e)),n},inArray:function(e,t,n){var r;if(t){if(m)return m.call(t,e,n);for(r=t.length,n=n?0>n?Math.max(0,r+n):n:0;r>n;n++)if(n in t&&t[n]===e)return n}return-1},merge:function(e,n){var r=n.length,i=e.length,o=0;if("number"==typeof r)for(;r>o;o++)e[i++]=n[o];else while(n[o]!==t)e[i++]=n[o++];return e.length=i,e},grep:function(e,t,n){var r,i=[],o=0,a=e.length;for(n=!!n;a>o;o++)r=!!t(e[o],o),n!==r&&i.push(e[o]);return i},map:function(e,t,n){var r,i=0,o=e.length,a=M(e),s=[];if(a)for(;o>i;i++)r=t(e[i],i,n),null!=r&&(s[s.length]=r);else for(i in e)r=t(e[i],i,n),null!=r&&(s[s.length]=r);return d.apply([],s)},guid:1,proxy:function(e,n){var r,i,o;return"string"==typeof n&&(o=e[n],n=e,e=o),x.isFunction(e)?(r=g.call(arguments,2),i=function(){return e.apply(n||this,r.concat(g.call(arguments)))},i.guid=e.guid=e.guid||x.guid++,i):t},access:function(e,n,r,i,o,a,s){var l=0,u=e.length,c=null==r;if("object"===x.type(r)){o=!0;for(l in r)x.access(e,n,l,r[l],!0,a,s)}else if(i!==t&&(o=!0,x.isFunction(i)||(s=!0),c&&(s?(n.call(e,i),n=null):(c=n,n=function(e,t,n){return c.call(x(e),n)})),n))for(;u>l;l++)n(e[l],r,s?i:i.call(e[l],l,n(e[l],r)));return o?e:c?n.call(e):u?n(e[0],r):a},now:function(){return(new Date).getTime()},swap:function(e,t,n,r){var i,o,a={};for(o in t)a[o]=e.style[o],e.style[o]=t[o];i=n.apply(e,r||[]);for(o in t)e.style[o]=a[o];return i}}),x.ready.promise=function(t){if(!n)if(n=x.Deferred(),"complete"===a.readyState)setTimeout(x.ready);else if(a.addEventListener)a.addEventListener("DOMContentLoaded",q,!1),e.addEventListener("load",q,!1);else{a.attachEvent("onreadystatechange",q),e.attachEvent("onload",q);var r=!1;try{r=null==e.frameElement&&a.documentElement}catch(i){}r&&r.doScroll&&function o(){if(!x.isReady){try{r.doScroll("left")}catch(e){return setTimeout(o,50)}_(),x.ready()}}()}return n.promise(t)},x.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(e,t){c["[object "+t+"]"]=t.toLowerCase()});function M(e){var t=e.length,n=x.type(e);return x.isWindow(e)?!1:1===e.nodeType&&t?!0:"array"===n||"function"!==n&&(0===t||"number"==typeof t&&t>0&&t-1 in e)}r=x(a),function(e,t){var n,r,i,o,a,s,l,u,c,p,f,d,h,g,m,y,v,b="sizzle"+-new Date,w=e.document,T=0,C=0,N=lt(),k=lt(),E=lt(),S=!1,A=function(){return 0},j=typeof t,D=1<<31,L={}.hasOwnProperty,H=[],q=H.pop,_=H.push,M=H.push,O=H.slice,F=H.indexOf||function(e){var t=0,n=this.length;for(;n>t;t++)if(this[t]===e)return t;return-1},B="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",P="[\\x20\\t\\r\\n\\f]",R="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",W=R.replace("w","w#"),$="\\["+P+"*("+R+")"+P+"*(?:([*^$|!~]?=)"+P+"*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+W+")|)|)"+P+"*\\]",I=":("+R+")(?:\\(((['\"])((?:\\\\.|[^\\\\])*?)\\3|((?:\\\\.|[^\\\\()[\\]]|"+$.replace(3,8)+")*)|.*)\\)|)",z=RegExp("^"+P+"+|((?:^|[^\\\\])(?:\\\\.)*)"+P+"+$","g"),X=RegExp("^"+P+"*,"+P+"*"),U=RegExp("^"+P+"*([>+~]|"+P+")"+P+"*"),V=RegExp(P+"*[+~]"),Y=RegExp("="+P+"*([^\\]'\"]*)"+P+"*\\]","g"),J=RegExp(I),G=RegExp("^"+W+"$"),Q={ID:RegExp("^#("+R+")"),CLASS:RegExp("^\\.("+R+")"),TAG:RegExp("^("+R.replace("w","w*")+")"),ATTR:RegExp("^"+$),PSEUDO:RegExp("^"+I),CHILD:RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+P+"*(even|odd|(([+-]|)(\\d*)n|)"+P+"*(?:([+-]|)"+P+"*(\\d+)|))"+P+"*\\)|)","i"),bool:RegExp("^(?:"+B+")$","i"),needsContext:RegExp("^"+P+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+P+"*((?:-\\d)?\\d*)"+P+"*\\)|)(?=[^-]|$)","i")},K=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,et=/^(?:input|select|textarea|button)$/i,tt=/^h\d$/i,nt=/'|\\/g,rt=RegExp("\\\\([\\da-f]{1,6}"+P+"?|("+P+")|.)","ig"),it=function(e,t,n){var r="0x"+t-65536;return r!==r||n?t:0>r?String.fromCharCode(r+65536):String.fromCharCode(55296|r>>10,56320|1023&r)};try{M.apply(H=O.call(w.childNodes),w.childNodes),H[w.childNodes.length].nodeType}catch(ot){M={apply:H.length?function(e,t){_.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function at(e,t,n,i){var o,a,s,l,u,c,d,m,y,x;if((t?t.ownerDocument||t:w)!==f&&p(t),t=t||f,n=n||[],!e||"string"!=typeof e)return n;if(1!==(l=t.nodeType)&&9!==l)return[];if(h&&!i){if(o=Z.exec(e))if(s=o[1]){if(9===l){if(a=t.getElementById(s),!a||!a.parentNode)return n;if(a.id===s)return n.push(a),n}else if(t.ownerDocument&&(a=t.ownerDocument.getElementById(s))&&v(t,a)&&a.id===s)return n.push(a),n}else{if(o[2])return M.apply(n,t.getElementsByTagName(e)),n;if((s=o[3])&&r.getElementsByClassName&&t.getElementsByClassName)return M.apply(n,t.getElementsByClassName(s)),n}if(r.qsa&&(!g||!g.test(e))){if(m=d=b,y=t,x=9===l&&e,1===l&&"object"!==t.nodeName.toLowerCase()){c=bt(e),(d=t.getAttribute("id"))?m=d.replace(nt,"\\$&"):t.setAttribute("id",m),m="[id='"+m+"'] ",u=c.length;while(u--)c[u]=m+xt(c[u]);y=V.test(e)&&t.parentNode||t,x=c.join(",")}if(x)try{return M.apply(n,y.querySelectorAll(x)),n}catch(T){}finally{d||t.removeAttribute("id")}}}return At(e.replace(z,"$1"),t,n,i)}function st(e){return K.test(e+"")}function lt(){var e=[];function t(n,r){return e.push(n+=" ")>o.cacheLength&&delete t[e.shift()],t[n]=r}return t}function ut(e){return e[b]=!0,e}function ct(e){var t=f.createElement("div");try{return!!e(t)}catch(n){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function pt(e,t,n){e=e.split("|");var r,i=e.length,a=n?null:t;while(i--)(r=o.attrHandle[e[i]])&&r!==t||(o.attrHandle[e[i]]=a)}function ft(e,t){var n=e.getAttributeNode(t);return n&&n.specified?n.value:e[t]===!0?t.toLowerCase():null}function dt(e,t){return e.getAttribute(t,"type"===t.toLowerCase()?1:2)}function ht(e){return"input"===e.nodeName.toLowerCase()?e.defaultValue:t}function gt(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&(~t.sourceIndex||D)-(~e.sourceIndex||D);if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function mt(e){return function(t){var n=t.nodeName.toLowerCase();return"input"===n&&t.type===e}}function yt(e){return function(t){var n=t.nodeName.toLowerCase();return("input"===n||"button"===n)&&t.type===e}}function vt(e){return ut(function(t){return t=+t,ut(function(n,r){var i,o=e([],n.length,t),a=o.length;while(a--)n[i=o[a]]&&(n[i]=!(r[i]=n[i]))})})}s=at.isXML=function(e){var t=e&&(e.ownerDocument||e).documentElement;return t?"HTML"!==t.nodeName:!1},r=at.support={},p=at.setDocument=function(e){var n=e?e.ownerDocument||e:w,i=n.parentWindow;return n!==f&&9===n.nodeType&&n.documentElement?(f=n,d=n.documentElement,h=!s(n),i&&i.frameElement&&i.attachEvent("onbeforeunload",function(){p()}),r.attributes=ct(function(e){return e.innerHTML="",pt("type|href|height|width",dt,"#"===e.firstChild.getAttribute("href")),pt(B,ft,null==e.getAttribute("disabled")),e.className="i",!e.getAttribute("className")}),r.input=ct(function(e){return e.innerHTML="",e.firstChild.setAttribute("value",""),""===e.firstChild.getAttribute("value")}),pt("value",ht,r.attributes&&r.input),r.getElementsByTagName=ct(function(e){return e.appendChild(n.createComment("")),!e.getElementsByTagName("*").length}),r.getElementsByClassName=ct(function(e){return e.innerHTML="
",e.firstChild.className="i",2===e.getElementsByClassName("i").length}),r.getById=ct(function(e){return d.appendChild(e).id=b,!n.getElementsByName||!n.getElementsByName(b).length}),r.getById?(o.find.ID=function(e,t){if(typeof t.getElementById!==j&&h){var n=t.getElementById(e);return n&&n.parentNode?[n]:[]}},o.filter.ID=function(e){var t=e.replace(rt,it);return function(e){return e.getAttribute("id")===t}}):(delete o.find.ID,o.filter.ID=function(e){var t=e.replace(rt,it);return function(e){var n=typeof e.getAttributeNode!==j&&e.getAttributeNode("id");return n&&n.value===t}}),o.find.TAG=r.getElementsByTagName?function(e,n){return typeof n.getElementsByTagName!==j?n.getElementsByTagName(e):t}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},o.find.CLASS=r.getElementsByClassName&&function(e,n){return typeof n.getElementsByClassName!==j&&h?n.getElementsByClassName(e):t},m=[],g=[],(r.qsa=st(n.querySelectorAll))&&(ct(function(e){e.innerHTML="",e.querySelectorAll("[selected]").length||g.push("\\["+P+"*(?:value|"+B+")"),e.querySelectorAll(":checked").length||g.push(":checked")}),ct(function(e){var t=n.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("t",""),e.querySelectorAll("[t^='']").length&&g.push("[*^$]="+P+"*(?:''|\"\")"),e.querySelectorAll(":enabled").length||g.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),g.push(",.*:")})),(r.matchesSelector=st(y=d.webkitMatchesSelector||d.mozMatchesSelector||d.oMatchesSelector||d.msMatchesSelector))&&ct(function(e){r.disconnectedMatch=y.call(e,"div"),y.call(e,"[s!='']:x"),m.push("!=",I)}),g=g.length&&RegExp(g.join("|")),m=m.length&&RegExp(m.join("|")),v=st(d.contains)||d.compareDocumentPosition?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},r.sortDetached=ct(function(e){return 1&e.compareDocumentPosition(n.createElement("div"))}),A=d.compareDocumentPosition?function(e,t){if(e===t)return S=!0,0;var i=t.compareDocumentPosition&&e.compareDocumentPosition&&e.compareDocumentPosition(t);return i?1&i||!r.sortDetached&&t.compareDocumentPosition(e)===i?e===n||v(w,e)?-1:t===n||v(w,t)?1:c?F.call(c,e)-F.call(c,t):0:4&i?-1:1:e.compareDocumentPosition?-1:1}:function(e,t){var r,i=0,o=e.parentNode,a=t.parentNode,s=[e],l=[t];if(e===t)return S=!0,0;if(!o||!a)return e===n?-1:t===n?1:o?-1:a?1:c?F.call(c,e)-F.call(c,t):0;if(o===a)return gt(e,t);r=e;while(r=r.parentNode)s.unshift(r);r=t;while(r=r.parentNode)l.unshift(r);while(s[i]===l[i])i++;return i?gt(s[i],l[i]):s[i]===w?-1:l[i]===w?1:0},n):f},at.matches=function(e,t){return at(e,null,null,t)},at.matchesSelector=function(e,t){if((e.ownerDocument||e)!==f&&p(e),t=t.replace(Y,"='$1']"),!(!r.matchesSelector||!h||m&&m.test(t)||g&&g.test(t)))try{var n=y.call(e,t);if(n||r.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(i){}return at(t,f,null,[e]).length>0},at.contains=function(e,t){return(e.ownerDocument||e)!==f&&p(e),v(e,t)},at.attr=function(e,n){(e.ownerDocument||e)!==f&&p(e);var i=o.attrHandle[n.toLowerCase()],a=i&&L.call(o.attrHandle,n.toLowerCase())?i(e,n,!h):t;return a===t?r.attributes||!h?e.getAttribute(n):(a=e.getAttributeNode(n))&&a.specified?a.value:null:a},at.error=function(e){throw Error("Syntax error, unrecognized expression: "+e)},at.uniqueSort=function(e){var t,n=[],i=0,o=0;if(S=!r.detectDuplicates,c=!r.sortStable&&e.slice(0),e.sort(A),S){while(t=e[o++])t===e[o]&&(i=n.push(o));while(i--)e.splice(n[i],1)}return e},a=at.getText=function(e){var t,n="",r=0,i=e.nodeType;if(i){if(1===i||9===i||11===i){if("string"==typeof e.textContent)return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=a(e)}else if(3===i||4===i)return e.nodeValue}else for(;t=e[r];r++)n+=a(t);return n},o=at.selectors={cacheLength:50,createPseudo:ut,match:Q,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(rt,it),e[3]=(e[4]||e[5]||"").replace(rt,it),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||at.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&at.error(e[0]),e},PSEUDO:function(e){var n,r=!e[5]&&e[2];return Q.CHILD.test(e[0])?null:(e[3]&&e[4]!==t?e[2]=e[4]:r&&J.test(r)&&(n=bt(r,!0))&&(n=r.indexOf(")",r.length-n)-r.length)&&(e[0]=e[0].slice(0,n),e[2]=r.slice(0,n)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(rt,it).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=N[e+" "];return t||(t=RegExp("(^|"+P+")"+e+"("+P+"|$)"))&&N(e,function(e){return t.test("string"==typeof e.className&&e.className||typeof e.getAttribute!==j&&e.getAttribute("class")||"")})},ATTR:function(e,t,n){return function(r){var i=at.attr(r,e);return null==i?"!="===t:t?(i+="","="===t?i===n:"!="===t?i!==n:"^="===t?n&&0===i.indexOf(n):"*="===t?n&&i.indexOf(n)>-1:"$="===t?n&&i.slice(-n.length)===n:"~="===t?(" "+i+" ").indexOf(n)>-1:"|="===t?i===n||i.slice(0,n.length+1)===n+"-":!1):!0}},CHILD:function(e,t,n,r,i){var o="nth"!==e.slice(0,3),a="last"!==e.slice(-4),s="of-type"===t;return 1===r&&0===i?function(e){return!!e.parentNode}:function(t,n,l){var u,c,p,f,d,h,g=o!==a?"nextSibling":"previousSibling",m=t.parentNode,y=s&&t.nodeName.toLowerCase(),v=!l&&!s;if(m){if(o){while(g){p=t;while(p=p[g])if(s?p.nodeName.toLowerCase()===y:1===p.nodeType)return!1;h=g="only"===e&&!h&&"nextSibling"}return!0}if(h=[a?m.firstChild:m.lastChild],a&&v){c=m[b]||(m[b]={}),u=c[e]||[],d=u[0]===T&&u[1],f=u[0]===T&&u[2],p=d&&m.childNodes[d];while(p=++d&&p&&p[g]||(f=d=0)||h.pop())if(1===p.nodeType&&++f&&p===t){c[e]=[T,d,f];break}}else if(v&&(u=(t[b]||(t[b]={}))[e])&&u[0]===T)f=u[1];else while(p=++d&&p&&p[g]||(f=d=0)||h.pop())if((s?p.nodeName.toLowerCase()===y:1===p.nodeType)&&++f&&(v&&((p[b]||(p[b]={}))[e]=[T,f]),p===t))break;return f-=i,f===r||0===f%r&&f/r>=0}}},PSEUDO:function(e,t){var n,r=o.pseudos[e]||o.setFilters[e.toLowerCase()]||at.error("unsupported pseudo: "+e);return r[b]?r(t):r.length>1?(n=[e,e,"",t],o.setFilters.hasOwnProperty(e.toLowerCase())?ut(function(e,n){var i,o=r(e,t),a=o.length;while(a--)i=F.call(e,o[a]),e[i]=!(n[i]=o[a])}):function(e){return r(e,0,n)}):r}},pseudos:{not:ut(function(e){var t=[],n=[],r=l(e.replace(z,"$1"));return r[b]?ut(function(e,t,n,i){var o,a=r(e,null,i,[]),s=e.length;while(s--)(o=a[s])&&(e[s]=!(t[s]=o))}):function(e,i,o){return t[0]=e,r(t,null,o,n),!n.pop()}}),has:ut(function(e){return function(t){return at(e,t).length>0}}),contains:ut(function(e){return function(t){return(t.textContent||t.innerText||a(t)).indexOf(e)>-1}}),lang:ut(function(e){return G.test(e||"")||at.error("unsupported lang: "+e),e=e.replace(rt,it).toLowerCase(),function(t){var n;do if(n=h?t.lang:t.getAttribute("xml:lang")||t.getAttribute("lang"))return n=n.toLowerCase(),n===e||0===n.indexOf(e+"-");while((t=t.parentNode)&&1===t.nodeType);return!1}}),target:function(t){var n=e.location&&e.location.hash;return n&&n.slice(1)===t.id},root:function(e){return e===d},focus:function(e){return e===f.activeElement&&(!f.hasFocus||f.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},enabled:function(e){return e.disabled===!1},disabled:function(e){return e.disabled===!0},checked:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&!!e.checked||"option"===t&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,e.selected===!0},empty:function(e){for(e=e.firstChild;e;e=e.nextSibling)if(e.nodeName>"@"||3===e.nodeType||4===e.nodeType)return!1;return!0},parent:function(e){return!o.pseudos.empty(e)},header:function(e){return tt.test(e.nodeName)},input:function(e){return et.test(e.nodeName)},button:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&"button"===e.type||"button"===t},text:function(e){var t;return"input"===e.nodeName.toLowerCase()&&"text"===e.type&&(null==(t=e.getAttribute("type"))||t.toLowerCase()===e.type)},first:vt(function(){return[0]}),last:vt(function(e,t){return[t-1]}),eq:vt(function(e,t,n){return[0>n?n+t:n]}),even:vt(function(e,t){var n=0;for(;t>n;n+=2)e.push(n);return e}),odd:vt(function(e,t){var n=1;for(;t>n;n+=2)e.push(n);return e}),lt:vt(function(e,t,n){var r=0>n?n+t:n;for(;--r>=0;)e.push(r);return e}),gt:vt(function(e,t,n){var r=0>n?n+t:n;for(;t>++r;)e.push(r);return e})}};for(n in{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})o.pseudos[n]=mt(n);for(n in{submit:!0,reset:!0})o.pseudos[n]=yt(n);function bt(e,t){var n,r,i,a,s,l,u,c=k[e+" "];if(c)return t?0:c.slice(0);s=e,l=[],u=o.preFilter;while(s){(!n||(r=X.exec(s)))&&(r&&(s=s.slice(r[0].length)||s),l.push(i=[])),n=!1,(r=U.exec(s))&&(n=r.shift(),i.push({value:n,type:r[0].replace(z," ")}),s=s.slice(n.length));for(a in o.filter)!(r=Q[a].exec(s))||u[a]&&!(r=u[a](r))||(n=r.shift(),i.push({value:n,type:a,matches:r}),s=s.slice(n.length));if(!n)break}return t?s.length:s?at.error(e):k(e,l).slice(0)}function xt(e){var t=0,n=e.length,r="";for(;n>t;t++)r+=e[t].value;return r}function wt(e,t,n){var r=t.dir,o=n&&"parentNode"===r,a=C++;return t.first?function(t,n,i){while(t=t[r])if(1===t.nodeType||o)return e(t,n,i)}:function(t,n,s){var l,u,c,p=T+" "+a;if(s){while(t=t[r])if((1===t.nodeType||o)&&e(t,n,s))return!0}else while(t=t[r])if(1===t.nodeType||o)if(c=t[b]||(t[b]={}),(u=c[r])&&u[0]===p){if((l=u[1])===!0||l===i)return l===!0}else if(u=c[r]=[p],u[1]=e(t,n,s)||i,u[1]===!0)return!0}}function Tt(e){return e.length>1?function(t,n,r){var i=e.length;while(i--)if(!e[i](t,n,r))return!1;return!0}:e[0]}function Ct(e,t,n,r,i){var o,a=[],s=0,l=e.length,u=null!=t;for(;l>s;s++)(o=e[s])&&(!n||n(o,r,i))&&(a.push(o),u&&t.push(s));return a}function Nt(e,t,n,r,i,o){return r&&!r[b]&&(r=Nt(r)),i&&!i[b]&&(i=Nt(i,o)),ut(function(o,a,s,l){var u,c,p,f=[],d=[],h=a.length,g=o||St(t||"*",s.nodeType?[s]:s,[]),m=!e||!o&&t?g:Ct(g,f,e,s,l),y=n?i||(o?e:h||r)?[]:a:m;if(n&&n(m,y,s,l),r){u=Ct(y,d),r(u,[],s,l),c=u.length;while(c--)(p=u[c])&&(y[d[c]]=!(m[d[c]]=p))}if(o){if(i||e){if(i){u=[],c=y.length;while(c--)(p=y[c])&&u.push(m[c]=p);i(null,y=[],u,l)}c=y.length;while(c--)(p=y[c])&&(u=i?F.call(o,p):f[c])>-1&&(o[u]=!(a[u]=p))}}else y=Ct(y===a?y.splice(h,y.length):y),i?i(null,a,y,l):M.apply(a,y)})}function kt(e){var t,n,r,i=e.length,a=o.relative[e[0].type],s=a||o.relative[" "],l=a?1:0,c=wt(function(e){return e===t},s,!0),p=wt(function(e){return F.call(t,e)>-1},s,!0),f=[function(e,n,r){return!a&&(r||n!==u)||((t=n).nodeType?c(e,n,r):p(e,n,r))}];for(;i>l;l++)if(n=o.relative[e[l].type])f=[wt(Tt(f),n)];else{if(n=o.filter[e[l].type].apply(null,e[l].matches),n[b]){for(r=++l;i>r;r++)if(o.relative[e[r].type])break;return Nt(l>1&&Tt(f),l>1&&xt(e.slice(0,l-1).concat({value:" "===e[l-2].type?"*":""})).replace(z,"$1"),n,r>l&&kt(e.slice(l,r)),i>r&&kt(e=e.slice(r)),i>r&&xt(e))}f.push(n)}return Tt(f)}function Et(e,t){var n=0,r=t.length>0,a=e.length>0,s=function(s,l,c,p,d){var h,g,m,y=[],v=0,b="0",x=s&&[],w=null!=d,C=u,N=s||a&&o.find.TAG("*",d&&l.parentNode||l),k=T+=null==C?1:Math.random()||.1;for(w&&(u=l!==f&&l,i=n);null!=(h=N[b]);b++){if(a&&h){g=0;while(m=e[g++])if(m(h,l,c)){p.push(h);break}w&&(T=k,i=++n)}r&&((h=!m&&h)&&v--,s&&x.push(h))}if(v+=b,r&&b!==v){g=0;while(m=t[g++])m(x,y,l,c);if(s){if(v>0)while(b--)x[b]||y[b]||(y[b]=q.call(p));y=Ct(y)}M.apply(p,y),w&&!s&&y.length>0&&v+t.length>1&&at.uniqueSort(p)}return w&&(T=k,u=C),x};return r?ut(s):s}l=at.compile=function(e,t){var n,r=[],i=[],o=E[e+" "];if(!o){t||(t=bt(e)),n=t.length;while(n--)o=kt(t[n]),o[b]?r.push(o):i.push(o);o=E(e,Et(i,r))}return o};function St(e,t,n){var r=0,i=t.length;for(;i>r;r++)at(e,t[r],n);return n}function At(e,t,n,i){var a,s,u,c,p,f=bt(e);if(!i&&1===f.length){if(s=f[0]=f[0].slice(0),s.length>2&&"ID"===(u=s[0]).type&&r.getById&&9===t.nodeType&&h&&o.relative[s[1].type]){if(t=(o.find.ID(u.matches[0].replace(rt,it),t)||[])[0],!t)return n;e=e.slice(s.shift().value.length)}a=Q.needsContext.test(e)?0:s.length;while(a--){if(u=s[a],o.relative[c=u.type])break;if((p=o.find[c])&&(i=p(u.matches[0].replace(rt,it),V.test(s[0].type)&&t.parentNode||t))){if(s.splice(a,1),e=i.length&&xt(s),!e)return M.apply(n,i),n;break}}}return l(e,f)(i,t,!h,n,V.test(e)),n}o.pseudos.nth=o.pseudos.eq;function jt(){}jt.prototype=o.filters=o.pseudos,o.setFilters=new jt,r.sortStable=b.split("").sort(A).join("")===b,p(),[0,0].sort(A),r.detectDuplicates=S,x.find=at,x.expr=at.selectors,x.expr[":"]=x.expr.pseudos,x.unique=at.uniqueSort,x.text=at.getText,x.isXMLDoc=at.isXML,x.contains=at.contains}(e);var O={};function F(e){var t=O[e]={};return x.each(e.match(T)||[],function(e,n){t[n]=!0}),t}x.Callbacks=function(e){e="string"==typeof e?O[e]||F(e):x.extend({},e);var n,r,i,o,a,s,l=[],u=!e.once&&[],c=function(t){for(r=e.memory&&t,i=!0,a=s||0,s=0,o=l.length,n=!0;l&&o>a;a++)if(l[a].apply(t[0],t[1])===!1&&e.stopOnFalse){r=!1;break}n=!1,l&&(u?u.length&&c(u.shift()):r?l=[]:p.disable())},p={add:function(){if(l){var t=l.length;(function i(t){x.each(t,function(t,n){var r=x.type(n);"function"===r?e.unique&&p.has(n)||l.push(n):n&&n.length&&"string"!==r&&i(n)})})(arguments),n?o=l.length:r&&(s=t,c(r))}return this},remove:function(){return l&&x.each(arguments,function(e,t){var r;while((r=x.inArray(t,l,r))>-1)l.splice(r,1),n&&(o>=r&&o--,a>=r&&a--)}),this},has:function(e){return e?x.inArray(e,l)>-1:!(!l||!l.length)},empty:function(){return l=[],o=0,this},disable:function(){return l=u=r=t,this},disabled:function(){return!l},lock:function(){return u=t,r||p.disable(),this},locked:function(){return!u},fireWith:function(e,t){return t=t||[],t=[e,t.slice?t.slice():t],!l||i&&!u||(n?u.push(t):c(t)),this},fire:function(){return p.fireWith(this,arguments),this},fired:function(){return!!i}};return p},x.extend({Deferred:function(e){var t=[["resolve","done",x.Callbacks("once memory"),"resolved"],["reject","fail",x.Callbacks("once memory"),"rejected"],["notify","progress",x.Callbacks("memory")]],n="pending",r={state:function(){return n},always:function(){return i.done(arguments).fail(arguments),this},then:function(){var e=arguments;return x.Deferred(function(n){x.each(t,function(t,o){var a=o[0],s=x.isFunction(e[t])&&e[t];i[o[1]](function(){var e=s&&s.apply(this,arguments);e&&x.isFunction(e.promise)?e.promise().done(n.resolve).fail(n.reject).progress(n.notify):n[a+"With"](this===r?n.promise():this,s?[e]:arguments)})}),e=null}).promise()},promise:function(e){return null!=e?x.extend(e,r):r}},i={};return r.pipe=r.then,x.each(t,function(e,o){var a=o[2],s=o[3];r[o[1]]=a.add,s&&a.add(function(){n=s},t[1^e][2].disable,t[2][2].lock),i[o[0]]=function(){return i[o[0]+"With"](this===i?r:this,arguments),this},i[o[0]+"With"]=a.fireWith}),r.promise(i),e&&e.call(i,i),i},when:function(e){var t=0,n=g.call(arguments),r=n.length,i=1!==r||e&&x.isFunction(e.promise)?r:0,o=1===i?e:x.Deferred(),a=function(e,t,n){return function(r){t[e]=this,n[e]=arguments.length>1?g.call(arguments):r,n===s?o.notifyWith(t,n):--i||o.resolveWith(t,n)}},s,l,u;if(r>1)for(s=Array(r),l=Array(r),u=Array(r);r>t;t++)n[t]&&x.isFunction(n[t].promise)?n[t].promise().done(a(t,u,n)).fail(o.reject).progress(a(t,l,s)):--i;return i||o.resolveWith(u,n),o.promise()}}),x.support=function(t){var n,r,o,s,l,u,c,p,f,d=a.createElement("div");if(d.setAttribute("className","t"),d.innerHTML="
a",n=d.getElementsByTagName("*")||[],r=d.getElementsByTagName("a")[0],!r||!r.style||!n.length)return t;s=a.createElement("select"),u=s.appendChild(a.createElement("option")),o=d.getElementsByTagName("input")[0],r.style.cssText="top:1px;float:left;opacity:.5",t.getSetAttribute="t"!==d.className,t.leadingWhitespace=3===d.firstChild.nodeType,t.tbody=!d.getElementsByTagName("tbody").length,t.htmlSerialize=!!d.getElementsByTagName("link").length,t.style=/top/.test(r.getAttribute("style")),t.hrefNormalized="/a"===r.getAttribute("href"),t.opacity=/^0.5/.test(r.style.opacity),t.cssFloat=!!r.style.cssFloat,t.checkOn=!!o.value,t.optSelected=u.selected,t.enctype=!!a.createElement("form").enctype,t.html5Clone="<:nav>"!==a.createElement("nav").cloneNode(!0).outerHTML,t.inlineBlockNeedsLayout=!1,t.shrinkWrapBlocks=!1,t.pixelPosition=!1,t.deleteExpando=!0,t.noCloneEvent=!0,t.reliableMarginRight=!0,t.boxSizingReliable=!0,o.checked=!0,t.noCloneChecked=o.cloneNode(!0).checked,s.disabled=!0,t.optDisabled=!u.disabled;try{delete d.test}catch(h){t.deleteExpando=!1}o=a.createElement("input"),o.setAttribute("value",""),t.input=""===o.getAttribute("value"),o.value="t",o.setAttribute("type","radio"),t.radioValue="t"===o.value,o.setAttribute("checked","t"),o.setAttribute("name","t"),l=a.createDocumentFragment(),l.appendChild(o),t.appendChecked=o.checked,t.checkClone=l.cloneNode(!0).cloneNode(!0).lastChild.checked,d.attachEvent&&(d.attachEvent("onclick",function(){t.noCloneEvent=!1}),d.cloneNode(!0).click());for(f in{submit:!0,change:!0,focusin:!0})d.setAttribute(c="on"+f,"t"),t[f+"Bubbles"]=c in e||d.attributes[c].expando===!1;d.style.backgroundClip="content-box",d.cloneNode(!0).style.backgroundClip="",t.clearCloneStyle="content-box"===d.style.backgroundClip;for(f in x(t))break;return t.ownLast="0"!==f,x(function(){var n,r,o,s="padding:0;margin:0;border:0;display:block;box-sizing:content-box;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;",l=a.getElementsByTagName("body")[0];l&&(n=a.createElement("div"),n.style.cssText="border:0;width:0;height:0;position:absolute;top:0;left:-9999px;margin-top:1px",l.appendChild(n).appendChild(d),d.innerHTML="
t
",o=d.getElementsByTagName("td"),o[0].style.cssText="padding:0;margin:0;border:0;display:none",p=0===o[0].offsetHeight,o[0].style.display="",o[1].style.display="none",t.reliableHiddenOffsets=p&&0===o[0].offsetHeight,d.innerHTML="",d.style.cssText="box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;",x.swap(l,null!=l.style.zoom?{zoom:1}:{},function(){t.boxSizing=4===d.offsetWidth}),e.getComputedStyle&&(t.pixelPosition="1%"!==(e.getComputedStyle(d,null)||{}).top,t.boxSizingReliable="4px"===(e.getComputedStyle(d,null)||{width:"4px"}).width,r=d.appendChild(a.createElement("div")),r.style.cssText=d.style.cssText=s,r.style.marginRight=r.style.width="0",d.style.width="1px",t.reliableMarginRight=!parseFloat((e.getComputedStyle(r,null)||{}).marginRight)),typeof d.style.zoom!==i&&(d.innerHTML="",d.style.cssText=s+"width:1px;padding:1px;display:inline;zoom:1",t.inlineBlockNeedsLayout=3===d.offsetWidth,d.style.display="block",d.innerHTML="
",d.firstChild.style.width="5px",t.shrinkWrapBlocks=3!==d.offsetWidth,t.inlineBlockNeedsLayout&&(l.style.zoom=1)),l.removeChild(n),n=d=o=r=null) -}),n=s=l=u=r=o=null,t}({});var B=/(?:\{[\s\S]*\}|\[[\s\S]*\])$/,P=/([A-Z])/g;function R(e,n,r,i){if(x.acceptData(e)){var o,a,s=x.expando,l=e.nodeType,u=l?x.cache:e,c=l?e[s]:e[s]&&s;if(c&&u[c]&&(i||u[c].data)||r!==t||"string"!=typeof n)return c||(c=l?e[s]=p.pop()||x.guid++:s),u[c]||(u[c]=l?{}:{toJSON:x.noop}),("object"==typeof n||"function"==typeof n)&&(i?u[c]=x.extend(u[c],n):u[c].data=x.extend(u[c].data,n)),a=u[c],i||(a.data||(a.data={}),a=a.data),r!==t&&(a[x.camelCase(n)]=r),"string"==typeof n?(o=a[n],null==o&&(o=a[x.camelCase(n)])):o=a,o}}function W(e,t,n){if(x.acceptData(e)){var r,i,o=e.nodeType,a=o?x.cache:e,s=o?e[x.expando]:x.expando;if(a[s]){if(t&&(r=n?a[s]:a[s].data)){x.isArray(t)?t=t.concat(x.map(t,x.camelCase)):t in r?t=[t]:(t=x.camelCase(t),t=t in r?[t]:t.split(" ")),i=t.length;while(i--)delete r[t[i]];if(n?!I(r):!x.isEmptyObject(r))return}(n||(delete a[s].data,I(a[s])))&&(o?x.cleanData([e],!0):x.support.deleteExpando||a!=a.window?delete a[s]:a[s]=null)}}}x.extend({cache:{},noData:{applet:!0,embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"},hasData:function(e){return e=e.nodeType?x.cache[e[x.expando]]:e[x.expando],!!e&&!I(e)},data:function(e,t,n){return R(e,t,n)},removeData:function(e,t){return W(e,t)},_data:function(e,t,n){return R(e,t,n,!0)},_removeData:function(e,t){return W(e,t,!0)},acceptData:function(e){if(e.nodeType&&1!==e.nodeType&&9!==e.nodeType)return!1;var t=e.nodeName&&x.noData[e.nodeName.toLowerCase()];return!t||t!==!0&&e.getAttribute("classid")===t}}),x.fn.extend({data:function(e,n){var r,i,o=null,a=0,s=this[0];if(e===t){if(this.length&&(o=x.data(s),1===s.nodeType&&!x._data(s,"parsedAttrs"))){for(r=s.attributes;r.length>a;a++)i=r[a].name,0===i.indexOf("data-")&&(i=x.camelCase(i.slice(5)),$(s,i,o[i]));x._data(s,"parsedAttrs",!0)}return o}return"object"==typeof e?this.each(function(){x.data(this,e)}):arguments.length>1?this.each(function(){x.data(this,e,n)}):s?$(s,e,x.data(s,e)):null},removeData:function(e){return this.each(function(){x.removeData(this,e)})}});function $(e,n,r){if(r===t&&1===e.nodeType){var i="data-"+n.replace(P,"-$1").toLowerCase();if(r=e.getAttribute(i),"string"==typeof r){try{r="true"===r?!0:"false"===r?!1:"null"===r?null:+r+""===r?+r:B.test(r)?x.parseJSON(r):r}catch(o){}x.data(e,n,r)}else r=t}return r}function I(e){var t;for(t in e)if(("data"!==t||!x.isEmptyObject(e[t]))&&"toJSON"!==t)return!1;return!0}x.extend({queue:function(e,n,r){var i;return e?(n=(n||"fx")+"queue",i=x._data(e,n),r&&(!i||x.isArray(r)?i=x._data(e,n,x.makeArray(r)):i.push(r)),i||[]):t},dequeue:function(e,t){t=t||"fx";var n=x.queue(e,t),r=n.length,i=n.shift(),o=x._queueHooks(e,t),a=function(){x.dequeue(e,t)};"inprogress"===i&&(i=n.shift(),r--),i&&("fx"===t&&n.unshift("inprogress"),delete o.stop,i.call(e,a,o)),!r&&o&&o.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return x._data(e,n)||x._data(e,n,{empty:x.Callbacks("once memory").add(function(){x._removeData(e,t+"queue"),x._removeData(e,n)})})}}),x.fn.extend({queue:function(e,n){var r=2;return"string"!=typeof e&&(n=e,e="fx",r--),r>arguments.length?x.queue(this[0],e):n===t?this:this.each(function(){var t=x.queue(this,e,n);x._queueHooks(this,e),"fx"===e&&"inprogress"!==t[0]&&x.dequeue(this,e)})},dequeue:function(e){return this.each(function(){x.dequeue(this,e)})},delay:function(e,t){return e=x.fx?x.fx.speeds[e]||e:e,t=t||"fx",this.queue(t,function(t,n){var r=setTimeout(t,e);n.stop=function(){clearTimeout(r)}})},clearQueue:function(e){return this.queue(e||"fx",[])},promise:function(e,n){var r,i=1,o=x.Deferred(),a=this,s=this.length,l=function(){--i||o.resolveWith(a,[a])};"string"!=typeof e&&(n=e,e=t),e=e||"fx";while(s--)r=x._data(a[s],e+"queueHooks"),r&&r.empty&&(i++,r.empty.add(l));return l(),o.promise(n)}});var z,X,U=/[\t\r\n\f]/g,V=/\r/g,Y=/^(?:input|select|textarea|button|object)$/i,J=/^(?:a|area)$/i,G=/^(?:checked|selected)$/i,Q=x.support.getSetAttribute,K=x.support.input;x.fn.extend({attr:function(e,t){return x.access(this,x.attr,e,t,arguments.length>1)},removeAttr:function(e){return this.each(function(){x.removeAttr(this,e)})},prop:function(e,t){return x.access(this,x.prop,e,t,arguments.length>1)},removeProp:function(e){return e=x.propFix[e]||e,this.each(function(){try{this[e]=t,delete this[e]}catch(n){}})},addClass:function(e){var t,n,r,i,o,a=0,s=this.length,l="string"==typeof e&&e;if(x.isFunction(e))return this.each(function(t){x(this).addClass(e.call(this,t,this.className))});if(l)for(t=(e||"").match(T)||[];s>a;a++)if(n=this[a],r=1===n.nodeType&&(n.className?(" "+n.className+" ").replace(U," "):" ")){o=0;while(i=t[o++])0>r.indexOf(" "+i+" ")&&(r+=i+" ");n.className=x.trim(r)}return this},removeClass:function(e){var t,n,r,i,o,a=0,s=this.length,l=0===arguments.length||"string"==typeof e&&e;if(x.isFunction(e))return this.each(function(t){x(this).removeClass(e.call(this,t,this.className))});if(l)for(t=(e||"").match(T)||[];s>a;a++)if(n=this[a],r=1===n.nodeType&&(n.className?(" "+n.className+" ").replace(U," "):"")){o=0;while(i=t[o++])while(r.indexOf(" "+i+" ")>=0)r=r.replace(" "+i+" "," ");n.className=e?x.trim(r):""}return this},toggleClass:function(e,t){var n=typeof e,r="boolean"==typeof t;return x.isFunction(e)?this.each(function(n){x(this).toggleClass(e.call(this,n,this.className,t),t)}):this.each(function(){if("string"===n){var o,a=0,s=x(this),l=t,u=e.match(T)||[];while(o=u[a++])l=r?l:!s.hasClass(o),s[l?"addClass":"removeClass"](o)}else(n===i||"boolean"===n)&&(this.className&&x._data(this,"__className__",this.className),this.className=this.className||e===!1?"":x._data(this,"__className__")||"")})},hasClass:function(e){var t=" "+e+" ",n=0,r=this.length;for(;r>n;n++)if(1===this[n].nodeType&&(" "+this[n].className+" ").replace(U," ").indexOf(t)>=0)return!0;return!1},val:function(e){var n,r,i,o=this[0];{if(arguments.length)return i=x.isFunction(e),this.each(function(n){var o;1===this.nodeType&&(o=i?e.call(this,n,x(this).val()):e,null==o?o="":"number"==typeof o?o+="":x.isArray(o)&&(o=x.map(o,function(e){return null==e?"":e+""})),r=x.valHooks[this.type]||x.valHooks[this.nodeName.toLowerCase()],r&&"set"in r&&r.set(this,o,"value")!==t||(this.value=o))});if(o)return r=x.valHooks[o.type]||x.valHooks[o.nodeName.toLowerCase()],r&&"get"in r&&(n=r.get(o,"value"))!==t?n:(n=o.value,"string"==typeof n?n.replace(V,""):null==n?"":n)}}}),x.extend({valHooks:{option:{get:function(e){var t=x.find.attr(e,"value");return null!=t?t:e.text}},select:{get:function(e){var t,n,r=e.options,i=e.selectedIndex,o="select-one"===e.type||0>i,a=o?null:[],s=o?i+1:r.length,l=0>i?s:o?i:0;for(;s>l;l++)if(n=r[l],!(!n.selected&&l!==i||(x.support.optDisabled?n.disabled:null!==n.getAttribute("disabled"))||n.parentNode.disabled&&x.nodeName(n.parentNode,"optgroup"))){if(t=x(n).val(),o)return t;a.push(t)}return a},set:function(e,t){var n,r,i=e.options,o=x.makeArray(t),a=i.length;while(a--)r=i[a],(r.selected=x.inArray(x(r).val(),o)>=0)&&(n=!0);return n||(e.selectedIndex=-1),o}}},attr:function(e,n,r){var o,a,s=e.nodeType;if(e&&3!==s&&8!==s&&2!==s)return typeof e.getAttribute===i?x.prop(e,n,r):(1===s&&x.isXMLDoc(e)||(n=n.toLowerCase(),o=x.attrHooks[n]||(x.expr.match.bool.test(n)?X:z)),r===t?o&&"get"in o&&null!==(a=o.get(e,n))?a:(a=x.find.attr(e,n),null==a?t:a):null!==r?o&&"set"in o&&(a=o.set(e,r,n))!==t?a:(e.setAttribute(n,r+""),r):(x.removeAttr(e,n),t))},removeAttr:function(e,t){var n,r,i=0,o=t&&t.match(T);if(o&&1===e.nodeType)while(n=o[i++])r=x.propFix[n]||n,x.expr.match.bool.test(n)?K&&Q||!G.test(n)?e[r]=!1:e[x.camelCase("default-"+n)]=e[r]=!1:x.attr(e,n,""),e.removeAttribute(Q?n:r)},attrHooks:{type:{set:function(e,t){if(!x.support.radioValue&&"radio"===t&&x.nodeName(e,"input")){var n=e.value;return e.setAttribute("type",t),n&&(e.value=n),t}}}},propFix:{"for":"htmlFor","class":"className"},prop:function(e,n,r){var i,o,a,s=e.nodeType;if(e&&3!==s&&8!==s&&2!==s)return a=1!==s||!x.isXMLDoc(e),a&&(n=x.propFix[n]||n,o=x.propHooks[n]),r!==t?o&&"set"in o&&(i=o.set(e,r,n))!==t?i:e[n]=r:o&&"get"in o&&null!==(i=o.get(e,n))?i:e[n]},propHooks:{tabIndex:{get:function(e){var t=x.find.attr(e,"tabindex");return t?parseInt(t,10):Y.test(e.nodeName)||J.test(e.nodeName)&&e.href?0:-1}}}}),X={set:function(e,t,n){return t===!1?x.removeAttr(e,n):K&&Q||!G.test(n)?e.setAttribute(!Q&&x.propFix[n]||n,n):e[x.camelCase("default-"+n)]=e[n]=!0,n}},x.each(x.expr.match.bool.source.match(/\w+/g),function(e,n){var r=x.expr.attrHandle[n]||x.find.attr;x.expr.attrHandle[n]=K&&Q||!G.test(n)?function(e,n,i){var o=x.expr.attrHandle[n],a=i?t:(x.expr.attrHandle[n]=t)!=r(e,n,i)?n.toLowerCase():null;return x.expr.attrHandle[n]=o,a}:function(e,n,r){return r?t:e[x.camelCase("default-"+n)]?n.toLowerCase():null}}),K&&Q||(x.attrHooks.value={set:function(e,n,r){return x.nodeName(e,"input")?(e.defaultValue=n,t):z&&z.set(e,n,r)}}),Q||(z={set:function(e,n,r){var i=e.getAttributeNode(r);return i||e.setAttributeNode(i=e.ownerDocument.createAttribute(r)),i.value=n+="","value"===r||n===e.getAttribute(r)?n:t}},x.expr.attrHandle.id=x.expr.attrHandle.name=x.expr.attrHandle.coords=function(e,n,r){var i;return r?t:(i=e.getAttributeNode(n))&&""!==i.value?i.value:null},x.valHooks.button={get:function(e,n){var r=e.getAttributeNode(n);return r&&r.specified?r.value:t},set:z.set},x.attrHooks.contenteditable={set:function(e,t,n){z.set(e,""===t?!1:t,n)}},x.each(["width","height"],function(e,n){x.attrHooks[n]={set:function(e,r){return""===r?(e.setAttribute(n,"auto"),r):t}}})),x.support.hrefNormalized||x.each(["href","src"],function(e,t){x.propHooks[t]={get:function(e){return e.getAttribute(t,4)}}}),x.support.style||(x.attrHooks.style={get:function(e){return e.style.cssText||t},set:function(e,t){return e.style.cssText=t+""}}),x.support.optSelected||(x.propHooks.selected={get:function(e){var t=e.parentNode;return t&&(t.selectedIndex,t.parentNode&&t.parentNode.selectedIndex),null}}),x.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){x.propFix[this.toLowerCase()]=this}),x.support.enctype||(x.propFix.enctype="encoding"),x.each(["radio","checkbox"],function(){x.valHooks[this]={set:function(e,n){return x.isArray(n)?e.checked=x.inArray(x(e).val(),n)>=0:t}},x.support.checkOn||(x.valHooks[this].get=function(e){return null===e.getAttribute("value")?"on":e.value})});var Z=/^(?:input|select|textarea)$/i,et=/^key/,tt=/^(?:mouse|contextmenu)|click/,nt=/^(?:focusinfocus|focusoutblur)$/,rt=/^([^.]*)(?:\.(.+)|)$/;function it(){return!0}function ot(){return!1}function at(){try{return a.activeElement}catch(e){}}x.event={global:{},add:function(e,n,r,o,a){var s,l,u,c,p,f,d,h,g,m,y,v=x._data(e);if(v){r.handler&&(c=r,r=c.handler,a=c.selector),r.guid||(r.guid=x.guid++),(l=v.events)||(l=v.events={}),(f=v.handle)||(f=v.handle=function(e){return typeof x===i||e&&x.event.triggered===e.type?t:x.event.dispatch.apply(f.elem,arguments)},f.elem=e),n=(n||"").match(T)||[""],u=n.length;while(u--)s=rt.exec(n[u])||[],g=y=s[1],m=(s[2]||"").split(".").sort(),g&&(p=x.event.special[g]||{},g=(a?p.delegateType:p.bindType)||g,p=x.event.special[g]||{},d=x.extend({type:g,origType:y,data:o,handler:r,guid:r.guid,selector:a,needsContext:a&&x.expr.match.needsContext.test(a),namespace:m.join(".")},c),(h=l[g])||(h=l[g]=[],h.delegateCount=0,p.setup&&p.setup.call(e,o,m,f)!==!1||(e.addEventListener?e.addEventListener(g,f,!1):e.attachEvent&&e.attachEvent("on"+g,f))),p.add&&(p.add.call(e,d),d.handler.guid||(d.handler.guid=r.guid)),a?h.splice(h.delegateCount++,0,d):h.push(d),x.event.global[g]=!0);e=null}},remove:function(e,t,n,r,i){var o,a,s,l,u,c,p,f,d,h,g,m=x.hasData(e)&&x._data(e);if(m&&(c=m.events)){t=(t||"").match(T)||[""],u=t.length;while(u--)if(s=rt.exec(t[u])||[],d=g=s[1],h=(s[2]||"").split(".").sort(),d){p=x.event.special[d]||{},d=(r?p.delegateType:p.bindType)||d,f=c[d]||[],s=s[2]&&RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"),l=o=f.length;while(o--)a=f[o],!i&&g!==a.origType||n&&n.guid!==a.guid||s&&!s.test(a.namespace)||r&&r!==a.selector&&("**"!==r||!a.selector)||(f.splice(o,1),a.selector&&f.delegateCount--,p.remove&&p.remove.call(e,a));l&&!f.length&&(p.teardown&&p.teardown.call(e,h,m.handle)!==!1||x.removeEvent(e,d,m.handle),delete c[d])}else for(d in c)x.event.remove(e,d+t[u],n,r,!0);x.isEmptyObject(c)&&(delete m.handle,x._removeData(e,"events"))}},trigger:function(n,r,i,o){var s,l,u,c,p,f,d,h=[i||a],g=v.call(n,"type")?n.type:n,m=v.call(n,"namespace")?n.namespace.split("."):[];if(u=f=i=i||a,3!==i.nodeType&&8!==i.nodeType&&!nt.test(g+x.event.triggered)&&(g.indexOf(".")>=0&&(m=g.split("."),g=m.shift(),m.sort()),l=0>g.indexOf(":")&&"on"+g,n=n[x.expando]?n:new x.Event(g,"object"==typeof n&&n),n.isTrigger=o?2:3,n.namespace=m.join("."),n.namespace_re=n.namespace?RegExp("(^|\\.)"+m.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,n.result=t,n.target||(n.target=i),r=null==r?[n]:x.makeArray(r,[n]),p=x.event.special[g]||{},o||!p.trigger||p.trigger.apply(i,r)!==!1)){if(!o&&!p.noBubble&&!x.isWindow(i)){for(c=p.delegateType||g,nt.test(c+g)||(u=u.parentNode);u;u=u.parentNode)h.push(u),f=u;f===(i.ownerDocument||a)&&h.push(f.defaultView||f.parentWindow||e)}d=0;while((u=h[d++])&&!n.isPropagationStopped())n.type=d>1?c:p.bindType||g,s=(x._data(u,"events")||{})[n.type]&&x._data(u,"handle"),s&&s.apply(u,r),s=l&&u[l],s&&x.acceptData(u)&&s.apply&&s.apply(u,r)===!1&&n.preventDefault();if(n.type=g,!o&&!n.isDefaultPrevented()&&(!p._default||p._default.apply(h.pop(),r)===!1)&&x.acceptData(i)&&l&&i[g]&&!x.isWindow(i)){f=i[l],f&&(i[l]=null),x.event.triggered=g;try{i[g]()}catch(y){}x.event.triggered=t,f&&(i[l]=f)}return n.result}},dispatch:function(e){e=x.event.fix(e);var n,r,i,o,a,s=[],l=g.call(arguments),u=(x._data(this,"events")||{})[e.type]||[],c=x.event.special[e.type]||{};if(l[0]=e,e.delegateTarget=this,!c.preDispatch||c.preDispatch.call(this,e)!==!1){s=x.event.handlers.call(this,e,u),n=0;while((o=s[n++])&&!e.isPropagationStopped()){e.currentTarget=o.elem,a=0;while((i=o.handlers[a++])&&!e.isImmediatePropagationStopped())(!e.namespace_re||e.namespace_re.test(i.namespace))&&(e.handleObj=i,e.data=i.data,r=((x.event.special[i.origType]||{}).handle||i.handler).apply(o.elem,l),r!==t&&(e.result=r)===!1&&(e.preventDefault(),e.stopPropagation()))}return c.postDispatch&&c.postDispatch.call(this,e),e.result}},handlers:function(e,n){var r,i,o,a,s=[],l=n.delegateCount,u=e.target;if(l&&u.nodeType&&(!e.button||"click"!==e.type))for(;u!=this;u=u.parentNode||this)if(1===u.nodeType&&(u.disabled!==!0||"click"!==e.type)){for(o=[],a=0;l>a;a++)i=n[a],r=i.selector+" ",o[r]===t&&(o[r]=i.needsContext?x(r,this).index(u)>=0:x.find(r,this,null,[u]).length),o[r]&&o.push(i);o.length&&s.push({elem:u,handlers:o})}return n.length>l&&s.push({elem:this,handlers:n.slice(l)}),s},fix:function(e){if(e[x.expando])return e;var t,n,r,i=e.type,o=e,s=this.fixHooks[i];s||(this.fixHooks[i]=s=tt.test(i)?this.mouseHooks:et.test(i)?this.keyHooks:{}),r=s.props?this.props.concat(s.props):this.props,e=new x.Event(o),t=r.length;while(t--)n=r[t],e[n]=o[n];return e.target||(e.target=o.srcElement||a),3===e.target.nodeType&&(e.target=e.target.parentNode),e.metaKey=!!e.metaKey,s.filter?s.filter(e,o):e},props:"altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(e,t){return null==e.which&&(e.which=null!=t.charCode?t.charCode:t.keyCode),e}},mouseHooks:{props:"button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(e,n){var r,i,o,s=n.button,l=n.fromElement;return null==e.pageX&&null!=n.clientX&&(i=e.target.ownerDocument||a,o=i.documentElement,r=i.body,e.pageX=n.clientX+(o&&o.scrollLeft||r&&r.scrollLeft||0)-(o&&o.clientLeft||r&&r.clientLeft||0),e.pageY=n.clientY+(o&&o.scrollTop||r&&r.scrollTop||0)-(o&&o.clientTop||r&&r.clientTop||0)),!e.relatedTarget&&l&&(e.relatedTarget=l===e.target?n.toElement:l),e.which||s===t||(e.which=1&s?1:2&s?3:4&s?2:0),e}},special:{load:{noBubble:!0},focus:{trigger:function(){if(this!==at()&&this.focus)try{return this.focus(),!1}catch(e){}},delegateType:"focusin"},blur:{trigger:function(){return this===at()&&this.blur?(this.blur(),!1):t},delegateType:"focusout"},click:{trigger:function(){return x.nodeName(this,"input")&&"checkbox"===this.type&&this.click?(this.click(),!1):t},_default:function(e){return x.nodeName(e.target,"a")}},beforeunload:{postDispatch:function(e){e.result!==t&&(e.originalEvent.returnValue=e.result)}}},simulate:function(e,t,n,r){var i=x.extend(new x.Event,n,{type:e,isSimulated:!0,originalEvent:{}});r?x.event.trigger(i,null,t):x.event.dispatch.call(t,i),i.isDefaultPrevented()&&n.preventDefault()}},x.removeEvent=a.removeEventListener?function(e,t,n){e.removeEventListener&&e.removeEventListener(t,n,!1)}:function(e,t,n){var r="on"+t;e.detachEvent&&(typeof e[r]===i&&(e[r]=null),e.detachEvent(r,n))},x.Event=function(e,n){return this instanceof x.Event?(e&&e.type?(this.originalEvent=e,this.type=e.type,this.isDefaultPrevented=e.defaultPrevented||e.returnValue===!1||e.getPreventDefault&&e.getPreventDefault()?it:ot):this.type=e,n&&x.extend(this,n),this.timeStamp=e&&e.timeStamp||x.now(),this[x.expando]=!0,t):new x.Event(e,n)},x.Event.prototype={isDefaultPrevented:ot,isPropagationStopped:ot,isImmediatePropagationStopped:ot,preventDefault:function(){var e=this.originalEvent;this.isDefaultPrevented=it,e&&(e.preventDefault?e.preventDefault():e.returnValue=!1)},stopPropagation:function(){var e=this.originalEvent;this.isPropagationStopped=it,e&&(e.stopPropagation&&e.stopPropagation(),e.cancelBubble=!0)},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=it,this.stopPropagation()}},x.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(e,t){x.event.special[e]={delegateType:t,bindType:t,handle:function(e){var n,r=this,i=e.relatedTarget,o=e.handleObj;return(!i||i!==r&&!x.contains(r,i))&&(e.type=o.origType,n=o.handler.apply(this,arguments),e.type=t),n}}}),x.support.submitBubbles||(x.event.special.submit={setup:function(){return x.nodeName(this,"form")?!1:(x.event.add(this,"click._submit keypress._submit",function(e){var n=e.target,r=x.nodeName(n,"input")||x.nodeName(n,"button")?n.form:t;r&&!x._data(r,"submitBubbles")&&(x.event.add(r,"submit._submit",function(e){e._submit_bubble=!0}),x._data(r,"submitBubbles",!0))}),t)},postDispatch:function(e){e._submit_bubble&&(delete e._submit_bubble,this.parentNode&&!e.isTrigger&&x.event.simulate("submit",this.parentNode,e,!0))},teardown:function(){return x.nodeName(this,"form")?!1:(x.event.remove(this,"._submit"),t)}}),x.support.changeBubbles||(x.event.special.change={setup:function(){return Z.test(this.nodeName)?(("checkbox"===this.type||"radio"===this.type)&&(x.event.add(this,"propertychange._change",function(e){"checked"===e.originalEvent.propertyName&&(this._just_changed=!0)}),x.event.add(this,"click._change",function(e){this._just_changed&&!e.isTrigger&&(this._just_changed=!1),x.event.simulate("change",this,e,!0)})),!1):(x.event.add(this,"beforeactivate._change",function(e){var t=e.target;Z.test(t.nodeName)&&!x._data(t,"changeBubbles")&&(x.event.add(t,"change._change",function(e){!this.parentNode||e.isSimulated||e.isTrigger||x.event.simulate("change",this.parentNode,e,!0)}),x._data(t,"changeBubbles",!0))}),t)},handle:function(e){var n=e.target;return this!==n||e.isSimulated||e.isTrigger||"radio"!==n.type&&"checkbox"!==n.type?e.handleObj.handler.apply(this,arguments):t},teardown:function(){return x.event.remove(this,"._change"),!Z.test(this.nodeName)}}),x.support.focusinBubbles||x.each({focus:"focusin",blur:"focusout"},function(e,t){var n=0,r=function(e){x.event.simulate(t,e.target,x.event.fix(e),!0)};x.event.special[t]={setup:function(){0===n++&&a.addEventListener(e,r,!0)},teardown:function(){0===--n&&a.removeEventListener(e,r,!0)}}}),x.fn.extend({on:function(e,n,r,i,o){var a,s;if("object"==typeof e){"string"!=typeof n&&(r=r||n,n=t);for(a in e)this.on(a,n,r,e[a],o);return this}if(null==r&&null==i?(i=n,r=n=t):null==i&&("string"==typeof n?(i=r,r=t):(i=r,r=n,n=t)),i===!1)i=ot;else if(!i)return this;return 1===o&&(s=i,i=function(e){return x().off(e),s.apply(this,arguments)},i.guid=s.guid||(s.guid=x.guid++)),this.each(function(){x.event.add(this,e,i,r,n)})},one:function(e,t,n,r){return this.on(e,t,n,r,1)},off:function(e,n,r){var i,o;if(e&&e.preventDefault&&e.handleObj)return i=e.handleObj,x(e.delegateTarget).off(i.namespace?i.origType+"."+i.namespace:i.origType,i.selector,i.handler),this;if("object"==typeof e){for(o in e)this.off(o,n,e[o]);return this}return(n===!1||"function"==typeof n)&&(r=n,n=t),r===!1&&(r=ot),this.each(function(){x.event.remove(this,e,r,n)})},trigger:function(e,t){return this.each(function(){x.event.trigger(e,t,this)})},triggerHandler:function(e,n){var r=this[0];return r?x.event.trigger(e,n,r,!0):t}});var st=/^.[^:#\[\.,]*$/,lt=/^(?:parents|prev(?:Until|All))/,ut=x.expr.match.needsContext,ct={children:!0,contents:!0,next:!0,prev:!0};x.fn.extend({find:function(e){var t,n=[],r=this,i=r.length;if("string"!=typeof e)return this.pushStack(x(e).filter(function(){for(t=0;i>t;t++)if(x.contains(r[t],this))return!0}));for(t=0;i>t;t++)x.find(e,r[t],n);return n=this.pushStack(i>1?x.unique(n):n),n.selector=this.selector?this.selector+" "+e:e,n},has:function(e){var t,n=x(e,this),r=n.length;return this.filter(function(){for(t=0;r>t;t++)if(x.contains(this,n[t]))return!0})},not:function(e){return this.pushStack(ft(this,e||[],!0))},filter:function(e){return this.pushStack(ft(this,e||[],!1))},is:function(e){return!!ft(this,"string"==typeof e&&ut.test(e)?x(e):e||[],!1).length},closest:function(e,t){var n,r=0,i=this.length,o=[],a=ut.test(e)||"string"!=typeof e?x(e,t||this.context):0;for(;i>r;r++)for(n=this[r];n&&n!==t;n=n.parentNode)if(11>n.nodeType&&(a?a.index(n)>-1:1===n.nodeType&&x.find.matchesSelector(n,e))){n=o.push(n);break}return this.pushStack(o.length>1?x.unique(o):o)},index:function(e){return e?"string"==typeof e?x.inArray(this[0],x(e)):x.inArray(e.jquery?e[0]:e,this):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(e,t){var n="string"==typeof e?x(e,t):x.makeArray(e&&e.nodeType?[e]:e),r=x.merge(this.get(),n);return this.pushStack(x.unique(r))},addBack:function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}});function pt(e,t){do e=e[t];while(e&&1!==e.nodeType);return e}x.each({parent:function(e){var t=e.parentNode;return t&&11!==t.nodeType?t:null},parents:function(e){return x.dir(e,"parentNode")},parentsUntil:function(e,t,n){return x.dir(e,"parentNode",n)},next:function(e){return pt(e,"nextSibling")},prev:function(e){return pt(e,"previousSibling")},nextAll:function(e){return x.dir(e,"nextSibling")},prevAll:function(e){return x.dir(e,"previousSibling")},nextUntil:function(e,t,n){return x.dir(e,"nextSibling",n)},prevUntil:function(e,t,n){return x.dir(e,"previousSibling",n)},siblings:function(e){return x.sibling((e.parentNode||{}).firstChild,e)},children:function(e){return x.sibling(e.firstChild)},contents:function(e){return x.nodeName(e,"iframe")?e.contentDocument||e.contentWindow.document:x.merge([],e.childNodes)}},function(e,t){x.fn[e]=function(n,r){var i=x.map(this,t,n);return"Until"!==e.slice(-5)&&(r=n),r&&"string"==typeof r&&(i=x.filter(r,i)),this.length>1&&(ct[e]||(i=x.unique(i)),lt.test(e)&&(i=i.reverse())),this.pushStack(i)}}),x.extend({filter:function(e,t,n){var r=t[0];return n&&(e=":not("+e+")"),1===t.length&&1===r.nodeType?x.find.matchesSelector(r,e)?[r]:[]:x.find.matches(e,x.grep(t,function(e){return 1===e.nodeType}))},dir:function(e,n,r){var i=[],o=e[n];while(o&&9!==o.nodeType&&(r===t||1!==o.nodeType||!x(o).is(r)))1===o.nodeType&&i.push(o),o=o[n];return i},sibling:function(e,t){var n=[];for(;e;e=e.nextSibling)1===e.nodeType&&e!==t&&n.push(e);return n}});function ft(e,t,n){if(x.isFunction(t))return x.grep(e,function(e,r){return!!t.call(e,r,e)!==n});if(t.nodeType)return x.grep(e,function(e){return e===t!==n});if("string"==typeof t){if(st.test(t))return x.filter(t,e,n);t=x.filter(t,e)}return x.grep(e,function(e){return x.inArray(e,t)>=0!==n})}function dt(e){var t=ht.split("|"),n=e.createDocumentFragment();if(n.createElement)while(t.length)n.createElement(t.pop());return n}var ht="abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",gt=/ jQuery\d+="(?:null|\d+)"/g,mt=RegExp("<(?:"+ht+")[\\s/>]","i"),yt=/^\s+/,vt=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,bt=/<([\w:]+)/,xt=/\s*$/g,At={option:[1,""],legend:[1,"
","
"],area:[1,"",""],param:[1,"",""],thead:[1,"","
"],tr:[2,"","
"],col:[2,"","
"],td:[3,"","
"],_default:x.support.htmlSerialize?[0,"",""]:[1,"X
","
"]},jt=dt(a),Dt=jt.appendChild(a.createElement("div"));At.optgroup=At.option,At.tbody=At.tfoot=At.colgroup=At.caption=At.thead,At.th=At.td,x.fn.extend({text:function(e){return x.access(this,function(e){return e===t?x.text(this):this.empty().append((this[0]&&this[0].ownerDocument||a).createTextNode(e))},null,e,arguments.length)},append:function(){return this.domManip(arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=Lt(this,e);t.appendChild(e)}})},prepend:function(){return this.domManip(arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=Lt(this,e);t.insertBefore(e,t.firstChild)}})},before:function(){return this.domManip(arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this)})},after:function(){return this.domManip(arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this.nextSibling)})},remove:function(e,t){var n,r=e?x.filter(e,this):this,i=0;for(;null!=(n=r[i]);i++)t||1!==n.nodeType||x.cleanData(Ft(n)),n.parentNode&&(t&&x.contains(n.ownerDocument,n)&&_t(Ft(n,"script")),n.parentNode.removeChild(n));return this},empty:function(){var e,t=0;for(;null!=(e=this[t]);t++){1===e.nodeType&&x.cleanData(Ft(e,!1));while(e.firstChild)e.removeChild(e.firstChild);e.options&&x.nodeName(e,"select")&&(e.options.length=0)}return this},clone:function(e,t){return e=null==e?!1:e,t=null==t?e:t,this.map(function(){return x.clone(this,e,t)})},html:function(e){return x.access(this,function(e){var n=this[0]||{},r=0,i=this.length;if(e===t)return 1===n.nodeType?n.innerHTML.replace(gt,""):t;if(!("string"!=typeof e||Tt.test(e)||!x.support.htmlSerialize&&mt.test(e)||!x.support.leadingWhitespace&&yt.test(e)||At[(bt.exec(e)||["",""])[1].toLowerCase()])){e=e.replace(vt,"<$1>");try{for(;i>r;r++)n=this[r]||{},1===n.nodeType&&(x.cleanData(Ft(n,!1)),n.innerHTML=e);n=0}catch(o){}}n&&this.empty().append(e)},null,e,arguments.length)},replaceWith:function(){var e=x.map(this,function(e){return[e.nextSibling,e.parentNode]}),t=0;return this.domManip(arguments,function(n){var r=e[t++],i=e[t++];i&&(r&&r.parentNode!==i&&(r=this.nextSibling),x(this).remove(),i.insertBefore(n,r))},!0),t?this:this.remove()},detach:function(e){return this.remove(e,!0)},domManip:function(e,t,n){e=d.apply([],e);var r,i,o,a,s,l,u=0,c=this.length,p=this,f=c-1,h=e[0],g=x.isFunction(h);if(g||!(1>=c||"string"!=typeof h||x.support.checkClone)&&Nt.test(h))return this.each(function(r){var i=p.eq(r);g&&(e[0]=h.call(this,r,i.html())),i.domManip(e,t,n)});if(c&&(l=x.buildFragment(e,this[0].ownerDocument,!1,!n&&this),r=l.firstChild,1===l.childNodes.length&&(l=r),r)){for(a=x.map(Ft(l,"script"),Ht),o=a.length;c>u;u++)i=l,u!==f&&(i=x.clone(i,!0,!0),o&&x.merge(a,Ft(i,"script"))),t.call(this[u],i,u);if(o)for(s=a[a.length-1].ownerDocument,x.map(a,qt),u=0;o>u;u++)i=a[u],kt.test(i.type||"")&&!x._data(i,"globalEval")&&x.contains(s,i)&&(i.src?x._evalUrl(i.src):x.globalEval((i.text||i.textContent||i.innerHTML||"").replace(St,"")));l=r=null}return this}});function Lt(e,t){return x.nodeName(e,"table")&&x.nodeName(1===t.nodeType?t:t.firstChild,"tr")?e.getElementsByTagName("tbody")[0]||e.appendChild(e.ownerDocument.createElement("tbody")):e}function Ht(e){return e.type=(null!==x.find.attr(e,"type"))+"/"+e.type,e}function qt(e){var t=Et.exec(e.type);return t?e.type=t[1]:e.removeAttribute("type"),e}function _t(e,t){var n,r=0;for(;null!=(n=e[r]);r++)x._data(n,"globalEval",!t||x._data(t[r],"globalEval"))}function Mt(e,t){if(1===t.nodeType&&x.hasData(e)){var n,r,i,o=x._data(e),a=x._data(t,o),s=o.events;if(s){delete a.handle,a.events={};for(n in s)for(r=0,i=s[n].length;i>r;r++)x.event.add(t,n,s[n][r])}a.data&&(a.data=x.extend({},a.data))}}function Ot(e,t){var n,r,i;if(1===t.nodeType){if(n=t.nodeName.toLowerCase(),!x.support.noCloneEvent&&t[x.expando]){i=x._data(t);for(r in i.events)x.removeEvent(t,r,i.handle);t.removeAttribute(x.expando)}"script"===n&&t.text!==e.text?(Ht(t).text=e.text,qt(t)):"object"===n?(t.parentNode&&(t.outerHTML=e.outerHTML),x.support.html5Clone&&e.innerHTML&&!x.trim(t.innerHTML)&&(t.innerHTML=e.innerHTML)):"input"===n&&Ct.test(e.type)?(t.defaultChecked=t.checked=e.checked,t.value!==e.value&&(t.value=e.value)):"option"===n?t.defaultSelected=t.selected=e.defaultSelected:("input"===n||"textarea"===n)&&(t.defaultValue=e.defaultValue)}}x.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(e,t){x.fn[e]=function(e){var n,r=0,i=[],o=x(e),a=o.length-1;for(;a>=r;r++)n=r===a?this:this.clone(!0),x(o[r])[t](n),h.apply(i,n.get());return this.pushStack(i)}});function Ft(e,n){var r,o,a=0,s=typeof e.getElementsByTagName!==i?e.getElementsByTagName(n||"*"):typeof e.querySelectorAll!==i?e.querySelectorAll(n||"*"):t;if(!s)for(s=[],r=e.childNodes||e;null!=(o=r[a]);a++)!n||x.nodeName(o,n)?s.push(o):x.merge(s,Ft(o,n));return n===t||n&&x.nodeName(e,n)?x.merge([e],s):s}function Bt(e){Ct.test(e.type)&&(e.defaultChecked=e.checked)}x.extend({clone:function(e,t,n){var r,i,o,a,s,l=x.contains(e.ownerDocument,e);if(x.support.html5Clone||x.isXMLDoc(e)||!mt.test("<"+e.nodeName+">")?o=e.cloneNode(!0):(Dt.innerHTML=e.outerHTML,Dt.removeChild(o=Dt.firstChild)),!(x.support.noCloneEvent&&x.support.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||x.isXMLDoc(e)))for(r=Ft(o),s=Ft(e),a=0;null!=(i=s[a]);++a)r[a]&&Ot(i,r[a]);if(t)if(n)for(s=s||Ft(e),r=r||Ft(o),a=0;null!=(i=s[a]);a++)Mt(i,r[a]);else Mt(e,o);return r=Ft(o,"script"),r.length>0&&_t(r,!l&&Ft(e,"script")),r=s=i=null,o},buildFragment:function(e,t,n,r){var i,o,a,s,l,u,c,p=e.length,f=dt(t),d=[],h=0;for(;p>h;h++)if(o=e[h],o||0===o)if("object"===x.type(o))x.merge(d,o.nodeType?[o]:o);else if(wt.test(o)){s=s||f.appendChild(t.createElement("div")),l=(bt.exec(o)||["",""])[1].toLowerCase(),c=At[l]||At._default,s.innerHTML=c[1]+o.replace(vt,"<$1>")+c[2],i=c[0];while(i--)s=s.lastChild;if(!x.support.leadingWhitespace&&yt.test(o)&&d.push(t.createTextNode(yt.exec(o)[0])),!x.support.tbody){o="table"!==l||xt.test(o)?""!==c[1]||xt.test(o)?0:s:s.firstChild,i=o&&o.childNodes.length;while(i--)x.nodeName(u=o.childNodes[i],"tbody")&&!u.childNodes.length&&o.removeChild(u)}x.merge(d,s.childNodes),s.textContent="";while(s.firstChild)s.removeChild(s.firstChild);s=f.lastChild}else d.push(t.createTextNode(o));s&&f.removeChild(s),x.support.appendChecked||x.grep(Ft(d,"input"),Bt),h=0;while(o=d[h++])if((!r||-1===x.inArray(o,r))&&(a=x.contains(o.ownerDocument,o),s=Ft(f.appendChild(o),"script"),a&&_t(s),n)){i=0;while(o=s[i++])kt.test(o.type||"")&&n.push(o)}return s=null,f},cleanData:function(e,t){var n,r,o,a,s=0,l=x.expando,u=x.cache,c=x.support.deleteExpando,f=x.event.special;for(;null!=(n=e[s]);s++)if((t||x.acceptData(n))&&(o=n[l],a=o&&u[o])){if(a.events)for(r in a.events)f[r]?x.event.remove(n,r):x.removeEvent(n,r,a.handle); -u[o]&&(delete u[o],c?delete n[l]:typeof n.removeAttribute!==i?n.removeAttribute(l):n[l]=null,p.push(o))}},_evalUrl:function(e){return x.ajax({url:e,type:"GET",dataType:"script",async:!1,global:!1,"throws":!0})}}),x.fn.extend({wrapAll:function(e){if(x.isFunction(e))return this.each(function(t){x(this).wrapAll(e.call(this,t))});if(this[0]){var t=x(e,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){var e=this;while(e.firstChild&&1===e.firstChild.nodeType)e=e.firstChild;return e}).append(this)}return this},wrapInner:function(e){return x.isFunction(e)?this.each(function(t){x(this).wrapInner(e.call(this,t))}):this.each(function(){var t=x(this),n=t.contents();n.length?n.wrapAll(e):t.append(e)})},wrap:function(e){var t=x.isFunction(e);return this.each(function(n){x(this).wrapAll(t?e.call(this,n):e)})},unwrap:function(){return this.parent().each(function(){x.nodeName(this,"body")||x(this).replaceWith(this.childNodes)}).end()}});var Pt,Rt,Wt,$t=/alpha\([^)]*\)/i,It=/opacity\s*=\s*([^)]*)/,zt=/^(top|right|bottom|left)$/,Xt=/^(none|table(?!-c[ea]).+)/,Ut=/^margin/,Vt=RegExp("^("+w+")(.*)$","i"),Yt=RegExp("^("+w+")(?!px)[a-z%]+$","i"),Jt=RegExp("^([+-])=("+w+")","i"),Gt={BODY:"block"},Qt={position:"absolute",visibility:"hidden",display:"block"},Kt={letterSpacing:0,fontWeight:400},Zt=["Top","Right","Bottom","Left"],en=["Webkit","O","Moz","ms"];function tn(e,t){if(t in e)return t;var n=t.charAt(0).toUpperCase()+t.slice(1),r=t,i=en.length;while(i--)if(t=en[i]+n,t in e)return t;return r}function nn(e,t){return e=t||e,"none"===x.css(e,"display")||!x.contains(e.ownerDocument,e)}function rn(e,t){var n,r,i,o=[],a=0,s=e.length;for(;s>a;a++)r=e[a],r.style&&(o[a]=x._data(r,"olddisplay"),n=r.style.display,t?(o[a]||"none"!==n||(r.style.display=""),""===r.style.display&&nn(r)&&(o[a]=x._data(r,"olddisplay",ln(r.nodeName)))):o[a]||(i=nn(r),(n&&"none"!==n||!i)&&x._data(r,"olddisplay",i?n:x.css(r,"display"))));for(a=0;s>a;a++)r=e[a],r.style&&(t&&"none"!==r.style.display&&""!==r.style.display||(r.style.display=t?o[a]||"":"none"));return e}x.fn.extend({css:function(e,n){return x.access(this,function(e,n,r){var i,o,a={},s=0;if(x.isArray(n)){for(o=Rt(e),i=n.length;i>s;s++)a[n[s]]=x.css(e,n[s],!1,o);return a}return r!==t?x.style(e,n,r):x.css(e,n)},e,n,arguments.length>1)},show:function(){return rn(this,!0)},hide:function(){return rn(this)},toggle:function(e){var t="boolean"==typeof e;return this.each(function(){(t?e:nn(this))?x(this).show():x(this).hide()})}}),x.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=Wt(e,"opacity");return""===n?"1":n}}}},cssNumber:{columnCount:!0,fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":x.support.cssFloat?"cssFloat":"styleFloat"},style:function(e,n,r,i){if(e&&3!==e.nodeType&&8!==e.nodeType&&e.style){var o,a,s,l=x.camelCase(n),u=e.style;if(n=x.cssProps[l]||(x.cssProps[l]=tn(u,l)),s=x.cssHooks[n]||x.cssHooks[l],r===t)return s&&"get"in s&&(o=s.get(e,!1,i))!==t?o:u[n];if(a=typeof r,"string"===a&&(o=Jt.exec(r))&&(r=(o[1]+1)*o[2]+parseFloat(x.css(e,n)),a="number"),!(null==r||"number"===a&&isNaN(r)||("number"!==a||x.cssNumber[l]||(r+="px"),x.support.clearCloneStyle||""!==r||0!==n.indexOf("background")||(u[n]="inherit"),s&&"set"in s&&(r=s.set(e,r,i))===t)))try{u[n]=r}catch(c){}}},css:function(e,n,r,i){var o,a,s,l=x.camelCase(n);return n=x.cssProps[l]||(x.cssProps[l]=tn(e.style,l)),s=x.cssHooks[n]||x.cssHooks[l],s&&"get"in s&&(a=s.get(e,!0,r)),a===t&&(a=Wt(e,n,i)),"normal"===a&&n in Kt&&(a=Kt[n]),""===r||r?(o=parseFloat(a),r===!0||x.isNumeric(o)?o||0:a):a}}),e.getComputedStyle?(Rt=function(t){return e.getComputedStyle(t,null)},Wt=function(e,n,r){var i,o,a,s=r||Rt(e),l=s?s.getPropertyValue(n)||s[n]:t,u=e.style;return s&&(""!==l||x.contains(e.ownerDocument,e)||(l=x.style(e,n)),Yt.test(l)&&Ut.test(n)&&(i=u.width,o=u.minWidth,a=u.maxWidth,u.minWidth=u.maxWidth=u.width=l,l=s.width,u.width=i,u.minWidth=o,u.maxWidth=a)),l}):a.documentElement.currentStyle&&(Rt=function(e){return e.currentStyle},Wt=function(e,n,r){var i,o,a,s=r||Rt(e),l=s?s[n]:t,u=e.style;return null==l&&u&&u[n]&&(l=u[n]),Yt.test(l)&&!zt.test(n)&&(i=u.left,o=e.runtimeStyle,a=o&&o.left,a&&(o.left=e.currentStyle.left),u.left="fontSize"===n?"1em":l,l=u.pixelLeft+"px",u.left=i,a&&(o.left=a)),""===l?"auto":l});function on(e,t,n){var r=Vt.exec(t);return r?Math.max(0,r[1]-(n||0))+(r[2]||"px"):t}function an(e,t,n,r,i){var o=n===(r?"border":"content")?4:"width"===t?1:0,a=0;for(;4>o;o+=2)"margin"===n&&(a+=x.css(e,n+Zt[o],!0,i)),r?("content"===n&&(a-=x.css(e,"padding"+Zt[o],!0,i)),"margin"!==n&&(a-=x.css(e,"border"+Zt[o]+"Width",!0,i))):(a+=x.css(e,"padding"+Zt[o],!0,i),"padding"!==n&&(a+=x.css(e,"border"+Zt[o]+"Width",!0,i)));return a}function sn(e,t,n){var r=!0,i="width"===t?e.offsetWidth:e.offsetHeight,o=Rt(e),a=x.support.boxSizing&&"border-box"===x.css(e,"boxSizing",!1,o);if(0>=i||null==i){if(i=Wt(e,t,o),(0>i||null==i)&&(i=e.style[t]),Yt.test(i))return i;r=a&&(x.support.boxSizingReliable||i===e.style[t]),i=parseFloat(i)||0}return i+an(e,t,n||(a?"border":"content"),r,o)+"px"}function ln(e){var t=a,n=Gt[e];return n||(n=un(e,t),"none"!==n&&n||(Pt=(Pt||x("