diff --git a/README b/README new file mode 100755 index 0000000..7c545f7 --- /dev/null +++ b/README @@ -0,0 +1,2 @@ +this is a test +this is also a test diff --git a/awstats/awstats012010.www.ck.ntuh.net.txt b/awstats/awstats012010.www.ck.ntuh.net.txt new file mode 120000 index 0000000..832594e --- /dev/null +++ b/awstats/awstats012010.www.ck.ntuh.net.txt @@ -0,0 +1 @@ +awstats012010.ck.ntuh.net.txt \ No newline at end of file diff --git a/awstats/awstats012011.www.ck.ntuh.net.txt b/awstats/awstats012011.www.ck.ntuh.net.txt new file mode 120000 index 0000000..604cc09 --- /dev/null +++ b/awstats/awstats012011.www.ck.ntuh.net.txt @@ -0,0 +1 @@ +awstats012011.ck.ntuh.net.txt \ No newline at end of file diff --git a/awstats/awstats022010.www.ck.ntuh.net.txt b/awstats/awstats022010.www.ck.ntuh.net.txt new file mode 120000 index 0000000..cfb1724 --- /dev/null +++ b/awstats/awstats022010.www.ck.ntuh.net.txt @@ -0,0 +1 @@ +awstats022010.ck.ntuh.net.txt \ No newline at end of file diff --git a/awstats/awstats022011.www.ck.ntuh.net.txt b/awstats/awstats022011.www.ck.ntuh.net.txt new file mode 120000 index 0000000..9a20326 --- /dev/null +++ b/awstats/awstats022011.www.ck.ntuh.net.txt @@ -0,0 +1 @@ +awstats022011.ck.ntuh.net.txt \ No newline at end of file diff --git a/awstats/awstats032010.www.ck.ntuh.net.txt b/awstats/awstats032010.www.ck.ntuh.net.txt new file mode 120000 index 0000000..712a4c9 --- /dev/null +++ b/awstats/awstats032010.www.ck.ntuh.net.txt @@ -0,0 +1 @@ +awstats032010.ck.ntuh.net.txt \ No newline at end of file diff --git a/awstats/awstats032011.www.ck.ntuh.net.txt b/awstats/awstats032011.www.ck.ntuh.net.txt new file mode 120000 index 0000000..a850a8c --- /dev/null +++ b/awstats/awstats032011.www.ck.ntuh.net.txt @@ -0,0 +1 @@ +awstats032011.ck.ntuh.net.txt \ No newline at end of file diff --git a/awstats/awstats042009.www.ck.ntuh.net.txt b/awstats/awstats042009.www.ck.ntuh.net.txt new file mode 120000 index 0000000..22024d9 --- /dev/null +++ b/awstats/awstats042009.www.ck.ntuh.net.txt @@ -0,0 +1 @@ +awstats042009.ck.ntuh.net.txt \ No newline at end of file diff --git a/awstats/awstats042010.www.ck.ntuh.net.txt b/awstats/awstats042010.www.ck.ntuh.net.txt new file mode 120000 index 0000000..b898b55 --- /dev/null +++ b/awstats/awstats042010.www.ck.ntuh.net.txt @@ -0,0 +1 @@ +awstats042010.ck.ntuh.net.txt \ No newline at end of file diff --git a/awstats/awstats042011.www.ck.ntuh.net.txt b/awstats/awstats042011.www.ck.ntuh.net.txt new file mode 120000 index 0000000..3ab16fb --- /dev/null +++ b/awstats/awstats042011.www.ck.ntuh.net.txt @@ -0,0 +1 @@ +awstats042011.ck.ntuh.net.txt \ No newline at end of file diff --git a/awstats/awstats052009.www.ck.ntuh.net.txt b/awstats/awstats052009.www.ck.ntuh.net.txt new file mode 120000 index 0000000..ab1e172 --- /dev/null +++ b/awstats/awstats052009.www.ck.ntuh.net.txt @@ -0,0 +1 @@ +awstats052009.ck.ntuh.net.txt \ No newline at end of file diff --git a/awstats/awstats052010.www.ck.ntuh.net.txt b/awstats/awstats052010.www.ck.ntuh.net.txt new file mode 120000 index 0000000..2013de3 --- /dev/null +++ b/awstats/awstats052010.www.ck.ntuh.net.txt @@ -0,0 +1 @@ +awstats052010.ck.ntuh.net.txt \ No newline at end of file diff --git a/awstats/awstats062010.www.ck.ntuh.net.txt b/awstats/awstats062010.www.ck.ntuh.net.txt new file mode 120000 index 0000000..a968b06 --- /dev/null +++ b/awstats/awstats062010.www.ck.ntuh.net.txt @@ -0,0 +1 @@ +awstats062010.ck.ntuh.net.txt \ No newline at end of file diff --git a/awstats/awstats072009.www.ck.ntuh.net.txt b/awstats/awstats072009.www.ck.ntuh.net.txt new file mode 120000 index 0000000..6b2b07e --- /dev/null +++ b/awstats/awstats072009.www.ck.ntuh.net.txt @@ -0,0 +1 @@ +awstats072009.ck.ntuh.net.txt \ No newline at end of file diff --git a/awstats/awstats072010.www.ck.ntuh.net.txt b/awstats/awstats072010.www.ck.ntuh.net.txt new file mode 120000 index 0000000..8a135c6 --- /dev/null +++ b/awstats/awstats072010.www.ck.ntuh.net.txt @@ -0,0 +1 @@ +awstats072010.ck.ntuh.net.txt \ No newline at end of file diff --git a/awstats/awstats082009.www.ck.ntuh.net.txt b/awstats/awstats082009.www.ck.ntuh.net.txt new file mode 120000 index 0000000..5c92387 --- /dev/null +++ b/awstats/awstats082009.www.ck.ntuh.net.txt @@ -0,0 +1 @@ +awstats082009.ck.ntuh.net.txt \ No newline at end of file diff --git a/awstats/awstats082010.www.ck.ntuh.net.txt b/awstats/awstats082010.www.ck.ntuh.net.txt new file mode 120000 index 0000000..a18991f --- /dev/null +++ b/awstats/awstats082010.www.ck.ntuh.net.txt @@ -0,0 +1 @@ +awstats082010.ck.ntuh.net.txt \ No newline at end of file diff --git a/awstats/awstats092009.www.ck.ntuh.net.txt b/awstats/awstats092009.www.ck.ntuh.net.txt new file mode 120000 index 0000000..6cc695e --- /dev/null +++ b/awstats/awstats092009.www.ck.ntuh.net.txt @@ -0,0 +1 @@ +awstats092009.ck.ntuh.net.txt \ No newline at end of file diff --git a/awstats/awstats092010.www.ck.ntuh.net.txt b/awstats/awstats092010.www.ck.ntuh.net.txt new file mode 120000 index 0000000..b572361 --- /dev/null +++ b/awstats/awstats092010.www.ck.ntuh.net.txt @@ -0,0 +1 @@ +awstats092010.ck.ntuh.net.txt \ No newline at end of file diff --git a/awstats/awstats102009.www.ck.ntuh.net.txt b/awstats/awstats102009.www.ck.ntuh.net.txt new file mode 120000 index 0000000..857812f --- /dev/null +++ b/awstats/awstats102009.www.ck.ntuh.net.txt @@ -0,0 +1 @@ +awstats102009.ck.ntuh.net.txt \ No newline at end of file diff --git a/awstats/awstats102010.www.ck.ntuh.net.txt b/awstats/awstats102010.www.ck.ntuh.net.txt new file mode 120000 index 0000000..5a656ef --- /dev/null +++ b/awstats/awstats102010.www.ck.ntuh.net.txt @@ -0,0 +1 @@ +awstats102010.ck.ntuh.net.txt \ No newline at end of file diff --git a/awstats/awstats112009.www.ck.ntuh.net.txt b/awstats/awstats112009.www.ck.ntuh.net.txt new file mode 120000 index 0000000..26474b7 --- /dev/null +++ b/awstats/awstats112009.www.ck.ntuh.net.txt @@ -0,0 +1 @@ +awstats112009.ck.ntuh.net.txt \ No newline at end of file diff --git a/awstats/awstats112010.www.ck.ntuh.net.txt b/awstats/awstats112010.www.ck.ntuh.net.txt new file mode 120000 index 0000000..c539b5e --- /dev/null +++ b/awstats/awstats112010.www.ck.ntuh.net.txt @@ -0,0 +1 @@ +awstats112010.ck.ntuh.net.txt \ No newline at end of file diff --git a/awstats/awstats122009.www.ck.ntuh.net.txt b/awstats/awstats122009.www.ck.ntuh.net.txt new file mode 120000 index 0000000..c179d81 --- /dev/null +++ b/awstats/awstats122009.www.ck.ntuh.net.txt @@ -0,0 +1 @@ +awstats122009.ck.ntuh.net.txt \ No newline at end of file diff --git a/awstats/awstats122010.www.ck.ntuh.net.txt b/awstats/awstats122010.www.ck.ntuh.net.txt new file mode 120000 index 0000000..e779eef --- /dev/null +++ b/awstats/awstats122010.www.ck.ntuh.net.txt @@ -0,0 +1 @@ +awstats122010.ck.ntuh.net.txt \ No newline at end of file diff --git a/cgi-bin/awstats.pl b/cgi-bin/awstats.pl new file mode 100755 index 0000000..19bef78 --- /dev/null +++ b/cgi-bin/awstats.pl @@ -0,0 +1,10750 @@ +#!/usr/bin/perl +#------------------------------------------------------------------------------ +# Free realtime web server logfile analyzer to show advanced web statistics. +# Works from command line or as a CGI. You must use this script as often as +# necessary from your scheduler to update your statistics and from command +# line or a browser to read report results. +# See AWStats documentation (in docs/ directory) for all setup instructions. +#------------------------------------------------------------------------------ +# $Revision: 1.892 $ - $Author: eldy $ - $Date: 2007/07/07 11:00:05 $ +require 5.005; + +#$|=1; +#use warnings; # Must be used in test mode only. This reduce a little process speed +#use diagnostics; # Must be used in test mode only. This reduce a lot of process speed +use strict;no strict "refs"; +use Time::Local; # use Time::Local 'timelocal_nocheck' is faster but not supported by all Time::Local modules +use Socket; + + +#------------------------------------------------------------------------------ +# Defines +#------------------------------------------------------------------------------ +use vars qw/ $REVISION $VERSION /; +$REVISION='$Revision: 1.892 $'; $REVISION =~ /\s(.*)\s/; $REVISION=$1; +$VERSION="6.7 (build $REVISION)"; + +# ----- Constants ----- +use vars qw/ +$DEBUGFORCED $NBOFLINESFORBENCHMARK $FRAMEWIDTH $NBOFLASTUPDATELOOKUPTOSAVE +$LIMITFLUSH $NEWDAYVISITTIMEOUT $VISITTIMEOUT $NOTSORTEDRECORDTOLERANCE +$WIDTHCOLICON $TOOLTIPON +$lastyearbeforeupdate $lastmonthbeforeupdate $lastdaybeforeupdate $lasthourbeforeupdate $lastdatebeforeupdate +/; +$DEBUGFORCED=0; # Force debug level to log lesser level into debug.log file (Keep this value to 0) +$NBOFLINESFORBENCHMARK=8192; # Benchmark info are printing every NBOFLINESFORBENCHMARK lines (Must be a power of 2) +$FRAMEWIDTH=240; # Width of left frame when UseFramesWhenCGI is on +$NBOFLASTUPDATELOOKUPTOSAVE=500; # Nb of records to save in DNS last update cache file +$LIMITFLUSH=5000; # Nb of records in data arrays after how we need to flush data on disk +$NEWDAYVISITTIMEOUT=764041; # Delay between 01-23:59:59 and 02-00:00:00 +$VISITTIMEOUT=10000; # Lapse of time to consider a page load as a new visit. 10000 = 1 hour (Default = 10000) +$NOTSORTEDRECORDTOLERANCE=20000; # Lapse of time to accept a record if not in correct order. 20000 = 2 hour (Default = 20000) +$WIDTHCOLICON=32; +$TOOLTIPON=0; # Tooltips plugin loaded +# ----- Running variables ----- +use vars qw/ +$DIR $PROG $Extension +$Debug $ShowSteps +$DebugResetDone $DNSLookupAlreadyDone +$RunAsCli $UpdateFor $HeaderHTTPSent $HeaderHTMLSent +$LastLine $LastLineNumber $LastLineOffset $LastLineChecksum $LastUpdate +$lowerval +$PluginMode +$TotalUnique $TotalVisits $TotalHostsKnown $TotalHostsUnknown +$TotalPages $TotalHits $TotalBytes +$TotalNotViewedPages $TotalNotViewedHits $TotalNotViewedBytes +$TotalEntries $TotalExits $TotalBytesPages $TotalDifferentPages +$TotalKeyphrases $TotalKeywords $TotalDifferentKeyphrases $TotalDifferentKeywords +$TotalSearchEnginesPages $TotalSearchEnginesHits $TotalRefererPages $TotalRefererHits $TotalDifferentSearchEngines $TotalDifferentReferer +$FrameName $Center $FileConfig $FileSuffix $Host $YearRequired $MonthRequired $DayRequired $HourRequired +$QueryString $SiteConfig $StaticLinks $PageCode $PageDir $PerlParsingFormat $UserAgent +$pos_vh $pos_host $pos_logname $pos_date $pos_tz $pos_method $pos_url $pos_code $pos_size +$pos_referer $pos_agent $pos_query $pos_gzipin $pos_gzipout $pos_compratio $pos_timetaken +$pos_cluster $pos_emails $pos_emailr $pos_hostr @pos_extra +/; +$DIR=$PROG=$Extension=''; +$Debug = $ShowSteps = 0; +$DebugResetDone = $DNSLookupAlreadyDone = 0; +$RunAsCli = $UpdateFor = $HeaderHTTPSent = $HeaderHTMLSent = 0; +$LastLine = $LastLineNumber = $LastLineOffset = $LastLineChecksum = $LastUpdate = 0; +$lowerval = 0; +$PluginMode = ''; +$TotalUnique = $TotalVisits = $TotalHostsKnown = $TotalHostsUnknown = 0; +$TotalPages = $TotalHits = $TotalBytes = 0; +$TotalNotViewedPages = $TotalNotViewedHits = $TotalNotViewedBytes = 0; +$TotalEntries = $TotalExits = $TotalBytesPages = $TotalDifferentPages = 0; +$TotalKeyphrases = $TotalKeywords = $TotalDifferentKeyphrases = $TotalDifferentKeywords = 0; +$TotalSearchEnginesPages = $TotalSearchEnginesHits = $TotalRefererPages = $TotalRefererHits = $TotalDifferentSearchEngines = $TotalDifferentReferer = 0; +($FrameName, $Center, $FileConfig, $FileSuffix, $Host, $YearRequired, $MonthRequired, $DayRequired, $HourRequired, +$QueryString, $SiteConfig, $StaticLinks, $PageCode, $PageDir, $PerlParsingFormat, $UserAgent)= +('','','','','','','','','','','','','','','',''); +# ----- Plugins variable ----- +use vars qw/ %PluginsLoaded $PluginDir $AtLeastOneSectionPlugin /; +%PluginsLoaded=(); +$PluginDir=''; +$AtLeastOneSectionPlugin=0; +# ----- Time vars ----- +use vars qw/ +$starttime +$nowtime $tomorrowtime +$nowweekofmonth $nowweekofyear $nowdaymod $nowsmallyear +$nowsec $nowmin $nowhour $nowday $nowmonth $nowyear $nowwday $nowyday $nowns +$StartSeconds $StartMicroseconds +/; +$StartSeconds=$StartMicroseconds=0; +# ----- Variables for config file reading ----- +use vars qw/ +$FoundNotPageList +/; +$FoundNotPageList=0; +# ----- Config file variables ----- +use vars qw/ +$StaticExt +$DNSStaticCacheFile +$DNSLastUpdateCacheFile +$MiscTrackerUrl +$Lang +$MaxRowsInHTMLOutput +$MaxLengthOfShownURL +$MaxLengthOfStoredURL +$MaxLengthOfStoredUA +%BarPng +$BuildReportFormat +$BuildHistoryFormat +$ExtraTrackedRowsLimit +$DatabaseBreak +$SectionsToBeSaved +/; +$StaticExt='html'; +$DNSStaticCacheFile='dnscache.txt'; +$DNSLastUpdateCacheFile='dnscachelastupdate.txt'; +$MiscTrackerUrl='/js/awstats_misc_tracker.js'; +$Lang='auto'; +$SectionsToBeSaved='all'; +$MaxRowsInHTMLOutput=1000; +$MaxLengthOfShownURL=64; +$MaxLengthOfStoredURL=256; # Note: Apache LimitRequestLine is default to 8190 +$MaxLengthOfStoredUA=256; +%BarPng=('vv'=>'vv.png','vu'=>'vu.png','hu'=>'hu.png','vp'=>'vp.png','hp'=>'hp.png', +'he'=>'he.png','hx'=>'hx.png','vh'=>'vh.png','hh'=>'hh.png','vk'=>'vk.png','hk'=>'hk.png'); +$BuildReportFormat='html'; +$BuildHistoryFormat='text'; +$ExtraTrackedRowsLimit=500; +$DatabaseBreak='month'; +use vars qw/ +$DebugMessages $AllowToUpdateStatsFromBrowser $EnableLockForUpdate $DNSLookup $AllowAccessFromWebToAuthenticatedUsersOnly +$BarHeight $BarWidth $CreateDirDataIfNotExists $KeepBackupOfHistoricFiles +$NbOfLinesParsed $NbOfLinesDropped $NbOfLinesCorrupted $NbOfOldLines $NbOfNewLines +$NbOfLinesShowsteps $NewLinePhase $NbOfLinesForCorruptedLog $PurgeLogFile $ArchiveLogRecords +$ShowDropped $ShowCorrupted $ShowUnknownOrigin $ShowLinksToWhoIs +$ShowAuthenticatedUsers $ShowFileSizesStats $ShowScreenSizeStats $ShowSMTPErrorsStats +$ShowEMailSenders $ShowEMailReceivers $ShowWormsStats $ShowClusterStats +$IncludeInternalLinksInOriginSection +$AuthenticatedUsersNotCaseSensitive +$Expires $UpdateStats $MigrateStats $URLNotCaseSensitive $URLWithQuery $URLReferrerWithQuery +$DecodeUA +/; +($DebugMessages, $AllowToUpdateStatsFromBrowser, $EnableLockForUpdate, $DNSLookup, $AllowAccessFromWebToAuthenticatedUsersOnly, +$BarHeight, $BarWidth, $CreateDirDataIfNotExists, $KeepBackupOfHistoricFiles, +$NbOfLinesParsed, $NbOfLinesDropped, $NbOfLinesCorrupted, $NbOfOldLines, $NbOfNewLines, +$NbOfLinesShowsteps, $NewLinePhase, $NbOfLinesForCorruptedLog, $PurgeLogFile, $ArchiveLogRecords, +$ShowDropped, $ShowCorrupted, $ShowUnknownOrigin, $ShowLinksToWhoIs, +$ShowAuthenticatedUsers, $ShowFileSizesStats, $ShowScreenSizeStats, $ShowSMTPErrorsStats, +$ShowEMailSenders, $ShowEMailReceivers, $ShowWormsStats, $ShowClusterStats, +$IncludeInternalLinksInOriginSection, +$AuthenticatedUsersNotCaseSensitive, +$Expires, $UpdateStats, $MigrateStats, $URLNotCaseSensitive, $URLWithQuery, $URLReferrerWithQuery, +$DecodeUA)= +(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0); +use vars qw/ +$DetailedReportsOnNewWindows +$FirstDayOfWeek $KeyWordsNotSensitive $SaveDatabaseFilesWithPermissionsForEveryone +$WarningMessages $ShowLinksOnUrl $UseFramesWhenCGI +$ShowMenu $ShowSummary $ShowMonthStats $ShowDaysOfMonthStats $ShowDaysOfWeekStats +$ShowHoursStats $ShowDomainsStats $ShowHostsStats +$ShowRobotsStats $ShowSessionsStats $ShowPagesStats $ShowFileTypesStats +$ShowOSStats $ShowBrowsersStats $ShowOriginStats +$ShowKeyphrasesStats $ShowKeywordsStats $ShowMiscStats $ShowHTTPErrorsStats +$AddDataArrayMonthStats $AddDataArrayShowDaysOfMonthStats $AddDataArrayShowDaysOfWeekStats $AddDataArrayShowHoursStats +/; +($DetailedReportsOnNewWindows, +$FirstDayOfWeek, $KeyWordsNotSensitive, $SaveDatabaseFilesWithPermissionsForEveryone, +$WarningMessages, $ShowLinksOnUrl, $UseFramesWhenCGI, +$ShowMenu, $ShowSummary, $ShowMonthStats, $ShowDaysOfMonthStats, $ShowDaysOfWeekStats, +$ShowHoursStats, $ShowDomainsStats, $ShowHostsStats, +$ShowRobotsStats, $ShowSessionsStats, $ShowPagesStats, $ShowFileTypesStats, +$ShowOSStats, $ShowBrowsersStats, $ShowOriginStats, +$ShowKeyphrasesStats, $ShowKeywordsStats, $ShowMiscStats, $ShowHTTPErrorsStats, +$AddDataArrayMonthStats, $AddDataArrayShowDaysOfMonthStats, $AddDataArrayShowDaysOfWeekStats, $AddDataArrayShowHoursStats +)= +(1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1); +use vars qw/ +$AllowFullYearView +$LevelForRobotsDetection $LevelForWormsDetection $LevelForBrowsersDetection $LevelForOSDetection $LevelForRefererAnalyze +$LevelForFileTypesDetection $LevelForSearchEnginesDetection $LevelForKeywordsDetection +/; +($AllowFullYearView, +$LevelForRobotsDetection, $LevelForWormsDetection, $LevelForBrowsersDetection, $LevelForOSDetection, $LevelForRefererAnalyze, +$LevelForFileTypesDetection, $LevelForSearchEnginesDetection, $LevelForKeywordsDetection)= +(2,2,0,2,2,2,2,2,2); +use vars qw/ +$DirLock $DirCgi $DirConfig $DirData $DirIcons $DirLang $AWScript $ArchiveFileName +$AllowAccessFromWebToFollowingIPAddresses $HTMLHeadSection $HTMLEndSection $LinksToWhoIs $LinksToIPWhoIs +$LogFile $LogType $LogFormat $LogSeparator $Logo $LogoLink $StyleSheet $WrapperScript $SiteDomain +$UseHTTPSLinkForUrl $URLQuerySeparators $URLWithAnchor $ErrorMessages $ShowFlagLinks +/; +($DirLock, $DirCgi, $DirConfig, $DirData, $DirIcons, $DirLang, $AWScript, $ArchiveFileName, +$AllowAccessFromWebToFollowingIPAddresses, $HTMLHeadSection, $HTMLEndSection, $LinksToWhoIs, $LinksToIPWhoIs, +$LogFile, $LogType, $LogFormat, $LogSeparator, $Logo, $LogoLink, $StyleSheet, $WrapperScript, $SiteDomain, +$UseHTTPSLinkForUrl, $URLQuerySeparators, $URLWithAnchor, $ErrorMessages, $ShowFlagLinks)= +('','','','','','','','','','','','','','','','','','','','','','','','','','',''); +use vars qw/ +$color_Background $color_TableBG $color_TableBGRowTitle +$color_TableBGTitle $color_TableBorder $color_TableRowTitle $color_TableTitle +$color_text $color_textpercent $color_titletext $color_weekend $color_link $color_hover $color_other +$color_h $color_k $color_p $color_e $color_x $color_s $color_u $color_v +/; +($color_Background, $color_TableBG, $color_TableBGRowTitle, +$color_TableBGTitle, $color_TableBorder, $color_TableRowTitle, $color_TableTitle, +$color_text, $color_textpercent, $color_titletext, $color_weekend, $color_link, $color_hover, $color_other, +$color_h, $color_k, $color_p, $color_e, $color_x, $color_s, $color_u, $color_v)= +('','','','','','','','','','','','','','','','','','','','','',''); +# ---------- Init arrays -------- +use vars qw/ +@RobotsSearchIDOrder_list1 @RobotsSearchIDOrder_list2 @RobotsSearchIDOrder_listgen +@SearchEnginesSearchIDOrder_list1 @SearchEnginesSearchIDOrder_list2 @SearchEnginesSearchIDOrder_listgen +@BrowsersSearchIDOrder @OSSearchIDOrder @WordsToExtractSearchUrl @WordsToCleanSearchUrl +@WormsSearchIDOrder +@RobotsSearchIDOrder @SearchEnginesSearchIDOrder +@_from_p @_from_h +@_time_p @_time_h @_time_k @_time_nv_p @_time_nv_h @_time_nv_k +@DOWIndex @fieldlib @keylist +/; +@RobotsSearchIDOrder = @SearchEnginesSearchIDOrder = (); +@_from_p = @_from_h = (); +@_time_p = @_time_h = @_time_k = @_time_nv_p = @_time_nv_h = @_time_nv_k = (); +@DOWIndex = @fieldlib = @keylist = (); +use vars qw/ +@MiscListOrder %MiscListCalc +%OSFamily %BrowsersFamily @SessionsRange %SessionsAverage +%LangBrowserToLangAwstats %LangAWStatsToFlagAwstats +@HostAliases @AllowAccessFromWebToFollowingAuthenticatedUsers +@DefaultFile @SkipDNSLookupFor +@SkipHosts @SkipUserAgents @SkipFiles @SkipReferrers @NotPageFiles +@OnlyHosts @OnlyUserAgents @OnlyFiles +@URLWithQueryWithOnly @URLWithQueryWithout +@ExtraName @ExtraCondition @ExtraStatTypes @MaxNbOfExtra @MinHitExtra +@ExtraFirstColumnTitle @ExtraFirstColumnValues @ExtraFirstColumnFunction @ExtraFirstColumnFormat +@ExtraCodeFilter @ExtraConditionType @ExtraConditionTypeVal +@ExtraFirstColumnValuesType @ExtraFirstColumnValuesTypeVal +@ExtraAddAverageRow @ExtraAddSumRow +@PluginsToLoad +/; +@MiscListOrder=('AddToFavourites','JavascriptDisabled','JavaEnabled','DirectorSupport','FlashSupport','RealPlayerSupport','QuickTimeSupport','WindowsMediaPlayerSupport','PDFSupport'); +%MiscListCalc=('TotalMisc'=>'','AddToFavourites'=>'u','JavascriptDisabled'=>'hm','JavaEnabled'=>'hm','DirectorSupport'=>'hm','FlashSupport'=>'hm','RealPlayerSupport'=>'hm','QuickTimeSupport'=>'hm','WindowsMediaPlayerSupport'=>'hm','PDFSupport'=>'hm'); +%OSFamily=('win'=>'Windows','mac'=>'Macintosh','linux'=>'Linux','bsd'=>'BSD'); +%BrowsersFamily=('msie'=>1,'firefox'=>2,'netscape'=>3,'svn'=>4); +@SessionsRange=('0s-30s','30s-2mn','2mn-5mn','5mn-15mn','15mn-30mn','30mn-1h','1h+'); +%SessionsAverage=('0s-30s',15,'30s-2mn',75,'2mn-5mn',210,'5mn-15mn',600,'15mn-30mn',1350,'30mn-1h',2700,'1h+',3600); +# HTTP-Accept or Lang parameter => AWStats code to use for lang +# ISO-639-1 or 2 or other => awstats-xx.txt where xx is ISO-639-1 +%LangBrowserToLangAwstats=( +'sq'=>'al','ar'=>'ar','ba'=>'ba','bg'=>'bg','zh-tw'=>'tw','zh'=>'cn','cs'=>'cz', +'de'=>'de','da'=>'dk', +'en'=>'en','et'=>'et','fi'=>'fi','fr'=>'fr','gl'=>'gl', +'es'=>'es','eu'=>'eu','ca'=>'ca', +'el'=>'gr','hu'=>'hu','is'=>'is','in'=>'id','it'=>'it', +'ja'=>'jp','kr'=>'ko','lv'=>'lv','nl'=>'nl','no'=>'nb','nb'=>'nb','nn'=>'nn', +'pl'=>'pl','pt'=>'pt','pt-br'=>'br','ro'=>'ro','ru'=>'ru','sr'=>'sr','sk'=>'sk', +'sv'=>'se','th'=>'th','tr'=>'tr','uk'=>'ua','cy'=>'cy','wlk'=>'cy' +); +%LangAWStatsToFlagAwstats=( # If flag (country ISO-3166 two letters) is not same than AWStats Lang code +'ca'=>'es_cat','et'=>'ee','eu'=>'es_eu', +'cy'=>'wlk', +'gl'=>'glg', +'he'=>'il', +'ko'=>'kr', +'ar'=>'sa', +'sr'=>'cs' +); +@HostAliases = @AllowAccessFromWebToFollowingAuthenticatedUsers=(); +@DefaultFile = @SkipDNSLookupFor = (); +@SkipHosts = @SkipUserAgents = @NotPageFiles = @SkipFiles = @SkipReferrers = (); +@OnlyHosts = @OnlyUserAgents = @OnlyFiles = (); +@URLWithQueryWithOnly = @URLWithQueryWithout = (); +@ExtraName = @ExtraCondition = @ExtraStatTypes = @MaxNbOfExtra = @MinHitExtra = (); +@ExtraFirstColumnTitle = @ExtraFirstColumnValues = @ExtraFirstColumnFunction = @ExtraFirstColumnFormat = (); +@ExtraCodeFilter = @ExtraConditionType = @ExtraConditionTypeVal = (); +@ExtraFirstColumnValuesType = @ExtraFirstColumnValuesTypeVal = (); +@ExtraAddAverageRow = @ExtraAddSumRow = (); +@PluginsToLoad = (); +# ---------- Init hash arrays -------- +use vars qw/ +%BrowsersHashIDLib %BrowsersHashIcon %BrowsersHereAreGrabbers +%DomainsHashIDLib +%MimeHashLib %MimeHashIcon %MimeHashFamily +%OSHashID %OSHashLib +%RobotsHashIDLib %RobotsAffiliateLib +%SearchEnginesHashID %SearchEnginesHashLib %SearchEnginesWithKeysNotInQuery %SearchEnginesKnownUrl %NotSearchEnginesKeys +%WormsHashID %WormsHashLib %WormsHashTarget +/; +use vars qw/ +%HTMLOutput %NoLoadPlugin %FilterIn %FilterEx +%BadFormatWarning +%MonthNumLib +%ValidHTTPCodes %ValidSMTPCodes +%TrapInfosForHTTPErrorCodes %NotPageList %DayBytes %DayHits %DayPages %DayVisits +%MaxNbOf %MinHit +%ListOfYears %HistoryAlreadyFlushed %PosInFile %ValueInFile +%val %nextval %egal +%TmpDNSLookup %TmpOS %TmpRefererServer %TmpRobot %TmpBrowser %MyDNSTable +/; +%HTMLOutput = %NoLoadPlugin = %FilterIn = %FilterEx = (); +%BadFormatWarning = (); +%MonthNumLib = (); +%ValidHTTPCodes = %ValidSMTPCodes = (); +%TrapInfosForHTTPErrorCodes=(); $TrapInfosForHTTPErrorCodes{404}=1; # TODO Add this in config file +%NotPageList=(); +%DayBytes = %DayHits = %DayPages = %DayVisits = (); +%MaxNbOf = %MinHit = (); +%ListOfYears = %HistoryAlreadyFlushed = %PosInFile = %ValueInFile = (); +%val = %nextval = %egal = (); +%TmpDNSLookup = %TmpOS = %TmpRefererServer = %TmpRobot = %TmpBrowser = %MyDNSTable = (); +use vars qw/ +%FirstTime %LastTime +%MonthHostsKnown %MonthHostsUnknown +%MonthUnique %MonthVisits +%MonthPages %MonthHits %MonthBytes +%MonthNotViewedPages %MonthNotViewedHits %MonthNotViewedBytes +%_session %_browser_h +%_domener_p %_domener_h %_domener_k %_errors_h %_errors_k +%_filetypes_h %_filetypes_k %_filetypes_gz_in %_filetypes_gz_out +%_host_p %_host_h %_host_k %_host_l %_host_s %_host_u +%_waithost_e %_waithost_l %_waithost_s %_waithost_u +%_keyphrases %_keywords %_os_h %_pagesrefs_p %_pagesrefs_h %_robot_h %_robot_k %_robot_l %_robot_r +%_worm_h %_worm_k %_worm_l %_login_h %_login_p %_login_k %_login_l %_screensize_h +%_misc_p %_misc_h %_misc_k +%_cluster_p %_cluster_h %_cluster_k +%_se_referrals_p %_se_referrals_h %_sider404_h %_referer404_h %_url_p %_url_k %_url_e %_url_x +%_unknownreferer_l %_unknownrefererbrowser_l +%_emails_h %_emails_k %_emails_l %_emailr_h %_emailr_k %_emailr_l +/; +&Init_HashArray(); +# ---------- Init Regex -------- +use vars qw/ $regclean1 $regclean2 $regdate /; +$regclean1=qr/<(recnb|\/td)>/i; +$regclean2=qr/<\/?[^<>]+>/i; +$regdate=qr/(\d\d\d\d)(\d\d)(\d\d)(\d\d)(\d\d)(\d\d)/; + +# ---------- Init Tie::hash arrays -------- +# Didn't find a tie that increase speed +#use Tie::StdHash; +#use Tie::Cache::LRU; +#tie %_host_p, 'Tie::StdHash'; +#tie %TmpOS, 'Tie::Cache::LRU'; + +# PROTOCOL CODES +use vars qw/ %httpcodelib %ftpcodelib %smtpcodelib /; + +# DEFAULT MESSAGE +use vars qw/ @Message /; +@Message=( +'Unknown', +'Unknown (unresolved ip)', +'Others', +'View details', +'Day', +'Month', +'Year', +'Statistics for', +'First visit', +'Last visit', +'Number of visits', +'Unique visitors', +'Visit', +'different keywords', +'Search', +'Percent', +'Traffic', +'Domains/Countries', +'Visitors', +'Pages-URL', +'Hours', +'Browsers', +'', +'Referers', +'Never updated (See \'Build/Update\' on awstats_setup.html page)', +'Visitors domains/countries', +'hosts', +'pages', +'different pages-url', +'Viewed', +'Other words', +'Pages not found', +'HTTP Error codes', +'Netscape versions', +'IE versions', +'Last Update', +'Connect to site from', +'Origin', +'Direct address / Bookmarks', +'Origin unknown', +'Links from an Internet Search Engine', +'Links from an external page (other web sites except search engines)', +'Links from an internal page (other page on same site)', +'Keyphrases used on search engines', +'Keywords used on search engines', +'Unresolved IP Address', +'Unknown OS (Referer field)', +'Required but not found URLs (HTTP code 404)', +'IP Address', +'Error Hits', +'Unknown browsers (Referer field)', +'different robots', +'visits/visitor', +'Robots/Spiders visitors', +'Free realtime logfile analyzer for advanced web statistics', +'of', +'Pages', +'Hits', +'Versions', +'Operating Systems', +'Jan', +'Feb', +'Mar', +'Apr', +'May', +'Jun', +'Jul', +'Aug', +'Sep', +'Oct', +'Nov', +'Dec', +'Navigation', +'File type', +'Update now', +'Bandwidth', +'Back to main page', +'Top', +'dd mmm yyyy - HH:MM', +'Filter', +'Full list', +'Hosts', +'Known', +'Robots', +'Sun', +'Mon', +'Tue', +'Wed', +'Thu', +'Fri', +'Sat', +'Days of week', +'Who', +'When', +'Authenticated users', +'Min', +'Average', +'Max', +'Web compression', +'Bandwidth saved', +'Compression on', +'Compression result', +'Total', +'different keyphrases', +'Entry', +'Code', +'Average size', +'Links from a NewsGroup', +'KB', +'MB', +'GB', +'Grabber', +'Yes', +'No', +'Info.', +'OK', +'Exit', +'Visits duration', +'Close window', +'Bytes', +'Search Keyphrases', +'Search Keywords', +'different refering search engines', +'different refering sites', +'Other phrases', +'Other logins (and/or anonymous users)', +'Refering search engines', +'Refering sites', +'Summary', +'Exact value not available in "Year" view', +'Data value arrays', +'Sender EMail', +'Receiver EMail', +'Reported period', +'Extra/Marketing', +'Screen sizes', +'Worm/Virus attacks', +'Add to favorites (estimated)', +'Days of month', +'Miscellaneous', +'Browsers with Java support', +'Browsers with Macromedia Director Support', +'Browsers with Flash Support', +'Browsers with Real audio playing support', +'Browsers with Quictime audio playing support', +'Browsers with Windows Media audio playing support', +'Browsers with PDF support', +'SMTP Error codes', +'Countries', +'Mails', +'Size', +'First', +'Last', +'Exclude filter', +'Codes shown here gave hits or traffic "not viewed" by visitors, so they are not included in other charts.', +'Cluster', +'Robots shown here gave hits or traffic "not viewed" by visitors, so they are not included in other charts.', +'Numbers after + are successful hits on "robots.txt" files', +'Worms shown here gave hits or traffic "not viewed" by visitors, so thay are not included in other charts.', +'Not viewed traffic includes traffic generated by robots, worms, or replies with special HTTP status codes.', +'Traffic viewed', +'Traffic not viewed', +'Monthly history', +'Worms', +'different worms', +'Mails successfully sent', +'Mails failed/refused', +'Sensitive targets', +'Javascript disabled', +'Created by', +'plugins', +'Regions', +'Cities' +); + + + +#------------------------------------------------------------------------------ +# Functions +#------------------------------------------------------------------------------ + +# Function to solve pb with openvms +sub file_filt (@) { + my @retval; + foreach my $fl (@_) { + $fl =~ tr/^//d; + push @retval, $fl; + } + return sort @retval; +} + +#------------------------------------------------------------------------------ +# Function: Write on output header of HTTP answer +# Parameters: None +# Input: $HeaderHTTPSent $BuildReportFormat $PageCode $Expires +# Output: $HeaderHTTPSent=1 +# Return: None +#------------------------------------------------------------------------------ +sub http_head { + if (! $HeaderHTTPSent) { + if ($BuildReportFormat eq 'xhtml' || $BuildReportFormat eq 'xml') { print ($ENV{'HTTP_USER_AGENT'}=~/MSIE|Googlebot/i?"Content-type: text/html; charset=$PageCode\n":"Content-type: text/xml; charset=$PageCode\n"); } + else { print "Content-type: text/html; charset=$PageCode\n"; } + + # Expires must be GMT ANSI asctime and must be after Content-type to avoid pb with some servers (SAMBAR) + if ($Expires =~ /^\d+$/) { + print "Cache-Control: public\n"; + print "Last-Modified: ".gmtime($starttime)."\n"; + print "Expires: ".(gmtime($starttime+$Expires))."\n"; + } + print "\n"; + } + $HeaderHTTPSent++;; +} + +#------------------------------------------------------------------------------ +# Function: Write on output header of HTML page +# Parameters: None +# Input: %HTMLOutput $PluginMode $Expires $Lang $StyleSheet $HTMLHeadSection $PageCode $PageDir +# Output: $HeaderHTMLSent=1 +# Return: None +#------------------------------------------------------------------------------ +sub html_head { + my $dir=$PageDir?'right':'left'; + if (scalar keys %HTMLOutput || $PluginMode) { + my $MetaRobot=0; # meta robots + my $periodtitle=" ($YearRequired"; + $periodtitle.=($MonthRequired ne 'all'?"-$MonthRequired":""); + $periodtitle.=($DayRequired ne ''?"-$DayRequired":""); + $periodtitle.=($HourRequired ne ''?"-$HourRequired":""); + $periodtitle.=")"; + # Write head section + if ($BuildReportFormat eq 'xhtml' || $BuildReportFormat eq 'xml') { + if ($PageCode) { print "\n"; } + else { print "\n"; }; + if ($FrameName ne 'index') { print "\n"; } + else { print "\n"; } + print "\n"; + } else { + if ($FrameName ne 'index') { print "\n"; } + else { print "\n"; } + print "\n"; + } + print "\n"; + + my $endtag='>'; + if ($BuildReportFormat eq 'xhtml' || $BuildReportFormat eq 'xml') { $endtag=' />'; } + + # Affiche tag meta generator + print "\n":"$Message[7] $SiteDomain$periodtitle\n"; + if ($FrameName ne 'index') + { + + if ($StyleSheet) { + print "\n"; + } + + # A STYLE section must be in head section. Do not use " for number in a style section + print "\n"; + } + + print "\n\n"; + if ($FrameName ne 'index') { + print "\n"; + } + } + $HeaderHTMLSent++; +} + +#------------------------------------------------------------------------------ +# Function: Write on output end of HTML page +# Parameters: 0|1 (0=no list plugins,1=list plugins) +# Input: %HTMLOutput $HTMLEndSection $FrameName $BuildReportFormat +# Output: None +# Return: None +#------------------------------------------------------------------------------ +sub html_end { + my $listplugins=shift||0; + if (scalar keys %HTMLOutput) { + + # Call to plugins' function AddHTMLBodyFooter + foreach my $pluginname (keys %{$PluginsLoaded{'AddHTMLBodyFooter'}}) { +# my $function="AddHTMLBodyFooter_$pluginname()"; +# eval("$function"); + my $function="AddHTMLBodyFooter_$pluginname"; + &$function(); + } + + if ($FrameName ne 'index' && $FrameName ne 'mainleft') { + print "$Center

\n"; + print ""; + print "Advanced Web Statistics $VERSION - "; + print $Message[169]." $PROG"; + if ($listplugins) { + my $atleastoneplugin=0; + foreach my $pluginname (keys %{$PluginsLoaded{'init'}}) { + if (! $atleastoneplugin) { $atleastoneplugin=1; print " ($Message[170]: "; } + else { print ", "; } + print "$pluginname"; + } + if ($atleastoneplugin) { print ")"; } + } + print "
\n"; + if ($HTMLEndSection) { print "
\n$HTMLEndSection\n"; } + } + print "\n"; + if ($FrameName ne 'index') { + if ($FrameName ne 'mainleft' && $BuildReportFormat eq 'html') { print "
\n"; } + print "\n"; + } + print "\n"; +# print "\n"; + } +} + +#------------------------------------------------------------------------------ +# Function: Print on stdout tab header of a chart +# Parameters: $title $tooltipnb [$width percentage of chart title] +# Input: None +# Output: None +# Return: None +#------------------------------------------------------------------------------ +sub tab_head { + my $title=shift; + my $tooltipnb=shift; + my $width=shift||70; + my $class=shift; + if ($width == 70 && $QueryString =~ /buildpdf/i) { print "\n"; } + else { print "
\n"; } + + if ($tooltipnb) { + print ""; + } + else { + print ""; + } + print "\n"; + print "
$title
$title  
\n"; + if ($width == 70 && $QueryString =~ /buildpdf/i) { print "\n"; } + else { print "
\n"; } +} + +#------------------------------------------------------------------------------ +# Function: Print on stdout tab ender of a chart +# Parameters: None +# Input: None +# Output: None +# Return: None +#------------------------------------------------------------------------------ +sub tab_end { + my $string=shift; + print "
"; + if ($string) { print "$string
\n"; } + print "
\n\n"; +} + +#------------------------------------------------------------------------------ +# Function: Write error message and exit +# Parameters: $message $secondmessage $thirdmessage $donotshowsetupinfo +# Input: $HeaderHTTPSent $HeaderHTMLSent %HTMLOutput $LogSeparator $LogFormat +# Output: None +# Return: None +#------------------------------------------------------------------------------ +sub error { + my $message=shift||''; if (scalar keys %HTMLOutput) { $message =~ s/\/>/g; } + my $secondmessage=shift||''; + my $thirdmessage=shift||''; + my $donotshowsetupinfo=shift||0; + + if (! $HeaderHTTPSent && $ENV{'GATEWAY_INTERFACE'}) { http_head(); } + if (! $HeaderHTMLSent && scalar keys %HTMLOutput) { print "\n"; $HeaderHTMLSent=1; } + if ($Debug) { debug("$message $secondmessage $thirdmessage",1); } + my $tagbold=''; my $tagunbold=''; my $tagbr=''; my $tagfontred=''; my $tagfontgrey=''; my $tagunfont=''; + if (scalar keys %HTMLOutput) { + $tagbold=''; $tagunbold=''; $tagbr='
'; + $tagfontred=''; + $tagfontgrey=''; + $tagunfont=''; + } + if (! $ErrorMessages && $message =~ /^Format error$/i) { + # Files seems to have bad format + if (scalar keys %HTMLOutput) { print "

\n"; } + if ($message !~ $LogSeparator) { + # Bad LogSeparator parameter + print "${tagfontred}AWStats did not found the ${tagbold}LogSeparator${tagunbold} in your log records.${tagbr}${tagunfont}\n"; + } + else { + # Bad LogFormat parameter + print "AWStats did not find any valid log lines that match your ${tagbold}LogFormat${tagunbold} parameter, in the ${NbOfLinesForCorruptedLog}th first non commented lines read of your log.${tagbr}\n"; + print "${tagfontred}Your log file ${tagbold}$thirdmessage${tagunbold} must have a bad format or ${tagbold}LogFormat${tagunbold} parameter setup does not match this format.${tagbr}${tagbr}${tagunfont}\n"; + print "Your AWStats ${tagbold}LogFormat${tagunbold} parameter is:\n"; + print "${tagbold}$LogFormat${tagunbold}${tagbr}\n"; + print "This means each line in your web server log file need to have "; + if ($LogFormat == 1) { + print "${tagbold}\"combined log format\"${tagunbold} like this:${tagbr}\n"; + print (scalar keys %HTMLOutput?"$tagfontgrey":""); + print "111.22.33.44 - - [10/Jan/2001:02:14:14 +0200] \"GET / HTTP/1.1\" 200 1234 \"http://www.fromserver.com/from.htm\" \"Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0)\"\n"; + print (scalar keys %HTMLOutput?"$tagunfont${tagbr}${tagbr}\n":""); + } + if ($LogFormat == 2) { + print "${tagbold}\"MSIE Extended W3C log format\"${tagunbold} like this:${tagbr}\n"; + print (scalar keys %HTMLOutput?"$tagfontgrey":""); + print "date time c-ip c-username cs-method cs-uri-sterm sc-status sc-bytes cs-version cs(User-Agent) cs(Referer)\n"; + print (scalar keys %HTMLOutput?"$tagunfont${tagbr}${tagbr}\n":""); + } + if ($LogFormat == 3) { + print "${tagbold}\"WebStar native log format\"${tagunbold}${tagbr}\n"; + } + if ($LogFormat == 4) { + print "${tagbold}\"common log format\"${tagunbold} like this:${tagbr}\n"; + print (scalar keys %HTMLOutput?"$tagfontgrey":""); + print "111.22.33.44 - - [10/Jan/2001:02:14:14 +0200] \"GET / HTTP/1.1\" 200 1234\n"; + print (scalar keys %HTMLOutput?"$tagunfont${tagbr}${tagbr}\n":""); + } + if ($LogFormat == 6) { + print "${tagbold}\"Lotus Notes/Lotus Domino\"${tagunbold}${tagbr}\n"; + print (scalar keys %HTMLOutput?"$tagfontgrey":""); + print "111.22.33.44 - Firstname Middlename Lastname [10/Jan/2001:02:14:14 +0200] \"GET / HTTP/1.1\" 200 1234 \"http://www.fromserver.com/from.htm\" \"Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0)\"\n"; + print (scalar keys %HTMLOutput?"
${tagbr}${tagbr}\n":""); + } + if ($LogFormat !~ /^[1-6]$/) { + print "the following personalized log format:${tagbr}\n"; + print (scalar keys %HTMLOutput?"$tagfontgrey":""); + print "$LogFormat\n"; + print (scalar keys %HTMLOutput?"$tagunfont${tagbr}${tagbr}\n":""); + } + print "And this is an example of records AWStats found in your log file (the record number $NbOfLinesForCorruptedLog in your log):\n"; + print (scalar keys %HTMLOutput?"
$tagfontgrey":""); + print "$secondmessage"; + print (scalar keys %HTMLOutput?"$tagunfont${tagbr}${tagbr}":""); + print "\n"; + } + #print "Note: If your $NbOfLinesForCorruptedLog first lines in your log files are wrong because of "; + #print "a worm virus attack, you can increase the NbOfLinesForCorruptedLog parameter in config file.\n"; + #print "\n"; + } + else { + print (scalar keys %HTMLOutput?"
$tagfontred\n":""); + print ($ErrorMessages?"$ErrorMessages":"Error: $message"); + print (scalar keys %HTMLOutput?"\n
":""); + print "\n"; + } + if (! $ErrorMessages && ! $donotshowsetupinfo) { + if ($message =~ /Couldn.t open config file/i) { + my $dir=$DIR; + if ($dir =~ /^\./) { $dir.='/../..'; } + else { $dir =~ s/[\\\/]?wwwroot[\/\\]cgi-bin[\\\/]?//; } + print "${tagbr}\n"; + if ($ENV{'GATEWAY_INTERFACE'}) { + print "- ${tagbold}Did you use the correct URL ?${tagunbold}${tagbr}\n"; + print "Example: http://localhost/awstats/awstats.pl?config=mysite${tagbr}\n"; + print "Example: http://127.0.0.1/cgi-bin/awstats.pl?config=mysite${tagbr}\n"; + } else { + print "- ${tagbold}Did you use correct config parameter ?${tagunbold}${tagbr}\n"; + print "Example: If your config file is awstats.mysite.conf, use -config=mysite\n"; + } + print "- ${tagbold}Did you create your config file 'awstats.$SiteConfig.conf' ?${tagunbold}${tagbr}\n"; + print "If not, you can run \"awstats_configure.pl\"\nfrom command line, or create it manually.${tagbr}\n"; + print "${tagbr}\n"; + } + else { print "${tagbr}${tagbold}Setup (".($FileConfig?"'".$FileConfig."'":"Config")." file, web server or permissions) may be wrong.${tagunbold}${tagbr}\n"; } + print "Check config file, permissions and AWStats documentation (in 'docs' directory).\n"; + } + # Remove lock if not a lock message + if ($EnableLockForUpdate && $message !~ /lock file/) { &Lock_Update(0); } + if (scalar keys %HTMLOutput) { print "\n"; } + exit 1; +} + +#------------------------------------------------------------------------------ +# Function: Write a warning message +# Parameters: $message +# Input: $HeaderHTTPSent $HeaderHTMLSent $WarningMessage %HTMLOutput +# Output: None +# Return: None +#------------------------------------------------------------------------------ +sub warning { + my $messagestring=shift; + + if ($Debug) { debug("$messagestring",1); } + if ($WarningMessages) { + if (! $HeaderHTTPSent && $ENV{'GATEWAY_INTERFACE'}) { http_head(); } + if (! $HeaderHTMLSent) { html_head(); } + if (scalar keys %HTMLOutput) { + $messagestring =~ s/\n/\/g; + print "$messagestring
\n"; + } + else { + print "$messagestring\n"; + } + } +} + +#------------------------------------------------------------------------------ +# Function: Write debug message and exit +# Parameters: $string $level +# Input: %HTMLOutput $Debug=required level $DEBUGFORCED=required level forced +# Output: None +# Return: None +#------------------------------------------------------------------------------ +sub debug { + my $level = $_[1] || 1; + + if (! $HeaderHTTPSent && $ENV{'GATEWAY_INTERFACE'}) { http_head(); } # To send the HTTP header and see debug + if ($level <= $DEBUGFORCED) { + my $debugstring = $_[0]; + if (! $DebugResetDone) { open(DEBUGFORCEDFILE,"debug.log"); close DEBUGFORCEDFILE; chmod 0666,"debug.log"; $DebugResetDone=1; } + open(DEBUGFORCEDFILE,">>debug.log"); + print DEBUGFORCEDFILE localtime(time)." - $$ - DEBUG $level - $debugstring\n"; + close DEBUGFORCEDFILE; + } + if ($DebugMessages && $level <= $Debug) { + my $debugstring = $_[0]; + if (scalar keys %HTMLOutput) { $debugstring =~ s/^ /   /; $debugstring .= "
"; } + print localtime(time)." - DEBUG $level - $debugstring\n"; + } +} + +#------------------------------------------------------------------------------ +# Function: Optimize an array removing duplicate entries +# Parameters: @Array notcasesensitive=0|1 +# Input: None +# Output: None +# Return: None +#------------------------------------------------------------------------------ +sub OptimizeArray { + my $array=shift; + my @arrayunreg=map{if (/\(\?[-\w]*:(.*)\)/) { $1 } } @$array; + my $notcasesensitive=shift; + my $searchlist=0; + if ($Debug) { debug("OptimizeArray (notcasesensitive=$notcasesensitive)",4); } + while ($searchlist>-1 && @arrayunreg) { + my $elemtoremove=-1; + OPTIMIZELOOP: + foreach my $i ($searchlist..(scalar @arrayunreg)-1) { + # Search if $i elem is already treated by another elem + foreach my $j (0..(scalar @arrayunreg)-1) { + if ($i == $j) { next; } + my $parami=$notcasesensitive?lc($arrayunreg[$i]):$arrayunreg[$i]; + my $paramj=$notcasesensitive?lc($arrayunreg[$j]):$arrayunreg[$j]; + if ($Debug) { debug(" Compare $i ($parami) to $j ($paramj)",4); } + if (index($parami,$paramj)>-1) { + if ($Debug) { debug(" Elem $i ($arrayunreg[$i]) already treated with elem $j ($arrayunreg[$j])",4); } + $elemtoremove=$i; + last OPTIMIZELOOP; + } + } + } + if ($elemtoremove > -1) { + if ($Debug) { debug(" Remove elem $elemtoremove - $arrayunreg[$elemtoremove]",4); } + splice @arrayunreg, $elemtoremove, 1; + $searchlist=$elemtoremove; + } + else { + $searchlist=-1; + } + } + if ($notcasesensitive) { return map{qr/$_/i} @arrayunreg; } + return map{qr/$_/} @arrayunreg; +} + +#------------------------------------------------------------------------------ +# Function: Check if parameter is in SkipDNSLookupFor array +# Parameters: ip @SkipDNSLookupFor (a NOT case sensitive precompiled regex array) +# Return: 0 Not found, 1 Found +#------------------------------------------------------------------------------ +sub SkipDNSLookup { + foreach (@SkipDNSLookupFor) { if ($_[0] =~ /$_/) { return 1; } } + 0; # Not in @SkipDNSLookupFor +} + +#------------------------------------------------------------------------------ +# Function: Check if parameter is in SkipHosts array +# Parameters: host @SkipHosts (a NOT case sensitive precompiled regex array) +# Return: 0 Not found, 1 Found +#------------------------------------------------------------------------------ +sub SkipHost { + foreach (@SkipHosts) { if ($_[0] =~ /$_/) { return 1; } } + 0; # Not in @SkipHosts +} + +#------------------------------------------------------------------------------ +# Function: Check if parameter is in SkipReferrers array +# Parameters: host @SkipReferrers (a NOT case sensitive precompiled regex array) +# Return: 0 Not found, 1 Found +#------------------------------------------------------------------------------ +sub SkipReferrer { + foreach (@SkipReferrers) { if ($_[0] =~ /$_/) { return 1; } } + 0; # Not in @SkipReferrers +} + +#------------------------------------------------------------------------------ +# Function: Check if parameter is in SkipUserAgents array +# Parameters: useragent @SkipUserAgents (a NOT case sensitive precompiled regex array) +# Return: 0 Not found, 1 Found +#------------------------------------------------------------------------------ +sub SkipUserAgent { + foreach (@SkipUserAgents) { if ($_[0] =~ /$_/) { return 1; } } + 0; # Not in @SkipUserAgent +} + +#------------------------------------------------------------------------------ +# Function: Check if parameter is in SkipFiles array +# Parameters: url @SkipFiles (a NOT case sensitive precompiled regex array) +# Return: 0 Not found, 1 Found +#------------------------------------------------------------------------------ +sub SkipFile { + foreach (@SkipFiles) { if ($_[0] =~ /$_/) { return 1; } } + 0; # Not in @SkipFiles +} + +#------------------------------------------------------------------------------ +# Function: Check if parameter is in OnlyHosts array +# Parameters: host @OnlyHosts (a NOT case sensitive precompiled regex array) +# Return: 0 Not found, 1 Found +#------------------------------------------------------------------------------ +sub OnlyHost { + foreach (@OnlyHosts) { if ($_[0] =~ /$_/) { return 1; } } + 0; # Not in @OnlyHosts +} + +#------------------------------------------------------------------------------ +# Function: Check if parameter is in OnlyUserAgents array +# Parameters: useragent @OnlyUserAgents (a NOT case sensitive precompiled regex array) +# Return: 0 Not found, 1 Found +#------------------------------------------------------------------------------ +sub OnlyUserAgent { + foreach (@OnlyUserAgents) { if ($_[0] =~ /$_/) { return 1; } } + 0; # Not in @OnlyHosts +} + +#------------------------------------------------------------------------------ +# Function: Check if parameter is in NotPageFiles array +# Parameters: url @NotPageFiles (a NOT case sensitive precompiled regex array) +# Return: 0 Not found, 1 Found +#------------------------------------------------------------------------------ +sub NotPageFile { + foreach (@NotPageFiles) { if ($_[0] =~ /$_/) { return 1; } } + 0; # Not in @NotPageFiles +} + +#------------------------------------------------------------------------------ +# Function: Check if parameter is in OnlyFiles array +# Parameters: url @OnlyFiles (a NOT case sensitive precompiled regex array) +# Return: 0 Not found, 1 Found +#------------------------------------------------------------------------------ +sub OnlyFile { + foreach (@OnlyFiles) { if ($_[0] =~ /$_/) { return 1; } } + 0; # Not in @OnlyFiles +} + +#------------------------------------------------------------------------------ +# Function: Return day of week of a day +# Parameters: $day $month $year +# Return: 0-6 +#------------------------------------------------------------------------------ +sub DayOfWeek { + my ($day, $month, $year) = @_; + if ($Debug) { debug("DayOfWeek for $day $month $year",4); } + if ($month < 3) { $month += 10; $year--; } + else { $month -= 2; } + my $cent = sprintf("%1i",($year/100)); + my $y = ($year % 100); + my $dw = (sprintf("%1i",(2.6*$month)-0.2) + $day + $y + sprintf("%1i",($y/4)) + sprintf("%1i",($cent/4)) - (2*$cent)) % 7; + $dw += 7 if ($dw<0); + if ($Debug) { debug(" is $dw",4); } + return $dw; +} + +#------------------------------------------------------------------------------ +# Function: Return 1 if a date exists +# Parameters: $day $month $year +# Return: 1 if date exists else 0 +#------------------------------------------------------------------------------ +sub DateIsValid { + my ($day, $month, $year) = @_; + if ($Debug) { debug("DateIsValid for $day $month $year",4); } + if ($day < 1) { return 0; } + if ($day > 31) { return 0; } + if ($month==4 || $month==6 || $month==9 || $month==11) { + if ($day > 30) { return 0; } + } + elsif ($month==2) { + my $leapyear=($year%4==0?1:0); # A leap year every 4 years + if ($year%100==0 && $year%400!=0) { $leapyear=0; } # Except if year is 100x and not 400x + if ($day > (28+$leapyear)) { return 0; } + } + return 1; +} + +#------------------------------------------------------------------------------ +# Function: Return string of visit duration +# Parameters: $starttime $endtime +# Input: None +# Output: None +# Return: A string that identify the visit duration range +#------------------------------------------------------------------------------ +sub GetSessionRange { + my $starttime = my $endtime; + if (shift =~ /$regdate/o) { $starttime = Time::Local::timelocal($6,$5,$4,$3,$2-1,$1); } + if (shift =~ /$regdate/o) { $endtime = Time::Local::timelocal($6,$5,$4,$3,$2-1,$1); } + my $delay=$endtime-$starttime; + if ($Debug) { debug("GetSessionRange $endtime - $starttime = $delay",4); } + if ($delay <= 30) { return $SessionsRange[0]; } + if ($delay <= 120) { return $SessionsRange[1]; } + if ($delay <= 300) { return $SessionsRange[2]; } + if ($delay <= 900) { return $SessionsRange[3]; } + if ($delay <= 1800) { return $SessionsRange[4]; } + if ($delay <= 3600) { return $SessionsRange[5]; } + return $SessionsRange[6]; +} + +#------------------------------------------------------------------------------ +# Function: Read config file +# Parameters: None or configdir to scan +# Input: $DIR $PROG $SiteConfig +# Output: Global variables +# Return: - +#------------------------------------------------------------------------------ +sub Read_Config { + # Check config file in common possible directories : + # Windows : "$DIR" (same dir than awstats.pl) + # Standard, Mandrake and Debian package : "/etc/awstats" + # Other possible directories : "/usr/local/etc/awstats", "/etc" + # FHS standard, Suse package : "/etc/opt/awstats" + my $configdir=shift; + my @PossibleConfigDir=(); + + if ($configdir) + { + # If from CGI, overwriting of configdir is only possible if AWSTATS_ENABLE_CONFIG_DIR defined + if ($ENV{'GATEWAY_INTERFACE'} && ! $ENV{"AWSTATS_ENABLE_CONFIG_DIR"}) + { + error("Sorry, to allow overwriting of configdir parameter from an AWStats CGI usage, environment variable AWSTATS_ENABLE_CONFIG_DIR must be set to 1"); + } + else + { + @PossibleConfigDir=("$configdir"); + } + } + else { @PossibleConfigDir=("$DIR","/etc/awstats","/usr/local/etc/awstats","/etc","/etc/opt/awstats"); } + + # Open config file + $FileConfig=$FileSuffix=''; + foreach (@PossibleConfigDir) { + my $searchdir=$_; + if ($searchdir && $searchdir !~ /[\\\/]$/) { $searchdir .= "/"; } + if (open(CONFIG,"$searchdir$PROG.$SiteConfig.conf")) { $FileConfig="$searchdir$PROG.$SiteConfig.conf"; $FileSuffix=".$SiteConfig"; last; } + if (open(CONFIG,"$searchdir$PROG.conf")) { $FileConfig="$searchdir$PROG.conf"; $FileSuffix=''; last; } + } + if (! $FileConfig) { error("Couldn't open config file \"$PROG.$SiteConfig.conf\" nor \"$PROG.conf\" after searching in path \"".join(',',@PossibleConfigDir)."\": $!"); } + + # Analyze config file content and close it + &Parse_Config( *CONFIG , 1 , $FileConfig); + close CONFIG; + + # If parameter NotPageList not found, init for backward compatibility + if (! $FoundNotPageList) { + %NotPageList=('css'=>1,'js'=>1,'class'=>1,'gif'=>1,'jpg'=>1,'jpeg'=>1,'png'=>1,'bmp'=>1,'ico'=>1,'swf'=>1); + } + # If parameter ValidHTTPCodes empty, init for backward compatibility + if (! scalar keys %ValidHTTPCodes) { $ValidHTTPCodes{"200"}=$ValidHTTPCodes{"304"}=1; } + # If parameter ValidSMTPCodes empty, init for backward compatibility + if (! scalar keys %ValidSMTPCodes) { $ValidSMTPCodes{"1"}=$ValidSMTPCodes{"250"}=1; } +} + +#------------------------------------------------------------------------------ +# Function: Parse content of a config file +# Parameters: opened file handle, depth level, file name +# Input: - +# Output: Global variables +# Return: - +#------------------------------------------------------------------------------ +sub Parse_Config { + my ( $confighandle ) = $_[0]; + my $level = $_[1]; + my $configFile = $_[2]; + my $versionnum=0; + my $conflinenb=0; + + if ($level > 10) { error("$PROG can't read down more than 10 level of includes. Check that no 'included' config files include their parent config file (this cause infinite loop)."); } + + while (<$confighandle>) { + chomp $_; s/\r//; + $conflinenb++; + + # Extract version from first line + if (! $versionnum && $_ =~ /^# AWSTATS CONFIGURE FILE (\d+).(\d+)/i) { + $versionnum=($1*1000)+$2; + #if ($Debug) { debug(" Configure file version is $versionnum",1); } + next; + } + + if ($_ =~ /^\s*$/) { next; } + + # Check includes + if ($_ =~ /^Include "([^\"]+)"/ || $_ =~ /^#include "([^\"]+)"/) { # #include kept for backward compatibility + my $includeFile = $1; + # Expand __var__ by values + while ($includeFile =~ /__([^\s_]+(?:_[^\s_]+)*)__/) { + my $var=$1; $includeFile =~ s/__${var}__/$ENV{$var}/g; + } + if ($Debug) { debug("Found an include : $includeFile",2); } + if ( $includeFile !~ /^[\\\/]/ ) { + # Correct relative include files + if ($FileConfig =~ /^(.*[\\\/])[^\\\/]*$/) { $includeFile = "$1$includeFile"; } + } + if ($level > 1) { + warning("Warning: Perl versions before 5.6 cannot handle nested includes"); + next; + } + if ( open( CONFIG_INCLUDE, $includeFile ) ) { + &Parse_Config( *CONFIG_INCLUDE , $level+1, $includeFile); + close( CONFIG_INCLUDE ); + } + else { + error("Could not open include file: $includeFile" ); + } + next; + } + + # Remove comments + if ($_ =~ /^\s*#/) { next; } + $_ =~ s/\s#.*$//; + + # Extract param and value + my ($param,$value)=split(/=/,$_,2); + $param =~ s/^\s+//; $param =~ s/\s+$//; + + # If not a param=value, try with next line + if (! $param) { warning("Warning: Syntax error line $conflinenb in file '$configFile'. Config line is ignored."); next; } + if (! defined $value) { warning("Warning: Syntax error line $conflinenb in file '$configFile'. Config line is ignored."); next; } + + if ($value) { + $value =~ s/^\s+//; $value =~ s/\s+$//; + $value =~ s/^\"//; $value =~ s/\";?$//; + # Replace __MONENV__ with value of environnement variable MONENV + # Must be able to replace __VAR_1____VAR_2__ + while ($value =~ /__([^\s_]+(?:_[^\s_]+)*)__/) { my $var=$1; $value =~ s/__${var}__/$ENV{$var}/g; } + } + + # Initialize parameter for (param,value) + if ($param =~ /^LogFile/) { + if ($QueryString !~ /logfile=([^\s&]+)/i) { $LogFile=$value; } + next; + } + if ($param =~ /^DirIcons/) { + if ($QueryString !~ /diricons=([^\s&]+)/i) { $DirIcons=$value; } + next; + } + if ($param =~ /^SiteDomain/) { + # No regex test as SiteDomain is always exact value + $SiteDomain=$value; + next; + } + if ($param =~ /^HostAliases/) { + @HostAliases=(); + foreach my $elem (split(/\s+/,$value)) { + if ($elem =~ s/^\@//) { # If list of hostaliases in a file + open(DATAFILE,"<$elem") || error("Failed to open file '$elem' declared in HostAliases parameter"); + my @val=map(/^(.*)$/i,); + push @HostAliases, map{qr/^$_$/i} @val; + close(DATAFILE); + } + else { + if ($elem =~ /^REGEX\[(.*)\]$/i) { $elem=$1; } + else { $elem='^'.quotemeta($elem).'$'; } + if ($elem) { push @HostAliases, qr/$elem/i; } + } + } + next; + } + # Special optional setup params + if ($param =~ /^SkipDNSLookupFor/) { + @SkipDNSLookupFor=(); + foreach my $elem (split(/\s+/,$value)) { + if ($elem =~ /^REGEX\[(.*)\]$/i) { $elem=$1; } + else { $elem='^'.quotemeta($elem).'$'; } + if ($elem) { push @SkipDNSLookupFor, qr/$elem/i; } + } + next; + } + if ($param =~ /^AllowAccessFromWebToFollowingAuthenticatedUsers/) { + @AllowAccessFromWebToFollowingAuthenticatedUsers=(); + foreach (split(/\s+/,$value)) { push @AllowAccessFromWebToFollowingAuthenticatedUsers,$_; } + next; + } + if ($param =~ /^DefaultFile/) { + @DefaultFile=(); + foreach my $elem (split(/\s+/,$value)) { + # No REGEX for this option + #if ($elem =~ /^REGEX\[(.*)\]$/i) { $elem=$1; } + #else { $elem='^'.quotemeta($elem).'$'; } + if ($elem) { push @DefaultFile,$elem; } + } + next; + } + if ($param =~ /^SkipHosts/) { + @SkipHosts=(); + foreach my $elem (split(/\s+/,$value)) { + if ($elem =~ /^REGEX\[(.*)\]$/i) { $elem=$1; } + else { $elem='^'.quotemeta($elem).'$'; } + if ($elem) { push @SkipHosts, qr/$elem/i; } + } + next; + } + if ($param =~ /^SkipReferrersBlackList/ && $value) { + open (BLACKLIST, "<$value") || die "Failed to open blacklist: $!\n"; + while () { + chomp; + my $elem = $_; + $elem =~ s/ //; + $elem =~ s/\#.*//; + if ($elem) { push @SkipReferrers, qr/$elem/i; } + } + next; + close (BLACKLIST); + } + if ($param =~ /^SkipUserAgents/) { + @SkipUserAgents=(); + foreach my $elem (split(/\s+/,$value)) { + if ($elem =~ /^REGEX\[(.*)\]$/i) { $elem=$1; } + else { $elem='^'.quotemeta($elem).'$'; } + if ($elem) { push @SkipUserAgents, qr/$elem/i; } + } + next; + } + if ($param =~ /^SkipFiles/) { + @SkipFiles=(); + foreach my $elem (split(/\s+/,$value)) { + if ($elem =~ /^REGEX\[(.*)\]$/i) { $elem=$1; } + else { $elem='^'.quotemeta($elem).'$'; } + if ($elem) { push @SkipFiles, qr/$elem/i; } + } + next; + } + if ($param =~ /^OnlyHosts/) { + @OnlyHosts=(); + foreach my $elem (split(/\s+/,$value)) { + if ($elem =~ /^REGEX\[(.*)\]$/i) { $elem=$1; } + else { $elem='^'.quotemeta($elem).'$'; } + if ($elem) { push @OnlyHosts, qr/$elem/i; } + } + next; + } + if ($param =~ /^OnlyUserAgents/) { + @OnlyUserAgents=(); + foreach my $elem (split(/\s+/,$value)) { + if ($elem =~ /^REGEX\[(.*)\]$/i) { $elem=$1; } + else { $elem='^'.quotemeta($elem).'$'; } + if ($elem) { push @OnlyUserAgents, qr/$elem/i; } + } + next; + } + if ($param =~ /^OnlyFiles/) { + @OnlyFiles=(); + foreach my $elem (split(/\s+/,$value)) { + if ($elem =~ /^REGEX\[(.*)\]$/i) { $elem=$1; } + else { $elem='^'.quotemeta($elem).'$'; } + if ($elem) { push @OnlyFiles, qr/$elem/i; } + } + next; + } + if ($param =~ /^NotPageFiles/) { + @NotPageFiles=(); + foreach my $elem (split(/\s+/,$value)) { + if ($elem =~ /^REGEX\[(.*)\]$/i) { $elem=$1; } + else { $elem='^'.quotemeta($elem).'$'; } + if ($elem) { push @NotPageFiles, qr/$elem/i; } + } + next; + } + if ($param =~ /^NotPageList/) { + %NotPageList=(); + foreach (split(/\s+/,$value)) { $NotPageList{$_}=1; } + $FoundNotPageList=1; + next; + } + if ($param =~ /^ValidHTTPCodes/) { + %ValidHTTPCodes=(); + foreach (split(/\s+/,$value)) { $ValidHTTPCodes{$_}=1; } + next; + } + if ($param =~ /^ValidSMTPCodes/) { + %ValidSMTPCodes=(); + foreach (split(/\s+/,$value)) { $ValidSMTPCodes{$_}=1; } + next; + } + if ($param =~ /^URLWithQueryWithOnlyFollowingParameters$/) { + @URLWithQueryWithOnly=split(/\s+/,$value); + next; + } + if ($param =~ /^URLWithQueryWithoutFollowingParameters$/) { + @URLWithQueryWithout=split(/\s+/,$value); + next; + } + + # Extra parameters + if ($param =~ /^ExtraSectionName(\d+)/) { $ExtraName[$1]=$value; next; } + if ($param =~ /^ExtraSectionCodeFilter(\d+)/) { @{$ExtraCodeFilter[$1]}=split(/\s+/,$value); next; } + if ($param =~ /^ExtraSectionCondition(\d+)/) { $ExtraCondition[$1]=$value; next; } + if ($param =~ /^ExtraSectionStatTypes(\d+)/) { $ExtraStatTypes[$1]=$value; next; } + if ($param =~ /^ExtraSectionFirstColumnTitle(\d+)/) { $ExtraFirstColumnTitle[$1]=$value; next; } + if ($param =~ /^ExtraSectionFirstColumnValues(\d+)/) { $ExtraFirstColumnValues[$1]=$value; next; } + if ($param =~ /^ExtraSectionFirstColumnFunction(\d+)/) { $ExtraFirstColumnFunction[$1]=$value; next; } + if ($param =~ /^ExtraSectionFirstColumnFormat(\d+)/) { $ExtraFirstColumnFormat[$1]=$value; next; } + if ($param =~ /^ExtraSectionAddAverageRow(\d+)/) { $ExtraAddAverageRow[$1]=$value; next; } + if ($param =~ /^ExtraSectionAddSumRow(\d+)/) { $ExtraAddSumRow[$1]=$value; next; } + if ($param =~ /^MaxNbOfExtra(\d+)/) { $MaxNbOfExtra[$1]=$value; next; } + if ($param =~ /^MinHitExtra(\d+)/) { $MinHitExtra[$1]=$value; next; } + # Special appearance parameters + if ($param =~ /^LoadPlugin/) { push @PluginsToLoad, $value; next; } + # Other parameter checks we need to put after MaxNbOfExtra and MinHitExtra + if ($param =~ /^MaxNbOf(\w+)/) { $MaxNbOf{$1}=$value; next; } + if ($param =~ /^MinHit(\w+)/) { $MinHit{$1}=$value; next; } + # Check if this is a known parameter +# if (! $ConfOk{$param}) { error("Unknown config parameter '$param' found line $conflinenb in file \"configFile\""); } + # If parameters was not found previously, defined variable with name of param to value + $$param=$value; + } + + if ($Debug) { debug("Config file read was \"$configFile\" (level $level)"); } +} + +#------------------------------------------------------------------------------ +# Function: Load the reference databases +# Parameters: List of files to load +# Input: $DIR +# Output: Arrays and Hash tables are defined +# Return: - +#------------------------------------------------------------------------------ +sub Read_Ref_Data { + # Check lib files in common possible directories : + # Windows and standard package: "$DIR/lib" (lib in same dir than awstats.pl) + # Debian package: "/usr/share/awstats/lib" + my @PossibleLibDir=("$DIR/lib","/usr/share/awstats/lib"); + my %FilePath=(); my %DirAddedInINC=(); + my @FileListToLoad=(); + while (my $file=shift) { push @FileListToLoad, "$file.pm"; } + if ($Debug) { debug("Call to Read_Ref_Data with files to load: ".(join(',',@FileListToLoad))); } + foreach my $file (@FileListToLoad) { + foreach my $dir (@PossibleLibDir) { + my $searchdir=$dir; + if ($searchdir && (!($searchdir =~ /\/$/)) && (!($searchdir =~ /\\$/)) ) { $searchdir .= "/"; } + if (! $FilePath{$file}) { # To not load twice same file in different path + if (-s "${searchdir}${file}") { + $FilePath{$file}="${searchdir}${file}"; + if ($Debug) { debug("Call to Read_Ref_Data [FilePath{$file}=\"$FilePath{$file}\"]"); } + # Note: cygwin perl 5.8 need a push + require file + if (! $DirAddedInINC{"$dir"}) { + push @INC, "$dir"; + $DirAddedInINC{"$dir"}=1; + } + my $loadret=require "$file"; + #my $loadret=(require "$FilePath{$file}"||require "${file}"); + } + } + } + if (! $FilePath{$file}) { + my $filetext=$file; $filetext =~ s/\.pm$//; $filetext =~ s/_/ /g; + warning("Warning: Can't read file \"$file\" ($filetext detection will not work correctly).\nCheck if file is in \"".($PossibleLibDir[0])."\" directory and is readable."); + } + } + # Sanity check (if loaded) + if ((scalar keys %OSHashID) && @OSSearchIDOrder != scalar keys %OSHashID) { error("Not same number of records of OSSearchIDOrder (".(@OSSearchIDOrder)." entries) and OSHashID (".(scalar keys %OSHashID)." entries) in OS database. Check your file ".$FilePath{"operating_systems.pm"}); } + if ((scalar keys %SearchEnginesHashID) && (@SearchEnginesSearchIDOrder_list1+@SearchEnginesSearchIDOrder_list2+@SearchEnginesSearchIDOrder_listgen) != scalar keys %SearchEnginesHashID) { error("Not same number of records of SearchEnginesSearchIDOrder_listx (total is ".(@SearchEnginesSearchIDOrder_list1+@SearchEnginesSearchIDOrder_list2+@SearchEnginesSearchIDOrder_listgen)." entries) and SearchEnginesHashID (".(scalar keys %SearchEnginesHashID)." entries) in Search Engines database. Check your file ".$FilePath{"search_engines.pm"}." is up to date."); } + if ((scalar keys %BrowsersHashIDLib) && @BrowsersSearchIDOrder != (scalar keys %BrowsersHashIDLib) - 4) { error("Not same number of records of BrowsersSearchIDOrder (".(@BrowsersSearchIDOrder)." entries) and BrowsersHashIDLib (".((scalar keys %BrowsersHashIDLib) - 4)." entries without msie,netscape,firefox,svn) in Browsers database. May be you updated AWStats without updating browsers.pm file or you made changed into browsers.pm not correctly. Check your file ".$FilePath{"browsers.pm"}." is up to date."); } + if ((scalar keys %RobotsHashIDLib) && (@RobotsSearchIDOrder_list1+@RobotsSearchIDOrder_list2+@RobotsSearchIDOrder_listgen) != (scalar keys %RobotsHashIDLib) - 1) { error("Not same number of records of RobotsSearchIDOrder_listx (total is ".(@RobotsSearchIDOrder_list1+@RobotsSearchIDOrder_list2+@RobotsSearchIDOrder_listgen)." entries) and RobotsHashIDLib (".((scalar keys %RobotsHashIDLib) - 1)." entries without 'unknown') in Robots database. Check your file ".$FilePath{"robots.pm"}." is up to date."); } +} + + +#------------------------------------------------------------------------------ +# Function: Get the messages for a specified language +# Parameters: LanguageId +# Input: $DirLang $DIR +# Output: $Message table is defined in memory +# Return: None +#------------------------------------------------------------------------------ +sub Read_Language_Data { + # Check lang files in common possible directories : + # Windows and standard package: "$DIR/lang" (lang in same dir than awstats.pl) + # Debian package : "/usr/share/awstats/lang" + my @PossibleLangDir=("$DirLang","$DIR/lang","/usr/share/awstats/lang"); + + my $FileLang=''; + foreach (@PossibleLangDir) { + my $searchdir=$_; + if ($searchdir && (!($searchdir =~ /\/$/)) && (!($searchdir =~ /\\$/)) ) { $searchdir .= "/"; } + if (open(LANG,"${searchdir}awstats-$_[0].txt")) { $FileLang="${searchdir}awstats-$_[0].txt"; last; } + } + # If file not found, we try english + if (! $FileLang) { + foreach (@PossibleLangDir) { + my $searchdir=$_; + if ($searchdir && (!($searchdir =~ /\/$/)) && (!($searchdir =~ /\\$/)) ) { $searchdir .= "/"; } + if (open(LANG,"${searchdir}awstats-en.txt")) { $FileLang="${searchdir}awstats-en.txt"; last; } + } + } + if ($Debug) { debug("Call to Read_Language_Data [FileLang=\"$FileLang\"]"); } + if ($FileLang) { + my $i = 0; + binmode LANG; # Might avoid 'Malformed UTF-8 errors' + my $cregcode=qr/^PageCode=[\t\s\"\']*([\w-]+)/i; + my $cregdir=qr/^PageDir=[\t\s\"\']*([\w-]+)/i; + my $cregmessage=qr/^Message\d+=/i; + while () { + chomp $_; s/\r//; + if ($_ =~ /$cregcode/o) { $PageCode = $1; } + if ($_ =~ /$cregdir/o) { $PageDir = $1; } + if ($_ =~ s/$cregmessage//o) { + $_ =~ s/^#.*//; # Remove comments + $_ =~ s/\s+#.*//; # Remove comments + $_ =~ tr/\t / /s; # Change all blanks into " " + $_ =~ s/^\s+//; $_ =~ s/\s+$//; + $_ =~ s/^\"//; $_ =~ s/\"$//; + $Message[$i] = $_; + $i++; + } + } + close(LANG); + } + else { + warning("Warning: Can't find language files for \"$_[0]\". English will be used."); + } + # Some language string changes + if ($LogType eq 'M') { # For mail + $Message[8]=$Message[151]; + $Message[9]=$Message[152]; + $Message[57]=$Message[149]; + $Message[75]=$Message[150]; + } + if ($LogType eq 'F') { # For web + + } +} + + +#------------------------------------------------------------------------------ +# Function: Substitute date tags in a string by value +# Parameters: String +# Input: All global variables +# Output: Change on some global variables +# Return: String +#------------------------------------------------------------------------------ +sub Substitute_Tags { + my $SourceString=shift; + if ($Debug) { debug("Call to Substitute_Tags on $SourceString"); } + + my %MonthNumLibEn = ("01","Jan","02","Feb","03","Mar","04","Apr","05","May","06","Jun","07","Jul","08","Aug","09","Sep","10","Oct","11","Nov","12","Dec"); + + while ($SourceString =~ /%([ymdhwYMDHWNSO]+)-(\(\d+\)|\d+)/) { + # Accept tag %xx-dd and %xx-(dd) + my $timetag="$1"; + my $timephase=quotemeta("$2"); + my $timephasenb="$2"; $timephasenb=~s/[^\d]//g; + if ($Debug) { debug(" Found a time tag '$timetag' with a phase of '$timephasenb' hour in log file name",1); } + # Get older time + my ($oldersec,$oldermin,$olderhour,$olderday,$oldermonth,$olderyear,$olderwday,$olderyday) = localtime($starttime-($timephasenb*3600)); + my $olderweekofmonth=int($olderday/7); + my $olderweekofyear=int(($olderyday-1+6-($olderwday==0?6:$olderwday-1))/7)+1; if ($olderweekofyear > 52) { $olderweekofyear = 1; } + my $olderdaymod=$olderday%7; + $olderwday++; + my $olderns=Time::Local::timegm(0,0,0,$olderday,$oldermonth,$olderyear); + if ($olderdaymod <= $olderwday) { if (($olderwday != 7) || ($olderdaymod != 0)) { $olderweekofmonth=$olderweekofmonth+1; } } + if ($olderdaymod > $olderwday) { $olderweekofmonth=$olderweekofmonth+2; } + # Change format of time variables + $olderweekofmonth = "0$olderweekofmonth"; + if ($olderweekofyear < 10) { $olderweekofyear = "0$olderweekofyear"; } + if ($olderyear < 100) { $olderyear+=2000; } else { $olderyear+=1900; } + my $oldersmallyear=$olderyear;$oldersmallyear =~ s/^..//; + if (++$oldermonth < 10) { $oldermonth = "0$oldermonth"; } + if ($olderday < 10) { $olderday = "0$olderday"; } + if ($olderhour < 10) { $olderhour = "0$olderhour"; } + if ($oldermin < 10) { $oldermin = "0$oldermin"; } + if ($oldersec < 10) { $oldersec = "0$oldersec"; } + # Replace tag with new value + if ($timetag eq 'YYYY') { $SourceString =~ s/%YYYY-$timephase/$olderyear/ig; next; } + if ($timetag eq 'YY') { $SourceString =~ s/%YY-$timephase/$oldersmallyear/ig; next; } + if ($timetag eq 'MM') { $SourceString =~ s/%MM-$timephase/$oldermonth/ig; next; } + if ($timetag eq 'MO') { $SourceString =~ s/%MO-$timephase/$MonthNumLibEn{$oldermonth}/ig; next; } + if ($timetag eq 'DD') { $SourceString =~ s/%DD-$timephase/$olderday/ig; next; } + if ($timetag eq 'HH') { $SourceString =~ s/%HH-$timephase/$olderhour/ig; next; } + if ($timetag eq 'NS') { $SourceString =~ s/%NS-$timephase/$olderns/ig; next; } + if ($timetag eq 'WM') { $SourceString =~ s/%WM-$timephase/$olderweekofmonth/g; next; } + if ($timetag eq 'Wm') { my $olderweekofmonth0=$olderweekofmonth-1; $SourceString =~ s/%Wm-$timephase/$olderweekofmonth0/g; next; } + if ($timetag eq 'WY') { $SourceString =~ s/%WY-$timephase/$olderweekofyear/g; next; } + if ($timetag eq 'Wy') { my $olderweekofyear0=sprintf("%02d",$olderweekofyear-1); $SourceString =~ s/%Wy-$timephase/$olderweekofyear0/g; next; } + if ($timetag eq 'DW') { $SourceString =~ s/%DW-$timephase/$olderwday/g; next; } + if ($timetag eq 'Dw') { my $olderwday0=$olderwday-1; $SourceString =~ s/%Dw-$timephase/$olderwday0/g; next; } + # If unknown tag + error("Unknown tag '\%$timetag' in parameter."); + } + # Replace %YYYY %YY %MM %DD %HH with current value. Kept for backward compatibility. + $SourceString =~ s/%YYYY/$nowyear/ig; + $SourceString =~ s/%YY/$nowsmallyear/ig; + $SourceString =~ s/%MM/$nowmonth/ig; + $SourceString =~ s/%MO/$MonthNumLibEn{$nowmonth}/ig; + $SourceString =~ s/%DD/$nowday/ig; + $SourceString =~ s/%HH/$nowhour/ig; + $SourceString =~ s/%NS/$nowns/ig; + $SourceString =~ s/%WM/$nowweekofmonth/g; + my $nowweekofmonth0=$nowweekofmonth-1; $SourceString =~ s/%Wm/$nowweekofmonth0/g; + $SourceString =~ s/%WY/$nowweekofyear/g; + my $nowweekofyear0=$nowweekofyear-1; $SourceString =~ s/%Wy/$nowweekofyear0/g; + $SourceString =~ s/%DW/$nowwday/g; + my $nowwday0=$nowwday-1; $SourceString =~ s/%Dw/$nowwday0/g; + + return $SourceString; +} + + +#------------------------------------------------------------------------------ +# Function: Check if all parameters are correctly defined. If not set them to default. +# Parameters: None +# Input: All global variables +# Output: Change on some global variables +# Return: None +#------------------------------------------------------------------------------ +sub Check_Config { + if ($Debug) { debug("Call to Check_Config"); } + + # Show initial values of main parameters before check + if ($Debug) { + debug(" LogFile='$LogFile'",2); + debug(" LogType='$LogType'",2); + debug(" LogFormat='$LogFormat'",2); + debug(" LogSeparator='$LogSeparator'",2); + debug(" DNSLookup='$DNSLookup'",2); + debug(" DirData='$DirData'",2); + debug(" DirCgi='$DirCgi'",2); + debug(" DirIcons='$DirIcons'",2); + debug(" NotPageList ".(join(',',keys %NotPageList)),2); + debug(" ValidHTTPCodes ".(join(',',keys %ValidHTTPCodes)),2); + debug(" ValidSMTPCodes ".(join(',',keys %ValidSMTPCodes)),2); + debug(" UseFramesWhenCGI=$UseFramesWhenCGI",2); + debug(" BuildReportFormat=$BuildReportFormat",2); + debug(" BuildHistoryFormat=$BuildHistoryFormat",2); + debug(" URLWithQueryWithOnlyFollowingParameters=".(join(',',@URLWithQueryWithOnly)),2); + debug(" URLWithQueryWithoutFollowingParameters=".(join(',',@URLWithQueryWithout)),2); + } + + # Main section + $LogFile=&Substitute_Tags($LogFile); + if (! $LogFile) { error("LogFile parameter is not defined in config/domain file"); } + if ($LogType !~ /[WSMF]/i) { $LogType='W'; } + $LogFormat =~ s/\\//g; + if (! $LogFormat) { error("LogFormat parameter is not defined in config/domain file"); } + if ($LogFormat =~ /^\d$/ && $LogFormat !~ /[1-6]/) { error("LogFormat parameter is wrong in config/domain file. Value is '$LogFormat' (should be 1,2,3,4,5 or a 'personalized AWStats log format string')"); } + $LogSeparator||="\\s"; + $DirData||='.'; + $DirCgi||='/cgi-bin'; + $DirIcons||='/icon'; + if ($DNSLookup !~ /[0-2]/) { error("DNSLookup parameter is wrong in config/domain file. Value is '$DNSLookup' (should be 0,1 or 2)"); } + if (! $SiteDomain) { error("SiteDomain parameter not defined in your config/domain file. You must edit it for using this version of AWStats."); } + if ($AllowToUpdateStatsFromBrowser !~ /[0-1]/) { $AllowToUpdateStatsFromBrowser=0; } + if ($AllowFullYearView !~ /[0-3]/) { $AllowFullYearView=2; } + # Optional setup section + if (! $SectionsToBeSaved) { $SectionsToBeSaved='all'; } + if ($EnableLockForUpdate !~ /[0-1]/) { $EnableLockForUpdate=0; } + $DNSStaticCacheFile||='dnscache.txt'; + $DNSLastUpdateCacheFile||='dnscachelastupdate.txt'; + if ($DNSStaticCacheFile eq $DNSLastUpdateCacheFile) { error("DNSStaticCacheFile and DNSLastUpdateCacheFile must have different values."); } + if ($AllowAccessFromWebToAuthenticatedUsersOnly !~ /[0-1]/) { $AllowAccessFromWebToAuthenticatedUsersOnly=0; } + if ($CreateDirDataIfNotExists !~ /[0-1]/) { $CreateDirDataIfNotExists=0; } + if ($BuildReportFormat !~ /html|xhtml|xml/i) { $BuildReportFormat='html'; } + if ($BuildHistoryFormat !~ /text|xml/) { $BuildHistoryFormat='text'; } + if ($SaveDatabaseFilesWithPermissionsForEveryone !~ /[0-1]/) { $SaveDatabaseFilesWithPermissionsForEveryone=0; } + if ($PurgeLogFile !~ /[0-1]/) { $PurgeLogFile=0; } + if ($KeepBackupOfHistoricFiles !~ /[0-1]/) { $KeepBackupOfHistoricFiles=0; } + $DefaultFile[0]||='index.html'; + if ($AuthenticatedUsersNotCaseSensitive !~ /[0-1]/) { $AuthenticatedUsersNotCaseSensitive=0; } + if ($URLNotCaseSensitive !~ /[0-1]/) { $URLNotCaseSensitive=0; } + if ($URLWithAnchor !~ /[0-1]/) { $URLWithAnchor=0; } + $URLQuerySeparators =~ s/\s//g; + if (! $URLQuerySeparators) { $URLQuerySeparators='?;'; } + if ($URLWithQuery !~ /[0-1]/) { $URLWithQuery=0; } + if ($URLReferrerWithQuery !~ /[0-1]/) { $URLReferrerWithQuery=0; } + if ($WarningMessages !~ /[0-1]/) { $WarningMessages=1; } + if ($DebugMessages !~ /[0-1]/) { $DebugMessages=0; } + if ($NbOfLinesForCorruptedLog !~ /^\d+/ || $NbOfLinesForCorruptedLog<1) { $NbOfLinesForCorruptedLog=50; } + if ($Expires !~ /^\d+/) { $Expires=0; } + if ($DecodeUA !~ /[0-1]/) { $DecodeUA=0; } + $MiscTrackerUrl||='/js/awstats_misc_tracker.js'; + # Optional accuracy setup section + if ($LevelForWormsDetection !~ /^\d+/) { $LevelForWormsDetection=0; } + if ($LevelForRobotsDetection !~ /^\d+/) { $LevelForRobotsDetection=2; } + if ($LevelForBrowsersDetection !~ /^\w+/) { $LevelForBrowsersDetection=2; } # Can be 'allphones' + if ($LevelForOSDetection !~ /^\d+/) { $LevelForOSDetection=2; } + if ($LevelForRefererAnalyze !~ /^\d+/) { $LevelForRefererAnalyze=2; } + if ($LevelForFileTypesDetection !~ /^\d+/) { $LevelForFileTypesDetection=2; } + if ($LevelForSearchEnginesDetection !~ /^\d+/) { $LevelForSearchEnginesDetection=2; } + if ($LevelForKeywordsDetection !~ /^\d+/) { $LevelForKeywordsDetection=2; } + # Optional extra setup section + foreach my $extracpt (1..@ExtraName-1) { + if ($ExtraStatTypes[$extracpt] !~ /[PHBL]/) { $ExtraStatTypes[$extracpt]='PHBL'; } + if ($MaxNbOfExtra[$extracpt] !~ /^\d+$/ || $MaxNbOfExtra[$extracpt]<1) { $MaxNbOfExtra[$extracpt]=20; } + if ($MinHitExtra[$extracpt] !~ /^\d+$/ || $MinHitExtra[$extracpt]<1) { $MinHitExtra[$extracpt]=1; } + if (! $ExtraFirstColumnValues[$extracpt]) { error("Extra section number $extracpt is defined without ExtraSectionFirstColumnValues$extracpt parameter"); } + if (! $ExtraFirstColumnFormat[$extracpt]) { $ExtraFirstColumnFormat[$extracpt] = '%s'; } + } + # Optional appearance setup section + if ($MaxRowsInHTMLOutput !~ /^\d+/ || $MaxRowsInHTMLOutput<1) { $MaxRowsInHTMLOutput=1000; } + if ($ShowMenu !~ /[01]/) { $ShowMenu=1; } + if ($ShowSummary !~ /[01UVPHB]/) { $ShowSummary='UVPHB'; } + if ($ShowMonthStats !~ /[01UVPHB]/) { $ShowMonthStats='UVPHB'; } + if ($ShowDaysOfMonthStats !~ /[01VPHB]/) { $ShowDaysOfMonthStats='VPHB'; } + if ($ShowDaysOfWeekStats !~ /[01PHBL]/) { $ShowDaysOfWeekStats='PHBL'; } + if ($ShowHoursStats !~ /[01PHBL]/) { $ShowHoursStats='PHBL'; } + if ($ShowDomainsStats !~ /[01PHB]/) { $ShowDomainsStats='PHB'; } + if ($ShowHostsStats !~ /[01PHBL]/) { $ShowHostsStats='PHBL'; } + if ($ShowAuthenticatedUsers !~ /[01PHBL]/) { $ShowAuthenticatedUsers=0; } + if ($ShowRobotsStats !~ /[01HBL]/) { $ShowRobotsStats='HBL'; } + if ($ShowWormsStats !~ /[01HBL]/) { $ShowWormsStats='HBL'; } + if ($ShowEMailSenders !~ /[01HBML]/) { $ShowEMailSenders=0; } + if ($ShowEMailReceivers !~ /[01HBML]/) { $ShowEMailReceivers=0; } + if ($ShowSessionsStats !~ /[01]/) { $ShowSessionsStats=1; } + if ($ShowPagesStats !~ /[01PBEX]/i) { $ShowPagesStats='PBEX'; } + if ($ShowFileTypesStats !~ /[01HBC]/) { $ShowFileTypesStats='HB'; } + if ($ShowFileSizesStats !~ /[01]/) { $ShowFileSizesStats=1; } + if ($ShowOSStats !~ /[01]/) { $ShowOSStats=1; } + if ($ShowBrowsersStats !~ /[01]/) { $ShowBrowsersStats=1; } + if ($ShowScreenSizeStats !~ /[01]/) { $ShowScreenSizeStats=0; } + if ($ShowOriginStats !~ /[01PH]/) { $ShowOriginStats='PH'; } + if ($ShowKeyphrasesStats !~ /[01]/) { $ShowKeyphrasesStats=1; } + if ($ShowKeywordsStats !~ /[01]/) { $ShowKeywordsStats=1; } + if ($ShowClusterStats !~ /[01PHB]/) { $ShowClusterStats=0; } + if ($ShowMiscStats !~ /[01anjdfrqwp]/) { $ShowMiscStats='a'; } + if ($ShowHTTPErrorsStats !~ /[01]/) { $ShowHTTPErrorsStats=1; } + if ($ShowSMTPErrorsStats !~ /[01]/) { $ShowSMTPErrorsStats=0; } + if ($AddDataArrayMonthStats !~ /[01]/) { $AddDataArrayMonthStats=1; } + if ($AddDataArrayShowDaysOfMonthStats !~ /[01]/) { $AddDataArrayShowDaysOfMonthStats=1; } + if ($AddDataArrayShowDaysOfWeekStats !~ /[01]/) { $AddDataArrayShowDaysOfWeekStats=1; } + if ($AddDataArrayShowHoursStats !~ /[01]/) { $AddDataArrayShowHoursStats=1; } + my @maxnboflist=('Domain','HostsShown','LoginShown','RobotShown','WormsShown','PageShown','OsShown','BrowsersShown','ScreenSizesShown','RefererShown','KeyphrasesShown','KeywordsShown','EMailsShown'); + my @maxnboflistdefaultval=(10,10,10,10,5,10,10,10,5,10,10,10,20); + foreach my $i (0..(@maxnboflist-1)) { + if (! $MaxNbOf{$maxnboflist[$i]} || $MaxNbOf{$maxnboflist[$i]} !~ /^\d+$/ || $MaxNbOf{$maxnboflist[$i]}<1) { $MaxNbOf{$maxnboflist[$i]}=$maxnboflistdefaultval[$i]; } + } + my @minhitlist=('Domain','Host','Login','Robot','Worm','File','Os','Browser','ScreenSize','Refer','Keyphrase','Keyword','EMail'); + my @minhitlistdefaultval=(1,1,1,1,1,1,1,1,1,1,1,1,1); + foreach my $i (0..(@minhitlist-1)) { + if (! $MinHit{$minhitlist[$i]} || $MinHit{$minhitlist[$i]} !~ /^\d+$/ || $MinHit{$minhitlist[$i]}<1) { $MinHit{$minhitlist[$i]}=$minhitlistdefaultval[$i]; } + } + if ($FirstDayOfWeek !~ /[01]/) { $FirstDayOfWeek=1; } + if ($UseFramesWhenCGI !~ /[01]/) { $UseFramesWhenCGI=1; } + if ($DetailedReportsOnNewWindows !~ /[012]/) { $DetailedReportsOnNewWindows=1; } + if ($ShowLinksOnUrl !~ /[01]/) { $ShowLinksOnUrl=1; } + if ($MaxLengthOfShownURL !~ /^\d+/ || $MaxLengthOfShownURL<1) { $MaxLengthOfShownURL=64; } + if ($ShowLinksToWhoIs !~ /[01]/) { $ShowLinksToWhoIs=0; } + $Logo||='awstats_logo6.png'; + $LogoLink||='http://awstats.sourceforge.net'; + if ($BarWidth !~ /^\d+/ || $BarWidth<1) { $BarWidth=260; } + if ($BarHeight !~ /^\d+/ || $BarHeight<1) { $BarHeight=90; } + $color_Background =~ s/#//g; if ($color_Background !~ /^[0-9|A-H]+$/i) { $color_Background='FFFFFF'; } + $color_TableBGTitle =~ s/#//g; if ($color_TableBGTitle !~ /^[0-9|A-H]+$/i) { $color_TableBGTitle='CCCCDD'; } + $color_TableTitle =~ s/#//g; if ($color_TableTitle !~ /^[0-9|A-H]+$/i) { $color_TableTitle='000000'; } + $color_TableBG =~ s/#//g; if ($color_TableBG !~ /^[0-9|A-H]+$/i) { $color_TableBG='CCCCDD'; } + $color_TableRowTitle =~ s/#//g; if ($color_TableRowTitle !~ /^[0-9|A-H]+$/i) { $color_TableRowTitle='FFFFFF'; } + $color_TableBGRowTitle =~ s/#//g; if ($color_TableBGRowTitle !~ /^[0-9|A-H]+$/i) { $color_TableBGRowTitle='ECECEC'; } + $color_TableBorder =~ s/#//g; if ($color_TableBorder !~ /^[0-9|A-H]+$/i) { $color_TableBorder='ECECEC'; } + $color_text =~ s/#//g; if ($color_text !~ /^[0-9|A-H]+$/i) { $color_text='000000'; } + $color_textpercent =~ s/#//g; if ($color_textpercent !~ /^[0-9|A-H]+$/i) { $color_textpercent='606060'; } + $color_titletext =~ s/#//g; if ($color_titletext !~ /^[0-9|A-H]+$/i) { $color_titletext='000000'; } + $color_weekend =~ s/#//g; if ($color_weekend !~ /^[0-9|A-H]+$/i) { $color_weekend='EAEAEA'; } + $color_link =~ s/#//g; if ($color_link !~ /^[0-9|A-H]+$/i) { $color_link='0011BB'; } + $color_hover =~ s/#//g; if ($color_hover !~ /^[0-9|A-H]+$/i) { $color_hover='605040'; } + $color_other =~ s/#//g; if ($color_other !~ /^[0-9|A-H]+$/i) { $color_other='666688'; } + $color_u =~ s/#//g; if ($color_u !~ /^[0-9|A-H]+$/i) { $color_u='FFA060'; } + $color_v =~ s/#//g; if ($color_v !~ /^[0-9|A-H]+$/i) { $color_v='F4F090'; } + $color_p =~ s/#//g; if ($color_p !~ /^[0-9|A-H]+$/i) { $color_p='4477DD'; } + $color_h =~ s/#//g; if ($color_h !~ /^[0-9|A-H]+$/i) { $color_h='66EEFF'; } + $color_k =~ s/#//g; if ($color_k !~ /^[0-9|A-H]+$/i) { $color_k='2EA495'; } + $color_s =~ s/#//g; if ($color_s !~ /^[0-9|A-H]+$/i) { $color_s='8888DD'; } + $color_e =~ s/#//g; if ($color_e !~ /^[0-9|A-H]+$/i) { $color_e='CEC2E8'; } + $color_x =~ s/#//g; if ($color_x !~ /^[0-9|A-H]+$/i) { $color_x='C1B2E2'; } + + # Correct param if default value is asked + if ($ShowSummary eq '1') { $ShowSummary = 'UVPHB'; } + if ($ShowMonthStats eq '1') { $ShowMonthStats = 'UVPHB'; } + if ($ShowDaysOfMonthStats eq '1') { $ShowDaysOfMonthStats = 'VPHB'; } + if ($ShowDaysOfWeekStats eq '1') { $ShowDaysOfWeekStats = 'PHBL'; } + if ($ShowHoursStats eq '1') { $ShowHoursStats = 'PHBL'; } + if ($ShowDomainsStats eq '1') { $ShowDomainsStats = 'PHB'; } + if ($ShowHostsStats eq '1') { $ShowHostsStats = 'PHBL'; } + if ($ShowEMailSenders eq '1') { $ShowEMailSenders = 'HBML'; } + if ($ShowEMailReceivers eq '1') { $ShowEMailReceivers = 'HBML'; } + if ($ShowAuthenticatedUsers eq '1') { $ShowAuthenticatedUsers = 'PHBL'; } + if ($ShowRobotsStats eq '1') { $ShowRobotsStats = 'HBL'; } + if ($ShowWormsStats eq '1') { $ShowWormsStats = 'HBL'; } + if ($ShowPagesStats eq '1') { $ShowPagesStats = 'PBEX'; } + if ($ShowFileTypesStats eq '1') { $ShowFileTypesStats = 'HB'; } + if ($ShowOriginStats eq '1') { $ShowOriginStats = 'PH'; } + if ($ShowClusterStats eq '1') { $ShowClusterStats = 'PHB'; } + if ($ShowMiscStats eq '1') { $ShowMiscStats = 'anjdfrqwp'; } + + # Convert extra sections data into @ExtraConditionType, @ExtraConditionTypeVal... + foreach my $extranum (1..@ExtraName-1) { + my $part=0; + foreach my $conditioncouple (split(/\s*\|\|\s*/, $ExtraCondition[$extranum])) { + my ($conditiontype, $conditiontypeval)=split(/[,:]/,$conditioncouple,2); + $ExtraConditionType[$extranum][$part]=$conditiontype; + if ($conditiontypeval =~ /^REGEX\[(.*)\]$/i) { $conditiontypeval=$1; } + #else { $conditiontypeval=quotemeta($conditiontypeval); } + $ExtraConditionTypeVal[$extranum][$part]=qr/$conditiontypeval/i; + $part++; + } + $part=0; + foreach my $rowkeycouple (split(/\s*\|\|\s*/, $ExtraFirstColumnValues[$extranum])) { + my ($rowkeytype, $rowkeytypeval)=split(/[,:]/,$rowkeycouple,2); + $ExtraFirstColumnValuesType[$extranum][$part]=$rowkeytype; + if ($rowkeytypeval =~ /^REGEX\[(.*)\]$/i) { $rowkeytypeval=$1; } + #else { $rowkeytypeval=quotemeta($rowkeytypeval); } + $ExtraFirstColumnValuesTypeVal[$extranum][$part]=qr/$rowkeytypeval/i; + $part++; + } + } + + # Show definitive value for major parameters + if ($Debug) { + debug(" LogFile='$LogFile'",2); + debug(" LogFormat='$LogFormat'",2); + debug(" LogSeparator='$LogSeparator'",2); + debug(" DNSLookup='$DNSLookup'",2); + debug(" DirData='$DirData'",2); + debug(" DirCgi='$DirCgi'",2); + debug(" DirIcons='$DirIcons'",2); + debug(" SiteDomain='$SiteDomain'",2); + debug(" MiscTrackerUrl='$MiscTrackerUrl'",2); + foreach (keys %MaxNbOf) { debug(" MaxNbOf{$_}=$MaxNbOf{$_}",2); } + foreach (keys %MinHit) { debug(" MinHit{$_}=$MinHit{$_}",2); } + foreach my $extranum (1..@ExtraName-1) { + debug(" ExtraCodeFilter[$extranum] is array ".join(',',@{$ExtraCodeFilter[$extranum]}),2); + debug(" ExtraConditionType[$extranum] is array ".join(',',@{$ExtraConditionType[$extranum]}),2); + debug(" ExtraConditionTypeVal[$extranum] is array ".join(',',@{$ExtraConditionTypeVal[$extranum]}),2); + debug(" ExtraFirstColumnFunction[$extranum] is array ".join(',',@{$ExtraFirstColumnFunction[$extranum]}),2); + debug(" ExtraFirstColumnValuesType[$extranum] is array ".join(',',@{$ExtraFirstColumnValuesType[$extranum]}),2); + debug(" ExtraFirstColumnValuesTypeVal[$extranum] is array ".join(',',@{$ExtraFirstColumnValuesTypeVal[$extranum]}),2); + } + } + + # Deny URLWithQueryWithOnlyFollowingParameters and URLWithQueryWithoutFollowingParameters both set + if (@URLWithQueryWithOnly && @URLWithQueryWithout) { + error("URLWithQueryWithOnlyFollowingParameters and URLWithQueryWithoutFollowingParameters can't be both set at the same time"); + } + # Deny $ShowHTTPErrorsStats and $ShowSMTPErrorsStats both set + if ($ShowHTTPErrorsStats && $ShowSMTPErrorsStats) { + error("ShowHTTPErrorsStats and ShowSMTPErrorsStats can't be both set at the same time"); + } + + # Deny LogFile if contains a pipe and PurgeLogFile || ArchiveLogRecords set on + if (($PurgeLogFile || $ArchiveLogRecords) && $LogFile =~ /\|\s*$/) { + error("A pipe in log file name is not allowed if PurgeLogFile and ArchiveLogRecords are not set to 0"); + } + # If not a migrate, check if DirData is OK + if (! $MigrateStats && ! -d $DirData) { + if ($CreateDirDataIfNotExists) { + if ($Debug) { debug(" Make directory $DirData",2); } + my $mkdirok=mkdir "$DirData", 0766; + if (! $mkdirok) { error("$PROG failed to create directory DirData (DirData=\"$DirData\", CreateDirDataIfNotExists=$CreateDirDataIfNotExists)."); } + } + else { + error("AWStats database directory defined in config file by 'DirData' parameter ($DirData) does not exist or is not writable."); + } + } + + if ($LogType eq 'S') { $NOTSORTEDRECORDTOLERANCE=1000000; } +} + + +#------------------------------------------------------------------------------ +# Function: Common function used by init function of plugins +# Parameters: AWStats version required by plugin +# Input: $VERSION +# Output: None +# Return: '' if ok, "Error: xxx" if error +#------------------------------------------------------------------------------ +sub Check_Plugin_Version { + my $PluginNeedAWStatsVersion=shift; + if (! $PluginNeedAWStatsVersion) { return 0; } + $VERSION =~ /^(\d+)\.(\d+)/; + my $numAWStatsVersion=($1*1000)+$2; + $PluginNeedAWStatsVersion =~ /^(\d+)\.(\d+)/; + my $numPluginNeedAWStatsVersion=($1*1000)+$2; + if ($numPluginNeedAWStatsVersion > $numAWStatsVersion) { + return "Error: AWStats version $PluginNeedAWStatsVersion or higher is required. Detected $VERSION."; + } + return ''; +} + + +#------------------------------------------------------------------------------ +# Function: Return a checksum for an array of string +# Parameters: Array of string +# Input: None +# Output: None +# Return: Checksum number +#------------------------------------------------------------------------------ +sub CheckSum { + my $string=shift; + my $checksum=0; +# use MD5; +# $checksum = MD5->hexhash($string); + my $i=0; my $j=0; + while ($i < length($string)) { + my $c=substr($string,$i,1); + $checksum+=(ord($c)<<(8*$j)); + if ($j++ > 3) { $j=0; } + $i++; + } + return $checksum; +} + + +#------------------------------------------------------------------------------ +# Function: Load plugins files +# Parameters: None +# Input: $DIR @PluginsToLoad +# Output: None +# Return: None +#------------------------------------------------------------------------------ +sub Read_Plugins { + # Check plugin files in common possible directories : + # Windows and standard package: "$DIR/plugins" (plugins in same dir than awstats.pl) + # Redhat : "/usr/local/awstats/wwwroot/cgi-bin/plugins" + # Debian package : "/usr/share/awstats/plugins" + my @PossiblePluginsDir=("$DIR/plugins","/usr/local/awstats/wwwroot/cgi-bin/plugins","/usr/share/awstats/plugins"); + my %DirAddedInINC=(); + + #Removed for security reason + #foreach my $key (keys %NoLoadPlugin) { if ($NoLoadPlugin{$key} < 0) { push @PluginsToLoad, $key; } } + if ($Debug) { debug("Call to Read_Plugins with list: ".join(',',@PluginsToLoad)); } + foreach my $plugininfo (@PluginsToLoad) { + my ($pluginfile,$pluginparam)=split(/\s+/,$plugininfo,2); + $pluginparam||=""; # If split has only on part, pluginparam is not initialized + $pluginfile =~ s/\.pm$//i; + $pluginfile =~ /([^\/\\]+)$/; + my $pluginname=$1; # pluginname is pluginfile without any path + # Check if plugin is not disabled + if ($NoLoadPlugin{$pluginname} && $NoLoadPlugin{$pluginname} > 0) { + if ($Debug) { debug(" Plugin load for '$pluginfile' has been disabled from parameters"); } + next; + } + if ($pluginname) { + if (! $PluginsLoaded{'init'}{"$pluginname"}) { # Plugin not already loaded + my %pluginisfor=('timehires'=>'u','ipv6'=>'u','hashfiles'=>'u', + 'geoipfree'=>'u', + 'geoip'=>'ou','geoip_region_maxmind'=>'mou','geoip_city_maxmind'=>'mou','geoip_isp_maxmind'=>'mou','geoip_org_maxmind'=>'mou', + 'timezone'=>'ou', + 'decodeutfkeys'=>'o','hostinfo'=>'o','rawlog'=>'o','userinfo'=>'o','urlalias'=>'o','tooltips'=>'o'); + if ($pluginisfor{$pluginname}) { # If it's a known plugin, may be we don't need to load it + # Do not load "menu handler plugins" if output only and mainleft frame + if (! $UpdateStats && scalar keys %HTMLOutput && $FrameName eq 'mainleft' && $pluginisfor{$pluginname} !~ /m/) { $PluginsLoaded{'init'}{"$pluginname"}=1; next; } + # Do not load "update plugins" if output only + if (! $UpdateStats && scalar keys %HTMLOutput && $pluginisfor{$pluginname} !~ /o/) { $PluginsLoaded{'init'}{"$pluginname"}=1; next; } + # Do not load "output plugins" if update only + if ($UpdateStats && ! scalar keys %HTMLOutput && $pluginisfor{$pluginname} !~ /u/) { $PluginsLoaded{'init'}{"$pluginname"}=1; next; } + } + # Load plugin + foreach my $dir (@PossiblePluginsDir) { + my $searchdir=$dir; + if ($searchdir && (!($searchdir =~ /\/$/)) && (!($searchdir =~ /\\$/)) ) { $searchdir .= "/"; } + my $pluginpath="${searchdir}${pluginfile}.pm"; + if (-s "$pluginpath") { + $PluginDir="${searchdir}"; # Set plugin dir + if ($Debug) { debug(" Try to init plugin '$pluginname' ($pluginpath) with param '$pluginparam'",1); } + if (! $DirAddedInINC{"$dir"}) { + push @INC, "$dir"; + $DirAddedInINC{"$dir"}=1; + } + my $loadret=0; + my $modperl=$ENV{"MOD_PERL"}? eval { require mod_perl; $mod_perl::VERSION >= 1.99 ? 2 : 1 } : 0; + if ($modperl == 2) { $loadret=require "$pluginpath"; } + else { $loadret=require "$pluginfile.pm"; } + if (! $loadret || $loadret =~ /^error/i) { + # Load failed, we stop here + error("Plugin load for plugin '$pluginname' failed with return code: $loadret"); + } + my $ret; # To get init return + my $initfunction="\$ret=Init_$pluginname('$pluginparam')"; + my $initret=eval("$initfunction"); + if ($initret && $initret eq 'xxx') { $initret='Error: The PluginHooksFunctions variable defined in plugin file does not contain list of hooked functions'; } + if (! $initret || $initret =~ /^error/i) { + # Init function failed, we stop here + error("Plugin init for plugin '$pluginname' failed with return code: ".($initret?"$initret":"$@ (A module required by plugin might be missing).")); + } + # Plugin load and init successfull + foreach my $elem (split(/\s+/,$initret)) { + # Some functions can only be plugged once + my @uniquefunc=('GetCountryCodeByName','GetCountryCodeByAddr','ChangeTime','GetTimeZoneTitle','GetTime','SearchFile','LoadCache','SaveHash','ShowMenu'); + my $isuniquefunc=0; + foreach my $function (@uniquefunc) { + if ("$elem" eq "$function") { + # We try to load a 'unique' function, so we check and stop if already loaded + foreach my $otherpluginname (keys %{$PluginsLoaded{"$elem"}}) { + error("Conflict between plugin '$pluginname' and '$otherpluginname'. They both implements the 'must be unique' function '$elem'.\nYou must choose between one of them. Using together is not possible."); + } + $isuniquefunc=1; + last; + } + } + if ($isuniquefunc) { + # TODO Use $PluginsLoaded{"$elem"}="$pluginname"; for unique func + $PluginsLoaded{"$elem"}{"$pluginname"}=1; + } + else { $PluginsLoaded{"$elem"}{"$pluginname"}=1; } + if ("$elem" =~ /SectionInitHashArray/) { $AtLeastOneSectionPlugin=1; } + } + $PluginsLoaded{'init'}{"$pluginname"}=1; + if ($Debug) { debug(" Plugin '$pluginname' now hooks functions '$initret'",1); } + last; + } + } + if (! $PluginsLoaded{'init'}{"$pluginname"}) { + error("AWStats config file contains a directive to load plugin \"$pluginname\" (LoadPlugin=\"$plugininfo\") but AWStats can't open plugin file \"$pluginfile.pm\" for read.\nCheck if file is in \"".($PossiblePluginsDir[0])."\" directory and is readable."); + } + } + else { + warning("Warning: Tried to load plugin \"$pluginname\" twice. Fix config file."); + } + } + else { + error("Plugin \"$pluginfile\" is not a valid plugin name."); + } + } + # In output mode, geo ip plugins are not loaded, so message changes are done here (can't be done in plugin init function) + if ($PluginsLoaded{'init'}{'geoip'} || $PluginsLoaded{'init'}{'geoipfree'}) { $Message[17]=$Message[25]=$Message[148]; } +} + +#------------------------------------------------------------------------------ +# Function: Read history file and create or update tmp history file +# Parameters: year,month,day,hour,withupdate,withpurge,part_to_load[,lastlinenb,lastlineoffset,lastlinechecksum] +# Input: $DirData $PROG $FileSuffix $LastLine $DatabaseBreak +# Output: None +# Return: Tmp history file name created/updated or '' if withupdate is 0 +#------------------------------------------------------------------------------ +sub Read_History_With_TmpUpdate { + + my $year=sprintf("%04i",shift||0); + my $month=sprintf("%02i",shift||0); + my $day=shift; if ($day ne '') { $day=sprintf("%02i",$day); } + my $hour=shift; if ($hour ne '') { $hour=sprintf("%02i",$hour); } + my $withupdate=shift||0; + my $withpurge=shift||0; + my $part=shift||''; + + my ($date,$filedate)=('',''); + if ($DatabaseBreak eq 'month') { $date=sprintf("%04i%02i",$year,$month); $filedate=sprintf("%02i%04i",$month,$year); } + elsif ($DatabaseBreak eq 'year') { $date=sprintf("%04i%",$year); $filedate=sprintf("%04i",$year); } + elsif ($DatabaseBreak eq 'day') { $date=sprintf("%04i%02i%02i",$year,$month,$day); $filedate=sprintf("%02i%04i%02i",$month,$year,$day); } + elsif ($DatabaseBreak eq 'hour') { $date=sprintf("%04i%02i%02i%02i",$year,$month,$day,$hour); $filedate=sprintf("%02i%04i%02i%02i",$month,$year,$day,$hour); } + + my $xml=($BuildHistoryFormat eq 'xml'?1:0); + my $xmleb=''; my $xmlrb=''; + + my $lastlinenb=shift||0; + my $lastlineoffset=shift||0; + my $lastlinechecksum=shift||0; + + my %allsections=('general'=>1,'misc'=>2,'time'=>3,'visitor'=>4,'day'=>5, + 'domain'=>6,'cluster'=>7,'login'=>8,'robot'=>9,'worms'=>10,'emailsender'=>11,'emailreceiver'=>12, + 'session'=>13,'sider'=>14,'filetypes'=>15, + 'os'=>16,'browser'=>17,'screensize'=>18,'unknownreferer'=>19,'unknownrefererbrowser'=>20, + 'origin'=>21,'sereferrals'=>22,'pagerefs'=>23, + 'searchwords'=>24,'keywords'=>25, + 'errors'=>26); + + my $order=(scalar keys %allsections)+1; + foreach (keys %TrapInfosForHTTPErrorCodes) { $allsections{"sider_$_"}=$order++; } + foreach (1..@ExtraName-1) { $allsections{"extra_$_"}=$order++; } + foreach (keys %{$PluginsLoaded{'SectionInitHashArray'}}) { $allsections{"plugin_$_"}=$order++; } + my $withread=0; + + # Variable used to read old format history files + my $readvisitorforbackward=0; + + if ($Debug) { debug("Call to Read_History_With_TmpUpdate [$year,$month,$day,$hour,withupdate=$withupdate,withpurge=$withpurge,part=$part,lastlinenb=$lastlinenb,lastlineoffset=$lastlineoffset,lastlinechecksum=$lastlinechecksum]"); } + if ($Debug) { debug("date=$date"); } + + # Define SectionsToLoad (which sections to load) + my %SectionsToLoad = (); + if ($part eq 'all') { # Load all needed sections + my $order=1; + $SectionsToLoad{'general'}=$order++; + # When + $SectionsToLoad{'time'}=$order++; # Always loaded because needed to count TotalPages, TotalHits, TotalBandwidth + if ($UpdateStats || $MigrateStats || ($HTMLOutput{'main'} && $ShowHostsStats) || $HTMLOutput{'allhosts'} || $HTMLOutput{'lasthosts'} || $HTMLOutput{'unknownip'}) { $SectionsToLoad{'visitor'}=$order++; } # Must be before day, sider and session section + if ($UpdateStats || $MigrateStats || ($HTMLOutput{'main'} && ($ShowDaysOfWeekStats || $ShowDaysOfMonthStats)) || $HTMLOutput{'alldays'}) { $SectionsToLoad{'day'}=$order++; } + # Who + if ($UpdateStats || $MigrateStats || ($HTMLOutput{'main'} && $ShowDomainsStats) || $HTMLOutput{'alldomains'}) { $SectionsToLoad{'domain'}=$order++; } + if ($UpdateStats || $MigrateStats || ($HTMLOutput{'main'} && $ShowAuthenticatedUsers) || $HTMLOutput{'alllogins'} || $HTMLOutput{'lastlogins'}) { $SectionsToLoad{'login'}=$order++; } + if ($UpdateStats || $MigrateStats || ($HTMLOutput{'main'} && $ShowRobotsStats) || $HTMLOutput{'allrobots'} || $HTMLOutput{'lastrobots'}) { $SectionsToLoad{'robot'}=$order++; } + if ($UpdateStats || $MigrateStats || ($HTMLOutput{'main'} && $ShowWormsStats) || $HTMLOutput{'allworms'} || $HTMLOutput{'lastworms'}) { $SectionsToLoad{'worms'}=$order++; } + if ($UpdateStats || $MigrateStats || ($HTMLOutput{'main'} && $ShowEMailSenders) || $HTMLOutput{'allemails'} || $HTMLOutput{'lastemails'}) { $SectionsToLoad{'emailsender'}=$order++; } + if ($UpdateStats || $MigrateStats || ($HTMLOutput{'main'} && $ShowEMailReceivers) || $HTMLOutput{'allemailr'} || $HTMLOutput{'lastemailr'}) { $SectionsToLoad{'emailreceiver'}=$order++; } + # Navigation + if ($UpdateStats || $MigrateStats || ($HTMLOutput{'main'} && $ShowSessionsStats) || $HTMLOutput{'sessions'}) { $SectionsToLoad{'session'}=$order++; } + if ($UpdateStats || $MigrateStats || ($HTMLOutput{'main'} && $ShowPagesStats) || $HTMLOutput{'urldetail'} || $HTMLOutput{'urlentry'} || $HTMLOutput{'urlexit'}) { $SectionsToLoad{'sider'}=$order++; } + if ($UpdateStats || $MigrateStats || ($HTMLOutput{'main'} && $ShowFileTypesStats) || $HTMLOutput{'filetypes'}) { $SectionsToLoad{'filetypes'}=$order++; } + if ($UpdateStats || $MigrateStats || ($HTMLOutput{'main'} && $ShowOSStats) || $HTMLOutput{'osdetail'}) { $SectionsToLoad{'os'}=$order++; } + if ($UpdateStats || $MigrateStats || ($HTMLOutput{'main'} && $ShowBrowsersStats) || $HTMLOutput{'browserdetail'}) { $SectionsToLoad{'browser'}=$order++; } + if ($UpdateStats || $MigrateStats || $HTMLOutput{'unknownos'}) { $SectionsToLoad{'unknownreferer'}=$order++; } + if ($UpdateStats || $MigrateStats || $HTMLOutput{'unknownbrowser'}) { $SectionsToLoad{'unknownrefererbrowser'}=$order++; } + if ($UpdateStats || $MigrateStats || ($HTMLOutput{'main'} && $ShowScreenSizeStats)) { $SectionsToLoad{'screensize'}=$order++; } + # Referers + if ($UpdateStats || $MigrateStats || ($HTMLOutput{'main'} && $ShowOriginStats) || $HTMLOutput{'origin'}) { $SectionsToLoad{'origin'}=$order++; } + if ($UpdateStats || $MigrateStats || ($HTMLOutput{'main'} && $ShowOriginStats) || $HTMLOutput{'refererse'}) { $SectionsToLoad{'sereferrals'}=$order++; } + if ($UpdateStats || $MigrateStats || ($HTMLOutput{'main'} && $ShowOriginStats) || $HTMLOutput{'refererpages'}) { $SectionsToLoad{'pagerefs'}=$order++; } + if ($UpdateStats || $MigrateStats || ($HTMLOutput{'main'} && $ShowKeyphrasesStats) || $HTMLOutput{'keyphrases'} || $HTMLOutput{'keywords'}) { $SectionsToLoad{'searchwords'}=$order++; } + if (! $withupdate && $HTMLOutput{'main'} && $ShowKeywordsStats) { $SectionsToLoad{'keywords'}=$order++; } # If we update, dont need to load + # Others + if ($UpdateStats || $MigrateStats || ($HTMLOutput{'main'} && $ShowMiscStats)) { $SectionsToLoad{'misc'}=$order++; } + if ($UpdateStats || $MigrateStats || ($HTMLOutput{'main'} && ($ShowHTTPErrorsStats || $ShowSMTPErrorsStats)) || $HTMLOutput{'errors'}) { $SectionsToLoad{'errors'}=$order++; } + foreach (keys %TrapInfosForHTTPErrorCodes) { + if ($UpdateStats || $MigrateStats || $HTMLOutput{"errors$_"}) { $SectionsToLoad{"sider_$_"}=$order++; } + } + if ($UpdateStats || $MigrateStats || ($HTMLOutput{'main'} && $ShowClusterStats)) { $SectionsToLoad{'cluster'}=$order++; } + foreach (1..@ExtraName-1) { + if ($UpdateStats || $MigrateStats || ($HTMLOutput{'main'} && $ExtraStatTypes[$_]) || $HTMLOutput{"extra$_"}) { $SectionsToLoad{"extra_$_"}=$order++; } + } + foreach (keys %{$PluginsLoaded{'SectionInitHashArray'}}) { + if ($UpdateStats || $MigrateStats || $HTMLOutput{"plugin_$_"}) { $SectionsToLoad{"plugin_$_"}=$order++; } + } + } + else { # Load only required sections + my $order=1; + foreach (split(/\s+/,$part)) { $SectionsToLoad{$_}=$order++; } + } + + # Define SectionsToSave (which sections to save) + my %SectionsToSave = (); + if ($withupdate) { + if ($SectionsToBeSaved eq 'all') { + %SectionsToSave=%allsections; + } else { + my $order=1; + foreach (split(/\s+/,$SectionsToBeSaved)) { $SectionsToSave{$_}=$order++; } + } + } + + if ($Debug) { + debug(" List of sections marked for load : ".join(' ',(sort { $SectionsToLoad{$a} <=> $SectionsToLoad{$b} } keys %SectionsToLoad)),2); + debug(" List of sections marked for save : ".join(' ',(sort { $SectionsToSave{$a} <=> $SectionsToSave{$b} } keys %SectionsToSave)),2); + } + + # Define value for filetowrite and filetoread (Month before Year kept for backward compatibility) + my $filetowrite=''; + my $filetoread=''; + if ($HistoryAlreadyFlushed{"$year$month$day$hour"} && -s "$DirData/$PROG$filedate$FileSuffix.tmp.$$") { + # tmp history file was already flushed + $filetoread="$DirData/$PROG$filedate$FileSuffix.tmp.$$"; + $filetowrite="$DirData/$PROG$filedate$FileSuffix.tmp.$$.bis"; + } + else { + $filetoread="$DirData/$PROG$filedate$FileSuffix.txt"; + $filetowrite="$DirData/$PROG$filedate$FileSuffix.tmp.$$"; + } + if ($Debug) { debug(" History file to read is '$filetoread'",2); } + + # Is there an old data file to read or, if migrate, can we open the file for read + if (-s $filetoread || $MigrateStats) { $withread=1; } + + # Open files + if ($withread) { + open(HISTORY,$filetoread) || error("Couldn't open file \"$filetoread\" for read: $!","","",$MigrateStats); + binmode HISTORY; # Avoid premature EOF due to history files corrupted with \cZ or bin chars + } + if ($withupdate) { + open(HISTORYTMP,">$filetowrite") || error("Couldn't open file \"$filetowrite\" for write: $!"); + binmode HISTORYTMP; + if ($xml) { print HISTORYTMP ''."\n\n"; } + Save_History("header",$year,$month,$date); + } + + # Loop on read file + my $readxml=0; + if ($withread) { + my $countlines=0; + my $versionnum=0; + my @field=(); + while () { + chomp $_; s/\r//; + $countlines++; + + # Test if it's xml + if (! $readxml && $_ =~ /^ int($field[1])) { $FirstTime{$date}=int($field[1]); }; next; } + if ($field[0] eq 'LastTime' || $field[0] eq "${xmlrb}LastTime") { if (! $LastTime{$date} || $LastTime{$date} < int($field[1])) { $LastTime{$date}=int($field[1]); }; next; } + if ($field[0] eq 'LastUpdate' || $field[0] eq "${xmlrb}LastUpdate") { + if ($LastUpdate < $field[1]) { + $LastUpdate=int($field[1]); + #$LastUpdateLinesRead=int($field[2]); + #$LastUpdateNewLinesRead=int($field[3]); + #$LastUpdateLinesCorrupted=int($field[4]); + }; + next; + } + if ($field[0] eq 'TotalVisits' || $field[0] eq "${xmlrb}TotalVisits") { + if (! $withupdate) { $MonthVisits{$year.$month}+=int($field[1]); } + next; + } + if ($field[0] eq 'TotalUnique' || $field[0] eq "${xmlrb}TotalUnique") { if (! $withupdate) { $MonthUnique{$year.$month}+=int($field[1]); } next; } + if ($field[0] eq 'MonthHostsKnown' || $field[0] eq "${xmlrb}MonthHostsKnown") { if (! $withupdate) { $MonthHostsKnown{$year.$month}+=int($field[1]); } next; } + if ($field[0] eq 'MonthHostsUnknown' || $field[0] eq "${xmlrb}MonthHostsUnknown") { if (! $withupdate) { $MonthHostsUnknown{$year.$month}+=int($field[1]); } next; } + if (($field[0] eq 'END_GENERAL' || $field[0] eq "${xmleb}END_GENERAL")) { + if ($Debug) { debug(" End of GENERAL section"); } + if ($MigrateStats && ! $BadFormatWarning{$year.$month}) { + $BadFormatWarning{$year.$month}=1; + warning("Warning: You are migrating a file that is already a recent version (migrate not required for files version $versionnum).","","",1); + } + + delete $SectionsToLoad{'general'}; + if ($SectionsToSave{'general'}) { + Save_History('general',$year,$month,$date,$lastlinenb,$lastlineoffset,$lastlinechecksum); delete $SectionsToSave{'general'}; + } + if (! scalar %SectionsToLoad) { debug(" Stop reading history file. Got all we need."); last; } + next; + } + + # BEGIN_MISC + if ($field[0] eq 'BEGIN_MISC') { + if ($Debug) { debug(" Begin of MISC section"); } + $field[0]=''; + my $count=0;my $countloaded=0; + do { + if ($field[0]) { + $count++; + if ($SectionsToLoad{'misc'}) { + $countloaded++; + if ($field[1]) { $_misc_p{$field[0]}+=int($field[1]); } + if ($field[2]) { $_misc_h{$field[0]}+=int($field[2]); } + if ($field[3]) { $_misc_k{$field[0]}+=int($field[3]); } + } + } + $_=; + chomp $_; s/\r//; + @field=split(/\s+/,($readxml?CleanFromTags($_):$_)); $countlines++; + } + until ($field[0] eq 'END_MISC' || $field[0] eq "${xmleb}END_MISC" || ! $_); + if ($field[0] ne 'END_MISC' && $field[0] ne "${xmleb}END_MISC") { error("History file \"$filetoread\" is corrupted (End of section MISC not found).\nRestore a recent backup of this file (data for this month will be restored to backup date), remove it (data for month will be lost), or remove the corrupted section in file (data for at least this section will be lost).","","",1); } + if ($Debug) { debug(" End of MISC section ($count entries, $countloaded loaded)"); } + delete $SectionsToLoad{'misc'}; + if ($SectionsToSave{'misc'}) { + Save_History('misc',$year,$month,$date); delete $SectionsToSave{'misc'}; + if ($withpurge) { %_misc_p=(); %_misc_h=(); %_misc_k=(); } + } + if (! scalar %SectionsToLoad) { debug(" Stop reading history file. Got all we need."); last; } + next; + } + + # BEGIN_CLUSTER + if ($field[0] eq 'BEGIN_CLUSTER') { + if ($Debug) { debug(" Begin of CLUSTER section"); } + $field[0]=''; + my $count=0;my $countloaded=0; + do { + if ($field[0]) { + $count++; + if ($SectionsToLoad{'cluster'}) { + $countloaded++; + if ($field[1]) { $_cluster_p{$field[0]}+=int($field[1]); } + if ($field[2]) { $_cluster_h{$field[0]}+=int($field[2]); } + if ($field[3]) { $_cluster_k{$field[0]}+=int($field[3]); } + } + } + $_=; + chomp $_; s/\r//; + @field=split(/\s+/,($readxml?CleanFromTags($_):$_)); $countlines++; + } + until ($field[0] eq 'END_CLUSTER' || $field[0] eq "${xmleb}END_CLUSTER" || ! $_); + if ($field[0] ne 'END_CLUSTER' && $field[0] ne "${xmleb}END_CLUSTER") { error("History file \"$filetoread\" is corrupted (End of section CLUSTER not found).\nRestore a recent backup of this file (data for this month will be restored to backup date), remove it (data for month will be lost), or remove the corrupted section in file (data for at least this section will be lost).","","",1); } + if ($Debug) { debug(" End of CLUSTER section ($count entries, $countloaded loaded)"); } + delete $SectionsToLoad{'cluster'}; + if ($SectionsToSave{'cluster'}) { + Save_History('cluster',$year,$month,$date); delete $SectionsToSave{'cluster'}; + if ($withpurge) { %_cluster_p=(); %_cluster_h=(); %_cluster_k=(); } + } + if (! scalar %SectionsToLoad) { debug(" Stop reading history file. Got all we need."); last; } + next; + } + + # BEGIN_TIME + if ($field[0] eq 'BEGIN_TIME') { + my $monthpages=0;my $monthhits=0;my $monthbytes=0; + my $monthnotviewedpages=0;my $monthnotviewedhits=0;my $monthnotviewedbytes=0; + if ($Debug) { debug(" Begin of TIME section"); } + $field[0]=''; + my $count=0;my $countloaded=0; + do { + if ($field[0] ne '') { # Test on ne '' because field[0] is '0' for hour 0) + $count++; + if ($SectionsToLoad{'time'}) { + if ($withupdate || $MonthRequired eq 'all' || $MonthRequired eq "$month") { # Still required + $countloaded++; + if ($field[1]) { $_time_p[$field[0]]+=int($field[1]); } + if ($field[2]) { $_time_h[$field[0]]+=int($field[2]); } + if ($field[3]) { $_time_k[$field[0]]+=int($field[3]); } + if ($field[4]) { $_time_nv_p[$field[0]]+=int($field[4]); } + if ($field[5]) { $_time_nv_h[$field[0]]+=int($field[5]); } + if ($field[6]) { $_time_nv_k[$field[0]]+=int($field[6]); } + } + $monthpages+=int($field[1]); + $monthhits+=int($field[2]); + $monthbytes+=int($field[3]); + $monthnotviewedpages+=int($field[4]||0); + $monthnotviewedhits+=int($field[5]||0); + $monthnotviewedbytes+=int($field[6]||0); + } + } + $_=; + chomp $_; s/\r//; + @field=split(/\s+/,($readxml?CleanFromTags($_):$_)); $countlines++; + } + until ($field[0] eq 'END_TIME' || $field[0] eq "${xmleb}END_TIME" || ! $_); + if ($field[0] ne 'END_TIME' && $field[0] ne "${xmleb}END_TIME") { error("History file \"$filetoread\" is corrupted (End of section TIME not found).\nRestore a recent backup of this file (data for this month will be restored to backup date), remove it (data for month will be lost), or remove the corrupted section in file (data for at least this section will be lost).","","",1); } + if ($Debug) { debug(" End of TIME section ($count entries, $countloaded loaded)"); } + $MonthPages{$year.$month}+=$monthpages; + $MonthHits{$year.$month}+=$monthhits; + $MonthBytes{$year.$month}+=$monthbytes; + $MonthNotViewedPages{$year.$month}+=$monthnotviewedpages; + $MonthNotViewedHits{$year.$month}+=$monthnotviewedhits; + $MonthNotViewedBytes{$year.$month}+=$monthnotviewedbytes; + delete $SectionsToLoad{'time'}; + if ($SectionsToSave{'time'}) { + Save_History('time',$year,$month,$date); delete $SectionsToSave{'time'}; + if ($withpurge) { @_time_p=(); @_time_h=(); @_time_k=(); @_time_nv_p=(); @_time_nv_h=(); @_time_nv_k=(); } + } + if (! scalar %SectionsToLoad) { debug(" Stop reading history file. Got all we need."); last; } + next; + } + + # BEGIN_ORIGIN + if ($field[0] eq 'BEGIN_ORIGIN') { + if ($Debug) { debug(" Begin of ORIGIN section"); } + $field[0]=''; + my $count=0;my $countloaded=0; + do { + if ($field[0]) { + $count++; + if ($SectionsToLoad{'origin'}) { + if ($field[0] eq 'From0') { $_from_p[0]+=$field[1]; $_from_h[0]+=$field[2]; } + elsif ($field[0] eq 'From1') { $_from_p[1]+=$field[1]; $_from_h[1]+=$field[2]; } + elsif ($field[0] eq 'From2') { $_from_p[2]+=$field[1]; $_from_h[2]+=$field[2]; } + elsif ($field[0] eq 'From3') { $_from_p[3]+=$field[1]; $_from_h[3]+=$field[2]; } + elsif ($field[0] eq 'From4') { $_from_p[4]+=$field[1]; $_from_h[4]+=$field[2]; } + elsif ($field[0] eq 'From5') { $_from_p[5]+=$field[1]; $_from_h[5]+=$field[2]; } + } + } + $_=; + chomp $_; s/\r//; + @field=split(/\s+/,($readxml?CleanFromTags($_):$_)); $countlines++; + } + until ($field[0] eq 'END_ORIGIN' || $field[0] eq "${xmleb}END_ORIGIN" || ! $_); + if ($field[0] ne 'END_ORIGIN' && $field[0] ne "${xmleb}END_ORIGIN") { error("History file \"$filetoread\" is corrupted (End of section ORIGIN not found).\nRestore a recent backup of this file (data for this month will be restored to backup date), remove it (data for month will be lost), or remove the corrupted section in file (data for at least this section will be lost).","","",1); } + if ($Debug) { debug(" End of ORIGIN section ($count entries, $countloaded loaded)"); } + delete $SectionsToLoad{'origin'}; + if ($SectionsToSave{'origin'}) { + Save_History('origin',$year,$month,$date); delete $SectionsToSave{'origin'}; + if ($withpurge) { @_from_p=(); @_from_h=(); } + } + if (! scalar %SectionsToLoad) { debug(" Stop reading history file. Got all we need."); last; } + next; + } + # BEGIN_DAY + if ($field[0] eq 'BEGIN_DAY') { + if ($Debug) { debug(" Begin of DAY section"); } + $field[0]=''; + my $count=0;my $countloaded=0; + do { + if ($field[0]) { + $count++; + if ($SectionsToLoad{'day'}) { + $countloaded++; + if ($field[1]) { $DayPages{$field[0]}+=int($field[1]); } + $DayHits{$field[0]}+=int($field[2]); # DayHits always load (should be >0 and if not it's a day YYYYMM00 resulting of an old file migration) + if ($field[3]) { $DayBytes{$field[0]}+=int($field[3]); } + if ($field[4]) { $DayVisits{$field[0]}+=int($field[4]); } + } + } + $_=; + chomp $_; s/\r//; + @field=split(/\s+/,($readxml?CleanFromTags($_):$_)); $countlines++; + } + until ($field[0] eq 'END_DAY' || $field[0] eq "${xmleb}END_DAY" || ! $_); + if ($field[0] ne 'END_DAY' && $field[0] ne "${xmleb}END_DAY") { error("History file \"$filetoread\" is corrupted (End of section DAY not found).\nRestore a recent backup of this file (data for this month will be restored to backup date), remove it (data for month will be lost), or remove the corrupted section in file (data for at least this section will be lost).","","",1); } + if ($Debug) { debug(" End of DAY section ($count entries, $countloaded loaded)"); } + delete $SectionsToLoad{'day'}; + # WE DO NOT SAVE SECTION NOW BECAUSE VALUES CAN BE CHANGED AFTER READING VISITOR + #if ($SectionsToSave{'day'}) { # Must be made after read of visitor + # Save_History('day',$year,$month,$date); delete $SectionsToSave{'day'}; + # if ($withpurge) { %DayPages=(); %DayHits=(); %DayBytes=(); %DayVisits=(); } + #} + if (! scalar %SectionsToLoad) { debug(" Stop reading history file. Got all we need."); last; } + next; + } + # BEGIN_VISITOR + if ($field[0] eq 'BEGIN_VISITOR') { + if ($Debug) { debug(" Begin of VISITOR section"); } + $field[0]=''; + my $count=0;my $countloaded=0; + do { + if ($field[0]) { + $count++; + + # For backward compatibility + if ($readvisitorforbackward) { + if ($field[1]) { $MonthUnique{$year.$month}++; } + if ($MonthRequired ne 'all') { + if ($field[0] !~ /^\d+\.\d+\.\d+\.\d+$/ && $field[0] !~ /^[0-9A-F]*:/i) { $MonthHostsKnown{$year.$month}++; } + else { $MonthHostsUnknown{$year.$month}++; } + } + } + + # Process data saved in 'wait' arrays + if ($withupdate && $_waithost_e{$field[0]}){ + my $timehostl=int($field[4]||0); + my $timehosts=int($field[5]||0); + my $newtimehosts=($_waithost_s{$field[0]}?$_waithost_s{$field[0]}:$_host_s{$field[0]}); + my $newtimehostl=($_waithost_l{$field[0]}?$_waithost_l{$field[0]}:$_host_l{$field[0]}); + if ($newtimehosts > $timehostl + $VISITTIMEOUT ) { + if ($Debug) { debug(" Visit for $field[0] in 'wait' arrays is a new visit different than last in history",4); } + if ($field[6]) { $_url_x{$field[6]}++; } + $_url_e{$_waithost_e{$field[0]}}++; + $newtimehosts =~ /^(\d\d\d\d\d\d\d\d)/; $DayVisits{$1}++; + if ($timehosts && $timehostl) { $_session{GetSessionRange($timehosts,$timehostl)}++; } + if ($_waithost_s{$field[0]}) { + # First session found in log was followed by another one so it's finished + $_session{GetSessionRange($newtimehosts,$newtimehostl)}++; + } + # Here $_host_l $_host_s and $_host_u are correctly defined + } + else { + if ($Debug) { debug(" Visit for $field[0] in 'wait' arrays is following of last visit in history",4); } + if ($_waithost_s{$field[0]}) { + # First session found in log was followed by another one so it's finished + $_session{GetSessionRange(MinimumButNoZero($timehosts,$newtimehosts),$timehostl>$newtimehostl?$timehostl:$newtimehostl)}++; + # Here $_host_l $_host_s and $_host_u are correctly defined + } + else { + # We correct $_host_l $_host_s and $_host_u + if ($timehostl > $newtimehostl) { + $_host_l{$field[0]}=$timehostl; + $_host_u{$field[0]}=$field[6]; + } + if ($timehosts < $newtimehosts) { + $_host_s{$field[0]}=$timehosts; + } + } + } + delete $_waithost_e{$field[0]}; + delete $_waithost_l{$field[0]}; + delete $_waithost_s{$field[0]}; + delete $_waithost_u{$field[0]}; + } + + # Load records + if ($readvisitorforbackward!=2 && $SectionsToLoad{'visitor'}) { # if readvisitorforbackward==2 we do not load + my $loadrecord=0; + if ($withupdate) { + $loadrecord=1; + } + else { + if ($HTMLOutput{'allhosts'} || $HTMLOutput{'lasthosts'}) { + if ((!$FilterIn{'host'} || $field[0] =~ /$FilterIn{'host'}/i) + && (!$FilterEx{'host'} || $field[0] !~ /$FilterEx{'host'}/i)) { $loadrecord=1; } + } + elsif ($MonthRequired eq 'all' || $field[2] >= $MinHit{'Host'}) { + if ($HTMLOutput{'unknownip'} && ($field[0] =~ /^\d+\.\d+\.\d+\.\d+$/ || $field[0] =~ /^[0-9A-F]*:/i)) { $loadrecord=1; } + elsif ($HTMLOutput{'main'} && ($MonthRequired eq 'all' || $countloaded < $MaxNbOf{'HostsShown'})) { $loadrecord=1; } + } + } + if ($loadrecord) { + if ($field[1]) { $_host_p{$field[0]}+=$field[1]; } + if ($field[2]) { $_host_h{$field[0]}+=$field[2]; } + if ($field[3]) { $_host_k{$field[0]}+=$field[3]; } + if ($field[4] && ! $_host_l{$field[0]}) { # We save last connexion params if not previously defined + $_host_l{$field[0]}=int($field[4]); + if ($withupdate) { # field[5] field[6] are used only for update + if ($field[5] && ! $_host_s{$field[0]}) { $_host_s{$field[0]}=int($field[5]); } + if ($field[6] && ! $_host_u{$field[0]}) { $_host_u{$field[0]}=$field[6]; } + } + } + $countloaded++; + } + } + } + $_=; + chomp $_; s/\r//; + @field=split(/\s+/,($readxml?CleanFromTags($_):$_)); $countlines++; + } + until ($field[0] eq 'END_VISITOR' || $field[0] eq "${xmleb}END_VISITOR" || ! $_); + if ($field[0] ne 'END_VISITOR' && $field[0] ne "${xmleb}END_VISITOR") { error("History file \"$filetoread\" is corrupted (End of section VISITOR not found).\nRestore a recent backup of this file (data for this month will be restored to backup date), remove it (data for month will be lost), or remove the corrupted section in file (data for at least this section will be lost).","","",1); } + if ($Debug) { debug(" End of VISITOR section ($count entries, $countloaded loaded)"); } + delete $SectionsToLoad{'visitor'}; + # WE DO NOT SAVE SECTION NOW TO BE SURE TO HAVE THIS LARGE SECTION NOT AT THE BEGINNING OF FILE + #if ($SectionsToSave{'visitor'}) { + # Save_History('visitor',$year,$month,$date); delete $SectionsToSave{'visitor'}; + # if ($withpurge) { %_host_p=(); %_host_h=(); %_host_k=(); %_host_l=(); %_host_s=(); %_host_u=(); } + #} + if (! scalar %SectionsToLoad) { debug(" Stop reading history file. Got all we need."); last; } + next; + } + # BEGIN_UNKNOWNIP for backward compatibility + if ($field[0] eq 'BEGIN_UNKNOWNIP') { + my %iptomigrate=(); + if ($Debug) { debug(" Begin of UNKNOWNIP section"); } + $field[0]=''; + my $count=0;my $countloaded=0; + do { + if ($field[0]) { + $count++; + if ($SectionsToLoad{'unknownip'}) { + $iptomigrate{$field[0]}=$field[1]||0; + $countloaded++; + } + } + $_=; + chomp $_; s/\r//; + @field=split(/\s+/,($readxml?CleanFromTags($_):$_)); $countlines++; + } + until ($field[0] eq 'END_UNKNOWNIP' || $field[0] eq "${xmleb}END_UNKNOWNIP" || ! $_); + if ($field[0] ne 'END_UNKNOWNIP' && $field[0] ne "${xmleb}END_UNKNOWNIP") { error("History file \"$filetoread\" is corrupted (End of section UNKOWNIP not found).\nRestore a recent backup of this file (data for this month will be restored to backup date), remove it (data for month will be lost), or remove the corrupted section in file (data for at least this section will be lost).","","",1); } + if ($Debug) { debug(" End of UNKOWNIP section ($count entries, $countloaded loaded)"); } + delete $SectionsToLoad{'visitor'}; + # THIS SECTION IS NEVER SAVED. ONLY READ FOR MIGRATE AND CONVERTED INTO VISITOR SECTION + foreach (keys %iptomigrate) { + $_host_p{$_}+=int($_host_p{'Unknown'}/$countloaded); + $_host_h{$_}+=int($_host_h{'Unknown'}/$countloaded); + $_host_k{$_}+=int($_host_k{'Unknown'}/$countloaded); + if ($iptomigrate{$_} > 0) { $_host_l{$_}=$iptomigrate{$_} }; + } + delete $_host_p{'Unknown'}; + delete $_host_h{'Unknown'}; + delete $_host_k{'Unknown'}; + delete $_host_l{'Unknown'}; + if (! scalar %SectionsToLoad) { debug(" Stop reading history file. Got all we need."); last; } + next; + } + # BEGIN_LOGIN + if ($field[0] eq 'BEGIN_LOGIN') { + if ($Debug) { debug(" Begin of LOGIN section"); } + $field[0]=''; + my $count=0;my $countloaded=0; + do { + if ($field[0]) { + $count++; + if ($SectionsToLoad{'login'}) { + $countloaded++; + if ($field[1]) { $_login_p{$field[0]}+=$field[1]; } + if ($field[2]) { $_login_h{$field[0]}+=$field[2]; } + if ($field[3]) { $_login_k{$field[0]}+=$field[3]; } + if (! $_login_l{$field[0]} && $field[4]) { $_login_l{$field[0]}=int($field[4]); } + } + } + $_=; + chomp $_; s/\r//; + @field=split(/\s+/,($readxml?CleanFromTags($_):$_)); $countlines++; + } + until ($field[0] eq 'END_LOGIN' || $field[0] eq "${xmleb}END_LOGIN" || ! $_); + if ($field[0] ne 'END_LOGIN' && $field[0] ne "${xmleb}END_LOGIN") { error("History file \"$filetoread\" is corrupted (End of section LOGIN not found).\nRestore a recent backup of this file (data for this month will be restored to backup date), remove it (data for month will be lost), or remove the corrupted section in file (data for at least this section will be lost).","","",1); } + if ($Debug) { debug(" End of LOGIN section ($count entries, $countloaded loaded)"); } + delete $SectionsToLoad{'login'}; + if ($SectionsToSave{'login'}) { + Save_History('login',$year,$month,$date); delete $SectionsToSave{'login'}; + if ($withpurge) { %_login_p=(); %_login_h=(); %_login_k=(); %_login_l=(); } + } + if (! scalar %SectionsToLoad) { debug(" Stop reading history file. Got all we need."); last; } + next; + } + # BEGIN_DOMAIN + if ($field[0] eq 'BEGIN_DOMAIN') { + if ($Debug) { debug(" Begin of DOMAIN section"); } + $field[0]=''; + my $count=0;my $countloaded=0; + do { + if ($field[0]) { + $count++; + if ($SectionsToLoad{'domain'}) { + $countloaded++; + if ($field[1]) { $_domener_p{$field[0]}+=$field[1]; } + if ($field[2]) { $_domener_h{$field[0]}+=$field[2]; } + if ($field[3]) { $_domener_k{$field[0]}+=$field[3]; } + } + } + $_=; + chomp $_; s/\r//; + @field=split(/\s+/,($readxml?CleanFromTags($_):$_)); $countlines++; + } + until ($field[0] eq 'END_DOMAIN' || $field[0] eq "${xmleb}END_DOMAIN" || ! $_); + if ($field[0] ne 'END_DOMAIN' && $field[0] ne "${xmleb}END_DOMAIN") { error("History file \"$filetoread\" is corrupted (End of section DOMAIN not found).\nRestore a recent backup of this file (data for this month will be restored to backup date), remove it (data for month will be lost), or remove the corrupted section in file (data for at least this section will be lost).","","",1); } + if ($Debug) { debug(" End of DOMAIN section ($count entries, $countloaded loaded)"); } + delete $SectionsToLoad{'domain'}; + if ($SectionsToSave{'domain'}) { + Save_History('domain',$year,$month,$date); delete $SectionsToSave{'domain'}; + if ($withpurge) { %_domener_p=(); %_domener_h=(); %_domener_k=(); } + } + if (! scalar %SectionsToLoad) { debug(" Stop reading history file. Got all we need."); last; } + next; + } + # BEGIN_SESSION + if ($field[0] eq 'BEGIN_SESSION') { + if ($Debug) { debug(" Begin of SESSION section"); } + $field[0]=''; + my $count=0;my $countloaded=0; + do { + if ($field[0]) { + $count++; + if ($SectionsToLoad{'session'}) { + $countloaded++; + if ($field[1]) { $_session{$field[0]}+=$field[1]; } + } + } + $_=; + chomp $_; s/\r//; + @field=split(/\s+/,($readxml?CleanFromTags($_):$_)); $countlines++; + } + until ($field[0] eq 'END_SESSION' || $field[0] eq "${xmleb}END_SESSION" || ! $_); + if ($field[0] ne 'END_SESSION' && $field[0] ne "${xmleb}END_SESSION") { error("History file \"$filetoread\" is corrupted (End of section SESSION not found).\nRestore a recent backup of this file (data for this month will be restored to backup date), remove it (data for month will be lost), or remove the corrupted section in file (data for at least this section will be lost).","","",1); } + if ($Debug) { debug(" End of SESSION section ($count entries, $countloaded loaded)"); } + delete $SectionsToLoad{'session'}; + # WE DO NOT SAVE SECTION NOW BECAUSE VALUES CAN BE CHANGED AFTER READING VISITOR + #if ($SectionsToSave{'session'}) { + # Save_History('session',$year,$month,$date); delete $SectionsToSave{'session'}; } + # if ($withpurge) { %_session=(); } + #} + if (! scalar %SectionsToLoad) { debug(" Stop reading history file. Got all we need."); last; } + next; + } + # BEGIN_OS + if ($field[0] eq 'BEGIN_OS') { + if ($Debug) { debug(" Begin of OS section"); } + $field[0]=''; + my $count=0;my $countloaded=0; + do { + if ($field[0]) { + $count++; + if ($SectionsToLoad{'os'}) { + $countloaded++; + if ($field[1]) { $_os_h{$field[0]}+=$field[1]; } + } + } + $_=; + chomp $_; s/\r//; + @field=split(/\s+/,($readxml?CleanFromTags($_):$_)); $countlines++; + } + until ($field[0] eq 'END_OS' || $field[0] eq "${xmleb}END_OS" || ! $_); + if ($field[0] ne 'END_OS' && $field[0] ne "${xmleb}END_OS") { error("History file \"$filetoread\" is corrupted (End of section OS not found).\nRestore a recent backup of this file (data for this month will be restored to backup date), remove it (data for month will be lost), or remove the corrupted section in file (data for at least this section will be lost).","","",1); } + if ($Debug) { debug(" End of OS section ($count entries, $countloaded loaded)"); } + delete $SectionsToLoad{'os'}; + if ($SectionsToSave{'os'}) { + Save_History('os',$year,$month,$date); delete $SectionsToSave{'os'}; + if ($withpurge) { %_os_h=(); } + } + if (! scalar %SectionsToLoad) { debug(" Stop reading history file. Got all we need."); last; } + next; + } + # BEGIN_BROWSER + if ($field[0] eq 'BEGIN_BROWSER') { + if ($Debug) { debug(" Begin of BROWSER section"); } + $field[0]=''; + my $count=0;my $countloaded=0; + do { + if ($field[0]) { + $count++; + if ($SectionsToLoad{'browser'}) { + $countloaded++; + if ($field[1]) { $_browser_h{$field[0]}+=$field[1]; } + } + } + $_=; + chomp $_; s/\r//; + @field=split(/\s+/,($readxml?CleanFromTags($_):$_)); $countlines++; + } + until ($field[0] eq 'END_BROWSER' || $field[0] eq "${xmleb}END_BROWSER" || ! $_); + if ($field[0] ne 'END_BROWSER' && $field[0] ne "${xmleb}END_BROWSER") { error("History file \"$filetoread\" is corrupted (End of section BROWSER not found).\nRestore a recent backup of this file (data for this month will be restored to backup date), remove it (data for month will be lost), or remove the corrupted section in file (data for at least this section will be lost).","","",1); } + if ($Debug) { debug(" End of BROWSER section ($count entries, $countloaded loaded)"); } + delete $SectionsToLoad{'browser'}; + if ($SectionsToSave{'browser'}) { + Save_History('browser',$year,$month,$date); delete $SectionsToSave{'browser'}; + if ($withpurge) { %_browser_h=(); } + } + if (! scalar %SectionsToLoad) { debug(" Stop reading history file. Got all we need."); last; } + next; + } + # BEGIN_UNKNOWNREFERER + if ($field[0] eq 'BEGIN_UNKNOWNREFERER') { + if ($Debug) { debug(" Begin of UNKNOWNREFERER section"); } + $field[0]=''; + my $count=0;my $countloaded=0; + do { + if ($field[0]) { + $count++; + if ($SectionsToLoad{'unknownreferer'}) { + $countloaded++; + if (! $_unknownreferer_l{$field[0]}) { $_unknownreferer_l{$field[0]}=int($field[1]); } + } + } + $_=; + chomp $_; s/\r//; + @field=split(/\s+/,($readxml?CleanFromTags($_):$_)); $countlines++; + } + until ($field[0] eq 'END_UNKNOWNREFERER' || $field[0] eq "${xmleb}END_UNKNOWNREFERER" || ! $_); + if ($field[0] ne 'END_UNKNOWNREFERER' && $field[0] ne "${xmleb}END_UNKNOWNREFERER") { error("History file \"$filetoread\" is corrupted (End of section UNKNOWNREFERER not found).\nRestore a recent backup of this file (data for this month will be restored to backup date), remove it (data for month will be lost), or remove the corrupted section in file (data for at least this section will be lost).","","",1); } + if ($Debug) { debug(" End of UNKNOWNREFERER section ($count entries, $countloaded loaded)"); } + delete $SectionsToLoad{'unknownreferer'}; + if ($SectionsToSave{'unknownreferer'}) { + Save_History('unknownreferer',$year,$month,$date); delete $SectionsToSave{'unknownreferer'}; + if ($withpurge) { %_unknownreferer_l=(); } + } + if (! scalar %SectionsToLoad) { debug(" Stop reading history file. Got all we need."); last; } + next; + } + # BEGIN_UNKNOWNREFERERBROWSER + if ($field[0] eq 'BEGIN_UNKNOWNREFERERBROWSER') { + if ($Debug) { debug(" Begin of UNKNOWNREFERERBROWSER section"); } + $field[0]=''; + my $count=0;my $countloaded=0; + do { + if ($field[0]) { + $count++; + if ($SectionsToLoad{'unknownrefererbrowser'}) { + $countloaded++; + if (! $_unknownrefererbrowser_l{$field[0]}) { $_unknownrefererbrowser_l{$field[0]}=int($field[1]); } + } + } + $_=; + chomp $_; s/\r//; + @field=split(/\s+/,($readxml?CleanFromTags($_):$_)); $countlines++; + } + until ($field[0] eq 'END_UNKNOWNREFERERBROWSER' || $field[0] eq "${xmleb}END_UNKNOWNREFERERBROWSER" || ! $_); + if ($field[0] ne 'END_UNKNOWNREFERERBROWSER' && $field[0] ne "${xmleb}END_UNKNOWNREFERERBROWSER") { error("History file \"$filetoread\" is corrupted (End of section UNKNOWNREFERERBROWSER not found).\nRestore a recent backup of this file (data for this month will be restored to backup date), remove it (data for month will be lost), or remove the corrupted section in file (data for at least this section will be lost).","","",1); } + if ($Debug) { debug(" End of UNKNOWNREFERERBROWSER section ($count entries, $countloaded loaded)"); } + delete $SectionsToLoad{'unknownrefererbrowser'}; + if ($SectionsToSave{'unknownrefererbrowser'}) { + Save_History('unknownrefererbrowser',$year,$month,$date); delete $SectionsToSave{'unknownrefererbrowser'}; + if ($withpurge) { %_unknownrefererbrowser_l=(); } + } + if (! scalar %SectionsToLoad) { debug(" Stop reading history file. Got all we need."); last; } + next; + } + # BEGIN_SCREENSIZE + if ($field[0] eq 'BEGIN_SCREENSIZE') { + if ($Debug) { debug(" Begin of SCREENSIZE section"); } + $field[0]=''; + my $count=0;my $countloaded=0; + do { + if ($field[0]) { + $count++; + if ($SectionsToLoad{'screensize'}) { + $countloaded++; + if ($field[1]) { $_screensize_h{$field[0]}+=$field[1]; } + } + } + $_=; + chomp $_; s/\r//; + @field=split(/\s+/,($readxml?CleanFromTags($_):$_)); $countlines++; + } + until ($field[0] eq 'END_SCREENSIZE' || $field[0] eq "${xmleb}END_SCREENSIZE" || ! $_); + if ($field[0] ne 'END_SCREENSIZE' && $field[0] ne "${xmleb}END_SCREENSIZE") { error("History file \"$filetoread\" is corrupted (End of section SCREENSIZE not found).\nRestore a recent backup of this file (data for this month will be restored to backup date), remove it (data for month will be lost), or remove the corrupted section in file (data for at least this section will be lost).","","",1); } + if ($Debug) { debug(" End of SCREENSIZE section ($count entries, $countloaded loaded)"); } + delete $SectionsToLoad{'screensize'}; + if ($SectionsToSave{'screensize'}) { + Save_History('screensize',$year,$month,$date); delete $SectionsToSave{'screensize'}; + if ($withpurge) { %_screensize_h=(); } + } + if (! scalar %SectionsToLoad) { debug(" Stop reading history file. Got all we need."); last; } + next; + } + # BEGIN_ROBOT + if ($field[0] eq 'BEGIN_ROBOT') { + if ($Debug) { debug(" Begin of ROBOT section"); } + $field[0]=''; + my $count=0;my $countloaded=0; + do { + if ($field[0]) { + $count++; + if ($SectionsToLoad{'robot'}) { + $countloaded++; + if ($field[1]) { $_robot_h{$field[0]}+=$field[1]; } + $_robot_k{$field[0]}+=$field[2]; + if (! $_robot_l{$field[0]}) { $_robot_l{$field[0]}=int($field[3]); } + if ($field[4]) { $_robot_r{$field[0]}+=$field[4]; } + } + } + $_=; + chomp $_; s/\r//; + @field=split(/\s+/,($readxml?CleanFromTags($_):$_)); $countlines++; + } + until ($field[0] eq 'END_ROBOT' || $field[0] eq "${xmleb}END_ROBOT" || ! $_); + if ($field[0] ne 'END_ROBOT' && $field[0] ne "${xmleb}END_ROBOT") { error("History file \"$filetoread\" is corrupted (End of section ROBOT not found).\nRestore a recent backup of this file (data for this month will be restored to backup date), remove it (data for month will be lost), or remove the corrupted section in file (data for at least this section will be lost).","","",1); } + if ($Debug) { debug(" End of ROBOT section ($count entries, $countloaded loaded)"); } + delete $SectionsToLoad{'robot'}; + if ($SectionsToSave{'robot'}) { + Save_History('robot',$year,$month,$date); delete $SectionsToSave{'robot'}; + if ($withpurge) { %_robot_h=(); %_robot_k=(); %_robot_l=(); %_robot_r=(); } + } + if (! scalar %SectionsToLoad) { debug(" Stop reading history file. Got all we need."); last; } + next; + } + # BEGIN_WORMS + if ($field[0] eq 'BEGIN_WORMS') { + if ($Debug) { debug(" Begin of WORMS section"); } + $field[0]=''; + my $count=0;my $countloaded=0; + do { + if ($field[0]) { + $count++; + if ($SectionsToLoad{'worms'}) { + $countloaded++; + if ($field[1]) { $_worm_h{$field[0]}+=$field[1]; } + $_worm_k{$field[0]}+=$field[2]; + if (! $_worm_l{$field[0]}) { $_worm_l{$field[0]}=int($field[3]); } + } + } + $_=; + chomp $_; s/\r//; + @field=split(/\s+/,($readxml?CleanFromTags($_):$_)); $countlines++; + } + until ($field[0] eq 'END_WORMS' || $field[0] eq "${xmleb}END_WORMS" || ! $_); + if ($field[0] ne 'END_WORMS' && $field[0] ne "${xmleb}END_WORMS") { error("History file \"$filetoread\" is corrupted (End of section WORMS not found).\nRestore a recent backup of this file (data for this month will be restored to backup date), remove it (data for month will be lost), or remove the corrupted section in file (data for at least this section will be lost).","","",1); } + if ($Debug) { debug(" End of WORMS section ($count entries, $countloaded loaded)"); } + delete $SectionsToLoad{'worms'}; + if ($SectionsToSave{'worms'}) { + Save_History('worms',$year,$month,$date); delete $SectionsToSave{'worms'}; + if ($withpurge) { %_worm_h=(); %_worm_k=(); %_worm_l=(); } + } + if (! scalar %SectionsToLoad) { debug(" Stop reading history file. Got all we need."); last; } + next; + } + # BEGIN_EMAILS + if ($field[0] eq 'BEGIN_EMAILSENDER') { + if ($Debug) { debug(" Begin of EMAILSENDER section"); } + $field[0]=''; + my $count=0;my $countloaded=0; + do { + if ($field[0]) { + $count++; + if ($SectionsToLoad{'emailsender'}) { + $countloaded++; + if ($field[1]) { $_emails_h{$field[0]}+=$field[1]; } + if ($field[2]) { $_emails_k{$field[0]}+=$field[2]; } + if (! $_emails_l{$field[0]}) { $_emails_l{$field[0]}=int($field[3]); } + } + } + $_=; + chomp $_; s/\r//; + @field=split(/\s+/,($readxml?CleanFromTags($_):$_)); $countlines++; + } + until ($field[0] eq 'END_EMAILSENDER' || $field[0] eq "${xmleb}END_EMAILSENDER" || ! $_); + if ($field[0] ne 'END_EMAILSENDER' && $field[0] ne "${xmleb}END_EMAILSENDER") { error("History file \"$filetoread\" is corrupted (End of section EMAILSENDER not found).\nRestore a recent backup of this file (data for this month will be restored to backup date), remove it (data for month will be lost), or remove the corrupted section in file (data for at least this section will be lost).","","",1); } + if ($Debug) { debug(" End of EMAILSENDER section ($count entries, $countloaded loaded)"); } + delete $SectionsToLoad{'emailsender'}; + if ($SectionsToSave{'emailsender'}) { + Save_History('emailsender',$year,$month,$date); delete $SectionsToSave{'emailsender'}; + if ($withpurge) { %_emails_h=(); %_emails_k=(); %_emails_l=(); } + } + if (! scalar %SectionsToLoad) { debug(" Stop reading history file. Got all we need."); last; } + next; + } + # BEGIN_EMAILR + if ($field[0] eq 'BEGIN_EMAILRECEIVER') { + if ($Debug) { debug(" Begin of EMAILRECEIVER section"); } + $field[0]=''; + my $count=0;my $countloaded=0; + do { + if ($field[0]) { + $count++; + if ($SectionsToLoad{'emailreceiver'}) { + $countloaded++; + if ($field[1]) { $_emailr_h{$field[0]}+=$field[1]; } + if ($field[2]) { $_emailr_k{$field[0]}+=$field[2]; } + if (! $_emailr_l{$field[0]}) { $_emailr_l{$field[0]}=int($field[3]); } + } + } + $_=; + chomp $_; s/\r//; + @field=split(/\s+/,($readxml?CleanFromTags($_):$_)); $countlines++; + } + until ($field[0] eq 'END_EMAILRECEIVER' || $field[0] eq "${xmleb}END_EMAILRECEIVER" || ! $_); + if ($field[0] ne 'END_EMAILRECEIVER' && $field[0] ne "${xmleb}END_EMAILRECEIVER") { error("History file \"$filetoread\" is corrupted (End of section EMAILRECEIVER not found).\nRestore a recent backup of this file (data for this month will be restored to backup date), remove it (data for month will be lost), or remove the corrupted section in file (data for at least this section will be lost).","","",1); } + if ($Debug) { debug(" End of EMAILRECEIVER section ($count entries, $countloaded loaded)"); } + delete $SectionsToLoad{'emailreceiver'}; + if ($SectionsToSave{'emailreceiver'}) { + Save_History('emailreceiver',$year,$month,$date); delete $SectionsToSave{'emailreceiver'}; + if ($withpurge) { %_emailr_h=(); %_emailr_k=(); %_emailr_l=(); } + } + if (! scalar %SectionsToLoad) { debug(" Stop reading history file. Got all we need."); last; } + next; + } + # BEGIN_SIDER + if ($field[0] eq 'BEGIN_SIDER') { + if ($Debug) { debug(" Begin of SIDER section"); } + $field[0]=''; + my $count=0;my $countloaded=0; + do { + if ($field[0]) { + $count++; + if ($SectionsToLoad{'sider'}) { + my $loadrecord=0; + if ($withupdate) { + $loadrecord=1; + } + else { + if ($HTMLOutput{'main'}) { + if ($MonthRequired eq 'all') { $loadrecord=1; } + else { + if ($countloaded < $MaxNbOf{'PageShown'} && $field[1] >= $MinHit{'File'}) { $loadrecord=1; } + $TotalDifferentPages++; + } + } + else { # This is for $HTMLOutput = urldetail, urlentry or urlexit + if ($MonthRequired eq 'all' ) { + if ((!$FilterIn{'url'} || $field[0] =~ /$FilterIn{'url'}/) + && (!$FilterEx{'url'} || $field[0] !~ /$FilterEx{'url'}/)) { $loadrecord=1; } + } + else { + if ((!$FilterIn{'url'} || $field[0] =~ /$FilterIn{'url'}/) + && (!$FilterEx{'url'} || $field[0] !~ /$FilterEx{'url'}/) + && $field[1] >= $MinHit{'File'}) { $loadrecord=1; } + $TotalDifferentPages++; + } + } + # Posssibilite de mettre if ($FilterIn{'url'} && $field[0] =~ /$FilterIn{'url'}/) mais il faut gerer TotalPages de la meme maniere + $TotalBytesPages+=($field[2]||0); + $TotalEntries+=($field[3]||0); + $TotalExits+=($field[4]||0); + } + if ($loadrecord) { + if ($field[1]) { $_url_p{$field[0]}+=$field[1]; } + if ($field[2]) { $_url_k{$field[0]}+=$field[2]; } + if ($field[3]) { $_url_e{$field[0]}+=$field[3]; } + if ($field[4]) { $_url_x{$field[0]}+=$field[4]; } + $countloaded++; + } + } + } + $_=; + chomp $_; s/\r//; + @field=split(/\s+/,($readxml?CleanFromTags($_):$_)); $countlines++; + } + until ($field[0] eq 'END_SIDER' || $field[0] eq "${xmleb}END_SIDER" || ! $_); + if ($field[0] ne 'END_SIDER' && $field[0] ne "${xmleb}END_SIDER") { error("History file \"$filetoread\" is corrupted (End of section SIDER not found).\nRestore a recent backup of this file (data for this month will be restored to backup date), remove it (data for month will be lost), or remove the corrupted section in file (data for at least this section will be lost).","","",1); } + if ($Debug) { debug(" End of SIDER section ($count entries, $countloaded loaded)"); } + delete $SectionsToLoad{'sider'}; + # WE DO NOT SAVE SECTION NOW BECAUSE VALUES CAN BE CHANGED AFTER READING VISITOR + #if ($SectionsToSave{'sider'}) { + # Save_History('sider',$year,$month,$date); delete $SectionsToSave{'sider'}; + # if ($withpurge) { %_url_p=(); %_url_k=(); %_url_e=(); %_url_x=(); } + #} + if (! scalar %SectionsToLoad) { debug(" Stop reading history file. Got all we need."); last; } + next; + } + # BEGIN_FILETYPES + if ($field[0] eq 'BEGIN_FILETYPES') { + if ($Debug) { debug(" Begin of FILETYPES section"); } + $field[0]=''; + my $count=0;my $countloaded=0; + do { + if ($field[0]) { + $count++; + if ($SectionsToLoad{'filetypes'}) { + $countloaded++; + if ($field[1]) { $_filetypes_h{$field[0]}+=$field[1]; } + if ($field[2]) { $_filetypes_k{$field[0]}+=$field[2]; } + if ($field[3]) { $_filetypes_gz_in{$field[0]}+=$field[3]; } + if ($field[4]) { $_filetypes_gz_out{$field[0]}+=$field[4]; } + } + } + $_=; + chomp $_; s/\r//; + @field=split(/\s+/,($readxml?CleanFromTags($_):$_)); $countlines++; + } + until ($field[0] eq 'END_FILETYPES' || $field[0] eq "${xmleb}END_FILETYPES" || ! $_); + if ($field[0] ne 'END_FILETYPES' && $field[0] ne "${xmleb}END_FILETYPES") { error("History file \"$filetoread\" is corrupted (End of section FILETYPES not found).\nRestore a recent backup of this file (data for this month will be restored to backup date), remove it (data for month will be lost), or remove the corrupted section in file (data for at least this section will be lost).","","",1); } + if ($Debug) { debug(" End of FILETYPES section ($count entries, $countloaded loaded)"); } + delete $SectionsToLoad{'filetypes'}; + if ($SectionsToSave{'filetypes'}) { + Save_History('filetypes',$year,$month,$date); delete $SectionsToSave{'filetypes'}; + if ($withpurge) { %_filetypes_h=(); %_filetypes_k=(); %_filetypes_gz_in=(); %_filetypes_gz_out=(); } + } + if (! scalar %SectionsToLoad) { debug(" Stop reading history file. Got all we need."); last; } + next; + } + # BEGIN_SEREFERRALS + if ($field[0] eq 'BEGIN_SEREFERRALS') { + if ($Debug) { debug(" Begin of SEREFERRALS section"); } + $field[0]=''; + my $count=0;my $countloaded=0; + do { + if ($field[0]) { + $count++; + if ($SectionsToLoad{'sereferrals'}) { + $countloaded++; + if ($versionnum < 5004) { # For history files < 5.4 + my $se=$field[0]; $se=~s/\./\\./g; + if ($SearchEnginesHashID{$se}) { + $_se_referrals_h{$SearchEnginesHashID{$se}}+=$field[1]||0; + } + else { + $_se_referrals_h{$field[0]}+=$field[1]||0; + } + } + elsif ($versionnum < 5091) { # For history files < 5.91 + my $se=$field[0]; $se=~s/\./\\./g; + if ($SearchEnginesHashID{$se}) { + $_se_referrals_p{$SearchEnginesHashID{$se}}+=$field[1]||0; + $_se_referrals_h{$SearchEnginesHashID{$se}}+=$field[2]||0; + } + else { + $_se_referrals_p{$field[0]}+=$field[1]||0; + $_se_referrals_h{$field[0]}+=$field[2]||0; + } + } else { + if ($field[1]) { $_se_referrals_p{$field[0]}+=$field[1]; } + if ($field[2]) { $_se_referrals_h{$field[0]}+=$field[2]; } + } + } + } + $_=; + chomp $_; s/\r//; + @field=split(/\s+/,($readxml?CleanFromTags($_):$_)); $countlines++; + } + until ($field[0] eq 'END_SEREFERRALS' || $field[0] eq "${xmleb}END_SEREFERRALS" || ! $_); + if ($field[0] ne 'END_SEREFERRALS' && $field[0] ne "${xmleb}END_SEREFERRALS") { error("History file \"$filetoread\" is corrupted (End of section SEREFERRALS not found).\nRestore a recent backup of this file (data for this month will be restored to backup date), remove it (data for month will be lost), or remove the corrupted section in file (data for at least this section will be lost).","","",1); } + if ($Debug) { debug(" End of SEREFERRALS section ($count entries, $countloaded loaded)"); } + delete $SectionsToLoad{'sereferrals'}; + if ($SectionsToSave{'sereferrals'}) { + Save_History('sereferrals',$year,$month,$date); delete $SectionsToSave{'sereferrals'}; + if ($withpurge) { %_se_referrals_p=(); %_se_referrals_h=(); } + } + if (! scalar %SectionsToLoad) { debug(" Stop reading history file. Got all we need."); last; } + next; + } + # BEGIN_PAGEREFS + if ($field[0] eq 'BEGIN_PAGEREFS') { + if ($Debug) { debug(" Begin of PAGEREFS section"); } + $field[0]=''; + my $count=0;my $countloaded=0; + do { + if ($field[0]) { + $count++; + if ($SectionsToLoad{'pagerefs'}) { + my $loadrecord=0; + if ($withupdate) { + $loadrecord=1; + } + else { + if ((!$FilterIn{'refererpages'} || $field[0] =~ /$FilterIn{'refererpages'}/) + && (!$FilterEx{'refererpages'} || $field[0] !~ /$FilterEx{'refererpages'}/)) { $loadrecord=1; } + } + if ($loadrecord) { + if ($versionnum < 5004) { # For history files < 5.4 + if ($field[1]) { $_pagesrefs_h{$field[0]}+=int($field[1]); } + } else { + if ($field[1]) { $_pagesrefs_p{$field[0]}+=int($field[1]); } + if ($field[2]) { $_pagesrefs_h{$field[0]}+=int($field[2]); } + } + $countloaded++; + } + } + } + $_=; + chomp $_; s/\r//; + @field=split(/\s+/,($readxml?CleanFromTags($_):$_)); $countlines++; + } + until ($field[0] eq 'END_PAGEREFS' || $field[0] eq "${xmleb}END_PAGEREFS" || ! $_); + if ($field[0] ne 'END_PAGEREFS' && $field[0] ne "${xmleb}END_PAGEREFS") { error("History file \"$filetoread\" is corrupted (End of section PAGEREFS not found).\nRestore a recent backup of this file (data for this month will be restored to backup date), remove it (data for month will be lost), or remove the corrupted section in file (data for at least this section will be lost).","","",1); } + if ($Debug) { debug(" End of PAGEREFS section ($count entries, $countloaded loaded)"); } + delete $SectionsToLoad{'pagerefs'}; + if ($SectionsToSave{'pagerefs'}) { + Save_History('pagerefs',$year,$month,$date); delete $SectionsToSave{'pagerefs'}; + if ($withpurge) { %_pagesrefs_p=(); %_pagesrefs_h=(); } + } + if (! scalar %SectionsToLoad) { debug(" Stop reading history file. Got all we need."); last; } + next; + } + # BEGIN_SEARCHWORDS + if ($field[0] eq 'BEGIN_SEARCHWORDS') { + if ($Debug) { debug(" Begin of SEARCHWORDS section ($MaxNbOf{'KeyphrasesShown'},$MinHit{'Keyphrase'})"); } + $field[0]=''; + my $count=0;my $countloaded=0; + do { + if ($field[0]) { + $count++; + if ($SectionsToLoad{'searchwords'}) { + my $loadrecord=0; + if ($withupdate) { + $loadrecord=1; + } + else { + if ($HTMLOutput{'main'}) { + if ($MonthRequired eq 'all') { $loadrecord=1; } + else { + if ($countloaded < $MaxNbOf{'KeyphrasesShown'} && $field[1] >= $MinHit{'Keyphrase'}) { $loadrecord=1; } + $TotalDifferentKeyphrases++; + $TotalKeyphrases+=($field[1]||0); + } + } + elsif ($HTMLOutput{'keyphrases'}) { # Load keyphrases for keyphrases chart + if ($MonthRequired eq 'all' ) { $loadrecord=1; } + else { + if ($field[1] >= $MinHit{'Keyphrase'}) { $loadrecord=1; } + $TotalDifferentKeyphrases++; + $TotalKeyphrases+=($field[1]||0); + } + } + if ($HTMLOutput{'keywords'}) { # Load keyphrases for keywords chart + $loadrecord=2; + } + } + if ($loadrecord) { + if ($field[1]) { + if ($loadrecord==2) { + foreach (split(/\+/,$field[0])) { # field[0] is "val1+val2+..." + $_keywords{$_}+=$field[1]; + } + } + else { + $_keyphrases{$field[0]}+=$field[1]; + } + } + $countloaded++; + } + } + } + $_=; + chomp $_; s/\r//; + @field=split(/\s+/,($readxml?CleanFromTags($_):$_)); $countlines++; + } + until ($field[0] eq 'END_SEARCHWORDS' || $field[0] eq "${xmleb}END_SEARCHWORDS" || ! $_); + if ($field[0] ne 'END_SEARCHWORDS' && $field[0] ne "${xmleb}END_SEARCHWORDS") { error("History file \"$filetoread\" is corrupted (End of section SEARCHWORDS not found).\nRestore a recent backup of this file (data for this month will be restored to backup date), remove it (data for month will be lost), or remove the corrupted section in file (data for at least this section will be lost).","","",1); } + if ($Debug) { debug(" End of SEARCHWORDS section ($count entries, $countloaded loaded)"); } + delete $SectionsToLoad{'searchwords'}; + if ($SectionsToSave{'searchwords'}) { + Save_History('searchwords',$year,$month,$date); delete $SectionsToSave{'searchwords'}; # This save searwords and keywords sections + if ($withpurge) { %_keyphrases=(); } + } + if (! scalar %SectionsToLoad) { debug(" Stop reading history file. Got all we need."); last; } + next; + } + # BEGIN_KEYWORDS + if ($field[0] eq 'BEGIN_KEYWORDS') { + if ($Debug) { debug(" Begin of KEYWORDS section ($MaxNbOf{'KeywordsShown'},$MinHit{'Keyword'})"); } + $field[0]=''; + my $count=0;my $countloaded=0; + do { + if ($field[0]) { + $count++; + if ($SectionsToLoad{'keywords'}) { + my $loadrecord=0; + if ($MonthRequired eq 'all') { $loadrecord=1; } + else { + if ($countloaded < $MaxNbOf{'KeywordsShown'} && $field[1] >= $MinHit{'Keyword'}) { $loadrecord=1; } + $TotalDifferentKeywords++; + $TotalKeywords+=($field[1]||0); + } + if ($loadrecord) { + if ($field[1]) { $_keywords{$field[0]}+=$field[1]; } + $countloaded++; + } + } + } + $_=; + chomp $_; s/\r//; + @field=split(/\s+/,($readxml?CleanFromTags($_):$_)); $countlines++; + } + until ($field[0] eq 'END_KEYWORDS' || $field[0] eq "${xmleb}END_KEYWORDS" || ! $_); + if ($field[0] ne 'END_KEYWORDS' && $field[0] ne "${xmleb}END_KEYWORDS") { error("History file \"$filetoread\" is corrupted (End of section KEYWORDS not found).\nRestore a recent backup of this file (data for this month will be restored to backup date), remove it (data for month will be lost), or remove the corrupted section in file (data for at least this section will be lost).","","",1); } + if ($Debug) { debug(" End of KEYWORDS section ($count entries, $countloaded loaded)"); } + delete $SectionsToLoad{'keywords'}; + if ($SectionsToSave{'keywords'}) { + Save_History('keywords',$year,$month,$date); delete $SectionsToSave{'keywords'}; + if ($withpurge) { %_keywords=(); } + } + if (! scalar %SectionsToLoad) { debug(" Stop reading history file. Got all we need."); last; } + next; + } + # BEGIN_ERRORS + if ($field[0] eq 'BEGIN_ERRORS') { + if ($Debug) { debug(" Begin of ERRORS section"); } + $field[0]=''; + my $count=0;my $countloaded=0; + do { + if ($field[0]) { + $count++; + if ($SectionsToLoad{'errors'}) { + $countloaded++; + if ($field[1]) { $_errors_h{$field[0]}+=$field[1]; } + if ($field[2]) { $_errors_k{$field[0]}+=$field[2]; } + } + } + $_=; + chomp $_; s/\r//; + @field=split(/\s+/,($readxml?CleanFromTags($_):$_)); $countlines++; + } + until ($field[0] eq 'END_ERRORS' || $field[0] eq "${xmleb}END_ERRORS" || ! $_); + if ($field[0] ne 'END_ERRORS' && $field[0] ne "${xmleb}END_ERRORS") { error("History file \"$filetoread\" is corrupted (End of section ERRORS not found).\nRestore a recent backup of this file (data for this month will be restored to backup date), remove it (data for month will be lost), or remove the corrupted section in file (data for at least this section will be lost).","","",1); } + if ($Debug) { debug(" End of ERRORS section ($count entries, $countloaded loaded)"); } + delete $SectionsToLoad{'errors'}; + if ($SectionsToSave{'errors'}) { + Save_History('errors',$year,$month,$date); delete $SectionsToSave{'errors'}; + if ($withpurge) { %_errors_h=(); %_errors_k=(); } + } + if (! scalar %SectionsToLoad) { debug(" Stop reading history file. Got all we need."); last; } + next; + } + # BEGIN_SIDER_xxx + foreach my $code (keys %TrapInfosForHTTPErrorCodes) { + if ($field[0] eq "BEGIN_SIDER_$code") { + if ($Debug) { debug(" Begin of SIDER_$code section"); } + $field[0]=''; + my $count=0;my $countloaded=0; + do { + if ($field[0]) { + $count++; + if ($SectionsToLoad{"sider_$code"}) { + $countloaded++; + if ($field[1]) { $_sider404_h{$field[0]}+=$field[1]; } + if ($withupdate || $HTMLOutput{"errors$code"}) { + if ($field[2]) { $_referer404_h{$field[0]}=$field[2]; } + } + } + } + $_=; + chomp $_; s/\r//; + @field=split(/\s+/,($readxml?CleanFromTags($_):$_)); $countlines++; + } + until ($field[0] eq "END_SIDER_$code" || $field[0] eq "${xmleb}END_SIDER_$code" || ! $_); + if ($field[0] ne "END_SIDER_$code" && $field[0] ne "${xmleb}END_SIDER_$code") { error("History file \"$filetoread\" is corrupted (End of section SIDER_$code not found).\nRestore a recent backup of this file (data for this month will be restored to backup date), remove it (data for month will be lost), or remove the corrupted section in file (data for at least this section will be lost).","","",1); } + if ($Debug) { debug(" End of SIDER_$code section ($count entries, $countloaded loaded)"); } + delete $SectionsToLoad{"sider_$code"}; + if ($SectionsToSave{"sider_$code"}) { + Save_History("sider_$code",$year,$month,$date); delete $SectionsToSave{"sider_$code"}; + if ($withpurge) { %_sider404_h=(); %_referer404_h=(); } + } + if (! scalar %SectionsToLoad) { debug(" Stop reading history file. Got all we need."); last; } + next; + } + } + # BEGIN_EXTRA_xxx + foreach my $extranum (1..@ExtraName-1) { + if ($field[0] eq "BEGIN_EXTRA_$extranum") { + if ($Debug) { debug(" Begin of EXTRA_$extranum"); } + $field[0]=''; + my $count=0;my $countloaded=0; + do { + if ($field[0] ne '') { + $count++; + if ($SectionsToLoad{"extra_$extranum"}) { + if ($ExtraStatTypes[$extranum] =~ /P/i && $field[1]) { ${'_section_' . $extranum . '_p'}{$field[0]}+=$field[1]; } + ${'_section_' . $extranum . '_h'}{$field[0]}+=$field[2]; + if ($ExtraStatTypes[$extranum] =~ /B/i && $field[3]) { ${'_section_' . $extranum . '_k'}{$field[0]}+=$field[3]; } + if ($ExtraStatTypes[$extranum] =~ /L/i && ! ${'_section_' . $extranum . '_l'}{$field[0]} && $field[4]) { ${'_section_' . $extranum . '_l'}{$field[0]}=int($field[4]); } + $countloaded++; + } + } + $_=; + chomp $_; s/\r//; + @field=split(/\s+/,($readxml?CleanFromTags($_):$_)); $countlines++; + } + until ($field[0] eq "END_EXTRA_$extranum" || $field[0] eq "${xmleb}END_EXTRA_$extranum" || ! $_); + if ($field[0] ne "END_EXTRA_$extranum" && $field[0] ne "${xmleb}END_EXTRA_$extranum") { error("History file \"$filetoread\" is corrupted (End of section EXTRA_$extranum not found).\nRestore a recent backup of this file (data for this month will be restored to backup date), remove it (data for month will be lost), or remove the corrupted section in file (data for at least this section will be lost).","","",1); } + if ($Debug) { debug(" End of EXTRA_$extranum section ($count entries, $countloaded loaded)"); } + delete $SectionsToLoad{"extra_$extranum"}; + if ($SectionsToSave{"extra_$extranum"}) { + Save_History("extra_$extranum",$year,$month,$date); delete $SectionsToSave{"extra_$extranum"}; + if ($withpurge) { %{'_section_' . $extranum . '_p'}=(); %{'_section_' . $extranum . '_h'}=(); %{'_section_' . $extranum . '_b'}=(); %{'_section_' . $extranum . '_l'}=(); } + } + if (! scalar %SectionsToLoad) { debug(" Stop reading history file. Got all we need."); last; } + next; + } + } + + # BEGIN_PLUGINS + if ($AtLeastOneSectionPlugin && $field[0] =~ /^BEGIN_PLUGIN_(\w+)$/i) { + my $pluginname=$1; + my $found=0; + foreach (keys %{$PluginsLoaded{'SectionInitHashArray'}}) { + if ($pluginname eq $_) { + # The plugin for this section was loaded + $found=1; + my $issectiontoload=$SectionsToLoad{"plugin_$pluginname"}; +# my $function="SectionReadHistory_$pluginname(\$issectiontoload,\$readxml,\$xmleb,\$countlines)"; +# eval("$function"); + my $function="SectionReadHistory_$pluginname"; + &$function($issectiontoload,$readxml,$xmleb,$countlines); + delete $SectionsToLoad{"plugin_$pluginname"}; + if ($SectionsToSave{"plugin_$pluginname"}) { + Save_History("plugin_$pluginname",$year,$month,$date); + delete $SectionsToSave{"plugin_$pluginname"}; + if ($withpurge) { +# my $function="SectionInitHashArray_$pluginname()"; +# eval("$function"); + my $function="SectionInitHashArray_$pluginname"; + &$function(); + } + } + last; + } + } + if (! scalar %SectionsToLoad) { debug(" Stop reading history file. Got all we need."); last; } + # The plugin for this section was not loaded + if (! $found) { + do { + $_=; + chomp $_; s/\r//; + @field=split(/\s+/,($readxml?CleanFromTags($_):$_)); $countlines++; + } + until ($field[0] eq "END_PLUGIN_$pluginname" || $field[0] eq "${xmleb}END_PLUGIN_$pluginname" || ! $_); + } + next; + } + + # For backward compatibility (ORIGIN section was "HitFromx" in old history files) + if ($SectionsToLoad{'origin'}) { + if ($field[0] eq 'HitFrom0') { $_from_p[0]+=0; $_from_h[0]+=$field[1]; next; } + if ($field[0] eq 'HitFrom1') { $_from_p[1]+=0; $_from_h[1]+=$field[1]; next; } + if ($field[0] eq 'HitFrom2') { $_from_p[2]+=0; $_from_h[2]+=$field[1]; next; } + if ($field[0] eq 'HitFrom3') { $_from_p[3]+=0; $_from_h[3]+=$field[1]; next; } + if ($field[0] eq 'HitFrom4') { $_from_p[4]+=0; $_from_h[4]+=$field[1]; next; } + if ($field[0] eq 'HitFrom5') { $_from_p[5]+=0; $_from_h[5]+=$field[1]; next; } + } + } + } + + if ($withupdate) { + # Process rest of data saved in 'wait' arrays (data for hosts that are not in history file or no history file found) + # This can change some values for day, sider and session sections + if ($Debug) { debug(" Processing data in 'wait' arrays",3); } + foreach (keys %_waithost_e) { + if ($Debug) { debug(" Visit in 'wait' array for $_ is a new visit",4); } + my $newtimehosts=($_waithost_s{$_}?$_waithost_s{$_}:$_host_s{$_}); + my $newtimehostl=($_waithost_l{$_}?$_waithost_l{$_}:$_host_l{$_}); + $_url_e{$_waithost_e{$_}}++; + $newtimehosts =~ /^(\d\d\d\d\d\d\d\d)/; $DayVisits{$1}++; + if ($_waithost_s{$_}) { + # There was also a second session in processed log + $_session{GetSessionRange($newtimehosts,$newtimehostl)}++; + } + } + } + + # Write all unwrote sections in section order ('general','time', 'day','sider','session' and other...) + if ($Debug) { debug(" Check and write all unwrote sections: ".join(',',keys %SectionsToSave),2); } + foreach my $key (sort { $SectionsToSave{$a} <=> $SectionsToSave{$b} } keys %SectionsToSave) { + Save_History("$key",$year,$month,$date,$lastlinenb,$lastlineoffset,$lastlinechecksum); + } + %SectionsToSave=(); + + # Update offset in map section and last data in general section then close files + if ($withupdate) { + if ($xml) { print HISTORYTMP "\n\n\n"; } + + # Update offset of sections in the MAP section + foreach (sort { $PosInFile{$a} <=> $PosInFile{$b} } keys %ValueInFile) { + if ($Debug) { debug(" Update offset of section $_=$ValueInFile{$_} in file at offset $PosInFile{$_}"); } + if ($PosInFile{"$_"}) { + seek(HISTORYTMP,$PosInFile{"$_"},0); print HISTORYTMP $ValueInFile{"$_"}; + } + } + # Save last data in general sections + if ($Debug) { debug(" Update MonthVisits=$MonthVisits{$year.$month} in file at offset $PosInFile{TotalVisits}"); } + seek(HISTORYTMP,$PosInFile{"TotalVisits"},0); print HISTORYTMP $MonthVisits{$year.$month}; + if ($Debug) { debug(" Update MonthUnique=$MonthUnique{$year.$month} in file at offset $PosInFile{TotalUnique}"); } + seek(HISTORYTMP,$PosInFile{"TotalUnique"},0); print HISTORYTMP $MonthUnique{$year.$month}; + if ($Debug) { debug(" Update MonthHostsKnown=$MonthHostsKnown{$year.$month} in file at offset $PosInFile{MonthHostsKnown}"); } + seek(HISTORYTMP,$PosInFile{"MonthHostsKnown"},0); print HISTORYTMP $MonthHostsKnown{$year.$month}; + if ($Debug) { debug(" Update MonthHostsUnknown=$MonthHostsUnknown{$year.$month} in file at offset $PosInFile{MonthHostsUnknown}"); } + seek(HISTORYTMP,$PosInFile{"MonthHostsUnknown"},0); print HISTORYTMP $MonthHostsUnknown{$year.$month}; + close(HISTORYTMP) || error("Failed to write temporary history file"); + } + if ($withread) { + close(HISTORY) || error("Command for pipe '$filetoread' failed"); + } + + # Purge data + if ($withpurge) { &Init_HashArray(); } + + # If update, rename tmp file bis into tmp file or set HistoryAlreadyFlushed + if ($withupdate) { + if ($HistoryAlreadyFlushed{"$year$month$day$hour"}) { + debug("Rename tmp history file bis '$filetoread' to '$filetowrite'"); + if (rename($filetowrite,$filetoread)==0) { + error("Failed to update tmp history file $filetoread"); + } + } + else { + $HistoryAlreadyFlushed{"$year$month$day$hour"}=1; + } + + if (! $ListOfYears{"$year"} || $ListOfYears{"$year"} lt "$month") { $ListOfYears{"$year"}="$month"; } + } + + # For backward compatibility, if LastLine does not exist, set to LastTime + $LastLine||=$LastTime{$date}; + + return ($withupdate?"$filetowrite":""); +} + +#------------------------------------------------------------------------------ +# Function: Save a part of history file +# Parameters: sectiontosave,year,month,breakdate[,lastlinenb,lastlineoffset,lastlinechecksum] +# Input: $VERSION HISTORYTMP $nowyear $nowmonth $nowday $nowhour $nowmin $nowsec $LastLineNumber $LastLineOffset $LastLineChecksum +# Output: None +# Return: None +#------------------------------------------------------------------------------ +sub Save_History { + my $sectiontosave=shift||''; + my $year=shift||''; + my $month=shift||''; + my $breakdate=shift||''; + + my $xml=($BuildHistoryFormat eq 'xml'?1:0); + my ($xmlbb,$xmlbs,$xmlbe,$xmlhb,$xmlhs,$xmlhe,$xmlrb,$xmlrs,$xmlre,$xmleb,$xmlee)=('','','','','','','','','','',''); + if ($xml) { ($xmlbb,$xmlbs,$xmlbe,$xmlhb,$xmlhs,$xmlhe,$xmlrb,$xmlrs,$xmlre,$xmleb,$xmlee)=("\n",'','','','','
','','
','','
',"\n" ); } + else { $xmlbs=' '; $xmlhs=' '; $xmlrs=' '; } + + my $lastlinenb=shift||0; + my $lastlineoffset=shift||0; + my $lastlinechecksum=shift||0; + if (! $lastlinenb) { # This happens for migrate + $lastlinenb=$LastLineNumber; + $lastlineoffset=$LastLineOffset; + $lastlinechecksum=$LastLineChecksum; + } + + if ($Debug) { debug(" Save_History [sectiontosave=$sectiontosave,year=$year,month=$month,lastlinenb=$lastlinenb,lastlineoffset=$lastlineoffset,lastlinechecksum=$lastlinechecksum]",1); } + my $spacebar=" "; + my %keysinkeylist=(); + + # Header + if ($sectiontosave eq 'header') { + if ($xml) { print HISTORYTMP "\n"; } + print HISTORYTMP "AWSTATS DATA FILE $VERSION\n"; + if ($xml) { print HISTORYTMP "\n"; } + print HISTORYTMP "# If you remove this file, all statistics for date $breakdate will be lost/reset.\n"; + if ($xml) { print HISTORYTMP "\n"; } + print HISTORYTMP "\n"; + if ($xml) { print HISTORYTMP "
\n"; } + print HISTORYTMP "# Position (offset in bytes) in this file of beginning of each section for\n"; + print HISTORYTMP "# direct I/O access. If you made changes somewhere in this file, you should\n"; + print HISTORYTMP "# also remove completely the MAP section (AWStats will rewrite it at next\n"; + print HISTORYTMP "# update).\n"; + print HISTORYTMP "${xmlbb}BEGIN_MAP${xmlbs}".(26+(scalar keys %TrapInfosForHTTPErrorCodes)+(scalar @ExtraName?scalar @ExtraName-1:0)+(scalar keys %{$PluginsLoaded{'SectionInitHashArray'}}))."${xmlbe}\n"; + print HISTORYTMP "${xmlrb}POS_GENERAL${xmlrs}";$PosInFile{"general"}=tell HISTORYTMP;print HISTORYTMP "$spacebar${xmlre}\n"; + # When + print HISTORYTMP "${xmlrb}POS_TIME${xmlrs}";$PosInFile{"time"}=tell HISTORYTMP;print HISTORYTMP "$spacebar${xmlre}\n"; + print HISTORYTMP "${xmlrb}POS_VISITOR${xmlrs}";$PosInFile{"visitor"}=tell HISTORYTMP;print HISTORYTMP "$spacebar${xmlre}\n"; + print HISTORYTMP "${xmlrb}POS_DAY${xmlrs}";$PosInFile{"day"}=tell HISTORYTMP;print HISTORYTMP "$spacebar${xmlre}\n"; + # Who + print HISTORYTMP "${xmlrb}POS_DOMAIN${xmlrs}";$PosInFile{"domain"}=tell HISTORYTMP;print HISTORYTMP "$spacebar${xmlre}\n"; + print HISTORYTMP "${xmlrb}POS_LOGIN${xmlrs}";$PosInFile{"login"}=tell HISTORYTMP;print HISTORYTMP "$spacebar${xmlre}\n"; + print HISTORYTMP "${xmlrb}POS_ROBOT${xmlrs}";$PosInFile{"robot"}=tell HISTORYTMP;print HISTORYTMP "$spacebar${xmlre}\n"; + print HISTORYTMP "${xmlrb}POS_WORMS${xmlrs}";$PosInFile{"worms"}=tell HISTORYTMP;print HISTORYTMP "$spacebar${xmlre}\n"; + print HISTORYTMP "${xmlrb}POS_EMAILSENDER${xmlrs}";$PosInFile{"emailsender"}=tell HISTORYTMP;print HISTORYTMP "$spacebar${xmlre}\n"; + print HISTORYTMP "${xmlrb}POS_EMAILRECEIVER${xmlrs}";$PosInFile{"emailreceiver"}=tell HISTORYTMP;print HISTORYTMP "$spacebar${xmlre}\n"; + # Navigation + print HISTORYTMP "${xmlrb}POS_SESSION${xmlrs}";$PosInFile{"session"}=tell HISTORYTMP;print HISTORYTMP "$spacebar${xmlre}\n"; + print HISTORYTMP "${xmlrb}POS_SIDER${xmlrs}";$PosInFile{"sider"}=tell HISTORYTMP;print HISTORYTMP "$spacebar${xmlre}\n"; + print HISTORYTMP "${xmlrb}POS_FILETYPES${xmlrs}";$PosInFile{"filetypes"}=tell HISTORYTMP;print HISTORYTMP "$spacebar${xmlre}\n"; + print HISTORYTMP "${xmlrb}POS_OS${xmlrs}";$PosInFile{"os"}=tell HISTORYTMP;print HISTORYTMP "$spacebar${xmlre}\n"; + print HISTORYTMP "${xmlrb}POS_BROWSER${xmlrs}";$PosInFile{"browser"}=tell HISTORYTMP;print HISTORYTMP "$spacebar${xmlre}\n"; + print HISTORYTMP "${xmlrb}POS_SCREENSIZE${xmlrs}";$PosInFile{"screensize"}=tell HISTORYTMP;print HISTORYTMP "$spacebar${xmlre}\n"; + print HISTORYTMP "${xmlrb}POS_UNKNOWNREFERER${xmlrs}";$PosInFile{'unknownreferer'}=tell HISTORYTMP;print HISTORYTMP "$spacebar${xmlre}\n"; + print HISTORYTMP "${xmlrb}POS_UNKNOWNREFERERBROWSER${xmlrs}";$PosInFile{'unknownrefererbrowser'}=tell HISTORYTMP;print HISTORYTMP "$spacebar${xmlre}\n"; + # Referers + print HISTORYTMP "${xmlrb}POS_ORIGIN${xmlrs}";$PosInFile{"origin"}=tell HISTORYTMP;print HISTORYTMP "$spacebar${xmlre}\n"; + print HISTORYTMP "${xmlrb}POS_SEREFERRALS${xmlrs}";$PosInFile{"sereferrals"}=tell HISTORYTMP;print HISTORYTMP "$spacebar${xmlre}\n"; + print HISTORYTMP "${xmlrb}POS_PAGEREFS${xmlrs}";$PosInFile{"pagerefs"}=tell HISTORYTMP;print HISTORYTMP "$spacebar${xmlre}\n"; + print HISTORYTMP "${xmlrb}POS_SEARCHWORDS${xmlrs}";$PosInFile{"searchwords"}=tell HISTORYTMP;print HISTORYTMP "$spacebar${xmlre}\n"; + print HISTORYTMP "${xmlrb}POS_KEYWORDS${xmlrs}";$PosInFile{"keywords"}=tell HISTORYTMP;print HISTORYTMP "$spacebar${xmlre}\n"; + # Others + print HISTORYTMP "${xmlrb}POS_MISC${xmlrs}";$PosInFile{"misc"}=tell HISTORYTMP;print HISTORYTMP "$spacebar${xmlre}\n"; + print HISTORYTMP "${xmlrb}POS_ERRORS${xmlrs}";$PosInFile{"errors"}=tell HISTORYTMP;print HISTORYTMP "$spacebar${xmlre}\n"; + print HISTORYTMP "${xmlrb}POS_CLUSTER${xmlrs}";$PosInFile{"cluster"}=tell HISTORYTMP;print HISTORYTMP "$spacebar${xmlre}\n"; + foreach (keys %TrapInfosForHTTPErrorCodes) { + print HISTORYTMP "${xmlrb}POS_SIDER_$_${xmlrs}";$PosInFile{"sider_$_"}=tell HISTORYTMP;print HISTORYTMP "$spacebar${xmlre}\n"; + } + foreach (1..@ExtraName-1) { + print HISTORYTMP "${xmlrb}POS_EXTRA_$_${xmlrs}";$PosInFile{"extra_$_"}=tell HISTORYTMP;print HISTORYTMP "$spacebar${xmlre}\n"; + } + foreach (keys %{$PluginsLoaded{'SectionInitHashArray'}}) { + print HISTORYTMP "${xmlrb}POS_PLUGIN_$_${xmlrs}";$PosInFile{"plugin_$_"}=tell HISTORYTMP;print HISTORYTMP "$spacebar${xmlre}\n"; + } + print HISTORYTMP "${xmleb}END_MAP${xmlee}\n"; + } + + # General + if ($sectiontosave eq 'general') { + if ($LastUpdate < int("$nowyear$nowmonth$nowday$nowhour$nowmin$nowsec")) { $LastUpdate=int("$nowyear$nowmonth$nowday$nowhour$nowmin$nowsec"); } + print HISTORYTMP "\n"; + if ($xml) { print HISTORYTMP "
\n"; } + print HISTORYTMP "# LastLine = Date of last record processed - Last record line number in last log - Last record offset in last log - Last record signature value\n"; + print HISTORYTMP "# FirstTime = Date of first visit for history file\n"; + print HISTORYTMP "# LastTime = Date of last visit for history file\n"; + print HISTORYTMP "# LastUpdate = Date of last update - Nb of parsed records - Nb of parsed old records - Nb of parsed new records - Nb of parsed corrupted - Nb of parsed dropped\n"; + print HISTORYTMP "# TotalVisits = Number of visits\n"; + print HISTORYTMP "# TotalUnique = Number of unique visitors\n"; + print HISTORYTMP "# MonthHostsKnown = Number of hosts known\n"; + print HISTORYTMP "# MonthHostsUnKnown = Number of hosts unknown\n"; + $ValueInFile{$sectiontosave}=tell HISTORYTMP; + print HISTORYTMP "${xmlbb}BEGIN_GENERAL${xmlbs}8${xmlbe}\n"; + print HISTORYTMP "${xmlrb}LastLine${xmlrs}".($LastLine>0?$LastLine:$LastTime{$breakdate})." $lastlinenb $lastlineoffset $lastlinechecksum${xmlre}\n"; + print HISTORYTMP "${xmlrb}FirstTime${xmlrs}".$FirstTime{$breakdate}."${xmlre}\n"; + print HISTORYTMP "${xmlrb}LastTime${xmlrs}".$LastTime{$breakdate}."${xmlre}\n"; + print HISTORYTMP "${xmlrb}LastUpdate${xmlrs}$LastUpdate $NbOfLinesParsed $NbOfOldLines $NbOfNewLines $NbOfLinesCorrupted $NbOfLinesDropped${xmlre}\n"; + print HISTORYTMP "${xmlrb}TotalVisits${xmlrs}";$PosInFile{"TotalVisits"}=tell HISTORYTMP;print HISTORYTMP "$spacebar${xmlre}\n"; + print HISTORYTMP "${xmlrb}TotalUnique${xmlrs}";$PosInFile{"TotalUnique"}=tell HISTORYTMP;print HISTORYTMP "$spacebar${xmlre}\n"; + print HISTORYTMP "${xmlrb}MonthHostsKnown${xmlrs}";$PosInFile{"MonthHostsKnown"}=tell HISTORYTMP;print HISTORYTMP "$spacebar${xmlre}\n"; + print HISTORYTMP "${xmlrb}MonthHostsUnknown${xmlrs}";$PosInFile{"MonthHostsUnknown"}=tell HISTORYTMP;print HISTORYTMP "$spacebar${xmlre}\n"; + print HISTORYTMP "${xmleb}".(${xmleb}?"\n":"")."END_GENERAL${xmlee}\n"; # END_GENERAL on a new line following xml tag because END_ detection does not work like other sections + } + + # When + if ($sectiontosave eq 'time') { + print HISTORYTMP "\n"; + if ($xml) { print HISTORYTMP "
\n"; } + print HISTORYTMP "# Hour - Pages - Hits - Bandwidth - Not viewed Pages - Not viewed Hits - Not viewed Bandwidth\n"; + $ValueInFile{$sectiontosave}=tell HISTORYTMP; + print HISTORYTMP "${xmlbb}BEGIN_TIME${xmlbs}24${xmlbe}\n"; + for (my $ix=0; $ix<=23; $ix++) { print HISTORYTMP "${xmlrb}$ix${xmlrs}".int($_time_p[$ix])."${xmlrs}".int($_time_h[$ix])."${xmlrs}".int($_time_k[$ix])."${xmlrs}".int($_time_nv_p[$ix])."${xmlrs}".int($_time_nv_h[$ix])."${xmlrs}".int($_time_nv_k[$ix])."${xmlre}\n"; } + print HISTORYTMP "${xmleb}END_TIME${xmlee}\n"; + } + if ($sectiontosave eq 'day') { # This section must be saved after VISITOR section is read + print HISTORYTMP "\n"; + if ($xml) { print HISTORYTMP "
\n"; } + print HISTORYTMP "# Date - Pages - Hits - Bandwidth - Visits\n"; + $ValueInFile{$sectiontosave}=tell HISTORYTMP; + print HISTORYTMP "${xmlbb}BEGIN_DAY${xmlbs}".(scalar keys %DayHits)."${xmlbe}\n"; + my $monthvisits=0; + foreach (sort keys %DayHits) { + if ($_ =~ /^$year$month/i) { # Found a day entry of the good month + my $page=$DayPages{$_}||0; + my $hits=$DayHits{$_}||0; + my $bytes=$DayBytes{$_}||0; + my $visits=$DayVisits{$_}||0; + print HISTORYTMP "${xmlrb}$_${xmlrs}$page${xmlrs}$hits${xmlrs}$bytes${xmlrs}$visits${xmlre}\n"; + $monthvisits+=$visits; + } + } + $MonthVisits{$year.$month}=$monthvisits; + print HISTORYTMP "${xmleb}END_DAY${xmlee}\n"; + } + + # Who + if ($sectiontosave eq 'domain') { + print HISTORYTMP "\n"; + if ($xml) { print HISTORYTMP "
$MaxNbOf{'Domain'}\n"; } + print HISTORYTMP "# Domain - Pages - Hits - Bandwidth\n"; + print HISTORYTMP "# The $MaxNbOf{'Domain'} first Pages must be first (order not required for others)\n"; + $ValueInFile{$sectiontosave}=tell HISTORYTMP; + print HISTORYTMP "${xmlbb}BEGIN_DOMAIN${xmlbs}".(scalar keys %_domener_h)."${xmlbe}\n"; + # We save page list in score sorted order to get a -output faster and with less use of memory. + &BuildKeyList($MaxNbOf{'Domain'},$MinHit{'Domain'},\%_domener_h,\%_domener_p); + my %keysinkeylist=(); + foreach (@keylist) { + $keysinkeylist{$_}=1; + my $page=$_domener_p{$_}||0; + my $bytes=$_domener_k{$_}||0; # ||0 could be commented to reduce history file size + print HISTORYTMP "${xmlrb}$_${xmlrs}$page${xmlrs}$_domener_h{$_}${xmlrs}$bytes${xmlre}\n"; + } + foreach (keys %_domener_h) { + if ($keysinkeylist{$_}) { next; } + my $page=$_domener_p{$_}||0; + my $bytes=$_domener_k{$_}||0; # ||0 could be commented to reduce history file size + print HISTORYTMP "${xmlrb}$_${xmlrs}$page${xmlrs}$_domener_h{$_}${xmlrs}$bytes${xmlre}\n"; + } + print HISTORYTMP "${xmleb}END_DOMAIN${xmlee}\n"; + } + if ($sectiontosave eq 'visitor') { + print HISTORYTMP "\n"; + if ($xml) { print HISTORYTMP "
$MaxNbOf{'HostsShown'}\n"; } + print HISTORYTMP "# Host - Pages - Hits - Bandwidth - Last visit date - [Start date of last visit] - [Last page of last visit]\n"; + print HISTORYTMP "# [Start date of last visit] and [Last page of last visit] are saved only if session is not finished\n"; + print HISTORYTMP "# The $MaxNbOf{'HostsShown'} first Hits must be first (order not required for others)\n"; + $ValueInFile{$sectiontosave}=tell HISTORYTMP; + print HISTORYTMP "${xmlbb}BEGIN_VISITOR${xmlbs}".(scalar keys %_host_h)."${xmlbe}\n"; + my $monthhostsknown=0; + # We save page list in score sorted order to get a -output faster and with less use of memory. + &BuildKeyList($MaxNbOf{'HostsShown'},$MinHit{'Host'},\%_host_h,\%_host_p); + my %keysinkeylist=(); + foreach my $key (@keylist) { + if ($key !~ /^\d+\.\d+\.\d+\.\d+$/ && $key !~ /^[0-9A-F]*:/i) { $monthhostsknown++; } + $keysinkeylist{$key}=1; + my $page=$_host_p{$key}||0; + my $bytes=$_host_k{$key}||0; + my $timehostl=$_host_l{$key}||0; + my $timehosts=$_host_s{$key}||0; + my $lastpage=$_host_u{$key}||''; + if ($timehostl && $timehosts && $lastpage) { + if (($timehostl+$VISITTIMEOUT) < $LastLine) { + # Session for this user is expired + if ($timehosts) { $_session{GetSessionRange($timehosts,$timehostl)}++; } + if ($lastpage) { $_url_x{$lastpage}++; } + delete $_host_s{$key}; + delete $_host_u{$key}; + print HISTORYTMP "${xmlrb}$key${xmlrs}$page${xmlrs}$_host_h{$key}${xmlrs}$bytes${xmlrs}$timehostl${xmlre}\n"; + } + else { + # If this user has started a new session that is not expired + print HISTORYTMP "${xmlrb}$key${xmlrs}$page${xmlrs}$_host_h{$key}${xmlrs}$bytes${xmlrs}$timehostl${xmlrs}$timehosts${xmlrs}$lastpage${xmlre}\n"; + } + } + else { + my $hostl=$timehostl||''; + print HISTORYTMP "${xmlrb}$key${xmlrs}$page${xmlrs}$_host_h{$key}${xmlrs}$bytes${xmlrs}$hostl${xmlre}\n"; + } + } + foreach my $key (keys %_host_h) { + if ($keysinkeylist{$key}) { next; } + if ($key !~ /^\d+\.\d+\.\d+\.\d+$/ && $key !~ /^[0-9A-F]*:/i) { $monthhostsknown++; } + my $page=$_host_p{$key}||0; + my $bytes=$_host_k{$key}||0; + my $timehostl=$_host_l{$key}||0; + my $timehosts=$_host_s{$key}||0; + my $lastpage=$_host_u{$key}||''; + if ($timehostl && $timehosts && $lastpage) { + if (($timehostl+$VISITTIMEOUT) < $LastLine) { + # Session for this user is expired + if ($timehosts) { $_session{GetSessionRange($timehosts,$timehostl)}++; } + if ($lastpage) { $_url_x{$lastpage}++; } + delete $_host_s{$key}; + delete $_host_u{$key}; + print HISTORYTMP "${xmlrb}$key${xmlrs}$page${xmlrs}$_host_h{$key}${xmlrs}$bytes${xmlrs}$timehostl${xmlre}\n"; + } + else { + # If this user has started a new session that is not expired + print HISTORYTMP "${xmlrb}$key${xmlrs}$page${xmlrs}$_host_h{$key}${xmlrs}$bytes${xmlrs}$timehostl${xmlrs}$timehosts${xmlrs}$lastpage${xmlre}\n"; + } + } + else { + my $hostl=$timehostl||''; + print HISTORYTMP "${xmlrb}$key${xmlrs}$page${xmlrs}$_host_h{$key}${xmlrs}$bytes${xmlrs}$hostl${xmlre}\n"; + } + } + $MonthUnique{$year.$month}=(scalar keys %_host_p); + $MonthHostsKnown{$year.$month}=$monthhostsknown; + $MonthHostsUnknown{$year.$month}=(scalar keys %_host_h) - $monthhostsknown; + print HISTORYTMP "${xmleb}END_VISITOR${xmlee}\n"; + } + if ($sectiontosave eq 'login') { + print HISTORYTMP "\n"; + if ($xml) { print HISTORYTMP "
$MaxNbOf{'LoginShown'}\n"; } + print HISTORYTMP "# Login - Pages - Hits - Bandwidth - Last visit\n"; + print HISTORYTMP "# The $MaxNbOf{'LoginShown'} first Pages must be first (order not required for others)\n"; + $ValueInFile{$sectiontosave}=tell HISTORYTMP; + print HISTORYTMP "${xmlbb}BEGIN_LOGIN${xmlbs}".(scalar keys %_login_h)."${xmlbe}\n"; + # We save login list in score sorted order to get a -output faster and with less use of memory. + &BuildKeyList($MaxNbOf{'LoginShown'},$MinHit{'Login'},\%_login_h,\%_login_p); + my %keysinkeylist=(); + foreach (@keylist) { + $keysinkeylist{$_}=1; + print HISTORYTMP "${xmlrb}$_${xmlrs}".int($_login_p{$_}||0)."${xmlrs}".int($_login_h{$_}||0)."${xmlrs}".int($_login_k{$_}||0)."${xmlrs}".($_login_l{$_}||'')."${xmlre}\n"; + } + foreach (keys %_login_h) { + if ($keysinkeylist{$_}) { next; } + print HISTORYTMP "${xmlrb}$_${xmlrs}".int($_login_p{$_}||0)."${xmlrs}".int($_login_h{$_}||0)."${xmlrs}".int($_login_k{$_}||0)."${xmlrs}".($_login_l{$_}||'')."${xmlre}\n"; + } + print HISTORYTMP "${xmleb}END_LOGIN${xmlee}\n"; + } + if ($sectiontosave eq 'robot') { + print HISTORYTMP "\n"; + if ($xml) { print HISTORYTMP "
$MaxNbOf{'RobotShown'}\n"; } + print HISTORYTMP "# Robot ID - Hits - Bandwidth - Last visit - Hits on robots.txt\n"; + print HISTORYTMP "# The $MaxNbOf{'RobotShown'} first Hits must be first (order not required for others)\n"; + $ValueInFile{$sectiontosave}=tell HISTORYTMP; + print HISTORYTMP "${xmlbb}BEGIN_ROBOT${xmlbs}".(scalar keys %_robot_h)."${xmlbe}\n"; + # We save robot list in score sorted order to get a -output faster and with less use of memory. + &BuildKeyList($MaxNbOf{'RobotShown'},$MinHit{'Robot'},\%_robot_h,\%_robot_h); + my %keysinkeylist=(); + foreach (@keylist) { + $keysinkeylist{$_}=1; + print HISTORYTMP "${xmlrb}$_${xmlrs}".int($_robot_h{$_})."${xmlrs}".int($_robot_k{$_})."${xmlrs}$_robot_l{$_}${xmlrs}".int($_robot_r{$_}||0)."${xmlre}\n"; + } + foreach (keys %_robot_h) { + if ($keysinkeylist{$_}) { next; } + print HISTORYTMP "${xmlrb}$_${xmlrs}".int($_robot_h{$_})."${xmlrs}".int($_robot_k{$_})."${xmlrs}$_robot_l{$_}${xmlrs}".int($_robot_r{$_}||0)."${xmlre}\n"; + } + print HISTORYTMP "${xmleb}END_ROBOT${xmlee}\n"; + } + if ($sectiontosave eq 'worms') { + print HISTORYTMP "\n"; + if ($xml) { print HISTORYTMP "
$MaxNbOf{'WormsShown'}\n"; } + print HISTORYTMP "# Worm ID - Hits - Bandwidth - Last visit\n"; + print HISTORYTMP "# The $MaxNbOf{'WormsShown'} first Hits must be first (order not required for others)\n"; + $ValueInFile{$sectiontosave}=tell HISTORYTMP; + print HISTORYTMP "${xmlbb}BEGIN_WORMS${xmlbs}".(scalar keys %_worm_h)."${xmlbe}\n"; + # We save worm list in score sorted order to get a -output faster and with less use of memory. + &BuildKeyList($MaxNbOf{'WormsShown'},$MinHit{'Worm'},\%_worm_h,\%_worm_h); + my %keysinkeylist=(); + foreach (@keylist) { + $keysinkeylist{$_}=1; + print HISTORYTMP "${xmlrb}$_${xmlrs}".int($_worm_h{$_})."${xmlrs}".int($_worm_k{$_})."${xmlrs}$_worm_l{$_}${xmlre}\n"; + } + foreach (keys %_worm_h) { + if ($keysinkeylist{$_}) { next; } + print HISTORYTMP "${xmlrb}$_${xmlrs}".int($_worm_h{$_})."${xmlrs}".int($_worm_k{$_})."${xmlrs}$_worm_l{$_}${xmlre}\n"; + } + print HISTORYTMP "${xmleb}END_WORMS${xmlee}\n"; + } + if ($sectiontosave eq 'emailsender') { + print HISTORYTMP "\n"; + if ($xml) { print HISTORYTMP "
$MaxNbOf{'EMailsShown'}\n"; } + print HISTORYTMP "# EMail - Hits - Bandwidth - Last visit\n"; + print HISTORYTMP "# The $MaxNbOf{'EMailsShown'} first Hits must be first (order not required for others)\n"; + $ValueInFile{$sectiontosave}=tell HISTORYTMP; + print HISTORYTMP "${xmlbb}BEGIN_EMAILSENDER${xmlbs}".(scalar keys %_emails_h)."${xmlbe}\n"; + # We save sender email list in score sorted order to get a -output faster and with less use of memory. + &BuildKeyList($MaxNbOf{'EMailsShown'},$MinHit{'EMail'},\%_emails_h,\%_emails_h); + my %keysinkeylist=(); + foreach (@keylist) { + $keysinkeylist{$_}=1; + print HISTORYTMP "${xmlrb}$_${xmlrs}".int($_emails_h{$_}||0)."${xmlrs}".int($_emails_k{$_}||0)."${xmlrs}$_emails_l{$_}${xmlre}\n"; + } + foreach (keys %_emails_h) { + if ($keysinkeylist{$_}) { next; } + print HISTORYTMP "${xmlrb}$_${xmlrs}".int($_emails_h{$_}||0)."${xmlrs}".int($_emails_k{$_}||0)."${xmlrs}$_emails_l{$_}${xmlre}\n"; + } + print HISTORYTMP "${xmleb}END_EMAILSENDER${xmlee}\n"; + } + if ($sectiontosave eq 'emailreceiver') { + print HISTORYTMP "\n"; + if ($xml) { print HISTORYTMP "
$MaxNbOf{'EMailsShown'}\n"; } + print HISTORYTMP "# EMail - Hits - Bandwidth - Last visit\n"; + print HISTORYTMP "# The $MaxNbOf{'EMailsShown'} first hits must be first (order not required for others)\n"; + $ValueInFile{$sectiontosave}=tell HISTORYTMP; + print HISTORYTMP "${xmlbb}BEGIN_EMAILRECEIVER${xmlbs}".(scalar keys %_emailr_h)."${xmlbe}\n"; + # We save receiver email list in score sorted order to get a -output faster and with less use of memory. + &BuildKeyList($MaxNbOf{'EMailsShown'},$MinHit{'EMail'},\%_emailr_h,\%_emailr_h); + my %keysinkeylist=(); + foreach (@keylist) { + $keysinkeylist{$_}=1; + print HISTORYTMP "${xmlrb}$_${xmlrs}".int($_emailr_h{$_}||0)."${xmlrs}".int($_emailr_k{$_}||0)."${xmlrs}$_emailr_l{$_}${xmlre}\n"; + } + foreach (keys %_emailr_h) { + if ($keysinkeylist{$_}) { next; } + print HISTORYTMP "${xmlrb}$_${xmlrs}".int($_emailr_h{$_}||0)."${xmlrs}".int($_emailr_k{$_}||0)."${xmlrs}$_emailr_l{$_}${xmlre}\n"; + } + print HISTORYTMP "${xmleb}END_EMAILRECEIVER${xmlee}\n"; + } + + # Navigation + if ($sectiontosave eq 'session') { # This section must be saved after VISITOR section is read + print HISTORYTMP "\n"; + if ($xml) { print HISTORYTMP "
\n"; } + print HISTORYTMP "# Session range - Number of visits\n"; + $ValueInFile{$sectiontosave}=tell HISTORYTMP; + print HISTORYTMP "${xmlbb}BEGIN_SESSION${xmlbs}".(scalar keys %_session)."${xmlbe}\n"; + foreach (keys %_session) { print HISTORYTMP "${xmlrb}$_${xmlrs}".int($_session{$_})."${xmlre}\n"; } + print HISTORYTMP "${xmleb}END_SESSION${xmlee}\n"; + } + if ($sectiontosave eq 'sider') { # This section must be saved after VISITOR section is read + print HISTORYTMP "\n"; + if ($xml) { print HISTORYTMP "
$MaxNbOf{'PageShown'}\n"; } + print HISTORYTMP "# URL - Pages - Bandwidth - Entry - Exit\n"; + print HISTORYTMP "# The $MaxNbOf{'PageShown'} first Pages must be first (order not required for others)\n"; + $ValueInFile{$sectiontosave}=tell HISTORYTMP; + print HISTORYTMP "${xmlbb}BEGIN_SIDER${xmlbs}".(scalar keys %_url_p)."${xmlbe}\n"; + # We save page list in score sorted order to get a -output faster and with less use of memory. + &BuildKeyList($MaxNbOf{'PageShown'},$MinHit{'File'},\%_url_p,\%_url_p); + %keysinkeylist=(); + foreach (@keylist) { + $keysinkeylist{$_}=1; + my $newkey=$_; + $newkey =~ s/([^:])\/\//$1\//g; # Because some targeted url were taped with 2 / (Ex: //rep//file.htm). We must keep http://rep/file.htm + print HISTORYTMP "${xmlrb}$newkey${xmlrs}".int($_url_p{$_}||0)."${xmlrs}".int($_url_k{$_}||0)."${xmlrs}".int($_url_e{$_}||0)."${xmlrs}".int($_url_x{$_}||0)."${xmlre}\n"; + } + foreach (keys %_url_p) { + if ($keysinkeylist{$_}) { next; } + my $newkey=$_; + $newkey =~ s/([^:])\/\//$1\//g; # Because some targeted url were taped with 2 / (Ex: //rep//file.htm). We must keep http://rep/file.htm + print HISTORYTMP "${xmlrb}$newkey ".int($_url_p{$_}||0)."${xmlrs}".int($_url_k{$_}||0)."${xmlrs}".int($_url_e{$_}||0)."${xmlrs}".int($_url_x{$_}||0)."${xmlre}\n"; + } + print HISTORYTMP "${xmleb}END_SIDER${xmlee}\n"; + } + if ($sectiontosave eq 'filetypes') { + print HISTORYTMP "\n"; + if ($xml) { print HISTORYTMP "
\n"; } + print HISTORYTMP "# Files type - Hits - Bandwidth - Bandwidth without compression - Bandwidth after compression\n"; + $ValueInFile{$sectiontosave}=tell HISTORYTMP; + print HISTORYTMP "${xmlbb}BEGIN_FILETYPES${xmlbs}".(scalar keys %_filetypes_h)."${xmlbe}\n"; + foreach (keys %_filetypes_h) { + my $hits=$_filetypes_h{$_}||0; + my $bytes=$_filetypes_k{$_}||0; + my $bytesbefore=$_filetypes_gz_in{$_}||0; + my $bytesafter=$_filetypes_gz_out{$_}||0; + print HISTORYTMP "${xmlrb}$_${xmlrs}$hits${xmlrs}$bytes${xmlrs}$bytesbefore${xmlrs}$bytesafter${xmlre}\n"; + } + print HISTORYTMP "${xmleb}END_FILETYPES${xmlee}\n"; + } + if ($sectiontosave eq 'os') { + print HISTORYTMP "\n"; + if ($xml) { print HISTORYTMP "
\n"; } + print HISTORYTMP "# OS ID - Hits\n"; + $ValueInFile{$sectiontosave}=tell HISTORYTMP; + print HISTORYTMP "${xmlbb}BEGIN_OS${xmlbs}".(scalar keys %_os_h)."${xmlbe}\n"; + foreach (keys %_os_h) { print HISTORYTMP "${xmlrb}$_${xmlrs}$_os_h{$_}${xmlre}\n"; } + print HISTORYTMP "${xmleb}END_OS${xmlee}\n"; + } + if ($sectiontosave eq 'browser') { + print HISTORYTMP "\n"; + if ($xml) { print HISTORYTMP "
\n"; } + print HISTORYTMP "# Browser ID - Hits\n"; + $ValueInFile{$sectiontosave}=tell HISTORYTMP; + print HISTORYTMP "${xmlbb}BEGIN_BROWSER${xmlbs}".(scalar keys %_browser_h)."${xmlbe}\n"; + foreach (keys %_browser_h) { print HISTORYTMP "${xmlrb}$_${xmlrs}$_browser_h{$_}${xmlre}\n"; } + print HISTORYTMP "${xmleb}END_BROWSER${xmlee}\n"; + } + if ($sectiontosave eq 'screensize') { + print HISTORYTMP "\n"; + if ($xml) { print HISTORYTMP "
\n"; } + print HISTORYTMP "# Screen size - Hits\n"; + $ValueInFile{$sectiontosave}=tell HISTORYTMP; + print HISTORYTMP "${xmlbb}BEGIN_SCREENSIZE${xmlbs}".(scalar keys %_screensize_h)."${xmlbe}\n"; + foreach (keys %_screensize_h) { print HISTORYTMP "${xmlrb}$_${xmlrs}$_screensize_h{$_}${xmlre}\n"; } + print HISTORYTMP "${xmleb}END_SCREENSIZE${xmlee}\n"; + } + + # Referer + if ($sectiontosave eq 'unknownreferer') { + print HISTORYTMP "\n"; + if ($xml) { print HISTORYTMP "
\n"; } + print HISTORYTMP "# Unknown referer OS - Last visit date\n"; + $ValueInFile{$sectiontosave}=tell HISTORYTMP; + print HISTORYTMP "${xmlbb}BEGIN_UNKNOWNREFERER${xmlbs}".(scalar keys %_unknownreferer_l)."${xmlbe}\n"; + foreach (keys %_unknownreferer_l) { print HISTORYTMP "${xmlrb}".XMLEncodeForHisto($_)."${xmlrs}$_unknownreferer_l{$_}${xmlre}\n"; } + print HISTORYTMP "${xmleb}END_UNKNOWNREFERER${xmlee}\n"; + } + if ($sectiontosave eq 'unknownrefererbrowser') { + print HISTORYTMP "\n"; + if ($xml) { print HISTORYTMP "
\n"; } + print HISTORYTMP "# Unknown referer Browser - Last visit date\n"; + $ValueInFile{$sectiontosave}=tell HISTORYTMP; + print HISTORYTMP "${xmlbb}BEGIN_UNKNOWNREFERERBROWSER${xmlbs}".(scalar keys %_unknownrefererbrowser_l)."${xmlbe}\n"; + foreach (keys %_unknownrefererbrowser_l) { print HISTORYTMP "${xmlrb}".XMLEncodeForHisto($_)."${xmlrs}$_unknownrefererbrowser_l{$_}${xmlre}\n"; } + print HISTORYTMP "${xmleb}END_UNKNOWNREFERERBROWSER${xmlee}\n"; + } + if ($sectiontosave eq 'origin') { + print HISTORYTMP "\n"; + if ($xml) { print HISTORYTMP "
\n"; } + print HISTORYTMP "# Origin - Pages - Hits \n"; + $ValueInFile{$sectiontosave}=tell HISTORYTMP; + print HISTORYTMP "${xmlbb}BEGIN_ORIGIN${xmlbs}6"."${xmlbe}\n"; + print HISTORYTMP "${xmlrb}From0${xmlrs}".int($_from_p[0])."${xmlrs}".int($_from_h[0])."${xmlre}\n"; + print HISTORYTMP "${xmlrb}From1${xmlrs}".int($_from_p[1])."${xmlrs}".int($_from_h[1])."${xmlre}\n"; + print HISTORYTMP "${xmlrb}From2${xmlrs}".int($_from_p[2])."${xmlrs}".int($_from_h[2])."${xmlre}\n"; + print HISTORYTMP "${xmlrb}From3${xmlrs}".int($_from_p[3])."${xmlrs}".int($_from_h[3])."${xmlre}\n"; + print HISTORYTMP "${xmlrb}From4${xmlrs}".int($_from_p[4])."${xmlrs}".int($_from_h[4])."${xmlre}\n"; # Same site + print HISTORYTMP "${xmlrb}From5${xmlrs}".int($_from_p[5])."${xmlrs}".int($_from_h[5])."${xmlre}\n"; # News + print HISTORYTMP "${xmleb}END_ORIGIN${xmlee}\n"; + } + if ($sectiontosave eq 'sereferrals') { + print HISTORYTMP "\n"; + if ($xml) { print HISTORYTMP "
\n"; } + print HISTORYTMP "# Search engine referers ID - Pages - Hits\n"; + $ValueInFile{$sectiontosave}=tell HISTORYTMP; + print HISTORYTMP "${xmlbb}BEGIN_SEREFERRALS${xmlbs}".(scalar keys %_se_referrals_h)."${xmlbe}\n"; + foreach (keys %_se_referrals_h) { print HISTORYTMP "${xmlrb}$_${xmlrs}".int($_se_referrals_p{$_}||0)."${xmlrs}$_se_referrals_h{$_}${xmlre}\n"; } + print HISTORYTMP "${xmleb}END_SEREFERRALS${xmlee}\n"; + } + if ($sectiontosave eq 'pagerefs') { + print HISTORYTMP "\n"; + if ($xml) { print HISTORYTMP "
$MaxNbOf{'RefererShown'}\n"; } + print HISTORYTMP "# External page referers - Pages - Hits\n"; + print HISTORYTMP "# The $MaxNbOf{'RefererShown'} first Pages must be first (order not required for others)\n"; + $ValueInFile{$sectiontosave}=tell HISTORYTMP; + print HISTORYTMP "${xmlbb}BEGIN_PAGEREFS${xmlbs}".(scalar keys %_pagesrefs_h)."${xmlbe}\n"; + # We save page list in score sorted order to get a -output faster and with less use of memory. + &BuildKeyList($MaxNbOf{'RefererShown'},$MinHit{'Refer'},\%_pagesrefs_h,\%_pagesrefs_p); + %keysinkeylist=(); + foreach (@keylist) { + $keysinkeylist{$_}=1; + my $newkey=$_; + $newkey =~ s/^http(s|):\/\/([^\/]+)\/$/http$1:\/\/$2/i; # Remove / at end of http://.../ but not at end of http://.../dir/ + print HISTORYTMP "${xmlrb}".XMLEncodeForHisto($newkey)."${xmlrs}".int($_pagesrefs_p{$_}||0)."${xmlrs}$_pagesrefs_h{$_}${xmlre}\n"; + } + foreach (keys %_pagesrefs_h) { + if ($keysinkeylist{$_}) { next; } + my $newkey=$_; + $newkey =~ s/^http(s|):\/\/([^\/]+)\/$/http$1:\/\/$2/i; # Remove / at end of http://.../ but not at end of http://.../dir/ + print HISTORYTMP "${xmlrb}".XMLEncodeForHisto($newkey)."${xmlrs}".int($_pagesrefs_p{$_}||0)."${xmlrs}$_pagesrefs_h{$_}${xmlre}\n"; + } + print HISTORYTMP "${xmleb}END_PAGEREFS${xmlee}\n"; + } + if ($sectiontosave eq 'searchwords') { + # Save phrases section + print HISTORYTMP "\n"; + if ($xml) { print HISTORYTMP "
$MaxNbOf{'KeyphrasesShown'}\n"; } + print HISTORYTMP "# Search keyphrases - Number of search\n"; + print HISTORYTMP "# The $MaxNbOf{'KeyphrasesShown'} first number of search must be first (order not required for others)\n"; + $ValueInFile{$sectiontosave}=tell HISTORYTMP; + print HISTORYTMP "${xmlbb}BEGIN_SEARCHWORDS${xmlbs}".(scalar keys %_keyphrases)."${xmlbe}\n"; + # We will also build _keywords + %_keywords=(); + # We save key list in score sorted order to get a -output faster and with less use of memory. + &BuildKeyList($MaxNbOf{'KeywordsShown'},$MinHit{'Keyword'},\%_keyphrases,\%_keyphrases); + %keysinkeylist=(); + foreach my $key (@keylist) { + $keysinkeylist{$key}=1; + my $keyphrase=$key; + $keyphrase =~ tr/ /\+/s; + print HISTORYTMP "${xmlrb}".XMLEncodeForHisto($keyphrase)."${xmlrs}".$_keyphrases{$key}."${xmlre}\n"; + foreach (split(/\+/,$key)) { $_keywords{$_}+=$_keyphrases{$key}; } # To init %_keywords + } + foreach my $key (keys %_keyphrases) { + if ($keysinkeylist{$key}) { next; } + my $keyphrase=$key; + $keyphrase =~ tr/ /\+/s; + print HISTORYTMP "${xmlrb}".XMLEncodeForHisto($keyphrase)."${xmlrs}".$_keyphrases{$key}."${xmlre}\n"; + foreach (split(/\+/,$key)) { $_keywords{$_}+=$_keyphrases{$key}; } # To init %_keywords + } + print HISTORYTMP "${xmleb}END_SEARCHWORDS${xmlee}\n"; + + # Now save keywords section + print HISTORYTMP "\n"; + if ($xml) { print HISTORYTMP "
$MaxNbOf{'KeywordsShown'}\n"; } + print HISTORYTMP "# Search keywords - Number of search\n"; + print HISTORYTMP "# The $MaxNbOf{'KeywordsShown'} first number of search must be first (order not required for others)\n"; + $ValueInFile{"keywords"}=tell HISTORYTMP; + print HISTORYTMP "${xmlbb}BEGIN_KEYWORDS${xmlbs}".(scalar keys %_keywords)."${xmlbe}\n"; + # We save key list in score sorted order to get a -output faster and with less use of memory. + &BuildKeyList($MaxNbOf{'KeywordsShown'},$MinHit{'Keyword'},\%_keywords,\%_keywords); + %keysinkeylist=(); + foreach (@keylist) { + $keysinkeylist{$_}=1; + my $keyword=$_; + print HISTORYTMP "${xmlrb}".XMLEncodeForHisto($keyword)."${xmlrs}".$_keywords{$_}."${xmlre}\n"; + } + foreach (keys %_keywords) { + if ($keysinkeylist{$_}) { next; } + my $keyword=$_; + print HISTORYTMP "${xmlrb}".XMLEncodeForHisto($keyword)."${xmlrs}".$_keywords{$_}."${xmlre}\n"; + } + print HISTORYTMP "${xmleb}END_KEYWORDS${xmlee}\n"; + + } + + # Other - Errors + if ($sectiontosave eq 'cluster') { + print HISTORYTMP "\n"; + if ($xml) { print HISTORYTMP "
\n"; } + print HISTORYTMP "# Cluster ID - Pages - Hits - Bandwidth\n"; + $ValueInFile{$sectiontosave}=tell HISTORYTMP; + print HISTORYTMP "${xmlbb}BEGIN_CLUSTER${xmlbs}".(scalar keys %_cluster_h)."${xmlbe}\n"; + foreach (keys %_cluster_h) { print HISTORYTMP "${xmlrb}$_${xmlrs}".int($_cluster_p{$_}||0)."${xmlrs}".int($_cluster_h{$_}||0)."${xmlrs}".int($_cluster_k{$_}||0)."${xmlre}\n"; } + print HISTORYTMP "${xmleb}END_CLUSTER${xmlee}\n"; + } + if ($sectiontosave eq 'misc') { + print HISTORYTMP "\n"; + if ($xml) { print HISTORYTMP "
\n"; } + print HISTORYTMP "# Misc ID - Pages - Hits - Bandwidth\n"; + $ValueInFile{$sectiontosave}=tell HISTORYTMP; + print HISTORYTMP "${xmlbb}BEGIN_MISC${xmlbs}".(scalar keys %MiscListCalc)."${xmlbe}\n"; + foreach (keys %MiscListCalc) { print HISTORYTMP "${xmlrb}$_${xmlrs}".int($_misc_p{$_}||0)."${xmlrs}".int($_misc_h{$_}||0)."${xmlrs}".int($_misc_k{$_}||0)."${xmlre}\n"; } + print HISTORYTMP "${xmleb}END_MISC${xmlee}\n"; + } + if ($sectiontosave eq 'errors') { + print HISTORYTMP "\n"; + if ($xml) { print HISTORYTMP "
\n"; } + print HISTORYTMP "# Errors - Hits - Bandwidth\n"; + $ValueInFile{$sectiontosave}=tell HISTORYTMP; + print HISTORYTMP "${xmlbb}BEGIN_ERRORS${xmlbs}".(scalar keys %_errors_h)."${xmlbe}\n"; + foreach (keys %_errors_h) { print HISTORYTMP "${xmlrb}$_${xmlrs}$_errors_h{$_}${xmlrs}".int($_errors_k{$_}||0)."${xmlre}\n"; } + print HISTORYTMP "${xmleb}END_ERRORS${xmlee}\n"; + } + # Other - Trapped errors + foreach my $code (keys %TrapInfosForHTTPErrorCodes) { + if ($sectiontosave eq "sider_$code") { + print HISTORYTMP "\n"; + if ($xml) { print HISTORYTMP "
\n"; } + print HISTORYTMP "# URL with $code errors - Hits - Last URL referer\n"; + $ValueInFile{$sectiontosave}=tell HISTORYTMP; + print HISTORYTMP "${xmlbb}BEGIN_SIDER_$code${xmlbs}".(scalar keys %_sider404_h)."${xmlbe}\n"; + foreach (keys %_sider404_h) { + my $newkey=$_; + my $newreferer=$_referer404_h{$_}||''; + print HISTORYTMP "${xmlrb}".XMLEncodeForHisto($newkey)."${xmlrs}$_sider404_h{$_}${xmlrs}".XMLEncodeForHisto($newreferer)."${xmlre}\n"; + } + print HISTORYTMP "${xmleb}END_SIDER_$code${xmlee}\n"; + } + } + # Other - Extra stats sections + foreach my $extranum (1..@ExtraName-1) { + if ($sectiontosave eq "extra_$extranum") { + print HISTORYTMP "\n"; + if ($xml) { print HISTORYTMP "
$MaxNbOfExtra[$extranum]\n"; } + print HISTORYTMP "# Extra key - Pages - Hits - Bandwidth - Last access\n"; + print HISTORYTMP "# The $MaxNbOfExtra[$extranum] first number of hits are first\n"; + $ValueInFile{$sectiontosave}=tell HISTORYTMP; + print HISTORYTMP "${xmlbb}BEGIN_EXTRA_$extranum${xmlbs}".scalar (keys %{'_section_' . $extranum . '_h'})."${xmlbe}\n"; + &BuildKeyList($MaxNbOfExtra[$extranum],$MinHitExtra[$extranum],\%{'_section_' . $extranum . '_h'},\%{'_section_' . $extranum . '_p'}); + %keysinkeylist=(); + foreach (@keylist) { + $keysinkeylist{$_}=1; + my $page=${'_section_' . $extranum . '_p'}{$_}||0; + my $bytes=${'_section_' . $extranum . '_k'}{$_}||0; + my $lastaccess=${'_section_' . $extranum . '_l'}{$_}||''; + print HISTORYTMP "${xmlrb}".XMLEncodeForHisto($_)."${xmlrs}$page${xmlrs}", ${'_section_' . $extranum . '_h'}{$_}, "${xmlrs}$bytes${xmlrs}$lastaccess${xmlre}\n"; next; + } + foreach (keys %{'_section_' . $extranum . '_h'}) { + if ($keysinkeylist{$_}) { next; } + my $page=${'_section_' . $extranum . '_p'}{$_}||0; + my $bytes=${'_section_' . $extranum . '_k'}{$_}||0; + my $lastaccess=${'_section_' . $extranum . '_l'}{$_}||''; + print HISTORYTMP "${xmlrb}".XMLEncodeForHisto($_)."${xmlrs}$page${xmlrs}", ${'_section_' . $extranum . '_h'}{$_}, "${xmlrs}$bytes${xmlrs}$lastaccess${xmlre}\n"; next; + } + print HISTORYTMP "${xmleb}END_EXTRA_$extranum${xmlee}\n"; + } + } + + # Other - Plugin sections + if ($AtLeastOneSectionPlugin && $sectiontosave =~ /^plugin_(\w+)$/i) { + my $pluginname=$1; + if ($PluginsLoaded{'SectionInitHashArray'}{"$pluginname"}) { +# my $function="SectionWriteHistory_$pluginname(\$xml,\$xmlbb,\$xmlbs,\$xmlbe,\$xmlrb,\$xmlrs,\$xmlre,\$xmleb,\$xmlee)"; +# eval("$function"); + my $function="SectionWriteHistory_$pluginname"; + &$function($xml,$xmlbb,$xmlbs,$xmlbe,$xmlrb,$xmlrs,$xmlre,$xmleb,$xmlee); + } + } + + %keysinkeylist=(); +} + +#-------------------------------------------------------------------- +# Function: Rename all tmp history file into history +# Parameters: None +# Input: $DirData $PROG $FileSuffix +# $KeepBackupOfHistoricFile $SaveDatabaseFilesWithPermissionsForEveryone +# Output: None +# Return: 1 Ok, 0 at least one error (tmp files are removed) +#-------------------------------------------------------------------- +sub Rename_All_Tmp_History { + my $pid=$$; + my $renameok=1; + + if ($Debug) { debug("Call to Rename_All_Tmp_History (FileSuffix=$FileSuffix)"); } + + opendir(DIR,"$DirData"); + + my $datemask; + if ($DatabaseBreak eq 'month') { $datemask='\d\d\d\d\d\d'; } + elsif ($DatabaseBreak eq 'year') { $datemask='\d\d\d\d'; } + elsif ($DatabaseBreak eq 'day') { $datemask='\d\d\d\d\d\d\d\d'; } + elsif ($DatabaseBreak eq 'hour') { $datemask='\d\d\d\d\d\d\d\d\d\d'; } + if ($Debug) { debug("Scan for temp history files to rename into DirData='$DirData' with mask='$datemask'"); } + + my $regfilesuffix=quotemeta($FileSuffix); + foreach (grep /^$PROG($datemask)$regfilesuffix\.tmp\.$pid$/, file_filt sort readdir DIR) { + /^$PROG($datemask)$regfilesuffix\.tmp\.$pid$/; + if ($renameok) { # No rename error yet + if ($Debug) { debug(" Rename new tmp history file $PROG$1$FileSuffix.tmp.$$ into $PROG$1$FileSuffix.txt",1); } + if (-s "$DirData/$PROG$1$FileSuffix.tmp.$$") { # Rename tmp files if size > 0 + if ($KeepBackupOfHistoricFiles) { + if (-s "$DirData/$PROG$1$FileSuffix.txt") { # History file already exists. We backup it + if ($Debug) { debug(" Make a backup of old history file into $PROG$1$FileSuffix.bak before",1); } + #if (FileCopy("$DirData/$PROG$1$FileSuffix.txt","$DirData/$PROG$1$FileSuffix.bak")) { + if (rename("$DirData/$PROG$1$FileSuffix.txt", "$DirData/$PROG$1$FileSuffix.bak")==0) { + warning("Warning: Failed to make a backup of \"$DirData/$PROG$1$FileSuffix.txt\" into \"$DirData/$PROG$1$FileSuffix.bak\"."); + } + if ($SaveDatabaseFilesWithPermissionsForEveryone) { + chmod 0666,"$DirData/$PROG$1$FileSuffix.bak"; + } + } + else { + if ($Debug) { debug(" No need to backup old history file",1); } + } + } + if (rename("$DirData/$PROG$1$FileSuffix.tmp.$$", "$DirData/$PROG$1$FileSuffix.txt")==0) { + $renameok=0; # At least one error in renaming working files + # Remove tmp file + unlink "$DirData/$PROG$1$FileSuffix.tmp.$$"; + warning("Warning: Failed to rename \"$DirData/$PROG$1$FileSuffix.tmp.$$\" into \"$DirData/$PROG$1$FileSuffix.txt\".\nWrite permissions on \"$PROG$1$FileSuffix.txt\" might be wrong".($ENV{'GATEWAY_INTERFACE'}?" for an 'update from web'":"")." or file might be opened."); + next; + } + if ($SaveDatabaseFilesWithPermissionsForEveryone) { + chmod 0666,"$DirData/$PROG$1$FileSuffix.txt"; + } + } + } + else { # Because of rename error, we remove all remaining tmp files + unlink "$DirData/$PROG$1$FileSuffix.tmp.$$"; + } + } + close DIR; + return $renameok; +} + +#------------------------------------------------------------------------------ +# Function: Load DNS cache file entries into a memory hash array +# Parameters: Hash array ref to load into, +# File name to load, +# File suffix to use +# Save to a second plugin file if not up to date +# Input: None +# Output: Hash array is loaded +# Return: 1 No DNS Cache file found, 0 OK +#------------------------------------------------------------------------------ +sub Read_DNS_Cache { + my $hashtoload=shift; + my $dnscachefile=shift; + my $filesuffix=shift; + my $savetohash=shift; + + my $dnscacheext=''; + my $filetoload=''; + my $timetoload = time(); + + if ($Debug) { debug("Call to Read_DNS_Cache [file=\"$dnscachefile\"]"); } + if ($dnscachefile =~ s/(\.\w+)$//) { $dnscacheext=$1; } + foreach my $dir ("$DirData",".","") { + my $searchdir=$dir; + if ($searchdir && (!($searchdir =~ /\/$/)) && (!($searchdir =~ /\\$/)) ) { $searchdir .= "/"; } + if (-f "${searchdir}$dnscachefile$filesuffix$dnscacheext") { $filetoload="${searchdir}$dnscachefile$filesuffix$dnscacheext"; } + # Plugin call : Change filetoload + if ($PluginsLoaded{'SearchFile'}{'hashfiles'}) { SearchFile_hashfiles($searchdir,$dnscachefile,$filesuffix,$dnscacheext,$filetoload); } + if ($filetoload) { last; } # We found a file to load + } + + if (! $filetoload) { + if ($Debug) { debug(" No DNS Cache file found"); } + return 1; + } + + # Plugin call : Load hashtoload + if ($PluginsLoaded{'LoadCache'}{'hashfiles'}) { LoadCache_hashfiles($filetoload,$hashtoload); } + if (! scalar keys %$hashtoload) { + open(DNSFILE,"$filetoload") or error("Couldn't open DNS Cache file \"$filetoload\": $!"); + #binmode DNSFILE; # If we set binmode here, it seems that the load is broken on ActiveState 5.8 + # This is a fast way to load with regexp + %$hashtoload = map(/^(?:\d{0,10}\s+)?([0-9A-F:\.]+)\s+([^\s]+)$/oi,); + close DNSFILE; + if ($savetohash) { + # Plugin call : Save hash file (all records) with test if up to date to save + if ($PluginsLoaded{'SaveHash'}{'hashfiles'}) { SaveHash_hashfiles($filetoload,$hashtoload,1,0); } + } + } + if ($Debug) { debug(" Loaded ".(scalar keys %$hashtoload)." items from $filetoload in ".(time()-$timetoload)." seconds.",1); } + return 0; +} + +#------------------------------------------------------------------------------ +# Function: Save a memory hash array into a DNS cache file +# Parameters: Hash array ref to save, +# File name to save, +# File suffix to use +# Input: None +# Output: None +# Return: 0 OK, 1 Error +#------------------------------------------------------------------------------ +sub Save_DNS_Cache_File { + my $hashtosave=shift; + my $dnscachefile=shift; + my $filesuffix=shift; + + my $dnscacheext=''; + my $filetosave=''; + my $timetosave = time(); + my $nbofelemtosave=$NBOFLASTUPDATELOOKUPTOSAVE; + my $nbofelemsaved=0; + + if ($Debug) { debug("Call to Save_DNS_Cache_File [file=\"$dnscachefile\"]"); } + if (! scalar keys %$hashtosave) { + if ($Debug) { debug(" No data to save"); } + return 0; + } + if ($dnscachefile =~ s/(\.\w+)$//) { $dnscacheext=$1; } + $filetosave="$dnscachefile$filesuffix$dnscacheext"; + # Plugin call : Save hash file (only $NBOFLASTUPDATELOOKUPTOSAVE records) with no test if up to date + if ($PluginsLoaded{'SaveHash'}{'hashfiles'}) { + SaveHash_hashfiles($filetosave,$hashtosave,0,$nbofelemtosave,$nbofelemsaved); + if ($SaveDatabaseFilesWithPermissionsForEveryone) { + chmod 0666,"$filetosave"; + } + } + if (! $nbofelemsaved) { + $filetosave="$dnscachefile$filesuffix$dnscacheext"; + if ($Debug) { debug(" Save data ".($nbofelemtosave?"($nbofelemtosave records max)":"(all records)")." into file $filetosave"); } + if (! open(DNSFILE,">$filetosave")) { + warning("Warning: Failed to open for writing last update DNS Cache file \"$filetosave\": $!"); + return 1; + } + binmode DNSFILE; + my $starttimemin=int($starttime/60); + foreach my $key (keys %$hashtosave) { + #if ($hashtosave->{$key} ne '*') { + my $ipsolved=$hashtosave->{$key}; + print DNSFILE "$starttimemin\t$key\t".($ipsolved eq 'ip'?'*':$ipsolved)."\n"; # Change 'ip' to '*' for backward compatibility + if (++$nbofelemsaved >= $NBOFLASTUPDATELOOKUPTOSAVE) { last; } + #} + } + close DNSFILE; + + if ($SaveDatabaseFilesWithPermissionsForEveryone) { + chmod 0666,"$filetosave"; + } + + } + if ($Debug) { debug(" Saved $nbofelemsaved items into $filetosave in ".(time()-$timetosave)." seconds.",1); } + return 0; +} + +#------------------------------------------------------------------------------ +# Function: Return time elapsed since last call in miliseconds +# Parameters: 0|1 (0 reset counter, 1 no reset) +# Input: None +# Output: None +# Return: Number of miliseconds elapsed since last call +#------------------------------------------------------------------------------ +sub GetDelaySinceStart { + if (shift) { $StartSeconds=0; } # Reset chrono + my ($newseconds, $newmicroseconds)=(time(),0); + # Plugin call : Return seconds and milliseconds + if ($PluginsLoaded{'GetTime'}{'timehires'}) { GetTime_timehires($newseconds, $newmicroseconds); } + if (! $StartSeconds) { $StartSeconds=$newseconds; $StartMicroseconds=$newmicroseconds; } + return (($newseconds-$StartSeconds)*1000+int(($newmicroseconds-$StartMicroseconds)/1000)); +} + +#------------------------------------------------------------------------------ +# Function: Reset all variables whose name start with _ because a new month start +# Parameters: None +# Input: $YearRequired All variables whose name start with _ +# Output: All variables whose name start with _ +# Return: None +#------------------------------------------------------------------------------ +sub Init_HashArray { + if ($Debug) { debug("Call to Init_HashArray"); } + # Reset global hash arrays + %FirstTime = %LastTime = (); + %MonthHostsKnown = %MonthHostsUnknown = (); + %MonthVisits = %MonthUnique = (); + %MonthPages = %MonthHits = %MonthBytes = (); + %MonthNotViewedPages = %MonthNotViewedHits = %MonthNotViewedBytes = (); + %DayPages = %DayHits = %DayBytes = %DayVisits = (); + # Reset all arrays with name beginning by _ + for (my $ix=0; $ix<6; $ix++) { $_from_p[$ix]=0; $_from_h[$ix]=0; } + for (my $ix=0; $ix<24; $ix++) { $_time_h[$ix]=0; $_time_k[$ix]=0; $_time_p[$ix]=0; $_time_nv_h[$ix]=0; $_time_nv_k[$ix]=0; $_time_nv_p[$ix]=0; } + # Reset all hash arrays with name beginning by _ + %_session = %_browser_h = (); + %_domener_p = %_domener_h = %_domener_k = %_errors_h = %_errors_k = (); + %_filetypes_h = %_filetypes_k = %_filetypes_gz_in = %_filetypes_gz_out = (); + %_host_p = %_host_h = %_host_k = %_host_l = %_host_s = %_host_u = (); + %_waithost_e = %_waithost_l = %_waithost_s = %_waithost_u = (); + %_keyphrases = %_keywords = %_os_h = %_pagesrefs_p = %_pagesrefs_h = %_robot_h = %_robot_k = %_robot_l = %_robot_r = (); + %_worm_h = %_worm_k = %_worm_l = %_login_p = %_login_h = %_login_k = %_login_l = %_screensize_h = (); + %_misc_p = %_misc_h = %_misc_k = (); + %_cluster_p = %_cluster_h = %_cluster_k = (); + %_se_referrals_p = %_se_referrals_h = %_sider404_h = %_referer404_h = %_url_p = %_url_k = %_url_e = %_url_x = (); + %_unknownreferer_l = %_unknownrefererbrowser_l = (); + %_emails_h = %_emails_k = %_emails_l = %_emailr_h = %_emailr_k = %_emailr_l = (); + for (my $ix=1; $ix < @ExtraName; $ix++) { + %{'_section_' . $ix . '_h'} = %{'_section_' . $ix . '_o'} = %{'_section_' . $ix . '_k'} = + %{'_section_' . $ix . '_l'} = %{'_section_' . $ix . '_p'} = (); + } + foreach my $pluginname (keys %{$PluginsLoaded{'SectionInitHashArray'}}) { +# my $function="SectionInitHashArray_$pluginname()"; +# eval("$function"); + my $function="SectionInitHashArray_$pluginname"; + &$function(); + } +} + +#------------------------------------------------------------------------------ +# Function: Change word separators of a keyphrase string into space and +# remove bad coded chars +# Parameters: stringtodecode +# Input: None +# Output: None +# Return: decodedstring +#------------------------------------------------------------------------------ +sub ChangeWordSeparatorsIntoSpace { + $_[0] =~ s/%0[ad]/ /ig; # LF CR + $_[0] =~ s/%2[02789abc]/ /ig; # space " ' ( ) * + , + $_[0] =~ s/%3a/ /ig; # : + $_[0] =~ tr/\+\'\(\)\"\*,:/ /s; # "&" and "=" must not be in this list +} + +#------------------------------------------------------------------------------ +# Function: Transforms special chars by entities as needed in XML/XHTML +# Parameters: stringtoencode +# Return: encodedstring +#------------------------------------------------------------------------------ +sub XMLEncode { + if ($BuildReportFormat ne 'xhtml' && $BuildReportFormat ne 'xml') { return shift; } + my $string = shift; + $string =~ s/&/&/g; + $string =~ s//>/g; + $string =~ s/\"/"/g; + $string =~ s/\'/'/g; + return $string; +} + +#------------------------------------------------------------------------------ +# Function: Transforms spaces into %20 and special chars by entities as needed in XML/XHTML +# Parameters: stringtoencode +# Return: encodedstring +#------------------------------------------------------------------------------ +sub XMLEncodeForHisto { + my $string = shift; + $string =~ s/\s/%20/g; + if ($BuildHistoryFormat ne 'xml') { return $string; } + $string =~ s/&/&/g; + $string =~ s//>/g; + $string =~ s/\"/"/g; + $string =~ s/\'/'/g; + return $string; +} + +#------------------------------------------------------------------------------ +# Function: Encode a binary string into an ASCII string +# Parameters: stringtoencode +# Return: encodedstring +#------------------------------------------------------------------------------ +sub EncodeString { + my $string = shift; +# use bytes; + $string =~ s/([\x2B\x80-\xFF])/sprintf ("%%%2x", ord($1))/eg; +# no bytes; + $string =~ tr/ /+/s; + return $string; +} + +#------------------------------------------------------------------------------ +# Function: Decode an only text string into a binary string +# Parameters: stringtodecode +# Input: None +# Output: None +# Return: decodedstring +#------------------------------------------------------------------------------ +sub DecodeEncodedString { + my $stringtodecode=shift; + $stringtodecode =~ tr/\+/ /s; + $stringtodecode =~ s/%([A-F0-9][A-F0-9])/pack("C", hex($1))/ieg; + $stringtodecode =~ s/["']//g; + return $stringtodecode; +} + +#------------------------------------------------------------------------------ +# Function: Decode an precompiled regex value to a common regex value +# Parameters: compiledregextodecode +# Input: None +# Output: None +# Return: standardregex +#------------------------------------------------------------------------------ +sub UnCompileRegex { + shift =~ /\(\?[-\w]*:(.*)\)/; + return $1; +} + +#------------------------------------------------------------------------------ +# Function: Clean a string of all chars that are not char or _ - \ / . \s +# Parameters: stringtoclean, full +# Input: None +# Output: None +# Return: cleanedstring +#------------------------------------------------------------------------------ +sub Sanitize { + my $stringtoclean=shift; + my $full=shift||0; + if ($full) { + $stringtoclean =~ s/[^\w]//g; + } else { + $stringtoclean =~ s/[^\w\-\\\/\.:\s]//g; + } + return $stringtoclean; +} + +#------------------------------------------------------------------------------ +# Function: Clean a string of HTML tags to avoid 'Cross Site Scripting attacks' +# and clean | char. +# A XSS attack is providing an AWStats url with XSS code that is executed +# when page loaded by awstats CGI is loaded from AWStats server. Such a code +# can be +# This make the browser sending a request to the attacker server that contains +# cookie used for AWStats server sessions. Attacker can this way caught this +# cookie and used it to go on AWStats server like original visitor. For this +# resaon, parameter received by AWStats must be sanitized by this function +# before beeing put inside a web page. +# Parameters: stringtoclean +# Input: None +# Output: None +# Return: cleanedstring +#------------------------------------------------------------------------------ +sub CleanXSS { + my $stringtoclean=shift; + $stringtoclean =~ s//>/g; + $stringtoclean =~ s/|//g; + return $stringtoclean; +} + +#------------------------------------------------------------------------------ +# Function: Clean tags in a string +# Parameters: stringtodecode +# Input: None +# Output: None +# Return: decodedstring +#------------------------------------------------------------------------------ +sub CleanFromTags { + my $stringtoclean=shift; + $stringtoclean =~ s/$regclean1/ /g; # Replace or with space + $stringtoclean =~ s/$regclean2//g; # Remove + return $stringtoclean; +} + +#------------------------------------------------------------------------------ +# Function: Copy one file into another +# Parameters: sourcefilename targetfilename +# Input: None +# Output: None +# Return: 0 if copy is ok, 1 else +#------------------------------------------------------------------------------ +sub FileCopy { + my $filesource = shift; + my $filetarget = shift; + if ($Debug) { debug("FileCopy($filesource,$filetarget)",1); } + open(FILESOURCE,"$filesource") || return 1; + open(FILETARGET,">$filetarget") || return 1; + binmode FILESOURCE; + binmode FILETARGET; + # ... + close(FILETARGET); + close(FILESOURCE); + if ($Debug) { debug(" File copied",1); } + return 0; +} + +#------------------------------------------------------------------------------ +# Function: Format a QUERY_STRING +# Parameters: query +# Input: None +# Output: None +# Return: formated query +#------------------------------------------------------------------------------ +# TODO Appeller cette fonction partout ou il y a des NewLinkParams +sub CleanNewLinkParamsFrom { + my $NewLinkParams=shift; + while (my $param = shift) { + $NewLinkParams =~ s/(^|&|&)$param(=[^&]*|$)//i; + } + $NewLinkParams =~ s/(&|&)+/&/i; + $NewLinkParams =~ s/^&//; $NewLinkParams =~ s/&$//; + return $NewLinkParams; +} + +#------------------------------------------------------------------------------ +# Function: Show flags for other language translations +# Parameters: Current languade id (en, fr, ...) +# Input: None +# Output: None +# Return: None +#------------------------------------------------------------------------------ +sub Show_Flag_Links { + my $CurrentLang = shift; + + # Build flags link + my $NewLinkParams=$QueryString; + my $NewLinkTarget=''; + if ($ENV{'GATEWAY_INTERFACE'}) { + $NewLinkParams=CleanNewLinkParamsFrom($NewLinkParams,('update','staticlinks','framename','lang')); + $NewLinkParams =~ s/(^|&|&)update(=\w*|$)//i; + $NewLinkParams =~ s/(^|&|&)staticlinks(=\w*|$)//i; + $NewLinkParams =~ s/(^|&|&)framename=[^&]*//i; + $NewLinkParams =~ s/(^|&|&)lang=[^&]*//i; + $NewLinkParams =~ s/(&|&)+/&/i; + $NewLinkParams =~ s/^&//; $NewLinkParams =~ s/&$//; + if ($NewLinkParams) { $NewLinkParams="${NewLinkParams}&"; } + if ($FrameName eq 'mainright') { $NewLinkTarget=" target=\"_parent\""; } + } + else { + $NewLinkParams=($SiteConfig?"config=$SiteConfig&":"")."year=$YearRequired&month=$MonthRequired&"; + } + if ($NewLinkParams !~ /output=/) { $NewLinkParams.='output=main&'; } + if ($FrameName eq 'mainright') { $NewLinkParams.='framename=index&'; } + + foreach my $lng (split(/\s+/,$ShowFlagLinks)) { + $lng=$LangBrowserToLangAwstats{$lng}?$LangBrowserToLangAwstats{$lng}:$lng; + if ($lng ne $CurrentLang) { + my %lngtitle=('en','English','fr','French','de','German','it','Italian','nl','Dutch','es','Spanish'); + my $lngtitle=($lngtitle{$lng}?$lngtitle{$lng}:$lng); + my $flag=($LangAWStatsToFlagAwstats{$lng}?$LangAWStatsToFlagAwstats{$lng}:$lng); + print " \n"; + } + } +} + +#------------------------------------------------------------------------------ +# Function: Format value in bytes in a string (Bytes, Kb, Mb, Gb) +# Parameters: bytes (integer value or "0.00") +# Input: None +# Output: None +# Return: "x.yz MB" or "x.yy KB" or "x Bytes" or "0" +#------------------------------------------------------------------------------ +sub Format_Bytes { + my $bytes = shift||0; + my $fudge = 1; + # Do not use exp/log function to calculate 1024power, function make segfault on some unix/perl versions + if ($bytes >= ($fudge << 30)) { return sprintf("%.2f", $bytes/1073741824)." $Message[110]"; } + if ($bytes >= ($fudge << 20)) { return sprintf("%.2f", $bytes/1048576)." $Message[109]"; } + if ($bytes >= ($fudge << 10)) { return sprintf("%.2f", $bytes/1024)." $Message[108]"; } + if ($bytes < 0) { $bytes="?"; } + return int($bytes).(int($bytes)?" $Message[119]":""); +} + +#------------------------------------------------------------------------------ +# Function: Format a number +# Parameters: number +# Input: None +# Output: None +# Return: "999 999 999 999" +#------------------------------------------------------------------------------ +sub Format_Number { + my $number = shift||0; + $number=~s/(\d)(\d\d\d)$/$1 $2/; + $number=~s/(\d)(\d\d\d\s\d\d\d)$/$1 $2/; + $number=~s/(\d)(\d\d\d\s\d\d\d\s\d\d\d)$/$1 $2/; + return $number; +} + +#------------------------------------------------------------------------------ +# Function: Return " alt=string title=string" +# Parameters: string +# Input: None +# Output: None +# Return: "alt=string title=string" +#------------------------------------------------------------------------------ +sub AltTitle { + my $string = shift||''; + return " alt='$string' title='$string'"; +# return " alt=\"$string\" title=\"$string\""; +# return ($BuildReportFormat?"":" alt=\"$string\"")." title=\"$string\""; +} + +#------------------------------------------------------------------------------ +# Function: Tell if an email is a local or external email +# Parameters: email +# Input: $SiteDomain(exact string) $HostAliases(quoted regex string) +# Output: None +# Return: -1, 0 or 1 +#------------------------------------------------------------------------------ +sub IsLocalEMail { + my $email=shift||'unknown'; + if ($email !~ /\@(.*)$/) { return 0; } + my $domain=$1; + if ($domain =~ /^$SiteDomain$/i) { return 1; } + foreach (@HostAliases) { if ($domain =~ /$_/) { return 1; } } + return -1; +} + +#------------------------------------------------------------------------------ +# Function: Format a date according to Message[78] (country date format) +# Parameters: String date YYYYMMDDHHMMSS +# Option 0=LastUpdate and LastTime date +# 1=Arrays date except daymonthvalues +# 2=daymonthvalues date (only year month and day) +# Input: $Message[78] +# Output: None +# Return: Date with format defined by Message[78] and option +#------------------------------------------------------------------------------ +sub Format_Date { + my $date=shift; + my $option=shift||0; + my $year=substr("$date",0,4); + my $month=substr("$date",4,2); + my $day=substr("$date",6,2); + my $hour=substr("$date",8,2); + my $min=substr("$date",10,2); + my $sec=substr("$date",12,2); + my $dateformat=$Message[78]; + if ($option == 2) { + $dateformat =~ s/^[^ymd]+//g; + $dateformat =~ s/[^ymd]+$//g; + } + $dateformat =~ s/yyyy/$year/g; + $dateformat =~ s/yy/$year/g; + $dateformat =~ s/mmm/$MonthNumLib{$month}/g; + $dateformat =~ s/mm/$month/g; + $dateformat =~ s/dd/$day/g; + $dateformat =~ s/HH/$hour/g; + $dateformat =~ s/MM/$min/g; + $dateformat =~ s/SS/$sec/g; + return "$dateformat"; +} + +#------------------------------------------------------------------------------ +# Function: Return 1 if string contains only ascii chars +# Parameters: string +# Input: None +# Output: None +# Return: 0 or 1 +#------------------------------------------------------------------------------ +sub IsAscii { + my $string=shift; + if ($Debug) { debug("IsAscii($string)",5); } + if ($string =~ /^[\w\+\-\/\\\.%,;:=\"\'&?!\s]+$/) { + if ($Debug) { debug(" Yes",6); } + return 1; # Only alphanum chars (and _) or + - / \ . % , ; : = " ' & ? space \t + } + if ($Debug) { debug(" No",6); } + return 0; +} + +#------------------------------------------------------------------------------ +# Function: Return the lower value between 2 but exclude value if 0 +# Parameters: Val1 and Val2 +# Input: None +# Output: None +# Return: min(Val1,Val2) +#------------------------------------------------------------------------------ +sub MinimumButNoZero { + my ($val1,$val2)=@_; + return ($val1&&($val1<$val2||!$val2)?$val1:$val2); +} + +#------------------------------------------------------------------------------ +# Function: Add a val from sorting tree +# Parameters: keytoadd keyval [firstadd] +# Input: None +# Output: None +# Return: None +#------------------------------------------------------------------------------ +sub AddInTree { + my $keytoadd=shift; + my $keyval=shift; + my $firstadd=shift||0; + if ($firstadd==1) { # Val is the first one + if ($Debug) { debug(" firstadd",4); } + $val{$keyval}=$keytoadd; + $lowerval=$keyval; + if ($Debug) { debug(" lowerval=$lowerval, nb elem val=".(scalar keys %val).", nb elem egal=".(scalar keys %egal).".",4); } + return; + } + if ($val{$keyval}) { # Val is already in tree + if ($Debug) { debug(" val is already in tree",4); } + $egal{$keytoadd}=$val{$keyval}; + $val{$keyval}=$keytoadd; + if ($Debug) { debug(" lowerval=$lowerval, nb elem val=".(scalar keys %val).", nb elem egal=".(scalar keys %egal).".",4); } + return; + } + if ($keyval <= $lowerval) { # Val is a new one lower (should happens only when tree is not full) + if ($Debug) { debug(" keytoadd val=$keyval is lower or equal to lowerval=$lowerval",4); } + $val{$keyval}=$keytoadd; + $nextval{$keyval}=$lowerval; + $lowerval=$keyval; + if ($Debug) { debug(" lowerval=$lowerval, nb elem val=".(scalar keys %val).", nb elem egal=".(scalar keys %egal).".",4); } + return; + } + # Val is a new one higher + if ($Debug) { debug(" keytoadd val=$keyval is higher than lowerval=$lowerval",4); } + $val{$keyval}=$keytoadd; + my $valcursor=$lowerval; # valcursor is value just before keyval + while ($nextval{$valcursor} && ($nextval{$valcursor} < $keyval)) { $valcursor=$nextval{$valcursor}; } + if ($nextval{$valcursor}) { # keyval is between valcursor and nextval{valcursor} + $nextval{$keyval}=$nextval{$valcursor}; + } + $nextval{$valcursor}=$keyval; + if ($Debug) { debug(" lowerval=$lowerval, nb elem val=".(scalar keys %val).", nb elem egal=".(scalar keys %egal).".",4); } +} + +#------------------------------------------------------------------------------ +# Function: Remove a val from sorting tree +# Parameters: None +# Input: $lowerval %val %egal +# Output: None +# Return: None +#------------------------------------------------------------------------------ +sub Removelowerval { + my $keytoremove=$val{$lowerval}; # This is lower key + if ($Debug) { debug(" remove for lowerval=$lowerval: key=$keytoremove",4); } + if ($egal{$keytoremove}) { + $val{$lowerval}=$egal{$keytoremove}; + delete $egal{$keytoremove}; + } + else { + delete $val{$lowerval}; + $lowerval=$nextval{$lowerval}; # Set new lowerval + } + if ($Debug) { debug(" new lower value=$lowerval, val size=".(scalar keys %val).", egal size=".(scalar keys %egal),4); } +} + +#------------------------------------------------------------------------------ +# Function: Build @keylist array +# Parameters: Size max for @keylist array, +# Min value in hash for select, +# Hash used for select, +# Hash used for order +# Input: None +# Output: None +# Return: @keylist response array +#------------------------------------------------------------------------------ +sub BuildKeyList { + my $ArraySize=shift||error("System error. Call to BuildKeyList function with incorrect value for first param","","",1); + my $MinValue=shift||error("System error. Call to BuildKeyList function with incorrect value for second param","","",1); + my $hashforselect=shift; + my $hashfororder=shift; + if ($Debug) { debug(" BuildKeyList($ArraySize,$MinValue,$hashforselect with size=".(scalar keys %$hashforselect).",$hashfororder with size=".(scalar keys %$hashfororder).")",3); } + delete $hashforselect->{0};delete $hashforselect->{''}; # Those is to protect from infinite loop when hash array has an incorrect null key + my $count=0; + $lowerval=0; # Global because used in AddInTree and Removelowerval + %val=(); %nextval=(); %egal=(); + foreach my $key (keys %$hashforselect) { + if ($count < $ArraySize) { + if ($hashforselect->{$key} >= $MinValue) { + $count++; + if ($Debug) { debug(" Add in tree entry $count : $key (value=".($hashfororder->{$key}||0).", tree not full)",4); } + AddInTree($key,$hashfororder->{$key}||0,$count); + } + next; + } + $count++; + if (($hashfororder->{$key}||0)<=$lowerval) { next; } + if ($Debug) { debug(" Add in tree entry $count : $key (value=".($hashfororder->{$key}||0)." > lowerval=$lowerval)",4); } + AddInTree($key,$hashfororder->{$key}||0); + if ($Debug) { debug(" Removelower in tree",4); } + Removelowerval(); + } + + # Build key list and sort it + if ($Debug) { debug(" Build key list and sort it. lowerval=$lowerval, nb elem val=".(scalar keys %val).", nb elem egal=".(scalar keys %egal).".",3); } + my %notsortedkeylist=(); + foreach my $key (values %val) { $notsortedkeylist{$key}=1; } + foreach my $key (values %egal) { $notsortedkeylist{$key}=1; } + @keylist=(); + @keylist=(sort {($hashfororder->{$b}||0) <=> ($hashfororder->{$a}||0) } keys %notsortedkeylist); + if ($Debug) { debug(" BuildKeyList End (keylist size=".(@keylist).")",3); } + return; +} + +#------------------------------------------------------------------------------ +# Function: Lock or unlock update +# Parameters: status (1 to lock, 0 to unlock) +# Input: $DirLock (if status=0) $PROG $FileSuffix +# Output: $DirLock (if status=1) +# Return: None +#------------------------------------------------------------------------------ +sub Lock_Update { + my $status=shift; + my $lock="$PROG$FileSuffix.lock"; + if ($status) { + # We stop if there is at least one lock file wherever it is + foreach my $key ($ENV{"TEMP"},$ENV{"TMP"},"/tmp","/",".") { + my $newkey =$key; + $newkey =~ s/[\\\/]$//; + if (-f "$newkey/$lock") { error("An AWStats update process seems to be already running for this config file. Try later.\nIf this is not true, remove manually lock file '$newkey/$lock'.","","",1); } + } + # Set lock where we can + foreach my $key ($ENV{"TEMP"},$ENV{"TMP"},"/tmp","/",".") { + if (! -d "$key") { next; } + $DirLock=$key; + $DirLock =~ s/[\\\/]$//; + if ($Debug) { debug("Update lock file $DirLock/$lock is set"); } + open(LOCK,">$DirLock/$lock") || error("Failed to create lock file $DirLock/$lock","","",1); + print LOCK "AWStats update started by process $$ at $nowyear-$nowmonth-$nowday $nowhour:$nowmin:$nowsec\n"; + close(LOCK); + last; + } + } + else { + # Remove lock + if ($Debug) { debug("Update lock file $DirLock/$lock is removed"); } + unlink("$DirLock/$lock"); + } + return; +} + +#------------------------------------------------------------------------------ +# Function: Signal handler to call Lock_Update to remove lock file +# Parameters: Signal name +# Input: None +# Output: None +# Return: None +#------------------------------------------------------------------------------ +sub SigHandler { + my $signame = shift; + print ucfirst($PROG)." process (ID $$) interrupted by signal $signame.\n"; + &Lock_Update(0); + exit 1; +} + +#------------------------------------------------------------------------------ +# Function: Convert an IPAddress into an integer +# Parameters: IPAddress +# Input: None +# Output: None +# Return: Int +#------------------------------------------------------------------------------ +sub Convert_IP_To_Decimal { + my ($IPAddress) = @_; + my @ip_seg_arr = split(/\./,$IPAddress); + my $decimal_ip_address = 256 * 256 *256 * $ip_seg_arr[0] + 256 * 256 * $ip_seg_arr[1] + 256 * $ip_seg_arr[2] + $ip_seg_arr[3]; + return($decimal_ip_address); +} + +#------------------------------------------------------------------------------ +# Function: Test there is at least on value in list not null +# Parameters: List of values +# Input: None +# Output: None +# Return: 1 There is at least one not null value, 0 else +#------------------------------------------------------------------------------ +sub AtLeastOneNotNull { + if ($Debug) { debug(" Call to AtLeastOneNotNull (".join('-',@_).")",3); } + foreach my $val (@_) { if ($val) { return 1; } } + return 0; +} + +#------------------------------------------------------------------------------ +# Function: Return the string to add in html tag to include popup javascript code +# Parameters: tooltip number +# Input: None +# Output: None +# Return: string with javascript code +#------------------------------------------------------------------------------ +sub Tooltip { + my $ttnb=shift; + return ($TOOLTIPON?" onmouseover=\"ShowTip($ttnb);\" onmouseout=\"HideTip($ttnb);\"":""); +} + +#------------------------------------------------------------------------------ +# Function: Insert a form filter +# Parameters: Name of filter field, default for filter field, default for exclude filter field +# Input: $StaticLinks, $QueryString, $SiteConfig, $DirConfig +# Output: HTML Form +# Return: None +#------------------------------------------------------------------------------ +sub ShowFormFilter { + my $fieldfiltername=shift; + my $fieldfilterinvalue=shift; + my $fieldfilterexvalue=shift; + if (! $StaticLinks) { + my $NewLinkParams=${QueryString}; + $NewLinkParams =~ s/(^|&|&)update(=\w*|$)//i; + $NewLinkParams =~ s/(^|&|&)output(=\w*|$)//i; + $NewLinkParams =~ s/(^|&|&)staticlinks(=\w*|$)//i; + $NewLinkParams =~ s/(&|&)+/&/i; + $NewLinkParams =~ s/^&//; $NewLinkParams =~ s/&$//; + if ($NewLinkParams) { $NewLinkParams="${NewLinkParams}&"; } + print "\n
\n"; + print "\n"; + print "\n"; + print "\n"; + print ""; + print "\n"; + print "\n"; + print "\n"; + print ""; + print "
$Message[79] :   $Message[153] :"; + print "\n"; + if ($SiteConfig) { print "\n"; } + if ($DirConfig) { print "\n"; } + if ($QueryString =~ /(^|&|&)year=(\d\d\d\d)/i) { print "\n"; } + if ($QueryString =~ /(^|&|&)month=(\d\d)/i || $QueryString =~ /(^|&|&)month=(all)/i) { print "\n"; } + if ($QueryString =~ /(^|&|&)lang=(\w+)/i) { print "\n"; } + if ($QueryString =~ /(^|&|&)debug=(\d+)/i) { print "\n"; } + if ($QueryString =~ /(^|&|&)framename=(\w+)/i) { print "\n"; } + print "  
\n"; + print "
\n"; + print "
\n"; + print "\n"; + } +} + +#------------------------------------------------------------------------------ +# Function: Write other user info (with help of plugin) +# Parameters: $user +# Input: $SiteConfig +# Output: URL link +# Return: None +#------------------------------------------------------------------------------ +sub ShowUserInfo { + my $user=shift; + # Call to plugins' function ShowInfoUser + foreach my $pluginname (sort keys %{$PluginsLoaded{'ShowInfoUser'}}) { +# my $function="ShowInfoUser_$pluginname('$user')"; +# eval("$function"); + my $function="ShowInfoUser_$pluginname"; + &$function($user); + } +} + +#------------------------------------------------------------------------------ +# Function: Write other cluster info (with help of plugin) +# Parameters: $clusternb +# Input: $SiteConfig +# Output: Cluster info +# Return: None +#------------------------------------------------------------------------------ +sub ShowClusterInfo { + my $user=shift; + # Call to plugins' function ShowInfoCluster + foreach my $pluginname (sort keys %{$PluginsLoaded{'ShowInfoCluster'}}) { +# my $function="ShowInfoCluster_$pluginname('$user')"; +# eval("$function"); + my $function="ShowInfoCluster_$pluginname"; + &$function($user); + } +} + +#------------------------------------------------------------------------------ +# Function: Write other host info (with help of plugin) +# Parameters: $host +# Input: $LinksToWhoIs $LinksToWhoIsIp +# Output: None +# Return: None +#------------------------------------------------------------------------------ +sub ShowHostInfo { + my $host=shift; + # Call to plugins' function ShowInfoHost + foreach my $pluginname (sort keys %{$PluginsLoaded{'ShowInfoHost'}}) { +# my $function="ShowInfoHost_$pluginname('$host')"; +# eval("$function"); + my $function="ShowInfoHost_$pluginname"; + &$function($host); + } +} + +#------------------------------------------------------------------------------ +# Function: Write other url info (with help of plugin) +# Parameters: $url +# Input: %Aliases $MaxLengthOfShownURL $ShowLinksOnUrl $SiteDomain $UseHTTPSLinkForUrl +# Output: URL link +# Return: None +#------------------------------------------------------------------------------ +sub ShowURLInfo { + my $url=shift; + my $nompage=CleanXSS($url); + + # Call to plugins' function ShowInfoURL + foreach my $pluginname (keys %{$PluginsLoaded{'ShowInfoURL'}}) { +# my $function="ShowInfoURL_$pluginname('$url')"; +# eval("$function"); + my $function="ShowInfoURL_$pluginname"; + &$function($url); + } + + if (length($nompage)>$MaxLengthOfShownURL) { $nompage=substr($nompage,0,$MaxLengthOfShownURL)."..."; } + if ($ShowLinksOnUrl) { + my $newkey=CleanXSS($url); + if ($LogType eq 'W' || $LogType eq 'S') { # Web or streaming log file + if ($newkey =~ /^http(s|):/i) { # URL seems to be extracted from a proxy log file + print "".XMLEncode($nompage).""; + } + elsif ($newkey =~ /^\//) { # URL seems to be an url extracted from a web or wap server log file + $newkey =~ s/^\/$SiteDomain//i; + # Define urlprot + my $urlprot='http'; + if ($UseHTTPSLinkForUrl && $newkey =~ /^$UseHTTPSLinkForUrl/) { $urlprot='https'; } + print "".XMLEncode($nompage).""; + } + else { + print XMLEncode($nompage); + } + } + elsif ($LogType eq 'F') { # Ftp log file + print XMLEncode($nompage); + } + elsif ($LogType eq 'M') { # Smtp log file + print XMLEncode($nompage); + } + else { # Other type log file + print XMLEncode($nompage); + } + } + else { + print XMLEncode($nompage); + } +} + +#------------------------------------------------------------------------------ +# Function: Define value for PerlParsingFormat (used for regex log record parsing) +# Parameters: $LogFormat +# Input: - +# Output: $pos_xxx, @pos_extra, @fieldlib, $PerlParsingFormat +# Return: - +#------------------------------------------------------------------------------ +sub DefinePerlParsingFormat { + my $LogFormat=shift; + $pos_vh = $pos_host = $pos_logname = $pos_date = $pos_tz = $pos_method = $pos_url = $pos_code = $pos_size = -1; + $pos_referer = $pos_agent = $pos_query = $pos_gzipin = $pos_gzipout = $pos_compratio = -1; + $pos_cluster = $pos_emails = $pos_emailr = $pos_hostr = -1; + @pos_extra=(); + @fieldlib=(); + $PerlParsingFormat=''; + # Log records examples: + # Apache combined: 62.161.78.73 user - [dd/mmm/yyyy:hh:mm:ss +0000] "GET / HTTP/1.1" 200 1234 "http://www.from.com/from.htm" "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0)" + # Apache combined (408 error): my.domain.com - user [09/Jan/2001:11:38:51 -0600] "OPTIONS /mime-tmp/xxx file.doc HTTP/1.1" 408 - "-" "-" + # Apache combined (408 error): 62.161.78.73 user - [dd/mmm/yyyy:hh:mm:ss +0000] "-" 408 - "-" "-" + # Apache common_with_mod_gzip_info1: %h %l %u %t \"%r\" %>s %b mod_gzip: %{mod_gzip_compression_ratio}npct. + # Apache common_with_mod_gzip_info2: %h %l %u %t \"%r\" %>s %b mod_gzip: %{mod_gzip_result}n In:%{mod_gzip_input_size}n Out:%{mod_gzip_output_size}n:%{mod_gzip_compression_ratio}npct. + # Apache deflate: %h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" (%{ratio}n) + # IIS: 2000-07-19 14:14:14 62.161.78.73 - GET / 200 1234 HTTP/1.1 Mozilla/4.0+(compatible;+MSIE+5.01;+Windows+NT+5.0) http://www.from.com/from.htm + # WebStar: 05/21/00 00:17:31 OK 200 212.242.30.6 Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt) http://www.cover.dk/ "www.cover.dk" :Documentation:graphics:starninelogo.white.gif 1133 + # Squid extended: 12.229.91.170 - - [27/Jun/2002:03:30:50 -0700] "GET http://www.callistocms.com/images/printable.gif HTTP/1.1" 304 354 "-" "Mozilla/5.0 Galeon/1.0.3 (X11; Linux i686; U;) Gecko/0" TCP_REFRESH_HIT:DIRECT + if ($Debug) { debug("Call To DefinePerlParsingFormat (LogType='$LogType', LogFormat='$LogFormat')"); } + if ($LogFormat =~ /^[1-6]$/) { # Pre-defined log format + if ($LogFormat eq '1' || $LogFormat eq '6') { # Same than "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"". + # %u (user) is "([^\\[]+)" instead of "[^ ]+" because can contain space (Lotus Notes). referer and ua might be "". +# $PerlParsingFormat="([^ ]+) [^ ]+ ([^\\[]+) \\[([^ ]+) [^ ]+\\] \\\"([^ ]+) (.+) [^\\\"]+\\\" ([\\d|-]+) ([\\d|-]+) \\\"(.*?)\\\" \\\"([^\\\"]*)\\\""; + $PerlParsingFormat="([^ ]+) [^ ]+ ([^\\[]+) \\[([^ ]+) [^ ]+\\] \\\"([^ ]+) ([^ ]+) [^\\\"]+\\\" ([\\d|-]+) ([\\d|-]+) \\\"(.*?)\\\" \\\"([^\\\"]*)\\\""; + $pos_host=0;$pos_logname=1;$pos_date=2;$pos_method=3;$pos_url=4;$pos_code=5;$pos_size=6;$pos_referer=7;$pos_agent=8; + @fieldlib=('host','logname','date','method','url','code','size','referer','ua'); + } + elsif ($LogFormat eq '2') { # Same than "date time c-ip cs-username cs-method cs-uri-stem sc-status sc-bytes cs-version cs(User-Agent) cs(Referer)" + $PerlParsingFormat="(\\S+ \\S+) (\\S+) (\\S+) (\\S+) (\\S+) ([\\d|-]+) ([\\d|-]+) \\S+ (\\S+) (\\S+)"; + $pos_date=0;$pos_host=1;$pos_logname=2;$pos_method=3;$pos_url=4;$pos_code=5;$pos_size=6;$pos_agent=7;$pos_referer=8; + @fieldlib=('date','host','logname','method','url','code','size','ua','referer'); + } + elsif ($LogFormat eq '3') { + $PerlParsingFormat="([^\\t]*\\t[^\\t]*)\\t([^\\t]*)\\t([\\d|-]*)\\t([^\\t]*)\\t([^\\t]*)\\t([^\\t]*)\\t[^\\t]*\\t([^\\t]*)\\t([\\d]*)"; + $pos_date=0;$pos_method=1;$pos_code=2;$pos_host=3;$pos_agent=4;$pos_referer=5;$pos_url=6;$pos_size=7; + @fieldlib=('date','method','code','host','ua','referer','url','size'); + } + elsif ($LogFormat eq '4') { # Same than "%h %l %u %t \"%r\" %>s %b" + # %u (user) is "(.+)" instead of "[^ ]+" because can contain space (Lotus Notes). + $PerlParsingFormat="([^ ]+) [^ ]+ (.+) \\[([^ ]+) [^ ]+\\] \\\"([^ ]+) ([^ ]+) [^\\\"]+\\\" ([\\d|-]+) ([\\d|-]+)"; + $pos_host=0;$pos_logname=1;$pos_date=2;$pos_method=3;$pos_url=4;$pos_code=5;$pos_size=6; + @fieldlib=('host','logname','date','method','url','code','size'); + } + } + else { # Personalized log format + my $LogFormatString=$LogFormat; + # Replacement for Notes format string that are not Apache + $LogFormatString =~ s/%vh/%virtualname/g; + # Replacement for Apache format string + $LogFormatString =~ s/%v(\s)/%virtualname$1/g; $LogFormatString =~ s/%v$/%virtualname/g; + $LogFormatString =~ s/%h(\s)/%host$1/g; $LogFormatString =~ s/%h$/%host/g; + $LogFormatString =~ s/%l(\s)/%other$1/g; $LogFormatString =~ s/%l$/%other/g; + $LogFormatString =~ s/\"%u\"/%lognamequot/g; + $LogFormatString =~ s/%u(\s)/%logname$1/g; $LogFormatString =~ s/%u$/%logname/g; + $LogFormatString =~ s/%t(\s)/%time1$1/g; $LogFormatString =~ s/%t$/%time1/g; + $LogFormatString =~ s/\"%r\"/%methodurl/g; + $LogFormatString =~ s/%>s/%code/g; + $LogFormatString =~ s/%b(\s)/%bytesd$1/g; $LogFormatString =~ s/%b$/%bytesd/g; + $LogFormatString =~ s/\"%{Referer}i\"/%refererquot/g; + $LogFormatString =~ s/\"%{User-Agent}i\"/%uaquot/g; + $LogFormatString =~ s/%{mod_gzip_input_size}n/%gzipin/g; + $LogFormatString =~ s/%{mod_gzip_output_size}n/%gzipout/g; + $LogFormatString =~ s/%{mod_gzip_compression_ratio}n/%gzipratio/g; + $LogFormatString =~ s/\(%{ratio}n\)/%deflateratio/g; + # Replacement for a IIS and ISA format string + $LogFormatString =~ s/cs-uri-query/%query/g; # Must be before cs-uri + $LogFormatString =~ s/date\stime/%time2/g; + $LogFormatString =~ s/c-ip/%host/g; + $LogFormatString =~ s/cs-username/%logname/g; + $LogFormatString =~ s/cs-method/%method/g; # GET, POST, SMTP, RETR STOR + $LogFormatString =~ s/cs-uri-stem/%url/g; $LogFormatString =~ s/cs-uri/%url/g; + $LogFormatString =~ s/sc-status/%code/g; + $LogFormatString =~ s/sc-bytes/%bytesd/g; + $LogFormatString =~ s/cs-version/%other/g; # Protocol + $LogFormatString =~ s/cs\(User-Agent\)/%ua/g; $LogFormatString =~ s/c-agent/%ua/g; + $LogFormatString =~ s/cs\(Referer\)/%referer/g; $LogFormatString =~ s/cs-referred/%referer/g; + $LogFormatString =~ s/sc-authenticated/%other/g; + $LogFormatString =~ s/s-svcname/%other/g; + $LogFormatString =~ s/s-computername/%other/g; + $LogFormatString =~ s/r-host/%virtualname/g; + $LogFormatString =~ s/cs-host/%virtualname/g; + $LogFormatString =~ s/r-ip/%other/g; + $LogFormatString =~ s/r-port/%other/g; + $LogFormatString =~ s/time-taken/%other/g; + $LogFormatString =~ s/cs-bytes/%other/g; + $LogFormatString =~ s/cs-protocol/%other/g; + $LogFormatString =~ s/cs-transport/%other/g; + $LogFormatString =~ s/s-operation/%method/g; # GET, POST, SMTP, RETR STOR + $LogFormatString =~ s/cs-mime-type/%other/g; + $LogFormatString =~ s/s-object-source/%other/g; + $LogFormatString =~ s/s-cache-info/%other/g; + $LogFormatString =~ s/cluster-node/%cluster/g; + # Added for MMS + $LogFormatString =~ s/protocol/%protocolmms/g; # cs-method might not be available + $LogFormatString =~ s/c-status/%codemms/g; # c-status used when sc-status not available + if ($Debug) { debug(" LogFormatString=$LogFormatString"); } + # $LogFormatString has an AWStats format, so we can generate PerlParsingFormat variable + my $i = 0; + my $LogSeparatorWithoutStar=$LogSeparator; $LogSeparatorWithoutStar =~ s/[\*\+]//g; + foreach my $f (split(/\s+/,$LogFormatString)) { + # Add separator for next field + if ($PerlParsingFormat) { $PerlParsingFormat.="$LogSeparator"; } + # Special for logname + if ($f =~ /%lognamequot$/) { + $pos_logname = $i; $i++; push @fieldlib, 'logname'; + $PerlParsingFormat .= "\\\"?([^\\\"]*)\\\"?"; # logname can be "value", "" and - in same log (Lotus notes) + } + # Date format + elsif ($f =~ /%time1$/ || $f =~ /%time1b$/) { # [dd/mmm/yyyy:hh:mm:ss +0000] or [dd/mmm/yyyy:hh:mm:ss], time1b kept for backward compatibility + $pos_date = $i; $i++; push @fieldlib, 'date'; + $pos_tz = $i; $i++; push @fieldlib, 'tz'; + $PerlParsingFormat .= "\\[([^$LogSeparatorWithoutStar]+)( [^$LogSeparatorWithoutStar]+)?\\]"; + } + elsif ($f =~ /%time2$/) { # yyyy-mm-dd hh:mm:ss + $pos_date = $i; $i++; push @fieldlib, 'date'; + $PerlParsingFormat .= "([^$LogSeparatorWithoutStar]+\\s[^$LogSeparatorWithoutStar]+)"; # Need \s for Exchange log files + } + elsif ($f =~ /%time3$/) { # mon d hh:mm:ss or mon d hh:mm:ss or mon dd hh:mm:ss yyyy or day mon dd hh:mm:ss or day mon dd hh:mm:ss yyyy + $pos_date = $i; $i++; push @fieldlib, 'date'; + $PerlParsingFormat .= "(?:\\w\\w\\w )?(\\w\\w\\w \\s?\\d+ \\d\\d:\\d\\d:\\d\\d(?: \\d\\d\\d\\d)?)"; + } + elsif ($f =~ /%time4$/) { # ddddddddddddd + $pos_date = $i; $i++; push @fieldlib, 'date'; + $PerlParsingFormat .= "(\\d+)"; + } + # Special for methodurl and methodurlnoprot + elsif ($f =~ /%methodurl$/) { + $pos_method = $i; $i++; push @fieldlib, 'method'; + $pos_url = $i; $i++; push @fieldlib, 'url'; + $PerlParsingFormat .= "\\\"([^$LogSeparatorWithoutStar]+) ([^$LogSeparatorWithoutStar]+) [^\\\"]+\\\""; + } + elsif ($f =~ /%methodurlnoprot$/) { + $pos_method = $i; $i++; push @fieldlib, 'method'; + $pos_url = $i; $i++; push @fieldlib, 'url'; + $PerlParsingFormat .= "\\\"([^$LogSeparatorWithoutStar]+) ([^$LogSeparatorWithoutStar]+)\\\""; + } + # Common command tags + elsif ($f =~ /%virtualnamequot$/) { + $pos_vh = $i; $i++; push @fieldlib, 'vhost'; + $PerlParsingFormat .= "\\\"([^$LogSeparatorWithoutStar]+)\\\""; + } + elsif ($f =~ /%virtualname$/) { + $pos_vh = $i; $i++; push @fieldlib, 'vhost'; + $PerlParsingFormat .= "([^$LogSeparatorWithoutStar]+)"; + } + elsif ($f =~ /%host_r$/) { + $pos_hostr = $i; $i++; push @fieldlib, 'hostr'; + $PerlParsingFormat .= "([^$LogSeparatorWithoutStar]+)"; + } + elsif ($f =~ /%host$/) { + $pos_host = $i; $i++; push @fieldlib, 'host'; + $PerlParsingFormat .= "([^$LogSeparatorWithoutStar]+)"; + } + elsif ($f =~ /%logname$/) { + $pos_logname = $i; $i++; push @fieldlib, 'logname'; + $PerlParsingFormat .= "([^$LogSeparatorWithoutStar]+)"; + } + elsif ($f =~ /%method$/) { + $pos_method = $i; $i++; push @fieldlib, 'method'; + $PerlParsingFormat .= "([^$LogSeparatorWithoutStar]+)"; + } + elsif ($f =~ /%url$/) { + $pos_url = $i; $i++; push @fieldlib, 'url'; + $PerlParsingFormat .= "([^$LogSeparatorWithoutStar]+)"; + } + elsif ($f =~ /%query$/) { + $pos_query = $i; $i++; push @fieldlib, 'query'; + $PerlParsingFormat .= "([^$LogSeparatorWithoutStar]+)"; + } + elsif ($f =~ /%code$/) { + $pos_code = $i; $i++; push @fieldlib, 'code'; + $PerlParsingFormat .= "([^$LogSeparatorWithoutStar]+)"; + } + elsif ($f =~ /%bytesd$/) { + $pos_size = $i; $i++; push @fieldlib, 'size'; + $PerlParsingFormat .= "([^$LogSeparatorWithoutStar]+)"; + } + elsif ($f =~ /%refererquot$/) { + $pos_referer = $i; $i++; push @fieldlib, 'referer'; + $PerlParsingFormat .= "\\\"([^\\\"]*)\\\""; # referer might be "" + } + elsif ($f =~ /%referer$/) { + $pos_referer = $i; $i++; push @fieldlib, 'referer'; + $PerlParsingFormat .= "([^$LogSeparatorWithoutStar]+)"; + } + elsif ($f =~ /%uaquot$/) { + $pos_agent = $i; $i++; push @fieldlib, 'ua'; + $PerlParsingFormat .= "\\\"([^\\\"]*)\\\""; # ua might be "" + } + elsif ($f =~ /%uabracket$/) { + $pos_agent = $i; $i++; push @fieldlib, 'ua'; + $PerlParsingFormat .= "\\\[([^\\\]]*)\\\]"; # ua might be [] + } + elsif ($f =~ /%ua$/) { + $pos_agent = $i; $i++; push @fieldlib, 'ua'; + $PerlParsingFormat .= "([^$LogSeparatorWithoutStar]+)"; + } + elsif ($f =~ /%gzipin$/ ) { + $pos_gzipin=$i;$i++; push @fieldlib, 'gzipin'; + $PerlParsingFormat .= "([^$LogSeparatorWithoutStar]+)"; + } + elsif ($f =~ /%gzipout/ ) { # Compare $f to /%gzipout/ and not to /%gzipout$/ like other fields + $pos_gzipout=$i;$i++; push @fieldlib, 'gzipout'; + $PerlParsingFormat .= "([^$LogSeparatorWithoutStar]+)"; + } + elsif ($f =~ /%gzipratio/ ) { # Compare $f to /%gzipratio/ and not to /%gzipratio$/ like other fields + $pos_compratio=$i;$i++; push @fieldlib, 'gzipratio'; + $PerlParsingFormat .= "([^$LogSeparatorWithoutStar]+)"; + } + elsif ($f =~ /%deflateratio/ ) { # Compare $f to /%deflateratio/ and not to /%deflateratio$/ like other fields + $pos_compratio=$i;$i++; push @fieldlib, 'deflateratio'; + $PerlParsingFormat .= "([^$LogSeparatorWithoutStar]+)"; + } + elsif ($f =~ /%email_r$/) { + $pos_emailr = $i; $i++; push @fieldlib, 'email_r'; + $PerlParsingFormat .= "([^$LogSeparatorWithoutStar]+)"; + } + elsif ($f =~ /%email$/) { + $pos_emails = $i; $i++; push @fieldlib, 'email'; + $PerlParsingFormat .= "([^$LogSeparatorWithoutStar]+)"; + } + elsif ($f =~ /%cluster$/) { + $pos_cluster = $i; $i++; push @fieldlib, 'clusternb'; + $PerlParsingFormat .= "([^$LogSeparatorWithoutStar]+)"; + } + elsif ($f =~ /%timetaken$/) { + $pos_timetaken = $i; $i++; push @fieldlib, 'timetaken'; + $PerlParsingFormat .= "([^$LogSeparatorWithoutStar]+)"; + } + # Special for protocolmms, used for method if method not already found (for MMS) + elsif ($f =~ /%protocolmms$/) { + if ($pos_method < 0) { + $pos_method = $i; $i++; push @fieldlib, 'method'; + $PerlParsingFormat .= "([^$LogSeparatorWithoutStar]+)"; + } + } + # Special for codemms, used for code only if code not already found (for MMS) + elsif ($f =~ /%codemms$/) { + if ($pos_code < 0) { + $pos_code = $i; $i++; push @fieldlib, 'code'; + $PerlParsingFormat .= "([^$LogSeparatorWithoutStar]+)"; + } + } + # Extra tag + elsif ($f =~ /%extra(\d+)$/) { + $pos_extra[$1] = $i; $i++; push @fieldlib, "extra$1"; + $PerlParsingFormat .= "([^$LogSeparatorWithoutStar]+)"; + } + # Other tag + elsif ($f =~ /%other$/) { + $PerlParsingFormat .= "[^$LogSeparatorWithoutStar]+"; + } + elsif ($f =~ /%otherquot$/) { + $PerlParsingFormat .= "\\\"[^\\\"]*\\\""; + } + # Unknown tag (no parenthesis) + else { + $PerlParsingFormat .= "[^$LogSeparatorWithoutStar]+"; + } + } + if (! $PerlParsingFormat) { error("No recognized format tag in personalized LogFormat string"); } + } + if ($pos_host < 0) { error("Your personalized LogFormat does not include all fields required by AWStats (Add \%host in your LogFormat string)."); } + if ($pos_date < 0) { error("Your personalized LogFormat does not include all fields required by AWStats (Add \%time1 or \%time2 in your LogFormat string)."); } + if ($pos_method < 0) { error("Your personalized LogFormat does not include all fields required by AWStats (Add \%methodurl or \%method in your LogFormat string)."); } + if ($pos_url < 0) { error("Your personalized LogFormat does not include all fields required by AWStats (Add \%methodurl or \%url in your LogFormat string)."); } + if ($pos_code < 0) { error("Your personalized LogFormat does not include all fields required by AWStats (Add \%code in your LogFormat string)."); } + if ($pos_size < 0) { error("Your personalized LogFormat does not include all fields required by AWStats (Add \%bytesd in your LogFormat string)."); } + $PerlParsingFormat=qr/^$PerlParsingFormat/; + if ($Debug) { debug(" PerlParsingFormat is $PerlParsingFormat"); } +} + + +sub ShowMenuCateg { + my ($categ,$categtext,$categicon,$frame,$targetpage,$linkanchor,$NewLinkParams,$NewLinkTarget)=(shift,shift,shift,shift,shift,shift,shift,shift); + $categicon=''; # Comment this to enabme category icons + my ($menu,$menulink,$menutext)=(shift,shift,shift); + my $linetitle=0; + # Call to plugins' function AddHTMLMenuLink + foreach my $pluginname (keys %{$PluginsLoaded{'AddHTMLMenuLink'}}) { +# my $function="AddHTMLMenuLink_$pluginname('$categ',\$menu,\$menulink,\$menutext)"; +# eval("$function"); + my $function="AddHTMLMenuLink_$pluginname"; + &$function($categ,$menu,$menulink,$menutext); + } + foreach my $key (%$menu) { if ($menu->{$key} && $menu->{$key} > 0) { $linetitle++; last; } } + if (! $linetitle) { return; } + # At least one entry in menu for this category, we can show categpry and entries + my $WIDTHMENU1=($FrameName eq 'mainleft'?$FRAMEWIDTH:150); + print "".($categicon?" ":"")."$categtext:\n"; + print ($frame?"\n":""); + foreach my $key (sort { $menu->{$a} <=> $menu->{$b} } keys %$menu) { + if ($menu->{$key}==0) { next; } + if ($menulink->{$key}==1) { print ($frame?"":""); print "$menutext->{$key}"; print ($frame?"\n":"   "); } + if ($menulink->{$key}==2) { print ($frame?"   \"...\" ":""); print "$menutext->{$key}\n"; print ($frame?"\n":"   "); } + } + print ($frame?"":"\n"); +} + + +sub ShowEmailSendersChart { + my $NewLinkParams=shift; + my $NewLinkTarget=shift; + my $MaxLengthOfShownEMail=48; + + my $total_p;my $total_h;my $total_k; + my $max_p;my $max_h;my $max_k; + my $rest_p;my $rest_h;my $rest_k; + + # Show filter form + #&ShowFormFilter("emailsfilter",$EmailsFilter); + # Show emails list + + print "$Center 
\n"; + my $title; + if ($HTMLOutput{'allemails'} || $HTMLOutput{'lastemails'}) { + $title="$Message[131]"; + } + else { + $title="$Message[131] ($Message[77] $MaxNbOf{'EMailsShown'})   -   $Message[80]"; + if ($ShowEMailSenders =~ /L/i) { $title.="   -   $Message[9]"; } + } + &tab_head("$title",19,0,'emailsenders'); + print "$Message[131] : ".(scalar keys %_emails_h).""; + if ($ShowEMailSenders =~ /H/i) { print "$Message[57]"; } + if ($ShowEMailSenders =~ /B/i) { print "$Message[75]"; } + if ($ShowEMailSenders =~ /M/i) { print "$Message[106]"; } + if ($ShowEMailSenders =~ /L/i) { print "$Message[9]"; } + print "\n"; + print "Local External"; + $total_p=$total_h=$total_k=0; + $max_h=1; foreach (values %_emails_h) { if ($_ > $max_h) { $max_h = $_; } } + $max_k=1; foreach (values %_emails_k) { if ($_ > $max_k) { $max_k = $_; } } + my $count=0; + if (! $HTMLOutput{'allemails'} && ! $HTMLOutput{'lastemails'}) { &BuildKeyList($MaxNbOf{'EMailsShown'},$MinHit{'EMail'},\%_emails_h,\%_emails_h); } + if ($HTMLOutput{'allemails'}) { &BuildKeyList($MaxRowsInHTMLOutput,$MinHit{'EMail'},\%_emails_h,\%_emails_h); } + if ($HTMLOutput{'lastemails'}) { &BuildKeyList($MaxRowsInHTMLOutput,$MinHit{'EMail'},\%_emails_h,\%_emails_l); } + foreach my $key (@keylist) { + my $newkey=$key; + if (length($key)>$MaxLengthOfShownEMail) { $newkey=substr($key,0,$MaxLengthOfShownEMail)."..."; } + my $bredde_h=0;my $bredde_k=0; + if ($max_h > 0) { $bredde_h=int($BarWidth*$_emails_h{$key}/$max_h)+1; } + if ($max_k > 0) { $bredde_k=int($BarWidth*$_emails_k{$key}/$max_k)+1; } + print ""; + my $direction=IsLocalEMail($key); + if ($direction > 0) { print "$newkey-> "; } + if ($direction == 0) { print "$newkey"; } + if ($direction < 0) { print " <-$newkey"; } + if ($ShowEMailSenders =~ /H/i) { print "$_emails_h{$key}"; } + if ($ShowEMailSenders =~ /B/i) { print "".Format_Bytes($_emails_k{$key}).""; } + if ($ShowEMailSenders =~ /M/i) { print "".Format_Bytes($_emails_k{$key}/($_emails_h{$key}||1)).""; } + if ($ShowEMailSenders =~ /L/i) { print "".($_emails_l{$key}?Format_Date($_emails_l{$key},1):'-').""; } + print "\n"; + #$total_p += $_emails_p{$key}; + $total_h += $_emails_h{$key}; + $total_k += $_emails_k{$key}; + $count++; + } + $rest_p=0; # $rest_p=$TotalPages-$total_p; + $rest_h=$TotalHits-$total_h; + $rest_k=$TotalBytes-$total_k; + if ($rest_p > 0 || $rest_h > 0 || $rest_k > 0) { # All other sender emails + print "$Message[2]"; + if ($ShowEMailSenders =~ /H/i) { print "$rest_h"; } + if ($ShowEMailSenders =~ /B/i) { print "".Format_Bytes($rest_k).""; } + if ($ShowEMailSenders =~ /M/i) { print "".Format_Bytes($rest_k/($rest_h||1)).""; } + if ($ShowEMailSenders =~ /L/i) { print " "; } + print "\n"; + } + &tab_end(); +} + + +sub ShowEmailReceiversChart { + my $NewLinkParams=shift; + my $NewLinkTarget=shift; + my $MaxLengthOfShownEMail=48; + + my $total_p;my $total_h;my $total_k; + my $max_p;my $max_h;my $max_k; + my $rest_p;my $rest_h;my $rest_k; + + # Show filter form + #&ShowFormFilter("emailrfilter",$EmailrFilter); + # Show emails list + + print "$Center 
\n"; + my $title; + if ($HTMLOutput{'allemailr'} || $HTMLOutput{'lastemailr'}) { + $title="$Message[132]"; + } + else { + $title="$Message[132] ($Message[77] $MaxNbOf{'EMailsShown'})   -   $Message[80]"; + if ($ShowEMailReceivers =~ /L/i) { $title.="   -   $Message[9]"; } + } + &tab_head("$title",19,0,'emailreceivers'); + print "$Message[132] : ".(scalar keys %_emailr_h).""; + if ($ShowEMailReceivers =~ /H/i) { print "$Message[57]"; } + if ($ShowEMailReceivers =~ /B/i) { print "$Message[75]"; } + if ($ShowEMailReceivers =~ /M/i) { print "$Message[106]"; } + if ($ShowEMailReceivers =~ /L/i) { print "$Message[9]"; } + print "\n"; + print "Local External"; + $total_p=$total_h=$total_k=0; + $max_h=1; foreach (values %_emailr_h) { if ($_ > $max_h) { $max_h = $_; } } + $max_k=1; foreach (values %_emailr_k) { if ($_ > $max_k) { $max_k = $_; } } + my $count=0; + if (! $HTMLOutput{'allemailr'} && ! $HTMLOutput{'lastemailr'}) { &BuildKeyList($MaxNbOf{'EMailsShown'},$MinHit{'EMail'},\%_emailr_h,\%_emailr_h); } + if ($HTMLOutput{'allemailr'}) { &BuildKeyList($MaxRowsInHTMLOutput,$MinHit{'EMail'},\%_emailr_h,\%_emailr_h); } + if ($HTMLOutput{'lastemailr'}) { &BuildKeyList($MaxRowsInHTMLOutput,$MinHit{'EMail'},\%_emailr_h,\%_emailr_l); } + foreach my $key (@keylist) { + my $newkey=$key; + if (length($key)>$MaxLengthOfShownEMail) { $newkey=substr($key,0,$MaxLengthOfShownEMail)."..."; } + my $bredde_h=0;my $bredde_k=0; + if ($max_h > 0) { $bredde_h=int($BarWidth*$_emailr_h{$key}/$max_h)+1; } + if ($max_k > 0) { $bredde_k=int($BarWidth*$_emailr_k{$key}/$max_k)+1; } + print ""; + my $direction=IsLocalEMail($key); + if ($direction > 0) { print "$newkey<- "; } + if ($direction == 0) { print "$newkey"; } + if ($direction < 0) { print " ->$newkey"; } + if ($ShowEMailReceivers =~ /H/i) { print "$_emailr_h{$key}"; } + if ($ShowEMailReceivers =~ /B/i) { print "".Format_Bytes($_emailr_k{$key}).""; } + if ($ShowEMailReceivers =~ /M/i) { print "".Format_Bytes($_emailr_k{$key}/($_emailr_h{$key}||1)).""; } + if ($ShowEMailReceivers =~ /L/i) { print "".($_emailr_l{$key}?Format_Date($_emailr_l{$key},1):'-').""; } + print "\n"; + #$total_p += $_emailr_p{$key}; + $total_h += $_emailr_h{$key}; + $total_k += $_emailr_k{$key}; + $count++; + } + $rest_p=0; # $rest_p=$TotalPages-$total_p; + $rest_h=$TotalHits-$total_h; + $rest_k=$TotalBytes-$total_k; + if ($rest_p > 0 || $rest_h > 0 || $rest_k > 0) { # All other receiver emails + print "$Message[2]"; + if ($ShowEMailReceivers =~ /H/i) { print "$rest_h"; } + if ($ShowEMailReceivers =~ /B/i) { print "".Format_Bytes($rest_k).""; } + if ($ShowEMailReceivers =~ /M/i) { print "".Format_Bytes($rest_k/($rest_h||1)).""; } + if ($ShowEMailReceivers =~ /L/i) { print " "; } + print "\n"; + } + &tab_end(); +} + + + +#------------------------------------------------------------------------------ +# MAIN +#------------------------------------------------------------------------------ +($DIR=$0) =~ s/([^\/\\]+)$//; ($PROG=$1) =~ s/\.([^\.]*)$//; $Extension=$1; +$DIR||='.'; $DIR =~ s/([^\/\\])[\\\/]+$/$1/; + +$starttime=time(); + +# Get current time (time when AWStats was started) +($nowsec,$nowmin,$nowhour,$nowday,$nowmonth,$nowyear,$nowwday,$nowyday) = localtime($starttime); +$nowweekofmonth=int($nowday/7); +$nowweekofyear=int(($nowyday-1+6-($nowwday==0?6:$nowwday-1))/7)+1; if ($nowweekofyear > 52) { $nowweekofyear = 1; } +$nowdaymod=$nowday%7; +$nowwday++; +$nowns=Time::Local::timegm(0,0,0,$nowday,$nowmonth,$nowyear); +if ($nowdaymod <= $nowwday) { if (($nowwday != 7) || ($nowdaymod != 0)) { $nowweekofmonth=$nowweekofmonth+1; } } +if ($nowdaymod > $nowwday) { $nowweekofmonth=$nowweekofmonth+2; } +# Change format of time variables +$nowweekofmonth="0$nowweekofmonth"; +if ($nowweekofyear < 10) { $nowweekofyear = "0$nowweekofyear"; } +if ($nowyear < 100) { $nowyear+=2000; } else { $nowyear+=1900; } +$nowsmallyear=$nowyear;$nowsmallyear =~ s/^..//; +if (++$nowmonth < 10) { $nowmonth = "0$nowmonth"; } +if ($nowday < 10) { $nowday = "0$nowday"; } +if ($nowhour < 10) { $nowhour = "0$nowhour"; } +if ($nowmin < 10) { $nowmin = "0$nowmin"; } +if ($nowsec < 10) { $nowsec = "0$nowsec"; } +$nowtime=int($nowyear.$nowmonth.$nowday.$nowhour.$nowmin.$nowsec); +# Get tomorrow time (will be used to discard some record with corrupted date (future date)) +my ($tomorrowsec,$tomorrowmin,$tomorrowhour,$tomorrowday,$tomorrowmonth,$tomorrowyear) = localtime($starttime+86400); +if ($tomorrowyear < 100) { $tomorrowyear+=2000; } else { $tomorrowyear+=1900; } +if (++$tomorrowmonth < 10) { $tomorrowmonth = "0$tomorrowmonth"; } +if ($tomorrowday < 10) { $tomorrowday = "0$tomorrowday"; } +if ($tomorrowhour < 10) { $tomorrowhour = "0$tomorrowhour"; } +if ($tomorrowmin < 10) { $tomorrowmin = "0$tomorrowmin"; } +if ($tomorrowsec < 10) { $tomorrowsec = "0$tomorrowsec"; } +$tomorrowtime=int($tomorrowyear.$tomorrowmonth.$tomorrowday.$tomorrowhour.$tomorrowmin.$tomorrowsec); + +# Allowed option +my @AllowedCLIArgs=('migrate','config', +'logfile','output','runascli','update', +'staticlinks','staticlinksext','noloadplugin','loadplugin', +'hostfilter','urlfilter','refererpagesfilter', +'lang','month','year','framename','debug', +'showsteps','showdropped','showcorrupted','showunknownorigin', +'limitflush','confdir','updatefor', +'hostfilter','hostfilterex','urlfilter','urlfilterex','refererpagesfilter','refererpagesfilterex', +'pluginmode','filterrawlog'); + +# Parse input parameters and sanitize them for security reasons +$QueryString=''; +# AWStats use GATEWAY_INTERFACE to known if ran as CLI or CGI. AWSTATS_DEL_GATEWAY_INTERFACE can +# be set to force AWStats to be ran as CLI even from a web page. +if ($ENV{'AWSTATS_DEL_GATEWAY_INTERFACE'}) { $ENV{'GATEWAY_INTERFACE'}=''; } +if ($ENV{'GATEWAY_INTERFACE'}) { # Run from a browser as CGI + $DebugMessages=0; + # Prepare QueryString + if ($ENV{'CONTENT_LENGTH'}) { + binmode STDIN; + read(STDIN, $QueryString, $ENV{'CONTENT_LENGTH'}); + } + if ($ENV{'QUERY_STRING'}) { + $QueryString = $ENV{'QUERY_STRING'}; + # Set & and & to & + $QueryString =~ s/&/&/g; + $QueryString =~ s/&/&/g; + } + + # Remove all XSS vulnerabilities coming from AWStats parameters + $QueryString = CleanXSS(&DecodeEncodedString($QueryString)); + + # Security test + if ($QueryString =~ /LogFile=([^&]+)/i) { error("Logfile parameter can't be overwritten when AWStats is used from a CGI"); } + + # No update but report by default when run from a browser + $UpdateStats=($QueryString=~/update=1/i?1:0); + + if ($QueryString =~ /config=([^&]+)/i) { $SiteConfig=&Sanitize("$1"); } + if ($QueryString =~ /diricons=([^&]+)/i) { $DirIcons="$1"; } + if ($QueryString =~ /pluginmode=([^&]+)/i) { $PluginMode=&Sanitize("$1",1); } + if ($QueryString =~ /configdir=([^&]+)/i) { $DirConfig=&Sanitize("$1"); } + # All filters + if ($QueryString =~ /hostfilter=([^&]+)/i) { $FilterIn{'host'}="$1"; } # Filter on host list can also be defined with hostfilter=filter + if ($QueryString =~ /hostfilterex=([^&]+)/i) { $FilterEx{'host'}="$1"; } # + if ($QueryString =~ /urlfilter=([^&]+)/i) { $FilterIn{'url'}="$1"; } # Filter on URL list can also be defined with urlfilter=filter + if ($QueryString =~ /urlfilterex=([^&]+)/i) { $FilterEx{'url'}="$1"; } # + if ($QueryString =~ /refererpagesfilter=([^&]+)/i) { $FilterIn{'refererpages'}="$1"; } # Filter on referer list can also be defined with refererpagesfilter=filter + if ($QueryString =~ /refererpagesfilterex=([^&]+)/i) { $FilterEx{'refererpages'}="$1"; } # + # All output + if ($QueryString =~ /output=allhosts:([^&]+)/i) { $FilterIn{'host'}="$1"; } # Filter on host list can be defined with output=allhosts:filter to reduce number of lines read and showed + if ($QueryString =~ /output=lasthosts:([^&]+)/i) { $FilterIn{'host'}="$1"; } # Filter on host list can be defined with output=lasthosts:filter to reduce number of lines read and showed + if ($QueryString =~ /output=urldetail:([^&]+)/i) { $FilterIn{'url'}="$1"; } # Filter on URL list can be defined with output=urldetail:filter to reduce number of lines read and showed + if ($QueryString =~ /output=refererpages:([^&]+)/i) { $FilterIn{'refererpages'}="$1"; } # Filter on referer list can be defined with output=refererpages:filter to reduce number of lines read and showed + + # If migrate + if ($QueryString =~ /(^|-|&|&)migrate=([^&]+)/i) { + $MigrateStats=&Sanitize("$2"); + $MigrateStats =~ /^(.*)$PROG(\d{0,2})(\d\d)(\d\d\d\d)(.*)\.txt$/; + $SiteConfig=$5?$5:'xxx'; $SiteConfig =~ s/^\.//; # SiteConfig is used to find config file + } +} +else { # Run from command line + $DebugMessages=1; + # Prepare QueryString + for (0..@ARGV-1) { + # If migrate + if ($ARGV[$_] =~ /(^|-|&|&)migrate=([^&]+)/i) { + $MigrateStats="$2"; + $MigrateStats =~ /^(.*)$PROG(\d{0,2})(\d\d)(\d\d\d\d)(.*)\.txt$/; + $SiteConfig=$5?$5:'xxx'; $SiteConfig =~ s/^\.//; # SiteConfig is used to find config file + next; + } + # TODO Check if ARGV is in @AllowedArg + if ($QueryString) { $QueryString .= '&'; } + my $NewLinkParams=$ARGV[$_]; $NewLinkParams =~ s/^-+//; + $QueryString .= "$NewLinkParams"; + } + + # Remove all XSS vulnerabilities coming from AWStats parameters + $QueryString = CleanXSS($QueryString); + + # Security test + if ($ENV{'AWSTATS_DEL_GATEWAY_INTERFACE'} && $QueryString =~ /LogFile=([^&]+)/i) { error("Logfile parameter can't be overwritten when AWStats is used from a CGI"); } + + # Update with no report by default when run from command line + $UpdateStats=1; + + if ($QueryString =~ /config=([^&]+)/i) { $SiteConfig=&Sanitize("$1"); } + if ($QueryString =~ /diricons=([^&]+)/i) { $DirIcons="$1"; } + if ($QueryString =~ /pluginmode=([^&]+)/i) { $PluginMode=&Sanitize("$1",1); } + if ($QueryString =~ /configdir=([^&]+)/i) { $DirConfig=&Sanitize("$1"); } + # All filters + if ($QueryString =~ /hostfilter=([^&]+)/i) { $FilterIn{'host'}="$1"; } # Filter on host list can also be defined with hostfilter=filter + if ($QueryString =~ /hostfilterex=([^&]+)/i) { $FilterEx{'host'}="$1"; } # + if ($QueryString =~ /urlfilter=([^&]+)/i) { $FilterIn{'url'}="$1"; } # Filter on URL list can also be defined with urlfilter=filter + if ($QueryString =~ /urlfilterex=([^&]+)/i) { $FilterEx{'url'}="$1"; } # + if ($QueryString =~ /refererpagesfilter=([^&]+)/i) { $FilterIn{'refererpages'}="$1"; } # Filter on referer list can also be defined with refererpagesfilter=filter + if ($QueryString =~ /refererpagesfilterex=([^&]+)/i) { $FilterEx{'refererpages'}="$1"; } # + # All output + if ($QueryString =~ /output=allhosts:([^&]+)/i) { $FilterIn{'host'}="$1"; } # Filter on host list can be defined with output=allhosts:filter to reduce number of lines read and showed + if ($QueryString =~ /output=lasthosts:([^&]+)/i) { $FilterIn{'host'}="$1"; } # Filter on host list can be defined with output=lasthosts:filter to reduce number of lines read and showed + if ($QueryString =~ /output=urldetail:([^&]+)/i) { $FilterIn{'url'}="$1"; } # Filter on URL list can be defined with output=urldetail:filter to reduce number of lines read and showed + if ($QueryString =~ /output=refererpages:([^&]+)/i) { $FilterIn{'refererpages'}="$1"; } # Filter on referer list can be defined with output=refererpages:filter to reduce number of lines read and showed + # Config parameters + if ($QueryString =~ /LogFile=([^&]+)/i) { $LogFile="$1"; } + + # If show options + if ($QueryString =~ /showsteps/i) { $ShowSteps=1; $QueryString=~s/showsteps[^&]*//i; } + if ($QueryString =~ /showcorrupted/i) { $ShowCorrupted=1; $QueryString=~s/showcorrupted[^&]*//i; } + if ($QueryString =~ /showdropped/i) { $ShowDropped=1; $QueryString=~s/showdropped[^&]*//i; } + if ($QueryString =~ /showunknownorigin/i) { $ShowUnknownOrigin=1; $QueryString=~s/showunknownorigin[^&]*//i; } + +} +if ($QueryString =~ /(^|&|&)staticlinks/i) { $StaticLinks=".$SiteConfig"; } +if ($QueryString =~ /(^|&|&)staticlinks=([^&]+)/i) { $StaticLinks=".$2"; } # When ran from awstatsbuildstaticpages.pl +if ($QueryString =~ /(^|&|&)staticlinksext=([^&]+)/i) { $StaticExt="$2"; } +if ($QueryString =~ /(^|&|&)framename=([^&]+)/i) { $FrameName="$2"; } +if ($QueryString =~ /(^|&|&)debug=(\d+)/i) { $Debug=$2; } +if ($QueryString =~ /(^|&|&)databasebreak=(\w+)/i) { $DatabaseBreak=$2; } +if ($QueryString =~ /(^|&|&)updatefor=(\d+)/i) { $UpdateFor=$2; } +if ($QueryString =~ /(^|&|&)noloadplugin=([^&]+)/i) { foreach (split(/,/,$2)) { $NoLoadPlugin{&Sanitize("$_",1)}=1; } } +if ($QueryString =~ /(^|&|&)limitflush=(\d+)/i) { $LIMITFLUSH=$2; } +# Get/Define output +if ($QueryString =~ /(^|&|&)output(=[^&]*|)(.*)(&|&)output(=[^&]*|)(&|$)/i) { error("Only 1 output option is allowed","","",1); } +if ($QueryString =~ /(^|&|&)output(=[^&]*|)(&|$)/i) { + # At least one output expected. We define %HTMLOutput + my $outputlist="$2"; + if ($outputlist) { + $outputlist =~ s/^=//; + foreach my $outputparam (split(/,/,$outputlist)) { + $outputparam=~s/:(.*)$//; + if ($outputparam) { $HTMLOutput{lc($outputparam)}="$1"||1; } + } + } + # If on command line and no update + if (! $ENV{'GATEWAY_INTERFACE'} && $QueryString !~ /update/i) { $UpdateStats=0; } + # If no output defined, used default value + if (! scalar keys %HTMLOutput) { $HTMLOutput{'main'}=1; } +} +if ($ENV{'GATEWAY_INTERFACE'} && ! scalar keys %HTMLOutput) { $HTMLOutput{'main'}=1; } + +# Remove -output option with no = from QueryString +$QueryString=~s/(^|&|&)output(&|$)/$1/i; $QueryString=~s/&+$//; + +# Check year, month, day, hour parameters +if ($QueryString =~ /(^|&|&)month=(year)/i) { error("month=year is a deprecated option. Use month=all instead."); } +if ($QueryString =~ /(^|&|&)year=(\d\d\d\d)/i) { $YearRequired=sprintf("%04d",$2); } +else { $YearRequired="$nowyear"; } +if ($QueryString =~ /(^|&|&)month=(\d{1,2})/i) { $MonthRequired=sprintf("%02d",$2); } +elsif ($QueryString =~ /(^|&|&)month=(all)/i) { $MonthRequired='all'; } +else { $MonthRequired="$nowmonth"; } +if ($QueryString =~ /(^|&|&)day=(\d{1,2})/i) { $DayRequired=sprintf("%02d",$2); } # day is a hidden option. Must not be used (Make results not understandable). Available for users that rename history files with day. +else { $DayRequired=''; } +if ($QueryString =~ /(^|&|&)hour=(\d{1,2})/i) { $HourRequired=sprintf("%02d",$2); } # hour is a hidden option. Must not be used (Make results not understandable). Available for users that rename history files with day. +else { $HourRequired=''; } + +# Check parameter validity +# TODO + +# Print AWStats and Perl version +if ($Debug) { + debug(ucfirst($PROG)." - $VERSION - Perl $^X $]",1); + debug("DIR=$DIR PROG=$PROG Extension=$Extension",2); + debug("QUERY_STRING=$QueryString",2); + debug("HTMLOutput=".join(',',keys %HTMLOutput),1); + debug("YearRequired=$YearRequired, MonthRequired=$MonthRequired",2); + debug("DayRequired=$DayRequired, HourRequired=$HourRequired",2); + debug("UpdateFor=$UpdateFor",2); + debug("PluginMode=$PluginMode",2); + debug("DirConfig=$DirConfig",2); +} + +# Force SiteConfig if AWSTATS_FORCE_CONFIG is defined +if ($ENV{'AWSTATS_CONFIG'}) { $ENV{'AWSTATS_FORCE_CONFIG'}=$ENV{'AWSTATS_CONFIG'}; } # For backward compatibility +if ($ENV{'AWSTATS_FORCE_CONFIG'}) { + if ($Debug) { debug("AWSTATS_FORCE_CONFIG parameter is defined to '".$ENV{'AWSTATS_FORCE_CONFIG'}."'. $PROG will use this as config value."); } + $SiteConfig=&Sanitize($ENV{'AWSTATS_FORCE_CONFIG'}); +} + +if ((! $ENV{'GATEWAY_INTERFACE'}) && (! $SiteConfig)) { + &Read_Ref_Data('browsers','domains','operating_systems','robots','search_engines','worms'); + print "----- $PROG $VERSION (c) 2000-2007 Laurent Destailleur -----\n"; + print "AWStats is a free web server logfile analyzer to show you advanced web\n"; + print "statistics.\n"; + print "AWStats comes with ABSOLUTELY NO WARRANTY. It's a free software distributed\n"; + print "with a GNU General Public License (See LICENSE file for details).\n"; + print "\n"; + print "Syntax: $PROG.$Extension -config=virtualhostname [options]\n"; + print "\n"; + print " This runs $PROG in command line to update statistics of a web site, from\n"; + print " the log file defined in AWStats config file (with -update option), or build\n"; + print " a HTML report (with -output option).\n"; + print " First, $PROG tries to read $PROG.virtualhostname.conf as the config file.\n"; + print " If not found, $PROG tries to read $PROG.conf\n"; + print " Note 1: Config files ($PROG.virtualhostname.conf or $PROG.conf) must be\n"; + print " in /etc/awstats, /usr/local/etc/awstats, /etc or same directory than\n"; + print " awstats.pl script file.\n"; + print " Note 2: If AWSTATS_FORCE_CONFIG environment variable is defined, AWStats will\n"; + print " use it as the \"config\" value, whatever is the value on command line or URL.\n"; + print " See AWStats documentation for all setup instrutions.\n"; + print "\n"; + print "Options to update statistics:\n"; + print " -update to update statistics (default)\n"; + print " -showsteps to add benchmark information every $NBOFLINESFORBENCHMARK lines processed\n"; + print " -showcorrupted to add output for each corrupted lines found, with reason\n"; + print " -showdropped to add output for each dropped lines found, with reason\n"; + print " -updatefor=n to stop the update process after parsing n lines\n"; + print " -LogFile=x to change log to analyze whatever is 'LogFile' in config file\n"; + print " Be care to process log files in chronological order when updating statistics.\n"; + print "\n"; + print "Options to show statistics:\n"; + print " -output to output main HTML report (no update made except with -update)\n"; + print " -output=x to output other report pages where x is:\n"; + print " alldomains to build page of all domains/countries\n"; + print " allhosts to build page of all hosts\n"; + print " lasthosts to build page of last hits for hosts\n"; + print " unknownip to build page of all unresolved IP\n"; + print " allemails to build page of all email senders (maillog)\n"; + print " lastemails to build page of last email senders (maillog)\n"; + print " allemailr to build page of all email receivers (maillog)\n"; + print " lastemailr to build page of last email receivers (maillog)\n"; + print " alllogins to build page of all logins used\n"; + print " lastlogins to build page of last hits for logins\n"; + print " allrobots to build page of all robots/spider visits\n"; + print " lastrobots to build page of last hits for robots\n"; + print " urldetail to list most often viewed pages \n"; + print " urldetail:filter to list most often viewed pages matching filter\n"; + print " urlentry to list entry pages\n"; + print " urlentry:filter to list entry pages matching filter\n"; + print " urlexit to list exit pages\n"; + print " urlexit:filter to list exit pages matching filter\n"; + print " osdetail to build page with os detailed versions\n"; + print " browserdetail to build page with browsers detailed versions\n"; + print " unknownbrowser to list 'User Agents' with unknown browser\n"; + print " unknownos to list 'User Agents' with unknown OS\n"; + print " refererse to build page of all refering search engines\n"; + print " refererpages to build page of all refering pages\n"; + #print " referersites to build page of all refering sites\n"; + print " keyphrases to list all keyphrases used on search engines\n"; + print " keywords to list all keywords used on search engines\n"; + print " errors404 to list 'Referers' for 404 errors\n"; + print " -staticlinks to have static links in HTML report page\n"; + print " -staticlinksext=xxx to have static links with .xxx extension instead of .html\n"; + print " -lang=LL to output a HTML report in language LL (en,de,es,fr,it,nl,...)\n"; + print " -month=MM to output a HTML report for an old month MM\n"; + print " -year=YYYY to output a HTML report for an old year YYYY\n"; + print " Those 'date' options doesn't allow you to process old log file. They only\n"; + print " allow you to see a past report for a chosen month/year period instead of\n"; + print " current month/year.\n"; + print "\n"; + print "Other options:\n"; + print " -debug=X to add debug informations lesser than level X (speed reduced)\n"; + print "\n"; + print "Now supports/detects:\n"; + print " Web/Ftp/Mail/streaming server log analyzis (and load balanced log files)\n"; + print " Reverse DNS lookup (IPv4 and IPv6) and GeoIP lookup\n"; + print " Number of visits, number of unique visitors\n"; + print " Visits duration and list of last visits\n"; + print " Authenticated users\n"; + print " Days of week and rush hours\n"; + print " Hosts list and unresolved IP addresses list\n"; + print " Most viewed, entry and exit pages\n"; + print " Files type and Web compression (mod_gzip, mod_deflate stats)\n"; + print " Screen size\n"; + print " Number of times site is 'added to favorites bookmarks'\n"; + print " Ratio of Browsers with support of: Java, Flash, RealG2 reader,\n"; + print " Quicktime reader, WMA reader, PDF reader\n"; + print " Configurable personalized reports\n"; + print " ".(scalar keys %DomainsHashIDLib)." domains/countries\n"; + print " ".(scalar keys %RobotsHashIDLib)." robots\n"; + print " ".(scalar keys %WormsHashLib)." worm's families\n"; + print " ".(scalar keys %OSHashLib)." operating systems\n"; + print " ".(scalar keys %BrowsersHashIDLib)." browsers"; + &Read_Ref_Data('browsers_phone'); + print " (".(scalar keys %BrowsersHashIDLib)." with phone browsers database)\n"; + print " ".(scalar keys %SearchEnginesHashLib)." search engines (and keyphrases/keywords used from them)\n"; + print " All HTTP errors with last referrer\n"; + print " Report by day/month/year\n"; + print " Dynamic or static HTML or XHTML reports, static PDF reports\n"; + print " Indexed text or XML monthly database\n"; + print " And a lot of other advanced features and options...\n"; + print "New versions and FAQ at http://awstats.sourceforge.net\n"; + exit 2; +} +$SiteConfig||=&Sanitize($ENV{'SERVER_NAME'}); +#$ENV{'SERVER_NAME'}||=$SiteConfig; # For thoose who use __SERVER_NAME__ in conf file and use CLI. +$ENV{'AWSTATS_CURRENT_CONFIG'}=$SiteConfig; + +# Read config file (SiteConfig must be defined) +&Read_Config($DirConfig); + +# Check language +if ($QueryString =~ /(^|&|&)lang=([^&]+)/i) { $Lang="$2"; } +if (! $Lang || $Lang eq 'auto') { # If lang not defined or forced to auto + my $langlist=$ENV{'HTTP_ACCEPT_LANGUAGE'}||''; $langlist =~ s/;[^,]*//g; + if ($Debug) { debug("Search an available language among HTTP_ACCEPT_LANGUAGE=$langlist",1); } + foreach my $code (split(/,/,$langlist)) { # Search for a valid lang in priority + if ($LangBrowserToLangAwstats{$code}) { $Lang=$LangBrowserToLangAwstats{$code}; if ($Debug) { debug(" Will try to use Lang=$Lang",1); } last; } + $code =~ s/-.*$//; + if ($LangBrowserToLangAwstats{$code}) { $Lang=$LangBrowserToLangAwstats{$code}; if ($Debug) { debug(" Will try to use Lang=$Lang",1); } last; } + } +} +if (! $Lang || $Lang eq 'auto') { + if ($Debug) { debug(" No language defined or available. Will use Lang=en",1); } + $Lang='en'; +} + +# Check and correct bad parameters +&Check_Config(); +# Now SiteDomain is defined + +if ($Debug && ! $DebugMessages) { + error("Debug has not been allowed. Change DebugMessages parameter in config file to allow debug."); +} + +# Define frame name and correct variable for frames +if (! $FrameName) { + if ($ENV{'GATEWAY_INTERFACE'} && $UseFramesWhenCGI && $HTMLOutput{'main'} && ! $PluginMode) { $FrameName='index'; } + else { $FrameName='main'; } +} + +# Load Message files, Reference data files and Plugins +if ($Debug) { debug("FrameName=$FrameName",1); } +if ($FrameName ne 'index') { + &Read_Language_Data($Lang); + if ($FrameName ne 'mainleft') { + my %datatoload=(); + my ($filedomains,$filemime,$filerobots,$fileworms,$filebrowser,$fileos,$filese)=('domains','mime','robots','worms','browsers','operating_systems','search_engines'); + my ($filestatushttp,$filestatussmtp)=('status_http','status_smtp'); + if ($LevelForBrowsersDetection eq 'allphones') { $filebrowser='browsers_phone'; } + if ($UpdateStats) { # If update + if ($LevelForFileTypesDetection<2) { $datatoload{$filemime}=1; } # Only if need to filter on known extensions + if ($LevelForRobotsDetection) { $datatoload{$filerobots}=1; } # ua + if ($LevelForWormsDetection) { $datatoload{$fileworms}=1; } # url + if ($LevelForBrowsersDetection) { $datatoload{$filebrowser}=1; } # ua + if ($LevelForOSDetection) { $datatoload{$fileos}=1; } # ua + if ($LevelForRefererAnalyze) { $datatoload{$filese}=1; } # referer + # if (...) { $datatoload{'referer_spam'}=1; } + } + if (scalar keys %HTMLOutput) { # If output + if ($ShowDomainsStats || $ShowHostsStats) { $datatoload{$filedomains}=1; } # TODO Replace by test if ($ShowDomainsStats) when plugins geoip can force load of domains datafile. + if ($ShowFileTypesStats) { $datatoload{$filemime}=1; } + if ($ShowRobotsStats) { $datatoload{$filerobots}=1; } + if ($ShowWormsStats) { $datatoload{$fileworms}=1; } + if ($ShowBrowsersStats) { $datatoload{$filebrowser}=1; } + if ($ShowOSStats) { $datatoload{$fileos}=1; } + if ($ShowOriginStats) { $datatoload{$filese}=1; } + if ($ShowHTTPErrorsStats) { $datatoload{$filestatushttp}=1; } + if ($ShowSMTPErrorsStats) { $datatoload{$filestatussmtp}=1; } + } + &Read_Ref_Data(keys %datatoload); + } + &Read_Plugins(); +} +# Here charset is defined, so we can send the http header (Need BuildReportFormat,PageCode) +if (! $HeaderHTTPSent && $ENV{'GATEWAY_INTERFACE'}) { http_head(); } # Run from a browser as CGI + +# Init other parameters +$NBOFLINESFORBENCHMARK--; +if ($ENV{'GATEWAY_INTERFACE'}) { $DirCgi=''; } +if ($DirCgi && !($DirCgi =~ /\/$/) && !($DirCgi =~ /\\$/)) { $DirCgi .= '/'; } +if (! $DirData || $DirData =~ /^\./) { + if (! $DirData || $DirData eq '.') { $DirData="$DIR"; } # If not defined or chosen to '.' value then DirData is current dir + elsif ($DIR && $DIR ne '.') { $DirData="$DIR/$DirData"; } +} +$DirData||='.'; # If current dir not defined then we put it to '.' +$DirData =~ s/[\\\/]+$//; + +if ($FirstDayOfWeek == 1) { @DOWIndex = (1,2,3,4,5,6,0); } +else { @DOWIndex = (0,1,2,3,4,5,6); } + +# Should we link to ourselves or to a wrapper script +$AWScript=($WrapperScript?"$WrapperScript":"$DirCgi$PROG.$Extension"); + +# Print html header (Need HTMLOutput,Expires,Lang,StyleSheet,HTMLHeadSectionExpires defined by Read_Config, PageCode defined by Read_Language_Data) +if (! $HeaderHTMLSent) { &html_head; } + +# AWStats output is replaced by a plugin output +if ($PluginMode) { +# my $function="BuildFullHTMLOutput_$PluginMode()"; +# eval("$function"); + my $function="BuildFullHTMLOutput_$PluginMode"; + &$function(); + if ($? || $@) { error("$@"); } + &html_end(0); + exit 0; +} + +# Security check +if ($AllowAccessFromWebToAuthenticatedUsersOnly && $ENV{'GATEWAY_INTERFACE'}) { + if ($Debug) { debug("REMOTE_USER=".$ENV{"REMOTE_USER"}); } + if (! $ENV{"REMOTE_USER"}) { + error("Access to statistics is only allowed from an authenticated session to authenticated users."); + } + if (@AllowAccessFromWebToFollowingAuthenticatedUsers) { + my $userisinlist=0; + my $remoteuser=quotemeta($ENV{"REMOTE_USER"}); + $remoteuser =~ s/\s/%20/g; # Allow authenticated user with space in name to be compared to allowed user list + my $currentuser=qr/^$remoteuser$/i; # Set precompiled regex + foreach (@AllowAccessFromWebToFollowingAuthenticatedUsers) { + if (/$currentuser/o) { $userisinlist=1; last; } + } + if (! $userisinlist) { + error("User '".$ENV{"REMOTE_USER"}."' is not allowed to access statistics of this domain/config."); + } + } +} +if ($AllowAccessFromWebToFollowingIPAddresses && $ENV{'GATEWAY_INTERFACE'}) +{ + my $IPAddress=$ENV{"REMOTE_ADDR"}; # IPv4 or IPv6 + my $useripaddress=&Convert_IP_To_Decimal($IPAddress); + my @allowaccessfromipaddresses = split (/[\s,]+/, $AllowAccessFromWebToFollowingIPAddresses); + my $allowaccess = 0; + foreach my $ipaddressrange (@allowaccessfromipaddresses) + { + if ($ipaddressrange !~ /^(\d+\.\d+\.\d+\.\d+)(?:-(\d+\.\d+\.\d+\.\d+))*$/ + && $ipaddressrange !~ /^([0-9A-Fa-f]{1,4}:){1,7}(:|)([0-9A-Fa-f]{1,4}|\/\d)/) + { + error("AllowAccessFromWebToFollowingIPAddresses is defined to '$AllowAccessFromWebToFollowingIPAddresses' but part of value does not match the correct syntax: IPv4AddressMin[-IPv4AddressMax] or IPv6Address[\/prefix] in \"$ipaddressrange\""); + } + + # Test ip v4 + if ($ipaddressrange =~ /^(\d+\.\d+\.\d+\.\d+)(?:-(\d+\.\d+\.\d+\.\d+))*$/) + { + my $ipmin=&Convert_IP_To_Decimal($1); + my $ipmax=$2?&Convert_IP_To_Decimal($2):$ipmin; + # Is it an authorized ip ? + if (($useripaddress >= $ipmin) && ($useripaddress <= $ipmax)) { + $allowaccess = 1; + last; + } + } + + # Test ip v6 + if ($ipaddressrange =~ /^([0-9A-Fa-f]{1,4}:){1,7}(:|)([0-9A-Fa-f]{1,4}|\/\d)/) + { + if ($ipaddressrange =~ /::\//) { + my @IPv6split = split (/::/, $ipaddressrange); + if ($IPAddress =~ /^$IPv6split[0]/) { + $allowaccess = 1; + last; + } + } elsif ($ipaddressrange == $IPAddress) { + $allowaccess = 1; + last; + } + } + } + if (! $allowaccess) { + error("Access to statistics is not allowed from your IP Address ".$ENV{"REMOTE_ADDR"}); + } +} +if (($UpdateStats || $MigrateStats) && (! $AllowToUpdateStatsFromBrowser) && $ENV{'GATEWAY_INTERFACE'}) { + error("".($UpdateStats?"Update":"Migrate")." of statistics has not been allowed from a browser (AllowToUpdateStatsFromBrowser should be set to 1)."); +} +if (scalar keys %HTMLOutput && $MonthRequired eq 'all') { + if (! $AllowFullYearView) { error("Full year view has not been allowed (AllowFullYearView is set to 0)."); } + if ($AllowFullYearView < 3 && $ENV{'GATEWAY_INTERFACE'}) { error("Full year view has not been allowed from a browser (AllowFullYearView should be set to 3)."); } +} + + +#------------------------------------------ +# MIGRATE PROCESS (Must be after reading config cause we need MaxNbOf... and Min...) +#------------------------------------------ +if ($MigrateStats) { + if ($Debug) { debug("MigrateStats is $MigrateStats",2); } + if ($MigrateStats !~ /^(.*)$PROG(\d\d)(\d\d\d\d)(\d{0,2})(\d{0,2})(.*)\.txt$/) { + error("AWStats history file name must match following syntax: ${PROG}MMYYYY[.config].txt","","",1); + } + $DirData="$1"; + $MonthRequired="$2"; + $YearRequired="$3"; + $DayRequired="$4"; + $HourRequired="$5"; + $FileSuffix="$6"; + # Correct DirData + if (! $DirData || $DirData =~ /^\./) { + if (! $DirData || $DirData eq '.') { $DirData="$DIR"; } # If not defined or chosen to '.' value then DirData is current dir + elsif ($DIR && $DIR ne '.') { $DirData="$DIR/$DirData"; } + } + $DirData||='.'; # If current dir not defined then we put it to '.' + $DirData =~ s/[\\\/]+$//; + print "Start migration for file '$MigrateStats'."; print $ENV{'GATEWAY_INTERFACE'}?"
\n":"\n"; + if ($EnableLockForUpdate) { &Lock_Update(1); } + my $newhistory=&Read_History_With_TmpUpdate($YearRequired,$MonthRequired,$DayRequired,$HourRequired,1,0,'all'); + if (rename("$newhistory","$MigrateStats")==0) { + unlink "$newhistory"; + error("Failed to rename \"$newhistory\" into \"$MigrateStats\".\nWrite permissions on \"$MigrateStats\" might be wrong".($ENV{'GATEWAY_INTERFACE'}?" for a 'migration from web'":"")." or file might be opened."); + } + if ($EnableLockForUpdate) { &Lock_Update(0); } + print "Migration for file '$MigrateStats' successful."; print $ENV{'GATEWAY_INTERFACE'}?"
\n":"\n"; + &html_end(1); + exit 0; +} + +# Output main frame page and exit. This must be after the security check. +if ($FrameName eq 'index') { + # Define the NewLinkParams for main chart + my $NewLinkParams=${QueryString}; + $NewLinkParams =~ s/(^|&|&)framename=[^&]*//i; + $NewLinkParams =~ s/(&|&)+/&/i; + $NewLinkParams =~ s/^&//; $NewLinkParams =~ s/&$//; + if ($NewLinkParams) { $NewLinkParams="${NewLinkParams}&"; } + # Exit if main frame + print "\n"; + print "\n"; + print "\n"; + print "<body>"; + print "Your browser does not support frames.<br />\n"; + print "You must set AWStats UseFramesWhenCGI parameter to 0\n"; + print "to see your reports.<br />\n"; + print "</body>\n"; + print "\n"; + &html_end(0); + exit 0; +} + +%MonthNumLib = ("01","$Message[60]","02","$Message[61]","03","$Message[62]","04","$Message[63]","05","$Message[64]","06","$Message[65]","07","$Message[66]","08","$Message[67]","09","$Message[68]","10","$Message[69]","11","$Message[70]","12","$Message[71]"); + +# Build ListOfYears list with all existing years +($lastyearbeforeupdate,$lastmonthbeforeupdate,$lastdaybeforeupdate,$lasthourbeforeupdate,$lastdatebeforeupdate)=(0,0,0,0,0); +my $datemask=''; +if ($DatabaseBreak eq 'month') { $datemask='(\d\d)(\d\d\d\d)'; } +elsif ($DatabaseBreak eq 'year') { $datemask='(\d\d\d\d)'; } +elsif ($DatabaseBreak eq 'day') { $datemask='(\d\d)(\d\d\d\d)(\d\d)'; } +elsif ($DatabaseBreak eq 'hour') { $datemask='(\d\d)(\d\d\d\d)(\d\d)(\d\d)'; } +if ($Debug) { debug("Scan for last history files into DirData='$DirData' with mask='$datemask'"); } +opendir(DIR,"$DirData"); +my $regfilesuffix=quotemeta($FileSuffix); +foreach (grep /^$PROG$datemask$regfilesuffix\.txt(|\.gz)$/i, file_filt sort readdir DIR) { + /^$PROG$datemask$regfilesuffix\.txt(|\.gz)$/i; + if (! $ListOfYears{"$2"} || "$1" gt $ListOfYears{"$2"}) { + # ListOfYears contains max month found + $ListOfYears{"$2"}="$1"; + } + my $rangestring=($2||"").($1||"").($3||"").($4||""); + if ($rangestring gt $lastdatebeforeupdate) { + # We are on a new max for mask + $lastyearbeforeupdate=($2||""); + $lastmonthbeforeupdate=($1||""); + $lastdaybeforeupdate=($3||""); + $lasthourbeforeupdate=($4||""); + $lastdatebeforeupdate=$rangestring; + } +} +close DIR; + +# If at least one file found, get value for LastLine +if ($lastyearbeforeupdate) { + # Read 'general' section of last history file for LastLine + &Read_History_With_TmpUpdate($lastyearbeforeupdate,$lastmonthbeforeupdate,$lastdaybeforeupdate,$lasthourbeforeupdate,0,0,"general"); +} +# Warning if lastline in future +if ($LastLine > ($nowtime + 20000)) +{ + warning("WARNING: LastLine parameter in history file is '$LastLine' so in future. May be you need to correct manually the line LastLine in some awstats*.$SiteConfig.conf files."); +} +# Force LastLine +if ($QueryString =~ /lastline=(\d{14})/i) +{ + $LastLine=$1; +} +if ($Debug) { + debug("Last year=$lastyearbeforeupdate - Last month=$lastmonthbeforeupdate"); + debug("Last day=$lastdaybeforeupdate - Last hour=$lasthourbeforeupdate"); + debug("LastLine=$LastLine"); + debug("LastLineNumber=$LastLineNumber"); + debug("LastLineOffset=$LastLineOffset"); + debug("LastLineChecksum=$LastLineChecksum"); +} + + + +# Init vars +&Init_HashArray(); + + +#------------------------------------------ +# UPDATE PROCESS +#------------------------------------------ +my $lastlinenb=0; my $lastlineoffset=0; my $lastlineoffsetnext=0; + +if ($Debug) { debug("UpdateStats is $UpdateStats",2); } +if ($UpdateStats && $FrameName ne 'index' && $FrameName ne 'mainleft') { # Update only on index page or when not framed to avoid update twice + + my %MonthNum = ("Jan","01","jan","01","Feb","02","feb","02","Mar","03","mar","03","Apr","04","apr","04","May","05","may","05","Jun","06","jun","06","Jul","07","jul","07","Aug","08","aug","08","Sep","09","sep","09","Oct","10","oct","10","Nov","11","nov","11","Dec","12","dec","12"); # MonthNum must be in english because used to translate log date in apache log files + + if (! scalar keys %HTMLOutput) { + print "Create/Update database for config \"$FileConfig\" by AWStats version $VERSION\n"; + print "From data in log file \"$LogFile\"...\n"; + } + + my $lastprocessedyear=$lastyearbeforeupdate||0; + my $lastprocessedmonth=$lastmonthbeforeupdate||0; + my $lastprocessedday=$lastdaybeforeupdate||0; + my $lastprocessedhour=$lasthourbeforeupdate||0; + my $lastprocesseddate=''; + if ($DatabaseBreak eq 'month') { $lastprocesseddate=sprintf("%04i%02i",$lastprocessedyear,$lastprocessedmonth); } + elsif ($DatabaseBreak eq 'year') { $lastprocesseddate=sprintf("%04i%",$lastprocessedyear); } + elsif ($DatabaseBreak eq 'day') { $lastprocesseddate=sprintf("%04i%02i%02i",$lastprocessedyear,$lastprocessedmonth,$lastprocessedday); } + elsif ($DatabaseBreak eq 'hour') { $lastprocesseddate=sprintf("%04i%02i%02i%02i",$lastprocessedyear,$lastprocessedmonth,$lastprocessedday,$lastprocessedhour); } + + + my @list; + # Init RobotsSearchIDOrder required for update process + @list=(); + if ($LevelForRobotsDetection >= 1) { + foreach (1..$LevelForRobotsDetection) { push @list,"list$_"; } + push @list,"listgen"; # Always added + } + foreach my $key (@list) { + push @RobotsSearchIDOrder,@{"RobotsSearchIDOrder_$key"}; + if ($Debug) { debug("Add ".@{"RobotsSearchIDOrder_$key"}." elements from RobotsSearchIDOrder_$key into RobotsSearchIDOrder",2); } + } + if ($Debug) { debug("RobotsSearchIDOrder has now ".@RobotsSearchIDOrder." elements",1); } + # Init SearchEnginesIDOrder required for update process + @list=(); + if ($LevelForSearchEnginesDetection >= 1) { + foreach (1..$LevelForSearchEnginesDetection) { push @list,"list$_"; } + push @list,"listgen"; # Always added + } + foreach my $key (@list) { + push @SearchEnginesSearchIDOrder,@{"SearchEnginesSearchIDOrder_$key"}; + if ($Debug) { debug("Add ".@{"SearchEnginesSearchIDOrder_$key"}." elements from SearchEnginesSearchIDOrder_$key into SearchEnginesSearchIDOrder",2); } + } + if ($Debug) { debug("SearchEnginesSearchIDOrder has now ".@SearchEnginesSearchIDOrder." elements",1); } + + # Complete HostAliases array + my $sitetoanalyze=quotemeta(lc($SiteDomain)); + if (! @HostAliases) { + warning("Warning: HostAliases parameter is not defined, $PROG choose \"$SiteDomain localhost 127.0.0.1\"."); + push @HostAliases,qr/^$sitetoanalyze$/i; push @HostAliases,qr/^localhost$/i; push @HostAliases,qr/^127\.0\.0\.1$/i; + } + else { unshift @HostAliases,qr/^$sitetoanalyze$/i; } # Add SiteDomain as first value + + # Optimize arrays + @HostAliases=&OptimizeArray(\@HostAliases,1); if ($Debug) { debug("HostAliases precompiled regex list is now @HostAliases",1); } + @SkipDNSLookupFor=&OptimizeArray(\@SkipDNSLookupFor,1); if ($Debug) { debug("SkipDNSLookupFor precompiled regex list is now @SkipDNSLookupFor",1); } + @SkipHosts=&OptimizeArray(\@SkipHosts,1); if ($Debug) { debug("SkipHosts precompiled regex list is now @SkipHosts",1); } + @SkipReferrers=&OptimizeArray(\@SkipReferrers,1); if ($Debug) { debug("SkipReferrers precompiled regex list is now @SkipReferrers",1); } + @SkipUserAgents=&OptimizeArray(\@SkipUserAgents,1); if ($Debug) { debug("SkipUserAgents precompiled regex list is now @SkipUserAgents",1); } + @SkipFiles=&OptimizeArray(\@SkipFiles,$URLNotCaseSensitive); if ($Debug) { debug("SkipFiles precompiled regex list is now @SkipFiles",1); } + @OnlyHosts=&OptimizeArray(\@OnlyHosts,1); if ($Debug) { debug("OnlyHosts precompiled regex list is now @OnlyHosts",1); } + @OnlyUserAgents=&OptimizeArray(\@OnlyUserAgents,1); if ($Debug) { debug("OnlyUserAgents precompiled regex list is now @OnlyUserAgents",1); } + @OnlyFiles=&OptimizeArray(\@OnlyFiles,$URLNotCaseSensitive); if ($Debug) { debug("OnlyFiles precompiled regex list is now @OnlyFiles",1); } + @NotPageFiles=&OptimizeArray(\@NotPageFiles,$URLNotCaseSensitive); if ($Debug) { debug("NotPageFiles precompiled regex list is now @NotPageFiles",1); } + # Precompile the regex search strings with qr + @RobotsSearchIDOrder=map{qr/$_/i} @RobotsSearchIDOrder; + @WormsSearchIDOrder=map{qr/$_/i} @WormsSearchIDOrder; + @BrowsersSearchIDOrder=map{qr/$_/i} @BrowsersSearchIDOrder; + @OSSearchIDOrder=map{qr/$_/i} @OSSearchIDOrder; + @SearchEnginesSearchIDOrder=map{qr/$_/i} @SearchEnginesSearchIDOrder; + my $miscquoted=quotemeta("$MiscTrackerUrl"); + my $defquoted=quotemeta("/$DefaultFile[0]"); + my $sitewithoutwww=lc($SiteDomain); $sitewithoutwww =~ s/www\.//; $sitewithoutwww=quotemeta($sitewithoutwww); + # Define precompiled regex + my $regmisc=qr/^$miscquoted/; + my $regfavico=qr/\/favicon\.ico$/i; + my $regrobot=qr/^\/robots\.txt$/i; + my $regtruncanchor=qr/#(\w*)$/; + my $regtruncurl=qr/([$URLQuerySeparators])(.*)$/; + my $regext=qr/\.(\w{1,6})$/; + my $regdefault; + if ($URLNotCaseSensitive) { $regdefault=qr/$defquoted$/i; } + else { $regdefault=qr/$defquoted$/; } + my $regipv4=qr/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/; + my $regipv6=qr/^[0-9A-F]*:/i; + my $regvermsie=qr/msie([+_ ]|)([\d\.]*)/i; + my $regvernetscape=qr/netscape.?\/([\d\.]*)/i; + my $regverfirefox=qr/firefox\/([\d\.]*)/i; + my $regversvn=qr/svn\/([\d\.]*)/i; + my $regvermozilla=qr/mozilla(\/|)([\d\.]*)/i; + my $regnotie=qr/webtv|omniweb|opera/i; + my $regnotnetscape=qr/gecko|compatible|opera|galeon|safari/i; + my $regreferer=qr/^(\w+):\/\/([^\/:]+)(:\d+|)/; + my $regreferernoquery=qr/^([^$URLQuerySeparators]+)/; + my $reglocal=qr/^(www\.|)$sitewithoutwww/i; + my $regget=qr/get|out/i; + my $regsent=qr/sent|put|in/i; + + # Define value of $pos_xxx, @fieldlib, $PerlParsingFormat + &DefinePerlParsingFormat($LogFormat); + + # Load DNS Cache Files + #------------------------------------------ + if ($DNSLookup) { + &Read_DNS_Cache(\%MyDNSTable,"$DNSStaticCacheFile","",1); # Load with save into a second plugin file if plugin enabled and second file not up to date. No use of FileSuffix + if ($DNSLookup == 1) { # System DNS lookup required + #if (! eval("use Socket;")) { error("Failed to load perl module Socket."); } + #use Socket; + &Read_DNS_Cache(\%TmpDNSLookup,"$DNSLastUpdateCacheFile","$FileSuffix",0); # Load with no save into a second plugin file. Use FileSuffix + } + } + + # Processing log + #------------------------------------------ + + if ($EnableLockForUpdate) { + # Trap signals to remove lock + $SIG{INT} = \&SigHandler; # 2 + #$SIG{KILL} = \&SigHandler; # 9 + #$SIG{TERM} = \&SigHandler; # 15 + # Set AWStats update lock + &Lock_Update(1); + } + + if ($Debug) { debug("Start Update process (lastprocesseddate=$lastprocesseddate)"); } + + # Open log file + if ($Debug) { debug("Open log file \"$LogFile\""); } + open(LOG,"$LogFile") || error("Couldn't open server log file \"$LogFile\" : $!"); + binmode LOG; # Avoid premature EOF due to log files corrupted with \cZ or bin chars + + # Define local variables for loop scan + my @field=(); + my $counterforflushtest=0; + my $qualifdrop=''; + my $countedtraffic=0; + # Reset chrono for benchmark (first call to GetDelaySinceStart) + &GetDelaySinceStart(1); + if (! scalar keys %HTMLOutput) { print "Phase 1 : First bypass old records, searching new record...\n"; } + + # Can we try a direct seek access in log ? + my $line; + if ($LastLine && $LastLineNumber && $LastLineOffset && $LastLineChecksum) + { + # Try a direct seek access to save time + if ($Debug) { debug("Try a direct access to LastLine=$LastLine, LastLineNumber=$LastLineNumber, LastLineOffset=$LastLineOffset, LastLineChecksum=$LastLineChecksum"); } + seek(LOG,$LastLineOffset,0); + if ($line=) { + chomp $line; $line =~ s/\r$//; + @field=map(/$PerlParsingFormat/,$line); + if ($Debug) { + my $string=''; + foreach (0..@field-1) { $string.="$fieldlib[$_]=$field[$_] "; } + if ($Debug) { debug(" Read line after direct access: $string",1); } + } + my $checksum=&CheckSum($line); + if ($Debug) { debug(" LastLineChecksum=$LastLineChecksum, Read line checksum=$checksum",1); } + if ($checksum == $LastLineChecksum ) { + if (! scalar keys %HTMLOutput) { print "Direct access after last parsed record (after line $LastLineNumber)\n"; } + $lastlinenb=$LastLineNumber; + $lastlineoffset=$LastLineOffset; + $lastlineoffsetnext=tell LOG; + $NewLinePhase=1; + } + else { + if (! scalar keys %HTMLOutput) { print "Direct access to last remembered record has fallen on another record.\nSo searching new records from beginning of log file...\n"; } + $lastlinenb=0; + $lastlineoffset=0; + $lastlineoffsetnext=0; + seek(LOG,0,0); + } + } + else { + if (! scalar keys %HTMLOutput) { print "Direct access to last remembered record is out of file.\nSo searching it from beginning of log file...\n"; } + $lastlinenb=0; + $lastlineoffset=0; + $lastlineoffsetnext=0; + seek(LOG,0,0); + } + } + else { + # No try of direct seek access + if (! scalar keys %HTMLOutput) { print "Searching new records from beginning of log file...\n"; } + $lastlinenb=0; + $lastlineoffset=0; + $lastlineoffsetnext=0; + } + + # + # Loop on each log line + # + while ($line=) { + chomp $line; $line =~ s/\r$//; + if ($UpdateFor && $NbOfLinesParsed >= $UpdateFor) { last; } + $NbOfLinesParsed++; + + $lastlineoffset=$lastlineoffsetnext; $lastlineoffsetnext=tell LOG; + + if ($ShowSteps) { + if ((++$NbOfLinesShowsteps & $NBOFLINESFORBENCHMARK) == 0) { + my $delay=&GetDelaySinceStart(0); + print "$NbOfLinesParsed lines processed (".($delay>0?$delay:1000)." ms, ".int(1000*$NbOfLinesShowsteps/($delay>0?$delay:1000))." lines/second)\n"; + } + } + + if ($LogFormat eq '2' && $line =~ /^#Fields:/) { + my @fixField=map(/^#Fields: (.*)/, $line); + if ($fixField[0] !~ /s-kernel-time/) { + debug("Found new log format: '". $fixField[0] ."'",1); + &DefinePerlParsingFormat($fixField[0]); + } + } + + # Parse line record to get all required fields + if (! (@field=map(/$PerlParsingFormat/,$line))) { + $NbOfLinesCorrupted++; + if ($ShowCorrupted) { + if ($line =~ /^#/ || $line =~ /^!/) { print "Corrupted record line ".($lastlinenb+$NbOfLinesParsed)." (comment line): $line\n"; } + elsif ($line =~ /^\s*$/) { print "Corrupted record line ".($lastlinenb+$NbOfLinesParsed)." (blank line)\n"; } + else { print "Corrupted record line ".($lastlinenb+$NbOfLinesParsed)." (record format does not match LogFormat parameter): $line\n"; } + } + if ($NbOfLinesParsed >= $NbOfLinesForCorruptedLog && $NbOfLinesParsed == $NbOfLinesCorrupted) { error("Format error",$line,$LogFile); } # Exit with format error + if ($line =~ /^__end_of_file__/i) { last; } # For test purpose only + next; + } + + if ($Debug) { + my $string=''; + foreach (0..@field-1) { $string.="$fieldlib[$_]=$field[$_] "; } + if ($Debug) { debug(" Correct format line ".($lastlinenb+$NbOfLinesParsed).": $string",4); } + } + + # Drop wrong virtual host name + #---------------------------------------------------------------------- + if ($pos_vh>=0 && $field[$pos_vh] !~ /^$SiteDomain$/i) { + my $skip=1; + foreach (@HostAliases) { + if ($field[$pos_vh] =~ /$_/) { $skip=0; last; } + } + if ($skip) { + $NbOfLinesDropped++; + if ($ShowDropped) { print "Dropped record (virtual hostname '$field[$pos_vh]' does not match SiteDomain='$SiteDomain' nor HostAliases parameters): $line\n"; } + next; + } + } + + # Drop wrong method/protocol + #--------------------------- + if ($LogType ne 'M') { $field[$pos_url] =~ s/\s/%20/g; } + if ($LogType eq 'W' + && ($field[$pos_method] eq 'GET' + || $field[$pos_method] eq 'POST' + || $field[$pos_method] eq 'HEAD' + || $field[$pos_method] eq 'PROPFIND' + || $field[$pos_method] eq 'CHECKOUT' + || $field[$pos_method] eq 'LOCK' + || $field[$pos_method] eq 'PROPPATCH' + || $field[$pos_method] eq 'OPTIONS' + || $field[$pos_method] eq 'MKACTIVITY' + || $field[$pos_method] eq 'PUT' + || $field[$pos_method] eq 'MERGE' + || $field[$pos_method] eq 'DELETE' + || $field[$pos_method] eq 'REPORT' + || $field[$pos_method] eq 'MKCOL' + || $field[$pos_method] eq 'COPY' + || $field[$pos_method] =~ /OK/i + || $field[$pos_method] =~ /ERR\!/i)) { + # HTTP request. Keep only GET, POST, HEAD, *OK* and ERR! for Webstar. Do not keep OPTIONS, TRACE + } + elsif (($LogType eq 'W' || $LogType eq 'S') && ($field[$pos_method] eq 'GET' || $field[$pos_method] eq 'mms' || $field[$pos_method] eq 'rtsp' || $field[$pos_method] eq 'http' || $field[$pos_method] eq 'RTP')) { + # Streaming request (windows media server, realmedia or darwin streaming server) + } + elsif ($LogType eq 'M' && $field[$pos_method] eq 'SMTP') { + # Mail request ('SMTP' for mail log with maillogconvert.pl preprocessor) + } + elsif ($LogType eq 'F' && ($field[$pos_method] eq 'RETR' || $field[$pos_method] eq 'o' || $field[$pos_method] =~ /$regget/o)) { + # FTP GET request + } + elsif ($LogType eq 'F' && ($field[$pos_method] eq 'STOR' || $field[$pos_method] eq 'i' || $field[$pos_method] =~ /$regsent/o)) { + # FTP SENT request + } + else { + $NbOfLinesDropped++; + if ($ShowDropped) { print "Dropped record (method/protocol '$field[$pos_method]' not qualified when LogType=$LogType): $line\n"; } + next; + } + + $field[$pos_date] =~ tr/,-\/ \t/:::::/s; # " \t" is used instead of "\s" not known with tr + my @dateparts=split(/:/,$field[$pos_date]); # tr and split faster than @dateparts=split(/[\/\-:\s]/,$field[$pos_date]) + # Detected date format: dddddddddd, YYYY-MM-DD HH:MM:SS (IIS), MM/DD/YY\tHH:MM:SS, + # DD/Month/YYYY:HH:MM:SS (Apache), DD/MM/YYYY HH:MM:SS, Mon DD HH:MM:SS + if (! $dateparts[1]) { # Unix timestamp + ($dateparts[5],$dateparts[4],$dateparts[3],$dateparts[0],$dateparts[1],$dateparts[2]) = localtime(int($field[$pos_date])); + $dateparts[1]++;$dateparts[2]+=1900; + } + elsif ($dateparts[0] =~ /^....$/) { my $tmp=$dateparts[0]; $dateparts[0]=$dateparts[2]; $dateparts[2]=$tmp; } + elsif ($field[$pos_date] =~ /^..:..:..:/) { $dateparts[2]+=2000; my $tmp=$dateparts[0]; $dateparts[0]=$dateparts[1]; $dateparts[1]=$tmp; } + elsif ($dateparts[0] =~ /^...$/) { my $tmp=$dateparts[0]; $dateparts[0]=$dateparts[1]; $dateparts[1]=$tmp; $tmp=$dateparts[5]; $dateparts[5]=$dateparts[4]; $dateparts[4]=$dateparts[3]; $dateparts[3]=$dateparts[2]; $dateparts[2]=$tmp||$nowyear; } + if (exists($MonthNum{$dateparts[1]})) { $dateparts[1]=$MonthNum{$dateparts[1]}; } # Change lib month in num month if necessary + if ($dateparts[1] <= 0) { # Date corrupted (for example $dateparts[1]='dic' for december month in a spanish log file) + $NbOfLinesCorrupted++; + if ($ShowCorrupted) { print "Corrupted record line ".($lastlinenb+$NbOfLinesParsed)." (bad date format for month, may be month are not in english ?): $line\n"; } + next; + } + + # Now @dateparts is (DD,MM,YYYY,HH,MM,SS) and we're going to create $timerecord=YYYYMMDDHHMMSS + if ($PluginsLoaded{'ChangeTime'}{'timezone'}) { @dateparts=ChangeTime_timezone(\@dateparts); } + my $yearrecord=int($dateparts[2]); + my $monthrecord=int($dateparts[1]); + my $dayrecord=int($dateparts[0]); + my $hourrecord=int($dateparts[3]); + my $daterecord=''; + if ($DatabaseBreak eq 'month') { $daterecord=sprintf("%04i%02i",$yearrecord,$monthrecord); } + elsif ($DatabaseBreak eq 'year') { $daterecord=sprintf("%04i%",$yearrecord); } + elsif ($DatabaseBreak eq 'day') { $daterecord=sprintf("%04i%02i%02i",$yearrecord,$monthrecord,$dayrecord); } + elsif ($DatabaseBreak eq 'hour') { $daterecord=sprintf("%04i%02i%02i%02i",$yearrecord,$monthrecord,$dayrecord,$hourrecord); } + # TODO essayer de virer yearmonthrecord + my $yearmonthdayrecord=sprintf("$dateparts[2]%02i%02i",$dateparts[1],$dateparts[0]); + my $timerecord=((int("$yearmonthdayrecord")*100+$dateparts[3])*100+$dateparts[4])*100+$dateparts[5]; + + # Check date + #----------------------- + if ($LogType eq 'M' && $timerecord > $tomorrowtime) + { + # Postfix/Sendmail does not store year, so we assume that year is year-1 if record is in future + $yearrecord--; + if ($DatabaseBreak eq 'month') { $daterecord=sprintf("%04i%02i",$yearrecord,$monthrecord); } + elsif ($DatabaseBreak eq 'year') { $daterecord=sprintf("%04i%",$yearrecord); } + elsif ($DatabaseBreak eq 'day') { $daterecord=sprintf("%04i%02i%02i",$yearrecord,$monthrecord,$dayrecord); } + elsif ($DatabaseBreak eq 'hour') { $daterecord=sprintf("%04i%02i%02i%02i",$yearrecord,$monthrecord,$dayrecord,$hourrecord); } + # TODO essayer de virer yearmonthrecord + $yearmonthdayrecord=sprintf("$yearrecord%02i%02i",$dateparts[1],$dateparts[0]); + $timerecord=((int("$yearmonthdayrecord")*100+$dateparts[3])*100+$dateparts[4])*100+$dateparts[5]; + } + if ($timerecord < 10000000000000 || $timerecord > $tomorrowtime) { + $NbOfLinesCorrupted++; + if ($ShowCorrupted) { print "Corrupted record (invalid date, timerecord=$timerecord): $line\n"; } + next; # Should not happen, kept in case of parasite/corrupted line + } + if ($NewLinePhase) { + # TODO NOTSORTEDRECORDTOLERANCE does not work around midnight + if ($timerecord < ($LastLine - $NOTSORTEDRECORDTOLERANCE)) { + # Should not happen, kept in case of parasite/corrupted old line + $NbOfLinesCorrupted++; + if ($ShowCorrupted) { print "Corrupted record (date $timerecord lower than $LastLine-$NOTSORTEDRECORDTOLERANCE): $line\n"; } next; + } + } + else { + if ($timerecord <= $LastLine) { # Already processed + $NbOfOldLines++; + next; + } + # We found a new line. This will replace comparison "<=" with "<" between timerecord and LastLine (we should have only new lines now) + $NewLinePhase=1; # We will never enter here again + if ($ShowSteps) { + if ($NbOfLinesShowsteps > 1 && ($NbOfLinesShowsteps & $NBOFLINESFORBENCHMARK)) { + my $delay=&GetDelaySinceStart(0); + print "".($NbOfLinesParsed-1)." lines processed (".($delay>0?$delay:1000)." ms, ".int(1000*($NbOfLinesShowsteps-1)/($delay>0?$delay:1000))." lines/second)\n"; + } + &GetDelaySinceStart(1); $NbOfLinesShowsteps=1; + } + if (! scalar keys %HTMLOutput) { + print "Phase 2 : Now process new records (Flush history on disk after ".($LIMITFLUSH<<2)." hosts)...\n"; + #print "Phase 2 : Now process new records (Flush history on disk after ".($LIMITFLUSH<<2)." hosts or ".($LIMITFLUSH)." URLs)...\n"; + } + } + + # Convert URL for Webstar to common URL + if ($LogFormat eq '3') { + $field[$pos_url]=~s/:/\//g; + if ($field[$pos_code] eq '-') { $field[$pos_code]='200'; } + } + + # Here, field array, timerecord and yearmonthdayrecord are initialized for log record + if ($Debug) { debug(" This is a not already processed record ($timerecord)",4); } + + # We found a new line + #---------------------------------------- + if ($timerecord > $LastLine) { $LastLine = $timerecord; } # Test should always be true except with not sorted log files + + # Skip for some client host IP addresses, some URLs, other URLs + if (@SkipHosts && (&SkipHost($field[$pos_host]) || ($pos_hostr && &SkipHost($field[$pos_hostr])))) { $qualifdrop="Dropped record (host $field[$pos_host]".($pos_hostr?" and $field[$pos_hostr]":"")." not qualified by SkipHosts)"; } + elsif (@SkipFiles && &SkipFile($field[$pos_url])) { $qualifdrop="Dropped record (URL $field[$pos_url] not qualified by SkipFiles)"; } + elsif (@SkipUserAgents && $pos_agent >= 0 && &SkipUserAgent($field[$pos_agent])) { $qualifdrop="Dropped record (user agent '$field[$pos_agent]' not qualified by SkipUserAgents)"; } + elsif (@SkipReferrers && $pos_referer >= 0 && &SkipReferrer($field[$pos_referer])) { $qualifdrop="Dropped record (URL $field[$pos_referer] not qualified by SkipReferrers)"; } + elsif (@OnlyHosts && ! &OnlyHost($field[$pos_host]) && (! $pos_hostr || ! &OnlyHost($field[$pos_hostr]))) { $qualifdrop="Dropped record (host $field[$pos_host]".($pos_hostr?" and $field[$pos_hostr]":"")." not qualified by OnlyHosts)"; } + elsif (@OnlyFiles && ! &OnlyFile($field[$pos_url])) { $qualifdrop="Dropped record (URL $field[$pos_url] not qualified by OnlyFiles)"; } + elsif (@OnlyUserAgents && ! &OnlyUserAgent($field[$pos_agent])) { $qualifdrop="Dropped record (user agent '$field[$pos_agent]' not qualified by OnlyUserAgents)"; } + if ($qualifdrop) { + $NbOfLinesDropped++; + if ($Debug) { debug("$qualifdrop: $line",4); } + if ($ShowDropped) { print "$qualifdrop: $line\n"; } + $qualifdrop=''; + next; + } + + # Record is approved + #------------------- + + # Is it in a new break section ? + #------------------------------- + if ($daterecord > $lastprocesseddate) { + # A new break to process + if ($lastprocesseddate > 0) { + # We save data of previous break + &Read_History_With_TmpUpdate($lastprocessedyear,$lastprocessedmonth,$lastprocessedday,$lastprocessedhour,1,1,"all",($lastlinenb+$NbOfLinesParsed),$lastlineoffset,&CheckSum($line)); + $counterforflushtest=0; # We reset counterforflushtest + } + $lastprocessedyear=$yearrecord; + $lastprocessedmonth=$monthrecord; + $lastprocessedday=$dayrecord; + $lastprocessedhour=$hourrecord; + if ($DatabaseBreak eq 'month') { $lastprocesseddate=sprintf("%04i%02i",$yearrecord,$monthrecord); } + elsif ($DatabaseBreak eq 'year') { $lastprocesseddate=sprintf("%04i%",$yearrecord); } + elsif ($DatabaseBreak eq 'day') { $lastprocesseddate=sprintf("%04i%02i%02i",$yearrecord,$monthrecord,$dayrecord); } + elsif ($DatabaseBreak eq 'hour') { $lastprocesseddate=sprintf("%04i%02i%02i%02i",$yearrecord,$monthrecord,$dayrecord,$hourrecord); } + } + + $countedtraffic=0; + $NbOfNewLines++; + + # Convert $field[$pos_size] + # if ($field[$pos_size] eq '-') { $field[$pos_size]=0; } + + # Define a clean target URL and referrer URL + # We keep a clean $field[$pos_url] and + # we store original value for urlwithnoquery, tokenquery and standalonequery + #--------------------------------------------------------------------------- + if ($URLNotCaseSensitive) { $field[$pos_url]=lc($field[$pos_url]); } + # Possible URL syntax for $field[$pos_url]: /mydir/mypage.ext?param1=x¶m2=y#aaa, /mydir/mypage.ext#aaa, / + my $urlwithnoquery; my $tokenquery; my $standalonequery; my $anchor=''; + if ($field[$pos_url] =~ s/$regtruncanchor//o) { $anchor=$1; } # Remove and save anchor + if ($URLWithQuery) { + $urlwithnoquery=$field[$pos_url]; + my $foundparam=($urlwithnoquery =~ s/$regtruncurl//o); + $tokenquery=$1||''; + $standalonequery=$2||''; + # For IIS setup, if pos_query is enabled we need to combine the URL to query strings + if (! $foundparam && $pos_query >=0 && $field[$pos_query] && $field[$pos_query] ne '-') { + $foundparam=1; + $tokenquery='?'; + $standalonequery=$field[$pos_query]; + # Define query + $field[$pos_url] .= '?'.$field[$pos_query]; + } + if ($foundparam) { + # Keep only params that are defined in URLWithQueryWithOnlyFollowingParameters + my $newstandalonequery=''; + if (@URLWithQueryWithOnly) { + foreach (@URLWithQueryWithOnly) { + foreach my $p (split(/&/,$standalonequery)) { + if ($URLNotCaseSensitive) { if ($p =~ /^$_=/i) { $newstandalonequery.="$p&"; last; } } + else { if ($p =~ /^$_=/) { $newstandalonequery.="$p&"; last; } } + } + } + chop $newstandalonequery; + } + # Remove params that are marked to be ignored in URLWithQueryWithoutFollowingParameters + elsif (@URLWithQueryWithout) { + foreach my $p (split(/&/,$standalonequery)) { + my $found=0; + foreach (@URLWithQueryWithout) { + #if ($Debug) { debug(" Check if '$_=' is param '$p' to remove it from query",5); } + if ($URLNotCaseSensitive) { if ($p =~ /^$_=/i) { $found=1; last; } } + else { if ($p =~ /^$_=/) { $found=1; last; } } + } + if (! $found) { $newstandalonequery.="$p&"; } + } + chop $newstandalonequery; + } + else { $newstandalonequery=$standalonequery; } + # Define query + $field[$pos_url]=$urlwithnoquery; + if ($newstandalonequery) { $field[$pos_url].="$tokenquery$newstandalonequery"; } + } + } + else { + # Trunc parameters of URL + $field[$pos_url] =~ s/$regtruncurl//o; + $urlwithnoquery=$field[$pos_url]; + $tokenquery=$1||''; + $standalonequery=$2||''; + # For IIS setup, if pos_query is enabled we need to use it for query strings + if ($pos_query >=0 && $field[$pos_query] && $field[$pos_query] ne '-') { + $tokenquery='?'; + $standalonequery=$field[$pos_query]; + } + } + if ($URLWithAnchor && $anchor) { $field[$pos_url].="#$anchor"; } # Restore anchor + # Here now urlwithnoquery is /mydir/mypage.ext, /mydir, /, /page#XXX + # Here now tokenquery is '' or '?' or ';' + # Here now standalonequery is '' or 'param1=x' + + # Define page and extension + #-------------------------- + my $PageBool=1; + # Extension + my $extension; + if ($urlwithnoquery =~ /$regext/o || ($urlwithnoquery =~ /[\\\/]$/ && $DefaultFile[0] =~ /$regext/o)) { + $extension=($LevelForFileTypesDetection>=2 || $MimeHashFamily{$1})?lc($1):'Unknown'; + if ($NotPageList{$extension}) { $PageBool=0; } + } + else { + $extension='Unknown'; + } + + if (@NotPageFiles && &NotPageFile($field[$pos_url])) { $PageBool=0; } + + # Analyze: misc tracker (must be before return code) + #--------------------------------------------------- + if ($urlwithnoquery =~ /$regmisc/o) { + if ($Debug) { debug(" Found an URL that is a MiscTracker record with standalonequery=$standalonequery",2); } + my $foundparam=0; + foreach (split(/&/,$standalonequery)) { + if ($_ =~ /^screen=(\d+)x(\d+)/i) { $foundparam++; $_screensize_h{"$1x$2"}++; next; } + #if ($_ =~ /cdi=(\d+)/i) { $foundparam++; $_screendepth_h{"$1"}++; next; } + if ($_ =~ /^nojs=(\w+)/i) { $foundparam++; if ($1 eq 'y') { $_misc_h{"JavascriptDisabled"}++; } next; } + if ($_ =~ /^java=(\w+)/i) { $foundparam++; if ($1 eq 'true') { $_misc_h{"JavaEnabled"}++; } next; } + if ($_ =~ /^shk=(\w+)/i) { $foundparam++; if ($1 eq 'y') { $_misc_h{"DirectorSupport"}++; } next; } + if ($_ =~ /^fla=(\w+)/i) { $foundparam++; if ($1 eq 'y') { $_misc_h{"FlashSupport"}++; } next; } + if ($_ =~ /^rp=(\w+)/i) { $foundparam++; if ($1 eq 'y') { $_misc_h{"RealPlayerSupport"}++; } next; } + if ($_ =~ /^mov=(\w+)/i) { $foundparam++; if ($1 eq 'y') { $_misc_h{"QuickTimeSupport"}++; } next; } + if ($_ =~ /^wma=(\w+)/i) { $foundparam++; if ($1 eq 'y') { $_misc_h{"WindowsMediaPlayerSupport"}++; } next; } + if ($_ =~ /^pdf=(\w+)/i) { $foundparam++; if ($1 eq 'y') { $_misc_h{"PDFSupport"}++; } next; } + } + if ($foundparam) { $_misc_h{"TotalMisc"}++; } + } + + # Analyze: favicon (countedtraffic=>1 if favicon) + #------------------------------------------------ + if ($pos_referer >= 0 && $field[$pos_referer] && $urlwithnoquery =~ /$regfavico/o) { + if (($field[$pos_code] != 404 || $urlwithnoquery !~ /\/.+\/favicon\.ico$/i) && ($field[$pos_agent] =~ /MSIE/)) { + # We don't count one hit if (not on root and error) and MSIE + # If error not on root, another hit will be made on root. If not MSIE, hit are made not only for "Adding". + $_misc_h{'AddToFavourites'}++; # Hit on favicon on root or without error, we count it + } + $countedtraffic=1; # favicon is a case that must not be counted anywhere else + } + + # Analyze: Worms (countedtraffic=>2 if worm) + #------------------------------------------- + if (! $countedtraffic) { + if ($LevelForWormsDetection) { + foreach (@WormsSearchIDOrder) { + if ($field[$pos_url] =~ /$_/) { + # It's a worm + my $worm=&UnCompileRegex($_); + if ($Debug) { debug(" Record is a hit from a worm identified by '$worm'",2); } + $worm=$WormsHashID{$worm}||'unknown'; + $_worm_h{$worm}++; + $_worm_k{$worm}+=int($field[$pos_size]); + $_worm_l{$worm}=$timerecord; + $countedtraffic=2; + if ($PageBool) { $_time_nv_p[$hourrecord]++; } + $_time_nv_h[$hourrecord]++; + $_time_nv_k[$hourrecord]+=int($field[$pos_size]); + last; + } + } + } + } + + # Analyze: Status code (countedtraffic=>3 if error) + #-------------------------------------------------- + if (! $countedtraffic) { + if ($LogType eq 'W' || $LogType eq 'S') { # HTTP record or Stream record + if ($ValidHTTPCodes{$field[$pos_code]}) { # Code is valid + if ($field[$pos_code] == 304) { $field[$pos_size]=0; } + } + else { # Code is not valid + if ($field[$pos_code] !~ /^\d\d\d$/) { $field[$pos_code]=999; } + $_errors_h{$field[$pos_code]}++; + $_errors_k{$field[$pos_code]}+=int($field[$pos_size]); + foreach my $code (keys %TrapInfosForHTTPErrorCodes) { + if ($field[$pos_code] == $code) { + # This is an error code which referrer need to be tracked + my $newurl=substr($field[$pos_url],0,$MaxLengthOfStoredURL); + $newurl =~ s/[$URLQuerySeparators].*$//; + $_sider404_h{$newurl}++; + if ($pos_referer >= 0) { + my $newreferer=$field[$pos_referer]; + if (! $URLReferrerWithQuery) { $newreferer =~ s/[$URLQuerySeparators].*$//; } + $_referer404_h{$newurl}=$newreferer; + last; + } + } + } + if ($Debug) { debug(" Record stored in the status code chart (status code=$field[$pos_code])",3); } + $countedtraffic=3; + if ($PageBool) { $_time_nv_p[$hourrecord]++; } + $_time_nv_h[$hourrecord]++; + $_time_nv_k[$hourrecord]+=int($field[$pos_size]); + } + } + elsif ($LogType eq 'M') { # Mail record + if (! $ValidSMTPCodes{$field[$pos_code]}) { # Code is not valid + $_errors_h{$field[$pos_code]}++; + $_errors_k{$field[$pos_code]}+=int($field[$pos_size]); # Size is often 0 when error + if ($Debug) { debug(" Record stored in the status code chart (status code=$field[$pos_code])",3); } + $countedtraffic=3; + if ($PageBool) { $_time_nv_p[$hourrecord]++; } + $_time_nv_h[$hourrecord]++; + $_time_nv_k[$hourrecord]+=int($field[$pos_size]); + } + } + elsif ($LogType eq 'F') { # FTP record + } + } + + # Analyze: Robot from robot database (countedtraffic=>4 if robot) + #---------------------------------------------------------------- + if (! $countedtraffic) { + if ($pos_agent >= 0) { + if ($DecodeUA) { $field[$pos_agent] =~ s/%20/_/g; } # This is to support servers (like Roxen) that writes user agent with %20 in it + $UserAgent=$field[$pos_agent]; + + if ($LevelForRobotsDetection) { + + my $uarobot=$TmpRobot{$UserAgent}; + if (! $uarobot) { + #study $UserAgent; Does not increase speed + foreach (@RobotsSearchIDOrder) { + if ($UserAgent =~ /$_/) { + my $bot=&UnCompileRegex($_); + $TmpRobot{$UserAgent}=$uarobot="$bot"; # Last time, we won't search if robot or not. We know it is. + if ($Debug) { debug(" UserAgent '$UserAgent' is added to TmpRobot with value '$bot'",2); } + last; + } + } + if (! $uarobot) { # Last time, we won't search if robot or not. We know it's not. + $TmpRobot{$UserAgent}=$uarobot='-'; + } + } + if ($uarobot ne '-') { + # If robot, we stop here + if ($Debug) { debug(" UserAgent '$UserAgent' contains robot ID '$uarobot'",2); } + $_robot_h{$uarobot}++; + $_robot_k{$uarobot}+=int($field[$pos_size]); + $_robot_l{$uarobot}=$timerecord; + if ($urlwithnoquery =~ /$regrobot/o) { $_robot_r{$uarobot}++; } + $countedtraffic=4; + if ($PageBool) { $_time_nv_p[$hourrecord]++; } + $_time_nv_h[$hourrecord]++; + $_time_nv_k[$hourrecord]+=int($field[$pos_size]); + } + } + } + } + + # Analyze: Robot from "hit on robots.txt" file (countedtraffic=>5 if robot) + # ------------------------------------------------------------------------- + if (! $countedtraffic) { + if ($urlwithnoquery =~ /$regrobot/o) { + if ($Debug) { debug(" It's an unknown robot",2); } + $_robot_h{'unknown'}++; + $_robot_k{'unknown'}+=int($field[$pos_size]); + $_robot_l{'unknown'}=$timerecord; + $_robot_r{'unknown'}++; + $countedtraffic=5; # Must not be counted somewhere else + if ($PageBool) { $_time_nv_p[$hourrecord]++; } + $_time_nv_h[$hourrecord]++; + $_time_nv_k[$hourrecord]+=int($field[$pos_size]); + } + } + + # Analyze: File type - Compression + #--------------------------------- + if (! $countedtraffic) { + if ($LevelForFileTypesDetection) { + $_filetypes_h{$extension}++; + $_filetypes_k{$extension}+=int($field[$pos_size]); # TODO can cause a warning + # Compression + if ($pos_gzipin>=0 && $field[$pos_gzipin]) { # If in and out in log + my ($notused,$in)=split(/:/,$field[$pos_gzipin]); + my ($notused1,$out,$notused2)=split(/:/,$field[$pos_gzipout]); + if ($out) { + $_filetypes_gz_in{$extension}+=$in; + $_filetypes_gz_out{$extension}+=$out; + } + } + elsif ($pos_compratio>=0 && ($field[$pos_compratio] =~ /(\d+)/)) { # Calculate in/out size from percentage + if ($fieldlib[$pos_compratio] eq 'gzipratio') { + # with mod_gzip: % is size (before-after)/before (low for jpg) ?????????? + $_filetypes_gz_in{$extension}+=int($field[$pos_size]*100/((100-$1)||1)); + } else { + # with mod_deflate: % is size after/before (high for jpg) + $_filetypes_gz_in{$extension}+=int($field[$pos_size]*100/($1||1)); + } + $_filetypes_gz_out{$extension}+=int($field[$pos_size]); + } + } + + # Analyze: Date - Hour - Pages - Hits - Kilo + #------------------------------------------- + if ($PageBool) { + # Replace default page name with / only ('if' is to increase speed when only 1 value in @DefaultFile) + if (@DefaultFile > 1) { foreach my $elem (@DefaultFile) { if ($field[$pos_url] =~ s/\/$elem$/\//o) { last; } } } + else { $field[$pos_url] =~ s/$regdefault/\//o; } + # FirstTime and LastTime are First and Last human visits (so changed if access to a page) + $FirstTime{$lastprocesseddate}||=$timerecord; + $LastTime{$lastprocesseddate}=$timerecord; + $DayPages{$yearmonthdayrecord}++; + $_url_p{$field[$pos_url]}++; #Count accesses for page (page) + $_url_k{$field[$pos_url]}+=int($field[$pos_size]); + $_time_p[$hourrecord]++; #Count accesses for hour (page) + # TODO Use an id for hash key of url + # $_url_t{$_url_id} + } + $_time_h[$hourrecord]++; + $_time_k[$hourrecord]+=int($field[$pos_size]); + $DayHits{$yearmonthdayrecord}++; #Count accesses for hour (hit) + $DayBytes{$yearmonthdayrecord}+=int($field[$pos_size]); #Count accesses for hour (kb) + + # Analyze: Login + #--------------- + if ($pos_logname>=0 && $field[$pos_logname] && $field[$pos_logname] ne '-') { + $field[$pos_logname] =~ s/ /_/g; # This is to allow space in logname + if ($LogFormat eq '6') { $field[$pos_logname] =~ s/^\"//; $field[$pos_logname] =~ s/\"$//;} # logname field has " with Domino 6+ + if ($AuthenticatedUsersNotCaseSensitive) { $field[$pos_logname]=lc($field[$pos_logname]); } + + # We found an authenticated user + if ($PageBool) { $_login_p{$field[$pos_logname]}++; } #Count accesses for page (page) + $_login_h{$field[$pos_logname]}++; #Count accesses for page (hit) + $_login_k{$field[$pos_logname]}+=int($field[$pos_size]); #Count accesses for page (kb) + $_login_l{$field[$pos_logname]}=$timerecord; + } + } + + # Do DNS lookup + #-------------- + my $Host=$field[$pos_host]; + my $HostResolved=''; + + if (! $countedtraffic) { + my $ip=0; + if ($DNSLookup) { # DNS lookup is 1 or 2 + if ($Host =~ /$regipv4/o) { $ip=4; } # IPv4 + elsif ($Host =~ /$regipv6/o) { $ip=6; } # IPv6 + if ($ip) { + # Check in static DNS cache file + $HostResolved=$MyDNSTable{$Host}; + if ($HostResolved) { + if ($Debug) { debug(" DNS lookup asked for $Host and found in static DNS cache file: $HostResolved",4); } + } + elsif ($DNSLookup==1) { + # Check in session cache (dynamic DNS cache file + session DNS cache) + $HostResolved=$TmpDNSLookup{$Host}; + if (! $HostResolved) { + if (@SkipDNSLookupFor && &SkipDNSLookup($Host)) { + $HostResolved=$TmpDNSLookup{$Host}='*'; + if ($Debug) { debug(" No need of reverse DNS lookup for $Host, skipped at user request.",4); } + } + else { + if ($ip == 4) { + my $lookupresult=gethostbyaddr(pack("C4",split(/\./,$Host)),AF_INET); # This is very slow, may spend 20 seconds + if (! $lookupresult || $lookupresult =~ /$regipv4/o || ! IsAscii($lookupresult)) { + $TmpDNSLookup{$Host}=$HostResolved='*'; + } + else { + $TmpDNSLookup{$Host}=$HostResolved=$lookupresult; + } + if ($Debug) { debug(" Reverse DNS lookup for $Host done: $HostResolved",4); } + } + elsif ($ip == 6) { + if ($PluginsLoaded{'GetResolvedIP'}{'ipv6'}) { + my $lookupresult=GetResolvedIP_ipv6($Host); + if (! $lookupresult || ! IsAscii($lookupresult)) { + $TmpDNSLookup{$Host}=$HostResolved='*'; + } + else { + $TmpDNSLookup{$Host}=$HostResolved=$lookupresult; + } + } else { + $TmpDNSLookup{$Host}=$HostResolved='*'; + warning("Reverse DNS lookup for $Host not available without ipv6 plugin enabled."); + } + } + else { error("Bad value vor ip"); } + } + } + } + else { + $HostResolved='*'; + if ($Debug) { debug(" DNS lookup by static DNS cache file asked for $Host but not found.",4); } + } + } + else { + if ($Debug) { debug(" DNS lookup asked for $Host but this is not an IP address.",4); } + $DNSLookupAlreadyDone=$LogFile; + } + } + else { + if ($Host =~ /$regipv4/o) { $HostResolved='*'; $ip=4; } # IPv4 + elsif ($Host =~ /$regipv6/o) { $HostResolved='*'; $ip=6; } # IPv6 + if ($Debug) { debug(" No DNS lookup asked.",4); } + } + + # Analyze: Country (Top-level domain) + #------------------------------------ + if ($Debug) { debug(" Search country (Host=$Host HostResolved=$HostResolved ip=$ip)",4); } + my $Domain='ip'; + # Set $HostResolved to host and resolve domain + if ($HostResolved eq '*') { + # $Host is an IP address and is not resolved (failed or not asked) or resolution gives an IP address + $HostResolved = $Host; + # Resolve Domain + if ($PluginsLoaded{'GetCountryCodeByAddr'}{'geoip'}) { $Domain=GetCountryCodeByAddr_geoip($HostResolved); } + # elsif ($PluginsLoaded{'GetCountryCodeByAddr'}{'geoip_region_maxmind'}) { $Domain=GetCountryCodeByAddr_geoip_region_maxmind($HostResolved); } + # elsif ($PluginsLoaded{'GetCountryCodeByAddr'}{'geoip_city_maxmind'}) { $Domain=GetCountryCodeByAddr_geoip_city_maxmind($HostResolved); } + elsif ($PluginsLoaded{'GetCountryCodeByAddr'}{'geoipfree'}) { $Domain=GetCountryCodeByAddr_geoipfree($HostResolved); } + if ($AtLeastOneSectionPlugin) { + foreach my $pluginname (keys %{$PluginsLoaded{'SectionProcessIp'}}) { + my $function="SectionProcessIp_$pluginname"; + if ($Debug) { debug(" Call to plugin function $function",5); } + &$function($HostResolved); + } + } + } + else { + # $Host was already a host name ($ip=0, $Host=name, $HostResolved='') or has been resolved ($ip>0, $Host=ip, $HostResolved defined) + $HostResolved = lc($HostResolved?$HostResolved:$Host); + # Resolve Domain + if ($ip) { # If we have ip, we use it in priority instead of hostname + if ($PluginsLoaded{'GetCountryCodeByAddr'}{'geoip'}) { $Domain=GetCountryCodeByAddr_geoip($Host); } + # elsif ($PluginsLoaded{'GetCountryCodeByAddr'}{'geoip_region_maxmind'}) { $Domain=GetCountryCodeByAddr_geoip_region_maxmind($Host); } + # elsif ($PluginsLoaded{'GetCountryCodeByAddr'}{'geoip_city_maxmind'}) { $Domain=GetCountryCodeByAddr_geoip_city_maxmind($Host); } + elsif ($PluginsLoaded{'GetCountryCodeByAddr'}{'geoipfree'}) { $Domain=GetCountryCodeByAddr_geoipfree($Host); } + elsif ($HostResolved =~ /\.(\w+)$/) { $Domain=$1; } + if ($AtLeastOneSectionPlugin) { + foreach my $pluginname (keys %{$PluginsLoaded{'SectionProcessIp'}}) { + my $function="SectionProcessIp_$pluginname"; + if ($Debug) { debug(" Call to plugin function $function",5); } + &$function($Host); + } + } + } + else { + if ($PluginsLoaded{'GetCountryCodeByName'}{'geoip'}) { $Domain=GetCountryCodeByName_geoip($HostResolved); } + # elsif ($PluginsLoaded{'GetCountryCodeByName'}{'geoip_region_maxmind'}) { $Domain=GetCountryCodeByName_geoip_region_maxmind($HostResolved); } + # elsif ($PluginsLoaded{'GetCountryCodeByName'}{'geoip_city_maxmind'}) { $Domain=GetCountryCodeByName_geoip_city_maxmind($HostResolved); } + elsif ($PluginsLoaded{'GetCountryCodeByName'}{'geoipfree'}) { $Domain=GetCountryCodeByName_geoipfree($HostResolved); } + elsif ($HostResolved =~ /\.(\w+)$/) { $Domain=$1; } + if ($AtLeastOneSectionPlugin) { + foreach my $pluginname (keys %{$PluginsLoaded{'SectionProcessHostname'}}) { + my $function="SectionProcessHostname_$pluginname"; + if ($Debug) { debug(" Call to plugin function $function",5); } + &$function($HostResolved); + } + } + } + } + # Store country + if ($PageBool) { $_domener_p{$Domain}++; } + $_domener_h{$Domain}++; + $_domener_k{$Domain}+=int($field[$pos_size]); + + # Analyze: Host, URL entry+exit and Session + #------------------------------------------ + if ($PageBool) { + my $timehostl=$_host_l{$HostResolved}; + if ($timehostl) { + # A visit for this host was already detected + # TODO everywhere there is $VISITTIMEOUT + # $timehostl =~ /^\d\d\d\d\d\d(\d\d)/; my $daytimehostl=$1; + # if ($timerecord > ($timehostl+$VISITTIMEOUT+($dateparts[3]>$daytimehostl?$NEWDAYVISITTIMEOUT:0))) { + if ($timerecord > ($timehostl+$VISITTIMEOUT)) { + # This is a second visit or more + if (! $_waithost_s{$HostResolved}) { + # This is a second visit or more + # We count 'visit','exit','entry','DayVisits' + if ($Debug) { debug(" This is a second visit for $HostResolved.",4); } + my $timehosts=$_host_s{$HostResolved}; + my $page=$_host_u{$HostResolved}; + if ($page) { $_url_x{$page}++; } + $_url_e{$field[$pos_url]}++; + $DayVisits{$yearmonthdayrecord}++; + # We can't count session yet because we don't have the start so + # we save params of first 'wait' session + $_waithost_l{$HostResolved}=$timehostl; + $_waithost_s{$HostResolved}=$timehosts; + $_waithost_u{$HostResolved}=$page; + } + else { + # This is third visit or more + # We count 'session','visit','exit','entry','DayVisits' + if ($Debug) { debug(" This is a third visit or more for $HostResolved.",4); } + my $timehosts=$_host_s{$HostResolved}; + my $page=$_host_u{$HostResolved}; + if ($page) { $_url_x{$page}++; } + $_url_e{$field[$pos_url]}++; + $DayVisits{$yearmonthdayrecord}++; + if ($timehosts) { $_session{GetSessionRange($timehosts,$timehostl)}++; } + } + # Save new session properties + $_host_s{$HostResolved}=$timerecord; + $_host_l{$HostResolved}=$timerecord; + $_host_u{$HostResolved}=$field[$pos_url]; + } + elsif ($timerecord > $timehostl) { + # This is a same visit we can count + if ($Debug) { debug(" This is same visit still running for $HostResolved. host_l/host_u changed to $timerecord/$field[$pos_url]",4); } + $_host_l{$HostResolved}=$timerecord; + $_host_u{$HostResolved}=$field[$pos_url]; + } + elsif ($timerecord == $timehostl) { + # This is a same visit we can count + if ($Debug) { debug(" This is same visit still running for $HostResolved. host_l/host_u changed to $timerecord/$field[$pos_url]",4); } + $_host_u{$HostResolved}=$field[$pos_url]; + } + elsif ($timerecord < $_host_s{$HostResolved}) { + # Should happens only with not correctly sorted log files + if ($Debug) { debug(" This is same visit still running for $HostResolved with start not in order. host_s changed to $timerecord (entry page also changed if first visit)",4); } + if (! $_waithost_s{$HostResolved}) { + # We can reorder entry page only if it's the first visit found in this update run (The saved entry page was $_waithost_e if $_waithost_s{$HostResolved} is not defined. If second visit or more, entry was directly counted and not saved) + $_waithost_e{$HostResolved}=$field[$pos_url]; + } + else { + # We can't change entry counted as we dont't know what was the url counted as entry + } + $_host_s{$HostResolved}=$timerecord; + } + else { + if ($Debug) { debug(" This is same visit still running for $HostResolved with hit between start and last hits. No change",4); } + } + } + else { + # This is a new visit (may be). First new visit found for this host. We save in wait array the entry page to count later + if ($Debug) { debug(" New session (may be) for $HostResolved. Save in wait array to see later",4); } + $_waithost_e{$HostResolved}=$field[$pos_url]; + # Save new session properties + $_host_u{$HostResolved}=$field[$pos_url]; + $_host_s{$HostResolved}=$timerecord; + $_host_l{$HostResolved}=$timerecord; + } + $_host_p{$HostResolved}++; + } + $_host_h{$HostResolved}++; + $_host_k{$HostResolved}+=int($field[$pos_size]); + + # Analyze: Browser - OS + #---------------------- + if ($pos_agent >= 0 && $UserAgent) { + + if ($LevelForBrowsersDetection) { + + # Analyze: Browser + #----------------- + my $uabrowser=$TmpBrowser{$UserAgent}; + if (! $uabrowser) { + my $found=1; + # IE ? + if ($UserAgent =~ /$regvermsie/o && $UserAgent !~ /$regnotie/o) { + $_browser_h{"msie$2"}++; + $TmpBrowser{$UserAgent}="msie$2"; + } + # Firefox ? + elsif ($UserAgent =~ /$regverfirefox/o) { + $_browser_h{"firefox$1"}++; + $TmpBrowser{$UserAgent}="firefox$1"; + } + # Subversion ? + elsif ($UserAgent =~ /$regversvn/o) { + $_browser_h{"svn$1"}++; + $TmpBrowser{$UserAgent}="svn$1"; + } + # Netscape 6.x, 7.x ... ? + elsif ($UserAgent =~ /$regvernetscape/o) { + $_browser_h{"netscape$1"}++; + $TmpBrowser{$UserAgent}="netscape$1"; + } + # Netscape 3.x, 4.x ... ? + elsif ($UserAgent =~ /$regvermozilla/o && $UserAgent !~ /$regnotnetscape/o) { + $_browser_h{"netscape$2"}++; + $TmpBrowser{$UserAgent}="netscape$2"; + } + # Other known browsers ? + else { + $found=0; + foreach (@BrowsersSearchIDOrder) { # Search ID in order of BrowsersSearchIDOrder + if ($UserAgent =~ /$_/) { + my $browser=&UnCompileRegex($_); + # TODO If browser is in a family, use version + $_browser_h{"$browser"}++; + $TmpBrowser{$UserAgent}="$browser"; + $found=1; + last; + } + } + } + # Unknown browser ? + if (!$found) { + $_browser_h{'Unknown'}++; + $TmpBrowser{$UserAgent}='Unknown'; + my $newua=$UserAgent; $newua =~ tr/\+ /__/; + $_unknownrefererbrowser_l{$newua}=$timerecord; + } + } + else { + $_browser_h{$uabrowser}++; + if ($uabrowser eq 'Unknown') { + my $newua=$UserAgent; $newua =~ tr/\+ /__/; + $_unknownrefererbrowser_l{$newua}=$timerecord; + } + } + + } + + if ($LevelForOSDetection) { + + # Analyze: OS + #------------ + my $uaos=$TmpOS{$UserAgent}; + if (! $uaos) { + my $found=0; + # in OSHashID list ? + foreach (@OSSearchIDOrder) { # Search ID in order of OSSearchIDOrder + if ($UserAgent =~ /$_/) { + my $osid=$OSHashID{&UnCompileRegex($_)}; + $_os_h{"$osid"}++; + $TmpOS{$UserAgent}="$osid"; + $found=1; + last; + } + } + # Unknown OS ? + if (!$found) { + $_os_h{'Unknown'}++; + $TmpOS{$UserAgent}='Unknown'; + my $newua=$UserAgent; $newua =~ tr/\+ /__/; + $_unknownreferer_l{$newua}=$timerecord; + } + } + else { + $_os_h{$uaos}++; + if ($uaos eq 'Unknown') { + my $newua=$UserAgent; $newua =~ tr/\+ /__/; + $_unknownreferer_l{$newua}=$timerecord; + } + } + + } + + } + else { + $_browser_h{'Unknown'}++; + $_os_h{'Unknown'}++; + } + + # Analyze: Referer + #----------------- + my $found=0; + if ($pos_referer >= 0 && $LevelForRefererAnalyze && $field[$pos_referer]) { + + # Direct ? + if ($field[$pos_referer] eq '-' || $field[$pos_referer] eq 'bookmarks') { # "bookmarks" is sent by Netscape, '-' by all others browsers + # Direct access + if ($PageBool) { $_from_p[0]++; } + $_from_h[0]++; + $found=1; + } + else { + $field[$pos_referer] =~ /$regreferer/o; + my $refererprot=$1; + my $refererserver=($2||'').(! $3 || $3 eq ':80'?'':$3); # refererserver is www.xxx.com or www.xxx.com:81 but not www.xxx.com:80 + # HTML link ? + if ($refererprot =~ /^http/i) { + #if ($Debug) { debug(" Analyze referer refererprot=$refererprot refererserver=$refererserver",5); } + + # Kind of origin + if (!$TmpRefererServer{$refererserver}) { # is "=" if same site, "search egine key" if search engine, not defined otherwise + if ($refererserver =~ /$reglocal/o) { + # Intern (This hit came from another page of the site) + if ($Debug) { debug(" Server '$refererserver' is added to TmpRefererServer with value '='",2); } + $TmpRefererServer{$refererserver}='='; + $found=1; + } + else { + foreach (@HostAliases) { + if ($refererserver =~ /$_/) { + # Intern (This hit came from another page of the site) + if ($Debug) { debug(" Server '$refererserver' is added to TmpRefererServer with value '='",2); } + $TmpRefererServer{$refererserver}='='; + $found=1; + last; + } + } + if (! $found) { + # Extern (This hit came from an external web site). + + if ($LevelForSearchEnginesDetection) { + + foreach (@SearchEnginesSearchIDOrder) { # Search ID in order of SearchEnginesSearchIDOrder + if ($refererserver =~ /$_/) { + my $key=&UnCompileRegex($_); + if (! $NotSearchEnginesKeys{$key} || $refererserver !~ /$NotSearchEnginesKeys{$key}/i) { + # This hit came from the search engine $key + if ($Debug) { debug(" Server '$refererserver' is added to TmpRefererServer with value '$key'",2); } + $TmpRefererServer{$refererserver}=$SearchEnginesHashID{$key}; + $found=1; + } + last; + } + } + + } + } + } + } + + my $tmprefererserver=$TmpRefererServer{$refererserver}; + if ($tmprefererserver) { + if ($tmprefererserver eq '=') { + # Intern (This hit came from another page of the site) + if ($PageBool) { $_from_p[4]++; } + $_from_h[4]++; + $found=1; + } + else { + # This hit came from a search engine + if ($PageBool) { $_from_p[2]++; $_se_referrals_p{$tmprefererserver}++; } + $_from_h[2]++; + $_se_referrals_h{$tmprefererserver}++; + $found=1; + if ($PageBool && $LevelForKeywordsDetection) { + # we will complete %_keyphrases hash array + my @refurl=split(/\?/,$field[$pos_referer],2); # TODO Use \? or [$URLQuerySeparators] ? + if ($refurl[1]) + { + # Extract params of referer query string (q=cache:mmm:www/zzz+aaa+bbb q=aaa+bbb/ccc key=ddd%20eee lang_en ie=UTF-8 ...) + if ($SearchEnginesKnownUrl{$tmprefererserver}) { # Search engine with known URL syntax + foreach my $param (split(/&/,$KeyWordsNotSensitive?lc($refurl[1]):$refurl[1])) { + if ($param =~ s/^$SearchEnginesKnownUrl{$tmprefererserver}//) { + # We found good parameter + # Now param is keyphrase: "cache:mmm:www/zzz+aaa+bbb/ccc+ddd%20eee'fff,ggg" + $param =~ s/^(cache|related):[^\+]+//; # Should be useless since this is for hit on 'not pages' + &ChangeWordSeparatorsIntoSpace($param); # Change [ aaa+bbb/ccc+ddd%20eee'fff,ggg ] into [ aaa bbb/ccc ddd eee fff ggg] + $param =~ s/^ +//; $param =~ s/ +$//; # Trim + $param =~ tr/ /\+/s; + if ((length $param) > 0) { $_keyphrases{$param}++; } + last; + } + } + } + elsif ($LevelForKeywordsDetection >= 2) { # Search engine with unknown URL syntax + foreach my $param (split(/&/,$KeyWordsNotSensitive?lc($refurl[1]):$refurl[1])) { + my $foundexcludeparam=0; + foreach my $paramtoexclude (@WordsToCleanSearchUrl) { + if ($param =~ /$paramtoexclude/i) { $foundexcludeparam=1; last; } # Not the param with search criteria + } + if ($foundexcludeparam) { next; } + # We found good parameter + $param =~ s/.*=//; + # Now param is keyphrase: "aaa+bbb/ccc+ddd%20eee'fff,ggg" + $param =~ s/^(cache|related):[^\+]+//; # Should be useless since this is for hit on 'not pages' + &ChangeWordSeparatorsIntoSpace($param); # Change [ aaa+bbb/ccc+ddd%20eee'fff,ggg ] into [ aaa bbb/ccc ddd eee fff ggg ] + $param =~ s/^ +//; $param =~ s/ +$//; # Trim + $param =~ tr/ /\+/s; + if ((length $param) > 2) { $_keyphrases{$param}++; last; } + } + } + } # End of elsif refurl[1] + elsif ($SearchEnginesWithKeysNotInQuery{$tmprefererserver}) + { +# debug("xxx".$refurl[0]); + # If search engine with key inside page url like a9 (www.a9.com/searchkey1%20searchkey2) + if ($refurl[0] =~ /$SearchEnginesKnownUrl{$tmprefererserver}(.*)$/) { + my $param=$1; + &ChangeWordSeparatorsIntoSpace($param); + $param =~ tr/ /\+/s; + if ((length $param) > 0) { $_keyphrases{$param}++; } + } + } + + } + } + } # End of if ($TmpRefererServer) + else { + # This hit came from a site other than a search engine + if ($PageBool) { $_from_p[3]++; } + $_from_h[3]++; + # http://www.mysite.com/ must be same referer than http://www.mysite.com but .../mypage/ differs of .../mypage + #if ($refurl[0] =~ /^[^\/]+\/$/) { $field[$pos_referer] =~ s/\/$//; } # Code moved in Save_History + # TODO: lowercase the value for referer server to have refering server not case sensitive + if ($URLReferrerWithQuery) { + if ($PageBool) { $_pagesrefs_p{$field[$pos_referer]}++; } + $_pagesrefs_h{$field[$pos_referer]}++; + } + else { + # We discard query for referer + if ($field[$pos_referer]=~/$regreferernoquery/o) { + if ($PageBool) { $_pagesrefs_p{"$1"}++; } + $_pagesrefs_h{"$1"}++; + } + else { + if ($PageBool) { $_pagesrefs_p{$field[$pos_referer]}++; } + $_pagesrefs_h{$field[$pos_referer]}++; + } + } + $found=1; + } + } + + # News Link ? + if (! $found && $refererprot =~ /^news/i) { + $found=1; + if ($PageBool) { $_from_p[5]++; } + $_from_h[5]++; + } + } + } + + # Origin not found + if (!$found) { + if ($ShowUnknownOrigin) { print "Unknown origin: $field[$pos_referer]\n"; } + if ($PageBool) { $_from_p[1]++; } + $_from_h[1]++; + } + + # Analyze: EMail + #--------------- + if ($pos_emails>=0 && $field[$pos_emails]) { + if ($field[$pos_emails] eq '<>') { $field[$pos_emails]='Unknown'; } + elsif ($field[$pos_emails] !~ /\@/) { $field[$pos_emails].="\@$SiteDomain"; } + $_emails_h{lc($field[$pos_emails])}++; #Count accesses for sender email (hit) + $_emails_k{lc($field[$pos_emails])}+=int($field[$pos_size]); #Count accesses for sender email (kb) + $_emails_l{lc($field[$pos_emails])}=$timerecord; + } + if ($pos_emailr>=0 && $field[$pos_emailr]) { + if ($field[$pos_emailr] !~ /\@/) { $field[$pos_emailr].="\@$SiteDomain"; } + $_emailr_h{lc($field[$pos_emailr])}++; #Count accesses for receiver email (hit) + $_emailr_k{lc($field[$pos_emailr])}+=int($field[$pos_size]); #Count accesses for receiver email (kb) + $_emailr_l{lc($field[$pos_emailr])}=$timerecord; + } + } + + # Check cluster + #-------------- + if ($pos_cluster>=0) { + if ($PageBool) { $_cluster_p{$field[$pos_cluster]}++; } #Count accesses for page (page) + $_cluster_h{$field[$pos_cluster]}++; #Count accesses for page (hit) + $_cluster_k{$field[$pos_cluster]}+=int($field[$pos_size]); #Count accesses for page (kb) + } + + # Analyze: Extra + #--------------- + foreach my $extranum (1..@ExtraName-1) { + if ($Debug) { debug(" Process extra analyze $extranum",4); } + + # Check code + my $conditionok=0; + if ($ExtraCodeFilter[$extranum]) + { + foreach my $condnum (0..@{$ExtraCodeFilter[$extranum]}-1) { + if ($Debug) { debug(" Check code '$field[$pos_code]' must be '$ExtraCodeFilter[$extranum][$condnum]'",5); } + if ($field[$pos_code] eq "$ExtraCodeFilter[$extranum][$condnum]") { $conditionok=1; last; } + } + if (! $conditionok && @{$ExtraCodeFilter[$extranum]}) { next; } # End for this section + if ($Debug) { debug(" No check on code or code is OK. Now we check other conditions.",5); } + } + + # Check conditions + $conditionok=0; + foreach my $condnum (0..@{$ExtraConditionType[$extranum]}-1) { + my $conditiontype=$ExtraConditionType[$extranum][$condnum]; + my $conditiontypeval=$ExtraConditionTypeVal[$extranum][$condnum]; + if ($conditiontype eq 'URL') { + if ($Debug) { debug(" Check condition '$conditiontype' must contain '$conditiontypeval' in '$urlwithnoquery'",5); } + if ($urlwithnoquery =~ /$conditiontypeval/) { $conditionok=1; last; } + } + elsif ($conditiontype eq 'QUERY_STRING') { + if ($Debug) { debug(" Check condition '$conditiontype' must contain '$conditiontypeval' in '$standalonequery'",5); } + if ($standalonequery =~ /$conditiontypeval/) { $conditionok=1; last; } + } + elsif ($conditiontype eq 'URLWITHQUERY') { + if ($Debug) { debug(" Check condition '$conditiontype' must contain '$conditiontypeval' in '$urlwithnoquery$tokenquery$standalonequery'",5); } + if ("$urlwithnoquery$tokenquery$standalonequery" =~ /$conditiontypeval/) { $conditionok=1; last; } + } + elsif ($conditiontype eq 'REFERER') { + if ($Debug) { debug(" Check condition '$conditiontype' must contain '$conditiontypeval' in '$field[$pos_referer]'",5); } + if ($field[$pos_referer] =~ /$conditiontypeval/) { $conditionok=1; last; } + } + elsif ($conditiontype eq 'UA') { + if ($Debug) { debug(" Check condition '$conditiontype' must contain '$conditiontypeval' in '$field[$pos_agent]'",5); } + if ($field[$pos_agent] =~ /$conditiontypeval/) { $conditionok=1; last; } + } + elsif ($conditiontype eq 'HOST') { + if ($Debug) { debug(" Check condition '$conditiontype' must contain '$conditiontypeval' in '$field[$pos_host]'",5); } + if ($HostResolved =~ /$conditiontypeval/) { $conditionok=1; last; } + } + elsif ($conditiontype eq 'VHOST') { + if ($Debug) { debug(" Check condision '$conditiontype' must contain '$conditiontypeval' in '$field[$pos_vh]'",5); } + if ($field[$pos_vh] =~ /$conditiontypeval/) { $conditionok=1; last; } + } + elsif ($conditiontype =~ /extra(\d+)/i) { + if ($Debug) { debug(" Check condition '$conditiontype' must contain '$conditiontypeval' in '$field[$pos_extra[$1]]'",5); } + if ($field[$pos_extra[$1]] =~ /$conditiontypeval/) { $conditionok=1; last; } + } + else { error("Wrong value of parameter ExtraSectionCondition$extranum"); } + } + if (! $conditionok && @{$ExtraConditionType[$extranum]}) { next; } # End for this section + if ($Debug) { debug(" No condition or condition is OK. Now we extract value for first column of extra chart.",5); } + + # Determine actual column value to use. + my $rowkeyval; + my $rowkeyok=0; + foreach my $rowkeynum (0..@{$ExtraFirstColumnValuesType[$extranum]}-1) { + my $rowkeytype=$ExtraFirstColumnValuesType[$extranum][$rowkeynum]; + my $rowkeytypeval=$ExtraFirstColumnValuesTypeVal[$extranum][$rowkeynum]; + if ($rowkeytype eq 'URL') { + if ($urlwithnoquery =~ /$rowkeytypeval/) { $rowkeyval = "$1"; $rowkeyok = 1; last; } + } + elsif ($rowkeytype eq 'QUERY_STRING') { + if ($Debug) { debug(" Extract value from '$standalonequery' with regex '$rowkeytypeval'.",5); } + if ($standalonequery =~ /$rowkeytypeval/) { $rowkeyval = "$1"; $rowkeyok = 1; last; } + } + elsif ($rowkeytype eq 'URLWITHQUERY') { + if ("$urlwithnoquery$tokenquery$standalonequery" =~ /$rowkeytypeval/) { $rowkeyval = "$1"; $rowkeyok = 1; last; } + } + elsif ($rowkeytype eq 'REFERER') { + if ($field[$pos_referer] =~ /$rowkeytypeval/) { $rowkeyval = "$1"; $rowkeyok = 1; last; } + } + elsif ($rowkeytype eq 'UA') { + if ($field[$pos_agent] =~ /$rowkeytypeval/) { $rowkeyval = "$1"; $rowkeyok = 1; last; } + } + elsif ($rowkeytype eq 'HOST') { + if ($HostResolved =~ /$rowkeytypeval/) { $rowkeyval = "$1"; $rowkeyok = 1; last; } + } + elsif ($rowkeytype eq 'VHOST') { + if ($field[$pos_vh] =~ /$rowkeytypeval/) { $rowkeyval = "$1"; $rowkeyok = 1; last; } + } + elsif ($rowkeytype =~ /extra(\d+)/i) { + if ($field[$pos_extra[$1]] =~ /$rowkeytypeval/) { $rowkeyval = "$1"; $rowkeyok = 1; last; } + } + else { error("Wrong value of parameter ExtraSectionFirstColumnValues$extranum"); } + } + if (! $rowkeyok) { next; } # End for this section + if ($Debug) { debug(" Key val was found: $rowkeyval",5); } + + # Apply function on $rowkeyval + if ($ExtraFirstColumnFunction[$extranum]) + { + # Todo call function on string $rowkeyval + } + + # Here we got all values to increase counters + if ($PageBool && $ExtraStatTypes[$extranum] =~ /P/i) { ${'_section_' . $extranum . '_p'}{$rowkeyval}++; } + ${'_section_' . $extranum . '_h'}{$rowkeyval}++; # Must be set + if ($ExtraStatTypes[$extranum] =~ /B/i) { ${'_section_' . $extranum . '_k'}{$rowkeyval}+=int($field[$pos_size]); } + if ($ExtraStatTypes[$extranum] =~ /L/i) { + if (${'_section_' . $extranum . '_l'}{$rowkeyval}||0 < $timerecord) { ${'_section_' . $extranum . '_l'}{$rowkeyval}=$timerecord; } + } + # Check to avoid too large extra sections + if (scalar keys %{'_section_' . $extranum . '_h'} > $ExtraTrackedRowsLimit) { + error(<= 20000) { + #if (++$counterforflushtest >= 1) { + if ((scalar keys %_host_u) > ($LIMITFLUSH<<2) || (scalar keys %_url_p) > $LIMITFLUSH) { + # warning("Warning: Try to run AWStats update process more frequently to analyze smaler log files."); + if ($^X =~ /activestate/i || $^X =~ /activeperl/i) { + # We don't flush if perl is activestate to avoid slowing process because of memory hole + } + else { + # Clean tmp hash arrays + #%TmpDNSLookup = (); + %TmpOS = %TmpRefererServer = %TmpRobot = %TmpBrowser = (); + # We flush if perl is not activestate + print "Flush history file on disk"; + if ((scalar keys %_host_u) > ($LIMITFLUSH<<2)) { print " (unique hosts reach flush limit of ".($LIMITFLUSH<<2).")"; } + if ((scalar keys %_url_p) > $LIMITFLUSH) { print " (unique url reach flush limit of ".($LIMITFLUSH).")"; } + print "\n"; + if ($Debug) { + debug("End of set of $counterforflushtest records: Some hash arrays are too large. We flush and clean some.",2); + print " _host_p:".(scalar keys %_host_p)." _host_h:".(scalar keys %_host_h)." _host_k:".(scalar keys %_host_k)." _host_l:".(scalar keys %_host_l)." _host_s:".(scalar keys %_host_s)." _host_u:".(scalar keys %_host_u)."\n"; + print " _url_p:".(scalar keys %_url_p)." _url_k:".(scalar keys %_url_k)." _url_e:".(scalar keys %_url_e)." _url_x:".(scalar keys %_url_x)."\n"; + print " _waithost_e:".(scalar keys %_waithost_e)." _waithost_l:".(scalar keys %_waithost_l)." _waithost_s:".(scalar keys %_waithost_s)." _waithost_u:".(scalar keys %_waithost_u)."\n"; + } + &Read_History_With_TmpUpdate($lastprocessedyear,$lastprocessedmonth,$lastprocessedday,$lastprocessedhour,1,1,"all",($lastlinenb+$NbOfLinesParsed),$lastlineoffset,&CheckSum($_)); + &GetDelaySinceStart(1); $NbOfLinesShowsteps=1; + } + } + $counterforflushtest=0; + } + + } # End of loop for processing new record. + + if ($Debug) { + debug(" _host_p:".(scalar keys %_host_p)." _host_h:".(scalar keys %_host_h)." _host_k:".(scalar keys %_host_k)." _host_l:".(scalar keys %_host_l)." _host_s:".(scalar keys %_host_s)." _host_u:".(scalar keys %_host_u)."\n",1); + debug(" _url_p:".(scalar keys %_url_p)." _url_k:".(scalar keys %_url_k)." _url_e:".(scalar keys %_url_e)." _url_x:".(scalar keys %_url_x)."\n",1); + debug(" _waithost_e:".(scalar keys %_waithost_e)." _waithost_l:".(scalar keys %_waithost_l)." _waithost_s:".(scalar keys %_waithost_s)." _waithost_u:".(scalar keys %_waithost_u)."\n",1); + debug("End of processing log file (AWStats memory cache is TmpDNSLookup=".(scalar keys %TmpDNSLookup)." TmpBrowser=".(scalar keys %TmpBrowser)." TmpOS=".(scalar keys %TmpOS)." TmpRefererServer=".(scalar keys %TmpRefererServer)." TmpRobot=".(scalar keys %TmpRobot).")",1); + } + + # Save current processed break section + # If lastprocesseddate > 0 means there is at least one approved new record in log or at least one existing history file + if ($lastprocesseddate > 0) { # TODO: Do not save if we are sure a flush was just already done + # Get last line + seek(LOG,$lastlineoffset,0); + my $line=; + chomp $line; $line =~ s/\r$//; + if (! $NbOfLinesParsed) { + # TODO If there was no lines parsed (log was empty), we only update LastUpdate line with YYYYMMDDHHMMSS 0 0 0 0 0 + &Read_History_With_TmpUpdate($lastprocessedyear,$lastprocessedmonth,$lastprocessedday,$lastprocessedhour,1,1,"all",($lastlinenb+$NbOfLinesParsed),$lastlineoffset,&CheckSum($line)); + } + else { + &Read_History_With_TmpUpdate($lastprocessedyear,$lastprocessedmonth,$lastprocessedday,$lastprocessedhour,1,1,"all",($lastlinenb+$NbOfLinesParsed),$lastlineoffset,&CheckSum($line)); + } + } + + if ($Debug) { debug("Close log file \"$LogFile\""); } + close LOG || error("Command for pipe '$LogFile' failed"); + + # Process the Rename - Archive - Purge phase + my $renameok=1; my $archiveok=1; + + # Open Log file for writing if PurgeLogFile is on + if ($PurgeLogFile) { + if ($ArchiveLogRecords) { + if ($ArchiveLogRecords == 1) { # For backward compatibility + $ArchiveFileName="$DirData/${PROG}_archive$FileSuffix.log"; + } + else { + $ArchiveFileName="$DirData/${PROG}_archive$FileSuffix.".&Substitute_Tags($ArchiveLogRecords).".log"; + } + open(LOG,"+<$LogFile") || error("Enable to archive log records of \"$LogFile\" into \"$ArchiveFileName\" because source can't be opened for read and write: $!
\n"); + } + else { + open(LOG,"+<$LogFile"); + } + binmode LOG; + } + + # Rename all HISTORYTMP files into HISTORYTXT + &Rename_All_Tmp_History(); + + # Purge Log file if option is on and all renaming are ok + if ($PurgeLogFile) { + # Archive LOG file into ARCHIVELOG + if ($ArchiveLogRecords) { + if ($Debug) { debug("Start of archiving log file"); } + open(ARCHIVELOG,">>$ArchiveFileName") || error("Couldn't open file \"$ArchiveFileName\" to archive log: $!"); + binmode ARCHIVELOG; + while () { + if (! print ARCHIVELOG $_) { $archiveok=0; last; } + } + close(ARCHIVELOG) || error("Archiving failed during closing archive: $!"); + if ($SaveDatabaseFilesWithPermissionsForEveryone) { chmod 0666,"$ArchiveFileName"; } + if ($Debug) { debug("End of archiving log file"); } + } + # If rename and archive ok + if ($renameok && $archiveok) { + if ($Debug) { debug("Purge log file"); } + my $bold=($ENV{'GATEWAY_INTERFACE'}?'':''); + my $unbold=($ENV{'GATEWAY_INTERFACE'}?'':''); + my $br=($ENV{'GATEWAY_INTERFACE'}?'
':''); + truncate(LOG,0) || warning("Warning: $bold$PROG$unbold couldn't purge logfile \"$bold$LogFile$unbold\".$br\nChange your logfile permissions to allow write for your web server CGI process or change PurgeLogFile=1 into PurgeLogFile=0 in configure file and think to purge sometimes manually your logfile (just after running an update process to not loose any not already processed records your log file contains)."); + } + close(LOG); + } + + if ($DNSLookup==1 && $DNSLookupAlreadyDone) { + # DNSLookup warning + my $bold=($ENV{'GATEWAY_INTERFACE'}?'':''); + my $unbold=($ENV{'GATEWAY_INTERFACE'}?'':''); + my $br=($ENV{'GATEWAY_INTERFACE'}?'
':''); + warning("Warning: $bold$PROG$unbold has detected that some hosts names were already resolved in your logfile $bold$DNSLookupAlreadyDone$unbold.$br\nIf DNS lookup was already made by the logger (web server), you should change your setup DNSLookup=$DNSLookup into DNSLookup=0 to increase $PROG speed."); + } + if ($DNSLookup==1 && $NbOfNewLines) { + # Save new DNS last update cache file + Save_DNS_Cache_File(\%TmpDNSLookup,"$DirData/$DNSLastUpdateCacheFile","$FileSuffix"); # Save into file using FileSuffix + } + + if ($EnableLockForUpdate) { + # Remove lock + &Lock_Update(0); + # Restore signals handler + $SIG{INT} = 'DEFAULT'; # 2 + #$SIG{KILL} = 'DEFAULT'; # 9 + #$SIG{TERM} = 'DEFAULT'; # 15 + } + +} +# End of log processing if ($UPdateStats) + + +#--------------------------------------------------------------------- +# SHOW REPORT +#--------------------------------------------------------------------- + +if (scalar keys %HTMLOutput) { + + debug("YearRequired=$YearRequired, MonthRequired=$MonthRequired",2); + debug("DayRequired=$DayRequired, HourRequired=$HourRequired",2); + + my $max_p; my $max_h; my $max_k; my $max_v; + my $total_u; my $total_v; my $total_p; my $total_h; my $total_k; my $total_e; my $total_x; my $total_s; my $total_l; my $total_r; + my $average_u; my $average_v; my $average_p; my $average_h; my $average_k; my $average_s; + my $rest_p; my $rest_h; my $rest_k; my $rest_e; my $rest_x; my $rest_s; my $rest_l; my $rest_r; + my $average_nb; + + # Define the NewLinkParams for main chart + my $NewLinkParams=${QueryString}; + $NewLinkParams =~ s/(^|&|&)update(=\w*|$)//i; + $NewLinkParams =~ s/(^|&|&)output(=\w*|$)//i; + $NewLinkParams =~ s/(^|&|&)staticlinks(=\w*|$)//i; + $NewLinkParams =~ s/(^|&|&)framename=[^&]*//i; + my $NewLinkTarget=''; + if ($DetailedReportsOnNewWindows) { $NewLinkTarget=" target=\"awstatsbis\""; } + if (($FrameName eq 'mainleft' || $FrameName eq 'mainright') && $DetailedReportsOnNewWindows < 2) { + $NewLinkParams.="&framename=mainright"; + $NewLinkTarget=" target=\"mainright\""; + } + $NewLinkParams =~ s/(&|&)+/&/i; + $NewLinkParams =~ s/^&//; $NewLinkParams =~ s/&$//; + if ($NewLinkParams) { $NewLinkParams="${NewLinkParams}&"; } + + if ($FrameName ne 'mainleft') { + + # READING DATA + #------------- + &Init_HashArray(); + + # Lecture des fichiers history + if ($DatabaseBreak eq 'month') { + for (my $ix=12; $ix>=1; $ix--) { + my $stringforload=''; + my $monthix=sprintf("%02s",$ix); + if ($MonthRequired eq 'all' || $monthix eq $MonthRequired) { + $stringforload='all'; # Read full history file + } + elsif (($HTMLOutput{'main'} && $ShowMonthStats) || $HTMLOutput{'alldays'}) { + $stringforload='general time'; # Read general and time sections. + } + if ($stringforload) { + # On charge fichier + &Read_History_With_TmpUpdate($YearRequired,$monthix,'','',0,0,$stringforload); + } + } + } + if ($DatabaseBreak eq 'day') { + my $stringforload='all'; + my $monthix=sprintf("%02s",$MonthRequired); + my $dayix=sprintf("%02s",$DayRequired); + &Read_History_With_TmpUpdate($YearRequired,$monthix,$dayix,'',0,0,$stringforload); + } + if ($DatabaseBreak eq 'hour') { + my $stringforload='all'; + my $monthix=sprintf("%02s",$MonthRequired); + my $dayix=sprintf("%02s",$DayRequired); + my $hourix=sprintf("%02s",$HourRequired); + &Read_History_With_TmpUpdate($YearRequired,$monthix,$dayix,$hourix,0,0,$stringforload); + } + + } + + # HTMLHeadSection + if ($FrameName ne 'index' && $FrameName ne 'mainleft') { + print " \n\n"; + print "$HTMLHeadSection\n"; + print "\n"; + } + + # Call to plugins' function AddHTMLBodyHeader + foreach my $pluginname (keys %{$PluginsLoaded{'AddHTMLBodyHeader'}}) { +# my $function="AddHTMLBodyHeader_$pluginname()"; +# eval("$function"); + my $function="AddHTMLBodyHeader_$pluginname"; + &$function(); + } + + my $WIDTHMENU1=($FrameName eq 'mainleft'?$FRAMEWIDTH:150); + + # TOP BAN + #--------------------------------------------------------------------- + if ($ShowMenu || $FrameName eq 'mainleft') { + my $frame=($FrameName eq 'mainleft'); + + if ($Debug) { debug("ShowTopBan",2); } + print "$Center \n"; + + if ($FrameName ne 'mainleft') { + my $NewLinkParams=${QueryString}; + $NewLinkParams =~ s/(^|&|&)update(=\w*|$)//i; + $NewLinkParams =~ s/(^|&|&)staticlinks(=\w*|$)//i; + $NewLinkParams =~ s/(^|&|&)year=[^&]*//i; + $NewLinkParams =~ s/(^|&|&)month=[^&]*//i; + $NewLinkParams =~ s/(^|&|&)framename=[^&]*//i; + $NewLinkParams =~ s/(&|&)+/&/i; + $NewLinkParams =~ s/^&//; $NewLinkParams =~ s/&$//; + my $NewLinkTarget=''; + if ($FrameName eq 'mainright') { $NewLinkTarget=" target=\"_parent\""; } + print "
\n"; + } + + if ($QueryString !~ /buildpdf/i) { + print "\n"; + print "
\n"; + print "\n"; + } + else { + print "
\n"; + } + + if ($FrameName ne 'mainright') { + # Print Statistics Of + if ($FrameName eq 'mainleft') { + my $shortSiteDomain=$SiteDomain; + if (length($SiteDomain) > 30) { $shortSiteDomain=substr($SiteDomain,0,20)."...".substr($SiteDomain,length($SiteDomain)-5,5); } + print ""; + } + else { print ""; } + + # Logo and flags + if ($FrameName ne 'mainleft') { + if ($LogoLink =~ "http://awstats.sourceforge.net") { + print ""; + } + print "\n"; + } + if ($FrameName ne 'mainleft') { + # Print Last Update + print ""; + print ""; + + # Logo and flags + if ($FrameName eq 'mainright') { + if ($LogoLink =~ "http://awstats.sourceforge.net") { + print ""; + } + + print "\n"; + # Print selected period of analysis (month and year required) + print ""; + print "\n"; + } + if ($QueryString !~ /buildpdf/i) { + print "
$Message[7]:
$shortSiteDomain
$Message[7]: $SiteDomain"; + } + else { + print ""; + } + if (! $StaticLinks) { print "
"; Show_Flag_Links($Lang); } + print "
$Message[35]: "; + if ($LastUpdate) { print Format_Date($LastUpdate,0); } + else { + # Here NbOfOldLines = 0 (because LastUpdate is not defined) + if (! $UpdateStats) { print "$Message[24]"; } + else { print "No qualified records found in log ($NbOfLinesCorrupted corrupted, $NbOfLinesDropped dropped)"; } + + } + print ""; + # Print Update Now link + if ($AllowToUpdateStatsFromBrowser && ! $StaticLinks) { + my $NewLinkParams=${QueryString}; + $NewLinkParams =~ s/(^|&|&)update(=\w*|$)//i; + $NewLinkParams =~ s/(^|&|&)staticlinks(=\w*|$)//i; + $NewLinkParams =~ s/(^|&|&)framename=[^&]*//i; + if ($FrameName eq 'mainright') { $NewLinkParams.="&framename=mainright"; } + $NewLinkParams =~ s/(&|&)+/&/i; + $NewLinkParams =~ s/^&//; $NewLinkParams =~ s/&$//; + if ($NewLinkParams) { $NewLinkParams="${NewLinkParams}&"; } + print "       "; + print "$Message[74]"; + } + print "\n"; + } + else { + print "\n"; + } + if (! $StaticLinks) { print "
"; Show_Flag_Links($Lang); } + print "
$Message[133]:"; + if ($ENV{'GATEWAY_INTERFACE'} || !$StaticLinks) { + print "\n"; + print "\n"; + print "\n"; + if ($SiteConfig) { print "\n"; } + if ($DirConfig) { print "\n"; } + if ($QueryString =~ /lang=(\w+)/i) { print "\n"; } + if ($QueryString =~ /debug=(\d+)/i) { print "\n"; } + if ($FrameName eq 'mainright') { print "\n"; } + print ""; + } + else { + print ""; + if ($DayRequired) { print "$Message[4] $DayRequired - "; } + if ($MonthRequired eq 'all') { print "$Message[6] $YearRequired"; } + else { print "$Message[5] $MonthNumLib{$MonthRequired} $YearRequired"; } + print ""; + } + print "
\n"; + print "
\n"; + } + else { + print "\n"; + } + + if ($FrameName ne 'mainleft') { print "
\n"; } + else { print "
\n"; } + print "\n"; + } + + # Call to plugins' function AddHTMLMenuHeader + foreach my $pluginname (keys %{$PluginsLoaded{'AddHTMLMenuHeader'}}) { +# my $function="AddHTMLMenuHeader_$pluginname()"; +# eval("$function"); + my $function="AddHTMLMenuHeader_$pluginname"; + &$function(); + } + + # MENU + #--------------------------------------------------------------------- + if ($ShowMenu || $FrameName eq 'mainleft') { + my $frame=($FrameName eq 'mainleft'); + + if ($Debug) { debug("ShowMenu",2); } + + # Print menu links + if (($HTMLOutput{'main'} && $FrameName ne 'mainright') || $FrameName eq 'mainleft') { # If main page asked + # Define link anchor + my $linkanchor=($FrameName eq 'mainleft'?"$AWScript?${NewLinkParams}":""); + if ($linkanchor && ($linkanchor !~ /framename=mainright/)) { $linkanchor.="framename=mainright"; } + $linkanchor =~ s/(&|&)$//; $linkanchor=XMLEncode("$linkanchor"); + # Define target + my $targetpage=($FrameName eq 'mainleft'?" target=\"mainright\"":""); + # Print Menu + my $linetitle; # TODO a virer + if (! $PluginsLoaded{'ShowMenu'}{'menuapplet'}) { + my $menuicon=0; # TODO a virer + # Menu HTML + print "\n"; + if ($FrameName eq 'mainleft' && $ShowMonthStats) { print ($frame?"":""); print "$Message[128]"; print ($frame?"\n":"   "); } + my %menu=(); my %menulink=(); my %menutext=(); + # When + %menu=('month'=>$ShowMonthStats?1:0,'daysofmonth'=>$ShowDaysOfMonthStats?2:0,'daysofweek'=>$ShowDaysOfWeekStats?3:0,'hours'=>$ShowHoursStats?4:0); + %menulink=('month'=>1,'daysofmonth'=>1,'daysofweek'=>1,'hours'=>1); + %menutext=('month'=>$Message[162],'daysofmonth'=>$Message[138],'daysofweek'=>$Message[91],'hours'=>$Message[20]); + ShowMenuCateg('when',$Message[93],'menu4.png',$frame,$targetpage,$linkanchor,$NewLinkParams,$NewLinkTarget,\%menu,\%menulink,\%menutext); + # Who + %menu=('countries'=>$ShowDomainsStats?1:0,'alldomains'=>$ShowDomainsStats?2:0,'visitors'=>$ShowHostsStats?3:0,'allhosts'=>$ShowHostsStats?4:0,'lasthosts'=>($ShowHostsStats =~ /L/i)?5:0,'unknownip'=>$ShowHostsStats?6:0,'logins'=>$ShowAuthenticatedUsers?7:0,'alllogins'=>$ShowAuthenticatedUsers?8:0,'lastlogins'=>($ShowAuthenticatedUsers =~ /L/i)?9:0,'emailsenders'=>$ShowEMailSenders?10:0,'allemails'=>$ShowEMailSenders?11:0,'lastemails'=>($ShowEMailSenders =~ /L/i)?12:0,'emailreceivers'=>$ShowEMailReceivers?13:0,'allemailr'=>$ShowEMailReceivers?14:0,'lastemailr'=>($ShowEMailReceivers =~ /L/i)?15:0,'robots'=>$ShowRobotsStats?16:0,'allrobots'=>$ShowRobotsStats?17:0,'lastrobots'=>($ShowRobotsStats =~ /L/i)?18:0,'worms'=>$ShowWormsStats?19:0); + %menulink=('countries'=>1,'alldomains'=>2,'visitors'=>1,'allhosts'=>2,'lasthosts'=>2,'unknownip'=>2,'logins'=>1,'alllogins'=>2,'lastlogins'=>2,'emailsenders'=>1,'allemails'=>2,'lastemails'=>2,'emailreceivers'=>1,'allemailr'=>2,'lastemailr'=>2,'robots'=>1,'allrobots'=>2,'lastrobots'=>2,'worms'=>1); + %menutext=('countries'=>$Message[148],'alldomains'=>$Message[80],'visitors'=>$Message[81],'allhosts'=>$Message[80],'lasthosts'=>$Message[9],'unknownip'=>$Message[45],'logins'=>$Message[94],'alllogins'=>$Message[80],'lastlogins'=>$Message[9],'emailsenders'=>$Message[131],'allemails'=>$Message[80],'lastemails'=>$Message[9],'emailreceivers'=>$Message[132],'allemailr'=>$Message[80],'lastemailr'=>$Message[9],'robots'=>$Message[53],'allrobots'=>$Message[80],'lastrobots'=>$Message[9],'worms'=>$Message[136]); + ShowMenuCateg('who',$Message[92],'menu5.png',$frame,$targetpage,$linkanchor,$NewLinkParams,$NewLinkTarget,\%menu,\%menulink,\%menutext); + # Navigation + $linetitle=&AtLeastOneNotNull($ShowSessionsStats,$ShowPagesStats,$ShowFileTypesStats,$ShowFileSizesStats,$ShowOSStats,$ShowBrowsersStats,$ShowScreenSizeStats); + if ($linetitle) { print "".($menuicon?" ":"")."$Message[72]:\n"; } + if ($linetitle) { print ($frame?"\n":""); } + if ($ShowSessionsStats) { print ($frame?"":""); print "$Message[117]"; print ($frame?"\n":"   "); } + if ($ShowFileTypesStats) { print ($frame?"":""); print "$Message[73]"; print ($frame?"\n":"   "); } + if ($ShowPagesStats) { print ($frame?"":""); print "$Message[29]\n"; print ($frame?"\n":"   "); } + if ($ShowPagesStats) { print ($frame?"   \"...\" ":""); print "$Message[80]\n"; print ($frame?"\n":"   "); } + if ($ShowPagesStats =~ /E/i) { print ($frame?"   \"...\" ":""); print "$Message[104]\n"; print ($frame?"\n":"   "); } + if ($ShowPagesStats =~ /X/i) { print ($frame?"   \"...\" ":""); print "$Message[116]\n"; print ($frame?"\n":"   "); } + if ($ShowOSStats) { print ($frame?"":""); print "$Message[59]"; print ($frame?"\n":"   "); } + if ($ShowOSStats) { print ($frame?"   \"...\" ":""); print "$Message[58]\n"; print ($frame?"\n":"   "); } + if ($ShowOSStats) { print ($frame?"   \"...\" ":""); print "$Message[0]\n"; print ($frame?"\n":"   "); } + if ($ShowBrowsersStats) { print ($frame?"":""); print "$Message[21]"; print ($frame?"\n":"   "); } + if ($ShowBrowsersStats) { print ($frame?"   \"...\" ":""); print "$Message[58]\n"; print ($frame?"\n":"   "); } + if ($ShowBrowsersStats) { print ($frame?"   \"...\" ":""); print "$Message[0]\n"; print ($frame?"\n":"   "); } + if ($ShowScreenSizeStats) { print ($frame?"":""); print "$Message[135]"; print ($frame?"\n":"   "); } + if ($linetitle) { print ($frame?"":"\n"); } + # Referers + %menu=('referer'=>$ShowOriginStats?1:0,'refererse'=>$ShowOriginStats?2:0,'refererpages'=>$ShowOriginStats?3:0,'keys'=>($ShowKeyphrasesStats || $ShowKeywordsStats)?4:0,'keyphrases'=>$ShowKeyphrasesStats?5:0,'keywords'=>$ShowKeywordsStats?6:0); + %menulink=('referer'=>1,'refererse'=>2,'refererpages'=>2,'keys'=>1,'keyphrases'=>2,'keywords'=>2); + %menutext=('referer'=>$Message[37],'refererse'=>$Message[126],'refererpages'=>$Message[127],'keys'=>$Message[14],'keyphrases'=>$Message[120],'keywords'=>$Message[121]); + ShowMenuCateg('referers',$Message[23],'menu7.png',$frame,$targetpage,$linkanchor,$NewLinkParams,$NewLinkTarget,\%menu,\%menulink,\%menutext); + # Others + %menu=('filetypes'=>($ShowFileTypesStats =~ /C/i)?1:0,'misc'=>$ShowMiscStats?2:0,'errors'=>($ShowHTTPErrorsStats||$ShowSMTPErrorsStats)?3:0,'clusters'=>$ShowClusterStats?5:0); + %menulink=('filetypes'=>1,'misc'=>1,'errors'=>1,'clusters'=>1); + %menutext=('filetypes'=>$Message[98],'misc'=>$Message[139],'errors'=>($ShowSMTPErrorsStats?$Message[147]:$Message[32]),'clusters'=>$Message[155]); + foreach (keys %TrapInfosForHTTPErrorCodes) { + $menu{"errors$_"}=$ShowHTTPErrorsStats?4:0; + $menulink{"errors$_"}=2; + $menutext{"errors$_"}=$Message[31]; + } + ShowMenuCateg('others',$Message[2],'menu8.png',$frame,$targetpage,$linkanchor,$NewLinkParams,$NewLinkTarget,\%menu,\%menulink,\%menutext); + # Extra/Marketing + %menu=(); + %menulink=(); + %menutext=(); + foreach (1..@ExtraName-1) { + $menu{"extra$_"}=1; + $menulink{"extra$_"}=1; + $menutext{"extra$_"}=$ExtraName[$_]; + } + ShowMenuCateg('extra',$Message[134],'',$frame,$targetpage,$linkanchor,$NewLinkParams,$NewLinkTarget,\%menu,\%menulink,\%menutext); + print "\n"; + } + else { + # Menu Applet + if ($frame) { } + else {} + } + #print ($frame?"":"
\n"); + print "
\n"; + } + # Print Back link + elsif (! $HTMLOutput{'main'}) { + print "\n"; + $NewLinkParams =~ s/(^|&|&)hostfilter=[^&]*//i; + $NewLinkParams =~ s/(^|&|&)urlfilter=[^&]*//i; + $NewLinkParams =~ s/(^|&|&)refererpagesfilter=[^&]*//i; + $NewLinkParams =~ s/(&|&)+/&/i; + $NewLinkParams =~ s/^&//; $NewLinkParams =~ s/&$//; + if (! $DetailedReportsOnNewWindows || $FrameName eq 'mainright' || $QueryString =~ /buildpdf/i) { + print "\n"; + } + else { + print "\n"; + } + print "
$Message[76]
$Message[118]
\n"; + print "\n"; + } + } + + # Call to plugins' function AddHTMLMenuFooter + foreach my $pluginname (keys %{$PluginsLoaded{'AddHTMLMenuFooter'}}) { +# my $function="AddHTMLMenuFooter_$pluginname()"; +# eval("$function"); + my $function="AddHTMLMenuFooter_$pluginname"; + &$function(); + } + + # Exit if left frame + if ($FrameName eq 'mainleft') { + &html_end(0); + exit 0; + } + + # FirstTime LastTime + my $FirstTime=0; + my $LastTime=0; + foreach my $key (keys %FirstTime) { + my $keyqualified=0; + if ($MonthRequired eq 'all') { $keyqualified=1; } + if ($key =~ /^$YearRequired$MonthRequired/) { $keyqualified=1; } + if ($keyqualified) { + if ($FirstTime{$key} && ($FirstTime == 0 || $FirstTime > $FirstTime{$key})) { $FirstTime = $FirstTime{$key}; } + if ($LastTime < ($LastTime{$key}||0)) { $LastTime = $LastTime{$key}; } + } + } + + # TotalVisits TotalUnique TotalPages TotalHits TotalBytes TotalHostsKnown TotalHostsUnknown + $TotalUnique=$TotalVisits=$TotalPages=$TotalHits=$TotalBytes=0; + $TotalNotViewedPages=$TotalNotViewedHits=$TotalNotViewedBytes=0; + $TotalHostsKnown=$TotalHostsUnknown=0; + my $beginmonth=$MonthRequired;my $endmonth=$MonthRequired; + if ($MonthRequired eq 'all') { $beginmonth=1;$endmonth=12; } + for (my $month=$beginmonth; $month<=$endmonth; $month++) { + my $monthix=sprintf("%02s",$month); + $TotalHostsKnown+=$MonthHostsKnown{$YearRequired.$monthix}||0; # Wrong in year view + $TotalHostsUnknown+=$MonthHostsUnknown{$YearRequired.$monthix}||0; # Wrong in year view + $TotalUnique+=$MonthUnique{$YearRequired.$monthix}||0; # Wrong in year view + $TotalVisits+=$MonthVisits{$YearRequired.$monthix}||0; # Not completely true + $TotalPages+=$MonthPages{$YearRequired.$monthix}||0; + $TotalHits+=$MonthHits{$YearRequired.$monthix}||0; + $TotalBytes+=$MonthBytes{$YearRequired.$monthix}||0; + $TotalNotViewedPages+=$MonthNotViewedPages{$YearRequired.$monthix}||0; + $TotalNotViewedHits+=$MonthNotViewedHits{$YearRequired.$monthix}||0; + $TotalNotViewedBytes+=$MonthNotViewedBytes{$YearRequired.$monthix}||0; + } + # TotalHitsErrors TotalBytesErrors + my $TotalHitsErrors=0; my $TotalBytesErrors=0; + foreach (keys %_errors_h) { +# print "xxxx".$_." zzz".$_errors_h{$_}; + $TotalHitsErrors+=$_errors_h{$_}; + $TotalBytesErrors+=$_errors_k{$_}; + } + # TotalEntries (if not already specifically counted, we init it from _url_e hash table) + if (!$TotalEntries) { foreach (keys %_url_e) { $TotalEntries+=$_url_e{$_}; } } + # TotalExits (if not already specifically counted, we init it from _url_x hash table) + if (!$TotalExits) { foreach (keys %_url_x) { $TotalExits+=$_url_x{$_}; } } + # TotalBytesPages (if not already specifically counted, we init it from _url_k hash table) + if (!$TotalBytesPages) { foreach (keys %_url_k) { $TotalBytesPages+=$_url_k{$_}; } } + # TotalKeyphrases (if not already specifically counted, we init it from _keyphrases hash table) + if (!$TotalKeyphrases) { foreach (keys %_keyphrases) { $TotalKeyphrases+=$_keyphrases{$_}; } } + # TotalKeywords (if not already specifically counted, we init it from _keywords hash table) + if (!$TotalKeywords) { foreach (keys %_keywords) { $TotalKeywords+=$_keywords{$_}; } } + # TotalSearchEnginesPages (if not already specifically counted, we init it from _se_referrals_p hash table) + if (!$TotalSearchEnginesPages) { foreach (keys %_se_referrals_p) { $TotalSearchEnginesPages+=$_se_referrals_p{$_}; } } + # TotalSearchEnginesHits (if not already specifically counted, we init it from _se_referrals_h hash table) + if (!$TotalSearchEnginesHits) { foreach (keys %_se_referrals_h) { $TotalSearchEnginesHits+=$_se_referrals_h{$_}; } } + # TotalRefererPages (if not already specifically counted, we init it from _pagesrefs_p hash table) + if (!$TotalRefererPages) { foreach (keys %_pagesrefs_p) { $TotalRefererPages+=$_pagesrefs_p{$_}; } } + # TotalRefererHits (if not already specifically counted, we init it from _pagesrefs_h hash table) + if (!$TotalRefererHits) { foreach (keys %_pagesrefs_h) { $TotalRefererHits+=$_pagesrefs_h{$_}; } } + # TotalDifferentPages (if not already specifically counted, we init it from _url_p hash table) + $TotalDifferentPages||=scalar keys %_url_p; + # TotalDifferentKeyphrases (if not already specifically counted, we init it from _keyphrases hash table) + $TotalDifferentKeyphrases||=scalar keys %_keyphrases; + # TotalDifferentKeywords (if not already specifically counted, we init it from _keywords hash table) + $TotalDifferentKeywords||=scalar keys %_keywords; + # TotalDifferentSearchEngines (if not already specifically counted, we init it from _se_referrals_h hash table) + $TotalDifferentSearchEngines||=scalar keys %_se_referrals_h; + # TotalDifferentReferer (if not already specifically counted, we init it from _pagesrefs_h hash table) + $TotalDifferentReferer||=scalar keys %_pagesrefs_h; + + # Define firstdaytocountaverage, lastdaytocountaverage, firstdaytoshowtime, lastdaytoshowtime + my $firstdaytocountaverage=$nowyear.$nowmonth."01"; # Set day cursor to 1st day of month + my $firstdaytoshowtime=$nowyear.$nowmonth."01"; # Set day cursor to 1st day of month + my $lastdaytocountaverage=$nowyear.$nowmonth.$nowday; # Set day cursor to today + my $lastdaytoshowtime=$nowyear.$nowmonth."31"; # Set day cursor to last day of month + if ($MonthRequired eq 'all') { + $firstdaytocountaverage=$YearRequired."0101"; # Set day cursor to 1st day of the required year + } + if (($MonthRequired ne $nowmonth && $MonthRequired ne 'all') || $YearRequired ne $nowyear) { + if ($MonthRequired eq 'all') { + $firstdaytocountaverage=$YearRequired."0101"; # Set day cursor to 1st day of the required year + $firstdaytoshowtime=$YearRequired."1201"; # Set day cursor to 1st day of last month of required year + $lastdaytocountaverage=$YearRequired."1231"; # Set day cursor to last day of the required year + $lastdaytoshowtime=$YearRequired."1231"; # Set day cursor to last day of last month of required year + } + else { + $firstdaytocountaverage=$YearRequired.$MonthRequired."01"; # Set day cursor to 1st day of the required month + $firstdaytoshowtime=$YearRequired.$MonthRequired."01"; # Set day cursor to 1st day of the required month + $lastdaytocountaverage=$YearRequired.$MonthRequired."31"; # Set day cursor to last day of the required month + $lastdaytoshowtime=$YearRequired.$MonthRequired."31"; # Set day cursor to last day of the required month + } + } + if ($Debug) { + debug("firstdaytocountaverage=$firstdaytocountaverage, lastdaytocountaverage=$lastdaytocountaverage",1); + debug("firstdaytoshowtime=$firstdaytoshowtime, lastdaytoshowtime=$lastdaytoshowtime",1); + } + + # Call to plugins' function AddHTMLContentHeader + foreach my $pluginname (keys %{$PluginsLoaded{'AddHTMLContentHeader'}}) { +# my $function="AddHTMLContentHeader_$pluginname()"; +# eval("$function"); + # to add unique visitors & number of visits, by J Ruano @ CAPSiDE + if ($ShowDomainsStats =~ /U/i) { print "$Message[11]"; } + if ($ShowDomainsStats =~ /V/i) { print "$Message[10]"; } + + my $function="AddHTMLContentHeader_$pluginname"; + &$function(); + } + + # Output particular part + #----------------------- + if (scalar keys %HTMLOutput == 1) { + + if ($HTMLOutput{'alldomains'}) { + print "$Center 
\n"; + # Show domains list + my $title=''; my $cpt=0; + if ($HTMLOutput{'alldomains'}) { $title.="$Message[25]"; $cpt=(scalar keys %_domener_h); } + &tab_head("$title",19,0,'domains'); + print " $Message[17]"; + if ($ShowDomainsStats =~ /P/i) { print "$Message[56]"; } + if ($ShowDomainsStats =~ /H/i) { print "$Message[57]"; } + if ($ShowDomainsStats =~ /B/i) { print "$Message[75]"; } + print " "; + print "\n"; + $total_u=$total_v=$total_p=$total_h=$total_k=0; + $max_h=1; foreach (values %_domener_h) { if ($_ > $max_h) { $max_h = $_; } } + $max_k=1; foreach (values %_domener_k) { if ($_ > $max_k) { $max_k = $_; } } + my $count=0; + &BuildKeyList($MaxRowsInHTMLOutput,1,\%_domener_h,\%_domener_p); + foreach my $key (@keylist) { + my ($_domener_u, $_domener_v); + my $bredde_p=0;my $bredde_h=0;my $bredde_k=0; + if ($max_h > 0) { $bredde_p=int($BarWidth*$_domener_p{$key}/$max_h)+1; } # use max_h to enable to compare pages with hits + if ($_domener_p{$key} && $bredde_p==1) { $bredde_p=2; } + if ($max_h > 0) { $bredde_h=int($BarWidth*$_domener_h{$key}/$max_h)+1; } + if ($_domener_h{$key} && $bredde_h==1) { $bredde_h=2; } + if ($max_k > 0) { $bredde_k=int($BarWidth*($_domener_k{$key}||0)/$max_k)+1; } + if ($_domener_k{$key} && $bredde_k==1) { $bredde_k=2; } + my $newkey=lc($key); + if ($newkey eq 'ip' || ! $DomainsHashIDLib{$newkey}) { + print "$Message[0]$newkey"; + } + else { + print "$DomainsHashIDLib{$newkey}$newkey"; + } + ## to add unique visitors and number of visits, by Josep Ruano @ CAPSiDE + if ($ShowDomainsStats =~ /U/i) { + $_domener_u = ($_domener_p{$key} ? $_domener_p{$key}/$TotalPages : 0); + $_domener_u += ($_domener_h{$key}/$TotalHits); + $_domener_u = sprintf("%.0f", ($_domener_u * $TotalUnique) / 2); + print "$_domener_u (" . sprintf("%.1f%", 100*$_domener_u/$TotalUnique) . ")"; + } + if ($ShowDomainsStats =~ /V/i) { + $_domener_v = ($_domener_p{$key} ? $_domener_p{$key}/$TotalPages : 0); + $_domener_v += ($_domener_h{$key}/$TotalHits); + $_domener_v = sprintf("%.0f", ($_domener_v * $TotalVisits) / 2); + print "$_domener_v (" . sprintf("%.1f%", 100*$_domener_v/$TotalVisits) . ")"; + } + if ($ShowDomainsStats =~ /P/i) { print "$_domener_p{$key}"; } + if ($ShowDomainsStats =~ /H/i) { print "$_domener_h{$key}"; } + if ($ShowDomainsStats =~ /B/i) { print "".Format_Bytes($_domener_k{$key}).""; } + print ""; + if ($ShowDomainsStats =~ /P/i) { print "
\n"; } + if ($ShowDomainsStats =~ /H/i) { print "
\n"; } + if ($ShowDomainsStats =~ /B/i) { print ""; } + print ""; + print "\n"; + $total_u += $_domener_u; + $total_v += $_domener_v; + $total_p += $_domener_p{$key}; + $total_h += $_domener_h{$key}; + $total_k += $_domener_k{$key}||0; + $count++; + } + my $rest_u = $TotalUnique - $total_u; + my $rest_v = $TotalVisits - $total_v; + $rest_p=$TotalPages-$total_p; + $rest_h=$TotalHits-$total_h; + $rest_k=$TotalBytes-$total_k; + if ($rest_u > 0 || $rest_v > 0 || $rest_p > 0 || $rest_h > 0 || $rest_k > 0) { # All other domains (known or not) + print " $Message[2]"; + if ($ShowDomainsStats =~ /U/i) { print "$rest_u"; } + if ($ShowDomainsStats =~ /V/i) { print "$rest_v"; } + if ($ShowDomainsStats =~ /P/i) { print "$rest_p"; } + if ($ShowDomainsStats =~ /H/i) { print "$rest_h"; } + if ($ShowDomainsStats =~ /B/i) { print "".Format_Bytes($rest_k).""; } + print " "; + print "\n"; + } + &tab_end(); + &html_end(1); + } + if ($HTMLOutput{'allhosts'} || $HTMLOutput{'lasthosts'}) { + print "$Center 
\n"; + # Show filter form + &ShowFormFilter("hostfilter",$FilterIn{'host'},$FilterEx{'host'}); + # Show hosts list + my $title=''; my $cpt=0; + if ($HTMLOutput{'allhosts'}) { $title.="$Message[81]"; $cpt=(scalar keys %_host_h); } + if ($HTMLOutput{'lasthosts'}) { $title.="$Message[9]"; $cpt=(scalar keys %_host_h); } + &tab_head("$title",19,0,'hosts'); + print ""; + if ($FilterIn{'host'} || $FilterEx{'host'}) { # With filter + if ($FilterIn{'host'}) { print "$Message[79] '$FilterIn{'host'}'"; } + if ($FilterIn{'host'} && $FilterEx{'host'}) { print " - "; } + if ($FilterEx{'host'}) { print " Exlude $Message[79] '$FilterEx{'host'}'"; } + if ($FilterIn{'host'} || $FilterEx{'host'}) { print ": "; } + print "$cpt $Message[81]"; + if ($MonthRequired ne 'all') { + if ($HTMLOutput{'allhosts'} || $HTMLOutput{'lasthosts'}) { print "
$Message[102]: $TotalHostsKnown $Message[82], $TotalHostsUnknown $Message[1] - $TotalUnique $Message[11]"; } + } + } + else { # Without filter + if ($MonthRequired ne 'all') { print "$Message[102] : $TotalHostsKnown $Message[82], $TotalHostsUnknown $Message[1] - $TotalUnique $Message[11]"; } + else { print "$Message[102] : ".(scalar keys %_host_h); } + } + print ""; + &ShowHostInfo('__title__'); + if ($ShowHostsStats =~ /P/i) { print "$Message[56]"; } + if ($ShowHostsStats =~ /H/i) { print "$Message[57]"; } + if ($ShowHostsStats =~ /B/i) { print "$Message[75]"; } + if ($ShowHostsStats =~ /L/i) { print "$Message[9]"; } + print "\n"; + $total_p=$total_h=$total_k=0; + my $count=0; + if ($HTMLOutput{'allhosts'}) { &BuildKeyList($MaxRowsInHTMLOutput,$MinHit{'Host'},\%_host_h,\%_host_p); } + if ($HTMLOutput{'lasthosts'}) { &BuildKeyList($MaxRowsInHTMLOutput,$MinHit{'Host'},\%_host_h,\%_host_l); } + foreach my $key (@keylist) { + my $host=CleanXSS($key); + print "".($_robot_l{$key}?'':'')."$host".($_robot_l{$key}?'':'').""; + &ShowHostInfo($key); + if ($ShowHostsStats =~ /P/i) { print "".($_host_p{$key}?$_host_p{$key}:" ").""; } + if ($ShowHostsStats =~ /H/i) { print "$_host_h{$key}"; } + if ($ShowHostsStats =~ /B/i) { print "".Format_Bytes($_host_k{$key}).""; } + if ($ShowHostsStats =~ /L/i) { print "".($_host_l{$key}?Format_Date($_host_l{$key},1):'-').""; } + print "\n"; + $total_p += $_host_p{$key}; + $total_h += $_host_h{$key}; + $total_k += $_host_k{$key}||0; + $count++; + } + if ($Debug) { debug("Total real / shown : $TotalPages / $total_p - $TotalHits / $total_h - $TotalBytes / $total_h",2); } + $rest_p=$TotalPages-$total_p; + $rest_h=$TotalHits-$total_h; + $rest_k=$TotalBytes-$total_k; + if ($rest_p > 0 || $rest_h > 0 || $rest_k > 0) { # All other visitors (known or not) + print "$Message[2]"; + &ShowHostInfo(''); + if ($ShowHostsStats =~ /P/i) { print "".($rest_p?$rest_p:" ").""; } + if ($ShowHostsStats =~ /H/i) { print "$rest_h"; } + if ($ShowHostsStats =~ /B/i) { print "".Format_Bytes($rest_k).""; } + if ($ShowHostsStats =~ /L/i) { print " "; } + print "\n"; + } + &tab_end(); + &html_end(1); + } + if ($HTMLOutput{'unknownip'}) { + print "$Center 
\n"; + &tab_head("$Message[45]",19,0,'unknownwip'); + print "".(scalar keys %_host_h)." $Message[1]"; + &ShowHostInfo('__title__'); + if ($ShowHostsStats =~ /P/i) { print "$Message[56]"; } + if ($ShowHostsStats =~ /H/i) { print "$Message[57]"; } + if ($ShowHostsStats =~ /B/i) { print "$Message[75]"; } + if ($ShowHostsStats =~ /L/i) { print "$Message[9]"; } + print "\n"; + $total_p=$total_h=$total_k=0; + my $count=0; + &BuildKeyList($MaxRowsInHTMLOutput,$MinHit{'Host'},\%_host_h,\%_host_p); + foreach my $key (@keylist) { + my $host=CleanXSS($key); + print "$host"; + &ShowHostInfo($key); + if ($ShowHostsStats =~ /P/i) { print "".($_host_p{$key}?$_host_p{$key}:" ").""; } + if ($ShowHostsStats =~ /H/i) { print "$_host_h{$key}"; } + if ($ShowHostsStats =~ /B/i) { print "".Format_Bytes($_host_k{$key}).""; } + if ($ShowHostsStats =~ /L/i) { print "".($_host_l{$key}?Format_Date($_host_l{$key},1):'-').""; } + print "\n"; + $total_p += $_host_p{$key}; + $total_h += $_host_h{$key}; + $total_k += $_host_k{$key}||0; + $count++; + } + if ($Debug) { debug("Total real / shown : $TotalPages / $total_p - $TotalHits / $total_h - $TotalBytes / $total_h",2); } + $rest_p=$TotalPages-$total_p; + $rest_h=$TotalHits-$total_h; + $rest_k=$TotalBytes-$total_k; + if ($rest_p > 0 || $rest_h > 0 || $rest_k > 0) { # All other visitors (known or not) + print "$Message[82]"; + &ShowHostInfo(''); + if ($ShowHostsStats =~ /P/i) { print "".($rest_p?$rest_p:" ").""; } + if ($ShowHostsStats =~ /H/i) { print "$rest_h"; } + if ($ShowHostsStats =~ /B/i) { print "".Format_Bytes($rest_k).""; } + if ($ShowHostsStats =~ /L/i) { print " "; } + print "\n"; + } + &tab_end(); + &html_end(1); + } + if ($HTMLOutput{'allemails'} || $HTMLOutput{'lastemails'}) { + &ShowEmailSendersChart($NewLinkParams,$NewLinkTarget); + &html_end(1); + } + if ($HTMLOutput{'allemailr'} || $HTMLOutput{'lastemailr'}) { + &ShowEmailReceiversChart($NewLinkParams,$NewLinkTarget); + &html_end(1); + } + if ($HTMLOutput{'alllogins'} || $HTMLOutput{'lastlogins'}) { + print "$Center 
\n"; + my $title=''; + if ($HTMLOutput{'alllogins'}) { $title.="$Message[94]"; } + if ($HTMLOutput{'lastlogins'}) { $title.="$Message[9]"; } + &tab_head("$title",19,0,'logins'); + print "$Message[94] : ".(scalar keys %_login_h).""; + &ShowUserInfo('__title__'); + if ($ShowAuthenticatedUsers =~ /P/i) { print "$Message[56]"; } + if ($ShowAuthenticatedUsers =~ /H/i) { print "$Message[57]"; } + if ($ShowAuthenticatedUsers =~ /B/i) { print "$Message[75]"; } + if ($ShowAuthenticatedUsers =~ /L/i) { print "$Message[9]"; } + print "\n"; + $total_p=$total_h=$total_k=0; + my $count=0; + if ($HTMLOutput{'alllogins'}) { &BuildKeyList($MaxRowsInHTMLOutput,$MinHit{'Host'},\%_login_h,\%_login_p); } + if ($HTMLOutput{'lastlogins'}) { &BuildKeyList($MaxRowsInHTMLOutput,$MinHit{'Host'},\%_login_h,\%_login_l); } + foreach my $key (@keylist) { + print "$key"; + &ShowUserInfo($key); + if ($ShowAuthenticatedUsers =~ /P/i) { print "".($_login_p{$key}?$_login_p{$key}:" ").""; } + if ($ShowAuthenticatedUsers =~ /H/i) { print "$_login_h{$key}"; } + if ($ShowAuthenticatedUsers =~ /B/i) { print "".Format_Bytes($_login_k{$key}).""; } + if ($ShowAuthenticatedUsers =~ /L/i) { print "".($_login_l{$key}?Format_Date($_login_l{$key},1):'-').""; } + print "\n"; + $total_p += $_login_p{$key}||0; + $total_h += $_login_h{$key}; + $total_k += $_login_k{$key}||0; + $count++; + } + if ($Debug) { debug("Total real / shown : $TotalPages / $total_p - $TotalHits / $total_h - $TotalBytes / $total_h",2); } + $rest_p=$TotalPages-$total_p; + $rest_h=$TotalHits-$total_h; + $rest_k=$TotalBytes-$total_k; + if ($rest_p > 0 || $rest_h > 0 || $rest_k > 0) { # All other logins and/or anonymous + print "$Message[125]"; + &ShowUserInfo(''); + if ($ShowAuthenticatedUsers =~ /P/i) { print "".($rest_p?$rest_p:" ").""; } + if ($ShowAuthenticatedUsers =~ /H/i) { print "$rest_h"; } + if ($ShowAuthenticatedUsers =~ /B/i) { print "".Format_Bytes($rest_k).""; } + if ($ShowAuthenticatedUsers =~ /L/i) { print " "; } + print "\n"; + } + &tab_end(); + &html_end(1); + } + if ($HTMLOutput{'allrobots'} || $HTMLOutput{'lastrobots'}) { + print "$Center 
\n"; + my $title=''; + if ($HTMLOutput{'allrobots'}) { $title.="$Message[53]"; } + if ($HTMLOutput{'lastrobots'}) { $title.="$Message[9]"; } + &tab_head("$title",19,0,'robots'); + print "".(scalar keys %_robot_h)." $Message[51]"; + if ($ShowRobotsStats =~ /H/i) { print "$Message[57]"; } + if ($ShowRobotsStats =~ /B/i) { print "$Message[75]"; } + if ($ShowRobotsStats =~ /L/i) { print "$Message[9]"; } + print "\n"; + $total_p=$total_h=$total_k=$total_r=0; + my $count=0; + if ($HTMLOutput{'allrobots'}) { &BuildKeyList($MaxRowsInHTMLOutput,$MinHit{'Robot'},\%_robot_h,\%_robot_h); } + if ($HTMLOutput{'lastrobots'}) { &BuildKeyList($MaxRowsInHTMLOutput,$MinHit{'Robot'},\%_robot_h,\%_robot_l); } + foreach my $key (@keylist) { + print "".($RobotsHashIDLib{$key}?$RobotsHashIDLib{$key}:$key).""; + if ($ShowRobotsStats =~ /H/i) { print "".($_robot_h{$key}-$_robot_r{$key}).($_robot_r{$key}?"+$_robot_r{$key}":"").""; } + if ($ShowRobotsStats =~ /B/i) { print "".Format_Bytes($_robot_k{$key}).""; } + if ($ShowRobotsStats =~ /L/i) { print "".($_robot_l{$key}?Format_Date($_robot_l{$key},1):'-').""; } + print "\n"; + #$total_p += $_robot_p{$key}||0; + $total_h += $_robot_h{$key}; + $total_k += $_robot_k{$key}||0; + $total_r += $_robot_r{$key}||0; + $count++; + } + # For bots we need to count Totals + my $TotalPagesRobots = 0; #foreach (values %_robot_p) { $TotalPagesRobots+=$_; } + my $TotalHitsRobots = 0; foreach (values %_robot_h) { $TotalHitsRobots+=$_; } + my $TotalBytesRobots = 0; foreach (values %_robot_k) { $TotalBytesRobots+=$_; } + my $TotalRRobots = 0; foreach (values %_robot_r) { $TotalRRobots+=$_; } + $rest_p=0; #$rest_p=$TotalPagesRobots-$total_p; + $rest_h=$TotalHitsRobots-$total_h; + $rest_k=$TotalBytesRobots-$total_k; + $rest_r=$TotalRRobots-$total_r; + if ($Debug) { debug("Total real / shown : $TotalPagesRobots / $total_p - $TotalHitsRobots / $total_h - $TotalBytesRobots / $total_k",2); } + if ($rest_p > 0 || $rest_h > 0 || $rest_k > 0 || $rest_r > 0) { # All other robots + print "$Message[2]"; + if ($ShowRobotsStats =~ /H/i) { print "$rest_h"; } + if ($ShowRobotsStats =~ /B/i) { print "".(Format_Bytes($rest_k)).""; } + if ($ShowRobotsStats =~ /L/i) { print " "; } + print "\n"; + } + &tab_end("* $Message[156]".($TotalRRobots?" $Message[157]":"")); + &html_end(1); + } + if ($HTMLOutput{'urldetail'} || $HTMLOutput{'urlentry'} || $HTMLOutput{'urlexit'}) { + # Call to plugins' function ShowPagesFilter + foreach my $pluginname (keys %{$PluginsLoaded{'ShowPagesFilter'}}) { +# my $function="ShowPagesFilter_$pluginname()"; +# eval("$function"); + my $function="ShowPagesFilter_$pluginname"; + &$function(); + } + print "$Center 
\n"; + # Show filter form + &ShowFormFilter("urlfilter",$FilterIn{'url'},$FilterEx{'url'}); + # Show URL list + my $title=''; my $cpt=0; + if ($HTMLOutput{'urldetail'}) { $title=$Message[19]; $cpt=(scalar keys %_url_p); } + if ($HTMLOutput{'urlentry'}) { $title=$Message[104]; $cpt=(scalar keys %_url_e); } + if ($HTMLOutput{'urlexit'}) { $title=$Message[116]; $cpt=(scalar keys %_url_x); } + &tab_head("$title",19,0,'urls'); + print ""; + if ($FilterIn{'url'} || $FilterEx{'url'}) { + if ($FilterIn{'url'}) { print "$Message[79] $FilterIn{'url'}"; } + if ($FilterIn{'url'} && $FilterEx{'url'}) { print " - "; } + if ($FilterEx{'url'}) { print "Exclude $Message[79] $FilterEx{'url'}"; } + if ($FilterIn{'url'} || $FilterEx{'url'}) { print ": "; } + print "$cpt $Message[28]"; + if ($MonthRequired ne 'all') { + if ($HTMLOutput{'urldetail'}) { print "
$Message[102]: $TotalDifferentPages $Message[28]"; } + } + } + else { print "$Message[102]: $cpt $Message[28]"; } + print ""; + if ($ShowPagesStats =~ /P/i) { print "$Message[29]"; } + if ($ShowPagesStats =~ /B/i) { print "$Message[106]"; } + if ($ShowPagesStats =~ /E/i) { print "$Message[104]"; } + if ($ShowPagesStats =~ /X/i) { print "$Message[116]"; } + # Call to plugins' function ShowPagesAddField + foreach my $pluginname (keys %{$PluginsLoaded{'ShowPagesAddField'}}) { +# my $function="ShowPagesAddField_$pluginname('title')"; +# eval("$function"); + my $function="ShowPagesAddField_$pluginname"; + &$function('title'); + } + print " \n"; + $total_p=$total_k=$total_e=$total_x=0; + my $count=0; + if ($HTMLOutput{'urlentry'}) { &BuildKeyList($MaxRowsInHTMLOutput,$MinHit{'File'},\%_url_e,\%_url_e); } + elsif ($HTMLOutput{'urlexit'}) { &BuildKeyList($MaxRowsInHTMLOutput,$MinHit{'File'},\%_url_x,\%_url_x); } + else { &BuildKeyList($MaxRowsInHTMLOutput,$MinHit{'File'},\%_url_p,\%_url_p); } + $max_p=1; $max_k=1; + foreach my $key (@keylist) { + if ($_url_p{$key} > $max_p) { $max_p = $_url_p{$key}; } + if ($_url_k{$key}/($_url_p{$key}||1) > $max_k) { $max_k = $_url_k{$key}/($_url_p{$key}||1); } + } + foreach my $key (@keylist) { + print ""; + &ShowURLInfo($key); + print ""; + my $bredde_p=0; my $bredde_e=0; my $bredde_x=0; my $bredde_k=0; + if ($max_p > 0) { $bredde_p=int($BarWidth*($_url_p{$key}||0)/$max_p)+1; } + if (($bredde_p==1) && $_url_p{$key}) { $bredde_p=2; } + if ($max_p > 0) { $bredde_e=int($BarWidth*($_url_e{$key}||0)/$max_p)+1; } + if (($bredde_e==1) && $_url_e{$key}) { $bredde_e=2; } + if ($max_p > 0) { $bredde_x=int($BarWidth*($_url_x{$key}||0)/$max_p)+1; } + if (($bredde_x==1) && $_url_x{$key}) { $bredde_x=2; } + if ($max_k > 0) { $bredde_k=int($BarWidth*(($_url_k{$key}||0)/($_url_p{$key}||1))/$max_k)+1; } + if (($bredde_k==1) && $_url_k{$key}) { $bredde_k=2; } + if ($ShowPagesStats =~ /P/i) { print "$_url_p{$key}"; } + if ($ShowPagesStats =~ /B/i) { print "".($_url_k{$key}?Format_Bytes($_url_k{$key}/($_url_p{$key}||1)):" ").""; } + if ($ShowPagesStats =~ /E/i) { print "".($_url_e{$key}?$_url_e{$key}:" ").""; } + if ($ShowPagesStats =~ /X/i) { print "".($_url_x{$key}?$_url_x{$key}:" ").""; } + # Call to plugins' function ShowPagesAddField + foreach my $pluginname (keys %{$PluginsLoaded{'ShowPagesAddField'}}) { +# my $function="ShowPagesAddField_$pluginname('$key')"; +# eval("$function"); + my $function="ShowPagesAddField_$pluginname"; + &$function($key); + } + print ""; + # alt and title are not provided to reduce page size + if ($ShowPagesStats =~ /P/i) { print "
"; } + if ($ShowPagesStats =~ /B/i) { print "
"; } + if ($ShowPagesStats =~ /E/i) { print "
"; } + if ($ShowPagesStats =~ /X/i) { print ""; } + print "\n"; + $total_p += $_url_p{$key}; + $total_e += $_url_e{$key}; + $total_x += $_url_x{$key}; + $total_k += $_url_k{$key}; + $count++; + } + if ($Debug) { debug("Total real / shown : $TotalPages / $total_p - $TotalEntries / $total_e - $TotalExits / $total_x - $TotalBytesPages / $total_k",2); } + $rest_p=$TotalPages-$total_p; + $rest_k=$TotalBytesPages-$total_k; + $rest_e=$TotalEntries-$total_e; + $rest_x=$TotalExits-$total_x; + if ($rest_p > 0 || $rest_e > 0 || $rest_k > 0) { + print "$Message[2]"; + if ($ShowPagesStats =~ /P/i) { print "".($rest_p?$rest_p:" ").""; } + if ($ShowPagesStats =~ /B/i) { print "".($rest_k?Format_Bytes($rest_k/($rest_p||1)):" ").""; } + if ($ShowPagesStats =~ /E/i) { print "".($rest_e?$rest_e:" ").""; } + if ($ShowPagesStats =~ /X/i) { print "".($rest_x?$rest_x:" ").""; } + # Call to plugins' function ShowPagesAddField + foreach my $pluginname (keys %{$PluginsLoaded{'ShowPagesAddField'}}) { +# my $function="ShowPagesAddField_$pluginname('')"; +# eval("$function"); + my $function="ShowPagesAddField_$pluginname"; + &$function(''); + } + print " \n"; + } + &tab_end(); + &html_end(1); + } + if ($HTMLOutput{'unknownos'}) { + print "$Center 
\n"; + my $title="$Message[46]"; + &tab_head("$title",19,0,'unknownos'); + print "User agent (".(scalar keys %_unknownreferer_l).")$Message[9]\n"; + $total_l=0; + my $count=0; + &BuildKeyList($MaxRowsInHTMLOutput,1,\%_unknownreferer_l,\%_unknownreferer_l); + foreach my $key (@keylist) { + my $useragent=XMLEncode(CleanXSS($key)); + print "$useragent"; + print "".Format_Date($_unknownreferer_l{$key},1).""; + print "\n"; + $total_l+=1; + $count++; + } + $rest_l=(scalar keys %_unknownreferer_l)-$total_l; + if ($rest_l > 0) { + print "$Message[2]"; + print "-"; + print "\n"; + } + &tab_end(); + &html_end(1); + } + if ($HTMLOutput{'unknownbrowser'}) { + print "$Center 
\n"; + my $title="$Message[50]"; + &tab_head("$title",19,0,'unknownbrowser'); + print "User agent (".(scalar keys %_unknownrefererbrowser_l).")$Message[9]\n"; + $total_l=0; + my $count=0; + &BuildKeyList($MaxRowsInHTMLOutput,1,\%_unknownrefererbrowser_l,\%_unknownrefererbrowser_l); + foreach my $key (@keylist) { + my $useragent=XMLEncode(CleanXSS($key)); + print "$useragent".Format_Date($_unknownrefererbrowser_l{$key},1)."\n"; + $total_l+=1; + $count++; + } + $rest_l=(scalar keys %_unknownrefererbrowser_l)-$total_l; + if ($rest_l > 0) { + print "$Message[2]"; + print "-"; + print "\n"; + } + &tab_end(); + &html_end(1); + } + if ($HTMLOutput{'osdetail'}) { + # Show os versions + print "$Center 
"; + my $title="$Message[59]"; + &tab_head("$title",19,0,'osversions'); + print "$Message[58]"; + print "$Message[57]$Message[15]"; + print " "; + print "\n"; + $total_h=0; + my $count=0; + &BuildKeyList(MinimumButNoZero(scalar keys %_os_h,500),1,\%_os_h,\%_os_h); + my %keysinkeylist=(); + $max_h=1; + # Count total by family + my %totalfamily_h=(); + my $TotalFamily=0; + OSLOOP: foreach my $key (@keylist) { + $total_h+=$_os_h{$key}; + if ($_os_h{$key} > $max_h) { $max_h = $_os_h{$key}; } + foreach my $family (keys %OSFamily) { if ($key =~ /^$family/i) { $totalfamily_h{$family}+=$_os_h{$key}; $TotalFamily+=$_os_h{$key}; next OSLOOP; } } + } + # Write records grouped in a browser family + foreach my $family (keys %OSFamily) { + my $p=' '; + if ($total_h) { $p=int($totalfamily_h{$family}/$total_h*1000)/10; $p="$p %"; } + my $familyheadershown=0; + foreach my $key (reverse sort keys %_os_h) { + if ($key =~ /^$family(.*)/i) { + if (! $familyheadershown) + { + my $family_name=''; + if ($OSFamily{$family}) { $family_name=$OSFamily{$family}; } + print "$family_name"; + print "".int($totalfamily_h{$family})."$p "; + print "\n"; + $familyheadershown=1; + } + $keysinkeylist{$key}=1; + my $ver=$1; + my $p=' '; + if ($total_h) { $p=int($_os_h{$key}/$total_h*1000)/10; $p="$p %"; } + print ""; + print ""; + + + print "$OSHashLib{$key}"; + my $bredde_h=0; + if ($max_h > 0) { $bredde_h=int($BarWidth*($_os_h{$key}||0)/$max_h)+1; } + if (($bredde_h==1) && $_os_h{$key}) { $bredde_h=2; } + print "$_os_h{$key}$p"; + print ""; + # alt and title are not provided to reduce page size + if ($ShowOSStats) { print "
"; } + print ""; + print "\n"; + $count++; + } + } + } + # Write other records + my $familyheadershown=0; + foreach my $key (@keylist) { + if ($keysinkeylist{$key}) { next; } + if (! $familyheadershown) { + my $p=' '; + if ($total_h) { $p=int(($total_h-$TotalFamily)/$total_h*1000)/10; $p="$p %"; } + print "$Message[2]"; + print "".($total_h-$TotalFamily)."$p "; + print "\n"; + $familyheadershown=1; + } + my $p=' '; + if ($total_h) { $p=int($_os_h{$key}/$total_h*1000)/10; $p="$p %"; } + print ""; + if ($key eq 'Unknown') { + print "$Message[0]"; + } + else { + my $keywithoutcumul=$key; $keywithoutcumul =~ s/cumul$//i; + my $libos=$OSHashLib{$keywithoutcumul}||$keywithoutcumul; + my $nameicon=$keywithoutcumul; $nameicon =~ s/[^\w]//g; + print "$libos"; + } + my $bredde_h=0; + if ($max_h > 0) { $bredde_h=int($BarWidth*($_os_h{$key}||0)/$max_h)+1; } + if (($bredde_h==1) && $_os_h{$key}) { $bredde_h=2; } + print "$_os_h{$key}$p"; + print ""; + # alt and title are not provided to reduce page size + if ($ShowOSStats) { print "
"; } + print ""; + print "\n"; + } + &tab_end(); + &html_end(1); + } + if ($HTMLOutput{'browserdetail'}) { + # Show browsers versions + print "$Center 
"; + my $title="$Message[21]"; + &tab_head("$title",19,0,'browsersversions'); + print "$Message[58]"; + print "$Message[111]$Message[57]$Message[15]"; + print " "; + print "\n"; + $total_h=0; + my $count=0; + &BuildKeyList(MinimumButNoZero(scalar keys %_browser_h,500),1,\%_browser_h,\%_browser_h); + my %keysinkeylist=(); + $max_h=1; + # Count total by family + my %totalfamily_h=(); + my $TotalFamily=0; + BROWSERLOOP: foreach my $key (@keylist) { + $total_h+=$_browser_h{$key}; + if ($_browser_h{$key} > $max_h) { $max_h = $_browser_h{$key}; } + foreach my $family (keys %BrowsersFamily) { if ($key =~ /^$family/i) { $totalfamily_h{$family}+=$_browser_h{$key}; $TotalFamily+=$_browser_h{$key}; next BROWSERLOOP; } } + } + # Write records grouped in a browser family + foreach my $family (sort { $BrowsersFamily{$a} <=> $BrowsersFamily{$b} } keys %BrowsersFamily) { + my $p=' '; + if ($total_h) { $p=int($totalfamily_h{$family}/$total_h*1000)/10; $p="$p %"; } + my $familyheadershown=0; + foreach my $key (reverse sort keys %_browser_h) { + if ($key =~ /^$family(.*)/i) { + if (! $familyheadershown) { + print "".uc($family).""; + print " ".int($totalfamily_h{$family})."$p "; + print "\n"; + $familyheadershown=1; + } + $keysinkeylist{$key}=1; + my $ver=$1; + my $p=' '; + if ($total_h) { $p=int($_browser_h{$key}/$total_h*1000)/10; $p="$p %"; } + print ""; + print ""; + print "".ucfirst($family)." ".($ver?"$ver":"?").""; + print "".($BrowsersHereAreGrabbers{$family}?"$Message[112]":"$Message[113]").""; + my $bredde_h=0; + if ($max_h > 0) { $bredde_h=int($BarWidth*($_browser_h{$key}||0)/$max_h)+1; } + if (($bredde_h==1) && $_browser_h{$key}) { $bredde_h=2; } + print "$_browser_h{$key}$p"; + print ""; + # alt and title are not provided to reduce page size + if ($ShowBrowsersStats) { print "
"; } + print ""; + print "\n"; + $count++; + } + } + } + # Write other records + my $familyheadershown=0; + foreach my $key (@keylist) { + if ($keysinkeylist{$key}) { next; } + if (! $familyheadershown) { + my $p=' '; + if ($total_h) { $p=int(($total_h-$TotalFamily)/$total_h*1000)/10; $p="$p %"; } + print "$Message[2]"; + print " ".($total_h-$TotalFamily)."$p "; + print "\n"; + $familyheadershown=1; + } + my $p=' '; + if ($total_h) { $p=int($_browser_h{$key}/$total_h*1000)/10; $p="$p %"; } + print ""; + if ($key eq 'Unknown') { + print "$Message[0]?"; + } + else { + my $keywithoutcumul=$key; $keywithoutcumul =~ s/cumul$//i; + my $libbrowser=$BrowsersHashIDLib{$keywithoutcumul}||$keywithoutcumul; + my $nameicon=$BrowsersHashIcon{$keywithoutcumul}||"notavailable"; + print "$libbrowser".($BrowsersHereAreGrabbers{$key}?"$Message[112]":"$Message[113]").""; + } + my $bredde_h=0; + if ($max_h > 0) { $bredde_h=int($BarWidth*($_browser_h{$key}||0)/$max_h)+1; } + if (($bredde_h==1) && $_browser_h{$key}) { $bredde_h=2; } + print "$_browser_h{$key}$p"; + print ""; + # alt and title are not provided to reduce page size + if ($ShowBrowsersStats) { print "
"; } + print ""; + print "\n"; + } + &tab_end(); + &html_end(1); + } + if ($HTMLOutput{'refererse'}) { + print "$Center 
\n"; + my $title="$Message[40]"; + &tab_head("$title",19,0,'refererse'); + print "$TotalDifferentSearchEngines $Message[122]"; + print "$Message[56]$Message[15]"; + print "$Message[57]$Message[15]"; + print "\n"; + $total_s=0; + my $count=0; + &BuildKeyList($MaxRowsInHTMLOutput,$MinHit{'Refer'},\%_se_referrals_h,((scalar keys %_se_referrals_p)?\%_se_referrals_p:\%_se_referrals_h)); # before 5.4 only hits were recorded + foreach my $key (@keylist) { + my $newreferer=$SearchEnginesHashLib{$key}||CleanXSS($key); + my $p_p; my $p_h; + if ($TotalSearchEnginesPages) { $p_p=int($_se_referrals_p{$key}/$TotalSearchEnginesPages*1000)/10; } + if ($TotalSearchEnginesHits) { $p_h=int($_se_referrals_h{$key}/$TotalSearchEnginesHits*1000)/10; } + print "$newreferer"; + print "".($_se_referrals_p{$key}?$_se_referrals_p{$key}:' ').""; + print "".($_se_referrals_p{$key}?"$p_p %":' ').""; + print "$_se_referrals_h{$key}"; + print "$p_h %"; + print "\n"; + $total_p += $_se_referrals_p{$key}; + $total_h += $_se_referrals_h{$key}; + $count++; + } + if ($Debug) { debug("Total real / shown : $TotalSearchEnginesPages / $total_p - $TotalSearchEnginesHits / $total_h",2); } + $rest_p=$TotalSearchEnginesPages-$total_p; + $rest_h=$TotalSearchEnginesHits-$total_h; + if ($rest_p > 0 || $rest_h > 0) { + my $p_p;my $p_h; + if ($TotalSearchEnginesPages) { $p_p=int($rest_p/$TotalSearchEnginesPages*1000)/10; } + if ($TotalSearchEnginesHits) { $p_h=int($rest_h/$TotalSearchEnginesHits*1000)/10; } + print "$Message[2]"; + print "".($rest_p?$rest_p:' ').""; + print "".($rest_p?"$p_p %":' ').""; + print "$rest_h"; + print "$p_h %"; + print "\n"; + } + &tab_end(); + &html_end(1); + } + if ($HTMLOutput{'refererpages'}) { + print "$Center 
\n"; + # Show filter form + &ShowFormFilter("refererpagesfilter",$FilterIn{'refererpages'},$FilterEx{'refererpages'}); + my $title="$Message[41]"; my $cpt=0; + $cpt=(scalar keys %_pagesrefs_h); + &tab_head("$title",19,0,'refererpages'); + print ""; + if ($FilterIn{'refererpages'} || $FilterEx{'refererpages'}) { + if ($FilterIn{'refererpages'}) { print "$Message[79] $FilterIn{'refererpages'}"; } + if ($FilterIn{'refererpages'} && $FilterEx{'refererpages'}) { print " - "; } + if ($FilterEx{'refererpages'}) { print "Exclude $Message[79] $FilterEx{'refererpages'}"; } + if ($FilterIn{'refererpages'} || $FilterEx{'refererpages'}) { print ": "; } + print "$cpt $Message[28]"; + #if ($MonthRequired ne 'all') { + # if ($HTMLOutput{'refererpages'}) { print "
$Message[102]: $TotalDifferentPages $Message[28]"; } + #} + } + else { print "$Message[102]: $cpt $Message[28]"; } + print ""; + print "$Message[56]$Message[15]"; + print "$Message[57]$Message[15]"; + print "\n"; + $total_s=0; + my $count=0; + &BuildKeyList($MaxRowsInHTMLOutput,$MinHit{'Refer'},\%_pagesrefs_h,((scalar keys %_pagesrefs_p)?\%_pagesrefs_p:\%_pagesrefs_h)); + foreach my $key (@keylist) { + my $nompage=CleanXSS($key); + if (length($nompage)>$MaxLengthOfShownURL) { $nompage=substr($nompage,0,$MaxLengthOfShownURL)."..."; } + my $p_p; my $p_h; + if ($TotalRefererPages) { $p_p=int($_pagesrefs_p{$key}/$TotalRefererPages*1000)/10; } + if ($TotalRefererHits) { $p_h=int($_pagesrefs_h{$key}/$TotalRefererHits*1000)/10; } + print ""; + &ShowURLInfo($key); + print ""; + print "".($_pagesrefs_p{$key}?$_pagesrefs_p{$key}:' ')."".($_pagesrefs_p{$key}?"$p_p %":' ').""; + print "".($_pagesrefs_h{$key}?$_pagesrefs_h{$key}:' ')."".($_pagesrefs_h{$key}?"$p_h %":' ').""; + print "\n"; + $total_p += $_pagesrefs_p{$key}; + $total_h += $_pagesrefs_h{$key}; + $count++; + } + if ($Debug) { debug("Total real / shown : $TotalRefererPages / $total_p - $TotalRefererHits / $total_h",2); } + $rest_p=$TotalRefererPages-$total_p; + $rest_h=$TotalRefererHits-$total_h; + if ($rest_p > 0 || $rest_h > 0) { + my $p_p; my $p_h; + if ($TotalRefererPages) { $p_p=int($rest_p/$TotalRefererPages*1000)/10; } + if ($TotalRefererHits) { $p_h=int($rest_h/$TotalRefererHits*1000)/10; } + print "$Message[2]"; + print "".($rest_p?$rest_p:' ').""; + print "".($rest_p?"$p_p %":' ').""; + print "$rest_h"; + print "$p_h %"; + print "\n"; + } + &tab_end(); + &html_end(1); + } + if ($HTMLOutput{'keyphrases'}) { + print "$Center 
\n"; + &tab_head($Message[43],19,0,'keyphrases'); + print "$TotalDifferentKeyphrases $Message[103]$Message[14]$Message[15]\n"; + $total_s=0; + my $count=0; + &BuildKeyList($MaxRowsInHTMLOutput,$MinHit{'Keyphrase'},\%_keyphrases,\%_keyphrases); + foreach my $key (@keylist) { + my $mot; + # Convert coded keywords (utf8,...) to be correctly reported in HTML page. + if ($PluginsLoaded{'DecodeKey'}{'decodeutfkeys'}) { $mot=CleanXSS(DecodeKey_decodeutfkeys($key,$PageCode||'iso-8859-1')); } + else { $mot = CleanXSS(DecodeEncodedString($key)); } + my $p; + if ($TotalKeyphrases) { $p=int($_keyphrases{$key}/$TotalKeyphrases*1000)/10; } + print "".XMLEncode($mot)."$_keyphrases{$key}$p %\n"; + $total_s += $_keyphrases{$key}; + $count++; + } + if ($Debug) { debug("Total real / shown : $TotalKeyphrases / $total_s",2); } + $rest_s=$TotalKeyphrases-$total_s; + if ($rest_s > 0) { + my $p; + if ($TotalKeyphrases) { $p=int($rest_s/$TotalKeyphrases*1000)/10; } + print "$Message[124]$rest_s"; + print "$p %\n"; + } + &tab_end(); + &html_end(1); + } + if ($HTMLOutput{'keywords'}) { + print "$Center 
\n"; + &tab_head($Message[44],19,0,'keywords'); + print "$TotalDifferentKeywords $Message[13]$Message[14]$Message[15]\n"; + $total_s=0; + my $count=0; + &BuildKeyList($MaxRowsInHTMLOutput,$MinHit{'Keyword'},\%_keywords,\%_keywords); + foreach my $key (@keylist) { + my $mot; + # Convert coded keywords (utf8,...) to be correctly reported in HTML page. + if ($PluginsLoaded{'DecodeKey'}{'decodeutfkeys'}) { $mot=CleanXSS(DecodeKey_decodeutfkeys($key,$PageCode||'iso-8859-1')); } + else { $mot = CleanXSS(DecodeEncodedString($key)); } + my $p; + if ($TotalKeywords) { $p=int($_keywords{$key}/$TotalKeywords*1000)/10; } + print "".XMLEncode($mot)."$_keywords{$key}$p %\n"; + $total_s += $_keywords{$key}; + $count++; + } + if ($Debug) { debug("Total real / shown : $TotalKeywords / $total_s",2); } + $rest_s=$TotalKeywords-$total_s; + if ($rest_s > 0) { + my $p; + if ($TotalKeywords) { $p=int($rest_s/$TotalKeywords*1000)/10; } + print "$Message[30]$rest_s"; + print "$p %\n"; + } + &tab_end(); + &html_end(1); + } + foreach my $code (keys %TrapInfosForHTTPErrorCodes) { + if ($HTMLOutput{"errors$code"}) { + print "$Center 
\n"; + &tab_head($Message[47],19,0,"errors$code"); + print "URL (".(scalar keys %_sider404_h).")$Message[49]$Message[23]\n"; + $total_h=0; + my $count=0; + &BuildKeyList($MaxRowsInHTMLOutput,1,\%_sider404_h,\%_sider404_h); + foreach my $key (@keylist) { + my $nompage=XMLEncode(CleanXSS($key)); + #if (length($nompage)>$MaxLengthOfShownURL) { $nompage=substr($nompage,0,$MaxLengthOfShownURL)."..."; } + my $referer=XMLEncode(CleanXSS($_referer404_h{$key})); + print "$nompage"; + print "$_sider404_h{$key}"; + print "".($referer?"$referer":" ").""; + print "\n"; + $total_s += $_sider404_h{$key}; + $count++; + } + # TODO Build TotalErrorHits + # if ($Debug) { debug("Total real / shown : $TotalErrorHits / $total_h",2); } + # $rest_h=$TotalErrorHits-$total_h; + # if ($rest_h > 0) { + # my $p; + # if ($TotalErrorHits) { $p=int($rest_h/$TotalErrorHits*1000)/10; } + # print "$Message[30]"; + # print "$rest_h"; + # print "..."; + # print "\n"; + # } + &tab_end(); + &html_end(1); + } + } + if ($HTMLOutput{'info'}) { + # Not yet available + print "$Center 
"; + &html_end(1); + } + + my $htmloutput=''; + foreach my $key (keys %HTMLOutput) { $htmloutput=$key; } + if ($htmloutput =~ /^plugin_(\w+)$/) { + my $pluginname=$1; + print "$Center 
"; +# my $function="AddHTMLGraph_$pluginname()"; +# eval("$function"); + my $function="AddHTMLGraph_$pluginname"; + &$function(); + &html_end(1); + } + } + + # Output main page + #----------------- + + if ($HTMLOutput{'main'}) { + + # SUMMARY + #--------------------------------------------------------------------- + if ($ShowSummary) { + if ($Debug) { debug("ShowSummary",2); } + #print "$Center 
\n"; + my $title="$Message[128]"; + &tab_head("$title",0,0,'month'); + + my $NewLinkParams=${QueryString}; + $NewLinkParams =~ s/(^|&|&)update(=\w*|$)//i; + $NewLinkParams =~ s/(^|&|&)staticlinks(=\w*|$)//i; + $NewLinkParams =~ s/(^|&|&)year=[^&]*//i; + $NewLinkParams =~ s/(^|&|&)month=[^&]*//i; + $NewLinkParams =~ s/(^|&|&)framename=[^&]*//i; + $NewLinkParams =~ s/(&|&)+/&/i; + $NewLinkParams =~ s/^&//; $NewLinkParams =~ s/&$//; + if ($NewLinkParams) { $NewLinkParams="${NewLinkParams}&"; } + my $NewLinkTarget=''; + if ($FrameName eq 'mainright') { $NewLinkTarget=" target=\"_parent\""; } + + # Ratio + my $RatioVisits=0; my $RatioPages=0; my $RatioHits=0; my $RatioBytes=0; + if ($TotalUnique > 0) { $RatioVisits=int($TotalVisits/$TotalUnique*100)/100; } + if ($TotalVisits > 0) { $RatioPages=int($TotalPages/$TotalVisits*100)/100; } + if ($TotalVisits > 0) { $RatioHits=int($TotalHits/$TotalVisits*100)/100; } + if ($TotalVisits > 0) { $RatioBytes=int(($TotalBytes/1024)*100/($LogType eq 'M'?$TotalHits:$TotalVisits))/100; } + + my $colspan=5; + my $w='20'; + if ($LogType eq 'W' || $LogType eq 'S') { $w='17'; $colspan=6; } + + # Show first/last + print ""; + print "$Message[133]\n"; + print ($MonthRequired eq 'all'?"$Message[6] $YearRequired":"$Message[5] ".$MonthNumLib{$MonthRequired}." $YearRequired"); + print "\n"; + print ""; + print "$Message[8]\n"; + print "".($FirstTime?Format_Date($FirstTime,0):"NA").""; + print "\n"; + print ""; + print "$Message[9]\n"; + print "".($LastTime?Format_Date($LastTime,0):"NA")."\n"; + print "\n"; + + # Show main indicators title row + print ""; + if ($LogType eq 'W' || $LogType eq 'S') { print " "; } + if ($ShowSummary =~ /U/i) { print "$Message[11]"; } else { print " "; } + if ($ShowSummary =~ /V/i) { print "$Message[10]"; } else { print " "; } + if ($ShowSummary =~ /P/i) { print "$Message[56]"; } else { print " "; } + if ($ShowSummary =~ /H/i) { print "$Message[57]"; } else { print " "; } + if ($ShowSummary =~ /B/i) { print "$Message[75]"; } else { print " "; } + print "\n"; + # Show main indicators values for viewed traffic + print ""; + if ($LogType eq 'M') { + print "$Message[165]"; + print " 
 \n"; + print " 
 \n"; + if ($ShowSummary =~ /H/i) { print "$TotalHits".($LogType eq 'M'?"":"
($RatioHits ".lc($Message[57]."/".$Message[12]).")").""; } else { print " "; } + if ($ShowSummary =~ /B/i) { print "".Format_Bytes(int($TotalBytes))."
($RatioBytes $Message[108]/".$Message[($LogType eq 'M'?149:12)].")"; } else { print " "; } + } + else { + if ($LogType eq 'W' || $LogType eq 'S') { print "$Message[160] *"; } + if ($ShowSummary =~ /U/i) { print "".($MonthRequired eq 'all'?"<= $TotalUnique
$Message[129]":"$TotalUnique
 ").""; } else { print " "; } + if ($ShowSummary =~ /V/i) { print "$TotalVisits
($RatioVisits $Message[52])"; } else { print " "; } + if ($ShowSummary =~ /P/i) { print "$TotalPages
($RatioPages ".$Message[56]."/".$Message[12].")"; } else { print " "; } + if ($ShowSummary =~ /H/i) { print "$TotalHits".($LogType eq 'M'?"":"
($RatioHits ".$Message[57]."/".$Message[12].")").""; } else { print " "; } + if ($ShowSummary =~ /B/i) { print "".Format_Bytes(int($TotalBytes))."
($RatioBytes $Message[108]/".$Message[($LogType eq 'M'?149:12)].")"; } else { print " "; } + } + print "\n"; + # Show main indicators values for not viewed traffic values + if ($LogType eq 'M' || $LogType eq 'W' || $LogType eq 'S') { + print ""; + if ($LogType eq 'M') { + print "$Message[166]"; + print " 
 \n"; + print " 
 \n"; + if ($ShowSummary =~ /H/i) { print "$TotalNotViewedHits"; } else { print " "; } + if ($ShowSummary =~ /B/i) { print "".Format_Bytes(int($TotalNotViewedBytes)).""; } else { print " "; } + } + else { + if ($LogType eq 'W' || $LogType eq 'S') { print "$Message[161] *"; } + print " 
 \n"; + if ($ShowSummary =~ /P/i) { print "$TotalNotViewedPages"; } else { print " "; } + if ($ShowSummary =~ /H/i) { print "$TotalNotViewedHits"; } else { print " "; } + if ($ShowSummary =~ /B/i) { print "".Format_Bytes(int($TotalNotViewedBytes)).""; } else { print " "; } + } + print "\n"; + } + &tab_end($LogType eq 'W' || $LogType eq 'S'?"* $Message[159]":""); + } + + # BY MONTH + #--------------------------------------------------------------------- + if ($ShowMonthStats) { + + if ($Debug) { debug("ShowMonthStats",2); } + print "$Center 
\n"; + my $title="$Message[162]"; + &tab_head("$title",0,0,'month'); + print "\n"; + print "
\n"; + + $average_nb=$average_u=$average_v=$average_p=$average_h=$average_k=0; + $total_u=$total_v=$total_p=$total_h=$total_k=0; + + $max_v=$max_p=$max_h=$max_k=1; + # Define total and max + for (my $ix=1; $ix<=12; $ix++) { + my $monthix=sprintf("%02s",$ix); + $total_u+=$MonthUnique{$YearRequired.$monthix}||0; + $total_v+=$MonthVisits{$YearRequired.$monthix}||0; + $total_p+=$MonthPages{$YearRequired.$monthix}||0; + $total_h+=$MonthHits{$YearRequired.$monthix}||0; + $total_k+=$MonthBytes{$YearRequired.$monthix}||0; + #if (($MonthUnique{$YearRequired.$monthix}||0) > $max_v) { $max_v=$MonthUnique{$YearRequired.$monthix}; } + if (($MonthVisits{$YearRequired.$monthix}||0) > $max_v) { $max_v=$MonthVisits{$YearRequired.$monthix}; } + #if (($MonthPages{$YearRequired.$monthix}||0) > $max_p) { $max_p=$MonthPages{$YearRequired.$monthix}; } + if (($MonthHits{$YearRequired.$monthix}||0) > $max_h) { $max_h=$MonthHits{$YearRequired.$monthix}; } + if (($MonthBytes{$YearRequired.$monthix}||0) > $max_k) { $max_k=$MonthBytes{$YearRequired.$monthix}; } + } + # Define average + # TODO + + # Show bars for month + if ($PluginsLoaded{'ShowGraph'}{'graphapplet'}) { + my @blocklabel=(); + for (my $ix=1; $ix<=12; $ix++) { + my $monthix=sprintf("%02s",$ix); + push @blocklabel,"$MonthNumLib{$monthix}\§$YearRequired"; + } + my @vallabel=("$Message[11]","$Message[10]","$Message[56]","$Message[57]","$Message[75]"); + my @valcolor=("$color_u","$color_v","$color_p","$color_h","$color_k"); + my @valmax=($max_v,$max_v,$max_h,$max_h,$max_k); + my @valtotal=($total_u,$total_v,$total_p,$total_h,$total_k); + my @valaverage=(); + #my @valaverage=($average_v,$average_p,$average_h,$average_k); + my @valdata=(); + my $xx=0; + for (my $ix=1; $ix<=12; $ix++) { + my $monthix=sprintf("%02s",$ix); + $valdata[$xx++]=$MonthUnique{$YearRequired.$monthix}||0; + $valdata[$xx++]=$MonthVisits{$YearRequired.$monthix}||0; + $valdata[$xx++]=$MonthPages{$YearRequired.$monthix}||0; + $valdata[$xx++]=$MonthHits{$YearRequired.$monthix}||0; + $valdata[$xx++]=$MonthBytes{$YearRequired.$monthix}||0; + } + ShowGraph_graphapplet("$title","month",$ShowMonthStats,\@blocklabel,\@vallabel,\@valcolor,\@valmax,\@valtotal,\@valaverage,\@valdata); + } + else { + print "\n"; + print ""; + print "\n"; + for (my $ix=1; $ix<=12; $ix++) { + my $monthix=sprintf("%02s",$ix); + my $bredde_u=0; my $bredde_v=0;my $bredde_p=0;my $bredde_h=0;my $bredde_k=0; + if ($max_v > 0) { $bredde_u=int(($MonthUnique{$YearRequired.$monthix}||0)/$max_v*$BarHeight)+1; } + if ($max_v > 0) { $bredde_v=int(($MonthVisits{$YearRequired.$monthix}||0)/$max_v*$BarHeight)+1; } + if ($max_h > 0) { $bredde_p=int(($MonthPages{$YearRequired.$monthix}||0)/$max_h*$BarHeight)+1; } + if ($max_h > 0) { $bredde_h=int(($MonthHits{$YearRequired.$monthix}||0)/$max_h*$BarHeight)+1; } + if ($max_k > 0) { $bredde_k=int(($MonthBytes{$YearRequired.$monthix}||0)/$max_k*$BarHeight)+1; } + print "\n"; + } + print ""; + print "\n"; + # Show lib for month + print ""; +# if (!$StaticLinks) { +# print ""; +# } +# else { + print ""; +# } + for (my $ix=1; $ix<=12; $ix++) { + my $monthix=sprintf("%02s",$ix); +# if (!$StaticLinks) { +# print ""; +# } +# else { + print ""; +# } + } +# if (!$StaticLinks) { +# print ""; +# } +# else { + print ""; +# } + print "\n"; + print "
 "; + if ($ShowMonthStats =~ /U/i) { print ""; } + if ($ShowMonthStats =~ /V/i) { print ""; } + if ($ShowMonthStats =~ /P/i) { print ""; } + if ($ShowMonthStats =~ /H/i) { print ""; } + if ($ShowMonthStats =~ /B/i) { print ""; } + print " 
<< $MonthNumLib{$monthix}
$YearRequired
".(! $StaticLinks && $monthix==$nowmonth && $YearRequired==$nowyear?'':''); + print "$MonthNumLib{$monthix}
$YearRequired"; + print (! $StaticLinks && $monthix==$nowmonth && $YearRequired==$nowyear?'
':''); + print "
>> 
\n"; + } + print "
\n"; + + # Show data array for month + if ($AddDataArrayMonthStats) { + print "\n"; + print ""; + if ($ShowMonthStats =~ /U/i) { print ""; } + if ($ShowMonthStats =~ /V/i) { print ""; } + if ($ShowMonthStats =~ /P/i) { print ""; } + if ($ShowMonthStats =~ /H/i) { print ""; } + if ($ShowMonthStats =~ /B/i) { print ""; } + print "\n"; + for (my $ix=1; $ix<=12; $ix++) { + my $monthix=sprintf("%02s",$ix); + print ""; + print ""; + if ($ShowMonthStats =~ /U/i) { print ""; } + if ($ShowMonthStats =~ /V/i) { print ""; } + if ($ShowMonthStats =~ /P/i) { print ""; } + if ($ShowMonthStats =~ /H/i) { print ""; } + if ($ShowMonthStats =~ /B/i) { print ""; } + print "\n"; + } + # Average row + # TODO + # Total row + print ""; + if ($ShowMonthStats =~ /U/i) { print ""; } + if ($ShowMonthStats =~ /V/i) { print ""; } + if ($ShowMonthStats =~ /P/i) { print ""; } + if ($ShowMonthStats =~ /H/i) { print ""; } + if ($ShowMonthStats =~ /B/i) { print ""; } + print "\n"; + print "
$Message[5]$Message[11]$Message[10]$Message[56]$Message[57]$Message[75]
".(! $StaticLinks && $monthix==$nowmonth && $YearRequired==$nowyear?'':''); + print "$MonthNumLib{$monthix} $YearRequired"; + print (! $StaticLinks && $monthix==$nowmonth && $YearRequired==$nowyear?'':''); + print "",$MonthUnique{$YearRequired.$monthix}?$MonthUnique{$YearRequired.$monthix}:"0","",$MonthVisits{$YearRequired.$monthix}?$MonthVisits{$YearRequired.$monthix}:"0","",$MonthPages{$YearRequired.$monthix}?$MonthPages{$YearRequired.$monthix}:"0","",$MonthHits{$YearRequired.$monthix}?$MonthHits{$YearRequired.$monthix}:"0","",Format_Bytes(int($MonthBytes{$YearRequired.$monthix}||0)),"
$Message[102]$total_u$total_v$total_p$total_h".Format_Bytes($total_k)."
\n
\n"; + } + + print "
\n"; + print "\n"; + &tab_end(); + } + + print "\n \n\n"; + + # BY DAY OF MONTH + #--------------------------------------------------------------------- + if ($ShowDaysOfMonthStats) { + if ($Debug) { debug("ShowDaysOfMonthStats",2); } + print "$Center 
\n"; + my $title="$Message[138]"; + &tab_head("$title",0,0,'daysofmonth'); + print ""; + print "\n"; + print "
\n"; + + my $NewLinkParams=${QueryString}; + $NewLinkParams =~ s/(^|&|&)update(=\w*|$)//i; + $NewLinkParams =~ s/(^|&|&)staticlinks(=\w*|$)//i; + $NewLinkParams =~ s/(^|&|&)year=[^&]*//i; + $NewLinkParams =~ s/(^|&|&)month=[^&]*//i; + $NewLinkParams =~ s/(^|&|&)framename=[^&]*//i; + $NewLinkParams =~ s/(&|&)+/&/i; + $NewLinkParams =~ s/^&//; $NewLinkParams =~ s/&$//; + if ($NewLinkParams) { $NewLinkParams="${NewLinkParams}&"; } + my $NewLinkTarget=''; + if ($FrameName eq 'mainright') { $NewLinkTarget=" target=\"_parent\""; } + + $average_nb=$average_u=$average_v=$average_p=$average_h=$average_k=0; + $total_u=$total_v=$total_p=$total_h=$total_k=0; + # Define total and max + $max_v=$max_h=$max_k=0; # Start from 0 because can be lower than 1 + foreach my $daycursor ($firstdaytoshowtime..$lastdaytoshowtime) { + $daycursor =~ /^(\d\d\d\d)(\d\d)(\d\d)/; + my $year=$1; my $month=$2; my $day=$3; + if (! DateIsValid($day,$month,$year)) { next; } # If not an existing day, go to next + $total_v+=$DayVisits{$year.$month.$day}||0; + $total_p+=$DayPages{$year.$month.$day}||0; + $total_h+=$DayHits{$year.$month.$day}||0; + $total_k+=$DayBytes{$year.$month.$day}||0; + if (($DayVisits{$year.$month.$day}||0) > $max_v) { $max_v=$DayVisits{$year.$month.$day}; } + #if (($DayPages{$year.$month.$day}||0) > $max_p) { $max_p=$DayPages{$year.$month.$day}; } + if (($DayHits{$year.$month.$day}||0) > $max_h) { $max_h=$DayHits{$year.$month.$day}; } + if (($DayBytes{$year.$month.$day}||0) > $max_k) { $max_k=$DayBytes{$year.$month.$day}; } + } + # Define average + foreach my $daycursor ($firstdaytocountaverage..$lastdaytocountaverage) { + $daycursor =~ /^(\d\d\d\d)(\d\d)(\d\d)/; + my $year=$1; my $month=$2; my $day=$3; + if (! DateIsValid($day,$month,$year)) { next; } # If not an existing day, go to next + $average_nb++; # Increase number of day used to count + $average_v+=($DayVisits{$daycursor}||0); + $average_p+=($DayPages{$daycursor}||0); + $average_h+=($DayHits{$daycursor}||0); + $average_k+=($DayBytes{$daycursor}||0); + } + if ($average_nb) { + $average_v=$average_v/$average_nb; + $average_p=$average_p/$average_nb; + $average_h=$average_h/$average_nb; + $average_k=$average_k/$average_nb; + if ($average_v > $max_v) { $max_v=$average_v; } + #if ($average_p > $max_p) { $max_p=$average_p; } + if ($average_h > $max_h) { $max_h=$average_h; } + if ($average_k > $max_k) { $max_k=$average_k; } + } + else { + $average_v="?"; + $average_p="?"; + $average_h="?"; + $average_k="?"; + } + + # Show bars for day + if ($PluginsLoaded{'ShowGraph'}{'graphapplet'}) { + my @blocklabel=(); + foreach my $daycursor ($firstdaytoshowtime..$lastdaytoshowtime) { + $daycursor =~ /^(\d\d\d\d)(\d\d)(\d\d)/; + my $year=$1; my $month=$2; my $day=$3; + if (! DateIsValid($day,$month,$year)) { next; } # If not an existing day, go to next + my $bold=($day==$nowday && $month==$nowmonth && $year==$nowyear?':':''); + my $weekend=(DayOfWeek($day,$month,$year)=~/[06]/?'!':''); + push @blocklabel,"$day§$MonthNumLib{$month}$weekend$bold"; + } + my @vallabel=("$Message[10]","$Message[56]","$Message[57]","$Message[75]"); + my @valcolor=("$color_v","$color_p","$color_h","$color_k"); + my @valmax=($max_v,$max_h,$max_h,$max_k); + my @valtotal=($total_v,$total_p,$total_h,$total_k); + $average_v=sprintf("%.2f",$average_v); + $average_p=sprintf("%.2f",$average_p); + $average_h=sprintf("%.2f",$average_h); + $average_k=(int($average_k)?Format_Bytes(sprintf("%.2f",$average_k)):"0.00"); + my @valaverage=($average_v,$average_p,$average_h,$average_k); + my @valdata=(); + my $xx=0; + foreach my $daycursor ($firstdaytoshowtime..$lastdaytoshowtime) { + $daycursor =~ /^(\d\d\d\d)(\d\d)(\d\d)/; + my $year=$1; my $month=$2; my $day=$3; + if (! DateIsValid($day,$month,$year)) { next; } # If not an existing day, go to next + $valdata[$xx++]=$DayVisits{$year.$month.$day}||0; + $valdata[$xx++]=$DayPages{$year.$month.$day}||0; + $valdata[$xx++]=$DayHits{$year.$month.$day}||0; + $valdata[$xx++]=$DayBytes{$year.$month.$day}||0; + } + ShowGraph_graphapplet("$title","daysofmonth",$ShowDaysOfMonthStats,\@blocklabel,\@vallabel,\@valcolor,\@valmax,\@valtotal,\@valaverage,\@valdata); + } + else { + print "\n"; + print "\n"; + foreach my $daycursor ($firstdaytoshowtime..$lastdaytoshowtime) { + $daycursor =~ /^(\d\d\d\d)(\d\d)(\d\d)/; + my $year=$1; my $month=$2; my $day=$3; + if (! DateIsValid($day,$month,$year)) { next; } # If not an existing day, go to next + my $bredde_v=0; my $bredde_p=0; my $bredde_h=0; my $bredde_k=0; + if ($max_v > 0) { $bredde_v=int(($DayVisits{$year.$month.$day}||0)/$max_v*$BarHeight)+1; } + if ($max_h > 0) { $bredde_p=int(($DayPages{$year.$month.$day}||0)/$max_h*$BarHeight)+1; } + if ($max_h > 0) { $bredde_h=int(($DayHits{$year.$month.$day}||0)/$max_h*$BarHeight)+1; } + if ($max_k > 0) { $bredde_k=int(($DayBytes{$year.$month.$day}||0)/$max_k*$BarHeight)+1; } + print "\n"; + } + print ""; + # Show average value cell + print "\n"; + print "\n"; + # Show lib for day + print ""; + foreach my $daycursor ($firstdaytoshowtime..$lastdaytoshowtime) { + $daycursor =~ /^(\d\d\d\d)(\d\d)(\d\d)/; + my $year=$1; my $month=$2; my $day=$3; + if (! DateIsValid($day,$month,$year)) { next; } # If not an existing day, go to next + my $dayofweekcursor=DayOfWeek($day,$month,$year); + print ""; + print (! $StaticLinks && $day==$nowday && $month==$nowmonth && $year==$nowyear?'':''); + print "$day
".$MonthNumLib{$month}.""; + print (! $StaticLinks && $day==$nowday && $month==$nowmonth && $year==$nowyear?'
':''); + print "\n"; + } + print "
"; + print "\n"; + print "\n"; + print "
"; + if ($ShowDaysOfMonthStats =~ /V/i) { print ""; } + if ($ShowDaysOfMonthStats =~ /P/i) { print ""; } + if ($ShowDaysOfMonthStats =~ /H/i) { print ""; } + if ($ShowDaysOfMonthStats =~ /B/i) { print ""; } + print " "; + my $bredde_v=0; my $bredde_p=0; my $bredde_h=0; my $bredde_k=0; + if ($max_v > 0) { $bredde_v=int($average_v/$max_v*$BarHeight)+1; } + if ($max_h > 0) { $bredde_p=int($average_p/$max_h*$BarHeight)+1; } + if ($max_h > 0) { $bredde_h=int($average_h/$max_h*$BarHeight)+1; } + if ($max_k > 0) { $bredde_k=int($average_k/$max_k*$BarHeight)+1; } + $average_v=sprintf("%.2f",$average_v); + $average_p=sprintf("%.2f",$average_p); + $average_h=sprintf("%.2f",$average_h); + $average_k=(int($average_k)?Format_Bytes(sprintf("%.2f",$average_k)):"0.00"); + if ($ShowDaysOfMonthStats =~ /V/i) { print ""; } + if ($ShowDaysOfMonthStats =~ /P/i) { print ""; } + if ($ShowDaysOfMonthStats =~ /H/i) { print ""; } + if ($ShowDaysOfMonthStats =~ /B/i) { print ""; } + print "
 $Message[96]
\n"; + } + print "
\n"; + + # Show data array for days + if ($AddDataArrayShowDaysOfMonthStats) { + print "\n"; + print ""; + if ($ShowDaysOfMonthStats =~ /V/i) { print ""; } + if ($ShowDaysOfMonthStats =~ /P/i) { print ""; } + if ($ShowDaysOfMonthStats =~ /H/i) { print ""; } + if ($ShowDaysOfMonthStats =~ /B/i) { print ""; } + print ""; + foreach my $daycursor ($firstdaytoshowtime..$lastdaytoshowtime) { + $daycursor =~ /^(\d\d\d\d)(\d\d)(\d\d)/; + my $year=$1; my $month=$2; my $day=$3; + if (! DateIsValid($day,$month,$year)) { next; } # If not an existing day, go to next + my $dayofweekcursor=DayOfWeek($day,$month,$year); + print ""; + print ""; + if ($ShowDaysOfMonthStats =~ /V/i) { print ""; } + if ($ShowDaysOfMonthStats =~ /P/i) { print ""; } + if ($ShowDaysOfMonthStats =~ /H/i) { print ""; } + if ($ShowDaysOfMonthStats =~ /B/i) { print ""; } + print "\n"; + } + # Average row + print ""; + if ($ShowDaysOfMonthStats =~ /V/i) { print ""; } + if ($ShowDaysOfMonthStats =~ /P/i) { print ""; } + if ($ShowDaysOfMonthStats =~ /H/i) { print ""; } + if ($ShowDaysOfMonthStats =~ /B/i) { print ""; } + print "\n"; + # Total row + print ""; + if ($ShowDaysOfMonthStats =~ /V/i) { print ""; } + if ($ShowDaysOfMonthStats =~ /P/i) { print ""; } + if ($ShowDaysOfMonthStats =~ /H/i) { print ""; } + if ($ShowDaysOfMonthStats =~ /B/i) { print ""; } + print "\n"; + print "
$Message[4]$Message[10]$Message[56]$Message[57]$Message[75]
".(! $StaticLinks && $day==$nowday && $month==$nowmonth && $year==$nowyear?'':''); + print Format_Date("$year$month$day"."000000",2); + print (! $StaticLinks && $day==$nowday && $month==$nowmonth && $year==$nowyear?'':''); + print "",$DayVisits{$year.$month.$day}?$DayVisits{$year.$month.$day}:"0","",$DayPages{$year.$month.$day}?$DayPages{$year.$month.$day}:"0","",$DayHits{$year.$month.$day}?$DayHits{$year.$month.$day}:"0","",Format_Bytes(int($DayBytes{$year.$month.$day}||0)),"
$Message[96]$average_v$average_p$average_h$average_k
$Message[102]$total_v$total_p$total_h".Format_Bytes($total_k)."
\n
"; + } + + print "
\n"; + print "\n"; + &tab_end(); + } + + # BY DAY OF WEEK + #------------------------- + if ($ShowDaysOfWeekStats) { + if ($Debug) { debug("ShowDaysOfWeekStats",2); } + print "$Center 
\n"; + my $title="$Message[91]"; + &tab_head("$title",18,0,'daysofweek'); + print ""; + print ""; + print "
\n"; + + $max_h=$max_k=0; # Start from 0 because can be lower than 1 + # Get average value for day of week + my @avg_dayofweek_nb=(); my @avg_dayofweek_p=(); my @avg_dayofweek_h=(); my @avg_dayofweek_k=(); + foreach my $daycursor ($firstdaytocountaverage..$lastdaytocountaverage) { + $daycursor =~ /^(\d\d\d\d)(\d\d)(\d\d)/; + my $year=$1; my $month=$2; my $day=$3; + if (! DateIsValid($day,$month,$year)) { next; } # If not an existing day, go to next + my $dayofweekcursor=DayOfWeek($day,$month,$year); + $avg_dayofweek_nb[$dayofweekcursor]++; # Increase number of day used to count for this day of week + $avg_dayofweek_p[$dayofweekcursor]+=($DayPages{$daycursor}||0); + $avg_dayofweek_h[$dayofweekcursor]+=($DayHits{$daycursor}||0); + $avg_dayofweek_k[$dayofweekcursor]+=($DayBytes{$daycursor}||0); + } + for (@DOWIndex) { + if ($avg_dayofweek_nb[$_]) { + $avg_dayofweek_p[$_]=$avg_dayofweek_p[$_]/$avg_dayofweek_nb[$_]; + $avg_dayofweek_h[$_]=$avg_dayofweek_h[$_]/$avg_dayofweek_nb[$_]; + $avg_dayofweek_k[$_]=$avg_dayofweek_k[$_]/$avg_dayofweek_nb[$_]; + #if ($avg_dayofweek_p[$_] > $max_p) { $max_p = $avg_dayofweek_p[$_]; } + if ($avg_dayofweek_h[$_] > $max_h) { $max_h = $avg_dayofweek_h[$_]; } + if ($avg_dayofweek_k[$_] > $max_k) { $max_k = $avg_dayofweek_k[$_]; } + } + else { + $avg_dayofweek_p[$_]="?"; + $avg_dayofweek_h[$_]="?"; + $avg_dayofweek_k[$_]="?"; + } + } + + # Show bars for days of week + if ($PluginsLoaded{'ShowGraph'}{'graphapplet'}) { + my @blocklabel=(); + for (@DOWIndex) { push @blocklabel,($Message[$_+84].($_=~/[06]/?"!":"")); } + my @vallabel=("$Message[56]","$Message[57]","$Message[75]"); + my @valcolor=("$color_p","$color_h","$color_k"); + my @valmax=(int($max_h),int($max_h),int($max_k)); + my @valtotal=($total_p,$total_h,$total_k); + $average_p=sprintf("%.2f",$average_p); + $average_h=sprintf("%.2f",$average_h); + $average_k=(int($average_k)?Format_Bytes(sprintf("%.2f",$average_k)):"0.00"); + my @valaverage=($average_p,$average_h,$average_k); + my @valdata=(); + my $xx=0; + for (@DOWIndex) { + $valdata[$xx++]=$avg_dayofweek_p[$_]||0; + $valdata[$xx++]=$avg_dayofweek_h[$_]||0; + $valdata[$xx++]=$avg_dayofweek_k[$_]||0; + # Round to be ready to show array + $avg_dayofweek_p[$_]=sprintf("%.2f",$avg_dayofweek_p[$_]); + $avg_dayofweek_h[$_]=sprintf("%.2f",$avg_dayofweek_h[$_]); + $avg_dayofweek_k[$_]=sprintf("%.2f",$avg_dayofweek_k[$_]); + # Remove decimal part that are .0 + if ($avg_dayofweek_p[$_] == int($avg_dayofweek_p[$_])) { $avg_dayofweek_p[$_]=int($avg_dayofweek_p[$_]); } + if ($avg_dayofweek_h[$_] == int($avg_dayofweek_h[$_])) { $avg_dayofweek_h[$_]=int($avg_dayofweek_h[$_]); } + } + ShowGraph_graphapplet("$title","daysofweek",$ShowDaysOfWeekStats,\@blocklabel,\@vallabel,\@valcolor,\@valmax,\@valtotal,\@valaverage,\@valdata); + } + else { + print "\n"; + print "\n"; + for (@DOWIndex) { + my $bredde_p=0; my $bredde_h=0; my $bredde_k=0; + if ($max_h > 0) { $bredde_p=int(($avg_dayofweek_p[$_]ne'?'?$avg_dayofweek_p[$_]:0)/$max_h*$BarHeight)+1; } + if ($max_h > 0) { $bredde_h=int(($avg_dayofweek_h[$_]ne'?'?$avg_dayofweek_h[$_]:0)/$max_h*$BarHeight)+1; } + if ($max_k > 0) { $bredde_k=int(($avg_dayofweek_k[$_]ne'?'?$avg_dayofweek_k[$_]:0)/$max_k*$BarHeight)+1; } + $avg_dayofweek_p[$_]=sprintf("%.2f",($avg_dayofweek_p[$_]ne'?'?$avg_dayofweek_p[$_]:0)); + $avg_dayofweek_h[$_]=sprintf("%.2f",($avg_dayofweek_h[$_]ne'?'?$avg_dayofweek_h[$_]:0)); + $avg_dayofweek_k[$_]=sprintf("%.2f",($avg_dayofweek_k[$_]ne'?'?$avg_dayofweek_k[$_]:0)); + # Remove decimal part that are .0 + if ($avg_dayofweek_p[$_] == int($avg_dayofweek_p[$_])) { $avg_dayofweek_p[$_]=int($avg_dayofweek_p[$_]); } + if ($avg_dayofweek_h[$_] == int($avg_dayofweek_h[$_])) { $avg_dayofweek_h[$_]=int($avg_dayofweek_h[$_]); } + print "\n"; + } + print "\n"; + print "\n"; + for (@DOWIndex) { + print "".(! $StaticLinks && $_==($nowwday-1) && $MonthRequired==$nowmonth && $YearRequired==$nowyear?'':''); + print $Message[$_+84]; + print (! $StaticLinks && $_==($nowwday-1) && $MonthRequired==$nowmonth && $YearRequired==$nowyear?'':''); + print ""; + } + print "\n
"; + if ($ShowDaysOfWeekStats =~ /P/i) { print ""; } + if ($ShowDaysOfWeekStats =~ /H/i) { print ""; } + if ($ShowDaysOfWeekStats =~ /B/i) { print ""; } + print "
\n"; + } + print "
\n"; + + # Show data array for days of week + if ($AddDataArrayShowDaysOfWeekStats) { + print "\n"; + print ""; + if ($ShowDaysOfWeekStats =~ /P/i) { print ""; } + if ($ShowDaysOfWeekStats =~ /H/i) { print ""; } + if ($ShowDaysOfWeekStats =~ /B/i) { print ""; } + for (@DOWIndex) { + print ""; + print ""; + if ($ShowDaysOfWeekStats =~ /P/i) { print ""; } + if ($ShowDaysOfWeekStats =~ /H/i) { print ""; } + if ($ShowDaysOfWeekStats =~ /B/i) { print ""; } + print "\n"; + } + print "
$Message[4]$Message[56]$Message[57]$Message[75]
".(! $StaticLinks && $_==($nowwday-1) && $MonthRequired==$nowmonth && $YearRequired==$nowyear?'':''); + print $Message[$_+84]; + print (! $StaticLinks && $_==($nowwday-1) && $MonthRequired==$nowmonth && $YearRequired==$nowyear?'':''); + print "",$avg_dayofweek_p[$_],"",$avg_dayofweek_h[$_],"",Format_Bytes($avg_dayofweek_k[$_]),"
\n
\n"; + } + + print "
"; + print "\n"; + &tab_end(); + } + + # BY HOUR + #---------------------------- + if ($ShowHoursStats) { + if ($Debug) { debug("ShowHoursStats",2); } + print "$Center 
\n"; + my $title="$Message[20]"; + if ($PluginsLoaded{'GetTimeZoneTitle'}{'timezone'}) { $title.=" (GMT ".(GetTimeZoneTitle_timezone()>=0?"+":"").int(GetTimeZoneTitle_timezone()).")"; } + &tab_head("$title",19,0,'hours'); + print "\n"; + print "
\n"; + + $max_h=$max_k=1; + for (my $ix=0; $ix<=23; $ix++) { + #if ($_time_p[$ix]>$max_p) { $max_p=$_time_p[$ix]; } + if ($_time_h[$ix]>$max_h) { $max_h=$_time_h[$ix]; } + if ($_time_k[$ix]>$max_k) { $max_k=$_time_k[$ix]; } + } + + # Show bars for hour + if ($PluginsLoaded{'ShowGraph'}{'graphapplet'}) { + my @blocklabel=(0..23); + my @vallabel=("$Message[56]","$Message[57]","$Message[75]"); + my @valcolor=("$color_p","$color_h","$color_k"); + my @valmax=(int($max_h),int($max_h),int($max_k)); + my @valtotal=($total_p,$total_h,$total_k); + my @valaverage=($average_p,$average_h,$average_k); + my @valdata=(); + my $xx=0; + for (0..23) { + $valdata[$xx++]=$_time_p[$_]||0; + $valdata[$xx++]=$_time_h[$_]||0; + $valdata[$xx++]=$_time_k[$_]||0; + } + ShowGraph_graphapplet("$title","hours",$ShowHoursStats,\@blocklabel,\@vallabel,\@valcolor,\@valmax,\@valtotal,\@valaverage,\@valdata); + } + else { + print "\n"; + print "\n"; + for (my $ix=0; $ix<=23; $ix++) { + my $bredde_p=0;my $bredde_h=0;my $bredde_k=0; + if ($max_h > 0) { $bredde_p=int($BarHeight*$_time_p[$ix]/$max_h)+1; } + if ($max_h > 0) { $bredde_h=int($BarHeight*$_time_h[$ix]/$max_h)+1; } + if ($max_k > 0) { $bredde_k=int($BarHeight*$_time_k[$ix]/$max_k)+1; } + print "\n"; + } + print "\n"; + # Show hour lib + print ""; + for (my $ix=0; $ix<=23; $ix++) { + print "\n"; # width=19 instead of 18 to avoid a MacOS browser bug. + } + print "\n"; + # Show clock icon + print "\n"; + for (my $ix=0; $ix<=23; $ix++) { + my $hrs=($ix>=12?$ix-12:$ix); + my $hre=($ix>=12?$ix-11:$ix+1); + my $apm=($ix>=12?"pm":"am"); + print "\n"; + } + print "\n"; + print "
"; + if ($ShowHoursStats =~ /P/i) { print ""; } + if ($ShowHoursStats =~ /H/i) { print ""; } + if ($ShowHoursStats =~ /B/i) { print ""; } + print "
$ix
\"$hrs:00
\n"; + } + print "
\n"; + + # Show data array for hours + if ($AddDataArrayShowHoursStats) { + print "\n"; + print ""; + print ""; + print "
\n"; + + print "\n"; + print ""; + if ($ShowHoursStats =~ /P/i) { print ""; } + if ($ShowHoursStats =~ /H/i) { print ""; } + if ($ShowHoursStats =~ /B/i) { print ""; } + print ""; + for (my $ix=0; $ix<=11; $ix++) { + my $monthix=($ix<10?"0$ix":"$ix"); + print ""; + print ""; + if ($ShowHoursStats =~ /P/i) { print ""; } + if ($ShowHoursStats =~ /H/i) { print ""; } + if ($ShowHoursStats =~ /B/i) { print ""; } + print "\n"; + } + print "
$Message[20]$Message[56]$Message[57]$Message[75]
$monthix",$_time_p[$monthix]?$_time_p[$monthix]:"0","",$_time_h[$monthix]?$_time_h[$monthix]:"0","",Format_Bytes(int($_time_k[$monthix])),"
\n"; + + print "
 
\n"; + + print "\n"; + print ""; + if ($ShowHoursStats =~ /P/i) { print ""; } + if ($ShowHoursStats =~ /H/i) { print ""; } + if ($ShowHoursStats =~ /B/i) { print ""; } + print "\n"; + for (my $ix=12; $ix<=23; $ix++) { + my $monthix=($ix<10?"0$ix":"$ix"); + print ""; + print ""; + if ($ShowHoursStats =~ /P/i) { print ""; } + if ($ShowHoursStats =~ /H/i) { print ""; } + if ($ShowHoursStats =~ /B/i) { print ""; } + print "\n"; + } + print "
$Message[20]$Message[56]$Message[57]$Message[75]
$monthix",$_time_p[$monthix]?$_time_p[$monthix]:"0","",$_time_h[$monthix]?$_time_h[$monthix]:"0","",Format_Bytes(int($_time_k[$monthix])),"
\n"; + + print "
\n"; + print "
\n"; + } + + print "
\n"; + &tab_end(); + } + + print "\n \n\n"; + + # BY COUNTRY/DOMAIN + #--------------------------- + if ($ShowDomainsStats) { + if ($Debug) { debug("ShowDomainsStats",2); } + print "$Center 
\n"; + my $title="$Message[25] ($Message[77] $MaxNbOf{'Domain'})   -   $Message[80]"; + &tab_head("$title",19,0,'countries'); + print " $Message[17]"; + + ## to add unique visitors and number of visits by calculation of average of the relation with total + ## pages and total hits, and total visits and total unique + ## by Josep Ruano @ CAPSiDE + if ($ShowDomainsStats =~ /U/i) { print "$Message[11]"; } + if ($ShowDomainsStats =~ /V/i) { print "$Message[10]"; } + if ($ShowDomainsStats =~ /P/i) { print "$Message[56]"; } + if ($ShowDomainsStats =~ /H/i) { print "$Message[57]"; } + if ($ShowDomainsStats =~ /B/i) { print "$Message[75]"; } + print " "; + print "\n"; + $total_u=$total_v=$total_p=$total_h=$total_k=0; + $max_h=1; foreach (values %_domener_h) { if ($_ > $max_h) { $max_h = $_; } } + $max_k=1; foreach (values %_domener_k) { if ($_ > $max_k) { $max_k = $_; } } + my $count=0; + &BuildKeyList($MaxNbOf{'Domain'},$MinHit{'Domain'},\%_domener_h,\%_domener_p); + foreach my $key (@keylist) { + my ($_domener_u, $_domener_v); + my $bredde_p=0;my $bredde_h=0;my $bredde_k=0;my $bredde_u=0; my $bredde_v=0; + if ($max_h > 0) { $bredde_p=int($BarWidth*$_domener_p{$key}/$max_h)+1; } # use max_h to enable to compare pages with hits + if ($_domener_p{$key} && $bredde_p==1) { $bredde_p=2; } + if ($max_h > 0) { $bredde_h=int($BarWidth*$_domener_h{$key}/$max_h)+1; } + if ($_domener_h{$key} && $bredde_h==1) { $bredde_h=2; } + if ($max_k > 0) { $bredde_k=int($BarWidth*($_domener_k{$key}||0)/$max_k)+1; } + if ($_domener_k{$key} && $bredde_k==1) { $bredde_k=2; } + my $newkey=lc($key); + if ($newkey eq 'ip' || ! $DomainsHashIDLib{$newkey}) { + print "$Message[0]$newkey"; + } + else { + print "$DomainsHashIDLib{$newkey}$newkey"; + } + ## to add unique visitors and number of visits, by Josep Ruano @ CAPSiDE + if ($ShowDomainsStats =~ /U/i) { + $_domener_u = ($_domener_p{$key} ? $_domener_p{$key}/$TotalPages : 0); + $_domener_u += ($_domener_h{$key}/$TotalHits); + $_domener_u = sprintf("%.0f", ($_domener_u * $TotalUnique) / 2); + print "$_domener_u (" . sprintf("%.1f%", 100*$_domener_u/$TotalUnique) . ")"; + } + if ($ShowDomainsStats =~ /V/i) { + $_domener_v = ($_domener_p{$key} ? $_domener_p{$key}/$TotalPages : 0); + $_domener_v += ($_domener_h{$key}/$TotalHits); + $_domener_v = sprintf("%.0f", ($_domener_v * $TotalVisits) / 2); + print "$_domener_v (" . sprintf("%.1f%", 100*$_domener_v/$TotalVisits) . ")"; + } + + if ($ShowDomainsStats =~ /P/i) { print "".($_domener_p{$key}?$_domener_p{$key}:' ').""; } + if ($ShowDomainsStats =~ /H/i) { print "$_domener_h{$key}"; } + if ($ShowDomainsStats =~ /B/i) { print "".Format_Bytes($_domener_k{$key}).""; } + print ""; + + if ($ShowDomainsStats =~ /P/i) { print "
\n"; } + if ($ShowDomainsStats =~ /H/i) { print "
\n"; } + if ($ShowDomainsStats =~ /B/i) { print ""; } + print ""; + print "\n"; + + $total_u += $_domener_u; + $total_v += $_domener_v; + $total_p += $_domener_p{$key}; + $total_h += $_domener_h{$key}; + $total_k += $_domener_k{$key}||0; + $count++; + } + my $rest_u = $TotalUnique - $total_u; + my $rest_v = $TotalVisits - $total_v; + $rest_p=$TotalPages-$total_p; + $rest_h=$TotalHits-$total_h; + $rest_k=$TotalBytes-$total_k; + if ($rest_u > 0 || $rest_v > 0 || $rest_p > 0 || $rest_h > 0 || $rest_k > 0) { # All other domains (known or not) + print " $Message[2]"; + if ($ShowDomainsStats =~ /U/i) { print "$rest_u"; } + if ($ShowDomainsStats =~ /V/i) { print "$rest_v"; } + if ($ShowDomainsStats =~ /P/i) { print "$rest_p"; } + if ($ShowDomainsStats =~ /H/i) { print "$rest_h"; } + if ($ShowDomainsStats =~ /B/i) { print "".Format_Bytes($rest_k).""; } + print " "; + print "\n"; + } + &tab_end(); + } + + # BY HOST/VISITOR + #-------------------------- + if ($ShowHostsStats) { + if ($Debug) { debug("ShowHostsStats",2); } + print "$Center 
\n"; + my $title="$Message[81] ($Message[77] $MaxNbOf{'HostsShown'})   -   $Message[80]   -   $Message[9]   -   $Message[45]"; + &tab_head("$title",19,0,'visitors'); + print ""; + print ""; + if ($MonthRequired ne 'all') { print "$Message[81] : $TotalHostsKnown $Message[82], $TotalHostsUnknown $Message[1]
$TotalUnique $Message[11]"; } + else { print "$Message[81] : ".(scalar keys %_host_h).""; } + &ShowHostInfo('__title__'); + if ($ShowHostsStats =~ /P/i) { print "$Message[56]"; } + if ($ShowHostsStats =~ /H/i) { print "$Message[57]"; } + if ($ShowHostsStats =~ /B/i) { print "$Message[75]"; } + if ($ShowHostsStats =~ /L/i) { print "$Message[9]"; } + print "\n"; + $total_p=$total_h=$total_k=0; + my $count=0; + &BuildKeyList($MaxNbOf{'HostsShown'},$MinHit{'Host'},\%_host_h,\%_host_p); + foreach my $key (@keylist) { + print ""; + print "$key"; + &ShowHostInfo($key); + if ($ShowHostsStats =~ /P/i) { print ''.($_host_p{$key}||" ").''; } + if ($ShowHostsStats =~ /H/i) { print "$_host_h{$key}"; } + if ($ShowHostsStats =~ /B/i) { print ''.Format_Bytes($_host_k{$key}).''; } + if ($ShowHostsStats =~ /L/i) { print ''.($_host_l{$key}?Format_Date($_host_l{$key},1):'-').''; } + print "\n"; + $total_p += $_host_p{$key}; + $total_h += $_host_h{$key}; + $total_k += $_host_k{$key}||0; + $count++; + } + $rest_p=$TotalPages-$total_p; + $rest_h=$TotalHits-$total_h; + $rest_k=$TotalBytes-$total_k; + if ($rest_p > 0 || $rest_h > 0 || $rest_k > 0) { # All other visitors (known or not) + print ""; + print "$Message[2]"; + &ShowHostInfo(''); + if ($ShowHostsStats =~ /P/i) { print "$rest_p"; } + if ($ShowHostsStats =~ /H/i) { print "$rest_h"; } + if ($ShowHostsStats =~ /B/i) { print "".Format_Bytes($rest_k).""; } + if ($ShowHostsStats =~ /L/i) { print " "; } + print "\n"; + } + &tab_end(); + } + + # BY SENDER EMAIL + #---------------------------- + if ($ShowEMailSenders) { + &ShowEmailSendersChart($NewLinkParams,$NewLinkTarget); + } + + # BY RECEIVER EMAIL + #---------------------------- + if ($ShowEMailReceivers) { + &ShowEmailReceiversChart($NewLinkParams,$NewLinkTarget); + } + + # BY LOGIN + #---------------------------- + if ($ShowAuthenticatedUsers) { + if ($Debug) { debug("ShowAuthenticatedUsers",2); } + print "$Center 
\n"; + my $title="$Message[94] ($Message[77] $MaxNbOf{'LoginShown'})   -   $Message[80]"; + if ($ShowAuthenticatedUsers =~ /L/i) { $title.="   -   $Message[9]"; } + &tab_head("$title",19,0,'logins'); + print "$Message[94] : ".(scalar keys %_login_h).""; + &ShowUserInfo('__title__'); + if ($ShowAuthenticatedUsers =~ /P/i) { print "$Message[56]"; } + if ($ShowAuthenticatedUsers =~ /H/i) { print "$Message[57]"; } + if ($ShowAuthenticatedUsers =~ /B/i) { print "$Message[75]"; } + if ($ShowAuthenticatedUsers =~ /L/i) { print "$Message[9]"; } + print "\n"; + $total_p=$total_h=$total_k=0; + $max_h=1; foreach (values %_login_h) { if ($_ > $max_h) { $max_h = $_; } } + $max_k=1; foreach (values %_login_k) { if ($_ > $max_k) { $max_k = $_; } } + my $count=0; + &BuildKeyList($MaxNbOf{'LoginShown'},$MinHit{'Login'},\%_login_h,\%_login_p); + foreach my $key (@keylist) { + my $bredde_p=0;my $bredde_h=0;my $bredde_k=0; + if ($max_h > 0) { $bredde_p=int($BarWidth*$_login_p{$key}/$max_h)+1; } # use max_h to enable to compare pages with hits + if ($max_h > 0) { $bredde_h=int($BarWidth*$_login_h{$key}/$max_h)+1; } + if ($max_k > 0) { $bredde_k=int($BarWidth*$_login_k{$key}/$max_k)+1; } + print "$key"; + &ShowUserInfo($key); + if ($ShowAuthenticatedUsers =~ /P/i) { print "".($_login_p{$key}?$_login_p{$key}:" ").""; } + if ($ShowAuthenticatedUsers =~ /H/i) { print "$_login_h{$key}"; } + if ($ShowAuthenticatedUsers =~ /B/i) { print "".Format_Bytes($_login_k{$key}).""; } + if ($ShowAuthenticatedUsers =~ /L/i) { print "".($_login_l{$key}?Format_Date($_login_l{$key},1):'-').""; } + print "\n"; + $total_p += $_login_p{$key}; + $total_h += $_login_h{$key}; + $total_k += $_login_k{$key}; + $count++; + } + $rest_p=$TotalPages-$total_p; + $rest_h=$TotalHits-$total_h; + $rest_k=$TotalBytes-$total_k; + if ($rest_p > 0 || $rest_h > 0 || $rest_k > 0) { # All other logins + print "".($PageDir eq 'rtl'?"":"")."$Message[125]".($PageDir eq 'rtl'?"":"").""; + &ShowUserInfo(''); + if ($ShowAuthenticatedUsers =~ /P/i) { print "".($rest_p?$rest_p:" ").""; } + if ($ShowAuthenticatedUsers =~ /H/i) { print "$rest_h"; } + if ($ShowAuthenticatedUsers =~ /B/i) { print "".Format_Bytes($rest_k).""; } + if ($ShowAuthenticatedUsers =~ /L/i) { print " "; } + print "\n"; + } + &tab_end(); + } + + # BY ROBOTS + #---------------------------- + if ($ShowRobotsStats) { + if ($Debug) { debug("ShowRobotStats",2); } + print "$Center 
\n"; + &tab_head("$Message[53] ($Message[77] $MaxNbOf{'RobotShown'})   -   $Message[80]   -   $Message[9]",19,0,'robots'); + print "".(scalar keys %_robot_h)." $Message[51]*"; + if ($ShowRobotsStats =~ /H/i) { print "$Message[57]"; } + if ($ShowRobotsStats =~ /B/i) { print "$Message[75]"; } + if ($ShowRobotsStats =~ /L/i) { print "$Message[9]"; } + print "\n"; + $total_p=$total_h=$total_k=$total_r=0; + my $count=0; + &BuildKeyList($MaxNbOf{'RobotShown'},$MinHit{'Robot'},\%_robot_h,\%_robot_h); + foreach my $key (@keylist) { + print "".($PageDir eq 'rtl'?"":"").($RobotsHashIDLib{$key}?$RobotsHashIDLib{$key}:$key).($PageDir eq 'rtl'?"":"").""; + if ($ShowRobotsStats =~ /H/i) { print "".($_robot_h{$key}-$_robot_r{$key}).($_robot_r{$key}?"+$_robot_r{$key}":"").""; } + if ($ShowRobotsStats =~ /B/i) { print "".Format_Bytes($_robot_k{$key}).""; } + if ($ShowRobotsStats =~ /L/i) { print "".($_robot_l{$key}?Format_Date($_robot_l{$key},1):'-').""; } + print "\n"; + #$total_p += $_robot_p{$key}; + $total_h += $_robot_h{$key}; + $total_k += $_robot_k{$key}||0; + $total_r += $_robot_r{$key}||0; + $count++; + } + # For bots we need to count Totals + my $TotalPagesRobots = 0; #foreach (values %_robot_p) { $TotalPagesRobots+=$_; } + my $TotalHitsRobots = 0; foreach (values %_robot_h) { $TotalHitsRobots+=$_; } + my $TotalBytesRobots = 0; foreach (values %_robot_k) { $TotalBytesRobots+=$_; } + my $TotalRRobots = 0; foreach (values %_robot_r) { $TotalRRobots+=$_; } + $rest_p=0; #$rest_p=$TotalPagesRobots-$total_p; + $rest_h=$TotalHitsRobots-$total_h; + $rest_k=$TotalBytesRobots-$total_k; + $rest_r=$TotalRRobots-$total_r; + if ($rest_p > 0 || $rest_h > 0 || $rest_k > 0 || $rest_r > 0) { # All other robots + print "$Message[2]"; + if ($ShowRobotsStats =~ /H/i) { print "".($rest_h-$rest_r).($rest_r?"+$rest_r":"").""; } + if ($ShowRobotsStats =~ /B/i) { print "".(Format_Bytes($rest_k)).""; } + if ($ShowRobotsStats =~ /L/i) { print " "; } + print "\n"; + } + &tab_end("* $Message[156]".($TotalRRobots?" $Message[157]":"")); + } + + # BY WORMS + #---------------------------- + if ($ShowWormsStats) { + if ($Debug) { debug("ShowWormsStats",2); } + print "$Center 
\n"; + &tab_head("$Message[163] ($Message[77] $MaxNbOf{'WormsShown'})",19,0,'worms'); + print ""; + print "".(scalar keys %_worm_h)." $Message[164]*"; + print "$Message[167]"; + if ($ShowWormsStats =~ /H/i) { print "$Message[57]"; } + if ($ShowWormsStats =~ /B/i) { print "$Message[75]"; } + if ($ShowWormsStats =~ /L/i) { print "$Message[9]"; } + print "\n"; + $total_p=$total_h=$total_k=0; + my $count=0; + &BuildKeyList($MaxNbOf{'WormsShown'},$MinHit{'Worm'},\%_worm_h,\%_worm_h); + foreach my $key (@keylist) { + print ""; + print "".($PageDir eq 'rtl'?"":"").($WormsHashLib{$key}?$WormsHashLib{$key}:$key).($PageDir eq 'rtl'?"":"").""; + print "".($PageDir eq 'rtl'?"":"").($WormsHashTarget{$key}?$WormsHashTarget{$key}:$key).($PageDir eq 'rtl'?"":"").""; + if ($ShowWormsStats =~ /H/i) { print "".$_worm_h{$key}.""; } + if ($ShowWormsStats =~ /B/i) { print "".Format_Bytes($_worm_k{$key}).""; } + if ($ShowWormsStats =~ /L/i) { print "".($_worm_l{$key}?Format_Date($_worm_l{$key},1):'-').""; } + print "\n"; + #$total_p += $_worm_p{$key}; + $total_h += $_worm_h{$key}; + $total_k += $_worm_k{$key}||0; + $count++; + } + # For worms we need to count Totals + my $TotalPagesWorms = 0; #foreach (values %_worm_p) { $TotalPagesWorms+=$_; } + my $TotalHitsWorms = 0; foreach (values %_worm_h) { $TotalHitsWorms+=$_; } + my $TotalBytesWorms = 0; foreach (values %_worm_k) { $TotalBytesWorms+=$_; } + $rest_p=0; #$rest_p=$TotalPagesRobots-$total_p; + $rest_h=$TotalHitsWorms-$total_h; + $rest_k=$TotalBytesWorms-$total_k; + if ($rest_p > 0 || $rest_h > 0 || $rest_k > 0) { # All other worms + print ""; + print "$Message[2]"; + print "-"; + if ($ShowWormsStats =~ /H/i) { print "".($rest_h).""; } + if ($ShowWormsStats =~ /B/i) { print "".(Format_Bytes($rest_k)).""; } + if ($ShowWormsStats =~ /L/i) { print " "; } + print "\n"; + } + &tab_end("* $Message[158]"); + } + + print "\n \n\n"; + + # BY SESSION + #---------------------------- + if ($ShowSessionsStats) { + if ($Debug) { debug("ShowSessionsStats",2); } + print "$Center 
\n"; + my $title="$Message[117]"; + &tab_head($title,19,0,'sessions'); + my $Totals=0; foreach (@SessionsRange) { $average_s+=($_session{$_}||0)*$SessionsAverage{$_}; $Totals+=$_session{$_}||0; } + if ($Totals) { $average_s=int($average_s/$Totals); } + else { $average_s='?'; } + print "$Message[10]: $TotalVisits - $Message[96]: $average_s s$Message[10]$Message[15]\n"; + $average_s=0; + $total_s=0; + my $count=0; + foreach my $key (@SessionsRange) { + my $p=0; + if ($TotalVisits) { $p=int($_session{$key}/$TotalVisits*1000)/10; } + $total_s+=$_session{$key}||0; + print "$key"; + print "".($_session{$key}?$_session{$key}:" ").""; + print "".($_session{$key}?"$p %":" ").""; + print "\n"; + $count++; + } + $rest_s=$TotalVisits-$total_s; + if ($rest_s > 0) { # All others sessions + my $p=0; + if ($TotalVisits) { $p=int($rest_s/$TotalVisits*1000)/10; } + print "$Message[0]"; + print "$rest_s"; + print "".($rest_s?"$p %":" ").""; + print "\n"; + } + &tab_end(); + } + + # BY FILE TYPE + #------------------------- + if ($ShowFileTypesStats) { + if ($Debug) { debug("ShowFileTypesStatsCompressionStats",2); } + print "$Center 
\n"; + my $Totalh=0; foreach (keys %_filetypes_h) { $Totalh+=$_filetypes_h{$_}; } + my $Totalk=0; foreach (keys %_filetypes_k) { $Totalk+=$_filetypes_k{$_}; } + my $title="$Message[73]"; + if ($ShowFileTypesStats =~ /C/i) { $title.=" - $Message[98]"; } + &tab_head("$title",19,0,'filetypes'); + print "$Message[73]"; + if ($ShowFileTypesStats =~ /H/i) { print "$Message[57]$Message[15]"; } + if ($ShowFileTypesStats =~ /B/i) { print "$Message[75]$Message[15]"; } + if ($ShowFileTypesStats =~ /C/i) { print "$Message[100]$Message[101]$Message[99]"; } + print "\n"; + my $total_con=0; my $total_cre=0; + my $count=0; + &BuildKeyList($MaxRowsInHTMLOutput,1,\%_filetypes_h,\%_filetypes_h); + foreach my $key (@keylist) { + my $p_h=' '; my $p_k=' '; + if ($Totalh) { $p_h=int($_filetypes_h{$key}/$Totalh*1000)/10; $p_h="$p_h %"; } + if ($Totalk) { $p_k=int($_filetypes_k{$key}/$Totalk*1000)/10; $p_k="$p_k %"; } + if ($key eq 'Unknown') { + print "$Message[0]"; + } + else { + my $nameicon=$MimeHashIcon{$key}||"notavailable"; + my $nametype=$MimeHashLib{$MimeHashFamily{$key}||""}||" "; + print "$key"; + print "$nametype"; + } + if ($ShowFileTypesStats =~ /H/i) { print "$_filetypes_h{$key}$p_h"; } + if ($ShowFileTypesStats =~ /B/i) { print ''.Format_Bytes($_filetypes_k{$key})."$p_k"; } + if ($ShowFileTypesStats =~ /C/i) { + if ($_filetypes_gz_in{$key}) { + my $percent=int(100*(1-$_filetypes_gz_out{$key}/$_filetypes_gz_in{$key})); + printf("%s%s%s (%s%)",Format_Bytes($_filetypes_gz_in{$key}),Format_Bytes($_filetypes_gz_out{$key}),Format_Bytes($_filetypes_gz_in{$key}-$_filetypes_gz_out{$key}),$percent); + $total_con+=$_filetypes_gz_in{$key}; + $total_cre+=$_filetypes_gz_out{$key}; + } + else { + print "   "; + } + } + print "\n"; + $count++; + } + # Add total (only usefull if compression is enabled) + if ($ShowFileTypesStats =~ /C/i) { + my $colspan=3; + if ($ShowFileTypesStats =~ /H/i) { $colspan+=2; } + if ($ShowFileTypesStats =~ /B/i) { $colspan+=2; } + print ""; + print "$Message[98]"; + if ($ShowFileTypesStats =~ /C/i) { + if ($total_con) { + my $percent=int(100*(1-$total_cre/$total_con)); + printf("%s%s%s (%s%)",Format_Bytes($total_con),Format_Bytes($total_cre),Format_Bytes($total_con-$total_cre),$percent); + } + else { + print "   "; + } + } + print "\n"; + } + &tab_end(); + } + + # BY FILE SIZE + #------------------------- + if ($ShowFileSizesStats) { + + } + + # BY FILE/URL + #------------------------- + if ($ShowPagesStats) { + if ($Debug) { debug("ShowPagesStats (MaxNbOf{'PageShown'}=$MaxNbOf{'PageShown'} TotalDifferentPages=$TotalDifferentPages)",2); } + print "$Center   
\n"; + my $title="$Message[19] ($Message[77] $MaxNbOf{'PageShown'})   -   $Message[80]"; + if ($ShowPagesStats =~ /E/i) { $title.="   -   $Message[104]"; } + if ($ShowPagesStats =~ /X/i) { $title.="   -   $Message[116]"; } + &tab_head("$title",19,0,'urls'); + print "$TotalDifferentPages $Message[28]"; + if ($ShowPagesStats =~ /P/i && $LogType ne 'F') { print "$Message[29]"; } + if ($ShowPagesStats =~ /[PH]/i && $LogType eq 'F') { print "$Message[57]"; } + if ($ShowPagesStats =~ /B/i) { print "$Message[106]"; } + if ($ShowPagesStats =~ /E/i) { print "$Message[104]"; } + if ($ShowPagesStats =~ /X/i) { print "$Message[116]"; } + # Call to plugins' function ShowPagesAddField + foreach my $pluginname (keys %{$PluginsLoaded{'ShowPagesAddField'}}) { +# my $function="ShowPagesAddField_$pluginname('title')"; +# eval("$function"); + my $function="ShowPagesAddField_$pluginname"; + &$function('title'); + } + print " \n"; + $total_p=$total_e=$total_x=$total_k=0; + $max_p=1; $max_k=1; + my $count=0; + &BuildKeyList($MaxNbOf{'PageShown'},$MinHit{'File'},\%_url_p,\%_url_p); + foreach my $key (@keylist) { + if ($_url_p{$key} > $max_p) { $max_p = $_url_p{$key}; } + if ($_url_k{$key}/($_url_p{$key}||1) > $max_k) { $max_k = $_url_k{$key}/($_url_p{$key}||1); } + } + foreach my $key (@keylist) { + print ""; + &ShowURLInfo($key); + print ""; + my $bredde_p=0; my $bredde_e=0; my $bredde_x=0; my $bredde_k=0; + if ($max_p > 0) { $bredde_p=int($BarWidth*($_url_p{$key}||0)/$max_p)+1; } + if (($bredde_p==1) && $_url_p{$key}) { $bredde_p=2; } + if ($max_p > 0) { $bredde_e=int($BarWidth*($_url_e{$key}||0)/$max_p)+1; } + if (($bredde_e==1) && $_url_e{$key}) { $bredde_e=2; } + if ($max_p > 0) { $bredde_x=int($BarWidth*($_url_x{$key}||0)/$max_p)+1; } + if (($bredde_x==1) && $_url_x{$key}) { $bredde_x=2; } + if ($max_k > 0) { $bredde_k=int($BarWidth*(($_url_k{$key}||0)/($_url_p{$key}||1))/$max_k)+1; } + if (($bredde_k==1) && $_url_k{$key}) { $bredde_k=2; } + if ($ShowPagesStats =~ /P/i && $LogType ne 'F') { print "$_url_p{$key}"; } + if ($ShowPagesStats =~ /[PH]/i && $LogType eq 'F') { print "$_url_p{$key}"; } + if ($ShowPagesStats =~ /B/i) { print "".($_url_k{$key}?Format_Bytes($_url_k{$key}/($_url_p{$key}||1)):" ").""; } + if ($ShowPagesStats =~ /E/i) { print "".($_url_e{$key}?$_url_e{$key}:" ").""; } + if ($ShowPagesStats =~ /X/i) { print "".($_url_x{$key}?$_url_x{$key}:" ").""; } + # Call to plugins' function ShowPagesAddField + foreach my $pluginname (keys %{$PluginsLoaded{'ShowPagesAddField'}}) { +# my $function="ShowPagesAddField_$pluginname('$key')"; +# eval("$function"); + my $function="ShowPagesAddField_$pluginname"; + &$function($key); + } + print ""; + if ($ShowPagesStats =~ /P/i && $LogType ne 'F') { print "
"; } + if ($ShowPagesStats =~ /[PH]/i && $LogType eq 'F') { print "
"; } + if ($ShowPagesStats =~ /B/i) { print "
"; } + if ($ShowPagesStats =~ /E/i) { print "
"; } + if ($ShowPagesStats =~ /X/i) { print ""; } + print "\n"; + $total_p += $_url_p{$key}||0; + $total_e += $_url_e{$key}||0; + $total_x += $_url_x{$key}||0; + $total_k += $_url_k{$key}||0; + $count++; + } + $rest_p=$TotalPages-$total_p; + $rest_e=$TotalEntries-$total_e; + $rest_x=$TotalExits-$total_x; + $rest_k=$TotalBytesPages-$total_k; + if ($rest_p > 0 || $rest_k > 0 || $rest_e > 0 || $rest_x > 0) { # All other urls + print "$Message[2]"; + if ($ShowPagesStats =~ /P/i && $LogType ne 'F') { print "$rest_p"; } + if ($ShowPagesStats =~ /[PH]/i && $LogType eq 'F') { print "$rest_p"; } + if ($ShowPagesStats =~ /B/i) { print "".($rest_k?Format_Bytes($rest_k/($rest_p||1)):" ").""; } + if ($ShowPagesStats =~ /E/i) { print "".($rest_e?$rest_e:" ").""; } + if ($ShowPagesStats =~ /X/i) { print "".($rest_x?$rest_x:" ").""; } + # Call to plugins' function ShowPagesAddField + foreach my $pluginname (keys %{$PluginsLoaded{'ShowPagesAddField'}}) { +# my $function="ShowPagesAddField_$pluginname('')"; +# eval("$function"); + my $function="ShowPagesAddField_$pluginname"; + &$function(''); + } + print " \n"; + } + &tab_end(); + } + + # BY OS + #---------------------------- + if ($ShowOSStats) { + if ($Debug) { debug("ShowOSStats",2); } + print "$Center 
\n"; + my $Totalh=0; my %new_os_h=(); + OSLOOP: foreach my $key (keys %_os_h) { + $Totalh+=$_os_h{$key}; + foreach my $family (keys %OSFamily) { if ($key =~ /^$family/i) { $new_os_h{"${family}cumul"}+=$_os_h{$key}; next OSLOOP; } } + $new_os_h{$key}+=$_os_h{$key}; + } + my $title="$Message[59] ($Message[77] $MaxNbOf{'OsShown'})   -   $Message[80]/$Message[58]   -   $Message[0]"; + &tab_head("$title",19,0,'os'); + print " $Message[59]$Message[57]$Message[15]\n"; + $total_h=0; + my $count=0; + &BuildKeyList($MaxNbOf{'OsShown'},$MinHit{'Os'},\%new_os_h,\%new_os_h); + foreach my $key (@keylist) { + my $p=' '; + if ($Totalh) { $p=int($new_os_h{$key}/$Totalh*1000)/10; $p="$p %"; } + if ($key eq 'Unknown') { + print "$Message[0]$_os_h{$key}$p\n"; + } + else { + my $keywithoutcumul=$key; $keywithoutcumul =~ s/cumul$//i; + my $libos=$OSHashLib{$keywithoutcumul}||$keywithoutcumul; + my $nameicon=$keywithoutcumul; $nameicon =~ s/[^\w]//g; + if ($OSFamily{$keywithoutcumul}) { $libos="".$OSFamily{$keywithoutcumul}.""; } + print "$libos$new_os_h{$key}$p\n"; + } + $total_h += $new_os_h{$key}; + $count++; + } + if ($Debug) { debug("Total real / shown : $Totalh / $total_h",2); } + $rest_h=$Totalh-$total_h; + if ($rest_h > 0) { + my $p; + if ($Totalh) { $p=int($rest_h/$Totalh*1000)/10; } + print ""; + print " "; + print "$Message[2]$rest_h"; + print "$p %\n"; + } + &tab_end(); + } + + # BY BROWSER + #---------------------------- + if ($ShowBrowsersStats) { + if ($Debug) { debug("ShowBrowsersStats",2); } + print "$Center 
\n"; + my $Totalh=0; my %new_browser_h=(); + BROWSERLOOP: foreach my $key (keys %_browser_h) { + $Totalh+=$_browser_h{$key}; + foreach my $family (keys %BrowsersFamily) { if ($key =~ /^$family/i) { $new_browser_h{"${family}cumul"}+=$_browser_h{$key}; next BROWSERLOOP; } } + $new_browser_h{$key}+=$_browser_h{$key}; + } + my $title="$Message[21] ($Message[77] $MaxNbOf{'BrowsersShown'})   -   $Message[80]/$Message[58]   -   $Message[0]"; + &tab_head("$title",19,0,'browsers'); + print " $Message[21]$Message[111]$Message[57]$Message[15]\n"; + $total_h=0; + my $count=0; + &BuildKeyList($MaxNbOf{'BrowsersShown'},$MinHit{'Browser'},\%new_browser_h,\%new_browser_h); + foreach my $key (@keylist) { + my $p=' '; + if ($Totalh) { $p=int($new_browser_h{$key}/$Totalh*1000)/10; $p="$p %"; } + if ($key eq 'Unknown') { + print "$Message[0]?$_browser_h{$key}$p\n"; + } + else { + my $keywithoutcumul=$key; $keywithoutcumul =~ s/cumul$//i; + my $libbrowser=$BrowsersHashIDLib{$keywithoutcumul}||$keywithoutcumul; + my $nameicon=$BrowsersHashIcon{$keywithoutcumul}||"notavailable"; + if ($BrowsersFamily{$keywithoutcumul}) { $libbrowser="$libbrowser"; } + print "".($PageDir eq 'rtl'?"":"")."$libbrowser".($PageDir eq 'rtl'?"":"")."".($BrowsersHereAreGrabbers{$key}?"$Message[112]":"$Message[113]")."$new_browser_h{$key}$p\n"; + } + $total_h += $new_browser_h{$key}; + $count++; + } + if ($Debug) { debug("Total real / shown : $Totalh / $total_h",2); } + $rest_h=$Totalh-$total_h; + if ($rest_h > 0) { + my $p; + if ($Totalh) { $p=int($rest_h/$Totalh*1000)/10; } + print ""; + print " "; + print "$Message[2] $rest_h"; + print "$p %\n"; + } + &tab_end(); + } + + # BY SCREEN SIZE + #---------------------------- + if ($ShowScreenSizeStats) { + if ($Debug) { debug("ShowScreenSizeStats",2); } + print "$Center 
\n"; + my $Totalh=0; foreach (keys %_screensize_h) { $Totalh+=$_screensize_h{$_}; } + my $title="$Message[135] ($Message[77] $MaxNbOf{'ScreenSizesShown'})"; + &tab_head("$title",0,0,'screensizes'); + print "$Message[135]$Message[15]\n"; + my $total_h=0; + my $count=0; + &BuildKeyList($MaxNbOf{'ScreenSizesShown'},$MinHit{'ScreenSize'},\%_screensize_h,\%_screensize_h); + foreach my $key (@keylist) { + my $p=' '; + if ($Totalh) { $p=int($_screensize_h{$key}/$Totalh*1000)/10; $p="$p %"; } + $total_h+=$_screensize_h{$key}||0; + print ""; + if ($key eq 'Unknown') { + print "$Message[0]"; + print "$p"; + } + else { + my $screensize=$key; + print "$screensize"; + print "$p"; + } + print "\n"; + $count++; + } + $rest_h=$Totalh-$total_h; + if ($rest_h > 0) { # All others sessions + my $p=0; + if ($Totalh) { $p=int($rest_h/$Totalh*1000)/10; } + print "$Message[2]"; + print "".($rest_h?"$p %":" ").""; + print "\n"; + } + &tab_end(); + } + + print "\n \n\n"; + + # BY REFERENCE + #--------------------------- + if ($ShowOriginStats) { + if ($Debug) { debug("ShowOriginStats",2); } + print "$Center 
\n"; + my $Totalp=0; foreach (0..5) { $Totalp+=($_ != 4 || $IncludeInternalLinksInOriginSection)?$_from_p[$_]:0; } + my $Totalh=0; foreach (0..5) { $Totalh+=($_ != 4 || $IncludeInternalLinksInOriginSection)?$_from_h[$_]:0; } + &tab_head($Message[36],19,0,'referer'); + my @p_p=(0,0,0,0,0,0); + if ($Totalp > 0) { + $p_p[0]=int($_from_p[0]/$Totalp*1000)/10; + $p_p[1]=int($_from_p[1]/$Totalp*1000)/10; + $p_p[2]=int($_from_p[2]/$Totalp*1000)/10; + $p_p[3]=int($_from_p[3]/$Totalp*1000)/10; + $p_p[4]=int($_from_p[4]/$Totalp*1000)/10; + $p_p[5]=int($_from_p[5]/$Totalp*1000)/10; + } + my @p_h=(0,0,0,0,0,0); + if ($Totalh > 0) { + $p_h[0]=int($_from_h[0]/$Totalh*1000)/10; + $p_h[1]=int($_from_h[1]/$Totalh*1000)/10; + $p_h[2]=int($_from_h[2]/$Totalh*1000)/10; + $p_h[3]=int($_from_h[3]/$Totalh*1000)/10; + $p_h[4]=int($_from_h[4]/$Totalh*1000)/10; + $p_h[5]=int($_from_h[5]/$Totalh*1000)/10; + } + print "$Message[37]"; + if ($ShowOriginStats =~ /P/i) { print "$Message[56]$Message[15]"; } + if ($ShowOriginStats =~ /H/i) { print "$Message[57]$Message[15]"; } + print "\n"; + #------- Referrals by direct address/bookmarks + print "$Message[38]"; + if ($ShowOriginStats =~ /P/i) { print "".($_from_p[0]?$_from_p[0]:" ")."".($_from_p[0]?"$p_p[0] %":" ").""; } + if ($ShowOriginStats =~ /H/i) { print "".($_from_h[0]?$_from_h[0]:" ")."".($_from_h[0]?"$p_h[0] %":" ").""; } + print "\n"; + #------- Referrals by news group + print "$Message[107]"; + if ($ShowOriginStats =~ /P/i) { print "".($_from_p[5]?$_from_p[5]:" ")."".($_from_p[5]?"$p_p[5] %":" ").""; } + if ($ShowOriginStats =~ /H/i) { print "".($_from_h[5]?$_from_h[5]:" ")."".($_from_h[5]?"$p_h[5] %":" ").""; } + print "\n"; + #------- Referrals by search engines + print "$Message[40] - $Message[80]
\n"; + if (scalar keys %_se_referrals_h) { + print "\n"; + $total_p=0; $total_h=0; + my $count=0; + &BuildKeyList($MaxNbOf{'RefererShown'},$MinHit{'Refer'},\%_se_referrals_h,((scalar keys %_se_referrals_p)?\%_se_referrals_p:\%_se_referrals_h)); + foreach my $key (@keylist) { + my $newreferer=$SearchEnginesHashLib{$key}||CleanXSS($key); + print ""; + print ""; + print ""; + print "\n"; + $total_p += $_se_referrals_p{$key}; + $total_h += $_se_referrals_h{$key}; + $count++; + } + if ($Debug) { debug("Total real / shown : $TotalSearchEnginesPages / $total_p - $TotalSearchEnginesHits / $total_h",2); } + $rest_p=$TotalSearchEnginesPages-$total_p; + $rest_h=$TotalSearchEnginesHits-$total_h; + if ($rest_p > 0 || $rest_h > 0) { + print ""; + print ""; + print ""; + print "\n"; + } + print "
- $newreferer".($_se_referrals_p{$key}?$_se_referrals_p{$key}:'0')."$_se_referrals_h{$key}
- $Message[2]$rest_p$rest_h
"; + } + print "\n"; + if ($ShowOriginStats =~ /P/i) { print "".($_from_p[2]?$_from_p[2]:" ")."".($_from_p[2]?"$p_p[2] %":" ").""; } + if ($ShowOriginStats =~ /H/i) { print "".($_from_h[2]?$_from_h[2]:" ")."".($_from_h[2]?"$p_h[2] %":" ").""; } + print "\n"; + #------- Referrals by external HTML link + print "$Message[41] - $Message[80]
\n"; + if (scalar keys %_pagesrefs_h) { + print "\n"; + $total_p=0; $total_h=0; + my $count=0; + &BuildKeyList($MaxNbOf{'RefererShown'},$MinHit{'Refer'},\%_pagesrefs_h,((scalar keys %_pagesrefs_p)?\%_pagesrefs_p:\%_pagesrefs_h)); + foreach my $key (@keylist) { + print ""; + print ""; + print ""; + print "\n"; + $total_p += $_pagesrefs_p{$key}; + $total_h += $_pagesrefs_h{$key}; + $count++; + } + if ($Debug) { debug("Total real / shown : $TotalRefererPages / $total_p - $TotalRefererHits / $total_h",2); } + $rest_p=$TotalRefererPages-$total_p; + $rest_h=$TotalRefererHits-$total_h; + if ($rest_p > 0 || $rest_h > 0) { + print ""; + print ""; + print ""; + print "\n"; + } + print "
- "; + &ShowURLInfo($key); + print "".($_pagesrefs_p{$key}?$_pagesrefs_p{$key}:'0')."$_pagesrefs_h{$key}
- $Message[2]$rest_p$rest_h
"; + } + print "\n"; + if ($ShowOriginStats =~ /P/i) { print "".($_from_p[3]?$_from_p[3]:" ")."".($_from_p[3]?"$p_p[3] %":" ").""; } + if ($ShowOriginStats =~ /H/i) { print "".($_from_h[3]?$_from_h[3]:" ")."".($_from_h[3]?"$p_h[3] %":" ").""; } + print "\n"; + #------- Referrals by internal HTML link + if ($IncludeInternalLinksInOriginSection) { + print "$Message[42]"; + if ($ShowOriginStats =~ /P/i) { print "".($_from_p[4]?$_from_p[4]:" ")."".($_from_p[4]?"$p_p[4] %":" ").""; } + if ($ShowOriginStats =~ /H/i) { print "".($_from_h[4]?$_from_h[4]:" ")."".($_from_h[4]?"$p_h[4] %":" ").""; } + print "\n"; + } + #------- Unknown origin + print "$Message[39]"; + if ($ShowOriginStats =~ /P/i) { print "".($_from_p[1]?$_from_p[1]:" ")."".($_from_p[1]?"$p_p[1] %":" ").""; } + if ($ShowOriginStats =~ /H/i) { print "".($_from_h[1]?$_from_h[1]:" ")."".($_from_h[1]?"$p_h[1] %":" ").""; } + print "\n"; + &tab_end(); + } + + print "\n \n\n"; + + # BY SEARCH KEYWORDS AND/OR KEYPHRASES + #------------------------------------- + if ($ShowKeyphrasesStats) { print "$Center "; } + if ($ShowKeywordsStats) { print "$Center "; } + if ($ShowKeyphrasesStats || $ShowKeywordsStats) { print "
\n"; } + if ($ShowKeyphrasesStats && $ShowKeywordsStats) { print ""; } + if ($ShowKeyphrasesStats) { + # By Keyphrases + if ($ShowKeyphrasesStats && $ShowKeywordsStats) { print "\n"; + $total_s=0; + my $count=0; + &BuildKeyList($MaxNbOf{'KeyphrasesShown'},$MinHit{'Keyphrase'},\%_keyphrases,\%_keyphrases); + foreach my $key (@keylist) { + my $mot; + # Convert coded keywords (utf8,...) to be correctly reported in HTML page. + if ($PluginsLoaded{'DecodeKey'}{'decodeutfkeys'}) { $mot=CleanXSS(DecodeKey_decodeutfkeys($key,$PageCode||'iso-8859-1')); } + else { $mot = CleanXSS(DecodeEncodedString($key)); } + my $p; + if ($TotalKeyphrases) { $p=int($_keyphrases{$key}/$TotalKeyphrases*1000)/10; } + print "\n"; + $total_s += $_keyphrases{$key}; + $count++; + } + if ($Debug) { debug("Total real / shown : $TotalKeyphrases / $total_s",2); } + $rest_s=$TotalKeyphrases-$total_s; + if ($rest_s > 0) { + my $p; + if ($TotalKeyphrases) { $p=int($rest_s/$TotalKeyphrases*1000)/10; } + print ""; + print "\n"; + } + &tab_end(); + if ($ShowKeyphrasesStats && $ShowKeywordsStats) { print "\n"; } + } + if ($ShowKeyphrasesStats && $ShowKeywordsStats) { print ""; } + if ($ShowKeywordsStats) { + # By Keywords + if ($ShowKeyphrasesStats && $ShowKeywordsStats) { print "\n"; + $total_s=0; + my $count=0; + &BuildKeyList($MaxNbOf{'KeywordsShown'},$MinHit{'Keyword'},\%_keywords,\%_keywords); + foreach my $key (@keylist) { + my $mot; + # Convert coded keywords (utf8,...) to be correctly reported in HTML page. + if ($PluginsLoaded{'DecodeKey'}{'decodeutfkeys'}) { $mot=CleanXSS(DecodeKey_decodeutfkeys($key,$PageCode||'iso-8859-1')); } + else { $mot = CleanXSS(DecodeEncodedString($key)); } + my $p; + if ($TotalKeywords) { $p=int($_keywords{$key}/$TotalKeywords*1000)/10; } + print "\n"; + $total_s += $_keywords{$key}; + $count++; + } + if ($Debug) { debug("Total real / shown : $TotalKeywords / $total_s",2); } + $rest_s=$TotalKeywords-$total_s; + if ($rest_s > 0) { + my $p; + if ($TotalKeywords) { $p=int($rest_s/$TotalKeywords*1000)/10; } + print ""; + print "\n"; + } + &tab_end(); + if ($ShowKeyphrasesStats && $ShowKeywordsStats) { print "\n"; } + } + if ($ShowKeyphrasesStats && $ShowKeywordsStats) { print "
\n"; } + if ($Debug) { debug("ShowKeyphrasesStats",2); } + &tab_head("$Message[120] ($Message[77] $MaxNbOf{'KeyphrasesShown'})
$Message[80]",19,($ShowKeyphrasesStats && $ShowKeywordsStats)?95:70,'keyphrases'); + print "
$TotalDifferentKeyphrases $Message[103]$Message[14]$Message[15]
".XMLEncode($mot)."$_keyphrases{$key}$p %
$Message[124]$rest_s$p %
  \n"; } + if ($Debug) { debug("ShowKeywordsStats",2); } + &tab_head("$Message[121] ($Message[77] $MaxNbOf{'KeywordsShown'})
$Message[80]",19,($ShowKeyphrasesStats && $ShowKeywordsStats)?95:70,'keywords'); + print "
$TotalDifferentKeywords $Message[13]$Message[14]$Message[15]
".XMLEncode($mot)."$_keywords{$key}$p %
$Message[30]$rest_s$p %
\n"; } + + print "\n \n\n"; + + # BY MISC + #---------------------------- + if ($ShowMiscStats) { + if ($Debug) { debug("ShowMiscStats",2); } + print "$Center 
\n"; + my $Totalh=0; my %new_browser_h=(); + if ($_misc_h{'AddToFavourites'}) { + foreach my $key (keys %_browser_h) { + $Totalh+=$_browser_h{$key}; + if ($key =~ /^msie/i) { $new_browser_h{"msiecumul"}+=$_browser_h{$key}; } + } + if ($new_browser_h{'msiecumul'}) { $_misc_h{'AddToFavourites'}=int(0.5+$_misc_h{'AddToFavourites'}*$Totalh/$new_browser_h{'msiecumul'}); } + } + my $title="$Message[139]"; + &tab_head("$title",19,0,'misc'); + print "$Message[139]"; + print " "; + print " "; + print "\n"; + my %label=('AddToFavourites'=>$Message[137],'JavascriptDisabled'=>$Message[168],'JavaEnabled'=>$Message[140],'DirectorSupport'=>$Message[141], + 'FlashSupport'=>$Message[142],'RealPlayerSupport'=>$Message[143],'QuickTimeSupport'=>$Message[144], + 'WindowsMediaPlayerSupport'=>$Message[145],'PDFSupport'=>$Message[146]); + foreach my $key (@MiscListOrder) { + my $mischar=substr($key,0,1); + if ($ShowMiscStats !~ /$mischar/i) { next; } + my $total=0; + my $p; + if ($MiscListCalc{$key} eq 'v') { $total=$TotalVisits; } + if ($MiscListCalc{$key} eq 'u') { $total=$TotalUnique; } + if ($MiscListCalc{$key} eq 'hm') { $total=$_misc_h{'TotalMisc'}||0; } + if ($total) { $p=int(($_misc_h{$key}?$_misc_h{$key}:0)/$total*1000)/10; } + print ""; + print "".($PageDir eq 'rtl'?"":"").$label{$key}.($PageDir eq 'rtl'?"":"").""; + if ($MiscListCalc{$key} eq 'v') { print "".($_misc_h{$key}||0)." / $total $Message[12]"; } + if ($MiscListCalc{$key} eq 'u') { print "".($_misc_h{$key}||0)." / $total $Message[18]"; } + if ($MiscListCalc{$key} eq 'hm') { print "-"; } + print "".($total?"$p %":" ").""; + print "\n"; + } + &tab_end(); + } + + # BY HTTP STATUS + #---------------------------- + if ($ShowHTTPErrorsStats) { + if ($Debug) { debug("ShowHTTPErrorsStats",2); } + print "$Center 
\n"; + my $title="$Message[32]"; + &tab_head("$title",19,0,'errors'); + print "$Message[32]*$Message[57]$Message[15]$Message[75]\n"; + $total_h=0; + my $count=0; + &BuildKeyList($MaxRowsInHTMLOutput,1,\%_errors_h,\%_errors_h); + foreach my $key (@keylist) { + my $p=int($_errors_h{$key}/$TotalHitsErrors*1000)/10; + print ""; + if ($TrapInfosForHTTPErrorCodes{$key}) { print "$key"; } + else { print "$key"; } + print "".($httpcodelib{$key}?$httpcodelib{$key}:'Unknown error')."$_errors_h{$key}$p %".Format_Bytes($_errors_k{$key}).""; + print "\n"; + $total_h+=$_errors_h{$key}; + $count++; + } + &tab_end("* $Message[154]"); + } + + # BY SMTP STATUS + #---------------------------- + if ($ShowSMTPErrorsStats) { + if ($Debug) { debug("ShowSMTPErrorsStats",2); } + print "$Center 
\n"; + my $title="$Message[147]"; + &tab_head("$title",19,0,'errors'); + print "$Message[147]$Message[57]$Message[15]$Message[75]\n"; + $total_h=0; + my $count=0; + &BuildKeyList($MaxRowsInHTMLOutput,1,\%_errors_h,\%_errors_h); + foreach my $key (@keylist) { + my $p=int($_errors_h{$key}/$TotalHitsErrors*1000)/10; + print ""; + print "$key"; + print "".($smtpcodelib{$key}?$smtpcodelib{$key}:'Unknown error')."$_errors_h{$key}$p %".Format_Bytes($_errors_k{$key}).""; + print "\n"; + $total_h+=$_errors_h{$key}; + $count++; + } + &tab_end(); + } + + # BY CLUSTER + #---------------------------- + if ($ShowClusterStats) { + if ($Debug) { debug("ShowClusterStats",2); } + print "$Center 
\n"; + my $title="$Message[155]"; + &tab_head("$title",19,0,'clusters'); + print "$Message[155]"; + &ShowClusterInfo('__title__'); + if ($ShowClusterStats =~ /P/i) { print "$Message[56]$Message[15]"; } + if ($ShowClusterStats =~ /H/i) { print "$Message[57]$Message[15]"; } + if ($ShowClusterStats =~ /B/i) { print "$Message[75]$Message[15]"; } + print "\n"; + $total_p=$total_h=$total_k=0; + # Cluster feature might have been enable in middle of month so we recalculate + # total for cluster section only, to calculate ratio, instead of using global total + foreach my $key (keys %_cluster_h) { + $total_p+=int($_cluster_p{$key}||0); + $total_h+=int($_cluster_h{$key}||0); + $total_k+=int($_cluster_k{$key}||0); + } + my $count=0; + foreach my $key (keys %_cluster_h) { + my $p_p=int($_cluster_p{$key}/$total_p*1000)/10; + my $p_h=int($_cluster_h{$key}/$total_h*1000)/10; + my $p_k=int($_cluster_k{$key}/$total_k*1000)/10; + print ""; + print "Computer $key"; + &ShowClusterInfo($key); + if ($ShowClusterStats =~ /P/i) { print "".($_cluster_p{$key}?$_cluster_p{$key}:" ")."$p_p %"; } + if ($ShowClusterStats =~ /H/i) { print "$_cluster_h{$key}$p_h %"; } + if ($ShowClusterStats =~ /B/i) { print "".Format_Bytes($_cluster_k{$key})."$p_k %"; } + print "\n"; + $count++; + } + &tab_end(); + } + + # BY EXTRA SECTIONS + #---------------------------- + foreach my $extranum (1..@ExtraName-1) { + if ($Debug) { debug("ExtraName$extranum",2); } + print "$Center 
"; + my $title=$ExtraName[$extranum]; + &tab_head("$title",19,0,"extra$extranum"); + print ""; + print "".$ExtraFirstColumnTitle[$extranum].""; + + if ($ExtraStatTypes[$extranum] =~ m/P/i) { print "$Message[56]"; } + if ($ExtraStatTypes[$extranum] =~ m/H/i) { print "$Message[57]"; } + if ($ExtraStatTypes[$extranum] =~ m/B/i) { print "$Message[75]"; } + if ($ExtraStatTypes[$extranum] =~ m/L/i) { print "$Message[9]"; } + print "\n"; + $total_p=$total_h=$total_k=0; + #$max_h=1; foreach (values %_login_h) { if ($_ > $max_h) { $max_h = $_; } } + #$max_k=1; foreach (values %_login_k) { if ($_ > $max_k) { $max_k = $_; } } + my $count=0; + if ($ExtraStatTypes[$extranum] =~ m/P/i) { + &BuildKeyList($MaxNbOfExtra[$extranum],$MinHitExtra[$extranum],\%{'_section_' . $extranum . '_h'},\%{'_section_' . $extranum . '_p'}); + } + else { + &BuildKeyList($MaxNbOfExtra[$extranum],$MinHitExtra[$extranum],\%{'_section_' . $extranum . '_h'},\%{'_section_' . $extranum . '_h'}); + } + foreach my $key (@keylist) { + my $firstcol = CleanXSS(DecodeEncodedString($key)); + $total_p+=${'_section_' . $extranum . '_p'}{$key}; + $total_h+=${'_section_' . $extranum . '_h'}{$key}; + $total_k+=${'_section_' . $extranum . '_k'}{$key}; + print ""; + printf("$ExtraFirstColumnFormat[$extranum]", $firstcol, $firstcol, $firstcol, $firstcol, $firstcol); + if ($ExtraStatTypes[$extranum] =~ m/P/i) { print "" . ${'_section_' . $extranum . '_p'}{$key} . ""; } + if ($ExtraStatTypes[$extranum] =~ m/H/i) { print "" . ${'_section_' . $extranum . '_h'}{$key} . ""; } + if ($ExtraStatTypes[$extranum] =~ m/B/i) { print "" . Format_Bytes(${'_section_' . $extranum . '_k'}{$key}) . ""; } + if ($ExtraStatTypes[$extranum] =~ m/L/i) { print "" . (${'_section_' . $extranum . '_l'}{$key}?Format_Date(${'_section_' . $extranum . '_l'}{$key},1):'-') . ""; } + print "\n"; + $count++; + } + if ($ExtraAddAverageRow[$extranum]) { + print ""; + print "$Message[96]"; + if ($ExtraStatTypes[$extranum] =~ m/P/i) { print "" . ($count?($total_p/$count):" ") . ""; } + if ($ExtraStatTypes[$extranum] =~ m/H/i) { print "" . ($count?($total_h/$count):" ") . ""; } + if ($ExtraStatTypes[$extranum] =~ m/B/i) { print "" . ($count?Format_Bytes($total_k/$count):" ") . ""; } + if ($ExtraStatTypes[$extranum] =~ m/L/i) { print " "; } + print "\n"; + } + if ($ExtraAddSumRow[$extranum]) { + print ""; + print "$Message[102]"; + if ($ExtraStatTypes[$extranum] =~ m/P/i) { print "" . ($total_p) . ""; } + if ($ExtraStatTypes[$extranum] =~ m/H/i) { print "" . ($total_h) . ""; } + if ($ExtraStatTypes[$extranum] =~ m/B/i) { print "" . Format_Bytes($total_k) . ""; } + if ($ExtraStatTypes[$extranum] =~ m/L/i) { print " "; } + print "\n"; + } + &tab_end(); + } + + &html_end(1); + } +} +else { + print "Jumped lines in file: $lastlinenb\n"; + if ($lastlinenb) { print " Found $lastlinenb already parsed records.\n"; } + print "Parsed lines in file: $NbOfLinesParsed\n"; + print " Found $NbOfLinesDropped dropped records,\n"; + print " Found $NbOfLinesCorrupted corrupted records,\n"; + print " Found $NbOfOldLines old records,\n"; + print " Found $NbOfNewLines new qualified records.\n"; +} + +#sleep 10; + +0; # Do not remove this line + + +#------------------------------------------------------- +# ALGORITHM SUMMARY +# +# Read_Config(); +# Check_Config() and Init variables +# if 'frame not index' +# &Read_Language_Data($Lang); +# if 'frame not mainleft' +# &Read_Ref_Data(); +# &Read_Plugins(); +# html_head +# +# If 'migrate' +# We create/update tmp file with +# &Read_History_With_TmpUpdate(year,month,day,hour,UPDATE,NOPURGE,"all"); +# Rename the tmp file +# html_end +# Exit +# End of 'migrate' +# +# Get last history file name +# Get value for $LastLine $LastLineNumber $LastLineOffset $LastLineChecksum with +# &Read_History_With_TmpUpdate(lastyearbeforeupdate,lastmonthbeforeupdate,lastdaybeforeupdate,lasthourbeforeupdate,NOUPDATE,NOPURGE,"general"); +# +# &Init_HashArray() +# +# If 'update' +# Loop on each new line in log file +# lastlineoffset=lastlineoffsetnext; lastlineoffsetnext=file pointer position +# If line corrupted, skip --> next on loop +# Drop wrong virtual host --> next on loop +# Drop wrong method/protocol --> next on loop +# Check date --> next on loop +# If line older than $LastLine, skip --> next on loop +# So it's new line +# $LastLine = time or record +# Skip if url is /robots.txt --> next on loop +# Skip line for @SkipHosts --> next on loop +# Skip line for @SkipFiles --> next on loop +# Skip line for @SkipUserAgent --> next on loop +# Skip line for not @OnlyHosts --> next on loop +# Skip line for not @OnlyFiles --> next on loop +# Skip line for not @OnlyUserAgent --> next on loop +# So it's new line approved +# If other month/year, create/update tmp file and purge data arrays with +# &Read_History_With_TmpUpdate(lastprocessedyear,lastprocessedmonth,lastprocessedday,lastprocessedhour,UPDATE,PURGE,"all",lastlinenb,lastlineoffset,CheckSum($_)); +# Define a clean Url and Query (set urlwithnoquery, tokenquery and standalonequery and $field[$pos_url]) +# Define PageBool and extension +# Analyze: Misc tracker --> complete %misc +# Analyze: Add to favorites --> complete %_misc, countedtraffic=1 (not counted anywhere) +# If (!countedtraffic) Analyze: Worms --> complete %_worms, countedtraffic=2 +# If (!countedtraffic) Analyze: Status code --> complete %_error_, %_sider404, %_referrer404 --> countedtraffic=3 +# If (!countedtraffic) Analyze: Robots known --> complete %_robot, countedtraffic=4 +# If (!countedtraffic) Analyze: Robots unknown on robots.txt --> complete %_robot, countedtraffic=5 +# If (!countedtraffic) Analyze: File types - Compression +# If (!countedtraffic) Analyze: Date - Hour - Pages - Hits - Kilo +# If (!countedtraffic) Analyze: Login +# If (!countedtraffic) Do DNS Lookup +# If (!countedtraffic) Analyze: Country +# If (!countedtraffic) Analyze: Host - Url - Session +# If (!countedtraffic) Analyze: Browser - OS +# If (!countedtraffic) Analyze: Referer +# If (!countedtraffic) Analyze: EMail +# Analyze: Cluster +# Analyze: Extra (must be after 'Define a clean Url and Query') +# If too many records, we flush data arrays with +# &Read_History_With_TmpUpdate(lastprocessedyear,lastprocessedmonth,lastprocessedday,lastprocessedhour,UPDATE,PURGE,"all",lastlinenb,lastlineoffset,CheckSum($_)); +# End of loop +# +# Create/update tmp file +# Seek to lastlineoffset in logfile to read and get last line into $_ +# &Read_History_With_TmpUpdate(lastprocessedyear,lastprocessedmonth,lastprocessedday,lastprocessedhour,UPDATE,PURGE,"all",lastlinenb,lastlineoffset,CheckSum($_)) +# Rename all created tmp files +# End of 'update' +# +# &Init_HashArray() +# +# If 'output' +# Loop for each month of required year +# &Read_History_With_TmpUpdate($YearRequired,$monthloop,'','',NOUPDATE,NOPURGE,'all' or 'general time' if not required month) +# End of loop +# Show data arrays in HTML page +# html_end +# End of 'output' +#------------------------------------------------------- + +#------------------------------------------------------- +# DNS CACHE FILE FORMATS SUPPORTED BY AWSTATS +# Format /etc/hosts x.y.z.w hostname +# Format analog UT/60 x.y.z.w hostname +#------------------------------------------------------- + +#------------------------------------------------------- +# IP Format (d=decimal on 16 bits, x=hexadecimal on 16 bits) +# +# 13.1.68.3 IPv4 (d.d.d.d) +# 0:0:0:0:0:0:13.1.68.3 IPv6 (x:x:x:x:x:x:d.d.d.d) +# ::13.1.68.3 +# 0:0:0:0:0:FFFF:13.1.68.3 IPv6 (x:x:x:x:x:x:d.d.d.d) +# ::FFFF:13.1.68.3 IPv6 +# +# 1070:0:0:0:0:800:200C:417B IPv6 +# 1070:0:0:0:0:800:200C:417B IPv6 +# 1070::800:200C:417B IPv6 +#------------------------------------------------------- diff --git a/cgi-bin/lang b/cgi-bin/lang new file mode 120000 index 0000000..8ba0ae1 --- /dev/null +++ b/cgi-bin/lang @@ -0,0 +1 @@ +/usr/share/awstats/lang \ No newline at end of file diff --git a/cgi-bin/lib b/cgi-bin/lib new file mode 120000 index 0000000..7cf8a2b --- /dev/null +++ b/cgi-bin/lib @@ -0,0 +1 @@ +/usr/share/awstats/lib \ No newline at end of file diff --git a/cgi-bin/plugins b/cgi-bin/plugins new file mode 120000 index 0000000..ae1435e --- /dev/null +++ b/cgi-bin/plugins @@ -0,0 +1 @@ +/usr/share/awstats/plugins \ No newline at end of file diff --git a/check_file.py b/check_file.py new file mode 100755 index 0000000..7350ca4 --- /dev/null +++ b/check_file.py @@ -0,0 +1,107 @@ +import fnmatch +import glob +import os +import struct + +MAX = 100 + + +def isDCM(filename): + with open(filename, 'rb') as infile: + header = infile.read(132) + if ord(header[0]) == 8: + return True + if header[-4:] == 'DICM': + return True + print ":".join("{:02x}".format(ord(c)) for c in header), filename + print header[-4:] + exit() + + + +def check_accuray(): + ACCURAY_PATIENTS = '/shares/mnt/ntuh-cks/accuray/database/patients/' + count = 0 + for patient in glob.glob("%s/*" % ACCURAY_PATIENTS): + print patient + for ct in glob.glob("%s/ct/patient/*" % patient): + for CTMR in glob.glob("%s/*" % ct): + for fullpath in glob.glob("%s/*" % CTMR): + if fullpath.endswith('import.list'): + continue + if isDCM(fullpath): + continue + count += 1 + exit() + + if count >= MAX: + exit() + # break + + +def isNII(filename): + with open(filename, 'rb') as infile: + header = infile.read(132) + + sizeof_hdr = struct.unpack('i', header[0:4])[0] + + if sizeof_hdr == 348: + return True + + + print ":".join("{:02x}".format(ord(c)) for c in header), filename + print sizeof_hdr + exit() + + +def check_accuray_nii(): + CONVERTED_PATIENTS = '/shares/mnt/ntuh-cks/accuray_nii/' + count = 0 + for patient in glob.glob("%s/*" % CONVERTED_PATIENTS): + print patient + for ct in glob.glob("%s/*.nii" % patient): + if isNII(ct): +# print("%s OK" % ct) + continue + count += 1 + exit() + + if count >= MAX: + exit() + # break + +def isISO(filename): + with open(filename, 'rb') as infile: + header = infile.read(32774) + + if header[-5:] in ('BEA01', 'CD001'): + return True + + print ":".join("{:02x}".format(ord(c)) for c in header[-5:]), filename +# exit() + + +def check_iso(): + ISO_PATIENTS = '/shares/mnt/ntuh-cks/ISO/' + count = 0 + + for path, dirs, files in os.walk(os.path.abspath(ISO_PATIENTS)): + for filename in fnmatch.filter(files, '*.iso'): + if 'RECYCLE' in path: + continue +# print os.path.join(path, filename) + if isISO(os.path.join(path, filename)): + continue + count += 1 +# exit() + + if count >= MAX: + exit() + # break + + +# check_accuray() +# check_accuray_nii() +# check_iso() +# print isDCM('/shares/mnt/ntuh-cks/accuray/database/patients/JOU_1920628/ct/patient/case2011.10.18.12.54.38/MR/IM1') + diff --git a/datetimepick.zip b/datetimepick.zip new file mode 100755 index 0000000..79190e9 Binary files /dev/null and b/datetimepick.zip differ diff --git a/etc/dav.digest.passwd b/etc/dav.digest.passwd new file mode 100755 index 0000000..e69de29 diff --git a/etc/php.ini b/etc/php.ini new file mode 120000 index 0000000..36456a4 --- /dev/null +++ b/etc/php.ini @@ -0,0 +1 @@ +php5/php.ini \ No newline at end of file diff --git a/etc/php5/php.ini b/etc/php5/php.ini new file mode 100755 index 0000000..9bfd487 --- /dev/null +++ b/etc/php5/php.ini @@ -0,0 +1,1853 @@ +[PHP] + +;;;;;;;;;;;;;;;;;;; +; About php.ini ; +;;;;;;;;;;;;;;;;;;; +; PHP's initialization file, generally called php.ini, is responsible for +; configuring many of the aspects of PHP's behavior. + +; PHP attempts to find and load this configuration from a number of locations. +; The following is a summary of its search order: +; 1. SAPI module specific location. +; 2. The PHPRC environment variable. (As of PHP 5.2.0) +; 3. A number of predefined registry keys on Windows (As of PHP 5.2.0) +; 4. Current working directory (except CLI) +; 5. The web server's directory (for SAPI modules), or directory of PHP +; (otherwise in Windows) +; 6. The directory from the --with-config-file-path compile time option, or the +; Windows directory (C:\windows or C:\winnt) +; See the PHP docs for more specific information. +; http://php.net/configuration.file + +; The syntax of the file is extremely simple. Whitespace and Lines +; beginning with a semicolon are silently ignored (as you probably guessed). +; Section headers (e.g. [Foo]) are also silently ignored, even though +; they might mean something in the future. + +; Directives following the section heading [PATH=/www/mysite] only +; apply to PHP files in the /www/mysite directory. Directives +; following the section heading [HOST=www.example.com] only apply to +; PHP files served from www.example.com. Directives set in these +; special sections cannot be overridden by user-defined INI files or +; at runtime. Currently, [PATH=] and [HOST=] sections only work under +; CGI/FastCGI. +; http://php.net/ini.sections + +; Directives are specified using the following syntax: +; directive = value +; Directive names are *case sensitive* - foo=bar is different from FOO=bar. +; Directives are variables used to configure PHP or PHP extensions. +; There is no name validation. If PHP can't find an expected +; directive because it is not set or is mistyped, a default value will be used. + +; The value can be a string, a number, a PHP constant (e.g. E_ALL or M_PI), one +; of the INI constants (On, Off, True, False, Yes, No and None) or an expression +; (e.g. E_ALL & ~E_NOTICE), a quoted string ("bar"), or a reference to a +; previously set variable or directive (e.g. ${foo}) + +; Expressions in the INI file are limited to bitwise operators and parentheses: +; | bitwise OR +; ^ bitwise XOR +; & bitwise AND +; ~ bitwise NOT +; ! boolean NOT + +; Boolean flags can be turned on using the values 1, On, True or Yes. +; They can be turned off using the values 0, Off, False or No. + +; An empty string can be denoted by simply not writing anything after the equal +; sign, or by using the None keyword: + +; foo = ; sets foo to an empty string +; foo = None ; sets foo to an empty string +; foo = "None" ; sets foo to the string 'None' + +; If you use constants in your value, and these constants belong to a +; dynamically loaded extension (either a PHP extension or a Zend extension), +; you may only use these constants *after* the line that loads the extension. + +;;;;;;;;;;;;;;;;;;; +; About this file ; +;;;;;;;;;;;;;;;;;;; +; PHP comes packaged with two INI files. One that is recommended to be used +; in production environments and one that is recommended to be used in +; development environments. + +; php.ini-production contains settings which hold security, performance and +; best practices at its core. But please be aware, these settings may break +; compatibility with older or less security conscience applications. We +; recommending using the production ini in production and testing environments. + +; php.ini-development is very similar to its production variant, except it's +; much more verbose when it comes to errors. We recommending using the +; development version only in development environments as errors shown to +; application users can inadvertently leak otherwise secure information. + +;;;;;;;;;;;;;;;;;;; +; Quick Reference ; +;;;;;;;;;;;;;;;;;;; +; The following are all the settings which are different in either the production +; or development versions of the INIs with respect to PHP's default behavior. +; Please see the actual settings later in the document for more details as to why +; we recommend these changes in PHP's behavior. + +; allow_call_time_pass_reference +; Default Value: On +; Development Value: Off +; Production Value: Off + +; display_errors +; Default Value: On +; Development Value: On +; Production Value: Off + +; display_startup_errors +; Default Value: Off +; Development Value: On +; Production Value: Off + +; error_reporting +; Default Value: E_ALL & ~E_NOTICE +; Development Value: E_ALL | E_STRICT +; Production Value: E_ALL & ~E_DEPRECATED + +; html_errors +; Default Value: On +; Development Value: On +; Production value: Off + +; log_errors +; Default Value: Off +; Development Value: On +; Production Value: On + +; magic_quotes_gpc +; Default Value: On +; Development Value: Off +; Production Value: Off + +; max_input_time +; Default Value: -1 (Unlimited) +; Development Value: 60 (60 seconds) +; Production Value: 60 (60 seconds) + +; output_buffering +; Default Value: Off +; Development Value: 4096 +; Production Value: 4096 + +; register_argc_argv +; Default Value: On +; Development Value: Off +; Production Value: Off + +; register_long_arrays +; Default Value: On +; Development Value: Off +; Production Value: Off + +; request_order +; Default Value: None +; Development Value: "GP" +; Production Value: "GP" + +; session.bug_compat_42 +; Default Value: On +; Development Value: On +; Production Value: Off + +; session.bug_compat_warn +; Default Value: On +; Development Value: On +; Production Value: Off + +; session.gc_divisor +; Default Value: 100 +; Development Value: 1000 +; Production Value: 1000 + +; session.hash_bits_per_character +; Default Value: 4 +; Development Value: 5 +; Production Value: 5 + +; short_open_tag +; Default Value: On +; Development Value: Off +; Production Value: Off + +; track_errors +; Default Value: Off +; Development Value: On +; Production Value: Off + +; url_rewriter.tags +; Default Value: "a=href,area=href,frame=src,form=,fieldset=" +; Development Value: "a=href,area=href,frame=src,input=src,form=fakeentry" +; Production Value: "a=href,area=href,frame=src,input=src,form=fakeentry" + +; variables_order +; Default Value: "EGPCS" +; Development Value: "GPCS" +; Production Value: "GPCS" + +;;;;;;;;;;;;;;;;;;;; +; php.ini Options ; +;;;;;;;;;;;;;;;;;;;; +; Name for user-defined php.ini (.htaccess) files. Default is ".user.ini" +;user_ini.filename = ".user.ini" + +; To disable this feature set this option to empty value +;user_ini.filename = + +; TTL for user-defined php.ini files (time-to-live) in seconds. Default is 300 seconds (5 minutes) +;user_ini.cache_ttl = 300 + +;;;;;;;;;;;;;;;;;;;; +; Language Options ; +;;;;;;;;;;;;;;;;;;;; + +; Enable the PHP scripting language engine under Apache. +; http://php.net/engine +engine = On + +; This directive determines whether or not PHP will recognize code between +; tags as PHP source which should be processed as such. It's been +; recommended for several years that you not use the short tag "short cut" and +; instead to use the full tag combination. With the wide spread use +; of XML and use of these tags by other languages, the server can become easily +; confused and end up parsing the wrong code in the wrong context. But because +; this short cut has been a feature for such a long time, it's currently still +; supported for backwards compatibility, but we recommend you don't use them. +; Default Value: On +; Development Value: Off +; Production Value: Off +; http://php.net/short-open-tag +short_open_tag = On + +; Allow ASP-style <% %> tags. +; http://php.net/asp-tags +asp_tags = Off + +; The number of significant digits displayed in floating point numbers. +; http://php.net/precision +precision = 14 + +; Enforce year 2000 compliance (will cause problems with non-compliant browsers) +; http://php.net/y2k-compliance +y2k_compliance = On + +; Output buffering is a mechanism for controlling how much output data +; (excluding headers and cookies) PHP should keep internally before pushing that +; data to the client. If your application's output exceeds this setting, PHP +; will send that data in chunks of roughly the size you specify. +; Turning on this setting and managing its maximum buffer size can yield some +; interesting side-effects depending on your application and web server. +; You may be able to send headers and cookies after you've already sent output +; through print or echo. You also may see performance benefits if your server is +; emitting less packets due to buffered output versus PHP streaming the output +; as it gets it. On production servers, 4096 bytes is a good setting for performance +; reasons. +; Note: Output buffering can also be controlled via Output Buffering Control +; functions. +; Possible Values: +; On = Enabled and buffer is unlimited. (Use with caution) +; Off = Disabled +; Integer = Enables the buffer and sets its maximum size in bytes. +; Note: This directive is hardcoded to Off for the CLI SAPI +; Default Value: Off +; Development Value: 4096 +; Production Value: 4096 +; http://php.net/output-buffering +output_buffering = 4096 + +; You can redirect all of the output of your scripts to a function. For +; example, if you set output_handler to "mb_output_handler", character +; encoding will be transparently converted to the specified encoding. +; Setting any output handler automatically turns on output buffering. +; Note: People who wrote portable scripts should not depend on this ini +; directive. Instead, explicitly set the output handler using ob_start(). +; Using this ini directive may cause problems unless you know what script +; is doing. +; Note: You cannot use both "mb_output_handler" with "ob_iconv_handler" +; and you cannot use both "ob_gzhandler" and "zlib.output_compression". +; Note: output_handler must be empty if this is set 'On' !!!! +; Instead you must use zlib.output_handler. +; http://php.net/output-handler +;output_handler = + +; Transparent output compression using the zlib library +; Valid values for this option are 'off', 'on', or a specific buffer size +; to be used for compression (default is 4KB) +; Note: Resulting chunk size may vary due to nature of compression. PHP +; outputs chunks that are few hundreds bytes each as a result of +; compression. If you prefer a larger chunk size for better +; performance, enable output_buffering in addition. +; Note: You need to use zlib.output_handler instead of the standard +; output_handler, or otherwise the output will be corrupted. +; http://php.net/zlib.output-compression +zlib.output_compression = Off + +; http://php.net/zlib.output-compression-level +;zlib.output_compression_level = -1 + +; You cannot specify additional output handlers if zlib.output_compression +; is activated here. This setting does the same as output_handler but in +; a different order. +; http://php.net/zlib.output-handler +;zlib.output_handler = + +; Implicit flush tells PHP to tell the output layer to flush itself +; automatically after every output block. This is equivalent to calling the +; PHP function flush() after each and every call to print() or echo() and each +; and every HTML block. Turning this option on has serious performance +; implications and is generally recommended for debugging purposes only. +; http://php.net/implicit-flush +; Note: This directive is hardcoded to On for the CLI SAPI +implicit_flush = Off + +; The unserialize callback function will be called (with the undefined class' +; name as parameter), if the unserializer finds an undefined class +; which should be instantiated. A warning appears if the specified function is +; not defined, or if the function doesn't include/implement the missing class. +; So only set this entry, if you really want to implement such a +; callback-function. +unserialize_callback_func = + +; When floats & doubles are serialized store serialize_precision significant +; digits after the floating point. The default value ensures that when floats +; are decoded with unserialize, the data will remain the same. +serialize_precision = 100 + +; This directive allows you to enable and disable warnings which PHP will issue +; if you pass a value by reference at function call time. Passing values by +; reference at function call time is a deprecated feature which will be removed +; from PHP at some point in the near future. The acceptable method for passing a +; value by reference to a function is by declaring the reference in the functions +; definition, not at call time. This directive does not disable this feature, it +; only determines whether PHP will warn you about it or not. These warnings +; should enabled in development environments only. +; Default Value: On (Suppress warnings) +; Development Value: Off (Issue warnings) +; Production Value: Off (Issue warnings) +; http://php.net/allow-call-time-pass-reference +allow_call_time_pass_reference = Off + +; Safe Mode +; http://php.net/safe-mode +safe_mode = Off + +; By default, Safe Mode does a UID compare check when +; opening files. If you want to relax this to a GID compare, +; then turn on safe_mode_gid. +; http://php.net/safe-mode-gid +safe_mode_gid = Off + +; When safe_mode is on, UID/GID checks are bypassed when +; including files from this directory and its subdirectories. +; (directory must also be in include_path or full path must +; be used when including) +; http://php.net/safe-mode-include-dir +safe_mode_include_dir = + +; When safe_mode is on, only executables located in the safe_mode_exec_dir +; will be allowed to be executed via the exec family of functions. +; http://php.net/safe-mode-exec-dir +safe_mode_exec_dir = + +; Setting certain environment variables may be a potential security breach. +; This directive contains a comma-delimited list of prefixes. In Safe Mode, +; the user may only alter environment variables whose names begin with the +; prefixes supplied here. By default, users will only be able to set +; environment variables that begin with PHP_ (e.g. PHP_FOO=BAR). +; Note: If this directive is empty, PHP will let the user modify ANY +; environment variable! +; http://php.net/safe-mode-allowed-env-vars +safe_mode_allowed_env_vars = PHP_ + +; This directive contains a comma-delimited list of environment variables that +; the end user won't be able to change using putenv(). These variables will be +; protected even if safe_mode_allowed_env_vars is set to allow to change them. +; http://php.net/safe-mode-protected-env-vars +safe_mode_protected_env_vars = LD_LIBRARY_PATH + +; open_basedir, if set, limits all file operations to the defined directory +; and below. This directive makes most sense if used in a per-directory +; or per-virtualhost web server configuration file. This directive is +; *NOT* affected by whether Safe Mode is turned On or Off. +; http://php.net/open-basedir +;open_basedir = + +; This directive allows you to disable certain functions for security reasons. +; It receives a comma-delimited list of function names. This directive is +; *NOT* affected by whether Safe Mode is turned On or Off. +; http://php.net/disable-functions +disable_functions = + +; This directive allows you to disable certain classes for security reasons. +; It receives a comma-delimited list of class names. This directive is +; *NOT* affected by whether Safe Mode is turned On or Off. +; http://php.net/disable-classes +disable_classes = + +; Colors for Syntax Highlighting mode. Anything that's acceptable in +; would work. +; http://php.net/syntax-highlighting +;highlight.string = #DD0000 +;highlight.comment = #FF9900 +;highlight.keyword = #007700 +;highlight.bg = #FFFFFF +;highlight.default = #0000BB +;highlight.html = #000000 + +; If enabled, the request will be allowed to complete even if the user aborts +; the request. Consider enabling it if executing long requests, which may end up +; being interrupted by the user or a browser timing out. PHP's default behavior +; is to disable this feature. +; http://php.net/ignore-user-abort +;ignore_user_abort = On + +; Determines the size of the realpath cache to be used by PHP. This value should +; be increased on systems where PHP opens many files to reflect the quantity of +; the file operations performed. +; http://php.net/realpath-cache-size +;realpath_cache_size = 16k + +; Duration of time, in seconds for which to cache realpath information for a given +; file or directory. For systems with rarely changing files, consider increasing this +; value. +; http://php.net/realpath-cache-ttl +;realpath_cache_ttl = 120 + +;;;;;;;;;;;;;;;;; +; Miscellaneous ; +;;;;;;;;;;;;;;;;; + +; Decides whether PHP may expose the fact that it is installed on the server +; (e.g. by adding its signature to the Web server header). It is no security +; threat in any way, but it makes it possible to determine whether you use PHP +; on your server or not. +; http://php.net/expose-php +expose_php = On + +;;;;;;;;;;;;;;;;;;; +; Resource Limits ; +;;;;;;;;;;;;;;;;;;; + +; Maximum execution time of each script, in seconds +; http://php.net/max-execution-time +; Note: This directive is hardcoded to 0 for the CLI SAPI +max_execution_time = 30 + +; Maximum amount of time each script may spend parsing request data. It's a good +; idea to limit this time on productions servers in order to eliminate unexpectedly +; long running scripts. +; Note: This directive is hardcoded to -1 for the CLI SAPI +; Default Value: -1 (Unlimited) +; Development Value: 60 (60 seconds) +; Production Value: 60 (60 seconds) +; http://php.net/max-input-time +max_input_time = 60 + +; Maximum input variable nesting level +; http://php.net/max-input-nesting-level +;max_input_nesting_level = 64 + +; Maximum amount of memory a script may consume (128MB) +; http://php.net/memory-limit +memory_limit = 128M + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; Error handling and logging ; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +; This directive informs PHP of which errors, warnings and notices you would like +; it to take action for. The recommended way of setting values for this +; directive is through the use of the error level constants and bitwise +; operators. The error level constants are below here for convenience as well as +; some common settings and their meanings. +; By default, PHP is set to take action on all errors, notices and warnings EXCEPT +; those related to E_NOTICE and E_STRICT, which together cover best practices and +; recommended coding standards in PHP. For performance reasons, this is the +; recommend error reporting setting. Your production server shouldn't be wasting +; resources complaining about best practices and coding standards. That's what +; development servers and development settings are for. +; Note: The php.ini-development file has this setting as E_ALL | E_STRICT. This +; means it pretty much reports everything which is exactly what you want during +; development and early testing. +; +; Error Level Constants: +; E_ALL - All errors and warnings (includes E_STRICT as of PHP 6.0.0) +; E_ERROR - fatal run-time errors +; E_RECOVERABLE_ERROR - almost fatal run-time errors +; E_WARNING - run-time warnings (non-fatal errors) +; E_PARSE - compile-time parse errors +; E_NOTICE - run-time notices (these are warnings which often result +; from a bug in your code, but it's possible that it was +; intentional (e.g., using an uninitialized variable and +; relying on the fact it's automatically initialized to an +; empty string) +; E_STRICT - run-time notices, enable to have PHP suggest changes +; to your code which will ensure the best interoperability +; and forward compatibility of your code +; E_CORE_ERROR - fatal errors that occur during PHP's initial startup +; E_CORE_WARNING - warnings (non-fatal errors) that occur during PHP's +; initial startup +; E_COMPILE_ERROR - fatal compile-time errors +; E_COMPILE_WARNING - compile-time warnings (non-fatal errors) +; E_USER_ERROR - user-generated error message +; E_USER_WARNING - user-generated warning message +; E_USER_NOTICE - user-generated notice message +; E_DEPRECATED - warn about code that will not work in future versions +; of PHP +; E_USER_DEPRECATED - user-generated deprecation warnings +; +; Common Values: +; E_ALL & ~E_NOTICE (Show all errors, except for notices and coding standards warnings.) +; E_ALL & ~E_NOTICE | E_STRICT (Show all errors, except for notices) +; E_COMPILE_ERROR|E_RECOVERABLE_ERROR|E_ERROR|E_CORE_ERROR (Show only errors) +; E_ALL | E_STRICT (Show all errors, warnings and notices including coding standards.) +; Default Value: E_ALL & ~E_NOTICE +; Development Value: E_ALL | E_STRICT +; Production Value: E_ALL & ~E_DEPRECATED +; http://php.net/error-reporting +error_reporting = E_ALL & ~E_DEPRECATED + +; This directive controls whether or not and where PHP will output errors, +; notices and warnings too. Error output is very useful during development, but +; it could be very dangerous in production environments. Depending on the code +; which is triggering the error, sensitive information could potentially leak +; out of your application such as database usernames and passwords or worse. +; It's recommended that errors be logged on production servers rather than +; having the errors sent to STDOUT. +; Possible Values: +; Off = Do not display any errors +; stderr = Display errors to STDERR (affects only CGI/CLI binaries!) +; On or stdout = Display errors to STDOUT +; Default Value: On +; Development Value: On +; Production Value: Off +; http://php.net/display-errors +display_errors = Off + +; The display of errors which occur during PHP's startup sequence are handled +; separately from display_errors. PHP's default behavior is to suppress those +; errors from clients. Turning the display of startup errors on can be useful in +; debugging configuration problems. But, it's strongly recommended that you +; leave this setting off on production servers. +; Default Value: Off +; Development Value: On +; Production Value: Off +; http://php.net/display-startup-errors +display_startup_errors = Off + +; Besides displaying errors, PHP can also log errors to locations such as a +; server-specific log, STDERR, or a location specified by the error_log +; directive found below. While errors should not be displayed on productions +; servers they should still be monitored and logging is a great way to do that. +; Default Value: Off +; Development Value: On +; Production Value: On +; http://php.net/log-errors +log_errors = On + +; Set maximum length of log_errors. In error_log information about the source is +; added. The default is 1024 and 0 allows to not apply any maximum length at all. +; http://php.net/log-errors-max-len +log_errors_max_len = 1024 + +; Do not log repeated messages. Repeated errors must occur in same file on same +; line unless ignore_repeated_source is set true. +; http://php.net/ignore-repeated-errors +ignore_repeated_errors = Off + +; Ignore source of message when ignoring repeated messages. When this setting +; is On you will not log errors with repeated messages from different files or +; source lines. +; http://php.net/ignore-repeated-source +ignore_repeated_source = Off + +; If this parameter is set to Off, then memory leaks will not be shown (on +; stdout or in the log). This has only effect in a debug compile, and if +; error reporting includes E_WARNING in the allowed list +; http://php.net/report-memleaks +report_memleaks = On + +; This setting is on by default. +;report_zend_debug = 0 + +; Store the last error/warning message in $php_errormsg (boolean). Setting this value +; to On can assist in debugging and is appropriate for development servers. It should +; however be disabled on production servers. +; Default Value: Off +; Development Value: On +; Production Value: Off +; http://php.net/track-errors +track_errors = Off + +; Turn off normal error reporting and emit XML-RPC error XML +; http://php.net/xmlrpc-errors +;xmlrpc_errors = 0 + +; An XML-RPC faultCode +;xmlrpc_error_number = 0 + +; When PHP displays or logs an error, it has the capability of inserting html +; links to documentation related to that error. This directive controls whether +; those HTML links appear in error messages or not. For performance and security +; reasons, it's recommended you disable this on production servers. +; Note: This directive is hardcoded to Off for the CLI SAPI +; Default Value: On +; Development Value: On +; Production value: Off +; http://php.net/html-errors +html_errors = Off + +; If html_errors is set On PHP produces clickable error messages that direct +; to a page describing the error or function causing the error in detail. +; You can download a copy of the PHP manual from http://php.net/docs +; and change docref_root to the base URL of your local copy including the +; leading '/'. You must also specify the file extension being used including +; the dot. PHP's default behavior is to leave these settings empty. +; Note: Never use this feature for production boxes. +; http://php.net/docref-root +; Examples +;docref_root = "/phpmanual/" + +; http://php.net/docref-ext +;docref_ext = .html + +; String to output before an error message. PHP's default behavior is to leave +; this setting blank. +; http://php.net/error-prepend-string +; Example: +;error_prepend_string = "" + +; String to output after an error message. PHP's default behavior is to leave +; this setting blank. +; http://php.net/error-append-string +; Example: +;error_append_string = "" + +; Log errors to specified file. PHP's default behavior is to leave this value +; empty. +; http://php.net/error-log +; Example: +;error_log = php_errors.log +; Log errors to syslog (Event Log on NT, not valid in Windows 95). +;error_log = syslog + +;;;;;;;;;;;;;;;;; +; Data Handling ; +;;;;;;;;;;;;;;;;; + +; The separator used in PHP generated URLs to separate arguments. +; PHP's default setting is "&". +; http://php.net/arg-separator.output +; Example: +;arg_separator.output = "&" + +; List of separator(s) used by PHP to parse input URLs into variables. +; PHP's default setting is "&". +; NOTE: Every character in this directive is considered as separator! +; http://php.net/arg-separator.input +; Example: +;arg_separator.input = ";&" + +; This directive determines which super global arrays are registered when PHP +; starts up. If the register_globals directive is enabled, it also determines +; what order variables are populated into the global space. G,P,C,E & S are +; abbreviations for the following respective super globals: GET, POST, COOKIE, +; ENV and SERVER. There is a performance penalty paid for the registration of +; these arrays and because ENV is not as commonly used as the others, ENV is +; is not recommended on productions servers. You can still get access to +; the environment variables through getenv() should you need to. +; Default Value: "EGPCS" +; Development Value: "GPCS" +; Production Value: "GPCS"; +; http://php.net/variables-order +variables_order = "GPCS" + +; This directive determines which super global data (G,P,C,E & S) should +; be registered into the super global array REQUEST. If so, it also determines +; the order in which that data is registered. The values for this directive are +; specified in the same manner as the variables_order directive, EXCEPT one. +; Leaving this value empty will cause PHP to use the value set in the +; variables_order directive. It does not mean it will leave the super globals +; array REQUEST empty. +; Default Value: None +; Development Value: "GP" +; Production Value: "GP" +; http://php.net/request-order +request_order = "GP" + +; Whether or not to register the EGPCS variables as global variables. You may +; want to turn this off if you don't want to clutter your scripts' global scope +; with user data. +; You should do your best to write your scripts so that they do not require +; register_globals to be on; Using form variables as globals can easily lead +; to possible security problems, if the code is not very well thought of. +; http://php.net/register-globals +register_globals = Off + +; Determines whether the deprecated long $HTTP_*_VARS type predefined variables +; are registered by PHP or not. As they are deprecated, we obviously don't +; recommend you use them. They are on by default for compatibility reasons but +; they are not recommended on production servers. +; Default Value: On +; Development Value: Off +; Production Value: Off +; http://php.net/register-long-arrays +register_long_arrays = Off + +; This directive determines whether PHP registers $argv & $argc each time it +; runs. $argv contains an array of all the arguments passed to PHP when a script +; is invoked. $argc contains an integer representing the number of arguments +; that were passed when the script was invoked. These arrays are extremely +; useful when running scripts from the command line. When this directive is +; enabled, registering these variables consumes CPU cycles and memory each time +; a script is executed. For performance reasons, this feature should be disabled +; on production servers. +; Note: This directive is hardcoded to On for the CLI SAPI +; Default Value: On +; Development Value: Off +; Production Value: Off +; http://php.net/register-argc-argv +register_argc_argv = Off + +; When enabled, the SERVER and ENV variables are created when they're first +; used (Just In Time) instead of when the script starts. If these variables +; are not used within a script, having this directive on will result in a +; performance gain. The PHP directives register_globals, register_long_arrays, +; and register_argc_argv must be disabled for this directive to have any affect. +; http://php.net/auto-globals-jit +auto_globals_jit = On + +; Maximum size of POST data that PHP will accept. +; http://php.net/post-max-size +post_max_size = 8M + +; Magic quotes are a preprocessing feature of PHP where PHP will attempt to +; escape any character sequences in GET, POST, COOKIE and ENV data which might +; otherwise corrupt data being placed in resources such as databases before +; making that data available to you. Because of character encoding issues and +; non-standard SQL implementations across many databases, it's not currently +; possible for this feature to be 100% accurate. PHP's default behavior is to +; enable the feature. We strongly recommend you use the escaping mechanisms +; designed specifically for the database your using instead of relying on this +; feature. Also note, this feature has been deprecated as of PHP 5.3.0 and is +; scheduled for removal in PHP 6. +; Default Value: On +; Development Value: Off +; Production Value: Off +; http://php.net/magic-quotes-gpc +magic_quotes_gpc = Off + +; Magic quotes for runtime-generated data, e.g. data from SQL, from exec(), etc. +; http://php.net/magic-quotes-runtime +magic_quotes_runtime = Off + +; Use Sybase-style magic quotes (escape ' with '' instead of \'). +; http://php.net/magic-quotes-sybase +magic_quotes_sybase = Off + +; Automatically add files before PHP document. +; http://php.net/auto-prepend-file +auto_prepend_file = + +; Automatically add files after PHP document. +; http://php.net/auto-append-file +auto_append_file = + +; By default, PHP will output a character encoding using +; the Content-type: header. To disable sending of the charset, simply +; set it to be empty. +; +; PHP's built-in default is text/html +; http://php.net/default-mimetype +default_mimetype = "text/html" + +; PHP's default character set is set to empty. +; http://php.net/default-charset +;default_charset = "iso-8859-1" + +; Always populate the $HTTP_RAW_POST_DATA variable. PHP's default behavior is +; to disable this feature. +; http://php.net/always-populate-raw-post-data +;always_populate_raw_post_data = On + +;;;;;;;;;;;;;;;;;;;;;;;;; +; Paths and Directories ; +;;;;;;;;;;;;;;;;;;;;;;;;; + +; UNIX: "/path1:/path2" +;include_path = ".:/usr/share/php" +; +; Windows: "\path1;\path2" +;include_path = ".;c:\php\includes" +; +; PHP's default setting for include_path is ".;/path/to/php/pear" +; http://php.net/include-path + +; The root of the PHP pages, used only if nonempty. +; if PHP was not compiled with FORCE_REDIRECT, you SHOULD set doc_root +; if you are running php as a CGI under any web server (other than IIS) +; see documentation for security issues. The alternate is to use the +; cgi.force_redirect configuration below +; http://php.net/doc-root +doc_root = + +; The directory under which PHP opens the script using /~username used only +; if nonempty. +; http://php.net/user-dir +user_dir = + +; Directory in which the loadable extensions (modules) reside. +; http://php.net/extension-dir +; extension_dir = "./" +; On windows: +; extension_dir = "ext" + +; Whether or not to enable the dl() function. The dl() function does NOT work +; properly in multithreaded servers, such as IIS or Zeus, and is automatically +; disabled on them. +; http://php.net/enable-dl +enable_dl = Off + +; cgi.force_redirect is necessary to provide security running PHP as a CGI under +; most web servers. Left undefined, PHP turns this on by default. You can +; turn it off here AT YOUR OWN RISK +; **You CAN safely turn this off for IIS, in fact, you MUST.** +; http://php.net/cgi.force-redirect +;cgi.force_redirect = 1 + +; if cgi.nph is enabled it will force cgi to always sent Status: 200 with +; every request. PHP's default behavior is to disable this feature. +;cgi.nph = 1 + +; if cgi.force_redirect is turned on, and you are not running under Apache or Netscape +; (iPlanet) web servers, you MAY need to set an environment variable name that PHP +; will look for to know it is OK to continue execution. Setting this variable MAY +; cause security issues, KNOW WHAT YOU ARE DOING FIRST. +; http://php.net/cgi.redirect-status-env +;cgi.redirect_status_env = ; + +; cgi.fix_pathinfo provides *real* PATH_INFO/PATH_TRANSLATED support for CGI. PHP's +; previous behaviour was to set PATH_TRANSLATED to SCRIPT_FILENAME, and to not grok +; what PATH_INFO is. For more information on PATH_INFO, see the cgi specs. Setting +; this to 1 will cause PHP CGI to fix its paths to conform to the spec. A setting +; of zero causes PHP to behave as before. Default is 1. You should fix your scripts +; to use SCRIPT_FILENAME rather than PATH_TRANSLATED. +; http://php.net/cgi.fix-pathinfo +;cgi.fix_pathinfo=1 + +; FastCGI under IIS (on WINNT based OS) supports the ability to impersonate +; security tokens of the calling client. This allows IIS to define the +; security context that the request runs under. mod_fastcgi under Apache +; does not currently support this feature (03/17/2002) +; Set to 1 if running under IIS. Default is zero. +; http://php.net/fastcgi.impersonate +;fastcgi.impersonate = 1; + +; Disable logging through FastCGI connection. PHP's default behavior is to enable +; this feature. +;fastcgi.logging = 0 + +; cgi.rfc2616_headers configuration option tells PHP what type of headers to +; use when sending HTTP response code. If it's set 0 PHP sends Status: header that +; is supported by Apache. When this option is set to 1 PHP will send +; RFC2616 compliant header. +; Default is zero. +; http://php.net/cgi.rfc2616-headers +;cgi.rfc2616_headers = 0 + +;;;;;;;;;;;;;;;; +; File Uploads ; +;;;;;;;;;;;;;;;; + +; Whether to allow HTTP file uploads. +; http://php.net/file-uploads +file_uploads = On + +; Temporary directory for HTTP uploaded files (will use system default if not +; specified). +; http://php.net/upload-tmp-dir +upload_tmp_dir = /home/ntuh/domains/ck.ntuh.net/tmp + +; Maximum allowed size for uploaded files. +; http://php.net/upload-max-filesize +upload_max_filesize = 2M + +; Maximum number of files that can be uploaded via a single request +max_file_uploads = 20 + +;;;;;;;;;;;;;;;;;; +; Fopen wrappers ; +;;;;;;;;;;;;;;;;;; + +; Whether to allow the treatment of URLs (like http:// or ftp://) as files. +; http://php.net/allow-url-fopen +allow_url_fopen = On + +; Whether to allow include/require to open URLs (like http:// or ftp://) as files. +; http://php.net/allow-url-include +allow_url_include = Off + +; Define the anonymous ftp password (your email address). PHP's default setting +; for this is empty. +; http://php.net/from +;from="john@doe.com" + +; Define the User-Agent string. PHP's default setting for this is empty. +; http://php.net/user-agent +;user_agent="PHP" + +; Default timeout for socket based streams (seconds) +; http://php.net/default-socket-timeout +default_socket_timeout = 60 + +; If your scripts have to deal with files from Macintosh systems, +; or you are running on a Mac and need to deal with files from +; unix or win32 systems, setting this flag will cause PHP to +; automatically detect the EOL character in those files so that +; fgets() and file() will work regardless of the source of the file. +; http://php.net/auto-detect-line-endings +;auto_detect_line_endings = Off + +;;;;;;;;;;;;;;;;;;;;;; +; Dynamic Extensions ; +;;;;;;;;;;;;;;;;;;;;;; + +; If you wish to have an extension loaded automatically, use the following +; syntax: +; +; extension=modulename.extension +; +; For example, on Windows: +; +; extension=msql.dll +; +; ... or under UNIX: +; +; extension=msql.so +; +; ... or with a path: +; +; extension=/path/to/extension/msql.so +; +; If you only provide the name of the extension, PHP will look for it in its +; default extension directory. +; + +;;;;;;;;;;;;;;;;;;; +; Module Settings ; +;;;;;;;;;;;;;;;;;;; + +[Date] +; Defines the default timezone used by the date functions +; http://php.net/date.timezone +;date.timezone = + +; http://php.net/date.default-latitude +;date.default_latitude = 31.7667 + +; http://php.net/date.default-longitude +;date.default_longitude = 35.2333 + +; http://php.net/date.sunrise-zenith +;date.sunrise_zenith = 90.583333 + +; http://php.net/date.sunset-zenith +;date.sunset_zenith = 90.583333 + +[filter] +; http://php.net/filter.default +;filter.default = unsafe_raw + +; http://php.net/filter.default-flags +;filter.default_flags = + +[iconv] +;iconv.input_encoding = ISO-8859-1 +;iconv.internal_encoding = ISO-8859-1 +;iconv.output_encoding = ISO-8859-1 + +[intl] +;intl.default_locale = +; This directive allows you to produce PHP errors when some error +; happens within intl functions. The value is the level of the error produced. +; Default is 0, which does not produce any errors. +;intl.error_level = E_WARNING + +[sqlite] +; http://php.net/sqlite.assoc-case +;sqlite.assoc_case = 0 + +[sqlite3] +;sqlite3.extension_dir = + +[Pcre] +;PCRE library backtracking limit. +; http://php.net/pcre.backtrack-limit +;pcre.backtrack_limit=100000 + +;PCRE library recursion limit. +;Please note that if you set this value to a high number you may consume all +;the available process stack and eventually crash PHP (due to reaching the +;stack size limit imposed by the Operating System). +; http://php.net/pcre.recursion-limit +;pcre.recursion_limit=100000 + +[Pdo] +; Whether to pool ODBC connections. Can be one of "strict", "relaxed" or "off" +; http://php.net/pdo-odbc.connection-pooling +;pdo_odbc.connection_pooling=strict + +;pdo_odbc.db2_instance_name + +[Pdo_mysql] +; If mysqlnd is used: Number of cache slots for the internal result set cache +; http://php.net/pdo_mysql.cache_size +pdo_mysql.cache_size = 2000 + +; Default socket name for local MySQL connects. If empty, uses the built-in +; MySQL defaults. +; http://php.net/pdo_mysql.default-socket +pdo_mysql.default_socket= + +[Phar] +; http://php.net/phar.readonly +;phar.readonly = On + +; http://php.net/phar.require-hash +;phar.require_hash = On + +;phar.cache_list = + +[Syslog] +; Whether or not to define the various syslog variables (e.g. $LOG_PID, +; $LOG_CRON, etc.). Turning it off is a good idea performance-wise. In +; runtime, you can define these variables by calling define_syslog_variables(). +; http://php.net/define-syslog-variables +define_syslog_variables = Off + +[mail function] +; For Win32 only. +; http://php.net/smtp +SMTP = localhost +; http://php.net/smtp-port +smtp_port = 25 + +; For Win32 only. +; http://php.net/sendmail-from +;sendmail_from = me@example.com + +; For Unix only. You may supply arguments as well (default: "sendmail -t -i"). +; http://php.net/sendmail-path +;sendmail_path = + +; Force the addition of the specified parameters to be passed as extra parameters +; to the sendmail binary. These parameters will always replace the value of +; the 5th parameter to mail(), even in safe mode. +;mail.force_extra_parameters = + +; Add X-PHP-Originating-Script: that will include uid of the script followed by the filename +mail.add_x_header = On + +; Log all mail() calls including the full path of the script, line #, to address and headers +;mail.log = + +[SQL] +; http://php.net/sql.safe-mode +sql.safe_mode = Off + +[ODBC] +; http://php.net/odbc.default-db +;odbc.default_db = Not yet implemented + +; http://php.net/odbc.default-user +;odbc.default_user = Not yet implemented + +; http://php.net/odbc.default-pw +;odbc.default_pw = Not yet implemented + +; Controls the ODBC cursor model. +; Default: SQL_CURSOR_STATIC (default). +;odbc.default_cursortype + +; Allow or prevent persistent links. +; http://php.net/odbc.allow-persistent +odbc.allow_persistent = On + +; Check that a connection is still valid before reuse. +; http://php.net/odbc.check-persistent +odbc.check_persistent = On + +; Maximum number of persistent links. -1 means no limit. +; http://php.net/odbc.max-persistent +odbc.max_persistent = -1 + +; Maximum number of links (persistent + non-persistent). -1 means no limit. +; http://php.net/odbc.max-links +odbc.max_links = -1 + +; Handling of LONG fields. Returns number of bytes to variables. 0 means +; passthru. +; http://php.net/odbc.defaultlrl +odbc.defaultlrl = 4096 + +; Handling of binary data. 0 means passthru, 1 return as is, 2 convert to char. +; See the documentation on odbc_binmode and odbc_longreadlen for an explanation +; of odbc.defaultlrl and odbc.defaultbinmode +; http://php.net/odbc.defaultbinmode +odbc.defaultbinmode = 1 + +;birdstep.max_links = -1 + +[Interbase] +; Allow or prevent persistent links. +ibase.allow_persistent = 1 + +; Maximum number of persistent links. -1 means no limit. +ibase.max_persistent = -1 + +; Maximum number of links (persistent + non-persistent). -1 means no limit. +ibase.max_links = -1 + +; Default database name for ibase_connect(). +;ibase.default_db = + +; Default username for ibase_connect(). +;ibase.default_user = + +; Default password for ibase_connect(). +;ibase.default_password = + +; Default charset for ibase_connect(). +;ibase.default_charset = + +; Default timestamp format. +ibase.timestampformat = "%Y-%m-%d %H:%M:%S" + +; Default date format. +ibase.dateformat = "%Y-%m-%d" + +; Default time format. +ibase.timeformat = "%H:%M:%S" + +[MySQL] +; Allow accessing, from PHP's perspective, local files with LOAD DATA statements +; http://php.net/mysql.allow_local_infile +mysql.allow_local_infile = On + +; Allow or prevent persistent links. +; http://php.net/mysql.allow-persistent +mysql.allow_persistent = On + +; If mysqlnd is used: Number of cache slots for the internal result set cache +; http://php.net/mysql.cache_size +mysql.cache_size = 2000 + +; Maximum number of persistent links. -1 means no limit. +; http://php.net/mysql.max-persistent +mysql.max_persistent = -1 + +; Maximum number of links (persistent + non-persistent). -1 means no limit. +; http://php.net/mysql.max-links +mysql.max_links = -1 + +; Default port number for mysql_connect(). If unset, mysql_connect() will use +; the $MYSQL_TCP_PORT or the mysql-tcp entry in /etc/services or the +; compile-time value defined MYSQL_PORT (in that order). Win32 will only look +; at MYSQL_PORT. +; http://php.net/mysql.default-port +mysql.default_port = + +; Default socket name for local MySQL connects. If empty, uses the built-in +; MySQL defaults. +; http://php.net/mysql.default-socket +mysql.default_socket = + +; Default host for mysql_connect() (doesn't apply in safe mode). +; http://php.net/mysql.default-host +mysql.default_host = + +; Default user for mysql_connect() (doesn't apply in safe mode). +; http://php.net/mysql.default-user +mysql.default_user = + +; Default password for mysql_connect() (doesn't apply in safe mode). +; Note that this is generally a *bad* idea to store passwords in this file. +; *Any* user with PHP access can run 'echo get_cfg_var("mysql.default_password") +; and reveal this password! And of course, any users with read access to this +; file will be able to reveal the password as well. +; http://php.net/mysql.default-password +mysql.default_password = + +; Maximum time (in seconds) for connect timeout. -1 means no limit +; http://php.net/mysql.connect-timeout +mysql.connect_timeout = 60 + +; Trace mode. When trace_mode is active (=On), warnings for table/index scans and +; SQL-Errors will be displayed. +; http://php.net/mysql.trace-mode +mysql.trace_mode = Off + +[MySQLi] + +; Maximum number of persistent links. -1 means no limit. +; http://php.net/mysqli.max-persistent +mysqli.max_persistent = -1 + +; Allow accessing, from PHP's perspective, local files with LOAD DATA statements +; http://php.net/mysqli.allow_local_infile +;mysqli.allow_local_infile = On + +; Allow or prevent persistent links. +; http://php.net/mysqli.allow-persistent +mysqli.allow_persistent = On + +; Maximum number of links. -1 means no limit. +; http://php.net/mysqli.max-links +mysqli.max_links = -1 + +; If mysqlnd is used: Number of cache slots for the internal result set cache +; http://php.net/mysqli.cache_size +mysqli.cache_size = 2000 + +; Default port number for mysqli_connect(). If unset, mysqli_connect() will use +; the $MYSQL_TCP_PORT or the mysql-tcp entry in /etc/services or the +; compile-time value defined MYSQL_PORT (in that order). Win32 will only look +; at MYSQL_PORT. +; http://php.net/mysqli.default-port +mysqli.default_port = 3306 + +; Default socket name for local MySQL connects. If empty, uses the built-in +; MySQL defaults. +; http://php.net/mysqli.default-socket +mysqli.default_socket = + +; Default host for mysql_connect() (doesn't apply in safe mode). +; http://php.net/mysqli.default-host +mysqli.default_host = + +; Default user for mysql_connect() (doesn't apply in safe mode). +; http://php.net/mysqli.default-user +mysqli.default_user = + +; Default password for mysqli_connect() (doesn't apply in safe mode). +; Note that this is generally a *bad* idea to store passwords in this file. +; *Any* user with PHP access can run 'echo get_cfg_var("mysqli.default_pw") +; and reveal this password! And of course, any users with read access to this +; file will be able to reveal the password as well. +; http://php.net/mysqli.default-pw +mysqli.default_pw = + +; Allow or prevent reconnect +mysqli.reconnect = Off + +[mysqlnd] +; Enable / Disable collection of general statstics by mysqlnd which can be +; used to tune and monitor MySQL operations. +; http://php.net/mysqlnd.collect_statistics +mysqlnd.collect_statistics = On + +; Enable / Disable collection of memory usage statstics by mysqlnd which can be +; used to tune and monitor MySQL operations. +; http://php.net/mysqlnd.collect_memory_statistics +mysqlnd.collect_memory_statistics = Off + +; Size of a pre-allocated buffer used when sending commands to MySQL in bytes. +; http://php.net/mysqlnd.net_cmd_buffer_size +;mysqlnd.net_cmd_buffer_size = 2048 + +; Size of a pre-allocated buffer used for reading data sent by the server in +; bytes. +; http://php.net/mysqlnd.net_read_buffer_size +;mysqlnd.net_read_buffer_size = 32768 + +[OCI8] + +; Connection: Enables privileged connections using external +; credentials (OCI_SYSOPER, OCI_SYSDBA) +; http://php.net/oci8.privileged-connect +;oci8.privileged_connect = Off + +; Connection: The maximum number of persistent OCI8 connections per +; process. Using -1 means no limit. +; http://php.net/oci8.max-persistent +;oci8.max_persistent = -1 + +; Connection: The maximum number of seconds a process is allowed to +; maintain an idle persistent connection. Using -1 means idle +; persistent connections will be maintained forever. +; http://php.net/oci8.persistent-timeout +;oci8.persistent_timeout = -1 + +; Connection: The number of seconds that must pass before issuing a +; ping during oci_pconnect() to check the connection validity. When +; set to 0, each oci_pconnect() will cause a ping. Using -1 disables +; pings completely. +; http://php.net/oci8.ping-interval +;oci8.ping_interval = 60 + +; Connection: Set this to a user chosen connection class to be used +; for all pooled server requests with Oracle 11g Database Resident +; Connection Pooling (DRCP). To use DRCP, this value should be set to +; the same string for all web servers running the same application, +; the database pool must be configured, and the connection string must +; specify to use a pooled server. +;oci8.connection_class = + +; High Availability: Using On lets PHP receive Fast Application +; Notification (FAN) events generated when a database node fails. The +; database must also be configured to post FAN events. +;oci8.events = Off + +; Tuning: This option enables statement caching, and specifies how +; many statements to cache. Using 0 disables statement caching. +; http://php.net/oci8.statement-cache-size +;oci8.statement_cache_size = 20 + +; Tuning: Enables statement prefetching and sets the default number of +; rows that will be fetched automatically after statement execution. +; http://php.net/oci8.default-prefetch +;oci8.default_prefetch = 100 + +; Compatibility. Using On means oci_close() will not close +; oci_connect() and oci_new_connect() connections. +; http://php.net/oci8.old-oci-close-semantics +;oci8.old_oci_close_semantics = Off + +[PostgresSQL] +; Allow or prevent persistent links. +; http://php.net/pgsql.allow-persistent +pgsql.allow_persistent = On + +; Detect broken persistent links always with pg_pconnect(). +; Auto reset feature requires a little overheads. +; http://php.net/pgsql.auto-reset-persistent +pgsql.auto_reset_persistent = Off + +; Maximum number of persistent links. -1 means no limit. +; http://php.net/pgsql.max-persistent +pgsql.max_persistent = -1 + +; Maximum number of links (persistent+non persistent). -1 means no limit. +; http://php.net/pgsql.max-links +pgsql.max_links = -1 + +; Ignore PostgreSQL backends Notice message or not. +; Notice message logging require a little overheads. +; http://php.net/pgsql.ignore-notice +pgsql.ignore_notice = 0 + +; Log PostgreSQL backends Noitce message or not. +; Unless pgsql.ignore_notice=0, module cannot log notice message. +; http://php.net/pgsql.log-notice +pgsql.log_notice = 0 + +[Sybase-CT] +; Allow or prevent persistent links. +; http://php.net/sybct.allow-persistent +sybct.allow_persistent = On + +; Maximum number of persistent links. -1 means no limit. +; http://php.net/sybct.max-persistent +sybct.max_persistent = -1 + +; Maximum number of links (persistent + non-persistent). -1 means no limit. +; http://php.net/sybct.max-links +sybct.max_links = -1 + +; Minimum server message severity to display. +; http://php.net/sybct.min-server-severity +sybct.min_server_severity = 10 + +; Minimum client message severity to display. +; http://php.net/sybct.min-client-severity +sybct.min_client_severity = 10 + +; Set per-context timeout +; http://php.net/sybct.timeout +;sybct.timeout= + +;sybct.packet_size + +; The maximum time in seconds to wait for a connection attempt to succeed before returning failure. +; Default: one minute +;sybct.login_timeout= + +; The name of the host you claim to be connecting from, for display by sp_who. +; Default: none +;sybct.hostname= + +; Allows you to define how often deadlocks are to be retried. -1 means "forever". +; Default: 0 +;sybct.deadlock_retry_count= + +[bcmath] +; Number of decimal digits for all bcmath functions. +; http://php.net/bcmath.scale +bcmath.scale = 0 + +[browscap] +; http://php.net/browscap +;browscap = extra/browscap.ini + +[Session] +; Handler used to store/retrieve data. +; http://php.net/session.save-handler +session.save_handler = files + +; Argument passed to save_handler. In the case of files, this is the path +; where data files are stored. Note: Windows users have to change this +; variable in order to use PHP's session functions. +; +; The path can be defined as: +; +session.save_path = /home/ntuh/domains/ck.ntuh.net/tmp +; +; where N is an integer. Instead of storing all the session files in +; /path, what this will do is use subdirectories N-levels deep, and +; store the session data in those directories. This is useful if you +; or your OS have problems with lots of files in one directory, and is +; a more efficient layout for servers that handle lots of sessions. +; +; NOTE 1: PHP will not create this directory structure automatically. +; You can use the script in the ext/session dir for that purpose. +; NOTE 2: See the section on garbage collection below if you choose to +; use subdirectories for session storage +; +; The file storage module creates files using mode 600 by default. +; You can change that by using +; +; session.save_path = "N;MODE;/path" +; +; where MODE is the octal representation of the mode. Note that this +; does not overwrite the process's umask. +; http://php.net/session.save-path +;session.save_path = "/tmp" + +; Whether to use cookies. +; http://php.net/session.use-cookies +session.use_cookies = 1 + +; http://php.net/session.cookie-secure +;session.cookie_secure = + +; This option forces PHP to fetch and use a cookie for storing and maintaining +; the session id. We encourage this operation as it's very helpful in combatting +; session hijacking when not specifying and managing your own session id. It is +; not the end all be all of session hijacking defense, but it's a good start. +; http://php.net/session.use-only-cookies +session.use_only_cookies = 1 + +; Name of the session (used as cookie name). +; http://php.net/session.name +session.name = PHPSESSID + +; Initialize session on request startup. +; http://php.net/session.auto-start +session.auto_start = 0 + +; Lifetime in seconds of cookie or, if 0, until browser is restarted. +; http://php.net/session.cookie-lifetime +session.cookie_lifetime = 0 + +; The path for which the cookie is valid. +; http://php.net/session.cookie-path +session.cookie_path = / + +; The domain for which the cookie is valid. +; http://php.net/session.cookie-domain +session.cookie_domain = + +; Whether or not to add the httpOnly flag to the cookie, which makes it inaccessible to browser scripting languages such as JavaScript. +; http://php.net/session.cookie-httponly +session.cookie_httponly = + +; Handler used to serialize data. php is the standard serializer of PHP. +; http://php.net/session.serialize-handler +session.serialize_handler = php + +; Defines the probability that the 'garbage collection' process is started +; on every session initialization. The probability is calculated by using +; gc_probability/gc_divisor. Where session.gc_probability is the numerator +; and gc_divisor is the denominator in the equation. Setting this value to 1 +; when the session.gc_divisor value is 100 will give you approximately a 1% chance +; the gc will run on any give request. +; Default Value: 1 +; Development Value: 1 +; Production Value: 1 +; http://php.net/session.gc-probability +session.gc_probability = 1 + +; Defines the probability that the 'garbage collection' process is started on every +; session initialization. The probability is calculated by using the following equation: +; gc_probability/gc_divisor. Where session.gc_probability is the numerator and +; session.gc_divisor is the denominator in the equation. Setting this value to 1 +; when the session.gc_divisor value is 100 will give you approximately a 1% chance +; the gc will run on any give request. Increasing this value to 1000 will give you +; a 0.1% chance the gc will run on any give request. For high volume production servers, +; this is a more efficient approach. +; Default Value: 100 +; Development Value: 1000 +; Production Value: 1000 +; http://php.net/session.gc-divisor +session.gc_divisor = 1000 + +; After this number of seconds, stored data will be seen as 'garbage' and +; cleaned up by the garbage collection process. +; http://php.net/session.gc-maxlifetime +session.gc_maxlifetime = 1440 + +; NOTE: If you are using the subdirectory option for storing session files +; (see session.save_path above), then garbage collection does *not* +; happen automatically. You will need to do your own garbage +; collection through a shell script, cron entry, or some other method. +; For example, the following script would is the equivalent of +; setting session.gc_maxlifetime to 1440 (1440 seconds = 24 minutes): +; cd /path/to/sessions; find -cmin +24 | xargs rm + +; PHP 4.2 and less have an undocumented feature/bug that allows you to +; to initialize a session variable in the global scope, even when register_globals +; is disabled. PHP 4.3 and later will warn you, if this feature is used. +; You can disable the feature and the warning separately. At this time, +; the warning is only displayed, if bug_compat_42 is enabled. This feature +; introduces some serious security problems if not handled correctly. It's +; recommended that you do not use this feature on production servers. But you +; should enable this on development servers and enable the warning as well. If you +; do not enable the feature on development servers, you won't be warned when it's +; used and debugging errors caused by this can be difficult to track down. +; Default Value: On +; Development Value: On +; Production Value: Off +; http://php.net/session.bug-compat-42 +session.bug_compat_42 = Off + +; This setting controls whether or not you are warned by PHP when initializing a +; session value into the global space. session.bug_compat_42 must be enabled before +; these warnings can be issued by PHP. See the directive above for more information. +; Default Value: On +; Development Value: On +; Production Value: Off +; http://php.net/session.bug-compat-warn +session.bug_compat_warn = Off + +; Check HTTP Referer to invalidate externally stored URLs containing ids. +; HTTP_REFERER has to contain this substring for the session to be +; considered as valid. +; http://php.net/session.referer-check +session.referer_check = + +; How many bytes to read from the file. +; http://php.net/session.entropy-length +session.entropy_length = 0 + +; Specified here to create the session id. +; http://php.net/session.entropy-file +;session.entropy_file = /dev/urandom +session.entropy_file = + +; http://php.net/session.entropy-length +;session.entropy_length = 16 + +; Set to {nocache,private,public,} to determine HTTP caching aspects +; or leave this empty to avoid sending anti-caching headers. +; http://php.net/session.cache-limiter +session.cache_limiter = nocache + +; Document expires after n minutes. +; http://php.net/session.cache-expire +session.cache_expire = 180 + +; trans sid support is disabled by default. +; Use of trans sid may risk your users security. +; Use this option with caution. +; - User may send URL contains active session ID +; to other person via. email/irc/etc. +; - URL that contains active session ID may be stored +; in publically accessible computer. +; - User may access your site with the same session ID +; always using URL stored in browser's history or bookmarks. +; http://php.net/session.use-trans-sid +session.use_trans_sid = 0 + +; Select a hash function for use in generating session ids. +; Possible Values +; 0 (MD5 128 bits) +; 1 (SHA-1 160 bits) +; This option may also be set to the name of any hash function supported by +; the hash extension. A list of available hashes is returned by the hash_alogs() +; function. +; http://php.net/session.hash-function +session.hash_function = 0 + +; Define how many bits are stored in each character when converting +; the binary hash data to something readable. +; Possible values: +; 4 (4 bits: 0-9, a-f) +; 5 (5 bits: 0-9, a-v) +; 6 (6 bits: 0-9, a-z, A-Z, "-", ",") +; Default Value: 4 +; Development Value: 5 +; Production Value: 5 +; http://php.net/session.hash-bits-per-character +session.hash_bits_per_character = 5 + +; The URL rewriter will look for URLs in a defined set of HTML tags. +; form/fieldset are special; if you include them here, the rewriter will +; add a hidden field with the info which is otherwise appended +; to URLs. If you want XHTML conformity, remove the form entry. +; Note that all valid entries require a "=", even if no value follows. +; Default Value: "a=href,area=href,frame=src,form=,fieldset=" +; Development Value: "a=href,area=href,frame=src,input=src,form=fakeentry" +; Production Value: "a=href,area=href,frame=src,input=src,form=fakeentry" +; http://php.net/url-rewriter.tags +url_rewriter.tags = "a=href,area=href,frame=src,input=src,form=fakeentry" + +[MSSQL] +; Allow or prevent persistent links. +mssql.allow_persistent = On + +; Maximum number of persistent links. -1 means no limit. +mssql.max_persistent = -1 + +; Maximum number of links (persistent+non persistent). -1 means no limit. +mssql.max_links = -1 + +; Minimum error severity to display. +mssql.min_error_severity = 10 + +; Minimum message severity to display. +mssql.min_message_severity = 10 + +; Compatibility mode with old versions of PHP 3.0. +mssql.compatability_mode = Off + +; Connect timeout +;mssql.connect_timeout = 5 + +; Query timeout +;mssql.timeout = 60 + +; Valid range 0 - 2147483647. Default = 4096. +;mssql.textlimit = 4096 + +; Valid range 0 - 2147483647. Default = 4096. +;mssql.textsize = 4096 + +; Limits the number of records in each batch. 0 = all records in one batch. +;mssql.batchsize = 0 + +; Specify how datetime and datetim4 columns are returned +; On => Returns data converted to SQL server settings +; Off => Returns values as YYYY-MM-DD hh:mm:ss +;mssql.datetimeconvert = On + +; Use NT authentication when connecting to the server +mssql.secure_connection = Off + +; Specify max number of processes. -1 = library default +; msdlib defaults to 25 +; FreeTDS defaults to 4096 +;mssql.max_procs = -1 + +; Specify client character set. +; If empty or not set the client charset from freetds.comf is used +; This is only used when compiled with FreeTDS +;mssql.charset = "ISO-8859-1" + +[Assertion] +; Assert(expr); active by default. +; http://php.net/assert.active +;assert.active = On + +; Issue a PHP warning for each failed assertion. +; http://php.net/assert.warning +;assert.warning = On + +; Don't bail out by default. +; http://php.net/assert.bail +;assert.bail = Off + +; User-function to be called if an assertion fails. +; http://php.net/assert.callback +;assert.callback = 0 + +; Eval the expression with current error_reporting(). Set to true if you want +; error_reporting(0) around the eval(). +; http://php.net/assert.quiet-eval +;assert.quiet_eval = 0 + +[COM] +; path to a file containing GUIDs, IIDs or filenames of files with TypeLibs +; http://php.net/com.typelib-file +;com.typelib_file = + +; allow Distributed-COM calls +; http://php.net/com.allow-dcom +;com.allow_dcom = true + +; autoregister constants of a components typlib on com_load() +; http://php.net/com.autoregister-typelib +;com.autoregister_typelib = true + +; register constants casesensitive +; http://php.net/com.autoregister-casesensitive +;com.autoregister_casesensitive = false + +; show warnings on duplicate constant registrations +; http://php.net/com.autoregister-verbose +;com.autoregister_verbose = true + +; The default character set code-page to use when passing strings to and from COM objects. +; Default: system ANSI code page +;com.code_page= + +[mbstring] +; language for internal character representation. +; http://php.net/mbstring.language +;mbstring.language = Japanese + +; internal/script encoding. +; Some encoding cannot work as internal encoding. +; (e.g. SJIS, BIG5, ISO-2022-*) +; http://php.net/mbstring.internal-encoding +;mbstring.internal_encoding = EUC-JP + +; http input encoding. +; http://php.net/mbstring.http-input +;mbstring.http_input = auto + +; http output encoding. mb_output_handler must be +; registered as output buffer to function +; http://php.net/mbstring.http-output +;mbstring.http_output = SJIS + +; enable automatic encoding translation according to +; mbstring.internal_encoding setting. Input chars are +; converted to internal encoding by setting this to On. +; Note: Do _not_ use automatic encoding translation for +; portable libs/applications. +; http://php.net/mbstring.encoding-translation +;mbstring.encoding_translation = Off + +; automatic encoding detection order. +; auto means +; http://php.net/mbstring.detect-order +;mbstring.detect_order = auto + +; substitute_character used when character cannot be converted +; one from another +; http://php.net/mbstring.substitute-character +;mbstring.substitute_character = none; + +; overload(replace) single byte functions by mbstring functions. +; mail(), ereg(), etc are overloaded by mb_send_mail(), mb_ereg(), +; etc. Possible values are 0,1,2,4 or combination of them. +; For example, 7 for overload everything. +; 0: No overload +; 1: Overload mail() function +; 2: Overload str*() functions +; 4: Overload ereg*() functions +; http://php.net/mbstring.func-overload +;mbstring.func_overload = 0 + +; enable strict encoding detection. +;mbstring.strict_detection = Off + +; This directive specifies the regex pattern of content types for which mb_output_handler() +; is activated. +; Default: mbstring.http_output_conv_mimetype=^(text/|application/xhtml\+xml) +;mbstring.http_output_conv_mimetype= + +; Allows to set script encoding. Only affects if PHP is compiled with --enable-zend-multibyte +; Default: "" +;mbstring.script_encoding= + +[gd] +; Tell the jpeg decode to ignore warnings and try to create +; a gd image. The warning will then be displayed as notices +; disabled by default +; http://php.net/gd.jpeg-ignore-warning +;gd.jpeg_ignore_warning = 0 + +[exif] +; Exif UNICODE user comments are handled as UCS-2BE/UCS-2LE and JIS as JIS. +; With mbstring support this will automatically be converted into the encoding +; given by corresponding encode setting. When empty mbstring.internal_encoding +; is used. For the decode settings you can distinguish between motorola and +; intel byte order. A decode setting cannot be empty. +; http://php.net/exif.encode-unicode +;exif.encode_unicode = ISO-8859-15 + +; http://php.net/exif.decode-unicode-motorola +;exif.decode_unicode_motorola = UCS-2BE + +; http://php.net/exif.decode-unicode-intel +;exif.decode_unicode_intel = UCS-2LE + +; http://php.net/exif.encode-jis +;exif.encode_jis = + +; http://php.net/exif.decode-jis-motorola +;exif.decode_jis_motorola = JIS + +; http://php.net/exif.decode-jis-intel +;exif.decode_jis_intel = JIS + +[Tidy] +; The path to a default tidy configuration file to use when using tidy +; http://php.net/tidy.default-config +;tidy.default_config = /usr/local/lib/php/default.tcfg + +; Should tidy clean and repair output automatically? +; WARNING: Do not use this option if you are generating non-html content +; such as dynamic images +; http://php.net/tidy.clean-output +tidy.clean_output = Off + +[soap] +; Enables or disables WSDL caching feature. +; http://php.net/soap.wsdl-cache-enabled +soap.wsdl_cache_enabled=1 + +; Sets the directory name where SOAP extension will put cache files. +; http://php.net/soap.wsdl-cache-dir +soap.wsdl_cache_dir="/tmp" + +; (time to live) Sets the number of second while cached file will be used +; instead of original one. +; http://php.net/soap.wsdl-cache-ttl +soap.wsdl_cache_ttl=86400 + +; Sets the size of the cache limit. (Max. number of WSDL files to cache) +soap.wsdl_cache_limit = 5 + +[sysvshm] +; A default size of the shared memory segment +;sysvshm.init_mem = 10000 + +[ldap] +; Sets the maximum number of open links or -1 for unlimited. +ldap.max_links = -1 + +[mcrypt] +; For more information about mcrypt settings see http://php.net/mcrypt-module-open + +; Directory where to load mcrypt algorithms +; Default: Compiled in into libmcrypt (usually /usr/local/lib/libmcrypt) +;mcrypt.algorithms_dir= + +; Directory where to load mcrypt modes +; Default: Compiled in into libmcrypt (usually /usr/local/lib/libmcrypt) +;mcrypt.modes_dir= + +[dba] +;dba.default_handler= + +; Local Variables: +; tab-width: 4 +; End: diff --git a/fcgi-bin/php5.fcgi b/fcgi-bin/php5.fcgi new file mode 100755 index 0000000..6889d84 --- /dev/null +++ b/fcgi-bin/php5.fcgi @@ -0,0 +1,8 @@ +#!/bin/bash +PHPRC=$PWD/../etc/php5 +export PHPRC +umask 022 +export PHP_FCGI_CHILDREN +SCRIPT_FILENAME=$PATH_TRANSLATED +export SCRIPT_FILENAME +exec /usr/bin/php5-cgi diff --git a/gunicorn.sh b/gunicorn.sh new file mode 100755 index 0000000..b8f53ab --- /dev/null +++ b/gunicorn.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash + +export PATH="/usr/local/bin:$PATH" + +#cd /home/ntuh/domains/ck.ntuh.net/mysite +cd "$(dirname "$0")/mysite" +/home/cks/.conda/envs/django3/bin/gunicorn -b 0.0.0.0:8114 -D mysite.wsgi diff --git a/impax_moved.py b/impax_moved.py new file mode 100755 index 0000000..7922c63 --- /dev/null +++ b/impax_moved.py @@ -0,0 +1,363 @@ +import glob +import re + +""" +def parse_z1(s): + ''' + 0008 0005 10 | specific_character_set | CS | 1-n | "ISO_IR 192" + + ''' + pattern = '(?P\d{4}) (?P\d{4})\s+(?P\d+) \|\s+(?P[^|]+?)\s+\| (?P..) \|\s+(?P\S+)\s+\|\s*(?P"[^|]*?"|\*[\s\S]+?Seq|[^\r]*)' + + r = re.compile(pattern) + + return [m.groupdict() for m in r.finditer(s)] + + + +def parse_z2(s): + ''' + [ object, original_order ] = 1 ( 4, 4 ) + ''' + + pattern = '\[ (.+?), (.+?) \] = (.+?) \( (.+?), (.+?) \)' + + return re.findall(pattern, s, re.MULTILINE) + + +def parse_z(s): + + pattern = '(?P\d{4}) (?P\d{4})\s+(?P\d+) \|\s+(?P[^|]+?)\s+\| (?P..) \|\s+(?P\S+)\s+\|\s*(?P"[^|]*?"|\*[\s\S]+?Seq|[^\r]*)' + r = re.compile(pattern) + ret1 = [m.groupdict() for m in r.finditer(s)] + + pattern = '\[ (.+?), (.+?) \] = (.+?) \( (.+?), (.+?) \)' + ret2 = re.findall(pattern, s, re.MULTILINE) + + return ret1, ret2 +""" + + +class IMPAX_Description: + def __init__(self, s): + pattern = '(?P\d{4}) (?P\d{4})\s+(?P\d+) \|\s+(?P[^|]+?)\s+\| (?P..) \|\s+(?P\S+)\s+\|\s*(?P"[^|]*?"|\*[\s\S]+?Seq|[^\r]*)' + r = re.compile(pattern) + self.data1 = [m.groupdict() for m in r.finditer(s)] + + pattern = '\[ (.+?), (.+?) \] = (.+?) \( (.+?), (.+?) \)' + self.data2 = re.findall(pattern, s, re.MULTILINE) + + self.data = {} + + for elm in self.data2: + self.data[elm[1]] = elm[2].replace('"', '') + + for elm in self.data1: + if '...' not in elm['Value']: + self.data[elm['Description']] = elm['Value'].replace('"', '') + +# print self.data +# exit() + + def dump(self): + return self.data1, self.data2 + + def get_old(self, s): + for elm in self.data2: + if elm[1] == s: + return elm[2].replace('"', '') + + for elm in self.data1: + if elm['Description'] == s: + return elm['Value'].replace('"', '') + + raise NameError('%s not found' % s) + + def get(self, s): + if s in self.data: +# print s, self.data[s] + return self.data[s] + + raise NameError('%s not found' % s) + + def keys(self): + return self.data.keys() + + def __sub__(self, other): + sdata = {} + for k in self.data: + if k not in other.data: +# sdata[k] = (self.data[k], None) + pass + elif self.data[k] != other.data[k]: + sdata[k] = (self.data[k], other.data[k]) + + for k in other.data: + if k not in self.data: +# sdata[k] = (None, other.data[k]) + pass + + return sdata + +class IMPAX_Series_one: + def __init__(self, path): + self.path = path + ztxt = '%s/z.txt' % (path) + with open(ztxt, 'r') as myfile: + data=myfile.read() + self.Description = IMPAX_Description(data) + + def direction(self): + import numpy as np + + image_orientation_patient = self.Description.get('image_orientation_patient').split('\\') + image_position_patient = self.Description.get('image_position_patient').split('\\') + + dir = [round(float(a)) for a in image_orientation_patient] + + pos = map(float, image_position_patient) + + dir2 = (abs(np.array(dir[:3])+np.array(dir[3:]))-1)*pos + dir2 = dir2 / np.linalg.norm(dir2) + + print self.path + print image_orientation_patient + print image_position_patient + print dir + print dir2 + + return dir + dir2.tolist() + + + def write(self, filename): + import SimpleITK + + print self.Description.get('image_number') +# print self.Description.get('referenced_image_sequence') +# print self.Description.get('source_image_sequence') + + files = glob.glob("%s/*.jpg" % self.path) + files.sort() + + sreader1 = SimpleITK.ImageSeriesReader() + sreader1.SetFileNames(files) + img = sreader1.Execute() + + pixel_spacing = self.Description.get('pixel_spacing').split('\\') + + try: + slice_spacing = float(self.Description.get('slice_spacing')) + except: + slice_spacing = float(self.Description.get('slice_thickness')) + + img.SetDirection(self.direction()) + + img.SetSpacing((float(pixel_spacing[0]), float(pixel_spacing[1]), slice_spacing)) + + SimpleITK.WriteImage(img, filename) + + print img.GetDirection() + print + +class IMPAX_Series: + def __init__(self, path): + self.DescriptionOrder = {} + self.path = path + files = glob.glob("%s/z*.txt" % self.path) + + for filename in files: +# print filename + m = re.search('z(.+).txt', filename) + if m is None: + continue + f_number = int(m.group(1)) + print filename, f_number + with open(filename, 'r') as myfile: + data=myfile.read() + + d = IMPAX_Description(data) + print d.get('image_number') + + d_number = int(d.get('image_number')) + if d_number != f_number: + raise NameError('File name: %s, Description: %d' % (filename, d_number)) + + self.DescriptionOrder[f_number] = d + + self.images = sorted(self.DescriptionOrder.keys()) + self.Description = self.DescriptionOrder[self.images[0]] + + + def direction_old(self): + import numpy as np + + pos_a = np.array(map(float, self.DescriptionOrder[self.images[0]].get('image_position_patient').split('\\'))) + pos_z = np.array(map(float, self.DescriptionOrder[self.images[-1]].get('image_position_patient').split('\\'))) +# dir2 = pos_z - pos_a +# print pos_a, pos_z, dir2 +# dir2 = dir2 / np.linalg.norm(dir2) +# dir2 = [round(a) for a in dir2] + + image_orientation_patient = self.Description.get('image_orientation_patient').split('\\') + image_position_patient = self.Description.get('image_position_patient').split('\\') + + dir = [round(float(a)) for a in image_orientation_patient] + + pos = map(float, image_position_patient) + + dir2 = (abs(np.array(dir[:3])+np.array(dir[3:]))-1)*(pos_a - pos_z) + dir2 = dir2 / np.linalg.norm(dir2) + + print self.path + print image_orientation_patient + print image_position_patient + print dir + print dir2 + + return dir + dir2.tolist() + + + def direction_old2(self): + import numpy as np + +# print self.DescriptionOrder[self.images[0]].get('image_number'), self.DescriptionOrder[self.images[0]].get('image_position_patient') +# print self.DescriptionOrder[self.images[-1]].get('image_number'), self.DescriptionOrder[self.images[-1]].get('image_position_patient') + + pos_a = np.array(map(float, self.DescriptionOrder[self.images[0]].get('image_position_patient').split('\\'))) + pos_z = np.array(map(float, self.DescriptionOrder[self.images[-1]].get('image_position_patient').split('\\'))) + + image_orientation_patient = self.Description.get('image_orientation_patient').split('\\') + image_position_patient = self.Description.get('image_position_patient').split('\\') + + dir = [float(a) for a in image_orientation_patient] + + pos = map(float, image_position_patient) + +# dir2 = (pos_z - pos_a) * [1, -1, 1]/ (self.images[-1] - self.images[0]) + dir2 = (pos_z - pos_a) / (self.images[-1] - self.images[0]) + + dir3 = np.array(dir+dir2.tolist()) + dir3 = dir3 / np.linalg.norm(dir3) + + print self.path + print image_orientation_patient + print pos_a, pos_z + print self.images + print dir + print dir2 + print dir3 + + return dir3.tolist() + + + def direction(self): + import numpy as np + +# print self.DescriptionOrder[self.images[0]].get('image_number'), self.DescriptionOrder[self.images[0]].get('image_position_patient') +# print self.DescriptionOrder[self.images[-1]].get('image_number'), self.DescriptionOrder[self.images[-1]].get('image_position_patient') + + pos_a = np.array(map(float, self.DescriptionOrder[self.images[0]].get('image_position_patient').split('\\'))) + pos_z = np.array(map(float, self.DescriptionOrder[self.images[-1]].get('image_position_patient').split('\\'))) + + image_orientation_patient = self.Description.get('image_orientation_patient').split('\\') + image_position_patient = self.Description.get('image_position_patient').split('\\') + + dir = [round(float(a)) for a in image_orientation_patient] +# dir = [float(a) for a in image_orientation_patient] + + pos = map(float, image_position_patient) + +# dir2 = (pos_z - pos_a) * [1, -1, 1]/ (self.images[-1] - self.images[0]) + dir2 = (pos_z - pos_a) / (self.images[-1] - self.images[0]) + + dir2 = dir2 / np.linalg.norm(dir2) + dir2 = [round(a) for a in dir2] +# dir2 = [a for a in dir2] + + + dir3 = np.array(dir+dir2) + + dir4 = np.linalg.inv(dir3.reshape(3,3)) + dir4 = np.transpose(dir3.reshape(3,3)) + + print self.path + print image_orientation_patient + print pos_a, pos_z + print self.images + print dir + print dir2 + print dir3 + print dir4 + + print list(dir4.flat) + + return list(dir4.flat) + +# return dir3.tolist() + + + def write(self, filename): + import SimpleITK + + print self.Description.get('image_number') +# print self.Description.get('referenced_image_sequence') +# print self.Description.get('source_image_sequence') + + files = glob.glob("%s/*.jpg" % self.path) + files.sort() + + sreader1 = SimpleITK.ImageSeriesReader() + sreader1.SetFileNames(files) + img = sreader1.Execute() + + pixel_spacing = self.Description.get('pixel_spacing').split('\\') + + try: + slice_spacing = float(self.Description.get('slice_spacing')) + except: + slice_spacing = float(self.Description.get('slice_thickness')) + + img.SetDirection(self.direction()) + + img.SetSpacing((float(pixel_spacing[0]), float(pixel_spacing[1]), slice_spacing)) + + SimpleITK.WriteImage(img, filename) + + print img.GetDirection() + print + + def get_description(self): + return self.Description + + +if __name__ == "__main__": + series = IMPAX_Series('/shares/mnt/ntuh-cks/impax/2671292/20130417') + series.write('/tmp/20130417.nii.gz') + + series = IMPAX_Series('/shares/mnt/ntuh-cks/impax/2671292/20130417C') + series.write('/tmp/20130417C.nii.gz') + + + +# series = IMPAX_Series('/shares/mnt/ntuh-cks/impax/0397533/20120815') +# series.write('/tmp/20120815.nii.gz') +# d1 = series.get_description() +# +# series = IMPAX_Series('/shares/mnt/ntuh-cks/impax/0397533/20120815C') +# series.write('/tmp/20120815C.nii.gz') +# +# series = IMPAX_Series('/shares/mnt/ntuh-cks/impax/0397533/20160216') +# series.write('/tmp/20160216.nii.gz') +# +# series = IMPAX_Series('/shares/mnt/ntuh-cks/impax/0397533/20160216C') +# series.write('/tmp/20160216C.nii.gz') +# d2 = series.get_description() +# +# import pprint +# pp = pprint.PrettyPrinter(indent=4) + +# print d1-d2 +# pp.pprint(d1-d2) + + + \ No newline at end of file diff --git a/logs/.nodelete b/logs/.nodelete new file mode 100755 index 0000000..e69de29 diff --git a/logs/access_log b/logs/access_log new file mode 120000 index 0000000..4cf86a6 --- /dev/null +++ b/logs/access_log @@ -0,0 +1 @@ +/var/log/virtualmin/ck.ntuh.net_access_log \ No newline at end of file diff --git a/logs/error_log b/logs/error_log new file mode 120000 index 0000000..23cc542 --- /dev/null +++ b/logs/error_log @@ -0,0 +1 @@ +/var/log/virtualmin/ck.ntuh.net_error_log \ No newline at end of file diff --git a/mysite/ai_clinic.py b/mysite/ai_clinic.py new file mode 100755 index 0000000..6184690 --- /dev/null +++ b/mysite/ai_clinic.py @@ -0,0 +1,36 @@ +#!/usr/bin/python +# coding=utf-8 + +from __future__ import unicode_literals + +import datetime +import os +import re + +import django + +os.environ['DJANGO_SETTINGS_MODULE'] = 'mysite.settings' +# os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings") +django.setup() + +# from mechanize import Browser +# br = Browser() +# br.set_handle_robots(False) + +from ck.models import * +# from ntuhgov import intra +from ntuhgov.portal_selenium import * + +def AI_CLINIC(): + # print(type(Patient)) + for mrn in OpenClinics('2019-3-22', '2', 10): + try: + p = Patient.objects.get(medical_records=mrn) + print('%s %s' % (mrn, p.name)) + except: + # print(mrn) + continue + +if __name__ == "__main__": + AI_CLINIC() +# PatientsRefresh() \ No newline at end of file diff --git a/mysite/calculator/__init__.py b/mysite/calculator/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/mysite/calculator/admin.py b/mysite/calculator/admin.py new file mode 100644 index 0000000..8c38f3f --- /dev/null +++ b/mysite/calculator/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/mysite/calculator/apps.py b/mysite/calculator/apps.py new file mode 100644 index 0000000..e13641c --- /dev/null +++ b/mysite/calculator/apps.py @@ -0,0 +1,5 @@ +from django.apps import AppConfig + + +class CalculatorConfig(AppConfig): + name = 'calculator' diff --git a/mysite/calculator/forms.py b/mysite/calculator/forms.py new file mode 100644 index 0000000..3f0a78d --- /dev/null +++ b/mysite/calculator/forms.py @@ -0,0 +1,11 @@ +from django import forms + +class PresciptionForm(forms.Form): + volume = forms.FloatField(required=False) + # num2 = forms.IntegerField(required=False) + +class CIForm(forms.Form): + Px = forms.IntegerField(label='Px(cGy)' , required=False) + Coverage = forms.FloatField (label='Coverage(%)', required=False) + TV = forms.FloatField (label='TV(cc)' , required=False) + PIV = forms.FloatField (label='PIV(cc)' , required=False) diff --git a/mysite/calculator/migrations/__init__.py b/mysite/calculator/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/mysite/calculator/models.py b/mysite/calculator/models.py new file mode 100644 index 0000000..71a8362 --- /dev/null +++ b/mysite/calculator/models.py @@ -0,0 +1,3 @@ +from django.db import models + +# Create your models here. diff --git a/mysite/calculator/tests.py b/mysite/calculator/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/mysite/calculator/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/mysite/calculator/urls.py b/mysite/calculator/urls.py new file mode 100755 index 0000000..087f899 --- /dev/null +++ b/mysite/calculator/urls.py @@ -0,0 +1,11 @@ +from django.urls import path + +from . import views + +app_name = 'polls' +urlpatterns = [ + + path('prescription/', views.PresciptionView.as_view(), name='prescription'), + path('ci/', views.CIView.as_view(), name='ci'), + +] \ No newline at end of file diff --git a/mysite/calculator/views.py b/mysite/calculator/views.py new file mode 100644 index 0000000..0aecb93 --- /dev/null +++ b/mysite/calculator/views.py @@ -0,0 +1,132 @@ +from math import exp, log + + +from django.shortcuts import render +from django.views.generic import TemplateView + +from scipy import stats + +import numpy as np + + +from .forms import * + +# Create your views here. + +diameter = [12.5, 15.0, 17.5, 20.0, 22.5, 25.0, 27.5, 30.0, 32.5] +volume = [1.02, 1.77, 2.81, 4.19, 5.96, 8.18, 10.9, 14.1, 18.0] + +# Flickinger, John C., et al. "Dose selection in stereotactic radiosurgery." Radiosurgery and Pathological Fundamentals 20 (2007): 28-42. +# https://doi.org/10.1159/000100093 +Kjellberg = [27.5, 25.0, 22.5, 20.0, 18.7, 17.5, 16.5, 15.0, 14.0] +ILF = [34.0, 29.0, 23.0, 18.0, 16.5, 14.5, 13.5, 13.0, 12.5] +RTOG = [24.0, 24.0, 24.0, 24.0, 18.0, 18.0, 18.0, 18.0, 15.0] + +NCT02353000 = [24.0, 21.0, 21.0, 21.0, 21.0, 21.0, 18.0, 18.0, 15.0] # https://doi.org/10.1186/s12885-017-3494-z + +# http://www.aboutcancer.com/gk_doses.htm +Pit = [20.0, 20.0, 20.0, 20.0, 16.0, 16.0, 15.0, 15.0, 14.0] # U Pitt +Other = [24.0, 24.0, 24.0, 24.0, 24.0, 24.0, 22.0, 22.0, 16.0] # Other sites (e.g. Cleveland Clinic) Too high? +Karolinska = [25.0, 25.0, 22.5, 20.0, 20.0, 20.0, 18.0, 18.0, 18.0] # Karolinska Policy on Brain Mets +ACOSOG_Z0300 = [24.0, 24.0, 24.0, 20.0, 20.0, 20.0, 20.0, 18.0, 18.0] # ACOSOG Z0300 + + +def log_regression(func, v): + +# print func + +# dose = map(func, Kjellberg, ILF, RTOG) +# dose = [func([Kjellberg[i], ILF[i], RTOG[i]]) for i in range(len(volume))] +# dose = [func([Kjellberg[i], ILF[i], RTOG[i], NCT02353000[i]]) for i in range(len(volume))] + + dose = [func([ + Kjellberg[i], + ILF[i], + RTOG[i], + + # NCT02353000[i], + +# Pit[i], +# Other[i], +# Karolinska[i], +# ACOSOG_Z0300[i], + + ]) for i in range(len(volume))] + +# print dose + + logv = list(map(log, volume)) + logd = list(map(log, dose)) + +# print(logv) + + gradient, intercept, r_value, p_value, std_err = stats.linregress(logv, logd) +# print "Gradient and intercept", gradient, intercept + return exp(log(v) * gradient + intercept) + + +def solve_d(d1, n, ab = 2.0): + coeff = [n/ab, n, -d1*(1+d1/ab)] + d = np.roots(coeff)[1] + return n*d + + +def fraction_string(d): + return (d, + solve_d(d, 2), + solve_d(d, 3), + solve_d(d, 4), + solve_d(d, 5), + ) + + +class PresciptionView(TemplateView): + template_name = 'calculator/prescription.html' + + def get(self, request, *args, **kwargs): + form = PresciptionForm() + return render(request,self.template_name, {'form':form}) + + def post(self,request): + form = PresciptionForm(request.POST) + if form.is_valid(): + v = form.cleaned_data['volume'] + result = {} + + result['min'] = fraction_string(log_regression(min , v)) + result['mean'] = fraction_string(log_regression(np.mean , v)) + result['median'] = fraction_string(log_regression(np.median, v)) + result['max'] = fraction_string(log_regression(max , v)) + + form = PresciptionForm() + #return redirect ('home:home') + + args = {'form': form , 'result': result} + return render(request, self.template_name, args ) + +class CIView(TemplateView): + template_name = 'calculator/ci.html' + + def get(self, request, *args, **kwargs): + form = CIForm() + return render(request,self.template_name, {'form':form}) + + def post(self,request): + form = CIForm(request.POST) + if form.is_valid(): + Px = form.cleaned_data['Px'] + Coverage = form.cleaned_data['Coverage'] + TV = form.cleaned_data['TV'] + PIV = form.cleaned_data['PIV'] + result = {} + + TVPIV = Coverage*TV/100 + result['TVPIV'] = Coverage*TV/100 + result['CI'] = PIV/TVPIV + result['nCI'] = (PIV/TVPIV)*(TV/TVPIV) + + form = CIForm() + #return redirect ('home:home') + + args = {'form': form , 'result': result} + return render(request, self.template_name, args ) \ No newline at end of file diff --git a/mysite/ck/0.py b/mysite/ck/0.py new file mode 100755 index 0000000..1f251bc --- /dev/null +++ b/mysite/ck/0.py @@ -0,0 +1,6 @@ +#!/usr/bin/env python + +from intra import * + +print HeightWeight('D120264406') +#print ReportResult('D120264406') diff --git a/mysite/ck/__init__.py b/mysite/ck/__init__.py new file mode 100755 index 0000000..e69de29 diff --git a/mysite/ck/admin.py b/mysite/ck/admin.py new file mode 100755 index 0000000..8c38f3f --- /dev/null +++ b/mysite/ck/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/mysite/ck/autocomplete_light_registry.py b/mysite/ck/autocomplete_light_registry.py new file mode 100755 index 0000000..00e0b68 --- /dev/null +++ b/mysite/ck/autocomplete_light_registry.py @@ -0,0 +1,32 @@ +import autocomplete_light.shortcuts as al +from models import ICD10CMfinal + +# This will generate a PersonAutocomplete class +al.register(ICD10CMfinal, + # Just like in ModelAdmin.search_fields + search_fields=[ + '^ICD9CM_code', + 'ICD9CM_English', + '^ICD10CM', + 'ICD10CM_English', + ], + attrs={ + # This will set the input placeholder attribute: +# 'placeholder': 'Other model name ?', + # This will set the yourlabs.Autocomplete.minimumCharacters + # options, the naming conversion is handled by jQuery + 'data-autocomplete-minimum-characters': 1, + }, + # This will set the data-widget-maximum-values attribute on the + # widget container element, and will be set to + # yourlabs.Widget.maximumValues (jQuery handles the naming + # conversion). + widget_attrs={ + 'data-widget-maximum-values': 4, + # Enable modern-style widget ! + 'class': 'modern-style', + +# 'style': "background-color: yellow; width: 375px; display: inline-block;", + 'style': "width: 576px; display: inline-block;", + }, +) diff --git a/mysite/ck/common.py b/mysite/ck/common.py new file mode 100644 index 0000000..517ecea --- /dev/null +++ b/mysite/ck/common.py @@ -0,0 +1,331 @@ +import datetime + +from django.db.models import Q +from django.utils import timezone + +import zeep + +from .models import * + +import ntuhgov.portal_selenium as portal + +def UpdateNHICase(case): + + # print(case) + + if 'PackageTime' not in case: + case['PackageTime'] = case['ApplyDate'] + + if 'ApplyQty' in case: + case['ResultDesc'] = case['ApplyQty'] + + if case['PackageTime'] is not None: + case['PackageTime']=case['PackageTime'].replace('/','-') + + if 'ExamineDate' in case and case['ExamineDate'] is not None: + case['ExamineDate']=case['ExamineDate'].replace('/','-') + if 'ApplyDate' in case and case['ApplyDate'] is not None: + case['ApplyDate']=case['ApplyDate'].replace('/','-') + + if 'ApplyDoctor' in case and case['ApplyDoctor'] is not None: + case['ApplyDoctor']=case['ApplyDoctor'].replace('\ue09b', '峯') #'許峯銘' + + if case['PackageTime'] is None: + return + + # id = case['ChartNo']+'_'+case['PackageTime'][:4] + id = case['ChartNo']+'_'+case['PackageTime'][:7] + + order = NHIOrder.objects.filter(id=id).first() + + if order == None: + order = NHIOrder(id=id) + + # print(order) + # exit() + # order, created = NHIOrder.objects.get_or_create(id=id) + + for k, v in case.items(): + # order[k] = v + # print(k,v) + if v is not None: + setattr(order, k, v) + + if order.Priority is None: + if order.Quantity == 'åŒæ„備查': + order.Priority = 1 + + order.save() + +FirstPriority = 900 +LastPriority = 100 +def SortNHI(CheckTreated=True): + + for v in NHIOrder.objects.values('ApplyDoctor').distinct(): + + if v['ApplyDoctor'] is None: + continue + + print(v) + + q = NHIOrder.objects.filter(ApplyDoctor=v['ApplyDoctor'],Priority__gt=0).order_by('-Priority', 'PackageTime') + total = len(q) + print(v['ApplyDoctor'], total) + + if total < 1: + continue + + + priority = FirstPriority + d = (FirstPriority-LastPriority)/total + for order in q: + + # check if treated + # patient = Patient.objects.get(medical_records=order.ChartNo) + + if CheckTreated: + patient = Patient.objects.filter(medical_records=order.ChartNo).first() + if patient is not None: + print(patient, patient.medical_records) + for t in patient.treatment_set.all(): + print(t.date_started, order.ExamineDate) + if (t.date_started is not None) and (order.ExamineDate is not None) and t.date_started > order.ExamineDate: + order.Priority = -1 + + # if v['ApplyDoctor'] is not None and order.Priority > 0: + if order.Priority > 0: + order.Priority = priority + priority -= d + order.save() + +def AddPatient(d, force=True): + # r = portal.QueryModifyPatBase({'IdNo': idcode, + # 'ChartNo': chartno, + # }) + + p = None + r = portal.QueryModifyPatBase(d) + + if r: + r['name'] = r['ChtName'] + r['medical_records'] = r['ChartNo'] + r['gender'] = r['Sex'] + r['birthday'] = r['Birth'] + r['address'] = r['AddressControl1'] + r['phone'] = r['ContTel'] + r['id_cards'] = r['IdNo'] + + result = [r] + else: + result = [] + + if force and len(result)>0: + r=result[0] + + if r['gender'] == 'M': + r['gender'] = 1 + else: + r['gender'] = 2 +# hw = intra.HeightWeight(r['id_cards']) +# hw = ntuhgov.portal.HeightWeight(r['id_cards']) + hw = portal.BriefHistoryLink(r['id_cards']) + p = Patient(name = r['name'], + medical_records = r['medical_records'], + gender = r['gender'], + birthday = r['birthday'], + address = r['address'], + phone = r['phone'], + id_cards = r['id_cards'], + # height = hw['Height'], + weight = hw['Weight'], + ) + + try: + p.height = int(hw['Height']) + except: + pass + p.save() + + return p + +def QueryMS(): + import mssql_ntuh.models as mssql + + tzinfo=timezone.get_default_timezone() + + # time_threshold = datetime.datetime.now() - datetime.timedelta(weeks=4) + # DateTimeField Treatment.timestamp received a naive datetime while time zone support is active. + time_threshold = timezone.now() - datetime.timedelta(weeks=4) + + # qs = mssql.PatientAppointmentSchedule.objects.using('mssql-ntuh').all() + qs = mssql.PatientAppointmentSchedule.objects.using('mssql-ntuh').filter(appointment_date__gt=time_threshold) + + for s in qs: + appointment_time = s.appointment_date.replace(tzinfo=tzinfo, hour=int(s.appointment_hour), minute=int(s.appointment_minutes)) + + if s.treatment_start_datetime: + start_time = s.treatment_start_datetime.replace(tzinfo=tzinfo) + elif s.checkin_datetime : + start_time = s.checkin_datetime.replace(tzinfo=tzinfo) + else: + start_time = s.appointment_date.replace(tzinfo=tzinfo, hour=int(s.appointment_hour), minute=int(s.appointment_minutes)) + + if s.treatment_complete_datetime: + end_time = s.treatment_complete_datetime.replace(tzinfo=tzinfo) + else: + end_time = start_time + datetime.timedelta(hours=1) + + if s.treatment_room == 'MR': + end_time = max(end_time, start_time + datetime.timedelta(hours=1)) + + # start_time = timezone.make_aware(datetime.datetime.now(),timezone.get_default_timezone()) + # start_time = timezone.get_default_timezone().localize(start_time) + # start_time = start_time.replace(tzinfo=tzinfo) + + print(s.mapping_patient, s.treatment_room, s.appointment_date, s.checkin_datetime, s.queue_datetime, s.treatment_start_datetime, s.treatment_complete_datetime, s.fallrisktime, s.willtime) + mapping_patient = mssql.Patient.objects.using('mssql-ntuh').filter(id=s.mapping_patient).first() + # print(p.name) + # try: + # print(s.mapping_patient.name) + # except: + # #no patient found + # continue + print(s.id, s.main_diagnose, s.treatment_room, start_time, end_time) + # chartno = s.mapping_patient.record_no + patient = Patient.objects.filter(medical_records=s.record_no).first() + # print(patient) + if patient is None: + print('AddPatient', s.record_no, mapping_patient.name) + patient = AddPatient({'ChartNo': s.record_no}) + + if patient is None: + # false patient + continue + + # print(patient.name) + treatment = patient.treatment_set.filter(Q(creation__gt=time_threshold) | Q(timestamp__gt=time_threshold)).order_by('-id').first() + + if treatment is None: + print('Add Treatment', mapping_patient.record_no, mapping_patient.name) + treatment = Treatment(patient=patient) + treatment.save() + + if treatment.surgeon is None and s.main_doctor: + treatment.surgeon = Surgeon.objects.filter(name=s.main_doctor).first() + if treatment.oncologist is None and s.rt_doctor: + treatment.oncologist = Oncologist.objects.filter(name=s.rt_doctor).first() + if treatment.other_diagnosis is None and s.main_diagnose: + treatment.other_diagnosis = s.main_diagnose + + + if s.treatment_room == 'CK': + if treatment.date_started is None or treatment.date_started > start_time.date(): + treatment.date_started = start_time + if treatment.date_completed is None or treatment.date_completed < end_time.date(): + treatment.date_completed = end_time + if treatment.bed is None and s.hospitalized_status: + treatment.bed = s.hospitalized_status + + if treatment.icd10cm is None: # 找之å‰çš„å¥ä¿ç”³è«‹ + order = NHIOrder.objects.filter(ChartNo=s.record_no).order_by('-id').first() + if order is not None and order.ExamineDate is not None: + treatment.icd10cm = ICD10CMfinal.objects.filter(ICD10CM=order.Diagnosis).first() + count = patient.treatment_set.filter(Q(creation__gt=order.ExamineDate)).count() + if count <= 1: + treatment.accounting = 10 + + timestamp = max(treatment.creation, treatment.timestamp) + print(patient.name, treatment, timestamp) + + print() + treatment.save() + + + vevent = treatment.vevent_set.filter(DESCRIPTION=s.id).first() + if vevent is None: + vevent = VEVENT(treatment=treatment,DESCRIPTION=s.id) + + vevent.DTSTART = start_time + vevent.DURATION = str(end_time-start_time) + # print(vevent.DURATION, type(vevent.DURATION)) + + print(s.treatment_room) + if s.treatment_room == 'CK': + vevent.mode = 310 + vevent.SUMMARY = patient.name+'治療' + elif s.treatment_room == 'MR': + vevent.mode = 220 + vevent.SUMMARY = patient.name+'MRI' + elif s.treatment_room == 'HE': + vevent.mode = 100 + vevent.SUMMARY = patient.name+'衛教' + elif s.treatment_room.startswith('CT'): + vevent.mode = 210 + vevent.SUMMARY = patient.name+s.treatment_room + + vevent.save() + + print(len(qs)) + +def UpdateNHICase2(case): + + print(case) + case = zeep.helpers.serialize_object(case) + + if 'PackageTime' not in case: + case['PackageTime'] = case['ApplyDate'] + + if 'ApplyQty' in case: + case['ResultDesc'] = case['ApplyQty'] + + if 'ApplyDoctor' in case and case['ApplyDoctor'] is not None: + case['ApplyDoctor']=case['ApplyDoctor'].replace('\ue09b', '峯') #'許峯銘' + + if case['PackageTime'] is None: + return + + case['Quantity'] = case['ResultDesc'] + case['ResultDesc'] = 1 + case['ExamineQuantity'] = 1 + + case['NhiDeptName'] = case['NhiDept'] + case['Diagnosis'] = case['DiagnosisCode'] + + # id = case['ChartNo']+'_'+case['PackageTime'][:4] + # print(case['PackageTime'].strftime('%Y-%m')) + id = case['ChartNo']+'_'+case['PackageTime'].strftime('%Y-%m') + + order = NHIOrder.objects.filter(id=id).first() + + if order == None: + order = NHIOrder(id=id) + + # print(order) + # exit() + # order, created = NHIOrder.objects.get_or_create(id=id) + + for k, v in case.items(): + # order[k] = v + # print(k,v) + if v is not None: + setattr(order, k, v) + + if order.Priority is None: + if order.Quantity == 'åŒæ„備查': + order.Priority = 1 + + order.save() + + +def GetCaseForCyberKnifeList(days=30): + + eDate = datetime.date.today() + sDate = eDate + datetime.timedelta(days=-days) + + settings = zeep.Settings(strict=False, xml_huge_tree=True) + client = zeep.Client('https://converws.ntuh.gov.tw/WebApplication/NtuhACEService/CyberKnifeService.asmx?WSDL', settings=settings) + # client = zeep.Client('https://tconverws.ntuh.gov.tw/WebApplication/NtuhACEService/CyberKnifeService.asmx?WSDL', settings=settings) + result = client.service.GetCaseForCyberKnifeList('T0', sDate, eDate) + # print(len(result)) + # exit() + return result diff --git a/mysite/ck/forms.py b/mysite/ck/forms.py new file mode 100755 index 0000000..83090ab --- /dev/null +++ b/mysite/ck/forms.py @@ -0,0 +1,78 @@ +#coding=utf-8 + +#from django import newforms as forms +from django import forms +from django_measurement.forms import MeasurementField +#from django.newforms import form_for_model +from django.forms import ModelForm +from .models import * +# import autocomplete_light +from dal import autocomplete + +#PatientForm = form_for_model(Patient) + +class PatientForm(forms.Form): + ChartNo = forms.CharField() + Name = forms.CharField() + idcode = forms.CharField() + +#TreatmentForm = form_for_model(Treatment) + +class TreatmentForm(ModelForm): +# class TreatmentForm(autocomplete_light.ModelForm): + def clean(self): + cleaned_data = super(TreatmentForm, self).clean() + if cleaned_data['icd10cm']: + cleaned_data['icd9'] = ICD9Diag.objects.get(pk=cleaned_data['icd10cm'].ICD9CM_code.replace('.', '')) + + class Meta: + model = Treatment + fields = '__all__' + widgets = { + 'icd10cm': autocomplete.ModelSelect2(url='icd10-autocomplete') + } + + +class LesionForm(forms.ModelForm): + class Meta: + model = Lesion + fields = [ + 'calibration_table', + 'density_correction', + + # 'treatment', + 'sub_location', + 'pathology', + 'dimensions', + + # 'volume', + 'volume_measure', + + 'plan_name', + + 'collimator_type', + 'collimator', + + 'path_no', + 'beam_no', + + 'mu_max', + 'mu_min', + + 'dose', + 'fractions', + 'iso_dose_curve', + + 'dmin', + 'dmax', + 'dmean', + + 'coverage', + 'ci', + 'nci', + + 'start_date', + 'end_date', + + 'memo', + ] diff --git a/mysite/ck/migrations.bak/0001_initial.py b/mysite/ck/migrations.bak/0001_initial.py new file mode 100755 index 0000000..7a99a05 --- /dev/null +++ b/mysite/ck/migrations.bak/0001_initial.py @@ -0,0 +1,512 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import models, migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ] + + operations = [ + migrations.CreateModel( + name='Activity', + fields=[ + ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ('title', models.CharField(max_length=200)), + ], + options={ + }, + bases=(models.Model,), + ), + migrations.CreateModel( + name='DiseaseStage', + fields=[ + ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ('stage', models.CharField(max_length=200)), + ], + options={ + }, + bases=(models.Model,), + ), + migrations.CreateModel( + name='ElectronicMedicalReport', + fields=[ + ('report_key', models.CharField(max_length=200, serialize=False, primary_key=True)), + ('report_class', models.CharField(max_length=200)), + ('check_date', models.DateField(null=True)), + ('report_date', models.DateField(null=True)), + ('report_code', models.CharField(max_length=200)), + ('report', models.TextField(null=True)), + ('saved', models.DateField(auto_now=True)), + ], + options={ + }, + bases=(models.Model,), + ), + migrations.CreateModel( + name='Followup', + fields=[ + ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ('date', models.DateField()), + ('memo', models.CharField(max_length=200, null=True, blank=True)), + ], + options={ + }, + bases=(models.Model,), + ), + migrations.CreateModel( + name='ICD9Diag', + fields=[ + ('code', models.CharField(max_length=5, serialize=False, primary_key=True)), + ('desc', models.CharField(max_length=50)), + ], + options={ + }, + bases=(models.Model,), + ), + migrations.CreateModel( + name='Lesion', + fields=[ + ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ('dimensions', models.CharField(max_length=200)), + ('volume', models.DecimalField(max_digits=9, decimal_places=2)), + ('plan_name', models.CharField(max_length=200, null=True, blank=True)), + ('collimator', models.CharField(max_length=200)), + ('path_no', models.IntegerField()), + ('beam_no', models.IntegerField()), + ('mu_max', models.DecimalField(max_digits=9, decimal_places=2)), + ('mu_min', models.DecimalField(max_digits=9, decimal_places=2)), + ('dose', models.IntegerField()), + ('fractions', models.IntegerField()), + ('iso_dose_curve', models.IntegerField()), + ('dmin', models.DecimalField(max_digits=9, decimal_places=2)), + ('dmax', models.DecimalField(max_digits=9, decimal_places=2)), + ('coverage', models.DecimalField(max_digits=9, decimal_places=2)), + ('ci', models.DecimalField(max_digits=9, decimal_places=2)), + ('nci', models.DecimalField(max_digits=9, decimal_places=2)), + ('start_date', models.DateField(null=True, blank=True)), + ('end_date', models.DateField(null=True, blank=True)), + ('memo', models.CharField(max_length=200, null=True, blank=True)), + ], + options={ + }, + bases=(models.Model,), + ), + migrations.CreateModel( + name='LesionFollow', + fields=[ + ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ('Date', models.DateField(verbose_name=b'\xe8\xbf\xbd\xe8\xb9\xa4\xe6\x97\xa5\xe6\x9c\x9f')), + ('Volume', models.FloatField(null=True, verbose_name=b'\xe9\xab\x94\xe7\xa9\x8d(mm3)')), + ('A', models.FloatField(null=True, verbose_name=b'\xe9\x95\xb7(mm)')), + ('B', models.FloatField(null=True, verbose_name=b'\xe5\xaf\xac(mm)')), + ('C', models.FloatField(null=True, verbose_name=b'\xe9\xab\x98(mm)')), + ('Memo', models.CharField(max_length=200, null=True, blank=True)), + ('Lesion', models.ForeignKey(to='ck.Lesion')), + ], + options={ + }, + bases=(models.Model,), + ), + migrations.CreateModel( + name='MedicalRecord', + fields=[ + ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ('Record', models.CharField(max_length=200, null=True)), + ('HospName', models.CharField(max_length=200, null=True)), + ('DeptName', models.CharField(max_length=200, null=True, verbose_name=b'\xe7\xa7\x91')), + ('InDate', models.DateField(verbose_name=b'\xe5\x85\xa5')), + ('OutDate', models.DateField(null=True, verbose_name=b'\xe5\x87\xba')), + ('WardName', models.CharField(max_length=200, null=True, verbose_name=b'\xe6\x88\xbf')), + ('RoomName', models.CharField(max_length=200, null=True, verbose_name=b'\xe5\xae\xa4')), + ('BedName', models.CharField(max_length=200, null=True, verbose_name=b'\xe5\xba\x8a')), + ('MainDrName', models.CharField(max_length=200, null=True, verbose_name=b'\xe4\xb8\xbb\xe6\xb2\xbb')), + ('MainDiagnosisName', models.CharField(max_length=200, null=True, verbose_name=b'\xe8\xa8\xba\xe6\x96\xb7')), + ('StatusName', models.CharField(max_length=200, null=True, verbose_name=b'\xe7\x8b\x80\xe6\x85\x8b')), + ('SpecialCureName', models.CharField(max_length=200, null=True, verbose_name=b'\xe8\xa1\x8c\xe7\x82\xba')), + ], + options={ + }, + bases=(models.Model,), + ), + migrations.CreateModel( + name='Oncologist', + fields=[ + ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ('name', models.CharField(max_length=200)), + ], + options={ + }, + bases=(models.Model,), + ), + migrations.CreateModel( + name='OPNote', + fields=[ + ('key_code', models.CharField(max_length=200, serialize=False, primary_key=True)), + ('key_name', models.CharField(max_length=200)), + ('doc', models.TextField(null=True, verbose_name=b'\xe6\x91\x98')), + ('saved', models.DateField(auto_now=True)), + ], + options={ + }, + bases=(models.Model,), + ), + migrations.CreateModel( + name='PACSImage', + fields=[ + ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ('PatChartNo', models.CharField(max_length=200, verbose_name=b'\xe7\x97\x85\xe6\xad\xb7\xe8\x99\x9f')), + ('RequestSheetNo', models.CharField(max_length=200, verbose_name=b'\xe5\x96\xae\xe8\x99\x9f')), + ('ExamDate', models.DateField(verbose_name=b'\xe6\xaa\xa2\xe6\x9f\xa5\xe6\x97\xa5')), + ('LinkOrderName', models.CharField(max_length=200, verbose_name=b'\xe6\xaa\xa2\xe6\x9f\xa5\xe5\x90\x8d\xe7\xa8\xb1')), + ('Modality', models.CharField(max_length=200, verbose_name=b'\xe5\x84\x80\xe5\x99\xa8')), + ('VerifiedStateString', models.CharField(max_length=200, verbose_name=b'\xe7\x8b\x80\xe6\x85\x8b')), + ('Exam', models.TextField(null=True, verbose_name=b'\xe5\xa0\xb1\xe5\x91\x8a\xe5\x85\xa7\xe5\xae\xb9')), + ('Impression', models.TextField(null=True)), + ('Report', models.TextField(null=True, verbose_name=b'\xe5\xa0\xb1\xe5\x91\x8a')), + ('Saved', models.IntegerField(verbose_name=b'\xe4\xbf\x9d\xe5\xad\x98', choices=[(0, b'\xe5\xbe\x85\xe8\x99\x95\xe7\x90\x86'), (10, b'\xe6\x9c\x89\xe8\xbc\xb8\xe5\x85\xa5'), (15, b'\xe5\xb7\xb2\xe7\xa2\xba\xe8\xaa\x8d'), (20, b'\xe4\xb8\x8d\xe9\x81\xa9\xe7\x94\xa8')])), + ], + options={ + }, + bases=(models.Model,), + ), + migrations.CreateModel( + name='PathExam', + fields=[ + ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ('path_code', models.CharField(unique=True, max_length=200, verbose_name=b'\xe7\x97\x85\xe7\x90\x86\xe8\x99\x9f')), + ('specimen_code', models.CharField(max_length=200, verbose_name=b'\xe6\xaa\xa2\xe9\xab\x94')), + ('specimen_get_date', models.DateField(verbose_name=b'\xe6\x94\xb6\xe4\xbb\xb6\xe6\x97\xa5')), + ('report_date', models.DateField(verbose_name=b'\xe5\xa0\xb1\xe5\x91\x8a\xe6\x97\xa5')), + ('division', models.CharField(max_length=200, verbose_name=b'\xe7\xa7\x91\xe5\x88\xa5')), + ('bed', models.CharField(max_length=200, null=True, verbose_name=b'\xe7\x97\x85\xe5\xba\x8a', blank=True)), + ('report', models.TextField(null=True, verbose_name=b'\xe6\xaa\xa2\xe6\x9f\xa5\xe5\xa0\xb1\xe5\x91\x8a', blank=True)), + ], + options={ + }, + bases=(models.Model,), + ), + migrations.CreateModel( + name='Pathology', + fields=[ + ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ('pathology', models.CharField(unique=True, max_length=200)), + ('stage', models.ForeignKey(to='ck.DiseaseStage')), + ], + options={ + }, + bases=(models.Model,), + ), + migrations.CreateModel( + name='Patient', + fields=[ + ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ('name', models.CharField(max_length=200, verbose_name=b'\xe5\xa7\x93\xe5\x90\x8d')), + ('medical_records', models.CharField(unique=True, max_length=200)), + ('gender', models.IntegerField(choices=[(1, b'Male'), (2, b'Female')])), + ('birthday', models.DateField()), + ('address', models.CharField(max_length=200)), + ('phone', models.CharField(max_length=200)), + ('id_cards', models.CharField(unique=True, max_length=200)), + ('memo', models.CharField(max_length=200, null=True, blank=True)), + ('dead', models.DateField(null=True, blank=True)), + ('height', models.DecimalField(null=True, max_digits=4, decimal_places=1)), + ('weight', models.DecimalField(null=True, max_digits=6, decimal_places=3)), + ('native', models.CharField(max_length=200, null=True, blank=True)), + ('past_and_family_history', models.TextField(null=True, blank=True)), + ('timestamp', models.DateTimeField(auto_now=True)), + ], + options={ + }, + bases=(models.Model,), + ), + migrations.CreateModel( + name='PatientMedicalRecord', + fields=[ + ('key_code', models.CharField(max_length=200, serialize=False, primary_key=True)), + ('key_name', models.CharField(max_length=200)), + ('hosp_name', models.CharField(max_length=200, null=True)), + ('dept_name', models.CharField(max_length=200, null=True, verbose_name=b'\xe7\xa7\x91')), + ('in_date', models.DateField(null=True, verbose_name=b'\xe5\x85\xa5')), + ('out_date', models.DateField(null=True, verbose_name=b'\xe5\x87\xba')), + ('ward_name', models.CharField(max_length=200, null=True, verbose_name=b'\xe6\x88\xbf')), + ('room_name', models.CharField(max_length=200, null=True, verbose_name=b'\xe5\xae\xa4')), + ('bed_name', models.CharField(max_length=200, null=True, verbose_name=b'\xe5\xba\x8a')), + ('come_clinic_date', models.DateField(null=True, verbose_name=b'\xe6\x8e\x9b\xe8\x99\x9f\xe6\x97\xa5')), + ('discharge_date', models.DateField(null=True, verbose_name=b'\xe9\x9b\xa2\xe9\x83\xa8\xe6\x97\xa5')), + ('special_cure_name', models.CharField(max_length=200, null=True, verbose_name=b'\xe8\xa1\x8c\xe7\x82\xba')), + ('main_dr_name', models.CharField(max_length=200, null=True, verbose_name=b'\xe4\xb8\xbb\xe6\xb2\xbb')), + ('main_diagnosis_name', models.CharField(max_length=200, null=True, verbose_name=b'\xe8\xa8\xba\xe6\x96\xb7')), + ('status_name', models.CharField(max_length=200, null=True, verbose_name=b'\xe7\x8b\x80\xe6\x85\x8b')), + ('temp_bed_id', models.CharField(max_length=200, null=True, verbose_name=b'\xe5\xba\x8a')), + ('account_status_name', models.CharField(max_length=200, null=True, verbose_name=b'\xe7\x8b\x80\xe6\x85\x8b')), + ('func', models.CharField(max_length=200, null=True)), + ('doc', models.TextField(null=True, verbose_name=b'\xe6\x91\x98')), + ('saved', models.DateField(auto_now=True)), + ('patient', models.ForeignKey(to='ck.Patient')), + ], + options={ + }, + bases=(models.Model,), + ), + migrations.CreateModel( + name='Price', + fields=[ + ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ('code', models.CharField(max_length=200, null=True, blank=True)), + ('identity', models.IntegerField(choices=[(10, b'\xe5\x81\xa5\xe4\xbf\x9d'), (20, b'\xe8\x87\xaa\xe8\xb2\xbb'), (30, b'\xe5\x85\xa7\xe5\x90\xab')])), + ('name', models.CharField(max_length=200)), + ('unit', models.CharField(max_length=200, null=True, blank=True)), + ('address', models.IntegerField(null=True, blank=True)), + ], + options={ + }, + bases=(models.Model,), + ), + migrations.CreateModel( + name='PrimaryTumorSite', + fields=[ + ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ('site', models.CharField(max_length=200)), + ], + options={ + }, + bases=(models.Model,), + ), + migrations.CreateModel( + name='PriorTreatment', + fields=[ + ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ('date', models.DateField()), + ('treatment', models.IntegerField(choices=[(1, b'Surgery'), (2, b'Biopsy'), (3, b'RT'), (4, b'Radiosurgery'), (5, b'Chemotherapy')])), + ('period', models.IntegerField(blank=True, null=True, choices=[(1, b'Before'), (2, b'Concurrent'), (3, b'None')])), + ('dose', models.IntegerField(null=True, blank=True)), + ('memo', models.CharField(max_length=200, null=True, blank=True)), + ('patient', models.ForeignKey(to='ck.Patient')), + ], + options={ + }, + bases=(models.Model,), + ), + migrations.CreateModel( + name='SubLocation', + fields=[ + ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ('group', models.IntegerField()), + ('sub_location', models.CharField(max_length=200)), + ('pathology', models.ManyToManyField(to='ck.Pathology')), + ], + options={ + }, + bases=(models.Model,), + ), + migrations.CreateModel( + name='Surgeon', + fields=[ + ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ('name', models.CharField(max_length=200)), + ], + options={ + }, + bases=(models.Model,), + ), + migrations.CreateModel( + name='TargetLocation', + fields=[ + ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ('location', models.CharField(max_length=200)), + ], + options={ + }, + bases=(models.Model,), + ), + migrations.CreateModel( + name='Treatment', + fields=[ + ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ('bed', models.CharField(max_length=200, null=True, verbose_name=b'\xe7\x97\x85\xe5\xba\x8a\xe8\x99\x9f', blank=True)), + ('other_diagnosis', models.CharField(max_length=200, null=True, verbose_name=b'\xe5\x85\xb6\xe4\xbb\x96\xe8\xa8\xba\xe6\x96\xb7', blank=True)), + ('tracking_mode', models.IntegerField(blank=True, null=True, choices=[(100, b'6D Skull'), (200, b'Xsight-Spine'), (210, b'Xsight-Lung'), (300, b'Fiducial'), (400, b'Synchrony')])), + ('referral', models.CharField(max_length=200, null=True, verbose_name=b'\xe8\xbd\x89\xe4\xbb\x8b\xe9\x86\xab\xe5\xb8\xab', blank=True)), + ('date_started', models.DateField(null=True, blank=True)), + ('date_completed', models.DateField(null=True, blank=True)), + ('accounting', models.IntegerField(blank=True, null=True, verbose_name=b'\xe8\xa8\x98\xe5\xb8\xb3\xe5\x88\xa5', choices=[(10, b'\xe5\x81\xa5\xe4\xbf\x9d'), (20, b'\xe8\x87\xaa\xe8\xb2\xbb'), (30, b'\xe5\x85\xa7\xe5\x90\xab')])), + ('karnofsky_score', models.IntegerField(blank=True, null=True, choices=[(100, b'100% - normal, no complaints, no signs of disease'), (90, b' 90% - capable of normal activity, few symptoms or signs of disease'), (80, b' 80% - normal activity with some difficulty, some symptoms or signs'), (70, b' 70% - caring for self, not capable of normal activity or work'), (60, b' 60% - requiring some help, can take care of most personal requirements'), (50, b' 50% - requires help often, requires frequent medical care'), (40, b' 40% - disabled, requires special care and help'), (30, b' 30% - severely disabled, hospital admission indicated but no risk of death'), (20, b' 20% - very ill, urgently requiring admission, requires supportive measures or treatment'), (10, b' 10% - moribund, rapidly progressive fatal disease processes'), (0, b' 0% - death')])), + ('complications', models.CharField(max_length=200, null=True, verbose_name=b'\xe4\xbd\xb5\xe7\x99\xbc\xe7\x97\x87', blank=True)), + ('chief_complaint', models.TextField(null=True, blank=True)), + ('memo', models.CharField(max_length=200, null=True, blank=True)), + ('timestamp', models.DateTimeField(auto_now=True)), + ], + options={ + }, + bases=(models.Model,), + ), + migrations.CreateModel( + name='TreatmentResponse', + fields=[ + ('treatment', models.ForeignKey(primary_key=True, serialize=False, to='ck.Treatment')), + ('time', models.DateField(null=True)), + ('event', models.NullBooleanField()), + ('time1y', models.DateField(null=True)), + ('event1y', models.NullBooleanField()), + ], + options={ + }, + bases=(models.Model,), + ), + migrations.CreateModel( + name='VEVENT', + fields=[ + ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ('DTSTAMP', models.DateTimeField(auto_now=True)), + ('DTSTART', models.DateTimeField()), + ('DTEND', models.TimeField(blank=True)), + ('DURATION', models.TimeField()), + ('SUMMARY', models.CharField(max_length=200, null=True, blank=True)), + ('CLASS', models.CharField(max_length=200, null=True, blank=True)), + ('CATEGORIES', models.CharField(max_length=200, null=True, blank=True)), + ('TRANSP', models.CharField(max_length=200, null=True, blank=True)), + ('RRULE', models.CharField(max_length=200, null=True, blank=True)), + ('DESCRIPTION', models.CharField(max_length=200, null=True, blank=True)), + ('mode', models.IntegerField(choices=[(110, b'Fiducial'), (200, b'\xe5\x9b\xba\xe5\xae\x9a\xe5\x99\xa8'), (210, b'CT'), (220, b'MRI'), (230, b'Angio'), (310, b'\xe6\xb2\xbb\xe7\x99\x82')])), + ('break_frequency', models.IntegerField(blank=True)), + ('system_err', models.IntegerField(blank=True)), + ('shift', models.IntegerField(blank=True)), + ('cone', models.IntegerField(blank=True)), + ('path', models.IntegerField(blank=True)), + ('price', models.ForeignKey(blank=True, to='ck.Price', null=True)), + ('treatment', models.ForeignKey(to='ck.Treatment')), + ], + options={ + }, + bases=(models.Model,), + ), + migrations.CreateModel( + name='XrayTextReport', + fields=[ + ('report_key', models.ForeignKey(primary_key=True, serialize=False, to='ck.ElectronicMedicalReport')), + ('old_access_no', models.CharField(max_length=200, null=True)), + ('ioe', models.CharField(max_length=200, null=True)), + ('refer_dept', models.CharField(max_length=200, null=True)), + ('status', models.CharField(max_length=200, null=True)), + ('formal_version', models.CharField(max_length=200, null=True)), + ('exam_date', models.DateField(null=True)), + ('order_desc', models.CharField(max_length=200, null=True)), + ('clean_html', models.TextField(null=True)), + ('response', models.CharField(max_length=200, null=True)), + ], + options={ + }, + bases=(models.Model,), + ), + migrations.AddField( + model_name='treatment', + name='disease_stage', + field=models.ForeignKey(blank=True, to='ck.DiseaseStage', null=True), + preserve_default=True, + ), + migrations.AddField( + model_name='treatment', + name='icd9', + field=models.ForeignKey(verbose_name=b'ICD9\xe8\xa8\xba\xe6\x96\xb7', blank=True, to='ck.ICD9Diag', null=True), + preserve_default=True, + ), + migrations.AddField( + model_name='treatment', + name='input', + field=models.ForeignKey(related_name='input', verbose_name=b'\xe5\xb7\xb2', blank=True, to='ck.Activity', null=True), + preserve_default=True, + ), + migrations.AddField( + model_name='treatment', + name='oncologist', + field=models.ForeignKey(blank=True, to='ck.Oncologist', null=True), + preserve_default=True, + ), + migrations.AddField( + model_name='treatment', + name='output', + field=models.ForeignKey(related_name='output', verbose_name=b'\xe5\xbe\x85', blank=True, to='ck.Activity', null=True), + preserve_default=True, + ), + migrations.AddField( + model_name='treatment', + name='patient', + field=models.ForeignKey(to='ck.Patient'), + preserve_default=True, + ), + migrations.AddField( + model_name='treatment', + name='primary_tumor_site', + field=models.ForeignKey(blank=True, to='ck.PrimaryTumorSite', null=True), + preserve_default=True, + ), + migrations.AddField( + model_name='treatment', + name='surgeon', + field=models.ForeignKey(blank=True, to='ck.Surgeon', null=True), + preserve_default=True, + ), + migrations.AddField( + model_name='sublocation', + name='target_location', + field=models.ForeignKey(to='ck.TargetLocation'), + preserve_default=True, + ), + migrations.AddField( + model_name='pathexam', + name='patient', + field=models.ForeignKey(to='ck.Patient'), + preserve_default=True, + ), + migrations.AddField( + model_name='pacsimage', + name='patient', + field=models.ForeignKey(to='ck.Patient'), + preserve_default=True, + ), + migrations.AddField( + model_name='opnote', + name='patient', + field=models.ForeignKey(to='ck.Patient'), + preserve_default=True, + ), + migrations.AddField( + model_name='medicalrecord', + name='patient', + field=models.ForeignKey(to='ck.Patient'), + preserve_default=True, + ), + migrations.AddField( + model_name='lesion', + name='pathology', + field=models.ForeignKey(to='ck.Pathology'), + preserve_default=True, + ), + migrations.AddField( + model_name='lesion', + name='sub_location', + field=models.ForeignKey(to='ck.SubLocation'), + preserve_default=True, + ), + migrations.AddField( + model_name='lesion', + name='treatment', + field=models.ForeignKey(to='ck.Treatment'), + preserve_default=True, + ), + migrations.AddField( + model_name='followup', + name='patient', + field=models.ForeignKey(to='ck.Patient'), + preserve_default=True, + ), + migrations.AddField( + model_name='electronicmedicalreport', + name='patient', + field=models.ForeignKey(to='ck.Patient'), + preserve_default=True, + ), + ] diff --git a/mysite/ck/migrations.bak/0002_auto_20160113_0821.py b/mysite/ck/migrations.bak/0002_auto_20160113_0821.py new file mode 100755 index 0000000..fe48e92 --- /dev/null +++ b/mysite/ck/migrations.bak/0002_auto_20160113_0821.py @@ -0,0 +1,39 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import models, migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('ck', '0001_initial'), + ] + + operations = [ + migrations.CreateModel( + name='ICD10CMfinal', + fields=[ + ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ('ICD9CM_code', models.CharField(max_length=255, verbose_name='ICD-9-CM\u4ee3\u78bc', db_column='ICD-9-CM\u4ee3\u78bc')), + ('ICD9CM_English', models.CharField(max_length=255, verbose_name='ICD-9-CM\u82f1\u6587\u540d\u7a31', db_column='ICD-9-CM\u82f1\u6587\u540d\u7a31')), + ('ICD9CM_Chinese', models.CharField(max_length=255, verbose_name='ICD-9-CM\u4e2d\u6587\u540d\u7a31', db_column='ICD-9-CM\u4e2d\u6587\u540d\u7a31')), + ('ICD10CM', models.CharField(max_length=255, verbose_name='ICD-10-CM', db_column='ICD-10-CM')), + ('ICD10CM_English', models.CharField(max_length=255, verbose_name='ICD-10-CM\u82f1\u6587\u540d\u7a31', db_column='ICD-10-CM\u82f1\u6587\u540d\u7a31')), + ('ICD10CM_Chinese', models.CharField(max_length=255, verbose_name='ICD-10-CM\u4e2d\u6587\u540d\u7a31', db_column='ICD-10-CM\u4e2d\u6587\u540d\u7a31')), + ('Corresponding', models.CharField(max_length=255, verbose_name='\u5c0d\u61c9\u60c5\u5f62', db_column='\u5c0d\u61c9\u60c5\u5f62')), + ], + options={ + 'db_table': 'ICD10CMfinal', + }, + ), + migrations.AlterModelOptions( + name='price', + options={'ordering': ['code', 'identity', 'name']}, + ), + migrations.AddField( + model_name='treatment', + name='icd10cm', + field=models.ForeignKey(verbose_name=b'ICD-10-CM', blank=True, to='ck.ICD10CMfinal', null=True), + ), + ] diff --git a/mysite/ck/migrations.bak/0003_auto_20160113_0830.py b/mysite/ck/migrations.bak/0003_auto_20160113_0830.py new file mode 100755 index 0000000..30eb3c8 --- /dev/null +++ b/mysite/ck/migrations.bak/0003_auto_20160113_0830.py @@ -0,0 +1,18 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import models, migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('ck', '0002_auto_20160113_0821'), + ] + + operations = [ + migrations.AlterModelOptions( + name='icd10cmfinal', + options={'managed': False}, + ), + ] diff --git a/mysite/ck/migrations.bak/0004_remove_treatment_icd10cm.py b/mysite/ck/migrations.bak/0004_remove_treatment_icd10cm.py new file mode 100755 index 0000000..85b47a2 --- /dev/null +++ b/mysite/ck/migrations.bak/0004_remove_treatment_icd10cm.py @@ -0,0 +1,18 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('ck', '0003_auto_20160113_0830'), + ] + + operations = [ + migrations.RemoveField( + model_name='treatment', + name='icd10cm', + ), + ] diff --git a/mysite/ck/migrations.bak/0005_treatment_icd10cm.py b/mysite/ck/migrations.bak/0005_treatment_icd10cm.py new file mode 100755 index 0000000..de964f1 --- /dev/null +++ b/mysite/ck/migrations.bak/0005_treatment_icd10cm.py @@ -0,0 +1,19 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('ck', '0004_remove_treatment_icd10cm'), + ] + + operations = [ + migrations.AddField( + model_name='treatment', + name='icd10cm', + field=models.ForeignKey(verbose_name=b'ICD-10-CM', blank=True, to='ck.ICD10CMfinal', null=True), + ), + ] diff --git a/mysite/ck/migrations.bak/0006_auto_20160114_0438.py b/mysite/ck/migrations.bak/0006_auto_20160114_0438.py new file mode 100755 index 0000000..3d15c02 --- /dev/null +++ b/mysite/ck/migrations.bak/0006_auto_20160114_0438.py @@ -0,0 +1,18 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('ck', '0005_treatment_icd10cm'), + ] + + operations = [ + migrations.AlterModelOptions( + name='icd10cmfinal', + options={}, + ), + ] diff --git a/mysite/ck/migrations.bak/0007_auto_20160114_0512.py b/mysite/ck/migrations.bak/0007_auto_20160114_0512.py new file mode 100755 index 0000000..e6db7db --- /dev/null +++ b/mysite/ck/migrations.bak/0007_auto_20160114_0512.py @@ -0,0 +1,18 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('ck', '0006_auto_20160114_0438'), + ] + + operations = [ + migrations.AlterModelOptions( + name='icd10cmfinal', + options={'managed': False}, + ), + ] diff --git a/mysite/ck/migrations.bak/0008_remove_treatment_icd10cm.py b/mysite/ck/migrations.bak/0008_remove_treatment_icd10cm.py new file mode 100755 index 0000000..21f2bda --- /dev/null +++ b/mysite/ck/migrations.bak/0008_remove_treatment_icd10cm.py @@ -0,0 +1,18 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('ck', '0007_auto_20160114_0512'), + ] + + operations = [ + migrations.RemoveField( + model_name='treatment', + name='icd10cm', + ), + ] diff --git a/mysite/ck/migrations.bak/0009_treatment_icd10cm.py b/mysite/ck/migrations.bak/0009_treatment_icd10cm.py new file mode 100755 index 0000000..35ecad0 --- /dev/null +++ b/mysite/ck/migrations.bak/0009_treatment_icd10cm.py @@ -0,0 +1,19 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('ck', '0008_remove_treatment_icd10cm'), + ] + + operations = [ + migrations.AddField( + model_name='treatment', + name='icd10cm', + field=models.ForeignKey(verbose_name=b'ICD-10-CM', blank=True, to='ck.ICD10CMfinal', null=True), + ), + ] diff --git a/mysite/ck/migrations.bak/0010_auto_20160114_0544.py b/mysite/ck/migrations.bak/0010_auto_20160114_0544.py new file mode 100755 index 0000000..c86fc5a --- /dev/null +++ b/mysite/ck/migrations.bak/0010_auto_20160114_0544.py @@ -0,0 +1,18 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('ck', '0009_treatment_icd10cm'), + ] + + operations = [ + migrations.AlterModelOptions( + name='icd10cmfinal', + options={}, + ), + ] diff --git a/mysite/ck/migrations.bak/0011_auto_20160114_0544.py b/mysite/ck/migrations.bak/0011_auto_20160114_0544.py new file mode 100755 index 0000000..bffadce --- /dev/null +++ b/mysite/ck/migrations.bak/0011_auto_20160114_0544.py @@ -0,0 +1,27 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('ck', '0010_auto_20160114_0544'), + ] + + operations = [ + migrations.RemoveField( + model_name='icd10cmfinal', + name='id', + ), + migrations.RemoveField( + model_name='treatment', + name='icd10cm', + ), + migrations.AlterField( + model_name='icd10cmfinal', + name='ICD10CM', + field=models.CharField(max_length=8, serialize=False, verbose_name='ICD-10-CM', primary_key=True, db_column='ICD-10-CM'), + ), + ] diff --git a/mysite/ck/migrations.bak/0012_treatment_icd10cm.py b/mysite/ck/migrations.bak/0012_treatment_icd10cm.py new file mode 100755 index 0000000..137963e --- /dev/null +++ b/mysite/ck/migrations.bak/0012_treatment_icd10cm.py @@ -0,0 +1,19 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('ck', '0011_auto_20160114_0544'), + ] + + operations = [ + migrations.AddField( + model_name='treatment', + name='icd10cm', + field=models.ForeignKey(verbose_name=b'ICD-10-CM', blank=True, to='ck.ICD10CMfinal', null=True), + ), + ] diff --git a/mysite/ck/migrations.bak/0013_auto_20160114_0555.py b/mysite/ck/migrations.bak/0013_auto_20160114_0555.py new file mode 100755 index 0000000..c4766bb --- /dev/null +++ b/mysite/ck/migrations.bak/0013_auto_20160114_0555.py @@ -0,0 +1,19 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('ck', '0012_treatment_icd10cm'), + ] + + operations = [ + migrations.AlterField( + model_name='icd10cmfinal', + name='ICD10CM', + field=models.CharField(max_length=8, serialize=False, verbose_name='ICD10CM', primary_key=True, db_column='ICD-10-CM'), + ), + ] diff --git a/mysite/ck/migrations.bak/0014_auto_20160114_0556.py b/mysite/ck/migrations.bak/0014_auto_20160114_0556.py new file mode 100755 index 0000000..d157950 --- /dev/null +++ b/mysite/ck/migrations.bak/0014_auto_20160114_0556.py @@ -0,0 +1,19 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('ck', '0013_auto_20160114_0555'), + ] + + operations = [ + migrations.AlterField( + model_name='icd10cmfinal', + name='ICD10CM', + field=models.CharField(max_length=8, serialize=False, verbose_name='ICD-10-CM', primary_key=True, db_column='ICD10CM'), + ), + ] diff --git a/mysite/ck/migrations.bak/0015_auto_20160114_0729.py b/mysite/ck/migrations.bak/0015_auto_20160114_0729.py new file mode 100755 index 0000000..046242b --- /dev/null +++ b/mysite/ck/migrations.bak/0015_auto_20160114_0729.py @@ -0,0 +1,18 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('ck', '0014_auto_20160114_0556'), + ] + + operations = [ + migrations.AlterModelOptions( + name='icd10cmfinal', + options={'managed': False}, + ), + ] diff --git a/mysite/ck/migrations.bak/0016_auto_20190102_0835.py b/mysite/ck/migrations.bak/0016_auto_20190102_0835.py new file mode 100644 index 0000000..794456e --- /dev/null +++ b/mysite/ck/migrations.bak/0016_auto_20190102_0835.py @@ -0,0 +1,36 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.6 on 2019-01-02 08:35 +from __future__ import unicode_literals + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('ck', '0015_auto_20160114_0729'), + ] + + operations = [ + migrations.AddField( + model_name='vevent', + name='mode_remark', + field=models.CharField(blank=True, max_length=200, null=True), + ), + migrations.AlterField( + model_name='treatmentresponse', + name='treatment', + field=models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, primary_key=True, serialize=False, to='ck.Treatment'), + ), + migrations.AlterField( + model_name='vevent', + name='mode', + field=models.IntegerField(choices=[(110, b'Fiducial'), (200, b'\xe5\x9b\xba\xe5\xae\x9a\xe5\x99\xa8'), (210, b'CT'), (220, b'MRI'), (230, b'Angio'), (300, b'\xe9\xa0\x90\xe6\x8e\x92'), (310, b'\xe6\xb2\xbb\xe7\x99\x82')]), + ), + migrations.AlterField( + model_name='xraytextreport', + name='report_key', + field=models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, primary_key=True, serialize=False, to='ck.ElectronicMedicalReport'), + ), + ] diff --git a/mysite/ck/migrations.bak/__init__.py b/mysite/ck/migrations.bak/__init__.py new file mode 100755 index 0000000..e69de29 diff --git a/mysite/ck/migrations/0001_initial.py b/mysite/ck/migrations/0001_initial.py new file mode 100644 index 0000000..e2e97e6 --- /dev/null +++ b/mysite/ck/migrations/0001_initial.py @@ -0,0 +1,404 @@ +# Generated by Django 3.1.5 on 2021-02-24 09:13 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ] + + operations = [ + migrations.CreateModel( + name='ICD10CMfinal', + fields=[ + ('ICD9CM_code', models.CharField(db_column='ICD-9-CM代碼', max_length=255, verbose_name='ICD-9-CM代碼')), + ('ICD9CM_English', models.CharField(db_column='ICD-9-CM英文å稱', max_length=255, verbose_name='ICD-9-CM英文å稱')), + ('ICD9CM_Chinese', models.CharField(db_column='ICD-9-CM中文å稱', max_length=255, verbose_name='ICD-9-CM中文å稱')), + ('ICD10CM', models.CharField(db_column='ICD10CM', max_length=8, primary_key=True, serialize=False, verbose_name='ICD-10-CM')), + ('ICD10CM_English', models.CharField(db_column='ICD-10-CM英文å稱', max_length=255, verbose_name='ICD-10-CM英文å稱')), + ('ICD10CM_Chinese', models.CharField(db_column='ICD-10-CM中文å稱', max_length=255, verbose_name='ICD-10-CM中文å稱')), + ('Corresponding', models.CharField(db_column='å°æ‡‰æƒ…å½¢', max_length=255, verbose_name='å°æ‡‰æƒ…å½¢')), + ], + options={ + 'db_table': 'ICD10CMfinal', + 'managed': False, + }, + ), + migrations.CreateModel( + name='Activity', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('title', models.CharField(max_length=200)), + ], + ), + migrations.CreateModel( + name='DiseaseStage', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('stage', models.CharField(max_length=200)), + ], + ), + migrations.CreateModel( + name='ElectronicMedicalReport', + fields=[ + ('report_key', models.CharField(max_length=200, primary_key=True, serialize=False)), + ('report_class', models.CharField(max_length=200)), + ('check_date', models.DateField(null=True)), + ('report_date', models.DateField(null=True)), + ('report_code', models.CharField(max_length=200)), + ('report', models.TextField(null=True)), + ('saved', models.DateField(auto_now=True)), + ], + ), + migrations.CreateModel( + name='ICD9Diag', + fields=[ + ('code', models.CharField(max_length=5, primary_key=True, serialize=False)), + ('desc', models.CharField(max_length=50)), + ], + ), + migrations.CreateModel( + name='Lesion', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('dimensions', models.CharField(max_length=200)), + ('volume', models.DecimalField(decimal_places=2, max_digits=9)), + ('plan_name', models.CharField(blank=True, max_length=200, null=True)), + ('collimator', models.CharField(max_length=200)), + ('path_no', models.IntegerField()), + ('beam_no', models.IntegerField()), + ('mu_max', models.DecimalField(decimal_places=2, max_digits=9)), + ('mu_min', models.DecimalField(decimal_places=2, max_digits=9)), + ('dose', models.IntegerField()), + ('fractions', models.IntegerField()), + ('iso_dose_curve', models.IntegerField()), + ('dmin', models.DecimalField(decimal_places=2, max_digits=9)), + ('dmax', models.DecimalField(decimal_places=2, max_digits=9)), + ('coverage', models.DecimalField(decimal_places=2, max_digits=9)), + ('ci', models.DecimalField(decimal_places=2, max_digits=9)), + ('nci', models.DecimalField(decimal_places=2, max_digits=9)), + ('start_date', models.DateField(blank=True, null=True)), + ('end_date', models.DateField(blank=True, null=True)), + ('memo', models.CharField(blank=True, max_length=200, null=True)), + ], + ), + migrations.CreateModel( + name='NHIOrder', + fields=[ + ('id', models.CharField(max_length=20, primary_key=True, serialize=False)), + ('ChartNo', models.CharField(max_length=10)), + ('PatientName', models.CharField(max_length=10)), + ('ApplyTypeDesc', models.CharField(max_length=10)), + ('StatusDesc', models.CharField(max_length=10)), + ('NhiDeptName', models.CharField(max_length=10)), + ('PackageTime', models.CharField(max_length=10)), + ('OrderCode', models.CharField(max_length=10)), + ('OrderName', models.CharField(max_length=10)), + ('ResultDesc', models.CharField(max_length=10)), + ('Quantity', models.CharField(max_length=10)), + ('ExamineQuantity', models.CharField(max_length=10)), + ('ExamineDate', models.CharField(max_length=10)), + ], + ), + migrations.CreateModel( + name='Oncologist', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=200)), + ], + ), + migrations.CreateModel( + name='Pathology', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('pathology', models.CharField(max_length=200, unique=True)), + ('stage', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='ck.diseasestage')), + ], + ), + migrations.CreateModel( + name='Patient', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=200, verbose_name='å§“å')), + ('medical_records', models.CharField(max_length=200, unique=True)), + ('gender', models.IntegerField(choices=[(1, 'Male'), (2, 'Female')])), + ('birthday', models.DateField()), + ('address', models.CharField(max_length=200)), + ('phone', models.CharField(max_length=200)), + ('id_cards', models.CharField(max_length=200, unique=True)), + ('memo', models.CharField(blank=True, max_length=200, null=True)), + ('dead', models.DateField(blank=True, null=True)), + ('height', models.DecimalField(decimal_places=1, max_digits=4, null=True)), + ('weight', models.DecimalField(decimal_places=3, max_digits=6, null=True)), + ('native', models.CharField(blank=True, max_length=200, null=True)), + ('past_and_family_history', models.TextField(blank=True, null=True)), + ('timestamp', models.DateTimeField(auto_now=True)), + ], + ), + migrations.CreateModel( + name='Price', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('code', models.CharField(blank=True, max_length=200, null=True)), + ('identity', models.IntegerField(choices=[(10, 'å¥ä¿'), (20, '自費'), (30, 'å…§å«')])), + ('name', models.CharField(max_length=200)), + ('unit', models.CharField(blank=True, max_length=200, null=True)), + ('address', models.IntegerField(blank=True, null=True)), + ], + options={ + 'ordering': ['code', 'identity', 'name'], + }, + ), + migrations.CreateModel( + name='PrimaryTumorSite', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('site', models.CharField(max_length=200)), + ], + ), + migrations.CreateModel( + name='Surgeon', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=200)), + ], + ), + migrations.CreateModel( + name='TargetLocation', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('location', models.CharField(max_length=200)), + ], + ), + migrations.CreateModel( + name='Treatment', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('bed', models.CharField(blank=True, max_length=200, null=True, verbose_name='病床號')), + ('other_diagnosis', models.CharField(blank=True, max_length=200, null=True, verbose_name='其他診斷')), + ('tracking_mode', models.IntegerField(blank=True, choices=[(100, '6D Skull'), (200, 'Xsight-Spine'), (210, 'Xsight-Lung'), (300, 'Fiducial'), (400, 'Synchrony')], null=True)), + ('referral', models.CharField(blank=True, max_length=200, null=True, verbose_name='轉介醫師')), + ('date_started', models.DateField(blank=True, null=True)), + ('date_completed', models.DateField(blank=True, null=True)), + ('accounting', models.IntegerField(blank=True, choices=[(10, 'å¥ä¿'), (20, '自費'), (30, 'å…§å«')], null=True, verbose_name='記帳別')), + ('karnofsky_score', models.IntegerField(blank=True, choices=[(100, '100% - normal, no complaints, no signs of disease'), (90, ' 90% - capable of normal activity, few symptoms or signs of disease'), (80, ' 80% - normal activity with some difficulty, some symptoms or signs'), (70, ' 70% - caring for self, not capable of normal activity or work'), (60, ' 60% - requiring some help, can take care of most personal requirements'), (50, ' 50% - requires help often, requires frequent medical care'), (40, ' 40% - disabled, requires special care and help'), (30, ' 30% - severely disabled, hospital admission indicated but no risk of death'), (20, ' 20% - very ill, urgently requiring admission, requires supportive measures or treatment'), (10, ' 10% - moribund, rapidly progressive fatal disease processes'), (0, ' 0% - death')], null=True)), + ('complications', models.CharField(blank=True, max_length=200, null=True, verbose_name='併發症')), + ('chief_complaint', models.TextField(blank=True, null=True)), + ('memo', models.CharField(blank=True, max_length=200, null=True)), + ('timestamp', models.DateTimeField(auto_now=True)), + ('disease_stage', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='ck.diseasestage')), + ('icd10cm', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='ck.icd10cmfinal', verbose_name='ICD-10-CM')), + ('icd9', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='ck.icd9diag', verbose_name='ICD9診斷')), + ('input', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='input', to='ck.activity', verbose_name='å·²')), + ('oncologist', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='ck.oncologist')), + ('output', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='output', to='ck.activity', verbose_name='å¾…')), + ('patient', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='ck.patient')), + ('primary_tumor_site', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='ck.primarytumorsite')), + ('surgeon', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='ck.surgeon')), + ], + ), + migrations.CreateModel( + name='TreatmentResponse', + fields=[ + ('treatment', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, primary_key=True, serialize=False, to='ck.treatment')), + ('time', models.DateField(null=True)), + ('event', models.NullBooleanField()), + ('time1y', models.DateField(null=True)), + ('event1y', models.NullBooleanField()), + ], + ), + migrations.CreateModel( + name='XrayTextReport', + fields=[ + ('report_key', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, primary_key=True, serialize=False, to='ck.electronicmedicalreport')), + ('old_access_no', models.CharField(max_length=200, null=True)), + ('ioe', models.CharField(max_length=200, null=True)), + ('refer_dept', models.CharField(max_length=200, null=True)), + ('status', models.CharField(max_length=200, null=True)), + ('formal_version', models.CharField(max_length=200, null=True)), + ('exam_date', models.DateField(null=True)), + ('order_desc', models.CharField(max_length=200, null=True)), + ('clean_html', models.TextField(null=True)), + ('response', models.CharField(max_length=200, null=True)), + ], + ), + migrations.CreateModel( + name='VEVENT', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('DTSTAMP', models.DateTimeField(auto_now=True)), + ('DTSTART', models.DateTimeField()), + ('DTEND', models.TimeField(blank=True)), + ('DURATION', models.TimeField()), + ('SUMMARY', models.CharField(blank=True, max_length=200, null=True)), + ('CLASS', models.CharField(blank=True, max_length=200, null=True)), + ('CATEGORIES', models.CharField(blank=True, max_length=200, null=True)), + ('TRANSP', models.CharField(blank=True, max_length=200, null=True)), + ('RRULE', models.CharField(blank=True, max_length=200, null=True)), + ('DESCRIPTION', models.CharField(blank=True, max_length=200, null=True)), + ('mode', models.IntegerField(choices=[(110, 'Fiducial'), (200, '固定器'), (210, 'CT'), (215, 'RT-CT'), (220, 'MRI'), (230, 'Angio'), (300, '頿ޒ'), (310, '治療')])), + ('mode_remark', models.CharField(blank=True, max_length=200, null=True)), + ('break_frequency', models.IntegerField(blank=True)), + ('system_err', models.IntegerField(blank=True)), + ('shift', models.IntegerField(blank=True)), + ('cone', models.IntegerField(blank=True)), + ('path', models.IntegerField(blank=True)), + ('price', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='ck.price')), + ('treatment', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='ck.treatment')), + ], + ), + migrations.CreateModel( + name='SubLocation', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('group', models.IntegerField()), + ('sub_location', models.CharField(max_length=200)), + ('pathology', models.ManyToManyField(to='ck.Pathology')), + ('target_location', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='ck.targetlocation')), + ], + ), + migrations.CreateModel( + name='PriorTreatment', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('date', models.DateField()), + ('treatment', models.IntegerField(choices=[(1, 'Surgery'), (2, 'Biopsy'), (3, 'RT'), (4, 'Radiosurgery'), (5, 'Chemotherapy')])), + ('period', models.IntegerField(blank=True, choices=[(1, 'Before'), (2, 'Concurrent'), (3, 'None')], null=True)), + ('dose', models.IntegerField(blank=True, null=True)), + ('memo', models.CharField(blank=True, max_length=200, null=True)), + ('patient', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='ck.patient')), + ], + ), + migrations.CreateModel( + name='PatientMedicalRecord', + fields=[ + ('key_code', models.CharField(max_length=200, primary_key=True, serialize=False)), + ('key_name', models.CharField(max_length=200)), + ('hosp_name', models.CharField(max_length=200, null=True)), + ('dept_name', models.CharField(max_length=200, null=True, verbose_name='ç§‘')), + ('in_date', models.DateField(null=True, verbose_name='å…¥')), + ('out_date', models.DateField(null=True, verbose_name='出')), + ('ward_name', models.CharField(max_length=200, null=True, verbose_name='房')), + ('room_name', models.CharField(max_length=200, null=True, verbose_name='室')), + ('bed_name', models.CharField(max_length=200, null=True, verbose_name='床')), + ('come_clinic_date', models.DateField(null=True, verbose_name='掛號日')), + ('discharge_date', models.DateField(null=True, verbose_name='離部日')), + ('special_cure_name', models.CharField(max_length=200, null=True, verbose_name='行為')), + ('main_dr_name', models.CharField(max_length=200, null=True, verbose_name='主治')), + ('main_diagnosis_name', models.CharField(max_length=200, null=True, verbose_name='診斷')), + ('status_name', models.CharField(max_length=200, null=True, verbose_name='狀態')), + ('temp_bed_id', models.CharField(max_length=200, null=True, verbose_name='床')), + ('account_status_name', models.CharField(max_length=200, null=True, verbose_name='狀態')), + ('func', models.CharField(max_length=200, null=True)), + ('doc', models.TextField(null=True, verbose_name='摘')), + ('saved', models.DateField(auto_now=True)), + ('patient', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='ck.patient')), + ], + ), + migrations.CreateModel( + name='PathExam', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('path_code', models.CharField(max_length=200, unique=True, verbose_name='ç—…ç†è™Ÿ')), + ('specimen_code', models.CharField(max_length=200, verbose_name='檢體')), + ('specimen_get_date', models.DateField(verbose_name='æ”¶ä»¶æ—¥')), + ('report_date', models.DateField(verbose_name='報告日')), + ('division', models.CharField(max_length=200, verbose_name='科別')), + ('bed', models.CharField(blank=True, max_length=200, null=True, verbose_name='病床')), + ('report', models.TextField(blank=True, null=True, verbose_name='檢查報告')), + ('patient', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='ck.patient')), + ], + ), + migrations.CreateModel( + name='PACSImage', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('PatChartNo', models.CharField(max_length=200, verbose_name='病歷號')), + ('RequestSheetNo', models.CharField(max_length=200, verbose_name='單號')), + ('ExamDate', models.DateField(verbose_name='檢查日')), + ('LinkOrderName', models.CharField(max_length=200, verbose_name='檢查å稱')), + ('Modality', models.CharField(max_length=200, verbose_name='儀器')), + ('VerifiedStateString', models.CharField(max_length=200, verbose_name='狀態')), + ('Exam', models.TextField(null=True, verbose_name='報告內容')), + ('Impression', models.TextField(null=True)), + ('Report', models.TextField(null=True, verbose_name='報告')), + ('Saved', models.IntegerField(choices=[(0, '待處ç†'), (10, '有輸入'), (15, '已確èª'), (20, 'ä¸é©ç”¨')], verbose_name='ä¿å­˜')), + ('patient', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='ck.patient')), + ], + ), + migrations.CreateModel( + name='OPNote', + fields=[ + ('key_code', models.CharField(max_length=200, primary_key=True, serialize=False)), + ('key_name', models.CharField(max_length=200)), + ('doc', models.TextField(null=True, verbose_name='摘')), + ('saved', models.DateField(auto_now=True)), + ('patient', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='ck.patient')), + ], + ), + migrations.CreateModel( + name='MedicalRecord', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('Record', models.CharField(max_length=200, null=True)), + ('HospName', models.CharField(max_length=200, null=True)), + ('DeptName', models.CharField(max_length=200, null=True, verbose_name='ç§‘')), + ('InDate', models.DateField(verbose_name='å…¥')), + ('OutDate', models.DateField(null=True, verbose_name='出')), + ('WardName', models.CharField(max_length=200, null=True, verbose_name='房')), + ('RoomName', models.CharField(max_length=200, null=True, verbose_name='室')), + ('BedName', models.CharField(max_length=200, null=True, verbose_name='床')), + ('MainDrName', models.CharField(max_length=200, null=True, verbose_name='主治')), + ('MainDiagnosisName', models.CharField(max_length=200, null=True, verbose_name='診斷')), + ('StatusName', models.CharField(max_length=200, null=True, verbose_name='狀態')), + ('SpecialCureName', models.CharField(max_length=200, null=True, verbose_name='行為')), + ('patient', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='ck.patient')), + ], + ), + migrations.CreateModel( + name='LesionFollow', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('Date', models.DateField(verbose_name='追蹤日期')), + ('Volume', models.FloatField(null=True, verbose_name='é«”ç©(mm3)')), + ('A', models.FloatField(null=True, verbose_name='é•·(mm)')), + ('B', models.FloatField(null=True, verbose_name='寬(mm)')), + ('C', models.FloatField(null=True, verbose_name='高(mm)')), + ('Memo', models.CharField(blank=True, max_length=200, null=True)), + ('Lesion', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='ck.lesion')), + ], + ), + migrations.AddField( + model_name='lesion', + name='pathology', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='ck.pathology'), + ), + migrations.AddField( + model_name='lesion', + name='sub_location', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='ck.sublocation'), + ), + migrations.AddField( + model_name='lesion', + name='treatment', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='ck.treatment'), + ), + migrations.CreateModel( + name='Followup', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('date', models.DateField()), + ('memo', models.CharField(blank=True, max_length=200, null=True)), + ('patient', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='ck.patient')), + ], + ), + migrations.AddField( + model_name='electronicmedicalreport', + name='patient', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='ck.patient'), + ), + ] diff --git a/mysite/ck/migrations/0002_auto_20210224_0919.py b/mysite/ck/migrations/0002_auto_20210224_0919.py new file mode 100644 index 0000000..30c52b0 --- /dev/null +++ b/mysite/ck/migrations/0002_auto_20210224_0919.py @@ -0,0 +1,18 @@ +# Generated by Django 3.1.5 on 2021-02-24 09:19 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('ck', '0001_initial'), + ] + + operations = [ + migrations.AlterField( + model_name='nhiorder', + name='OrderName', + field=models.CharField(max_length=20), + ), + ] diff --git a/mysite/ck/migrations/0003_auto_20210224_0920.py b/mysite/ck/migrations/0003_auto_20210224_0920.py new file mode 100644 index 0000000..7f459c6 --- /dev/null +++ b/mysite/ck/migrations/0003_auto_20210224_0920.py @@ -0,0 +1,18 @@ +# Generated by Django 3.1.5 on 2021-02-24 09:20 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('ck', '0002_auto_20210224_0919'), + ] + + operations = [ + migrations.AlterField( + model_name='nhiorder', + name='Quantity', + field=models.CharField(max_length=10, null=True), + ), + ] diff --git a/mysite/ck/migrations/0004_auto_20210224_0921.py b/mysite/ck/migrations/0004_auto_20210224_0921.py new file mode 100644 index 0000000..62ce49e --- /dev/null +++ b/mysite/ck/migrations/0004_auto_20210224_0921.py @@ -0,0 +1,18 @@ +# Generated by Django 3.1.5 on 2021-02-24 09:21 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('ck', '0003_auto_20210224_0920'), + ] + + operations = [ + migrations.AlterField( + model_name='nhiorder', + name='ExamineDate', + field=models.CharField(max_length=10, null=True), + ), + ] diff --git a/mysite/ck/migrations/0005_auto_20210224_0922.py b/mysite/ck/migrations/0005_auto_20210224_0922.py new file mode 100644 index 0000000..58779c3 --- /dev/null +++ b/mysite/ck/migrations/0005_auto_20210224_0922.py @@ -0,0 +1,18 @@ +# Generated by Django 3.1.5 on 2021-02-24 09:22 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('ck', '0004_auto_20210224_0921'), + ] + + operations = [ + migrations.AlterField( + model_name='nhiorder', + name='PatientName', + field=models.CharField(max_length=20), + ), + ] diff --git a/mysite/ck/migrations/0006_auto_20210224_1038.py b/mysite/ck/migrations/0006_auto_20210224_1038.py new file mode 100644 index 0000000..8d95012 --- /dev/null +++ b/mysite/ck/migrations/0006_auto_20210224_1038.py @@ -0,0 +1,78 @@ +# Generated by Django 3.1.5 on 2021-02-24 10:38 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('ck', '0005_auto_20210224_0922'), + ] + + operations = [ + migrations.AddField( + model_name='nhiorder', + name='ApplyDoctor', + field=models.CharField(max_length=10, null=True, verbose_name='申請醫師'), + ), + migrations.AlterField( + model_name='nhiorder', + name='ApplyTypeDesc', + field=models.CharField(max_length=10, verbose_name='申請類別'), + ), + migrations.AlterField( + model_name='nhiorder', + name='ChartNo', + field=models.CharField(max_length=10, verbose_name='病歷號'), + ), + migrations.AlterField( + model_name='nhiorder', + name='ExamineDate', + field=models.CharField(max_length=10, null=True, verbose_name='核定日期'), + ), + migrations.AlterField( + model_name='nhiorder', + name='ExamineQuantity', + field=models.CharField(max_length=10, verbose_name='核定數é‡'), + ), + migrations.AlterField( + model_name='nhiorder', + name='NhiDeptName', + field=models.CharField(max_length=10, verbose_name='科別'), + ), + migrations.AlterField( + model_name='nhiorder', + name='OrderCode', + field=models.CharField(max_length=10, verbose_name='申請項目'), + ), + migrations.AlterField( + model_name='nhiorder', + name='OrderName', + field=models.CharField(max_length=20, verbose_name='é …ç›®å稱'), + ), + migrations.AlterField( + model_name='nhiorder', + name='PackageTime', + field=models.CharField(max_length=10, verbose_name='逿¡ˆæ—¥æœŸ'), + ), + migrations.AlterField( + model_name='nhiorder', + name='PatientName', + field=models.CharField(max_length=20, verbose_name='病患姓å'), + ), + migrations.AlterField( + model_name='nhiorder', + name='Quantity', + field=models.CharField(max_length=10, null=True, verbose_name='æ ¸å®šçµæžœ'), + ), + migrations.AlterField( + model_name='nhiorder', + name='ResultDesc', + field=models.CharField(max_length=10, verbose_name='申請數é‡'), + ), + migrations.AlterField( + model_name='nhiorder', + name='StatusDesc', + field=models.CharField(max_length=10, verbose_name='案件狀態'), + ), + ] diff --git a/mysite/ck/migrations/0007_auto_20210224_1134.py b/mysite/ck/migrations/0007_auto_20210224_1134.py new file mode 100644 index 0000000..00b955b --- /dev/null +++ b/mysite/ck/migrations/0007_auto_20210224_1134.py @@ -0,0 +1,25 @@ +# Generated by Django 3.1.5 on 2021-02-24 11:34 + +from django.db import migrations, models +import django.utils.timezone + + +class Migration(migrations.Migration): + + dependencies = [ + ('ck', '0006_auto_20210224_1038'), + ] + + operations = [ + migrations.AddField( + model_name='nhiorder', + name='timestamp', + field=models.DateTimeField(auto_now_add=True, default=django.utils.timezone.now), + preserve_default=False, + ), + migrations.AddField( + model_name='nhiorder', + name='updated', + field=models.DateTimeField(auto_now=True), + ), + ] diff --git a/mysite/ck/migrations/0008_auto_20210224_1139.py b/mysite/ck/migrations/0008_auto_20210224_1139.py new file mode 100644 index 0000000..62e4636 --- /dev/null +++ b/mysite/ck/migrations/0008_auto_20210224_1139.py @@ -0,0 +1,33 @@ +# Generated by Django 3.1.5 on 2021-02-24 11:39 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('ck', '0007_auto_20210224_1134'), + ] + + operations = [ + migrations.AlterField( + model_name='nhiorder', + name='ExamineDate', + field=models.DateField(null=True, verbose_name='核定日期'), + ), + migrations.AlterField( + model_name='nhiorder', + name='ExamineQuantity', + field=models.IntegerField(verbose_name='核定數é‡'), + ), + migrations.AlterField( + model_name='nhiorder', + name='PackageTime', + field=models.DateField(verbose_name='逿¡ˆæ—¥æœŸ'), + ), + migrations.AlterField( + model_name='nhiorder', + name='ResultDesc', + field=models.IntegerField(verbose_name='申請數é‡'), + ), + ] diff --git a/mysite/ck/migrations/0009_auto_20210226_0406.py b/mysite/ck/migrations/0009_auto_20210226_0406.py new file mode 100644 index 0000000..c8a3920 --- /dev/null +++ b/mysite/ck/migrations/0009_auto_20210226_0406.py @@ -0,0 +1,23 @@ +# Generated by Django 3.1.5 on 2021-02-26 04:06 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('ck', '0008_auto_20210224_1139'), + ] + + operations = [ + migrations.AlterField( + model_name='treatmentresponse', + name='event', + field=models.BooleanField(null=True), + ), + migrations.AlterField( + model_name='treatmentresponse', + name='event1y', + field=models.BooleanField(null=True), + ), + ] diff --git a/mysite/ck/migrations/0010_auto_20210226_0444.py b/mysite/ck/migrations/0010_auto_20210226_0444.py new file mode 100644 index 0000000..4b53c25 --- /dev/null +++ b/mysite/ck/migrations/0010_auto_20210226_0444.py @@ -0,0 +1,93 @@ +# Generated by Django 3.1.5 on 2021-02-26 04:44 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('ck', '0009_auto_20210226_0406'), + ] + + operations = [ + migrations.AddField( + model_name='nhiorder', + name='AnticancerMedicine', + field=models.CharField(max_length=10, null=True, verbose_name='抗癌藥物'), + ), + migrations.AddField( + model_name='nhiorder', + name='ApplyDate', + field=models.DateField(null=True, verbose_name='申請日期'), + ), + migrations.AddField( + model_name='nhiorder', + name='ApplyPart', + field=models.CharField(max_length=10, null=True, verbose_name='申請部ä½'), + ), + migrations.AddField( + model_name='nhiorder', + name='ApplyQty', + field=models.CharField(max_length=10, null=True, verbose_name='申請é‡'), + ), + migrations.AddField( + model_name='nhiorder', + name='ApplyType', + field=models.CharField(max_length=10, null=True, verbose_name='申請類別'), + ), + migrations.AddField( + model_name='nhiorder', + name='Diagnosis', + field=models.CharField(max_length=10, null=True, verbose_name='疾病分類號'), + ), + migrations.AddField( + model_name='nhiorder', + name='EmrDateStr', + field=models.CharField(max_length=10, null=True, verbose_name='緊急通報日'), + ), + migrations.AddField( + model_name='nhiorder', + name='ExamineDateStr', + field=models.CharField(max_length=10, null=True, verbose_name='核定日期'), + ), + migrations.AddField( + model_name='nhiorder', + name='ExamineReason1', + field=models.CharField(max_length=10, null=True, verbose_name='核定原因1'), + ), + migrations.AddField( + model_name='nhiorder', + name='ExamineReason2', + field=models.CharField(max_length=10, null=True, verbose_name='核定原因2'), + ), + migrations.AddField( + model_name='nhiorder', + name='ExamineReasonDesc', + field=models.CharField(max_length=10, null=True, verbose_name='核定原因說明'), + ), + migrations.AddField( + model_name='nhiorder', + name='NhiDept', + field=models.CharField(max_length=10, null=True, verbose_name='申請科別'), + ), + migrations.AddField( + model_name='nhiorder', + name='Phone', + field=models.CharField(max_length=10, null=True, verbose_name='è¯çµ¡åˆ†æ©Ÿ'), + ), + migrations.AddField( + model_name='nhiorder', + name='Reason', + field=models.CharField(max_length=10, null=True, verbose_name='申請原因'), + ), + migrations.AlterField( + model_name='nhiorder', + name='PackageTime', + field=models.DateField(null=True, verbose_name='逿¡ˆæ—¥æœŸ'), + ), + migrations.AlterField( + model_name='nhiorder', + name='ResultDesc', + field=models.CharField(max_length=10, null=True, verbose_name='æ ¸å®šçµæžœ'), + ), + ] diff --git a/mysite/ck/migrations/0011_auto_20210226_0445.py b/mysite/ck/migrations/0011_auto_20210226_0445.py new file mode 100644 index 0000000..07e30a3 --- /dev/null +++ b/mysite/ck/migrations/0011_auto_20210226_0445.py @@ -0,0 +1,18 @@ +# Generated by Django 3.1.5 on 2021-02-26 04:45 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('ck', '0010_auto_20210226_0444'), + ] + + operations = [ + migrations.AlterField( + model_name='nhiorder', + name='ResultDesc', + field=models.IntegerField(verbose_name='申請數é‡'), + ), + ] diff --git a/mysite/ck/migrations/0012_auto_20210226_0459.py b/mysite/ck/migrations/0012_auto_20210226_0459.py new file mode 100644 index 0000000..d607515 --- /dev/null +++ b/mysite/ck/migrations/0012_auto_20210226_0459.py @@ -0,0 +1,28 @@ +# Generated by Django 3.1.5 on 2021-02-26 04:59 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('ck', '0011_auto_20210226_0445'), + ] + + operations = [ + migrations.AddField( + model_name='nhiorder', + name='ErrorMsg', + field=models.CharField(max_length=10, null=True), + ), + migrations.AddField( + model_name='nhiorder', + name='Status', + field=models.CharField(max_length=10, null=True, verbose_name='ç›®å‰ç‹€æ…‹'), + ), + migrations.AddField( + model_name='nhiorder', + name='SuccessMsg', + field=models.CharField(max_length=10, null=True), + ), + ] diff --git a/mysite/ck/migrations/0013_auto_20210226_0513.py b/mysite/ck/migrations/0013_auto_20210226_0513.py new file mode 100644 index 0000000..9a40a13 --- /dev/null +++ b/mysite/ck/migrations/0013_auto_20210226_0513.py @@ -0,0 +1,23 @@ +# Generated by Django 3.1.5 on 2021-02-26 05:13 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('ck', '0012_auto_20210226_0459'), + ] + + operations = [ + migrations.AlterField( + model_name='nhiorder', + name='ApplyQty', + field=models.IntegerField(null=True, verbose_name='申請é‡'), + ), + migrations.AlterField( + model_name='nhiorder', + name='PackageTime', + field=models.DateField(verbose_name='逿¡ˆæ—¥æœŸ'), + ), + ] diff --git a/mysite/ck/migrations/0014_auto_20210226_1526.py b/mysite/ck/migrations/0014_auto_20210226_1526.py new file mode 100644 index 0000000..e9c57b7 --- /dev/null +++ b/mysite/ck/migrations/0014_auto_20210226_1526.py @@ -0,0 +1,18 @@ +# Generated by Django 3.1.5 on 2021-02-26 15:26 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('ck', '0013_auto_20210226_0513'), + ] + + operations = [ + migrations.AlterField( + model_name='nhiorder', + name='Reason', + field=models.TextField(null=True, verbose_name='申請原因'), + ), + ] diff --git a/mysite/ck/migrations/0015_auto_20210226_1534.py b/mysite/ck/migrations/0015_auto_20210226_1534.py new file mode 100644 index 0000000..b708c7b --- /dev/null +++ b/mysite/ck/migrations/0015_auto_20210226_1534.py @@ -0,0 +1,18 @@ +# Generated by Django 3.1.5 on 2021-02-26 15:34 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('ck', '0014_auto_20210226_1526'), + ] + + operations = [ + migrations.AlterField( + model_name='nhiorder', + name='ExamineReasonDesc', + field=models.TextField(null=True, verbose_name='核定原因說明'), + ), + ] diff --git a/mysite/ck/migrations/0016_nhiorder_maindrnames.py b/mysite/ck/migrations/0016_nhiorder_maindrnames.py new file mode 100644 index 0000000..31cb095 --- /dev/null +++ b/mysite/ck/migrations/0016_nhiorder_maindrnames.py @@ -0,0 +1,18 @@ +# Generated by Django 3.1.5 on 2021-02-26 23:13 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('ck', '0015_auto_20210226_1534'), + ] + + operations = [ + migrations.AddField( + model_name='nhiorder', + name='MainDrNames', + field=models.TextField(null=True, verbose_name='主治'), + ), + ] diff --git a/mysite/ck/migrations/0017_auto_20210226_2346.py b/mysite/ck/migrations/0017_auto_20210226_2346.py new file mode 100644 index 0000000..a43d4da --- /dev/null +++ b/mysite/ck/migrations/0017_auto_20210226_2346.py @@ -0,0 +1,18 @@ +# Generated by Django 3.1.5 on 2021-02-26 23:46 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('ck', '0016_nhiorder_maindrnames'), + ] + + operations = [ + migrations.RenameField( + model_name='nhiorder', + old_name='MainDrNames', + new_name='MainDrName', + ), + ] diff --git a/mysite/ck/migrations/0018_nhiorder_priority.py b/mysite/ck/migrations/0018_nhiorder_priority.py new file mode 100644 index 0000000..6e43116 --- /dev/null +++ b/mysite/ck/migrations/0018_nhiorder_priority.py @@ -0,0 +1,18 @@ +# Generated by Django 3.1.5 on 2021-02-27 08:28 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('ck', '0017_auto_20210226_2346'), + ] + + operations = [ + migrations.AddField( + model_name='nhiorder', + name='Priority', + field=models.IntegerField(null=True, verbose_name='優先'), + ), + ] diff --git a/mysite/ck/migrations/0019_nhiorder_memo.py b/mysite/ck/migrations/0019_nhiorder_memo.py new file mode 100644 index 0000000..d756ea5 --- /dev/null +++ b/mysite/ck/migrations/0019_nhiorder_memo.py @@ -0,0 +1,18 @@ +# Generated by Django 3.1.5 on 2021-03-09 15:58 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('ck', '0018_nhiorder_priority'), + ] + + operations = [ + migrations.AddField( + model_name='nhiorder', + name='Memo', + field=models.TextField(null=True, verbose_name='備忘'), + ), + ] diff --git a/mysite/ck/migrations/0020_auto_20210311_0908.py b/mysite/ck/migrations/0020_auto_20210311_0908.py new file mode 100644 index 0000000..b495e5f --- /dev/null +++ b/mysite/ck/migrations/0020_auto_20210311_0908.py @@ -0,0 +1,18 @@ +# Generated by Django 3.1.5 on 2021-03-11 09:08 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('ck', '0019_nhiorder_memo'), + ] + + operations = [ + migrations.AlterField( + model_name='nhiorder', + name='ExamineQuantity', + field=models.IntegerField(null=True, verbose_name='核定數é‡'), + ), + ] diff --git a/mysite/ck/migrations/0021_auto_20210315_0917.py b/mysite/ck/migrations/0021_auto_20210315_0917.py new file mode 100644 index 0000000..b32032e --- /dev/null +++ b/mysite/ck/migrations/0021_auto_20210315_0917.py @@ -0,0 +1,23 @@ +# Generated by Django 3.1.5 on 2021-03-15 09:17 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('ck', '0020_auto_20210311_0908'), + ] + + operations = [ + migrations.AddField( + model_name='nhiorder', + name='num_sessions', + field=models.IntegerField(null=True, verbose_name='é è¨ˆåˆ†æ¬¡'), + ), + migrations.AlterField( + model_name='nhiorder', + name='ResultDesc', + field=models.IntegerField(default=1, verbose_name='申請數é‡'), + ), + ] diff --git a/mysite/ck/migrations/0022_auto_20210317_1643.py b/mysite/ck/migrations/0022_auto_20210317_1643.py new file mode 100644 index 0000000..6d48b4a --- /dev/null +++ b/mysite/ck/migrations/0022_auto_20210317_1643.py @@ -0,0 +1,18 @@ +# Generated by Django 3.1.5 on 2021-03-17 08:43 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('ck', '0021_auto_20210315_0917'), + ] + + operations = [ + migrations.AlterField( + model_name='nhiorder', + name='num_sessions', + field=models.CharField(max_length=10, null=True, verbose_name='é è¨ˆåˆ†æ¬¡'), + ), + ] diff --git a/mysite/ck/migrations/0023_lesion_volume_measure.py b/mysite/ck/migrations/0023_lesion_volume_measure.py new file mode 100644 index 0000000..30aa1f7 --- /dev/null +++ b/mysite/ck/migrations/0023_lesion_volume_measure.py @@ -0,0 +1,20 @@ +# Generated by Django 3.1.5 on 2021-03-17 15:21 + +from django.db import migrations +import django_measurement.models +import measurement.measures.volume + + +class Migration(migrations.Migration): + + dependencies = [ + ('ck', '0022_auto_20210317_1643'), + ] + + operations = [ + migrations.AddField( + model_name='lesion', + name='volume_measure', + field=django_measurement.models.MeasurementField(measurement=measurement.measures.volume.Volume, null=True), + ), + ] diff --git a/mysite/ck/migrations/0024_auto_20210318_1142.py b/mysite/ck/migrations/0024_auto_20210318_1142.py new file mode 100644 index 0000000..c53a8d8 --- /dev/null +++ b/mysite/ck/migrations/0024_auto_20210318_1142.py @@ -0,0 +1,40 @@ +# Generated by Django 3.1.5 on 2021-03-18 03:42 + +from django.db import migrations, models +import django_measurement.models +import measurement.measures.volume + + +class Migration(migrations.Migration): + + dependencies = [ + ('ck', '0023_lesion_volume_measure'), + ] + + operations = [ + migrations.AlterField( + model_name='lesion', + name='iso_dose_curve', + field=models.DecimalField(decimal_places=1, max_digits=9), + ), + migrations.AlterField( + model_name='lesion', + name='mu_max', + field=models.DecimalField(decimal_places=2, max_digits=9, null=True), + ), + migrations.AlterField( + model_name='lesion', + name='mu_min', + field=models.DecimalField(decimal_places=2, max_digits=9, null=True), + ), + migrations.AlterField( + model_name='lesion', + name='volume', + field=models.DecimalField(decimal_places=2, max_digits=9, null=True, verbose_name='Target Volume(mm3)'), + ), + migrations.AlterField( + model_name='lesion', + name='volume_measure', + field=django_measurement.models.MeasurementField(measurement=measurement.measures.volume.Volume, null=True, verbose_name='Target Volume'), + ), + ] diff --git a/mysite/ck/migrations/0025_lesion_collimator_type.py b/mysite/ck/migrations/0025_lesion_collimator_type.py new file mode 100644 index 0000000..119c5b1 --- /dev/null +++ b/mysite/ck/migrations/0025_lesion_collimator_type.py @@ -0,0 +1,18 @@ +# Generated by Django 3.1.5 on 2021-03-18 03:57 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('ck', '0024_auto_20210318_1142'), + ] + + operations = [ + migrations.AddField( + model_name='lesion', + name='collimator_type', + field=models.IntegerField(choices=[(10, 'fixed'), (20, 'Iris'), (30, 'MLC')], default=10), + ), + ] diff --git a/mysite/ck/migrations/0026_auto_20210318_1243.py b/mysite/ck/migrations/0026_auto_20210318_1243.py new file mode 100644 index 0000000..ba31b65 --- /dev/null +++ b/mysite/ck/migrations/0026_auto_20210318_1243.py @@ -0,0 +1,23 @@ +# Generated by Django 3.1.5 on 2021-03-18 04:43 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('ck', '0025_lesion_collimator_type'), + ] + + operations = [ + migrations.AddField( + model_name='lesion', + name='dmean', + field=models.DecimalField(decimal_places=2, max_digits=9, null=True, verbose_name='Mean. dose(cGy)'), + ), + migrations.AlterField( + model_name='lesion', + name='collimator_type', + field=models.IntegerField(choices=[(10, 'fixed'), (20, 'Iris'), (30, 'MLC')], default=10, verbose_name='Collimator Type'), + ), + ] diff --git a/mysite/ck/migrations/0027_auto_20210324_1421.py b/mysite/ck/migrations/0027_auto_20210324_1421.py new file mode 100644 index 0000000..09b0bd1 --- /dev/null +++ b/mysite/ck/migrations/0027_auto_20210324_1421.py @@ -0,0 +1,38 @@ +# Generated by Django 3.1.5 on 2021-03-24 06:21 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('ck', '0026_auto_20210318_1243'), + ] + + operations = [ + migrations.AddField( + model_name='lesion', + name='calibration_table', + field=models.CharField(choices=[('GE', 'GE'), ('PHIA', 'Philips'), ('SIE', 'Siemens')], max_length=9, null=True, verbose_name='CT Calibration table'), + ), + migrations.AddField( + model_name='lesion', + name='density_correction', + field=models.BooleanField(null=True, verbose_name='å½±åƒå¯†åº¦ä¿®æ­£'), + ), + migrations.AlterField( + model_name='lesion', + name='dmean', + field=models.DecimalField(decimal_places=2, max_digits=9, null=True, verbose_name='Mean dose(cGy)'), + ), + migrations.AlterField( + model_name='lesion', + name='mu_max', + field=models.DecimalField(blank=True, decimal_places=2, max_digits=9, null=True), + ), + migrations.AlterField( + model_name='lesion', + name='mu_min', + field=models.DecimalField(blank=True, decimal_places=2, max_digits=9, null=True), + ), + ] diff --git a/mysite/ck/migrations/0028_treatment_creation.py b/mysite/ck/migrations/0028_treatment_creation.py new file mode 100644 index 0000000..ef809c7 --- /dev/null +++ b/mysite/ck/migrations/0028_treatment_creation.py @@ -0,0 +1,19 @@ +# Generated by Django 3.1.5 on 2021-03-24 10:37 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('ck', '0027_auto_20210324_1421'), + ] + + operations = [ + migrations.AddField( + model_name='treatment', + name='creation', + field=models.DateTimeField(auto_now_add=True, default='2020-05-21'), + preserve_default=False, + ), + ] diff --git a/mysite/ck/migrations/0029_icd10count.py b/mysite/ck/migrations/0029_icd10count.py new file mode 100644 index 0000000..cf20410 --- /dev/null +++ b/mysite/ck/migrations/0029_icd10count.py @@ -0,0 +1,21 @@ +# Generated by Django 3.1.5 on 2021-03-27 13:29 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('ck', '0028_treatment_creation'), + ] + + operations = [ + migrations.CreateModel( + name='ICD10Count', + fields=[ + ('icd10cm', models.OneToOneField(on_delete=django.db.models.deletion.DO_NOTHING, primary_key=True, serialize=False, to='ck.icd10cmfinal')), + ('count', models.IntegerField()), + ], + ), + ] diff --git a/mysite/ck/migrations/0030_auto_20210327_2133.py b/mysite/ck/migrations/0030_auto_20210327_2133.py new file mode 100644 index 0000000..cfd8f9f --- /dev/null +++ b/mysite/ck/migrations/0030_auto_20210327_2133.py @@ -0,0 +1,18 @@ +# Generated by Django 3.1.5 on 2021-03-27 13:33 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('ck', '0029_icd10count'), + ] + + operations = [ + migrations.AlterField( + model_name='icd10count', + name='count', + field=models.IntegerField(null=True), + ), + ] diff --git a/mysite/ck/migrations/0031_auto_20210401_1704.py b/mysite/ck/migrations/0031_auto_20210401_1704.py new file mode 100644 index 0000000..3bae726 --- /dev/null +++ b/mysite/ck/migrations/0031_auto_20210401_1704.py @@ -0,0 +1,29 @@ +# Generated by Django 3.1.5 on 2021-04-01 09:04 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('ck', '0030_auto_20210327_2133'), + ] + + operations = [ + migrations.AddField( + model_name='nhiorder', + name='other_diagnosis', + field=models.CharField(blank=True, max_length=200, null=True, verbose_name='其他診斷'), + ), + migrations.AlterField( + model_name='treatment', + name='oncologist', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='ck.oncologist', verbose_name='放射腫瘤'), + ), + migrations.AlterField( + model_name='treatment', + name='surgeon', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='ck.surgeon', verbose_name='神經外科'), + ), + ] diff --git a/mysite/ck/migrations/0032_auto_20210408_1359.py b/mysite/ck/migrations/0032_auto_20210408_1359.py new file mode 100644 index 0000000..4d0ce44 --- /dev/null +++ b/mysite/ck/migrations/0032_auto_20210408_1359.py @@ -0,0 +1,33 @@ +# Generated by Django 3.1.5 on 2021-04-08 05:59 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('ck', '0031_auto_20210401_1704'), + ] + + operations = [ + migrations.AddField( + model_name='oncologist', + name='staff_code', + field=models.CharField(max_length=9, null=True), + ), + migrations.AddField( + model_name='surgeon', + name='staff_code', + field=models.CharField(max_length=9, null=True), + ), + migrations.AlterField( + model_name='nhiorder', + name='Memo', + field=models.TextField(null=True, verbose_name='備註'), + ), + migrations.AlterField( + model_name='nhiorder', + name='other_diagnosis', + field=models.CharField(blank=True, max_length=200, null=True, verbose_name='Dx'), + ), + ] diff --git a/mysite/ck/migrations/0033_auto_20210415_1213.py b/mysite/ck/migrations/0033_auto_20210415_1213.py new file mode 100644 index 0000000..83bf24c --- /dev/null +++ b/mysite/ck/migrations/0033_auto_20210415_1213.py @@ -0,0 +1,18 @@ +# Generated by Django 3.1.5 on 2021-04-15 04:13 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('ck', '0032_auto_20210408_1359'), + ] + + operations = [ + migrations.AlterField( + model_name='nhiorder', + name='PatientName', + field=models.CharField(max_length=30, verbose_name='病患姓å'), + ), + ] diff --git a/mysite/ck/migrations/__init__.py b/mysite/ck/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/mysite/ck/models.py b/mysite/ck/models.py new file mode 100755 index 0000000..7a54e95 --- /dev/null +++ b/mysite/ck/models.py @@ -0,0 +1,598 @@ +# coding=utf-8 + +from django_measurement.models import MeasurementField +from measurement.measures import Volume +from django.db import models + +# Create your models here. + +class ICD9Diag(models.Model): + code = models.CharField(max_length=5, primary_key=True) + desc = models.CharField(max_length=50) + + def __str__(self): + # return "%s.%s %s" % (self.code[0:3], self.code[3:], self.desc) + return self.code + +class ICD10CMfinal(models.Model): + ICD9CM_code = models.CharField(max_length=255, db_column=u"ICD-9-CM代碼", verbose_name=u"ICD-9-CM代碼") + ICD9CM_English = models.CharField(max_length=255, db_column=u"ICD-9-CM英文å稱", verbose_name=u"ICD-9-CM英文å稱") + ICD9CM_Chinese = models.CharField(max_length=255, db_column=u"ICD-9-CM中文å稱", verbose_name=u"ICD-9-CM中文å稱") + ICD10CM = models.CharField(max_length=8, db_column=u"ICD10CM", verbose_name=u"ICD-10-CM", primary_key=True) +# ICD10CM = models.CharField(max_length=255, db_column=u"ICD10CM", verbose_name=u"ICD-10-CM", primary_key=True) +# ICD10CM = models.CharField(max_length=255, primary_key=True) + ICD10CM_English = models.CharField(max_length=255, db_column=u"ICD-10-CM英文å稱", verbose_name=u"ICD-10-CM英文å稱") + ICD10CM_Chinese = models.CharField(max_length=255, db_column=u"ICD-10-CM中文å稱", verbose_name=u"ICD-10-CM中文å稱") + Corresponding = models.CharField(max_length=255, db_column=u"å°æ‡‰æƒ…å½¢", verbose_name=u"å°æ‡‰æƒ…å½¢") + class Meta: + managed = False + db_table = u'ICD10CMfinal2' + + def __str__(self): +# return "%s|%s| %s\n%s" % (self.ICD10CM, self.ICD9CM_code, self.ICD10CM_English, self.ICD9CM_English) + # return "%s|%s|%s" % (self.ICD10CM, self.ICD9CM_code, self.ICD10CM_English) + return "%s %s" % (self.ICD10CM, self.ICD10CM_English) + + def __jsonencode__(self): + return {'ICD10CM': self.ICD10CM} + +class ICD10Count(models.Model): + # icd10cm = models.ForeignKey(ICD10CMfinal, blank=True, null=True, verbose_name='ICD-10-CM', to_field='ICD10CM', on_delete=models.SET_NULL, primary_key=True) + icd10cm = models.OneToOneField(ICD10CMfinal, on_delete=models.DO_NOTHING, primary_key=True) + count = models.IntegerField(null=True) + + +class Activity(models.Model): + title = models.CharField(max_length=200) + + def __str__(self): + return self.title + + class Admin: + pass + +class Patient(models.Model): + GENDER_CHOICES = ( + (1, 'Male'), + (2, 'Female'), + ) +# STATUS_CHOICES = ( +# ( 0, 'Male'), +# (10, 'Female'), +# ) + name = models.CharField(max_length=200, verbose_name='å§“å') + medical_records = models.CharField(max_length=200, unique=True) + gender = models.IntegerField(choices=GENDER_CHOICES) + birthday = models.DateField() + address = models.CharField(max_length=200) + phone = models.CharField(max_length=200) + id_cards = models.CharField(max_length=200, unique=True) + memo = models.CharField(max_length=200, blank=True, null=True) + dead = models.DateField(blank=True, null=True) + + height = models.DecimalField(max_digits=4, decimal_places=1, null=True) + weight = models.DecimalField(max_digits=6, decimal_places=3, null=True) + native = models.CharField(max_length=200, blank=True, null=True) + past_and_family_history = models.TextField(blank=True, null=True) + +# last_followup = models.DateField(blank=True, null=True) +# next_followup = models.DateField(blank=True, null=True) + + timestamp = models.DateTimeField(auto_now=True) + + def __str__(self): + return self.name +# return self.name+' '+str(self.medical_records) + + class Admin: + pass + def get_absolute_url(self): + return "/patient/detail/%i/" % self.id + + # class Meta: + # ordering = ['name'] + + +class Oncologist(models.Model): + name = models.CharField(max_length=200) + staff_code = models.CharField(max_length=9,null=True) + def __str__(self): + return self.name + +class Surgeon(models.Model): + name = models.CharField(max_length=200) + staff_code = models.CharField(max_length=9,null=True) + def __str__(self): + return self.name + +class DiseaseStage(models.Model): + stage = models.CharField(max_length=200) + def __str__(self): + return self.stage + + class Admin: + pass + + +class PrimaryTumorSite(models.Model): +# id = models.IntegerField('ID', primary_key=True) + site = models.CharField(max_length=200) + + def __str__(self): + return self.site + + class Admin: + pass + +ACCOUNTING = ( + (10, 'å¥ä¿'), + (20, '自費'), + (30, 'å…§å«'), +) + +class Treatment(models.Model): + KARNOFSKY_SCORING = ( + (100, '100% - normal, no complaints, no signs of disease'), + ( 90, ' 90% - capable of normal activity, few symptoms or signs of disease'), + ( 80, ' 80% - normal activity with some difficulty, some symptoms or signs'), + ( 70, ' 70% - caring for self, not capable of normal activity or work'), + ( 60, ' 60% - requiring some help, can take care of most personal requirements'), + ( 50, ' 50% - requires help often, requires frequent medical care'), + ( 40, ' 40% - disabled, requires special care and help'), + ( 30, ' 30% - severely disabled, hospital admission indicated but no risk of death'), + ( 20, ' 20% - very ill, urgently requiring admission, requires supportive measures or treatment'), + ( 10, ' 10% - moribund, rapidly progressive fatal disease processes'), + ( 0, ' 0% - death'), + ) + + IMAGE_GUIDANCE = ( + (100, '6D Skull'), + (200, 'Xsight-Spine'), + (210, 'Xsight-Lung'), + (300, 'Fiducial'), + (400, 'Synchrony'), + ) + + patient = models.ForeignKey(Patient, on_delete=models.CASCADE) + bed = models.CharField(max_length=200, blank=True, null=True, verbose_name='病床號') + icd9 = models.ForeignKey(ICD9Diag, blank=True, null=True, verbose_name='ICD9診斷', on_delete=models.SET_NULL) + icd10cm = models.ForeignKey(ICD10CMfinal, blank=True, null=True, verbose_name='ICD-10-CM', to_field='ICD10CM', on_delete=models.SET_NULL) + other_diagnosis = models.CharField(max_length=200, blank=True, null=True, verbose_name='其他診斷') + tracking_mode = models.IntegerField(choices=IMAGE_GUIDANCE, blank=True, null=True) + referral = models.CharField(max_length=200, blank=True, null=True, verbose_name='轉介醫師') + oncologist = models.ForeignKey(Oncologist, blank=True, null=True, on_delete=models.SET_NULL, verbose_name='放射腫瘤') + surgeon = models.ForeignKey(Surgeon, blank=True, null=True, on_delete=models.SET_NULL, verbose_name='神經外科') + date_started = models.DateField(blank=True, null=True) + date_completed = models.DateField(blank=True, null=True) + accounting = models.IntegerField(choices=ACCOUNTING, blank=True, null=True, verbose_name='記帳別') + karnofsky_score = models.IntegerField(choices=KARNOFSKY_SCORING, blank=True, null=True) + disease_stage = models.ForeignKey(DiseaseStage, blank=True, null=True, on_delete=models.SET_NULL) + primary_tumor_site = models.ForeignKey(PrimaryTumorSite, blank=True, null=True, on_delete=models.SET_NULL) + input = models.ForeignKey(Activity, related_name='input', blank=True, null=True, verbose_name='å·²', on_delete=models.SET_NULL) + output = models.ForeignKey(Activity, related_name='output', blank=True, null=True, verbose_name='å¾…', on_delete=models.SET_NULL) + complications = models.CharField(max_length=200, blank=True, null=True, verbose_name='併發症') + chief_complaint = models.TextField(blank=True, null=True) + + memo = models.CharField(max_length=200, blank=True, null=True) + timestamp = models.DateTimeField(auto_now=True) + creation = models.DateTimeField(auto_now_add=True) + + class Admin: + pass + + def get_absolute_url(self): + return "/treatment/detail/%i/" % self.id + + def save(self, *args, **kwargs): + if self.icd10cm: + self.icd9_id = self.icd10cm.ICD9CM_code.replace('.', '') + + super(Treatment, self).save(*args, **kwargs) + +# 000B3121 Cyberknife Radiosurgery,Intracranial Lesion +# 000B3122 Cyberknife Radiosurgery,Extracranial Lesion +# 000B3123 Cyberknife Radiosurgery,Multifraction Therapy +class Price(models.Model): + code = models.CharField(max_length=200, blank=True, null=True) + identity = models.IntegerField(choices=ACCOUNTING) + name = models.CharField(max_length=200) + unit = models.CharField(max_length=200, blank=True, null=True) + address = models.IntegerField(blank=True, null=True) + + class Admin: + pass + + class Meta: + ordering = ["code", "identity", "name"] + + def __str__(self): + return self.code + '-' + self.get_identity_display() + '-' + self.name + +class VEVENT(models.Model): +# iCalendar + DTSTAMP = models.DateTimeField(auto_now=True) + DTSTART = models.DateTimeField() + DTEND = models.TimeField(blank=True) + DURATION = models.TimeField() + SUMMARY = models.CharField(max_length=200, blank=True, null=True) + CLASS = models.CharField(max_length=200, blank=True, null=True) + CATEGORIES = models.CharField(max_length=200, blank=True, null=True) + TRANSP = models.CharField(max_length=200, blank=True, null=True) + RRULE = models.CharField(max_length=200, blank=True, null=True) + + DESCRIPTION = models.CharField(max_length=200, blank=True, null=True) # map to PatientAppointmentSchedule + + MODE_CHOICES = ( + (100, '衛教(æ—¥)'), + (110, 'Fiducial'), + (200, '固定器'), + (210, 'CT'), + (215, 'RT-CT'), + (220, 'MRI'), + (230, 'Angio'), + (300, '頿ޒ'), + (310, '治療'), + ) + treatment = models.ForeignKey(Treatment, on_delete=models.CASCADE) + mode = models.IntegerField(choices=MODE_CHOICES) + mode_remark = models.CharField(max_length=200, blank=True, null=True) + price = models.ForeignKey(Price, blank=True, null=True, on_delete=models.SET_NULL) + + break_frequency = models.IntegerField(blank=True) + system_err = models.IntegerField(blank=True) + shift = models.IntegerField(blank=True) + cone = models.IntegerField(blank=True) + path = models.IntegerField(blank=True) + + def get_absolute_url(self): + return "/treatment/detail/%i/" % self.treatment.id + +class TargetLocation(models.Model): + location = models.CharField(max_length=200) + + def __str__(self): + return self.location + + class Admin: + pass + + +class Pathology(models.Model): + pathology = models.CharField(max_length=200, unique=True) + stage = models.ForeignKey(DiseaseStage, on_delete=models.CASCADE) + + def __str__(self): + return self.pathology + + class Admin: + pass + + +class SubLocation(models.Model): + target_location = models.ForeignKey(TargetLocation, on_delete=models.CASCADE) + group = models.IntegerField() + sub_location = models.CharField(max_length=200) + pathology = models.ManyToManyField(Pathology) + + def __str__(self): +# return TargetLocation.objects.get(id=self.target_location)+' - '+self.sub_location + return self.sub_location + + class Admin: + pass + + +class Lesion(models.Model): + treatment = models.ForeignKey(Treatment, on_delete=models.CASCADE) + sub_location = models.ForeignKey(SubLocation, on_delete=models.CASCADE) + pathology = models.ForeignKey(Pathology, on_delete=models.CASCADE) + + CT_CHOICES = ( + ('GE' , 'GE' ), + ('PHIA', 'Philips'), + ('SIE' , 'Siemens'), + ) + + calibration_table = models.CharField (max_length=9, choices=CT_CHOICES, null=True, verbose_name='CT Calibration table') + density_correction = models.BooleanField( null=True, verbose_name='å½±åƒå¯†åº¦ä¿®æ­£' ) + + dimensions = models.CharField(max_length=200) + volume = models.DecimalField(max_digits=9, decimal_places=2 , verbose_name='Target Volume(mm3)', null=True) + volume_measure = MeasurementField (measurement=Volume,unit_choices=(('cubic_centimeter','cm3'),), verbose_name='Target Volume' , null=True) + +# cubic_millimeter +# cubic_centimeter + + plan_name = models.CharField(max_length=200, blank=True, null=True) + + COLLIMATOR_CHOICES = ( + (10, 'fixed'), + (20, 'Iris'), + (30, 'MLC'), + ) + + collimator_type = models.IntegerField(choices=COLLIMATOR_CHOICES, default=10, verbose_name='Collimator Type' ) + collimator = models.CharField(max_length=200) + path_no = models.IntegerField() + beam_no = models.IntegerField() + + # mu_max = models.DecimalField(max_digits=9, decimal_places=2, null=True) + # mu_min = models.DecimalField(max_digits=9, decimal_places=2, null=True) + mu_max = models.DecimalField(max_digits=9, decimal_places=2, blank=True, null=True) + mu_min = models.DecimalField(max_digits=9, decimal_places=2, blank=True, null=True) + + dose = models.IntegerField() + fractions = models.IntegerField() + iso_dose_curve = models.DecimalField(max_digits=9, decimal_places=1) + + dmin = models.DecimalField(max_digits=9, decimal_places=2) + dmax = models.DecimalField(max_digits=9, decimal_places=2) + dmean = models.DecimalField(max_digits=9, decimal_places=2, verbose_name='Mean dose(cGy)', null=True) + + coverage = models.DecimalField(max_digits=9, decimal_places=2) + ci = models.DecimalField(max_digits=9, decimal_places=2) + nci = models.DecimalField(max_digits=9, decimal_places=2) + + start_date = models.DateField(blank=True, null=True) + end_date = models.DateField(blank=True, null=True) + + memo = models.CharField(max_length=200, blank=True, null=True) + + def get_absolute_url(self): + return "/treatment/detail/%i/" % self.treatment.id + + def sub_location_target_location(self): + return self.sub_location.target_location + + def treatment_id(self): + return treatment.id + + def save(self, *args, **kwargs): + if self.volume_measure is not None: + self.volume = self.volume_measure.cubic_millimeter + super().save(*args, **kwargs) + + +class PriorTreatment(models.Model): + TREATMENT_CHOICES = ( + (1, 'Surgery'), + (2, 'Biopsy'), + (3, 'RT'), + (4, 'Radiosurgery'), + (5, 'Chemotherapy'), + ) + PERIOD_CHOICES = ( + (1, 'Before'), + (2, 'Concurrent'), + (3, 'None'), + ) + patient = models.ForeignKey(Patient, on_delete=models.CASCADE) + date = models.DateField() + treatment = models.IntegerField(choices=TREATMENT_CHOICES) + period = models.IntegerField(choices=PERIOD_CHOICES, blank=True, null=True) + dose = models.IntegerField(blank=True, null=True) + memo = models.CharField(max_length=200, blank=True, null=True) + + def get_absolute_url(self): + return "/patient/detail/%i/" % self.patient.id + + +class PathExam(models.Model): + patient = models.ForeignKey(Patient, on_delete=models.CASCADE) + path_code = models.CharField(max_length=200, unique=True, verbose_name='ç—…ç†è™Ÿ') + specimen_code = models.CharField(max_length=200, verbose_name='檢體') + specimen_get_date = models.DateField(verbose_name='æ”¶ä»¶æ—¥') + report_date = models.DateField(verbose_name='報告日') + division = models.CharField(max_length=200, verbose_name='科別') + bed = models.CharField(max_length=200, blank=True, null=True, verbose_name='病床') + report = models.TextField(blank=True, null=True, verbose_name='檢查報告') + + +class Followup(models.Model): + patient = models.ForeignKey(Patient, on_delete=models.CASCADE) +# date = models.DateField(auto_now_add=True) + date = models.DateField() + memo = models.CharField(max_length=200, blank=True, null=True) + + def get_absolute_url(self): + return "/patient/detail/%i/" % self.patient.id + +class PACSImage(models.Model): + patient = models.ForeignKey(Patient, on_delete=models.CASCADE) + + PatChartNo = models.CharField(max_length=200, verbose_name='病歷號') + RequestSheetNo = models.CharField(max_length=200, verbose_name='單號') + ExamDate = models.DateField( verbose_name='檢查日') + LinkOrderName = models.CharField(max_length=200, verbose_name='檢查å稱') + Modality = models.CharField(max_length=200, verbose_name='儀器') + VerifiedStateString = models.CharField(max_length=200, verbose_name='狀態') + Exam = models.TextField(null=True, verbose_name='報告內容') + Impression = models.TextField(null=True) + Report = models.TextField(null=True, verbose_name='報告') + + SAVED_CHOICES = ( + (0 , '待處ç†'), + (10, '有輸入'), + (15, '已確èª'), + (20, 'ä¸é©ç”¨'), + ) +# Saved = models.BooleanField() + Saved = models.IntegerField(choices=SAVED_CHOICES, verbose_name='ä¿å­˜') + + +class ElectronicMedicalReport(models.Model): + report_key = models.CharField(max_length=200, primary_key=True) + patient = models.ForeignKey(Patient, on_delete=models.CASCADE) + + report_class = models.CharField(max_length=200) + check_date = models.DateField(null=True) + report_date = models.DateField(null=True) + report_code = models.CharField(max_length=200) + report = models.TextField(null=True) + saved = models.DateField(auto_now=True) + + +class XrayTextReport(models.Model): + # report_key = models.ForeignKey(ElectronicMedicalReport, primary_key=True) + report_key = models.OneToOneField(ElectronicMedicalReport, primary_key=True, on_delete=models.CASCADE) + + old_access_no = models.CharField(max_length=200, null=True) + ioe = models.CharField(max_length=200, null=True) + refer_dept = models.CharField(max_length=200, null=True) + status = models.CharField(max_length=200, null=True) + formal_version = models.CharField(max_length=200, null=True) + exam_date = models.DateField(null=True) + order_desc = models.CharField(max_length=200, null=True) + + clean_html = models.TextField(null=True) + + response = models.CharField(max_length=200, null=True) + + +class TreatmentResponse(models.Model): + # treatment = models.ForeignKey(Treatment, primary_key=True) + treatment = models.OneToOneField(Treatment, primary_key=True, on_delete=models.CASCADE) + + time = models.DateField(null=True) + event = models.BooleanField(null=True) + + time1y = models.DateField(null=True) + event1y = models.BooleanField(null=True) + +class LesionFollow(models.Model): + Lesion = models.ForeignKey(Lesion, on_delete=models.CASCADE) + Date = models.DateField(null=False, verbose_name='追蹤日期') + Volume = models.FloatField(null=True, verbose_name='é«”ç©(mm3)') + A = models.FloatField(null=True, verbose_name='é•·(mm)') + B = models.FloatField(null=True, verbose_name='寬(mm)') + C = models.FloatField(null=True, verbose_name='高(mm)') + Memo = models.CharField(max_length=200, blank=True, null=True) + + +class MedicalRecord(models.Model): + patient = models.ForeignKey(Patient, on_delete=models.CASCADE) + + Record = models.CharField(max_length=200, null=True) # 使€¥é–€ + + HospName = models.CharField(max_length=200, null=True) + DeptName = models.CharField(max_length=200, null=True, verbose_name='ç§‘') + InDate = models.DateField( null=False, verbose_name='å…¥') + OutDate = models.DateField( null=True, verbose_name='出') + WardName = models.CharField(max_length=200, null=True, verbose_name='房') + RoomName = models.CharField(max_length=200, null=True, verbose_name='室') + BedName = models.CharField(max_length=200, null=True, verbose_name='床') + MainDrName = models.CharField(max_length=200, null=True, verbose_name='主治') + MainDiagnosisName = models.CharField(max_length=200, null=True, verbose_name='診斷') + StatusName = models.CharField(max_length=200, null=True, verbose_name='狀態') + + SpecialCureName = models.CharField(max_length=200, null=True, verbose_name='行為') + + +#New records +class PatientMedicalRecord(models.Model): + key_code = models.CharField(max_length=200, primary_key=True) # 使€¥é–€ + patient = models.ForeignKey(Patient, on_delete=models.CASCADE) + + key_name = models.CharField(max_length=200) + + hosp_name = models.CharField(max_length=200, null=True) + dept_name = models.CharField(max_length=200, null=True, verbose_name='ç§‘') + in_date = models.DateField( null=True, verbose_name='å…¥') + out_date = models.DateField( null=True, verbose_name='出') + ward_name = models.CharField(max_length=200, null=True, verbose_name='房') + room_name = models.CharField(max_length=200, null=True, verbose_name='室') + bed_name = models.CharField(max_length=200, null=True, verbose_name='床') + + come_clinic_date = models.DateField( null=True, verbose_name='掛號日') + discharge_date = models.DateField( null=True, verbose_name='離部日') + + special_cure_name = models.CharField(max_length=200, null=True, verbose_name='行為') + + main_dr_name = models.CharField(max_length=200, null=True, verbose_name='主治') + main_diagnosis_name = models.CharField(max_length=200, null=True, verbose_name='診斷') + status_name = models.CharField(max_length=200, null=True, verbose_name='狀態') + + temp_bed_id = models.CharField(max_length=200, null=True, verbose_name='床') + + account_status_name = models.CharField(max_length=200, null=True, verbose_name='狀態') + + func = models.CharField(max_length=200, null=True) + doc = models.TextField( null=True, verbose_name='摘') + saved = models.DateField(auto_now=True) + +class OPNote(models.Model): + key_code = models.CharField(max_length=200, primary_key=True) + patient = models.ForeignKey(Patient, on_delete=models.CASCADE) + + key_name = models.CharField(max_length=200) + + doc = models.TextField( null=True, verbose_name='摘') + saved = models.DateField(auto_now=True) + +# {'ChartNo': '6791902', 'PatientName': '張秀玲', 'ApplyTypeDesc': '逿 ¸', 'StatusDesc': '新建案件', 'NhiDeptName': '放射腫瘤科', 'PackageTime': None, 'OrderCode': '37029B', 'OrderName': 'åŠ é¦¬æ©Ÿç«‹é«”å®šä½æ”¾å°„手術', 'ResultDesc': '1', 'Quantity': None, 'ExamineQuantity': '0', 'ExamineDate': None} +# {'ChartNo': '3302509', 'PatientName': '賴慧如', 'Status': '影醫部處ç†ä¸­', 'ErrorMsg': None, 'SuccessMsg': None, 'ApplyType': '逿 ¸', 'ApplyDate': '2021/02/25', 'AnticancerMedicine': 'å¦', 'ApplyPart': 'ç„¡', 'EmrDateStr': None, 'NhiDept': '神經外科', 'ApplyDoctor': 'è•­è¼”ä»', 'Phone': '63424', 'Diagnosis': 'D32.9', 'Reason': 'A 46Y/O patient female, PHX: olfactory grove meningioma sp OP in 2018,因目å‰ç™¼ç¾æœ‰recurrence, + +class NHIOrder(models.Model): + id = models.CharField(max_length=20, primary_key=True) + + ChartNo = models.CharField (verbose_name='病歷號' ,max_length=10) + PatientName = models.CharField (verbose_name='病患姓å',max_length=30) + ApplyTypeDesc = models.CharField (verbose_name='申請類別',max_length=10) + StatusDesc = models.CharField (verbose_name='案件狀態',max_length=10) + NhiDeptName = models.CharField (verbose_name='科別' ,max_length=10) + PackageTime = models.DateField (verbose_name='逿¡ˆæ—¥æœŸ') + OrderCode = models.CharField (verbose_name='申請項目',max_length=10) + OrderName = models.CharField (verbose_name='é …ç›®å稱',max_length=20) + ResultDesc = models.IntegerField(verbose_name='申請數é‡',default=1) + Quantity = models.CharField (verbose_name='æ ¸å®šçµæžœ',max_length=10, null=True) + ExamineQuantity= models.IntegerField(verbose_name='核定數é‡', null=True) + ExamineDate = models.DateField (verbose_name='核定日期', null=True) + + timestamp = models.DateTimeField(auto_now_add=True) + updated = models.DateTimeField(auto_now=True) + + # optional + + Status = models.CharField (verbose_name='ç›®å‰ç‹€æ…‹' ,max_length=10, null=True) + ErrorMsg = models.CharField ( max_length=10, null=True) + SuccessMsg = models.CharField ( max_length=10, null=True) + + ApplyType = models.CharField (verbose_name='申請類別' ,max_length=10, null=True) + ApplyDate = models.DateField (verbose_name='申請日期' , null=True) + AnticancerMedicine = models.CharField (verbose_name='抗癌藥物' ,max_length=10, null=True) + ApplyPart = models.CharField (verbose_name='申請部ä½' ,max_length=10, null=True) + EmrDateStr = models.CharField (verbose_name='緊急通報日' ,max_length=10, null=True) + NhiDept = models.CharField (verbose_name='申請科別' ,max_length=10, null=True) + ApplyDoctor = models.CharField (verbose_name='申請醫師' ,max_length=10, null=True) + Phone = models.CharField (verbose_name='è¯çµ¡åˆ†æ©Ÿ' ,max_length=10, null=True) + Diagnosis = models.CharField (verbose_name='疾病分類號' ,max_length=10, null=True) + Reason = models.TextField (verbose_name='申請原因' , null=True) + # OrderCode = models.CharField (verbose_name='醫令碼' ,max_length=10, null=True) + # OrderName = models.CharField (verbose_name='醫令å稱' ,max_length=10, null=True) + ApplyQty = models.IntegerField(verbose_name='申請é‡' , null=True) + # ResultDesc = models.CharField (verbose_name='æ ¸å®šçµæžœ' ,max_length=10, null=True) + # ExamineQuantity = models.CharField (verbose_name='核定é‡' ,max_length=10, null=True) + ExamineDateStr = models.CharField (verbose_name='核定日期' ,max_length=10, null=True) + ExamineReason1 = models.CharField (verbose_name='核定原因1' ,max_length=10, null=True) + ExamineReason2 = models.CharField (verbose_name='核定原因2' ,max_length=10, null=True) + ExamineReasonDesc = models.TextField (verbose_name='核定原因說明', null=True) + + # extra + + other_diagnosis = models.CharField(max_length=200, blank=True, null=True, verbose_name='Dx') + num_sessions = models.CharField (verbose_name='é è¨ˆåˆ†æ¬¡', max_length=10, null=True) + MainDrName = models.TextField (verbose_name='主治' , null=True) + Priority = models.IntegerField(verbose_name='優先' , null=True) + Memo = models.TextField (verbose_name='備註' , null=True) + + + + # def save(self, *args, **kwargs): + # if self.id is None: + # self.id = self.ChartNo+'_'+self.PackageTime[:7] + + # super(NHIOrder, self).save(*args, **kwargs) + +''' +sed 's/ENGINE=MyISAM/ENGINE=InnoDB/; s/DEFAULT CHARSET=utf8mb4//; s/DEFAULT CHARSET=utf8//; s/COLLATE=utf8_unicode_ci//' /data/tmp/ck_dev.sql > /data/tmp/ck_dev2.sql +''' diff --git a/mysite/ck/selenium.py b/mysite/ck/selenium.py new file mode 100755 index 0000000..66fc455 --- /dev/null +++ b/mysite/ck/selenium.py @@ -0,0 +1,2071 @@ + +""" +Copyright 2006 ThoughtWorks, Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +""" +__docformat__ = "restructuredtext en" + +# This file has been automatically generated via XSL + +import httplib +import urllib +import re + +class selenium: + """ + Defines an object that runs Selenium commands. + + Element Locators + ~~~~~~~~~~~~~~~~ + + Element Locators tell Selenium which HTML element a command refers to. + The format of a locator is: + + \ *locatorType*\ **=**\ \ *argument* + + + We support the following strategies for locating elements: + + + * \ **identifier**\ =\ *id*: + Select the element with the specified @id attribute. If no match is + found, select the first element whose @name attribute is \ *id*. + (This is normally the default; see below.) + * \ **id**\ =\ *id*: + Select the element with the specified @id attribute. + * \ **name**\ =\ *name*: + Select the first element with the specified @name attribute. + + * username + * name=username + + + The name may optionally be followed by one or more \ *element-filters*, separated from the name by whitespace. If the \ *filterType* is not specified, \ **value**\ is assumed. + + * name=flavour value=chocolate + + + * \ **dom**\ =\ *javascriptExpression*: + + Find an element by evaluating the specified string. This allows you to traverse the HTML Document Object + Model using JavaScript. Note that you must not return a value in this string; simply make it the last expression in the block. + + * dom=document.forms['myForm'].myDropdown + * dom=document.images[56] + * dom=function foo() { return document.links[1]; }; foo(); + + + * \ **xpath**\ =\ *xpathExpression*: + Locate an element using an XPath expression. + + * xpath=//img[@alt='The image alt text'] + * xpath=//table[@id='table1']//tr[4]/td[2] + * xpath=//a[contains(@href,'#id1')] + * xpath=//a[contains(@href,'#id1')]/@class + * xpath=(//table[@class='stylee'])//th[text()='theHeaderText']/../td + * xpath=//input[@name='name2' and @value='yes'] + * xpath=//\*[text()="right"] + + + * \ **link**\ =\ *textPattern*: + Select the link (anchor) element which contains text matching the + specified \ *pattern*. + + * link=The link text + + + * \ **css**\ =\ *cssSelectorSyntax*: + Select the element using css selectors. Please refer to CSS2 selectors, CSS3 selectors for more information. You can also check the TestCssLocators test in the selenium test suite for an example of usage, which is included in the downloaded selenium core package. + + * css=a[href="#id3"] + * css=span#firstChild + span + + + Currently the css selector locator supports all css1, css2 and css3 selectors except namespace in css3, some pseudo classes(:nth-of-type, :nth-last-of-type, :first-of-type, :last-of-type, :only-of-type, :visited, :hover, :active, :focus, :indeterminate) and pseudo elements(::first-line, ::first-letter, ::selection, ::before, ::after). + + * \ **ui**\ =\ *uiSpecifierString*: + Locate an element by resolving the UI specifier string to another locator, and evaluating it. See the Selenium UI-Element Reference for more details. + + * ui=loginPages::loginButton() + * ui=settingsPages::toggle(label=Hide Email) + * ui=forumPages::postBody(index=2)//a[2] + + + + + + Without an explicit locator prefix, Selenium uses the following default + strategies: + + + * \ **dom**\ , for locators starting with "document." + * \ **xpath**\ , for locators starting with "//" + * \ **identifier**\ , otherwise + + Element Filters + ~~~~~~~~~~~~~~~ + + Element filters can be used with a locator to refine a list of candidate elements. They are currently used only in the 'name' element-locator. + + Filters look much like locators, ie. + + \ *filterType*\ **=**\ \ *argument* + + Supported element-filters are: + + \ **value=**\ \ *valuePattern* + + + Matches elements based on their values. This is particularly useful for refining a list of similarly-named toggle-buttons. + + \ **index=**\ \ *index* + + + Selects a single element based on its position in the list (offset from zero). + + String-match Patterns + ~~~~~~~~~~~~~~~~~~~~~ + + Various Pattern syntaxes are available for matching string values: + + + * \ **glob:**\ \ *pattern*: + Match a string against a "glob" (aka "wildmat") pattern. "Glob" is a + kind of limited regular-expression syntax typically used in command-line + shells. In a glob pattern, "\*" represents any sequence of characters, and "?" + represents any single character. Glob patterns match against the entire + string. + * \ **regexp:**\ \ *regexp*: + Match a string using a regular-expression. The full power of JavaScript + regular-expressions is available. + * \ **regexpi:**\ \ *regexpi*: + Match a string using a case-insensitive regular-expression. + * \ **exact:**\ \ *string*: + + Match a string exactly, verbatim, without any of that fancy wildcard + stuff. + + + + If no pattern prefix is specified, Selenium assumes that it's a "glob" + pattern. + + + + For commands that return multiple values (such as verifySelectOptions), + the string being matched is a comma-separated list of the return values, + where both commas and backslashes in the values are backslash-escaped. + When providing a pattern, the optional matching syntax (i.e. glob, + regexp, etc.) is specified once, as usual, at the beginning of the + pattern. + + + """ + +### This part is hard-coded in the XSL + def __init__(self, host, port, browserStartCommand, browserURL): + self.host = host + self.port = port + self.browserStartCommand = browserStartCommand + self.browserURL = browserURL + self.sessionId = None + self.extensionJs = "" + + def setExtensionJs(self, extensionJs): + self.extensionJs = extensionJs + + def start(self): + result = self.get_string("getNewBrowserSession", [self.browserStartCommand, self.browserURL, self.extensionJs]) + try: + self.sessionId = result + except ValueError: + raise Exception, result + + def stop(self): + self.do_command("testComplete", []) + self.sessionId = None + + def do_command(self, verb, args): + conn = httplib.HTTPConnection(self.host, self.port) + body = u'cmd=' + urllib.quote_plus(unicode(verb).encode('utf-8')) + for i in range(len(args)): + body += '&' + unicode(i+1) + '=' + urllib.quote_plus(unicode(args[i]).encode('utf-8')) + if (None != self.sessionId): + body += "&sessionId=" + unicode(self.sessionId) + headers = {"Content-Type": "application/x-www-form-urlencoded; charset=utf-8"} + conn.request("POST", "/selenium-server/driver/", body, headers) + + response = conn.getresponse() + #print response.status, response.reason + data = unicode(response.read(), "UTF-8") + result = response.reason + #print "Selenium Result: " + repr(data) + "\n\n" + if (not data.startswith('OK')): + raise Exception, data + return data + + def get_string(self, verb, args): + result = self.do_command(verb, args) + return result[3:] + + def get_string_array(self, verb, args): + csv = self.get_string(verb, args) + token = "" + tokens = [] + escape = False + for i in range(len(csv)): + letter = csv[i] + if (escape): + token = token + letter + escape = False + continue + if (letter == '\\'): + escape = True + elif (letter == ','): + tokens.append(token) + token = "" + else: + token = token + letter + tokens.append(token) + return tokens + + def get_number(self, verb, args): + # Is there something I need to do here? + return self.get_string(verb, args) + + def get_number_array(self, verb, args): + # Is there something I need to do here? + return self.get_string_array(verb, args) + + def get_boolean(self, verb, args): + boolstr = self.get_string(verb, args) + if ("true" == boolstr): + return True + if ("false" == boolstr): + return False + raise ValueError, "result is neither 'true' nor 'false': " + boolstr + + def get_boolean_array(self, verb, args): + boolarr = self.get_string_array(verb, args) + for i in range(len(boolarr)): + if ("true" == boolstr): + boolarr[i] = True + continue + if ("false" == boolstr): + boolarr[i] = False + continue + raise ValueError, "result is neither 'true' nor 'false': " + boolarr[i] + return boolarr + + + +### From here on, everything's auto-generated from XML + + + def click(self,locator): + """ + Clicks on a link, button, checkbox or radio button. If the click action + causes a new page to load (like a link usually does), call + waitForPageToLoad. + + 'locator' is an element locator + """ + self.do_command("click", [locator,]) + + + def double_click(self,locator): + """ + Double clicks on a link, button, checkbox or radio button. If the double click action + causes a new page to load (like a link usually does), call + waitForPageToLoad. + + 'locator' is an element locator + """ + self.do_command("doubleClick", [locator,]) + + + def context_menu(self,locator): + """ + Simulates opening the context menu for the specified element (as might happen if the user "right-clicked" on the element). + + 'locator' is an element locator + """ + self.do_command("contextMenu", [locator,]) + + + def click_at(self,locator,coordString): + """ + Clicks on a link, button, checkbox or radio button. If the click action + causes a new page to load (like a link usually does), call + waitForPageToLoad. + + 'locator' is an element locator + 'coordString' is specifies the x,y position (i.e. - 10,20) of the mouse event relative to the element returned by the locator. + """ + self.do_command("clickAt", [locator,coordString,]) + + + def double_click_at(self,locator,coordString): + """ + Doubleclicks on a link, button, checkbox or radio button. If the action + causes a new page to load (like a link usually does), call + waitForPageToLoad. + + 'locator' is an element locator + 'coordString' is specifies the x,y position (i.e. - 10,20) of the mouse event relative to the element returned by the locator. + """ + self.do_command("doubleClickAt", [locator,coordString,]) + + + def context_menu_at(self,locator,coordString): + """ + Simulates opening the context menu for the specified element (as might happen if the user "right-clicked" on the element). + + 'locator' is an element locator + 'coordString' is specifies the x,y position (i.e. - 10,20) of the mouse event relative to the element returned by the locator. + """ + self.do_command("contextMenuAt", [locator,coordString,]) + + + def fire_event(self,locator,eventName): + """ + Explicitly simulate an event, to trigger the corresponding "on\ *event*" + handler. + + 'locator' is an element locator + 'eventName' is the event name, e.g. "focus" or "blur" + """ + self.do_command("fireEvent", [locator,eventName,]) + + + def focus(self,locator): + """ + Move the focus to the specified element; for example, if the element is an input field, move the cursor to that field. + + 'locator' is an element locator + """ + self.do_command("focus", [locator,]) + + + def key_press(self,locator,keySequence): + """ + Simulates a user pressing and releasing a key. + + 'locator' is an element locator + 'keySequence' is Either be a string("\" followed by the numeric keycode of the key to be pressed, normally the ASCII value of that key), or a single character. For example: "w", "\119". + """ + self.do_command("keyPress", [locator,keySequence,]) + + + def shift_key_down(self): + """ + Press the shift key and hold it down until doShiftUp() is called or a new page is loaded. + + """ + self.do_command("shiftKeyDown", []) + + + def shift_key_up(self): + """ + Release the shift key. + + """ + self.do_command("shiftKeyUp", []) + + + def meta_key_down(self): + """ + Press the meta key and hold it down until doMetaUp() is called or a new page is loaded. + + """ + self.do_command("metaKeyDown", []) + + + def meta_key_up(self): + """ + Release the meta key. + + """ + self.do_command("metaKeyUp", []) + + + def alt_key_down(self): + """ + Press the alt key and hold it down until doAltUp() is called or a new page is loaded. + + """ + self.do_command("altKeyDown", []) + + + def alt_key_up(self): + """ + Release the alt key. + + """ + self.do_command("altKeyUp", []) + + + def control_key_down(self): + """ + Press the control key and hold it down until doControlUp() is called or a new page is loaded. + + """ + self.do_command("controlKeyDown", []) + + + def control_key_up(self): + """ + Release the control key. + + """ + self.do_command("controlKeyUp", []) + + + def key_down(self,locator,keySequence): + """ + Simulates a user pressing a key (without releasing it yet). + + 'locator' is an element locator + 'keySequence' is Either be a string("\" followed by the numeric keycode of the key to be pressed, normally the ASCII value of that key), or a single character. For example: "w", "\119". + """ + self.do_command("keyDown", [locator,keySequence,]) + + + def key_up(self,locator,keySequence): + """ + Simulates a user releasing a key. + + 'locator' is an element locator + 'keySequence' is Either be a string("\" followed by the numeric keycode of the key to be pressed, normally the ASCII value of that key), or a single character. For example: "w", "\119". + """ + self.do_command("keyUp", [locator,keySequence,]) + + + def mouse_over(self,locator): + """ + Simulates a user hovering a mouse over the specified element. + + 'locator' is an element locator + """ + self.do_command("mouseOver", [locator,]) + + + def mouse_out(self,locator): + """ + Simulates a user moving the mouse pointer away from the specified element. + + 'locator' is an element locator + """ + self.do_command("mouseOut", [locator,]) + + + def mouse_down(self,locator): + """ + Simulates a user pressing the left mouse button (without releasing it yet) on + the specified element. + + 'locator' is an element locator + """ + self.do_command("mouseDown", [locator,]) + + + def mouse_down_right(self,locator): + """ + Simulates a user pressing the right mouse button (without releasing it yet) on + the specified element. + + 'locator' is an element locator + """ + self.do_command("mouseDownRight", [locator,]) + + + def mouse_down_at(self,locator,coordString): + """ + Simulates a user pressing the left mouse button (without releasing it yet) at + the specified location. + + 'locator' is an element locator + 'coordString' is specifies the x,y position (i.e. - 10,20) of the mouse event relative to the element returned by the locator. + """ + self.do_command("mouseDownAt", [locator,coordString,]) + + + def mouse_down_right_at(self,locator,coordString): + """ + Simulates a user pressing the right mouse button (without releasing it yet) at + the specified location. + + 'locator' is an element locator + 'coordString' is specifies the x,y position (i.e. - 10,20) of the mouse event relative to the element returned by the locator. + """ + self.do_command("mouseDownRightAt", [locator,coordString,]) + + + def mouse_up(self,locator): + """ + Simulates the event that occurs when the user releases the mouse button (i.e., stops + holding the button down) on the specified element. + + 'locator' is an element locator + """ + self.do_command("mouseUp", [locator,]) + + + def mouse_up_right(self,locator): + """ + Simulates the event that occurs when the user releases the right mouse button (i.e., stops + holding the button down) on the specified element. + + 'locator' is an element locator + """ + self.do_command("mouseUpRight", [locator,]) + + + def mouse_up_at(self,locator,coordString): + """ + Simulates the event that occurs when the user releases the mouse button (i.e., stops + holding the button down) at the specified location. + + 'locator' is an element locator + 'coordString' is specifies the x,y position (i.e. - 10,20) of the mouse event relative to the element returned by the locator. + """ + self.do_command("mouseUpAt", [locator,coordString,]) + + + def mouse_up_right_at(self,locator,coordString): + """ + Simulates the event that occurs when the user releases the right mouse button (i.e., stops + holding the button down) at the specified location. + + 'locator' is an element locator + 'coordString' is specifies the x,y position (i.e. - 10,20) of the mouse event relative to the element returned by the locator. + """ + self.do_command("mouseUpRightAt", [locator,coordString,]) + + + def mouse_move(self,locator): + """ + Simulates a user pressing the mouse button (without releasing it yet) on + the specified element. + + 'locator' is an element locator + """ + self.do_command("mouseMove", [locator,]) + + + def mouse_move_at(self,locator,coordString): + """ + Simulates a user pressing the mouse button (without releasing it yet) on + the specified element. + + 'locator' is an element locator + 'coordString' is specifies the x,y position (i.e. - 10,20) of the mouse event relative to the element returned by the locator. + """ + self.do_command("mouseMoveAt", [locator,coordString,]) + + + def type(self,locator,value): + """ + Sets the value of an input field, as though you typed it in. + + + Can also be used to set the value of combo boxes, check boxes, etc. In these cases, + value should be the value of the option selected, not the visible text. + + + 'locator' is an element locator + 'value' is the value to type + """ + self.do_command("type", [locator,value,]) + + + def type_keys(self,locator,value): + """ + Simulates keystroke events on the specified element, as though you typed the value key-by-key. + + + This is a convenience method for calling keyDown, keyUp, keyPress for every character in the specified string; + this is useful for dynamic UI widgets (like auto-completing combo boxes) that require explicit key events. + + Unlike the simple "type" command, which forces the specified value into the page directly, this command + may or may not have any visible effect, even in cases where typing keys would normally have a visible effect. + For example, if you use "typeKeys" on a form element, you may or may not see the results of what you typed in + the field. + + In some cases, you may need to use the simple "type" command to set the value of the field and then the "typeKeys" command to + send the keystroke events corresponding to what you just typed. + + + 'locator' is an element locator + 'value' is the value to type + """ + self.do_command("typeKeys", [locator,value,]) + + + def set_speed(self,value): + """ + Set execution speed (i.e., set the millisecond length of a delay which will follow each selenium operation). By default, there is no such delay, i.e., + the delay is 0 milliseconds. + + 'value' is the number of milliseconds to pause after operation + """ + self.do_command("setSpeed", [value,]) + + + def get_speed(self): + """ + Get execution speed (i.e., get the millisecond length of the delay following each selenium operation). By default, there is no such delay, i.e., + the delay is 0 milliseconds. + + See also setSpeed. + + """ + return self.get_string("getSpeed", []) + + + def check(self,locator): + """ + Check a toggle-button (checkbox/radio) + + 'locator' is an element locator + """ + self.do_command("check", [locator,]) + + + def uncheck(self,locator): + """ + Uncheck a toggle-button (checkbox/radio) + + 'locator' is an element locator + """ + self.do_command("uncheck", [locator,]) + + + def select(self,selectLocator,optionLocator): + """ + Select an option from a drop-down using an option locator. + + + + Option locators provide different ways of specifying options of an HTML + Select element (e.g. for selecting a specific option, or for asserting + that the selected option satisfies a specification). There are several + forms of Select Option Locator. + + + * \ **label**\ =\ *labelPattern*: + matches options based on their labels, i.e. the visible text. (This + is the default.) + + * label=regexp:^[Oo]ther + + + * \ **value**\ =\ *valuePattern*: + matches options based on their values. + + * value=other + + + * \ **id**\ =\ *id*: + + matches options based on their ids. + + * id=option1 + + + * \ **index**\ =\ *index*: + matches an option based on its index (offset from zero). + + * index=2 + + + + + + If no option locator prefix is provided, the default behaviour is to match on \ **label**\ . + + + + 'selectLocator' is an element locator identifying a drop-down menu + 'optionLocator' is an option locator (a label by default) + """ + self.do_command("select", [selectLocator,optionLocator,]) + + + def add_selection(self,locator,optionLocator): + """ + Add a selection to the set of selected options in a multi-select element using an option locator. + + @see #doSelect for details of option locators + + 'locator' is an element locator identifying a multi-select box + 'optionLocator' is an option locator (a label by default) + """ + self.do_command("addSelection", [locator,optionLocator,]) + + + def remove_selection(self,locator,optionLocator): + """ + Remove a selection from the set of selected options in a multi-select element using an option locator. + + @see #doSelect for details of option locators + + 'locator' is an element locator identifying a multi-select box + 'optionLocator' is an option locator (a label by default) + """ + self.do_command("removeSelection", [locator,optionLocator,]) + + + def remove_all_selections(self,locator): + """ + Unselects all of the selected options in a multi-select element. + + 'locator' is an element locator identifying a multi-select box + """ + self.do_command("removeAllSelections", [locator,]) + + + def submit(self,formLocator): + """ + Submit the specified form. This is particularly useful for forms without + submit buttons, e.g. single-input "Search" forms. + + 'formLocator' is an element locator for the form you want to submit + """ + self.do_command("submit", [formLocator,]) + + + def open(self,url): + """ + Opens an URL in the test frame. This accepts both relative and absolute + URLs. + + The "open" command waits for the page to load before proceeding, + ie. the "AndWait" suffix is implicit. + + \ *Note*: The URL must be on the same domain as the runner HTML + due to security restrictions in the browser (Same Origin Policy). If you + need to open an URL on another domain, use the Selenium Server to start a + new browser session on that domain. + + 'url' is the URL to open; may be relative or absolute + """ + self.do_command("open", [url,]) + + + def open_window(self,url,windowID): + """ + Opens a popup window (if a window with that ID isn't already open). + After opening the window, you'll need to select it using the selectWindow + command. + + + This command can also be a useful workaround for bug SEL-339. In some cases, Selenium will be unable to intercept a call to window.open (if the call occurs during or before the "onLoad" event, for example). + In those cases, you can force Selenium to notice the open window's name by using the Selenium openWindow command, using + an empty (blank) url, like this: openWindow("", "myFunnyWindow"). + + + 'url' is the URL to open, which can be blank + 'windowID' is the JavaScript window ID of the window to select + """ + self.do_command("openWindow", [url,windowID,]) + + + def select_window(self,windowID): + """ + Selects a popup window using a window locator; once a popup window has been selected, all + commands go to that window. To select the main window again, use null + as the target. + + + + + Window locators provide different ways of specifying the window object: + by title, by internal JavaScript "name," or by JavaScript variable. + + + * \ **title**\ =\ *My Special Window*: + Finds the window using the text that appears in the title bar. Be careful; + two windows can share the same title. If that happens, this locator will + just pick one. + + * \ **name**\ =\ *myWindow*: + Finds the window using its internal JavaScript "name" property. This is the second + parameter "windowName" passed to the JavaScript method window.open(url, windowName, windowFeatures, replaceFlag) + (which Selenium intercepts). + + * \ **var**\ =\ *variableName*: + Some pop-up windows are unnamed (anonymous), but are associated with a JavaScript variable name in the current + application window, e.g. "window.foo = window.open(url);". In those cases, you can open the window using + "var=foo". + + + + + If no window locator prefix is provided, we'll try to guess what you mean like this: + + 1.) if windowID is null, (or the string "null") then it is assumed the user is referring to the original window instantiated by the browser). + + 2.) if the value of the "windowID" parameter is a JavaScript variable name in the current application window, then it is assumed + that this variable contains the return value from a call to the JavaScript window.open() method. + + 3.) Otherwise, selenium looks in a hash it maintains that maps string names to window "names". + + 4.) If \ *that* fails, we'll try looping over all of the known windows to try to find the appropriate "title". + Since "title" is not necessarily unique, this may have unexpected behavior. + + If you're having trouble figuring out the name of a window that you want to manipulate, look at the Selenium log messages + which identify the names of windows created via window.open (and therefore intercepted by Selenium). You will see messages + like the following for each window as it is opened: + + ``debug: window.open call intercepted; window ID (which you can use with selectWindow()) is "myNewWindow"`` + + In some cases, Selenium will be unable to intercept a call to window.open (if the call occurs during or before the "onLoad" event, for example). + (This is bug SEL-339.) In those cases, you can force Selenium to notice the open window's name by using the Selenium openWindow command, using + an empty (blank) url, like this: openWindow("", "myFunnyWindow"). + + + 'windowID' is the JavaScript window ID of the window to select + """ + self.do_command("selectWindow", [windowID,]) + + + def select_pop_up(self,windowID): + """ + Simplifies the process of selecting a popup window (and does not offer + functionality beyond what ``selectWindow()`` already provides). + + * If ``windowID`` is either not specified, or specified as + "null", the first non-top window is selected. The top window is the one + that would be selected by ``selectWindow()`` without providing a + ``windowID`` . This should not be used when more than one popup + window is in play. + * Otherwise, the window will be looked up considering + ``windowID`` as the following in order: 1) the "name" of the + window, as specified to ``window.open()``; 2) a javascript + variable which is a reference to a window; and 3) the title of the + window. This is the same ordered lookup performed by + ``selectWindow`` . + + + + 'windowID' is an identifier for the popup window, which can take on a number of different meanings + """ + self.do_command("selectPopUp", [windowID,]) + + + def deselect_pop_up(self): + """ + Selects the main window. Functionally equivalent to using + ``selectWindow()`` and specifying no value for + ``windowID``. + + """ + self.do_command("deselectPopUp", []) + + + def select_frame(self,locator): + """ + Selects a frame within the current window. (You may invoke this command + multiple times to select nested frames.) To select the parent frame, use + "relative=parent" as a locator; to select the top frame, use "relative=top". + You can also select a frame by its 0-based index number; select the first frame with + "index=0", or the third frame with "index=2". + + + You may also use a DOM expression to identify the frame you want directly, + like this: ``dom=frames["main"].frames["subframe"]`` + + + 'locator' is an element locator identifying a frame or iframe + """ + self.do_command("selectFrame", [locator,]) + + + def get_whether_this_frame_match_frame_expression(self,currentFrameString,target): + """ + Determine whether current/locator identify the frame containing this running code. + + + This is useful in proxy injection mode, where this code runs in every + browser frame and window, and sometimes the selenium server needs to identify + the "current" frame. In this case, when the test calls selectFrame, this + routine is called for each frame to figure out which one has been selected. + The selected frame will return true, while all others will return false. + + + 'currentFrameString' is starting frame + 'target' is new frame (which might be relative to the current one) + """ + return self.get_boolean("getWhetherThisFrameMatchFrameExpression", [currentFrameString,target,]) + + + def get_whether_this_window_match_window_expression(self,currentWindowString,target): + """ + Determine whether currentWindowString plus target identify the window containing this running code. + + + This is useful in proxy injection mode, where this code runs in every + browser frame and window, and sometimes the selenium server needs to identify + the "current" window. In this case, when the test calls selectWindow, this + routine is called for each window to figure out which one has been selected. + The selected window will return true, while all others will return false. + + + 'currentWindowString' is starting window + 'target' is new window (which might be relative to the current one, e.g., "_parent") + """ + return self.get_boolean("getWhetherThisWindowMatchWindowExpression", [currentWindowString,target,]) + + + def wait_for_pop_up(self,windowID,timeout): + """ + Waits for a popup window to appear and load up. + + 'windowID' is the JavaScript window "name" of the window that will appear (not the text of the title bar) If unspecified, or specified as "null", this command will wait for the first non-top window to appear (don't rely on this if you are working with multiple popups simultaneously). + 'timeout' is a timeout in milliseconds, after which the action will return with an error. If this value is not specified, the default Selenium timeout will be used. See the setTimeout() command. + """ + self.do_command("waitForPopUp", [windowID,timeout,]) + + + def choose_cancel_on_next_confirmation(self): + """ + + + By default, Selenium's overridden window.confirm() function will + return true, as if the user had manually clicked OK; after running + this command, the next call to confirm() will return false, as if + the user had clicked Cancel. Selenium will then resume using the + default behavior for future confirmations, automatically returning + true (OK) unless/until you explicitly call this command for each + confirmation. + + + + Take note - every time a confirmation comes up, you must + consume it with a corresponding getConfirmation, or else + the next selenium operation will fail. + + + + """ + self.do_command("chooseCancelOnNextConfirmation", []) + + + def choose_ok_on_next_confirmation(self): + """ + + + Undo the effect of calling chooseCancelOnNextConfirmation. Note + that Selenium's overridden window.confirm() function will normally automatically + return true, as if the user had manually clicked OK, so you shouldn't + need to use this command unless for some reason you need to change + your mind prior to the next confirmation. After any confirmation, Selenium will resume using the + default behavior for future confirmations, automatically returning + true (OK) unless/until you explicitly call chooseCancelOnNextConfirmation for each + confirmation. + + + + Take note - every time a confirmation comes up, you must + consume it with a corresponding getConfirmation, or else + the next selenium operation will fail. + + + + """ + self.do_command("chooseOkOnNextConfirmation", []) + + + def answer_on_next_prompt(self,answer): + """ + Instructs Selenium to return the specified answer string in response to + the next JavaScript prompt [window.prompt()]. + + 'answer' is the answer to give in response to the prompt pop-up + """ + self.do_command("answerOnNextPrompt", [answer,]) + + + def go_back(self): + """ + Simulates the user clicking the "back" button on their browser. + + """ + self.do_command("goBack", []) + + + def refresh(self): + """ + Simulates the user clicking the "Refresh" button on their browser. + + """ + self.do_command("refresh", []) + + + def close(self): + """ + Simulates the user clicking the "close" button in the titlebar of a popup + window or tab. + + """ + self.do_command("close", []) + + + def is_alert_present(self): + """ + Has an alert occurred? + + + + This function never throws an exception + + + + """ + return self.get_boolean("isAlertPresent", []) + + + def is_prompt_present(self): + """ + Has a prompt occurred? + + + + This function never throws an exception + + + + """ + return self.get_boolean("isPromptPresent", []) + + + def is_confirmation_present(self): + """ + Has confirm() been called? + + + + This function never throws an exception + + + + """ + return self.get_boolean("isConfirmationPresent", []) + + + def get_alert(self): + """ + Retrieves the message of a JavaScript alert generated during the previous action, or fail if there were no alerts. + + + Getting an alert has the same effect as manually clicking OK. If an + alert is generated but you do not consume it with getAlert, the next Selenium action + will fail. + + Under Selenium, JavaScript alerts will NOT pop up a visible alert + dialog. + + Selenium does NOT support JavaScript alerts that are generated in a + page's onload() event handler. In this case a visible dialog WILL be + generated and Selenium will hang until someone manually clicks OK. + + + """ + return self.get_string("getAlert", []) + + + def get_confirmation(self): + """ + Retrieves the message of a JavaScript confirmation dialog generated during + the previous action. + + + + By default, the confirm function will return true, having the same effect + as manually clicking OK. This can be changed by prior execution of the + chooseCancelOnNextConfirmation command. + + + + If an confirmation is generated but you do not consume it with getConfirmation, + the next Selenium action will fail. + + + + NOTE: under Selenium, JavaScript confirmations will NOT pop up a visible + dialog. + + + + NOTE: Selenium does NOT support JavaScript confirmations that are + generated in a page's onload() event handler. In this case a visible + dialog WILL be generated and Selenium will hang until you manually click + OK. + + + + """ + return self.get_string("getConfirmation", []) + + + def get_prompt(self): + """ + Retrieves the message of a JavaScript question prompt dialog generated during + the previous action. + + + Successful handling of the prompt requires prior execution of the + answerOnNextPrompt command. If a prompt is generated but you + do not get/verify it, the next Selenium action will fail. + + NOTE: under Selenium, JavaScript prompts will NOT pop up a visible + dialog. + + NOTE: Selenium does NOT support JavaScript prompts that are generated in a + page's onload() event handler. In this case a visible dialog WILL be + generated and Selenium will hang until someone manually clicks OK. + + + """ + return self.get_string("getPrompt", []) + + + def get_location(self): + """ + Gets the absolute URL of the current page. + + """ + return self.get_string("getLocation", []) + + + def get_title(self): + """ + Gets the title of the current page. + + """ + return self.get_string("getTitle", []) + + + def get_body_text(self): + """ + Gets the entire text of the page. + + """ + return self.get_string("getBodyText", []) + + + def get_value(self,locator): + """ + Gets the (whitespace-trimmed) value of an input field (or anything else with a value parameter). + For checkbox/radio elements, the value will be "on" or "off" depending on + whether the element is checked or not. + + 'locator' is an element locator + """ + return self.get_string("getValue", [locator,]) + + + def get_text(self,locator): + """ + Gets the text of an element. This works for any element that contains + text. This command uses either the textContent (Mozilla-like browsers) or + the innerText (IE-like browsers) of the element, which is the rendered + text shown to the user. + + 'locator' is an element locator + """ + return self.get_string("getText", [locator,]) + + + def highlight(self,locator): + """ + Briefly changes the backgroundColor of the specified element yellow. Useful for debugging. + + 'locator' is an element locator + """ + self.do_command("highlight", [locator,]) + + + def get_eval(self,script): + """ + Gets the result of evaluating the specified JavaScript snippet. The snippet may + have multiple lines, but only the result of the last line will be returned. + + + Note that, by default, the snippet will run in the context of the "selenium" + object itself, so ``this`` will refer to the Selenium object. Use ``window`` to + refer to the window of your application, e.g. ``window.document.getElementById('foo')`` + + If you need to use + a locator to refer to a single element in your application page, you can + use ``this.browserbot.findElement("id=foo")`` where "id=foo" is your locator. + + + 'script' is the JavaScript snippet to run + """ + return self.get_string("getEval", [script,]) + + + def is_checked(self,locator): + """ + Gets whether a toggle-button (checkbox/radio) is checked. Fails if the specified element doesn't exist or isn't a toggle-button. + + 'locator' is an element locator pointing to a checkbox or radio button + """ + return self.get_boolean("isChecked", [locator,]) + + + def get_table(self,tableCellAddress): + """ + Gets the text from a cell of a table. The cellAddress syntax + tableLocator.row.column, where row and column start at 0. + + 'tableCellAddress' is a cell address, e.g. "foo.1.4" + """ + return self.get_string("getTable", [tableCellAddress,]) + + + def get_selected_labels(self,selectLocator): + """ + Gets all option labels (visible text) for selected options in the specified select or multi-select element. + + 'selectLocator' is an element locator identifying a drop-down menu + """ + return self.get_string_array("getSelectedLabels", [selectLocator,]) + + + def get_selected_label(self,selectLocator): + """ + Gets option label (visible text) for selected option in the specified select element. + + 'selectLocator' is an element locator identifying a drop-down menu + """ + return self.get_string("getSelectedLabel", [selectLocator,]) + + + def get_selected_values(self,selectLocator): + """ + Gets all option values (value attributes) for selected options in the specified select or multi-select element. + + 'selectLocator' is an element locator identifying a drop-down menu + """ + return self.get_string_array("getSelectedValues", [selectLocator,]) + + + def get_selected_value(self,selectLocator): + """ + Gets option value (value attribute) for selected option in the specified select element. + + 'selectLocator' is an element locator identifying a drop-down menu + """ + return self.get_string("getSelectedValue", [selectLocator,]) + + + def get_selected_indexes(self,selectLocator): + """ + Gets all option indexes (option number, starting at 0) for selected options in the specified select or multi-select element. + + 'selectLocator' is an element locator identifying a drop-down menu + """ + return self.get_string_array("getSelectedIndexes", [selectLocator,]) + + + def get_selected_index(self,selectLocator): + """ + Gets option index (option number, starting at 0) for selected option in the specified select element. + + 'selectLocator' is an element locator identifying a drop-down menu + """ + return self.get_string("getSelectedIndex", [selectLocator,]) + + + def get_selected_ids(self,selectLocator): + """ + Gets all option element IDs for selected options in the specified select or multi-select element. + + 'selectLocator' is an element locator identifying a drop-down menu + """ + return self.get_string_array("getSelectedIds", [selectLocator,]) + + + def get_selected_id(self,selectLocator): + """ + Gets option element ID for selected option in the specified select element. + + 'selectLocator' is an element locator identifying a drop-down menu + """ + return self.get_string("getSelectedId", [selectLocator,]) + + + def is_something_selected(self,selectLocator): + """ + Determines whether some option in a drop-down menu is selected. + + 'selectLocator' is an element locator identifying a drop-down menu + """ + return self.get_boolean("isSomethingSelected", [selectLocator,]) + + + def get_select_options(self,selectLocator): + """ + Gets all option labels in the specified select drop-down. + + 'selectLocator' is an element locator identifying a drop-down menu + """ + return self.get_string_array("getSelectOptions", [selectLocator,]) + + + def get_attribute(self,attributeLocator): + """ + Gets the value of an element attribute. The value of the attribute may + differ across browsers (this is the case for the "style" attribute, for + example). + + 'attributeLocator' is an element locator followed by an @ sign and then the name of the attribute, e.g. "foo@bar" + """ + return self.get_string("getAttribute", [attributeLocator,]) + + + def is_text_present(self,pattern): + """ + Verifies that the specified text pattern appears somewhere on the rendered page shown to the user. + + 'pattern' is a pattern to match with the text of the page + """ + return self.get_boolean("isTextPresent", [pattern,]) + + + def is_element_present(self,locator): + """ + Verifies that the specified element is somewhere on the page. + + 'locator' is an element locator + """ + return self.get_boolean("isElementPresent", [locator,]) + + + def is_visible(self,locator): + """ + Determines if the specified element is visible. An + element can be rendered invisible by setting the CSS "visibility" + property to "hidden", or the "display" property to "none", either for the + element itself or one if its ancestors. This method will fail if + the element is not present. + + 'locator' is an element locator + """ + return self.get_boolean("isVisible", [locator,]) + + + def is_editable(self,locator): + """ + Determines whether the specified input element is editable, ie hasn't been disabled. + This method will fail if the specified element isn't an input element. + + 'locator' is an element locator + """ + return self.get_boolean("isEditable", [locator,]) + + + def get_all_buttons(self): + """ + Returns the IDs of all buttons on the page. + + + If a given button has no ID, it will appear as "" in this array. + + + """ + return self.get_string_array("getAllButtons", []) + + + def get_all_links(self): + """ + Returns the IDs of all links on the page. + + + If a given link has no ID, it will appear as "" in this array. + + + """ + return self.get_string_array("getAllLinks", []) + + + def get_all_fields(self): + """ + Returns the IDs of all input fields on the page. + + + If a given field has no ID, it will appear as "" in this array. + + + """ + return self.get_string_array("getAllFields", []) + + + def get_attribute_from_all_windows(self,attributeName): + """ + Returns every instance of some attribute from all known windows. + + 'attributeName' is name of an attribute on the windows + """ + return self.get_string_array("getAttributeFromAllWindows", [attributeName,]) + + + def dragdrop(self,locator,movementsString): + """ + deprecated - use dragAndDrop instead + + 'locator' is an element locator + 'movementsString' is offset in pixels from the current location to which the element should be moved, e.g., "+70,-300" + """ + self.do_command("dragdrop", [locator,movementsString,]) + + + def set_mouse_speed(self,pixels): + """ + Configure the number of pixels between "mousemove" events during dragAndDrop commands (default=10). + + Setting this value to 0 means that we'll send a "mousemove" event to every single pixel + in between the start location and the end location; that can be very slow, and may + cause some browsers to force the JavaScript to timeout. + + If the mouse speed is greater than the distance between the two dragged objects, we'll + just send one "mousemove" at the start location and then one final one at the end location. + + + 'pixels' is the number of pixels between "mousemove" events + """ + self.do_command("setMouseSpeed", [pixels,]) + + + def get_mouse_speed(self): + """ + Returns the number of pixels between "mousemove" events during dragAndDrop commands (default=10). + + """ + return self.get_number("getMouseSpeed", []) + + + def drag_and_drop(self,locator,movementsString): + """ + Drags an element a certain distance and then drops it + + 'locator' is an element locator + 'movementsString' is offset in pixels from the current location to which the element should be moved, e.g., "+70,-300" + """ + self.do_command("dragAndDrop", [locator,movementsString,]) + + + def drag_and_drop_to_object(self,locatorOfObjectToBeDragged,locatorOfDragDestinationObject): + """ + Drags an element and drops it on another element + + 'locatorOfObjectToBeDragged' is an element to be dragged + 'locatorOfDragDestinationObject' is an element whose location (i.e., whose center-most pixel) will be the point where locatorOfObjectToBeDragged is dropped + """ + self.do_command("dragAndDropToObject", [locatorOfObjectToBeDragged,locatorOfDragDestinationObject,]) + + + def window_focus(self): + """ + Gives focus to the currently selected window + + """ + self.do_command("windowFocus", []) + + + def window_maximize(self): + """ + Resize currently selected window to take up the entire screen + + """ + self.do_command("windowMaximize", []) + + + def get_all_window_ids(self): + """ + Returns the IDs of all windows that the browser knows about. + + """ + return self.get_string_array("getAllWindowIds", []) + + + def get_all_window_names(self): + """ + Returns the names of all windows that the browser knows about. + + """ + return self.get_string_array("getAllWindowNames", []) + + + def get_all_window_titles(self): + """ + Returns the titles of all windows that the browser knows about. + + """ + return self.get_string_array("getAllWindowTitles", []) + + + def get_html_source(self): + """ + Returns the entire HTML source between the opening and + closing "html" tags. + + """ + return self.get_string("getHtmlSource", []) + + + def set_cursor_position(self,locator,position): + """ + Moves the text cursor to the specified position in the given input element or textarea. + This method will fail if the specified element isn't an input element or textarea. + + 'locator' is an element locator pointing to an input element or textarea + 'position' is the numerical position of the cursor in the field; position should be 0 to move the position to the beginning of the field. You can also set the cursor to -1 to move it to the end of the field. + """ + self.do_command("setCursorPosition", [locator,position,]) + + + def get_element_index(self,locator): + """ + Get the relative index of an element to its parent (starting from 0). The comment node and empty text node + will be ignored. + + 'locator' is an element locator pointing to an element + """ + return self.get_number("getElementIndex", [locator,]) + + + def is_ordered(self,locator1,locator2): + """ + Check if these two elements have same parent and are ordered siblings in the DOM. Two same elements will + not be considered ordered. + + 'locator1' is an element locator pointing to the first element + 'locator2' is an element locator pointing to the second element + """ + return self.get_boolean("isOrdered", [locator1,locator2,]) + + + def get_element_position_left(self,locator): + """ + Retrieves the horizontal position of an element + + 'locator' is an element locator pointing to an element OR an element itself + """ + return self.get_number("getElementPositionLeft", [locator,]) + + + def get_element_position_top(self,locator): + """ + Retrieves the vertical position of an element + + 'locator' is an element locator pointing to an element OR an element itself + """ + return self.get_number("getElementPositionTop", [locator,]) + + + def get_element_width(self,locator): + """ + Retrieves the width of an element + + 'locator' is an element locator pointing to an element + """ + return self.get_number("getElementWidth", [locator,]) + + + def get_element_height(self,locator): + """ + Retrieves the height of an element + + 'locator' is an element locator pointing to an element + """ + return self.get_number("getElementHeight", [locator,]) + + + def get_cursor_position(self,locator): + """ + Retrieves the text cursor position in the given input element or textarea; beware, this may not work perfectly on all browsers. + + + Specifically, if the cursor/selection has been cleared by JavaScript, this command will tend to + return the position of the last location of the cursor, even though the cursor is now gone from the page. This is filed as SEL-243. + + This method will fail if the specified element isn't an input element or textarea, or there is no cursor in the element. + + 'locator' is an element locator pointing to an input element or textarea + """ + return self.get_number("getCursorPosition", [locator,]) + + + def get_expression(self,expression): + """ + Returns the specified expression. + + + This is useful because of JavaScript preprocessing. + It is used to generate commands like assertExpression and waitForExpression. + + + 'expression' is the value to return + """ + return self.get_string("getExpression", [expression,]) + + + def get_xpath_count(self,xpath): + """ + Returns the number of nodes that match the specified xpath, eg. "//table" would give + the number of tables. + + 'xpath' is the xpath expression to evaluate. do NOT wrap this expression in a 'count()' function; we will do that for you. + """ + return self.get_number("getXpathCount", [xpath,]) + + + def assign_id(self,locator,identifier): + """ + Temporarily sets the "id" attribute of the specified element, so you can locate it in the future + using its ID rather than a slow/complicated XPath. This ID will disappear once the page is + reloaded. + + 'locator' is an element locator pointing to an element + 'identifier' is a string to be used as the ID of the specified element + """ + self.do_command("assignId", [locator,identifier,]) + + + def allow_native_xpath(self,allow): + """ + Specifies whether Selenium should use the native in-browser implementation + of XPath (if any native version is available); if you pass "false" to + this function, we will always use our pure-JavaScript xpath library. + Using the pure-JS xpath library can improve the consistency of xpath + element locators between different browser vendors, but the pure-JS + version is much slower than the native implementations. + + 'allow' is boolean, true means we'll prefer to use native XPath; false means we'll only use JS XPath + """ + self.do_command("allowNativeXpath", [allow,]) + + + def ignore_attributes_without_value(self,ignore): + """ + Specifies whether Selenium will ignore xpath attributes that have no + value, i.e. are the empty string, when using the non-native xpath + evaluation engine. You'd want to do this for performance reasons in IE. + However, this could break certain xpaths, for example an xpath that looks + for an attribute whose value is NOT the empty string. + + The hope is that such xpaths are relatively rare, but the user should + have the option of using them. Note that this only influences xpath + evaluation when using the ajaxslt engine (i.e. not "javascript-xpath"). + + 'ignore' is boolean, true means we'll ignore attributes without value at the expense of xpath "correctness"; false means we'll sacrifice speed for correctness. + """ + self.do_command("ignoreAttributesWithoutValue", [ignore,]) + + + def wait_for_condition(self,script,timeout): + """ + Runs the specified JavaScript snippet repeatedly until it evaluates to "true". + The snippet may have multiple lines, but only the result of the last line + will be considered. + + + Note that, by default, the snippet will be run in the runner's test window, not in the window + of your application. To get the window of your application, you can use + the JavaScript snippet ``selenium.browserbot.getCurrentWindow()``, and then + run your JavaScript in there + + + 'script' is the JavaScript snippet to run + 'timeout' is a timeout in milliseconds, after which this command will return with an error + """ + self.do_command("waitForCondition", [script,timeout,]) + + + def set_timeout(self,timeout): + """ + Specifies the amount of time that Selenium will wait for actions to complete. + + + Actions that require waiting include "open" and the "waitFor\*" actions. + + The default timeout is 30 seconds. + + 'timeout' is a timeout in milliseconds, after which the action will return with an error + """ + self.do_command("setTimeout", [timeout,]) + + + def wait_for_page_to_load(self,timeout): + """ + Waits for a new page to load. + + + You can use this command instead of the "AndWait" suffixes, "clickAndWait", "selectAndWait", "typeAndWait" etc. + (which are only available in the JS API). + + Selenium constantly keeps track of new pages loading, and sets a "newPageLoaded" + flag when it first notices a page load. Running any other Selenium command after + turns the flag to false. Hence, if you want to wait for a page to load, you must + wait immediately after a Selenium command that caused a page-load. + + + 'timeout' is a timeout in milliseconds, after which this command will return with an error + """ + self.do_command("waitForPageToLoad", [timeout,]) + + + def wait_for_frame_to_load(self,frameAddress,timeout): + """ + Waits for a new frame to load. + + + Selenium constantly keeps track of new pages and frames loading, + and sets a "newPageLoaded" flag when it first notices a page load. + + + See waitForPageToLoad for more information. + + 'frameAddress' is FrameAddress from the server side + 'timeout' is a timeout in milliseconds, after which this command will return with an error + """ + self.do_command("waitForFrameToLoad", [frameAddress,timeout,]) + + + def get_cookie(self): + """ + Return all cookies of the current page under test. + + """ + return self.get_string("getCookie", []) + + + def get_cookie_by_name(self,name): + """ + Returns the value of the cookie with the specified name, or throws an error if the cookie is not present. + + 'name' is the name of the cookie + """ + return self.get_string("getCookieByName", [name,]) + + + def is_cookie_present(self,name): + """ + Returns true if a cookie with the specified name is present, or false otherwise. + + 'name' is the name of the cookie + """ + return self.get_boolean("isCookiePresent", [name,]) + + + def create_cookie(self,nameValuePair,optionsString): + """ + Create a new cookie whose path and domain are same with those of current page + under test, unless you specified a path for this cookie explicitly. + + 'nameValuePair' is name and value of the cookie in a format "name=value" + 'optionsString' is options for the cookie. Currently supported options include 'path', 'max_age' and 'domain'. the optionsString's format is "path=/path/, max_age=60, domain=.foo.com". The order of options are irrelevant, the unit of the value of 'max_age' is second. Note that specifying a domain that isn't a subset of the current domain will usually fail. + """ + self.do_command("createCookie", [nameValuePair,optionsString,]) + + + def delete_cookie(self,name,optionsString): + """ + Delete a named cookie with specified path and domain. Be careful; to delete a cookie, you + need to delete it using the exact same path and domain that were used to create the cookie. + If the path is wrong, or the domain is wrong, the cookie simply won't be deleted. Also + note that specifying a domain that isn't a subset of the current domain will usually fail. + + Since there's no way to discover at runtime the original path and domain of a given cookie, + we've added an option called 'recurse' to try all sub-domains of the current domain with + all paths that are a subset of the current path. Beware; this option can be slow. In + big-O notation, it operates in O(n\*m) time, where n is the number of dots in the domain + name and m is the number of slashes in the path. + + 'name' is the name of the cookie to be deleted + 'optionsString' is options for the cookie. Currently supported options include 'path', 'domain' and 'recurse.' The optionsString's format is "path=/path/, domain=.foo.com, recurse=true". The order of options are irrelevant. Note that specifying a domain that isn't a subset of the current domain will usually fail. + """ + self.do_command("deleteCookie", [name,optionsString,]) + + + def delete_all_visible_cookies(self): + """ + Calls deleteCookie with recurse=true on all cookies visible to the current page. + As noted on the documentation for deleteCookie, recurse=true can be much slower + than simply deleting the cookies using a known domain/path. + + """ + self.do_command("deleteAllVisibleCookies", []) + + + def set_browser_log_level(self,logLevel): + """ + Sets the threshold for browser-side logging messages; log messages beneath this threshold will be discarded. + Valid logLevel strings are: "debug", "info", "warn", "error" or "off". + To see the browser logs, you need to + either show the log window in GUI mode, or enable browser-side logging in Selenium RC. + + 'logLevel' is one of the following: "debug", "info", "warn", "error" or "off" + """ + self.do_command("setBrowserLogLevel", [logLevel,]) + + + def run_script(self,script): + """ + Creates a new "script" tag in the body of the current test window, and + adds the specified text into the body of the command. Scripts run in + this way can often be debugged more easily than scripts executed using + Selenium's "getEval" command. Beware that JS exceptions thrown in these script + tags aren't managed by Selenium, so you should probably wrap your script + in try/catch blocks if there is any chance that the script will throw + an exception. + + 'script' is the JavaScript snippet to run + """ + self.do_command("runScript", [script,]) + + + def add_location_strategy(self,strategyName,functionDefinition): + """ + Defines a new function for Selenium to locate elements on the page. + For example, + if you define the strategy "foo", and someone runs click("foo=blah"), we'll + run your function, passing you the string "blah", and click on the element + that your function + returns, or throw an "Element not found" error if your function returns null. + + We'll pass three arguments to your function: + + * locator: the string the user passed in + * inWindow: the currently selected window + * inDocument: the currently selected document + + + The function must return null if the element can't be found. + + 'strategyName' is the name of the strategy to define; this should use only letters [a-zA-Z] with no spaces or other punctuation. + 'functionDefinition' is a string defining the body of a function in JavaScript. For example: ``return inDocument.getElementById(locator);`` + """ + self.do_command("addLocationStrategy", [strategyName,functionDefinition,]) + + + def capture_entire_page_screenshot(self,filename,kwargs): + """ + Saves the entire contents of the current window canvas to a PNG file. + Contrast this with the captureScreenshot command, which captures the + contents of the OS viewport (i.e. whatever is currently being displayed + on the monitor), and is implemented in the RC only. Currently this only + works in Firefox when running in chrome mode, and in IE non-HTA using + the EXPERIMENTAL "Snapsie" utility. The Firefox implementation is mostly + borrowed from the Screengrab! Firefox extension. Please see + http://www.screengrab.org and http://snapsie.sourceforge.net/ for + details. + + 'filename' is the path to the file to persist the screenshot as. No filename extension will be appended by default. Directories will not be created if they do not exist, and an exception will be thrown, possibly by native code. + 'kwargs' is a kwargs string that modifies the way the screenshot is captured. Example: "background=#CCFFDD" . Currently valid options: + * background + the background CSS for the HTML document. This may be useful to set for capturing screenshots of less-than-ideal layouts, for example where absolute positioning causes the calculation of the canvas dimension to fail and a black background is exposed (possibly obscuring black text). + + + """ + self.do_command("captureEntirePageScreenshot", [filename,kwargs,]) + + + def rollup(self,rollupName,kwargs): + """ + Executes a command rollup, which is a series of commands with a unique + name, and optionally arguments that control the generation of the set of + commands. If any one of the rolled-up commands fails, the rollup is + considered to have failed. Rollups may also contain nested rollups. + + 'rollupName' is the name of the rollup command + 'kwargs' is keyword arguments string that influences how the rollup expands into commands + """ + self.do_command("rollup", [rollupName,kwargs,]) + + + def add_script(self,scriptContent,scriptTagId): + """ + Loads script content into a new script tag in the Selenium document. This + differs from the runScript command in that runScript adds the script tag + to the document of the AUT, not the Selenium document. The following + entities in the script content are replaced by the characters they + represent: + + < + > + & + + The corresponding remove command is removeScript. + + 'scriptContent' is the Javascript content of the script to add + 'scriptTagId' is (optional) the id of the new script tag. If specified, and an element with this id already exists, this operation will fail. + """ + self.do_command("addScript", [scriptContent,scriptTagId,]) + + + def remove_script(self,scriptTagId): + """ + Removes a script tag from the Selenium document identified by the given + id. Does nothing if the referenced tag doesn't exist. + + 'scriptTagId' is the id of the script element to remove. + """ + self.do_command("removeScript", [scriptTagId,]) + + + def use_xpath_library(self,libraryName): + """ + Allows choice of one of the available libraries. + + 'libraryName' is name of the desired library Only the following three can be chosen: + * "ajaxslt" - Google's library + * "javascript-xpath" - Cybozu Labs' faster library + * "default" - The default library. Currently the default library is "ajaxslt" . + + If libraryName isn't one of these three, then no change will be made. + """ + self.do_command("useXpathLibrary", [libraryName,]) + + + def set_context(self,context): + """ + Writes a message to the status bar and adds a note to the browser-side + log. + + 'context' is the message to be sent to the browser + """ + self.do_command("setContext", [context,]) + + + def attach_file(self,fieldLocator,fileLocator): + """ + Sets a file input (upload) field to the file listed in fileLocator + + 'fieldLocator' is an element locator + 'fileLocator' is a URL pointing to the specified file. Before the file can be set in the input field (fieldLocator), Selenium RC may need to transfer the file to the local machine before attaching the file in a web page form. This is common in selenium grid configurations where the RC server driving the browser is not the same machine that started the test. Supported Browsers: Firefox ("\*chrome") only. + """ + self.do_command("attachFile", [fieldLocator,fileLocator,]) + + + def capture_screenshot(self,filename): + """ + Captures a PNG screenshot to the specified file. + + 'filename' is the absolute path to the file to be written, e.g. "c:\blah\screenshot.png" + """ + self.do_command("captureScreenshot", [filename,]) + + + def capture_screenshot_to_string(self): + """ + Capture a PNG screenshot. It then returns the file as a base 64 encoded string. + + """ + return self.get_string("captureScreenshotToString", []) + + + def captureNetworkTraffic(self, type): + """ + Returns the network traffic seen by the browser, including headers, AJAX requests, status codes, and timings. When this function is called, the traffic log is cleared, so the returned content is only the traffic seen since the last call. + + 'type' is The type of data to return the network traffic as. Valid values are: json, xml, or plain. + """ + return self.get_string("captureNetworkTraffic", [type,]) + + def addCustomRequestHeader(self, key, value): + """ + Tells the Selenium server to add the specificed key and value as a custom outgoing request header. This only works if the browser is configured to use the built in Selenium proxy. + + 'key' the header name. + 'value' the header value. + """ + return self.do_command("addCustomRequestHeader", [key,value,]) + + def capture_entire_page_screenshot_to_string(self,kwargs): + """ + Downloads a screenshot of the browser current window canvas to a + based 64 encoded PNG file. The \ *entire* windows canvas is captured, + including parts rendered outside of the current view port. + + Currently this only works in Mozilla and when running in chrome mode. + + 'kwargs' is A kwargs string that modifies the way the screenshot is captured. Example: "background=#CCFFDD". This may be useful to set for capturing screenshots of less-than-ideal layouts, for example where absolute positioning causes the calculation of the canvas dimension to fail and a black background is exposed (possibly obscuring black text). + """ + return self.get_string("captureEntirePageScreenshotToString", [kwargs,]) + + + def shut_down_selenium_server(self): + """ + Kills the running Selenium Server and all browser sessions. After you run this command, you will no longer be able to send + commands to the server; you can't remotely start the server once it has been stopped. Normally + you should prefer to run the "stop" command, which terminates the current browser session, rather than + shutting down the entire server. + + """ + self.do_command("shutDownSeleniumServer", []) + + + def retrieve_last_remote_control_logs(self): + """ + Retrieve the last messages logged on a specific remote control. Useful for error reports, especially + when running multiple remote controls in a distributed environment. The maximum number of log messages + that can be retrieve is configured on remote control startup. + + """ + return self.get_string("retrieveLastRemoteControlLogs", []) + + + def key_down_native(self,keycode): + """ + Simulates a user pressing a key (without releasing it yet) by sending a native operating system keystroke. + This function uses the java.awt.Robot class to send a keystroke; this more accurately simulates typing + a key on the keyboard. It does not honor settings from the shiftKeyDown, controlKeyDown, altKeyDown and + metaKeyDown commands, and does not target any particular HTML element. To send a keystroke to a particular + element, focus on the element first before running this command. + + 'keycode' is an integer keycode number corresponding to a java.awt.event.KeyEvent; note that Java keycodes are NOT the same thing as JavaScript keycodes! + """ + self.do_command("keyDownNative", [keycode,]) + + + def key_up_native(self,keycode): + """ + Simulates a user releasing a key by sending a native operating system keystroke. + This function uses the java.awt.Robot class to send a keystroke; this more accurately simulates typing + a key on the keyboard. It does not honor settings from the shiftKeyDown, controlKeyDown, altKeyDown and + metaKeyDown commands, and does not target any particular HTML element. To send a keystroke to a particular + element, focus on the element first before running this command. + + 'keycode' is an integer keycode number corresponding to a java.awt.event.KeyEvent; note that Java keycodes are NOT the same thing as JavaScript keycodes! + """ + self.do_command("keyUpNative", [keycode,]) + + + def key_press_native(self,keycode): + """ + Simulates a user pressing and releasing a key by sending a native operating system keystroke. + This function uses the java.awt.Robot class to send a keystroke; this more accurately simulates typing + a key on the keyboard. It does not honor settings from the shiftKeyDown, controlKeyDown, altKeyDown and + metaKeyDown commands, and does not target any particular HTML element. To send a keystroke to a particular + element, focus on the element first before running this command. + + 'keycode' is an integer keycode number corresponding to a java.awt.event.KeyEvent; note that Java keycodes are NOT the same thing as JavaScript keycodes! + """ + self.do_command("keyPressNative", [keycode,]) + diff --git a/mysite/ck/serializers.py b/mysite/ck/serializers.py new file mode 100644 index 0000000..04c3e67 --- /dev/null +++ b/mysite/ck/serializers.py @@ -0,0 +1,65 @@ +import datetime + +from django.urls import reverse + +from rest_framework import serializers + +from .models import * + +class VEVENT_Serializer(serializers.ModelSerializer): + title = serializers.CharField(source='SUMMARY') + start = serializers.DateTimeField(source='DTSTART') + + # end = serializers.CharField(source='DTEND') + end = serializers.SerializerMethodField() + className = serializers.SerializerMethodField() + url = serializers.SerializerMethodField() + description = serializers.SerializerMethodField() + # allDay = serializers.SerializerMethodField() + + def get_end(self, obj): + x = obj.DURATION + return obj.DTSTART + datetime.timedelta(hours=x.hour, minutes=x.minute, seconds=x.second) + + def get_className(self, obj): + return 'c%d' % obj.mode + + def get_url(self, obj): + # print(obj.treatment.id) + return reverse('event-update', + kwargs={'pk': obj.id}, + ) + return reverse('treatment-detail', + # args=[obj.treatment.id], + kwargs={'object_id': obj.treatment.id}, + ) + + def get_description(self, obj): + return None + + t = obj.treatment + desc = t.patient.medical_records + if t.surgeon: + desc += ' '+t.surgeon.name + elif t.oncologist: + desc += ' '+t.oncologist.name + print(desc) + return desc + + def get_allDay(self, obj): + return obj.DTSTART.hour < 8 + + class Meta: + model = VEVENT + fields = ('title', 'start', 'end', 'id', 'className', 'url', 'description') + + +class PatientSerializer(serializers.ModelSerializer): + # id = serializers.IntegerField(read_only=True) + + class Meta: + model = Patient + fields = '__all__' + # fields = ( + # 'id', 'name', + # ) \ No newline at end of file diff --git a/mysite/ck/tables.py b/mysite/ck/tables.py new file mode 100644 index 0000000..90c548f --- /dev/null +++ b/mysite/ck/tables.py @@ -0,0 +1,12 @@ +import django_tables2 as tables +from .models import * + +class PatientTable(tables.Table): + class Meta: + model = Patient + # template_name = "django_tables2/bootstrap.html" + template_name = "django_tables2/bootstrap4.html" + # fields = ("name", ) + + + # attrs = {"class": "table"} \ No newline at end of file diff --git a/mysite/ck/templates/base.html b/mysite/ck/templates/base.html new file mode 100755 index 0000000..a05d60c --- /dev/null +++ b/mysite/ck/templates/base.html @@ -0,0 +1,211 @@ +{% load static %} +{% with openicon='http://www.ntuh.net/open_icon_library-full/' beta=2 open_icon_library='http://www.ntuh.net/open_icon_library-full/' %} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {% block head %}{% endblock %} + + {% block title %}NTUH CyberKnife{% endblock %} + + +
+
+ {% block topsection %} + NTUH CyberKnife +
+
+ {% if user.is_authenticated %} + {{ user.username }} 登出 + {% else %} + 登入 + {% endif %} +
+
+ {% endblock %} +
+
+
+ + {% block pre_content %}{% endblock %} + {% block content %}{% endblock %} +
+
+
+ + +
+ {% block menu %} + {% endblock %} +

NTUHCK

+ +

Event

+ +

Patient

+ +

Treatment

+ +

Calculator

+ +
+ {% block leftcolumn %}{% endblock %} +
+ + +
+ + + + + + + + +{% endwith %} diff --git a/mysite/ck/templates/calculator/ci.html b/mysite/ck/templates/calculator/ci.html new file mode 100644 index 0000000..7a938a5 --- /dev/null +++ b/mysite/ck/templates/calculator/ci.html @@ -0,0 +1,84 @@ +{% extends "base.html" %} +{#% load endless %#} +{% load static %} + +{% block head %} + + + + + + + +{% endblock %} + + +{% block content %} + +
+ +

CI/nCI

+
+
+ + +
+ {% csrf_token %} + {{ form.as_p }} + + + + + + + +
+ +
+
+ + + + + + + + + + + + +
TVPIV{{result.TVPIV}}
CI{{result.CI}}
nCI{{result.nCI}}
+ +
+ + + + + + +{% endblock %} + diff --git a/mysite/ck/templates/calculator/prescription.html b/mysite/ck/templates/calculator/prescription.html new file mode 100644 index 0000000..88c2069 --- /dev/null +++ b/mysite/ck/templates/calculator/prescription.html @@ -0,0 +1,90 @@ +{% extends "base.html" %} +{#% load endless %#} +{% load static %} + +{% block head %} + + + + + + + +{% endblock %} + + +{% block content %} + +
+ +

Prescription dose

+
+
+ + +
+ {% csrf_token %} + {{ form.as_p }} + + + + + + + +
+ +
+
+ + + + + + + + + + + + + {% for k,v in result.items %} + + + + + + + + + {% endfor %} + +
Gy/2/3/4/5
{{k}}{{v.0}}{{v.1}}{{v.2}}{{v.3}}{{v.4}}
+ +
+ +{% endblock %} + diff --git a/mysite/ck/templates/calendar/followup.html b/mysite/ck/templates/calendar/followup.html new file mode 100755 index 0000000..1e14b8c --- /dev/null +++ b/mysite/ck/templates/calendar/followup.html @@ -0,0 +1,257 @@ + + + + + + + + + + +Event Calendar + + + + + + + + +
+ +
+ +NTUH CyberKnife + +
+ {% if user.is_authenticated %} + {{ user.username }} 登出 + {% else %} + 登入 + {% endif %} +
+ +
+ +
+
+ +
+
+
+ + + + + +
+ + + diff --git a/mysite/ck/templates/calendar/index.html b/mysite/ck/templates/calendar/index.html new file mode 100755 index 0000000..f81a83b --- /dev/null +++ b/mysite/ck/templates/calendar/index.html @@ -0,0 +1,234 @@ +{% extends "base.html" %} +{% load static %} + +{% block head %} + + + + + + + + + + + + + + + + + + + + + + +{% endblock %} + +{% block title %} + Calendar +{% endblock %} + +{% block leftcolumn %} + Check All +
+
+ +{% endblock %} + +{% block content %} +
+
+
+ +
+
+
+ +
+ +{% endblock %} diff --git a/mysite/ck/templates/calendar/index.html.20100224 b/mysite/ck/templates/calendar/index.html.20100224 new file mode 100755 index 0000000..6f9734e --- /dev/null +++ b/mysite/ck/templates/calendar/index.html.20100224 @@ -0,0 +1,245 @@ + + + + + + + + + +Event Calendar + + + + + + + + +
+ +
+ +NTUH CyberKnife + +
+ {% if user.is_authenticated %} + {{ user.username }} 登出 + {% else %} + 登入 + {% endif %} +
+ +
+ +
+
+ +
+
+
+ + + + + +
+ + + diff --git a/mysite/ck/templates/calendar/index.html.20100927 b/mysite/ck/templates/calendar/index.html.20100927 new file mode 100755 index 0000000..848225f --- /dev/null +++ b/mysite/ck/templates/calendar/index.html.20100927 @@ -0,0 +1,129 @@ + + + + + + + + + + + + + + + +
+ +
+ +NTUH CyberKnife + +
+ {% if user.is_authenticated %} + {{ user.username }} 登出 + {% else %} + 登入 + {% endif %} +
+ +
+ +
+ +
+ + +
+
+
+ + + + + +
+ + + + diff --git a/mysite/ck/templates/calendar/index2.html b/mysite/ck/templates/calendar/index2.html new file mode 100755 index 0000000..7dfdff6 --- /dev/null +++ b/mysite/ck/templates/calendar/index2.html @@ -0,0 +1,163 @@ + +Test Calendar + + + + + + +
+
+
+ + diff --git a/mysite/ck/templates/ck/below.html b/mysite/ck/templates/ck/below.html new file mode 100755 index 0000000..587e1b5 --- /dev/null +++ b/mysite/ck/templates/ck/below.html @@ -0,0 +1,39 @@ +{% extends "base.html" %} + +{% block title %} +Dojo: Hello World! +{% endblock %} + +{% block head %} + + +{% endblock %} + +{% block content %} + +Please enter your name: +{% endblock %} diff --git a/mysite/ck/templates/ck/brief_history.html b/mysite/ck/templates/ck/brief_history.html new file mode 100755 index 0000000..3215282 --- /dev/null +++ b/mysite/ck/templates/ck/brief_history.html @@ -0,0 +1,131 @@ +{% load calculate_age %} +{% load stack %} + + + + + Brief History + + +
+{{treatment.patient.medical_records}} {{treatment.patient.name}} {{treatment.patient.birthday}} + + + + + + + + + + +
Age: {{treatment.patient.birthday|age}}Birthday ( y / m / d ): {{treatment.patient.birthday}}Sex: {{treatment.patient.get_gender_display}}NativeDate: {% now "Y-m-d" %}
+Address: {{treatment.patient.address}}
+Telephone number: {{treatment.patient.phone}}
+Referral: {{treatment.surgeon}} {{treatment.referral}}
+
+Diagnosis: {{treatment.icd9}}, {{treatment.other_diagnosis}}
+
+Past and family history
+
+Pathology / cytology exam
+ + + + + + + + {% for path in treatment.patient.pathexam_set.all|dictsort:"path_code" %} + + + + + + {% endfor %} + + + + + + +
ç—…ç†è™Ÿå ±å‘Šæ—¥å ±å‘Š
{{ path.path_code }}{{ path.report_date }}{{ path.report }}
   
+
+Chief complaint and history
+{{treatment.chief_complaint}} +
+Laboratory data
+
+Image
+
+Prognostic factor(s)
+
+ + + + + + + + + + +
Stage(TNM)
+ + + + + + + + + + +
BSA: {{ treatment.patient.height|stnew|stpush:treatment.patient.height|stpush:treatment.patient.weight|stmult|stpush:3600|stdiv|stsqrt|stget|floatformat:3 }}BH{{treatment.patient.height}} cmBW{{treatment.patient.weight}} Kg
+ + + + + + + + + +
PerformanceKarnofsky{{treatment.karnofsky_score}}%ECOG
+
+Past radiotherapy & chemotherapy history
+ + + + + + + + + {% for prior in treatment.patient.priortreatment_set.all|dictsort:"date" %} + + + + + + + {% endfor %} + + + + + + + +
DateTreatmentDose(cGy)Memo
{{ prior.date }}{{ prior.get_treatment_display }}{{ prior.dose }}{{ prior.memo }}
    
+
+Treatment plan ( curative / palliative )
+
+ + + diff --git a/mysite/ck/templates/ck/followup_confirm_delete.html b/mysite/ck/templates/ck/followup_confirm_delete.html new file mode 100755 index 0000000..2336fa5 --- /dev/null +++ b/mysite/ck/templates/ck/followup_confirm_delete.html @@ -0,0 +1,13 @@ +{% extends "base.html" %} + +{% block title %} +Confirm delete +{% endblock %} + +{% block content %} +

Confirm delete {{object.name}}

+
{% csrf_token %} +

Are you sure?

+ +
+{% endblock %} diff --git a/mysite/ck/templates/ck/followup_form.html b/mysite/ck/templates/ck/followup_form.html new file mode 100755 index 0000000..c1064d6 --- /dev/null +++ b/mysite/ck/templates/ck/followup_form.html @@ -0,0 +1,66 @@ +{% extends "base.html" %} + +{% block head %} + +{% endblock %} + +{% block title %} + Follow-up Form +{% endblock %} + +{% block content %} + + {% if object %} + {{object.patient}} {{object.patient.medical_records}} +

Update follow-up

+ {% else %} + {{patient}} {{patient.medical_records}} +

Create follow-up

+ {% endif %} + + {% if form.errors %} + Please correct the following error{{ form.errors|pluralize }}: + {% endif %} + +
{% csrf_token %} +

{{form.patient.label_tag}}{{form.patient.errors}}

+

{{form.date.label_tag}}{{form.date}}{{form.date.errors}}

+

{{form.memo.label_tag}}{{form.memo}}{{form.memo.errors}}

+ +
+ + + + {% if object %} + Return to patient + {% else %} + Return to patient + {% endif %} + +{% endblock %} \ No newline at end of file diff --git a/mysite/ck/templates/ck/followup_image_long.html b/mysite/ck/templates/ck/followup_image_long.html new file mode 100755 index 0000000..fc5238d --- /dev/null +++ b/mysite/ck/templates/ck/followup_image_long.html @@ -0,0 +1,67 @@ +{% extends "base.html" %} + +{% block title %} +Long image follow-up +{% endblock %} + +{% block content %} +

Long image follow-up

+ + + + + + + + + + + + + + + + + + + + + + {% for patient, days, tdate, idate, vdate in results %} + + + + + + + + + + + + {% ifequal idate vdate %} + + {% else %} + + {% endifequal %} + + + + + + + {% endfor %} + +
No.å§“å病歷號性別生日地å€è¨ºæ–·èº«ä»½è­‰è™Ÿè¿½è¹¤æ—¥æ•¸æ²»ç™‚日期追蹤日期最後輸入測é‡
{{ forloop.counter }}{{ patient.name }}{{ patient.medical_records }}{{ patient.get_gender_display }}{{ patient.birthday }}{{ patient.address }} + {% for treatment in patient.treatment_set.all %} + {{ treatment.icd9 }}
+ {% endfor %} +
{{ patient.id_cards }}{{ days }}{{ tdate }}{{ idate }}{{ idate }}{{ vdate }}Measure
+{% endblock %} \ No newline at end of file diff --git a/mysite/ck/templates/ck/followup_new_volume.html b/mysite/ck/templates/ck/followup_new_volume.html new file mode 100755 index 0000000..9a0d59b --- /dev/null +++ b/mysite/ck/templates/ck/followup_new_volume.html @@ -0,0 +1,134 @@ +{% extends "base.html" %} + +{% block head %} + +{% endblock %} + + +{% block title %} +Follow-up new volume +{% endblock %} + +{% block content %} +

Follow-up new volume

+ + + + + + + + + + + + + + + + + + + + + + +
Patient ID{{ patient.id }}å§“å{{ patient.name }}病歷號{{ patient.medical_records }}性別{{ patient.get_gender_display }}生日{{ patient.birthday }}
地å€{{ patient.address }}電話{{ patient.phone }}身份證號{{ patient.id_cards }}Memo{{ patient.memo }} + {% if patient.dead %} + {{patient.dead}}已死亡 + {% endif %} +
身高(cm){{ patient.height }}é«”é‡(kg){{ patient.weight }}
+
+ {% for treatment in patient.treatment_set.all %} + + + + + + + + + + + + + + + + {% for lesion in treatment.lesion_set.all %} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {% for followup in lesion.lesionfollow_set.all %} + + + + + + + + + + + + + + {% endfor %} + {% endfor %} + +
Lesion IDTarget LocationAnatomic SublocationPathologyDateTarget Volume (mm3)Prescription Dose (cGy)Number of FractionsPrescription Isodose Curve
{{ lesion.id }}{{ lesion.sub_location.target_location }}{{ lesion.sub_location }}{{ lesion.pathology }}{%ifequal lesion.start_date lesion.end_date%}{{lesion.end_date}}{%else%}{{lesion.start_date}} ~ {{lesion.end_date|date:"m-d"}}{%endifequal%}{{ lesion.volume }}{{ lesion.dose }}{{ lesion.fractions }}{{ lesion.iso_dose_curve }}%
Follow IDDateFollowup volume (mm3)A (mm)B (mm)C (mm)MemoDelete
{{ followup.id }}{{ followup.Date }}{{ followup.Volume }}{{ followup.A }}{{ followup.B }}{{ followup.C }}{{ followup.Memo }} + Delete +
+ {% endfor %} +
+
{% csrf_token %} +

{{form.Lesion.label_tag}} + + {{form.Lesion.errors}}

+

{{form.Date.label_tag}}{{form.Date.errors}}

+

{{form.Volume.label_tag}}{{form.Volume}}{{form.Volume.errors}}

+

{{form.A.label_tag}}{{form.A}}{{form.A.errors}}

+

{{form.B.label_tag}}{{form.B}}{{form.B.errors}}

+

{{form.C.label_tag}}{{form.C}}{{form.C.errors}}

+

{{form.Memo.label_tag}}{{form.Memo}}{{form.Memo.errors}}

+ +
+{% endblock %} \ No newline at end of file diff --git a/mysite/ck/templates/ck/followup_newimages.html b/mysite/ck/templates/ck/followup_newimages.html new file mode 100755 index 0000000..0db8068 --- /dev/null +++ b/mysite/ck/templates/ck/followup_newimages.html @@ -0,0 +1,52 @@ +{% extends "base.html" %} + +{% block title %} +List new images +{% endblock %} + +{% block content %} +

List new images

+

刷新

+ + + + + + + + + + + + + + + + + {#% paginate 25 images %#} + {% for image in images %} + + + + + + + + + + + + + {% endfor %} + {#% show_pages %#} + +
å§“å病歷號單號檢查日檢查åç¨±å„€å™¨ç‹€æ…‹æ¸¬é‡æŽ¥å—/阻止
{{ image.patient }}{{ image.PatChartNo }}{{ image.RequestSheetNo }}{{ image.ExamDate }}{{ image.LinkOrderName }}{{ image.Modality }}{{ image.get_Saved_display }} + + + + ä¸é©ç”¨ +
+ +{% endblock %} \ No newline at end of file diff --git a/mysite/ck/templates/ck/followup_nosee.html b/mysite/ck/templates/ck/followup_nosee.html new file mode 100755 index 0000000..267aa42 --- /dev/null +++ b/mysite/ck/templates/ck/followup_nosee.html @@ -0,0 +1,58 @@ +{% extends "base.html" %} + +{% block title %} +Long time no see +{% endblock %} + +{% block content %} +

Long time no see

+ + + + + + + + + + + + + + + + + + + + {% for patient, date in results %} + + + + + + + + + + + + + + + + {% endfor %} + +
Last visitå§“å病歷號性別生日地å€é›»è©±èº«ä»½è­‰è™ŸMemoDetailNew FollowEdit
{{ date }}{{ patient.name }}{{ patient.medical_records }}{{ patient.get_gender_display }}{{ patient.birthday }}{{ patient.address }}{{ patient.phone }}{{ patient.id_cards }} + {{ patient.memo }} + {% if patient.dead %} + {{patient.dead}}已死亡 + {% endif %} + DetailNew FollowupEdit
+{% endblock %} \ No newline at end of file diff --git a/mysite/ck/templates/ck/lesion_confirm_delete.html b/mysite/ck/templates/ck/lesion_confirm_delete.html new file mode 100755 index 0000000..2336fa5 --- /dev/null +++ b/mysite/ck/templates/ck/lesion_confirm_delete.html @@ -0,0 +1,13 @@ +{% extends "base.html" %} + +{% block title %} +Confirm delete +{% endblock %} + +{% block content %} +

Confirm delete {{object.name}}

+
{% csrf_token %} +

Are you sure?

+ +
+{% endblock %} diff --git a/mysite/ck/templates/ck/lesion_form.dojo.html b/mysite/ck/templates/ck/lesion_form.dojo.html new file mode 100755 index 0000000..e7111e0 --- /dev/null +++ b/mysite/ck/templates/ck/lesion_form.dojo.html @@ -0,0 +1,229 @@ +{% extends "base.html" %} + +{% block head %} + + + +{% endblock %} + +{% block title %} +Lesion Form +{% endblock %} + +{% block content %} +{% if object %} + {{object.treatment.patient}} {{object.treatment.patient.medical_records}} +

Update lesion

+{% else %} + {{treatment.patient}} {{treatment.patient.medical_records}} +

Create lesion

+{% endif %} + +{% if form.has_errors %} +

Please correct the following error{{ form.errors|pluralize }}:

+{% endif %} + +

{{object.treatment.patient.name}}

+
{% csrf_token %} + + + +

+

+

+ {{ form.sub_location }} + {% if form.sub_location.errors %}{{ form.sub_location.errors }}{% endif %}

+

+ {{ form.pathology }} + {% if form.pathology.errors %}{{ form.pathology.errors }}{% endif %}

+

+ {{ form.dimensions }} + {% if form.dimensions.errors %}{{ form.dimensions.errors }}{% endif %}

+

+ {{ form.volume }} + {% if form.volume.errors %}{{ form.volume.errors }}{% endif %}

+

+ {{ form.plan_name }} + {% if form.plan_name.errors %}{{ form.plan_name.errors }}{% endif %}

+

+ {{ form.collimator }} + {% if form.collimator.errors %}{{ form.collimator.errors }}{% endif %}

+

+ {{ form.path_no }} + {% if form.path_no.errors %}{{ form.path_no.errors }}{% endif %}

+

+ {{ form.beam_no }} + {% if form.beam_no.errors %}{{ form.beam_no.errors }}{% endif %}

+

+ {{ form.mu_max }} + {% if form.mu_max.errors %}{{ form.mu_max.errors }}{% endif %}

+

+ {{ form.mu_min }} + {% if form.mu_min.errors %}{{ form.mu_min.errors }}{% endif %}

+

+ {{ form.dose }} + {% if form.dose.errors %}{{ form.dose.errors }}{% endif %}

+

+ {{ form.fractions }} + {% if form.fractions.errors %}{{ form.fractions.errors }}{% endif %}

+

+ {{ form.iso_dose_curve }} + {% if form.iso_dose_curve.errors %}{{ form.iso_dose_curve.errors }}{% endif %}

+

+ {{ form.dmax }} + {% if form.dmax.errors %}{{ form.dmax.errors }}{% endif %}

+

+ {{ form.dmin }} + {% if form.dmin.errors %}{{ form.dmin.errors }}{% endif %}

+

+ {{ form.coverage }} + {% if form.coverage.errors %}{{ form.coverage.errors }}{% endif %}

+

+ {{ form.ci }} + {% if form.ci.errors %}{{ form.ci.errors }}{% endif %}

+

+ {{ form.nci }} + {% if form.nci.errors %}{{ form.nci.errors }}{% endif %}

+

+ {{ form.start_date }} + {% if form.start_date.errors %}{{ form.start_date.errors }}{% endif %}

+

+ {{ form.end_date }} + {% if form.end_date.errors %}{{ form.end_date.errors }}{% endif %}

+

+ {{ form.memo }} + {% if form.memo.errors %}{{ form.memo.errors }}{% endif %}

+
+ +
+ Return to treatment + Return to patient +
+ + + +{% endblock %} diff --git a/mysite/ck/templates/ck/lesion_form.html b/mysite/ck/templates/ck/lesion_form.html new file mode 100755 index 0000000..2ff48ac --- /dev/null +++ b/mysite/ck/templates/ck/lesion_form.html @@ -0,0 +1,208 @@ +{% extends "base.html" %} + +{% block title %} +Lesion Form +{% endblock %} + +{% block content %} +{% if object %} + {{object.treatment.patient}} {{object.treatment.patient.medical_records}} +

Update lesion

+{% else %} + {{treatment.patient}} {{treatment.patient.medical_records}} +

Create lesion

+{% endif %} + +{{ form.errors }} + +{% if form.has_errors %} +

Please correct the following error{{ form.errors|pluralize }}:

+{% endif %} + +

{{object.treatment.patient.name}}

+ + + +
{% csrf_token %} + + + + + +

{{form.calibration_table.label_tag}}{{form.calibration_table}}{{form.calibration_table.errors}}

+

{{form.density_correction.label_tag}}{{form.density_correction}}{{form.density_correction.errors}}

+ +

+

+ +

{{form.sub_location.label_tag}}{{form.sub_location}}{{form.sub_location.errors}}

+

{{form.pathology.label_tag}}{{form.pathology}}{{form.pathology.errors}}

+ +

+ {{ form.dimensions }} + {% if form.dimensions.errors %}{{ form.dimensions.errors }}{% endif %}

+ + + +

{{form.volume_measure.label_tag}} + {{ form.volume_measure }} + {% if form.volume_measure.errors %}{{ form.volume_measure.errors }}{% endif %}

+ +

+ {{ form.plan_name }} + {% if form.plan_name.errors %}{{ form.plan_name.errors }}{% endif %}

+ +

{{form.collimator_type.label_tag}} + {{ form.collimator_type }} + {% if form.collimator_type.errors %}{{ form.collimator_type.errors }}{% endif %}

+

+ {{ form.collimator }} + {% if form.collimator.errors %}{{ form.collimator.errors }}{% endif %}

+ +

+ {{ form.path_no }} + {% if form.path_no.errors %}{{ form.path_no.errors }}{% endif %}

+

+ {{ form.beam_no }} + {% if form.beam_no.errors %}{{ form.beam_no.errors }}{% endif %}

+ + + {{ form.mu_max.as_hidden }} + {{ form.mu_min.as_hidden }} + + {% comment %} +

+ {{ form.mu_max }} + {% if form.mu_max.errors %}{{ form.mu_max.errors }}{% endif %}

+

+ {{ form.mu_min }} + {% if form.mu_min.errors %}{{ form.mu_min.errors }}{% endif %}

+ + {{ form.mu_max.as_hidden }} + {% endcomment %} + +

+ {{ form.dose }} + {% if form.dose.errors %}{{ form.dose.errors }}{% endif %}

+

+ {{ form.fractions }} + {% if form.fractions.errors %}{{ form.fractions.errors }}{% endif %}

+

+ {{ form.iso_dose_curve }} + {% if form.iso_dose_curve.errors %}{{ form.iso_dose_curve.errors }}{% endif %}

+ +

+ {{ form.dmax }} + {% if form.dmax.errors %}{{ form.dmax.errors }}{% endif %}

+

+ {{ form.dmin }} + {% if form.dmin.errors %}{{ form.dmin.errors }}{% endif %}

+

{{form.dmean.label_tag}} + {{ form.dmean }} + {% if form.dmean.errors %}{{ form.dmean.errors }}{% endif %}

+ +

+ {{ form.coverage }} + {% if form.coverage.errors %}{{ form.coverage.errors }}{% endif %}

+

+ {{ form.ci }} + {% if form.ci.errors %}{{ form.ci.errors }}{% endif %}

+

+ {{ form.nci }} + {% if form.nci.errors %}{{ form.nci.errors }}{% endif %}

+

+ {{ form.start_date }} + {% if form.start_date.errors %}{{ form.start_date.errors }}{% endif %}

+

+ {{ form.end_date }} + {% if form.end_date.errors %}{{ form.end_date.errors }}{% endif %}

+

+ {{ form.memo }} + {% if form.memo.errors %}{{ form.memo.errors }}{% endif %}

+
+ +
+ Return to treatment + Return to patient +
+ + +This is a lifesaver when debugging! +

{{ form.error_dict }}

+ + + + +{% endblock %} diff --git a/mysite/ck/templates/ck/lesionfollow_confirm_delete.html b/mysite/ck/templates/ck/lesionfollow_confirm_delete.html new file mode 100755 index 0000000..2336fa5 --- /dev/null +++ b/mysite/ck/templates/ck/lesionfollow_confirm_delete.html @@ -0,0 +1,13 @@ +{% extends "base.html" %} + +{% block title %} +Confirm delete +{% endblock %} + +{% block content %} +

Confirm delete {{object.name}}

+
{% csrf_token %} +

Are you sure?

+ +
+{% endblock %} diff --git a/mysite/ck/templates/ck/nhiorder_add.html b/mysite/ck/templates/ck/nhiorder_add.html new file mode 100644 index 0000000..e7a7cff --- /dev/null +++ b/mysite/ck/templates/ck/nhiorder_add.html @@ -0,0 +1,177 @@ +{% extends "base.html" %} +{#% load endless %#} +{% load static %} +{% block head %} + +{% comment %} + + +{% endcomment %} + + + + + + + + + + + +{% endblock %} + +{% block topsection %} +{% endblock %} + +{% block menu %} +

事å‰å¯©æŸ¥æ¡ˆä»¶

+NTUH CyberKnife +{% if user.is_authenticated %} +{{ user.username }} 登出 +{% else %} +登入 +{% endif %} +{% endblock %} + + +{% block content %} + +
+
+
+ + +
+ + +
+
+ +
+ {%if nhiorders%} + + + + + + + + + + + + + + + + + + + {%for order in nhiorders %} + + + + + + + + + + + + + + + {%endfor%} + +
病歷號病患姓åç”³è«‹é¡žåˆ¥æ¡ˆä»¶ç‹€æ…‹ç§‘åˆ¥é€æ¡ˆæ—¥æœŸç”³è«‹é …目項目åç¨±ç”³è«‹æ•¸é‡æ ¸å®šçµæžœå„ªå…ˆç”³è«‹é†«å¸«
{{order.ChartNo}}{{order.PatientName}}{{order.ApplyTypeDesc}}{{order.StatusDesc}}{{order.NhiDeptName}}{{order.PackageTime}}{{order.OrderCode}}{{order.OrderName}}{{order.ResultDesc}}{{order.Quantity}}{{order.Priority}} + {%if order.ApplyDoctor%} + {{order.ApplyDoctor}} + {%else%} + èªé ˜ + {%endif%} +
+ {%else%} + + + + + +
病歷號{{pat.ChartNo}}
病患姓å{{pat.ChtName}}
性別{{pat.Sex}}
生日{{pat.Birth}}
+ {%endif%} +
+ + +{%if nhiorders or pat%} +
+ {%if nhiorders %} + è‹¥é€æ ¸æœªé€šéŽï¼Œä¸å¿…新增自費,åªéœ€ç·¨è¼¯æ›´æ”¹å„ªå…ˆå€¼å³å¯ + edit編輯 + {%endif%} + add自費 +
+{%endif%} + +{% endblock %} + diff --git a/mysite/ck/templates/ck/nhiorder_list copy.html b/mysite/ck/templates/ck/nhiorder_list copy.html new file mode 100644 index 0000000..7cc677e --- /dev/null +++ b/mysite/ck/templates/ck/nhiorder_list copy.html @@ -0,0 +1,60 @@ +{% extends "base.html" %} +{#% load endless %#} +{% block head %} + +{% endblock %} +{% block content %} +

事å‰å¯©æŸ¥æ¡ˆä»¶

+ + + {% for case in page_obj %} + + + + + + + + + + + + + + + + + + + + + + + + + {% endfor %} +
{{ case.ChartNo }}{{ case.PatientName }}{{ case.ApplyTypeDesc }}{{ case.StatusDesc }}{{ case.NhiDeptName }}{{ case.PackageTime|date:"Y-m-d" }}{{ case.OrderCode }}{{ case.OrderName }}{{ case.ResultDesc }}{{ case.Quantity }}{{ case.ExamineQuantity }}{{ case.ExamineDate|date:"Y-m-d" }}{{ case.ApplyDoctor }}
+ + +{% endblock %} + diff --git a/mysite/ck/templates/ck/nhiorder_list.html b/mysite/ck/templates/ck/nhiorder_list.html new file mode 100644 index 0000000..d05267a --- /dev/null +++ b/mysite/ck/templates/ck/nhiorder_list.html @@ -0,0 +1,156 @@ +{% extends "base.html" %} +{#% load endless %#} +{% load static %} +{% block head %} + +{% comment %} + + +{% endcomment %} + + + + + + + + + + + +{% endblock %} + +{% block topsection %} +{% endblock %} + +{% block menu %} +

事å‰å¯©æŸ¥æ¡ˆä»¶

+NTUH CyberKnife +{% if user.is_authenticated %} +{{ user.username }} 登出 +{% else %} +登入 +{% endif %} +{% endblock %} + + +{% block content %} + + + +
+
+ + + {% for w in waiting_list %} + {% if w.ApplyDoctor %} + + {% else %} + + {% endif %} + {% endfor %} +
+
+
+
+ + +
+ + +
+
+
+
+ +
+
+
+
+ {{ datatable }} +
+ + + + + + +{% endblock %} + diff --git a/mysite/ck/templates/ck/patient_add.html b/mysite/ck/templates/ck/patient_add.html new file mode 100755 index 0000000..638b054 --- /dev/null +++ b/mysite/ck/templates/ck/patient_add.html @@ -0,0 +1,46 @@ +{% extends "base.html" %} + +{% block title %} +Add a patient +{% endblock %} + +{% block content %} +

Add a patient

+ {% if result %} + + + + + + + + + + + + + + + {% for patient in result %} + + + + + + + + + + + {% endfor %} + +
Addå§“å病歷號性別生日地å€é›»è©±èº«ä»½è­‰è™Ÿ
Add{{ patient.name }}{{ patient.medical_records }}{{ patient.gender }}{{ patient.birthday }}{{ patient.address }}{{ patient.phone }}{{ patient.id_cards }}
+
+ {% endif %} +
{% csrf_token %} + + {{ form.as_table }} +
+

+
+{% endblock %} diff --git a/mysite/ck/templates/ck/patient_confirm_delete.html b/mysite/ck/templates/ck/patient_confirm_delete.html new file mode 100755 index 0000000..2336fa5 --- /dev/null +++ b/mysite/ck/templates/ck/patient_confirm_delete.html @@ -0,0 +1,13 @@ +{% extends "base.html" %} + +{% block title %} +Confirm delete +{% endblock %} + +{% block content %} +

Confirm delete {{object.name}}

+
{% csrf_token %} +

Are you sure?

+ +
+{% endblock %} diff --git a/mysite/ck/templates/ck/patient_detail.html b/mysite/ck/templates/ck/patient_detail.html new file mode 100755 index 0000000..4828579 --- /dev/null +++ b/mysite/ck/templates/ck/patient_detail.html @@ -0,0 +1,250 @@ +{% extends "base.html" %} + +{% block title %} +List treatments +{% endblock %} + +{% block content %} +

Patient treatments

+ + + + + + + + + + + + + + + + + + + + + + + + +
Patient ID{{ patient.id }}å§“å{{ patient.name }}病歷號{{ patient.medical_records }}性別{{ patient.get_gender_display }}生日{{ patient.birthday }} + Edit + Print +
地å€{{ patient.address }}電話{{ patient.phone }}身份證號{{ patient.id_cards }}Memo{{ patient.memo }} + {% if patient.dead %} + {{patient.dead}}已死亡 + {% endif %} +
身高(cm){{ patient.height }}é«”é‡(kg){{ patient.weight }}
+ èº«é«˜é«”é‡ +
+ {% if patient.priortreatment_set.all %} + + + + + + + + + + + + + + + {% for prior in patient.priortreatment_set.all|dictsort:"date" %} + + + + + + + + + + + {% endfor %} + +
Prior Treatment IDStart DateTreatmentPeriodDose(cGy)MemoDeleteEdit
{{ prior.id }}{{ prior.date }}{{ prior.get_treatment_display }}{{ prior.get_period_display }}{{ prior.dose }}{{ prior.memo }}DeleteEdit
+ {% endif %} + + Add prior treatment + 手術紀錄查詢 + æ”¾å°„è¨˜éŒ„æ‘˜è¦æŸ¥è©¢ + + {% if patient.pathexam_set.all %} + + + + + + + + + + {% for path in patient.pathexam_set.all|dictsort:"path_code" %} + + + + + + {% endfor %} + +
ç—…ç†è™Ÿå ±å‘Šæ—¥å ±å‘Š
{{ path.path_code }}{{ path.report_date }}{{ path.report }}
+ {% endif %} + ç—…ç†å ±å‘ŠæŸ¥è©¢ + +
+
+ {% if treatments %} + + + + + + + + + + + + + + + + + + + + + {% for treatment in treatments %} + + + + + + + + + + + + + + + + + {% endfor %} + +
DetailIDDateOncologistSurgeon記帳別Disease StagePrimary tumor site已待MemoDeleteEditPrint
Detail{{ treatment.id }}{%if treatment.date_started == treatment.date_completed%}{{treatment.date_completed}}{%else%}{{treatment.date_started}} ~ {{treatment.date_completed}}{%endif%}{{ treatment.oncologist }}{{ treatment.surgeon }}{{ treatment.get_accounting_display }}{{ treatment.disease_stage }}{% if treatment.disease_stage_id == 5 %} + {{ treatment.primary_tumor_site }} + {% endif %}{{ treatment.input }}{{ treatment.output }}{{ treatment.memo }}DeleteEditPrint
+ {% endif %} + New treatment +
+ +
+ + {% if patient.followup_set.all %} + + + + + + + + + + + {% for followup in patient.followup_set.all|dictsort:"date" %} + + + + + + followup + {% endfor %} + +
DateMemoDeleteEdit
{{ followup.date }}{{ followup.memo }}DeleteEdit
+ {% endif %} + + New Follow-up + +
+ + {% if patient.medicalrecord_set.all %} + Last Medical Records + + + + + + + + + + + + + + + {% for mr in patient.medicalrecord_set.all|dictsortreversed:"InDate" %} + {%if forloop.counter0 < 5%} + + + + + + + + + + + {%endif%} + {% endfor %} + +
{{ mr.Record }}{{ mr.HospName }}{{ mr.DeptName }}{{ mr.InDate }} + {%if mr.WardName%}{{mr.WardName}}{%endif%} + {%if mr.RoomName%}{{mr.RoomName}}{%endif%} + {%if mr.BedName%}{{mr.BedName}}{%endif%} + {%if mr.OutDate%}{{mr.OutDate}}出 {%endif%} + {%if mr.SpecialCureName%}{{mr.SpecialCureName}}{%endif%} + {{ mr.MainDrName }}{{ mr.MainDiagnosisName }}{{ mr.StatusName }}
+ {% endif %} +
+ {% if pacsimages %} + PACS Images (CT/MRI) + + + + + + + + + + + + {% for p in pacsimages %} + + + + + + + + + + {% endfor %} + +
標示為ä¸é©ç”¨
{{ p.RequestSheetNo }}{{ p.ExamDate }}{{ p.LinkOrderName }}{{ p.Modality }}{{ p.VerifiedStateString }}{{ p.get_Saved_display }}N/A
+ {% endif %} + + +{% endblock %} diff --git a/mysite/ck/templates/ck/patient_form.html b/mysite/ck/templates/ck/patient_form.html new file mode 100755 index 0000000..d8151a8 --- /dev/null +++ b/mysite/ck/templates/ck/patient_form.html @@ -0,0 +1,45 @@ +{% extends "base.html" %} + +{% block head %} + +{% endblock %} + +{% block title %} +Patient form +{% endblock %} + +{% block content %} + +{% if object %} +

Update patient:

+{% else %} +

Create a Patient

+{% endif %} + +{% if form.has_errors %} +

Please correct the following error{{ form.errors|pluralize }}:

+{% endif %} + +
{% csrf_token %} + {{ form.as_p }} + +
+ +Return to patient list + + + + + +{% endblock %} \ No newline at end of file diff --git a/mysite/ck/templates/ck/patient_list copy.html b/mysite/ck/templates/ck/patient_list copy.html new file mode 100644 index 0000000..2fd6dfd --- /dev/null +++ b/mysite/ck/templates/ck/patient_list copy.html @@ -0,0 +1,113 @@ +{% extends "base.html" %} +{% load render_table from django_tables2 %} +{% load static %} + +{% block title %} +List patients +{% endblock %} + + + +{% block head %} + + + + + + + +{% endblock %} + + +{% block content %} + + +{# { datatable } #} +{% render_table object_list %} + +

List patients

+ + {% if is_paginated %} + + {% endif %} + + + + + + + + + + + + + + + + + + + + {% for patient in object_list %} + + + + + + + + + + + + + + + {% endfor %} + +
Detailå§“å病歷號性別生日地å€é›»è©±èº«ä»½è­‰è™ŸMemoDeleteEditPrint
Detail{{ patient.name }}{{ patient.medical_records }}{{ patient.get_gender_display }}{{ patient.birthday }}{{ patient.address }}{{ patient.phone }}{{ patient.id_cards }} + {{ patient.memo }} + {% if patient.dead %} + {{patient.dead}}已死亡 + {% endif %} + DeleteEditPrint
+ + {% if is_paginated %} + + {% endif %} + + + +{% endblock %} \ No newline at end of file diff --git a/mysite/ck/templates/ck/patient_list.html b/mysite/ck/templates/ck/patient_list.html new file mode 100755 index 0000000..36865f7 --- /dev/null +++ b/mysite/ck/templates/ck/patient_list.html @@ -0,0 +1,77 @@ +{% extends "base.html" %} +{% load render_table from django_tables2 %} +{% load static %} + +{% block title %} +List patients +{% endblock %} + + + +{% block head %} + + + + + + + +{% endblock %} + + +{% block content %} +

List patients

+ + +{#% render_table table %#} + + + +{{ datatable }} + + + + + + + +{% endblock %} \ No newline at end of file diff --git a/mysite/ck/templates/ck/patient_print.html b/mysite/ck/templates/ck/patient_print.html new file mode 100755 index 0000000..fc8e42a --- /dev/null +++ b/mysite/ck/templates/ck/patient_print.html @@ -0,0 +1,252 @@ + + + + + + + +電腦刀影åƒå°Žå¼•ç«‹é«”å®šä½æ”¾å°„æ‰‹è¡“æ‘˜è¦ + + + + + +
+ +
+ +
+ + + + + + + + + + +
+ 國 ç«‹ å° ç£ å¤§ å­¸ 醫 å­¸ 院 附 設 醫 院
National Taiwan University Hospital
+ 電腦刀影åƒå°Žå¼•ç«‹é«”å®šä½æ”¾å°„手術摘è¦
+
+ +
+ + + + + + + + + + + + +
病歷號:{{patient.medical_records}}å§“å:{{patient.name}}床號:   
+ +
+

民國95å¹´5月26日病歷委員會修正通éŽ

+
+ + + + + + + + + + + + + + +{% for treatment in treatments %} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +{% for lesion in treatment.lesion_set.all %} + + + + + + + + + + + + + +{% endfor %} + + + +{% endfor %} + +
性別: + {{patient.get_gender_display}} + 出生日期:
+ {{patient.birthday}}
電話: + {{patient.phone}}

療程 + + {{forloop.counter}} +  
ICD9診斷其他診斷備註
{{treatment.icd9|default:" "}}{{treatment.other_diagnosis|default:" "}}{{treatment.memo|default:" "}}
é–‹å§‹
日期
çµæŸ
日期
療程
日數
主治
醫師
完æˆ
治療
併發症
{{treatment.date_started}}{{treatment.date_completed}}{%if treatment.surgeon%}{{treatment.surgeon}}/{%endif%}{{treatment.oncologist}}{{treatment.input}} + {{treatment.complications|default:" "}}
éƒ¨ä½æ–¹å¼æ”¾å°„
能é‡
治療
次數
總劑é‡é–‹å§‹
日期
çµæŸ
日期
療程
日數
備註
{{lesion.sub_location.target_location}}-{{lesion.sub_location}}CyberKnife6MVå…‰å­{{lesion.fractions}}{{lesion.dose}} at {{lesion.iso_dose_curve}}%{{lesion.start_date}}{{lesion.end_date}}{{lesion.memo|default:" "}}
+ + +
+ + + + + + diff --git a/mysite/ck/templates/ck/patient_search.html b/mysite/ck/templates/ck/patient_search.html new file mode 100755 index 0000000..a8e402b --- /dev/null +++ b/mysite/ck/templates/ck/patient_search.html @@ -0,0 +1,58 @@ +{% extends "base.html" %} + +{% block title %} +Add/Search patients +{% endblock %} + +{% block content %} +

Add/Search patients

+
{% csrf_token %} + + + +
+ + {% if query %} +

Results for "{{ query|escape }}":

+ + {% if results %} + + + + + + + + + + + + + + + + + + {% for patient in results %} + + + + + + + + + + + + + + {% endfor %} + +
å§“å病歷號性別生日地å€é›»è©±èº«ä»½è­‰è™ŸMemoDeleteEdit
Detail{{ patient.name }}{{ patient.medical_records }}{{ patient.get_gender_display }}{{ patient.birthday }}{{ patient.address }}{{ patient.phone }}{{ patient.id_cards }}{{ patient.memo }}DeleteEdit
+ {% else %} +

No patient found. + Add a patient +

+ {% endif %} + {% endif %}{% endblock %} \ No newline at end of file diff --git a/mysite/ck/templates/ck/priortreatment_confirm_delete.html b/mysite/ck/templates/ck/priortreatment_confirm_delete.html new file mode 100755 index 0000000..2336fa5 --- /dev/null +++ b/mysite/ck/templates/ck/priortreatment_confirm_delete.html @@ -0,0 +1,13 @@ +{% extends "base.html" %} + +{% block title %} +Confirm delete +{% endblock %} + +{% block content %} +

Confirm delete {{object.name}}

+
{% csrf_token %} +

Are you sure?

+ +
+{% endblock %} diff --git a/mysite/ck/templates/ck/priortreatment_form.html b/mysite/ck/templates/ck/priortreatment_form.html new file mode 100755 index 0000000..4919c28 --- /dev/null +++ b/mysite/ck/templates/ck/priortreatment_form.html @@ -0,0 +1,83 @@ +{% extends "base.html" %} + +{% block head %} + + +{% endblock %} + +{% block title %} + Treatment Form +{% endblock %} + +{% block content %} + {% if object %} + {{object.patient}} +

Update prior treatment

+ {% else %} + {{patient}} +

Create prior treatment

+ {% endif %} + + {% if form.errors %} + Please correct the following error{{ form.errors|pluralize }}: + {% endif %} + +
{% csrf_token %} +

{{form.patient.label_tag}}{{form.patient.errors}}

+

{{form.date.label_tag}}{{form.date}}{{form.date.errors}}

+

{{form.treatment.label_tag}}{{form.treatment}}{{form.treatment.errors}}

+

{{form.period.label_tag}}{{form.period}}{{form.period.errors}}

+

{{form.dose.label_tag}}{{form.dose}}{{form.dose.errors}}

+

{{form.memo.label_tag}}{{form.memo}}{{form.memo.errors}}

+ +
+ + + {% if object %} + Return to patient + {% else %} + Return to patient + {% endif %} + +{% endblock %} \ No newline at end of file diff --git a/mysite/ck/templates/ck/record_weekly.html b/mysite/ck/templates/ck/record_weekly.html new file mode 100755 index 0000000..66813ae --- /dev/null +++ b/mysite/ck/templates/ck/record_weekly.html @@ -0,0 +1,152 @@ + + + + +æ¯é€±ç—…人數紀錄 + + + + + +
+ +
+ + + +
+ + + + + + + + + +
+ 國 ç«‹ å° ç£ å¤§ å­¸ 醫 å­¸ 院 附 設 醫 院
National Taiwan University Hospital
+ æ¯é€±ç—…人數紀錄
+
+ +
+ + + +

+ + + + + +
{{weeknumber}}日期:{{weekdate.mon}}~{{weekdate.fri}}人數統計:{{treatments|length}}人{{events|length}} sessions
+

+ + + + + + + + + + + + + + {%for treatment in treatments%} + + + + + + + + + + + {%endfor%} + +
 診斷部ä½å…¶ä»–診斷å¥ä¿ 自費治療日期外科醫師放腫醫師轉介醫師
{{forloop.counter}}{{treatment.icd9}}{{treatment.other_diagnosis}}{{treatment.accounting}} + {%for date in treatment.dates%} + {{date}} +
+ {%endfor%} +
{{treatment.surgeon}}{{treatment.oncologist}}{{treatment.referral}}
+
+ + + + + + + diff --git a/mysite/ck/templates/ck/timetable_scheduling.html b/mysite/ck/templates/ck/timetable_scheduling.html new file mode 100755 index 0000000..cccae8c --- /dev/null +++ b/mysite/ck/templates/ck/timetable_scheduling.html @@ -0,0 +1,184 @@ + + + + +治療排程時間表 + + + + + +
+ +
+ + + +
+ + + + + + + + + +
+ 國 ç«‹ å° ç£ å¤§ å­¸ 醫 å­¸ 院 附 設 醫 院
National Taiwan University Hospital
+ 電腦刀中心 治療/å®šä½æŽ’ç¨‹æ™‚é–“è¡¨
+
+ +
+ + + + + + + + + + + + + + {%for row in timetable%} + + + + + + + + + {%endfor%} + + + + + + + + + +
 {{weekdate.mon}}
星期一
{{weekdate.tue}}
星期二
{{weekdate.wed}}
星期三
{{weekdate.thu}}
星期四
{{weekdate.fri}}
星期五
{{row.name}}{{row.mon|default:" "|linebreaks}}{{row.tue|default:" "|linebreaks}}{{row.wed|default:" "|linebreaks}}{{row.thu|default:" "|linebreaks}}{{row.fri|default:" "|linebreaks}}
      
+ + + + + + + + + + + + + + + {%for row in timetable%} + + + + + + + + + + + + + {%endfor%} + + + + + + + + + + + + + +
 姓åç—…æ­·è™Ÿç¢¼ä¸»æ²»è¨ºæ–·éƒ¨ä½æ¬¡æ•¸nodemode時間實際治療時間
{{forloop.counter}}{{row.name}}{{row.medical_records}}{{row.indications|linebreaks}}{{row.diagnosis_site}}{{row.number|default:" "}}{{row.node|default:" "}}{{row.mode|default:" "}}{{row.time|default:" "}}{{row.actual_treatment|default:" "}}
          
+
+ + + + + + + diff --git a/mysite/ck/templates/ck/treatment_confirm_delete.html b/mysite/ck/templates/ck/treatment_confirm_delete.html new file mode 100755 index 0000000..2336fa5 --- /dev/null +++ b/mysite/ck/templates/ck/treatment_confirm_delete.html @@ -0,0 +1,13 @@ +{% extends "base.html" %} + +{% block title %} +Confirm delete +{% endblock %} + +{% block content %} +

Confirm delete {{object.name}}

+
{% csrf_token %} +

Are you sure?

+ +
+{% endblock %} diff --git a/mysite/ck/templates/ck/treatment_detail.html b/mysite/ck/templates/ck/treatment_detail.html new file mode 100755 index 0000000..bcba223 --- /dev/null +++ b/mysite/ck/templates/ck/treatment_detail.html @@ -0,0 +1,184 @@ +{% extends "base.html" %} + +{% block title %} +Treatment detail +{% endblock %} + +{% block content %} +

Treatment detail

+ + + + + + + + + + + + + + + + + + + + + + +
Patient ID{{ patient.id }}å§“å{{ patient.name }}病歷號{{ patient.medical_records }}性別{{ patient.get_gender_display }}生日{{ patient.birthday }} + Detail + Edit + Print +
地å€{{ patient.address }}電話{{ patient.phone }}身份證號{{ patient.id_cards }}Memo{{ patient.memo }}
已追蹤日期{{ patient.last_followup }}é è¿½è¹¤æ—¥æœŸ{{ patient.next_followup }}
+
+ + + + + + + + + + + + + {% for nhiorder in nhiorders %} + + + + + + + + {% endfor %} + +
逿¡ˆæ—¥æœŸç–¾ç—…åˆ†é¡žè™Ÿå…¶ä»–è¨ºæ–·ç”³è«‹åŽŸå› æ ¸å®šçµæžœ
{{nhiorder.PackageTime}}{{nhiorder.Diagnosis}}{{nhiorder.other_diagnosis}}{{nhiorder.Reason}}{{nhiorder.Quantity}}
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Treatment ID{{ treatment.id }}病床號{{ treatment.bed }}ICD + {% if treatment.icd10cm %} + {{ treatment.icd10cm }} + {% else %} + {{ treatment.icd9 }} + {% endif %} + 其他診斷{{ treatment.other_diagnosis }} + Edit + Print + Report + History +
Oncologist{{ treatment.oncologist }}Surgeon{{ treatment.surgeon }}Date{%if treatment.date_started == treatment.date_completed%}{{treatment.date_completed}}{%else%}{{treatment.date_started}}~{{treatment.date_completed}}{%endif%}記帳別{{ treatment.get_accounting_display }}Karnofsky score{{ treatment.karnofsky_score }}
Disease Stage{{ treatment.disease_stage }}Primary Tumor Site{{ treatment.primary_tumor_site }}å·²{{ treatment.input }}å¾…{{ treatment.output }}Memo{{ treatment.memo }}
+
+ + {% if vevents %} + + + + + + + + + + + + + + + + {% for vevent in vevents %} + + + + + + + + + + + + {% endfor %} + +
Event IDModeRemarkStartDurationDescription批價相關資訊DeleteEdit
{{ vevent.id }}{{ vevent.get_mode_display }}{{ vevent.mode_remark|default:"" }}{{ vevent.DTSTART }}{{ vevent.DURATION | date:"H:i"}}{{ vevent.DESCRIPTION|default:"" }}{{ vevent.price }}DeleteEdit
+ {% endif %} + New event +
+ + {% if lesions %} + + + + + + + + + + + + + + + + + + + {% for lesion in lesions %} + + + + + + + + + + + + + + + {% endfor %} + +
Lesion IDTarget LocationAnatomic SublocationPathologyTarget VolumePrescription Dose (cGy)Number of FractionsPrescription Isodose CurveCoverageDateDeleteEdit
{{ lesion.id }}{{ lesion.sub_location.target_location }}{{ lesion.sub_location }}{{ lesion.pathology }} + {% if lesion.volume_measure %} + {{ lesion.volume_measure.cubic_centimeter }} cm3 + {% else %} + {{ lesion.volume }} mm3 + {% endif %} + {{ lesion.dose }}{{ lesion.fractions }}{{ lesion.iso_dose_curve }}%{{ lesion.coverage }}%{%if lesion.start_date == lesion.end_date%}{{lesion.end_date}}{%else%}{{lesion.start_date}} ~ {{lesion.end_date|date:"m-d"}}{%endif%}DeleteEdit
+ {% endif %} + + New lesion + + +{% endblock %} diff --git a/mysite/ck/templates/ck/treatment_form.html b/mysite/ck/templates/ck/treatment_form.html new file mode 100755 index 0000000..eeec688 --- /dev/null +++ b/mysite/ck/templates/ck/treatment_form.html @@ -0,0 +1,220 @@ +{% extends "base.html" %} + +{% block head %} +{# include 'autocomplete_light/static.html' #} + + + + + + + + + + + + + + + + + + + +{% endblock %} + +{% block title %} + Treatment Form +{% endblock %} + +{% block content %} + {% if object %} + {{object.patient}} {{object.patient.medical_records}} +

Update treatment

+ {% else %} + {{patient}} {{patient.medical_records}} +

Create treatment

+ {% endif %} + + {% if form.errors %} + Please correct the following error{{ form.errors|pluralize }}: + {% endif %} + +
{% csrf_token %} +

{{form.patient.label_tag}}{{form.patient.errors}}

+

{{form.bed.label_tag}}{{form.bed}}{{form.bed.errors}}

+ + + {% comment %} +

{{form.icd9.label_tag}}{{form.icd9}}{{form.icd9.errors}}

+

{{form.icd9.label_tag}}{{form.icd9.errors}}

+

{{form.icd9.label_tag}}

{{form.icd9.errors}}

+ + + + SELECT icd10cm_id, COUNT(*) + FROM ck_treatment + GROUP BY icd10cm_id + ORDER BY COUNT(*) DESC + {% endcomment %} + +
+ +
+ {%if nhiorders %} + + + + + + + + + + + + {% for nhiorder in nhiorders %} + + + + + + + + {% endfor %} + +
逿¡ˆæ—¥æœŸç–¾ç—…åˆ†é¡žè™Ÿå…¶ä»–è¨ºæ–·ç”³è«‹åŽŸå› æ ¸å®šçµæžœ
{{nhiorder.PackageTime}}{{nhiorder.Diagnosis}}{{nhiorder.other_diagnosis}}{{nhiorder.Reason}}{{nhiorder.Quantity}}
+ {% endif %} +

{{form.icd10cm.label_tag}}{{form.icd10cm}}{{form.icd10cm.errors}}

+
+
+ + + {% for icd10 in topicd10|slice:"0:5" %} + + + + + + + {% endfor %} + +
{{icd10.ICD10CM_Chinese}}{{icd10.ICD9CM_Chinese}}
+
+
+ +

{{form.other_diagnosis.label_tag}}{{form.other_diagnosis}}{{form.other_diagnosis.errors}}

+

{{form.tracking_mode.label_tag}}{{form.tracking_mode}}{{form.tracking_mode.errors}}

+

{{form.referral.label_tag}}{{form.referral}}{{form.referral.errors}}

+

{{form.oncologist.label_tag}}{{form.oncologist}}{{form.oncologist.errors}}

+

{{form.surgeon.label_tag}}{{form.surgeon}}{{form.surgeon.errors}}

+

{{form.date_started.label_tag}}{{form.date_started}}{{form.date_started.errors}}

+

{{form.date_completed.label_tag}}{{form.date_completed}}{{form.date_completed.errors}}

+

{{form.accounting.label_tag}}{{form.accounting}}{{form.accounting.errors}}

+

{{form.karnofsky_score.label_tag}}{{form.karnofsky_score}}{{form.karnofsky_score.errors}}

+

{{form.disease_stage.label_tag}}{{form.disease_stage}}{{form.disease_stage.errors}}

+

{{form.primary_tumor_site.label_tag}}{{form.primary_tumor_site}}{{form.primary_tumor_site.errors}}

+

{{form.input.label_tag}}{{form.input}}{{form.input.errors}}

+

{{form.output.label_tag}}{{form.output}}{{form.output.errors}}

+

{{form.complications.label_tag}}{{form.complications}}{{form.complications.errors}}

+

{{form.chief_complaint.label_tag}}{{form.chief_complaint}}{{form.chief_complaint.errors}}

+

{{form.memo.label_tag}}{{form.memo}}{{form.memo.errors}}

+ +
+ + + + + {% if object %} + Return to patient + {% else %} + Return to patient + {% endif %} + + + + + +{% endblock %} + +{% block footer %} +{{ form.media }} +{% endblock %} \ No newline at end of file diff --git a/mysite/ck/templates/ck/treatment_form1.html b/mysite/ck/templates/ck/treatment_form1.html new file mode 100755 index 0000000..2341492 --- /dev/null +++ b/mysite/ck/templates/ck/treatment_form1.html @@ -0,0 +1,142 @@ +{% extends "base.html" %} + +{% block head %} + + +{% endblock %} + +{% block title %} +Treatment Form +{% endblock %} + +{% block content %} +{% if object %} +

Update treatment

+{% else %} +

Create treatment

+{% endif %} + +{% if form.has_errors %} +

Please correct the following error{{ form.errors|pluralize }}:

+{% endif %} + +

{{object.patient.name}}

+
{% csrf_token %} + + + +

+ {{ form.bed }} + {% if form.bed.errors %}{{ form.bed.errors }}{% endif %}

+
+

+ + {% if form.icd9.errors %}*** {{ form.icd9.errors|join:", " }}{% endif %}

+

+ {{ form.other_diagnosis }} + {% if form.other_diagnosis.errors %}{{ form.other_diagnosis.errors }}{% endif %}

+

+ + {% if form.date_started.errors %}{{ form.date_started.errors }}{% endif %}

+

+ + {% if form.date_completed.errors %}{{ form.date_completed.errors }}{% endif %}

+

+ {{ form.tracking_mode }} + {% if form.tracking_mode.errors %}{{ form.tracking_mode.errors }}{% endif %}

+

+ {{ form.referral }} + {% if form.referral.errors %}{{ form.referral.errors }}{% endif %}

+

+ {{ form.oncologist }} + {% if form.oncologist.errors %}{{ form.oncologist.errors }}{% endif %}

+

+ {{ form.surgeon }} + {% if form.surgeon.errors %}{{ form.surgeon.errors }}{% endif %}

+

+ {{ form.accounting }} + {% if form.accounting.errors %}{{ form.accounting.errors }}{% endif %}

+

+ {{ form.karnofsky_score }} + {% if form.karnofsky_score.errors %}{{ form.karnofsky_score.errors }}{% endif %}

+

+ {{ form.disease_stage }} + {% if form.disease_stage.errors %}{{ form.disease_stage.errors }}{% endif %}

+

+ {{ form.primary_tumor_site }} + {% if form.primary_tumor_site.errors %}{{ form.primary_tumor_site.errors }}{% endif %}

+

+ {{ form.input }} + {% if form.input.errors %}{{ form.input.errors }}{% endif %}

+

+ {{ form.output }} + {% if form.output.errors %}{{ form.output.errors }}{% endif %}

+

+ {{ form.complications }} + {% if form.complications.errors %}{{ form.complications.errors }}{% endif %}

+

+ {{ form.chief_complaint }} + {% if form.chief_complaint.errors %}{{ form.chief_complaint.errors }}{% endif %}

+

+ {{ form.memo }} + {% if form.memo.errors %}{{ form.memo.errors }}{% endif %}

+
+ +
+ Return to patient +
+ + + +{% endblock %} diff --git a/mysite/ck/templates/ck/treatment_list.html b/mysite/ck/templates/ck/treatment_list.html new file mode 100755 index 0000000..88ef0db --- /dev/null +++ b/mysite/ck/templates/ck/treatment_list.html @@ -0,0 +1,53 @@ +{% extends "base.html" %} +{#% load endless %#} +{% load static %} + +{% block head %} + + + + + + + +{% endblock %} + + +{% block content %} +

List treatments

+
+
+
+ +
+
+
+ + {{ datatable }} + + +{% endblock %} + diff --git a/mysite/ck/templates/ck/treatment_list_copy.html b/mysite/ck/templates/ck/treatment_list_copy.html new file mode 100755 index 0000000..b03426e --- /dev/null +++ b/mysite/ck/templates/ck/treatment_list_copy.html @@ -0,0 +1,122 @@ +{% extends "base.html" %} +{#% load endless %#} +{% load static %} + +{% block head %} + + + + + + + +{% endblock %} + + +{% block content %} +

List treatments

+ + {{ datatable }} + + {% if is_paginated %} + + {% endif %} + + + {% if object_list %} + + + + + + + + + + + + + + + + + + + + + + + {% for treatment in object_list %} + + + + + + + + + + + {% if treatment.icd10cm %} + + {% else %} + + {% endif %} + + + + + + + + {% endfor %} + {#% show_pages %#} + +
DetailIDPatientDateRadiat OncolSurgeon記帳別Disease StagePrimary tumor siteICD其他診斷已待病床號MemoDelete/Edit/Print
Detail{{ treatment.id }}{{ treatment.patient }} / {{ treatment.patient.medical_records }}{%ifequal treatment.date_started treatment.date_completed%}{{treatment.date_completed}}{%else%}{{treatment.date_started}} ~ {{treatment.date_completed}}{%endifequal%}{{ treatment.oncologist }}{{ treatment.surgeon }}{{ treatment.get_accounting_display }}{{ treatment.disease_stage }}{% ifequal treatment.disease_stage_id 5 %} + {{ treatment.primary_tumor_site }} + {% endifequal %}{{ treatment.icd10cm }}{{ treatment.icd9 }}{{ treatment.other_diagnosis }}{{ treatment.input }}{{ treatment.output }}{{ treatment.bed }}{{ treatment.memo }}Delete + Edit + Print + Report
+ + {% if is_paginated %} + + {% endif %} + + + {% endif %} + +{% endblock %} + diff --git a/mysite/ck/templates/ck/treatment_print.html b/mysite/ck/templates/ck/treatment_print.html new file mode 100755 index 0000000..fbeffeb --- /dev/null +++ b/mysite/ck/templates/ck/treatment_print.html @@ -0,0 +1,298 @@ + + + + +電腦刀治療紀錄 + + + + + +
+ +
+ +
+ + + + + + + + + +
+ 國 ç«‹ å° ç£ å¤§ å­¸ 醫 å­¸ 院 附 設 醫 院
National Taiwan University Hospital
+ 電腦刀中心 治療紀錄
+ + + +
+ +{% with contacts.object_list as lesions %} +
+ + + + + + + +
å§“å:{{treatment.patient.name}}病歷號:{{treatment.patient.medical_records}}床號:
+ + + + + + +{%for lesion in lesions%} + +{%endfor%} + + + + + {%for lesion in lesions%} + + {%endfor%} + + + {%for lesion in lesions%} + + {%endfor%} + + +{%for lesion in lesions%} + +{%endfor%} + + +{%for lesion in lesions%} + +{%endfor%} + + +{%for lesion in lesions%} + +{%endfor%} + + +{%for lesion in lesions%} + +{%endfor%} + + +{%for lesion in lesions%} + +{%endfor%} + + +{%for lesion in lesions%} + +{%endfor%} + + +{%for lesion in lesions%} + +{%endfor%} + + +{%for lesion in lesions%} + +{%endfor%} + + +{%for lesion in lesions%} + +{%endfor%} + + + + + + + + +{%for lesion in lesions%} + +{%endfor%} + + +{%for lesion in lesions%} + +{%endfor%} + + +{%for lesion in lesions%} + +{%endfor%} + + +{%for lesion in lesions%} + +{%endfor%} + + +{%for lesion in lesions%} + +{%endfor%} + + +{%for lesion in lesions%} + +{%endfor%} + + +{%for lesion in lesions%} + +{%endfor%} + + +{%for lesion in lesions%} + +{%endfor%} + + +{%for lesion in lesions%} + +{%endfor%} + + +{%for lesion in lesions%} + +{%endfor%} + + +{%for lesion in lesions%} + +{%endfor%} + + +{%for lesion in lesions%} + +{%endfor%} + + + {%for lesion in lesions%} + + {%endfor%} + + +{%for lesion in lesions%} + +{%endfor%} + + + +
Lesion No.{{contacts.start_index|add:forloop.counter0}}確èª
CT Calibration table{{lesion.get_calibration_table_display}}
å½±åƒå¯†åº¦ä¿®æ­£{{lesion.density_correction}}
Location{{lesion.sub_location.target_location}}-{{lesion.sub_location}}
Tumor dimension (mm){{lesion.dimensions}}
Tumor volume + {% if lesion.volume_measure %} + {{ lesion.volume_measure.cubic_centimeter }} cm3 + {% else %} + {{ lesion.volume }} mm3 + {% endif %} +
Volume treated at ref. dose (cm3) + +
Plan name{{lesion.plan_name|default:" "}}
Collimator Type{{lesion.get_collimator_type_display}}
Collimator size(mm){{lesion.collimator}}
Path No.{{lesion.path_no}}
Beam No.{{lesion.beam_no}}
Px dose(cGy){{lesion.dose}}
Fraction No.{{lesion.fractions}}
Px isodose line(%){{lesion.iso_dose_curve}}
Max. dose(cGy){{lesion.dmax}}
Min. dose(cGy){{lesion.dmin}}
Mean. dose(cGy){{lesion.dmean}}
Coverage % at ref. dose{{lesion.coverage}}
CI: PIV/TIV{{lesion.ci}}
nCI: PIVxTV/TIV2{{lesion.nci}}
HI: Dmax/RxDose + +
Date{%ifequal lesion.start_date lesion.end_date%}{{lesion.end_date}}{%else%}{{lesion.start_date}} ~ {{lesion.end_date|date:"m-d"}}{%endifequal%}
Memo{{lesion.memo|default:" "}}
物ç†å¸« plan
物ç†å¸« verify
+
+{% endwith %} + + + + + + + + + diff --git a/mysite/ck/templates/ck/treatment_record.html b/mysite/ck/templates/ck/treatment_record.html new file mode 100755 index 0000000..a401dfd --- /dev/null +++ b/mysite/ck/templates/ck/treatment_record.html @@ -0,0 +1,198 @@ + + + + +CyberKnife病患紀錄 + + + + + + +
+ +
+ +
+ + + + + + +
+ 國 ç«‹ å° ç£ å¤§ å­¸ 醫 å­¸ 院 附 設 醫 院
+ 電腦刀放射手術
+
+ + +
+ + + + + + + + + + + + + + + +
+ CyberKnife病患紀錄 + 轉介醫師:{{treatment.referral}}
主治醫師:{{treatment.surgeon}}
放腫醫師:{{treatment.oncologist}}
+ +
+ + + + + + + +
基本資料姓å: {{treatment.patient.name}}病歷號: {{treatment.patient.medical_records}}
+ 出生年月日: {{treatment.patient.birthday}}
性別: {{treatment.patient.get_gender_display}}病床號: {{treatment.bed}}
+ + + + + + +
診斷{{treatment.icd9}}{{treatment.other_diagnosis}}Pathology________
+ + + + + + +
治療部ä½________Grade:________Stage{{treatment.disease_stage}}
+ +

Previous Treatment

+ + + + + + + + + + {% for prior in treatment.patient.priortreatment_set.all|dictsort:"date" %} + + + + + + + {% endfor %} + + + + + + + +
DateTreatmentDose(cGy)Memo
{{ prior.date }}{{ prior.get_treatment_display }}{{ prior.dose }}{{ prior.memo }}
    
+ +

History

+ + + + + + + + + + + + + +
 
 
 
 
 
 
 
 
 
 
 
+ +

國立å°ç£å¤§å­¸é†«å­¸é™¢é™„設醫院 電腦刀放射手術

+ +
+ + + + + + + + diff --git a/mysite/ck/templates/ck/treatment_report.html b/mysite/ck/templates/ck/treatment_report.html new file mode 100755 index 0000000..9708664 --- /dev/null +++ b/mysite/ck/templates/ck/treatment_report.html @@ -0,0 +1,312 @@ +{% load calculate_age %} +{% load stack %} + + + + + +電腦刀治療紀錄 + + + + + +
+ +
+ +
+ + + + + + + + + +
+ 國 ç«‹ å° ç£ å¤§ å­¸ 醫 å­¸ 院 附 設 醫 院
National Taiwan University Hospital
+ 電腦刀(CyberKnife) 治療紀錄
+ + + +
+ +{% with contacts.object_list as lesions %} +
+ + + + + + + + + +
å§“å:{{treatment.patient.name}}性別: +{% ifequal treatment.patient.gender 1 %} +ç”· +{% else %} +女 +{% endifequal %} + 生日:{{treatment.patient.birthday}}年齡:{{ treatment.patient.birthday|timesince:treatment.date_started }}病歷號碼:{{treatment.patient.medical_records}}
+ + + + + + +
治療日期:{{treatment.date_started}} +{% ifnotequal treatment.date_started treatment.date_completed %} + ~ {{treatment.date_completed}} +{% endifnotequal %} + 報告日期:{% now "Y-m-d" %}醫師: +{% if treatment.surgeon %} +{{treatment.surgeon}}, +{% endif %} +{{treatment.oncologist}}
+
+ + + + + + +{%for lesion in lesions%} + +{%endfor%} + + + + +{%for lesion in lesions%} + +{%endfor%} + + +{%for lesion in lesions%} + +{%endfor%} + + +{%for lesion in lesions%} + +{%endfor%} + + +{%for lesion in lesions%} + +{%endfor%} + + + + +{%for lesion in lesions%} + +{%endfor%} + + +{%for lesion in lesions%} + +{%endfor%} + + +{%for lesion in lesions%} + +{%endfor%} + + + + +{%for lesion in lesions%} + +{%endfor%} + + + + +{%for lesion in lesions%} + +{%endfor%} + + +{%for lesion in lesions%} + +{%endfor%} + + +{%for lesion in lesions%} + +{%endfor%} + + +{%for lesion in lesions%} + +{%endfor%} + + +{%for lesion in lesions%} + +{%endfor%} + + +{%for lesion in lesions%} + +{%endfor%} + + +{%for lesion in lesions%} + +{%endfor%} + + +{%for lesion in lesions%} + +{%endfor%} + + +{%for lesion in lesions%} + +{%endfor%} + + +{%for lesion in lesions%} + +{%endfor%} + + +{%for lesion in lesions%} + +{%endfor%} + + +{%for lesion in lesions%} + +{%endfor%} + + +
Lesion No.{{contacts.start_index|add:forloop.counter0}}
Location{{lesion.sub_location.target_location}}-{{lesion.sub_location}}
Tumor dimension (mm){{lesion.dimensions}}
Tumor volume(mm3){{lesion.volume}}
Volume treated at ref. dose (mm3) + +
Collimator size(mm){{lesion.collimator}}
Path No.{{lesion.path_no}}
Beam No.{{lesion.beam_no}}
MU limit(Max./Min.){{lesion.mu_max}}/{{lesion.mu_min}}
Px dose(cGy){{lesion.dose}}
Fraction No.{{lesion.fractions}}
Px isodose line(%){{lesion.iso_dose_curve}}
Max. dose(cGy){{lesion.dmax}}
Min. dose(cGy){{lesion.dmin}}
Mean dose(cGy){{ 100|stnew|stpush:100|stpush:lesion.coverage|stsub|stpush:lesion.dose|stpush:lesion.dmin|stadd|stmult|stpush:lesion.dose|stpush:lesion.dmax|stadd|stpush:lesion.coverage|stmult|stadd|stpush:200|stdiv|stget|floatformat:2 }}
Coverage % at ref. dose{{lesion.coverage}}
CI: PIV/TIV{{lesion.ci}}
nCI: PIVxTV/TIV2{{lesion.nci}}
HI: Dmax/RxDose + +
Date{%ifequal lesion.start_date lesion.end_date%}{{lesion.end_date}}{%else%}{{lesion.start_date}} ~ {{lesion.end_date|date:"m-d"}}{%endifequal%}
Memo{{lesion.memo|default:" "}}
+
+{% endwith %} + + + + + + + + + diff --git a/mysite/ck/templates/ck/vevent_confirm_delete.html b/mysite/ck/templates/ck/vevent_confirm_delete.html new file mode 100755 index 0000000..2336fa5 --- /dev/null +++ b/mysite/ck/templates/ck/vevent_confirm_delete.html @@ -0,0 +1,13 @@ +{% extends "base.html" %} + +{% block title %} +Confirm delete +{% endblock %} + +{% block content %} +

Confirm delete {{object.name}}

+
{% csrf_token %} +

Are you sure?

+ +
+{% endblock %} diff --git a/mysite/ck/templates/ck/vevent_form.html b/mysite/ck/templates/ck/vevent_form.html new file mode 100755 index 0000000..0f1d3b4 --- /dev/null +++ b/mysite/ck/templates/ck/vevent_form.html @@ -0,0 +1,152 @@ +{% extends "base.html" %} + +{% block head %} + + + + + + + + + +{% endblock %} + +{% block title %} +Event Form +{% endblock %} + +{% block content %} +{% if object %} + {{object.treatment.patient}} {{object.treatment.patient.medical_records}} +

Update event

+{% else %} + {{treatment.patient}} {{treatment.patient.medical_records}} +

Create event

+{% endif %} + +{% if form.has_errors %} +

Please correct the following error{{ form.errors|pluralize }}:

+{% endif %} + +{{object.treatment.patient.name}} +
{% csrf_token %} + + + +

+ {{ form.mode }} + {% if form.mode.errors %}{{ form.mode.errors }}{% endif %} + {{ form.mode_remark }} + {% if form.mode_remark.errors %}{{ form.mode_remark.errors }}{% endif %} +

+ +

+ {{ form.DTSTART }} + + + {% if form.DTSTART.errors %}{{ form.DTSTART.errors }}{% endif %}

+ +

+ {{ form.DURATION }} + {% if form.DURATION.errors %}{{ form.DURATION.errors }}{% endif %}

+

+ {{ form.DESCRIPTION }} + {% if form.DESCRIPTION.errors %}{{ form.DESCRIPTION.errors }}{% endif %}

+

+ {{ form.price }} + {% if form.price.errors %}{{ form.price.errors }}{% endif %}

+

治療時間相關資訊

+

+ {{ form.DTEND }} + {% if form.DTEND.errors %}{{ form.DTEND.errors }}{% endif %}

+

+ {{ form.break_frequency }} + {% if form.break_frequency.errors %}{{ form.break_frequency.errors }}{% endif %}

+

+ {{ form.system_err }} + {% if form.system_err.errors %}{{ form.system_err.errors }}{% endif %}

+

+ {{ form.shift }} + {% if form.shift.errors %}{{ form.shift.errors }}{% endif %}

+

+ {{ form.cone }} + {% if form.cone.errors %}{{ form.cone.errors }}{% endif %}

+

+ {{ form.path }} + {% if form.path.errors %}{{ form.path.errors }}{% endif %}

+
+ +
+ Return to treatment + Return to patient +
+ + + +{% endblock %} diff --git a/mysite/ck/templates/registration/login.html b/mysite/ck/templates/registration/login.html new file mode 100755 index 0000000..c6a17e3 --- /dev/null +++ b/mysite/ck/templates/registration/login.html @@ -0,0 +1,20 @@ +{% extends "base.html" %} + +{% block content %} + + {% if form.errors %} +

Sorry, that's not a valid username or password

+ {% endif %} + +
+ {% csrf_token %} + + + + + + + + + +{% endblock %} diff --git a/mysite/ck/templates/wdCalendar.html b/mysite/ck/templates/wdCalendar.html new file mode 100755 index 0000000..c448c48 --- /dev/null +++ b/mysite/ck/templates/wdCalendar.html @@ -0,0 +1,291 @@ +{% extends "base.html" %} +{% block title %} + My Calendar +{% endblock %} +{% block head %} + + + + + + + + + + + + + + + + + + + + +{% endblock %} +{% block content %} +
+ +
+
My Calendar
+ + +
+ +
+
+
+ + New Event +
+
+
+
+
+ Today
+
+
+ +
+
Day
+
+
+
Week
+
+
+
Month
+ +
+
+
+
Refresh
+
+
+
+ + +
+
+ +
+
+
+ + Loading + +
+
+ +
+
+
+
+ +
+  
+
+  
+
+
+
+
+
+ +  
+
+   +
+
+ +
+{% endblock %} diff --git a/mysite/ck/templatetags/__init__.py b/mysite/ck/templatetags/__init__.py new file mode 100755 index 0000000..e69de29 diff --git a/mysite/ck/templatetags/calculate_age.py b/mysite/ck/templatetags/calculate_age.py new file mode 100755 index 0000000..13a0197 --- /dev/null +++ b/mysite/ck/templatetags/calculate_age.py @@ -0,0 +1,12 @@ +from django import template +import datetime + +register = template.Library() + +def age(bday, d=None): + if d is None: + d = datetime.date.today() + return (d.year - bday.year) - int((d.month, d.day) < (bday.month, bday.day)) + +register.filter('age', age) + diff --git a/mysite/ck/templatetags/stack.py b/mysite/ck/templatetags/stack.py new file mode 100755 index 0000000..bcfc019 --- /dev/null +++ b/mysite/ck/templatetags/stack.py @@ -0,0 +1,109 @@ +from django import template + +import math + +register = template.Library() + +class stack: + def __init__(self): + self.stack = [] + + def push(self, o): + self.stack.append(o) + #print 'push', self.stack + + def pop(self): + if len(self.stack) == 0: + # raise KeyError, "Stack is empty" + raise KeyError("Stack is empty") + o = self.stack[-1] + #print 'pop', self.stack + del self.stack[-1] + return o + + def is_empty(self): + return len(self.stack) == 0 + + def __len__(self): + return len(self.stack) + +# truncate a floating point number only if it has no decimal part (convert from string if necessary) +def number(num): + f = float(num) + i = int(f) + if i == f: #FIXME: floating point equality? + return i + return f + +stacks = {} + +@register.filter +def stnew(value): + #print 'stnew' + stacks[value] = stack() + return value + +@register.filter +def stpush(value, arg): + #print 'stpush:', + stacks[value].push(number(arg)) + return value + +@register.filter +def stpop(value): + #print 'stpop:', + if value in stacks: + stacks[value].pop() + return value + +@register.filter +def stget(value): + #print 'stget:', + if value in stacks: + return stacks[value].pop() + +@register.filter +def stadd(value): + #print 'stadd:', + two = stacks[value].pop() + one = stacks[value].pop() + stacks[value].push(one + two) + return value + +@register.filter +def stsub(value): + #print 'stsub:', + two = stacks[value].pop() + one = stacks[value].pop() + stacks[value].push(one - two) + return value + +@register.filter +def stmult(value): + #print 'stmult:', + two = stacks[value].pop() + one = stacks[value].pop() + stacks[value].push(one * two) + return value + +@register.filter +def stdiv(value): + #print 'stdiv:', + two = stacks[value].pop() + one = stacks[value].pop() + stacks[value].push(number(float(one) / float(two))) + return value + +@register.filter +def stmod(value): + two = stacks[value].pop() + one = stacks[value].pop() + stacks[value].push(one % two) + return value + +@register.filter +def stsqrt(value): + one = stacks[value].pop() + stacks[value].push(math.sqrt(one)) + return value + diff --git a/mysite/ck/tests.py b/mysite/ck/tests.py new file mode 100755 index 0000000..7ce503c --- /dev/null +++ b/mysite/ck/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/mysite/ck/unf.py b/mysite/ck/unf.py new file mode 100755 index 0000000..97c0513 --- /dev/null +++ b/mysite/ck/unf.py @@ -0,0 +1,269 @@ +#!/usr/bin/python +# coding=utf-8 + +from intra import * + +import datetime +import time + + +def unf(): + unf1 = unf_sort(-30,-7) + dr1 = unf1['dr'] + resident1 = unf1['resident'] + division1 = unf1['division'] + + unf2 = unf_sort(-365,-31) + dr2 = unf2['dr'] + resident2 = unf2['resident'] + division2 = unf2['division'] + + length = max(len(dr1), + len(resident1), + len(dr2), + len(resident2)) + + result=[] + + result.append(['主治醫師','科別','份數','ä½é™¢é†«å¸«','份數','主治醫師','科別','份數','ä½é™¢é†«å¸«','份數']) + + d1 = 0 + r1 = 0 + d2 = 0 + r2 = 0 + for i in range(length): + r = [] + if i < len(dr1): + r.append(dr1[i][0]) + if vs.has_key(dr1[i][0]): + r.append(vs[dr1[i][0]]) + else: + r.append('') + r.append(dr1[i][1]) + d1 += dr1[i][1] + else: + r.append('') + r.append('') + r.append('') + if i < len(resident1): + r.append(resident1[i][0]) + r.append(resident1[i][1]) + r1 += resident1[i][1] + else: + r.append('') + r.append('') + if i < len(dr2): + r.append(dr2[i][0]) + if vs.has_key(dr2[i][0]): + r.append(vs[dr2[i][0]]) + else: + r.append('') + r.append(dr2[i][1]) + d2 += dr2[i][1] + else: + r.append('') + r.append('') + r.append('') + if i < len(resident2): + r.append(resident2[i][0]) + r.append(resident2[i][1]) + r2 += resident2[i][1] + else: + r.append('') + r.append('') + + result.append(r) + +# output = open('/home/xfr/mysite/site_media/unf.html','w') + output = open('/SharedDocs/html/media.ntuh.net/unf.html','w') + + print >> output, """ + + + +å¤–ç§‘éƒ¨ç—…æ­·æœªå®Œæˆ + + +""" + + print >> output, "" + print >> output, "" % time.asctime() + print >> output, "" % ('7至30æ—¥','è¶…éŽ30æ—¥') + for r in result: + print >> output ,"" + for c in r: + print >> output, "" % c + print >> output ,"" + + print >> output, "" + print >> output, "" + print >> output, "" % d1 + print >> output, "" % r1 + print >> output, "" % d2 + print >> output, "" % r2 + print >> output, "" + + print >> output, "
%s
%s%s
%s
---
總計%i總計%i總計%i總計%i
" + print >> output, "
" + print >> output, "" + + + div1 = dict(division1) + div2 = dict(division2) + + for div in div1.keys(): + if not div2.has_key(div): + div2[div] = 0 + + for div in div2.keys(): + if not div1.has_key(div): + div1[div] = 0 + + div3 = {} + for div in div1.keys(): + div3[div] = div1[div] + div2[div] + + +# print div1 +# print div2 +# print div3 + + division_sort = sorted(list(div3), key=lambda x: -div3[x]) + # print division_sort + + print >> output, "" + for div in division_sort: + print >> output, "" % div + print >> output, "" + + print >> output, "" + for div in division_sort: + print >> output, "" % div1[div] + print >> output, "" + + print >> output, "" + for div in division_sort: + print >> output, "" % div2[div] + print >> output, "" + + print >> output, "" + for div in division_sort: + print >> output, "" % div3[div] + print >> output, "" + + + print >> output, "
%s
7至30日%s
è¶…éŽ30æ—¥%s
åˆè¨ˆ%s
" + + print >> output, "" + + + + output.close() + + return result + +def unf_month(): + day = datetime.date.today().day + EndDate = datetime.date.today() + datetime.timedelta(days=-day) + + unf1 = unf_sort(-365,-day) + dr1 = unf1['dr'] + resident1 = unf1['resident'] + division1 = unf1['division'] + + length = max(len(dr1), + len(resident1)) + + result=[] + + result.append(['主治醫師','科別','份數','ä½é™¢é†«å¸«','份數']) + + d1 = 0 + r1 = 0 + for i in range(length): + r = [] + if i < len(dr1): + r.append(dr1[i][0]) + if vs.has_key(dr1[i][0]): + r.append(vs[dr1[i][0]]) + else: + r.append('') + r.append(dr1[i][1]) + d1 += dr1[i][1] + else: + r.append('') + r.append('') + r.append('') + if i < len(resident1): + r.append(resident1[i][0]) + r.append(resident1[i][1]) + r1 += resident1[i][1] + else: + r.append('') + r.append('') + + result.append(r) + +# output = open('/home/xfr/mysite/site_media/unf.html','w') + output = open('/SharedDocs/html/media.ntuh.net/unf_month.html','w') + + print >> output, """ + + + +ä¸Šæœˆå¤–ç§‘éƒ¨ç—…æ­·æœªå®Œæˆ + + +""" + + print >> output, "" + print >> output, "" % time.asctime() + print >> output, "" % EndDate + for r in result: + print >> output ,"" + for c in r: + print >> output, "" % c + print >> output ,"" + + print >> output, "" + print >> output, "" + print >> output, "" % d1 + print >> output, "" % r1 + print >> output, "" + print >> output, "
%s
%så‰
%s
---
總計%i總計%i
" + + print >> output, "
" + print >> output, "" + + + div1 = dict(division1) + +# print div1 +# print div2 +# print div3 + + division_sort = sorted(list(div1), key=lambda x: -div1[x]) + # print division_sort + + print >> output, "" + for div in division_sort: + print >> output, "" % div + print >> output, "" + + print >> output, "" + for div in division_sort: + print >> output, "" % div1[div] + print >> output, "" + + + print >> output, "
%s
åˆè¨ˆ%s
" + + print >> output, "" + + output.close() + + return result + + +unf() +unf_month() diff --git a/mysite/ck/views.py b/mysite/ck/views.py new file mode 100755 index 0000000..a392f65 --- /dev/null +++ b/mysite/ck/views.py @@ -0,0 +1,2275 @@ +# coding=utf-8 + +from functools import cache + +import datetime, re + + + +# Create your views here. + +# import mx.DateTime + +from django.contrib import auth +from django.contrib.auth.decorators import login_required +from django.core.mail import send_mail +from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger +from django.db.models import * +from django.http import Http404, HttpResponse, HttpResponseRedirect, JsonResponse +#from django.newforms import form_for_instance +from django.shortcuts import * +# from django.shortcuts import render +from django.template import RequestContext +from django.urls import reverse_lazy +# from django.utils import simplejson +from django.views.generic import * + +import django.core.serializers + +# from cachier import cachier +from dal import autocomplete +from datatableview import Datatable, columns, helpers +from datatableview.views import DatatableView, XEditableDatatableView +from django_tables2 import SingleTableView +from rest_framework import generics, viewsets + +from .forms import * +from .models import * +from .serializers import * +from .tables import * + +from .common import AddPatient, SortNHI, UpdateNHICase, QueryMS + +#import ntuhgov.intra as intra +import ntuhgov.portal +# import ntuhgov import portal_spynner3 as portal_spynner +# from ntuhgov import portal_spynner3 as portal +# from ntuhgov import portal_ghost_xvfb as portal +from ntuhgov import portal_selenium as portal + +# from . import kd22 + +import logging +logger = logging.getLogger(__name__) + + +# @cache +# @cachier(next_time=True) +def top_icd10(q=None): + # qs = ICD10CMfinal.objects.annotate(count=Count('treatment')).order_by('-count') + # if q: + # qs = qs.filter( + # Q(ICD10CM__istartswith=q) + # | Q(ICD9CM_code__istartswith=q) + # | Q(ICD10CM_English__icontains=q) + # | Q(ICD9CM_English__icontains=q)) + # return qs + + if q is None: + return ICD10CMfinal.objects.all().order_by('-icd10count__count') + return ICD10CMfinal.objects.all() + return ICD10CMfinal.objects.annotate(count=Count('treatment')).order_by('-count') + return top_icd10(None).filter( + Q(ICD10CM__istartswith=q) + | Q(ICD9CM_code__istartswith=q) + | Q(ICD10CM_English__icontains=q) + | Q(ICD9CM_English__icontains=q)) + +@cache +def top_icd10_list(n): + return [x.ICD10CM for x in ICD10CMfinal.objects.all().order_by('-icd10count__count')[:n]] + + +class ICD10Autocomplete(autocomplete.Select2QuerySetView): + def get_queryset(self): + # Don't forget to filter out results depending on the visitor ! + if not self.request.user.is_authenticated: + return ICD10CMfinal.objects.none() + + # qs = ICD10CMfinal.objects.all() + qs = top_icd10(self.q) + + return qs + + +def top_icd10_list_dict(request): + # a = top_icd10() + # print(type(a)) + # for i in a: + # print(i, type(i)) + # break + count=10 + # return JsonResponse(list(top_icd10()[:count].values()), safe=False) + return JsonResponse(list(top_icd10().values()[:count]), safe=False) + +class CreateForPatient(CreateView): + # def get_initial(self): + # patient = get_object_or_404(Patient, pk=self.kwargs.get('patient_id')) + # return { + # 'patient': patient, + # } + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + context["patient"] = get_object_or_404(Patient, pk=self.kwargs.get('patient_id')) + return context + + +class CreateEventForTreatment(CreateView): + fields = '__all__' + def get_initial(self): + treatment = get_object_or_404(Treatment, pk=self.kwargs.get('treatment_id')) + return { + 'treatment': treatment, + } + + + +@login_required +def patient_add(request): + if request.method == 'GET': + parameters = request.GET + elif request.method == 'POST': + parameters = request.POST + + chartno = parameters.get('ChartNo', '') + name = parameters.get('Name', '') + idcode = parameters.get('idcode', '') + force = parameters.get('force', '') + + # p = AddPatient({'IdNo': idcode, 'ChartNo': chartno,}, force=force) + + r = portal.QueryModifyPatBase({'IdNo': idcode, + 'ChartNo': chartno, + }) + + if r: + r['name'] = r['ChtName'] + r['medical_records'] = r['ChartNo'] + r['gender'] = r['Sex'] + r['birthday'] = r['Birth'] + r['address'] = r['AddressControl1'] + r['phone'] = r['ContTel'] + r['id_cards'] = r['IdNo'] + + result = [r] + else: + result = [] + + if force and len(result)>0: + r=result[0] + + if r['gender'] == 'M': + r['gender'] = 1 + else: + r['gender'] = 2 +# hw = intra.HeightWeight(r['id_cards']) +# hw = ntuhgov.portal.HeightWeight(r['id_cards']) + hw = portal.BriefHistoryLink(r['id_cards']) + p = Patient(name = r['name'], + medical_records = r['medical_records'], + gender = r['gender'], + birthday = r['birthday'], + address = r['address'], + phone = r['phone'], + id_cards = r['id_cards'], + # height = hw['Height'], + # weight = hw['weight'], + ) + + try: + p.height = int(hw['Height']) + except: + pass + try: + p.weight = int(hw['Weight']) + except: + pass + p.save() + return HttpResponseRedirect('/patient/detail/%d/' % p.id) + + form = PatientForm() + return render(request, 'ck/patient_add.html', + { + 'form': form, + 'result': result, + } + ) + return render_to_response('ck/patient_add.html', + { + 'form': form, + 'result': result, + }, context_instance=RequestContext(request)) + +@login_required +def patient_detail(request, object_id): + if object_id=='': + object_id = request.session.get('patient') + patient = Patient.objects.get(id=object_id) + if object_id: + qset = ( + Q(patient=object_id) + ) + treatments = Treatment.objects.filter(qset).distinct() + else: + treatments = [] + +# update patient timestamp + +# ts = patient.timestamp.date() +# for treatment in treatments: +# if treatment.date_completed > ts: +# ts = treatment.date_completed +# if patient.timestamp.date() != ts: +# patient.timestamp = datetime.datetime.combine(ts, patient.timestamp.time()) +# patient.save() + + pacsimages = PACSImage.objects.filter(Q(patient=object_id),Q(Modality__startswith='CT')|Q(Modality__startswith='MR')).order_by('-ExamDate') + if len(pacsimages) > 9: + pacsimages = pacsimages[0:9] + + # response = render_to_response("ck/patient_detail.html", + # { + # "patient": patient, + # "treatments": treatments, + # "pacsimages": pacsimages, + # }, context_instance=RequestContext(request)) + response = render(request, "ck/patient_detail.html", + { + "patient": patient, + "treatments": treatments, + "pacsimages": pacsimages, + } + ) + response.set_cookie('patient', object_id) + request.session['patient'] = object_id + return response + +@login_required +def patient_follow(request): + pass + + +@login_required +def patient_print(request, object_id): + if object_id=='': + object_id = request.session.get('patient') + patient = Patient.objects.get(id=object_id) + if object_id: + qset = ( + Q(patient=object_id) + ) + treatments = Treatment.objects.filter(qset).distinct() + else: + treatments = [] + +# update patient timestamp + +# ts = patient.timestamp.date() +# for treatment in treatments: +# if treatment.date_completed > ts: +# ts = treatment.date_completed +# if patient.timestamp.date() != ts: +# patient.timestamp = datetime.datetime.combine(ts, patient.timestamp.time()) +# patient.save() + + # response = render_to_response("ck/patient_print.html", + # { + # "patient": patient, + # "treatments": treatments, + # }, context_instance=RequestContext(request)) + response = render(request, "ck/patient_print.html", + { + "patient": patient, + "treatments": treatments, + } + ) + response.set_cookie('patient', object_id) + request.session['patient'] = object_id + return response + + +@login_required +def patient_search(request): + query = request.GET.get('q', '') + if query: + qset = ( + Q(medical_records__icontains=query) | + Q(name__icontains=query) | + Q(id_cards__iexact=query) + ) + results = Patient.objects.filter(qset).distinct() + if len(results) == 0: + if re.match('^\d+', query): + return HttpResponseRedirect('/patient/add/?ChartNo='+query) + elif re.match('^\w\d+', query): + return HttpResponseRedirect('/patient/add/?idcode='+query) + else: + return HttpResponseRedirect('/patient/add/?Name='+query) + else: + results = [] +# print "query=", query +# print "results=", results + return render(request, 'ck/patient_search.html', + { + "results": results, + "query": query, + } + ) + return render_to_response("ck/patient_search.html", + { + "results": results, + "query": query, + }, context_instance=RequestContext(request)) + + + + +class PatientDatatableView(XEditableDatatableView): + model = Patient + + class datatable_class(Datatable): + + gender_display = columns.TextColumn ('Gender1', sources=['get_gender_display']) + + detail = columns.DisplayColumn('Detail' , processor='ProcessDetail') + operations = columns.DisplayColumn('Operations', processor='ProcessOperations') + + def ProcessDetail(self, *args, **kwargs): + data = args[0] + return f''' + launch + ''' + + def ProcessOperations(self, *args, **kwargs): + data = args[0] + # print(data) + # default_value = kwargs['default_value'] + return f''' + edit + delete + ''' + + class Meta: + ordering = ['-id'] + + columns = [ + 'detail', + + 'id', + 'name', + 'medical_records', + 'gender_display', + 'birthday', + # 'address', + 'phone', + 'id_cards', + 'memo', + 'dead', + + 'operations', + ] + + processors = { + 'memo': helpers.make_xeditable(), + } + +# django-tables2 +# class PatientListView(ListView): +class PatientListView(SingleTableView): + model = Patient + table_class = PatientTable + # template_name = 'tutorial/people.html' + +# django-rest-framework-datatables +class PatientViewSet(viewsets.ModelViewSet): + queryset = Patient.objects.all().order_by('name') + serializer_class = PatientSerializer + + + +@login_required +def prior_oncrt_query(request, object_id): + if object_id=='': + object_id = request.session.get('patient') + patient = Patient.objects.get(id=object_id) + priors = patient.priortreatment_set; + + answers = intra.oncrt_query(patient.medical_records) + +# return HttpResponse(str(answers)) + + for answer in answers: + if answer['way'] != 'Radiosurgery' and not priors.filter(date=answer['start_date']): + p = PriorTreatment( + patient = patient, + date = answer['start_date'], + treatment = 3, + period = 1, + dose = answer['total_dose'], + memo = answer['site'] + ' ' + answer['remarks'], + ) + p.save() + return HttpResponseRedirect('/patient/detail/'+object_id) + + +@login_required +def prior_op_note(request, object_id): + if object_id=='': + object_id = request.session.get('patient') + patient = Patient.objects.get(id=object_id) + priors = patient.priortreatment_set; + +# answers = intra.op_note_case(patient.medical_records) + answers = ntuhgov.portal.op_note_case(patient.medical_records) + +# return HttpResponse(str(answers)) + + for answer in answers: + if not priors.filter(date=answer['surgery_date_time']): + p = PriorTreatment( + patient = patient, + date = answer['surgery_date_time'], + treatment = 1, + memo = ' '.join([answer['division'], answer['name_surgery'], answer['surgeon']]) + ) + p.save() + return HttpResponseRedirect('/patient/detail/'+object_id) + +@login_required +def prior_path_exam(request, object_id): + if object_id=='': + object_id = request.session.get('patient') + patient = Patient.objects.get(id=object_id) + pathexams = patient.pathexam_set; + +# answers = intra.path_exam(patient.medical_records) + import ntuhgov.xportal + answers = ntuhgov.xportal.ReportPathology(patient.medical_records) + +# return HttpResponse(str(answers)) + + for answer in answers: + if not pathexams.filter(path_code=answer['PathCode']): + p = PathExam( + patient = patient, + path_code = answer['PathCode'], + specimen_code = answer['SpecimenCode'], + specimen_get_date = answer['SpecimenGetDate'][:10].replace('/','-'), + report_date = answer['ReportDate'][:10].replace('/','-'), + division = answer['DepCode'], + bed = answer['WardNoRoomCoBedNo'], + report = answer['Result'], + ) + + p.save() + return HttpResponseRedirect('/patient/detail/'+object_id) + +@login_required +def query_height_weight(request, object_id): + if object_id=='': + object_id = request.session.get('patient') + patient = Patient.objects.get(id=object_id) +# hw = intra.HeightWeight(patient.id_cards) + hw = ntuhgov.portal.HeightWeight(patient.id_cards) + patient.height = hw['Height'] + patient.weight = hw['Weight'] + patient.save() + + return HttpResponseRedirect('/patient/detail/'+object_id) + + +@login_required +def record_weekly(request, date): + if not date: + date = mx.DateTime.today() + + Monday = mx.DateTime.DateTimeFrom(date) + mx.DateTime.RelativeDateTime(days=-6,weekday=(mx.DateTime.Monday,0)) + NextMonday = Monday + mx.DateTime.RelativeDateTime(days=+7) + prevweek = mx.DateTime.DateTimeFrom(date) + mx.DateTime.RelativeDateTime(days=-7) + nextweek = mx.DateTime.DateTimeFrom(date) + mx.DateTime.RelativeDateTime(days=+7) + + weekday = ['mon', 'tue', 'wed', 'thu', 'fri', 'sat', 'sun'] + + weekdate = {} + d = Monday + for day in weekday: + weekdate[day] = d.strftime('%m/%d') + d = d + mx.DateTime.RelativeDateTime(days=+1) + +# print NextMonday, NNMonday + sMonday = str(Monday) + sNextMonday = str(NextMonday) + qset1 = Q(DTSTART__range=(sMonday, sNextMonday)) + + qset2 = Q(mode__exact=310) #310: 治療 + + events = VEVENT.objects.filter(qset1, qset2).order_by('DTSTART') + + tids = [] + + for event in events: + tid = event.treatment.id + if not tid in tids: + tids.append(tid) + + treatments = [] + for tid in tids: + t = Treatment.objects.get(id=tid); + treatment = { + 'id': t.id, + 'icd9': t.icd9, + 'other_diagnosis': t.other_diagnosis, + 'accounting': t.get_accounting_display(), + 'dates': [], + 'surgeon': t.surgeon, + 'oncologist': t.oncologist, + 'referral': t.referral, + } + + for event in events: + if tid == event.treatment.id: + treatment['dates'].append(event.DTSTART.date()) + +# for lesion in Treatment.objects.get(id=tid).lesion_set: +# treatment. + + + treatments.append(treatment) + + + +# treatments = Treatment.objects.filter(id__in=tids) + + # response = render_to_response("ck/record_weekly.html", + # { + # "prevweek": prevweek.date, + # "nextweek": nextweek.date, + # "weeknumber": Monday.strftime('%G年 第%V週'), + # "weekdate": weekdate, + # "events": events, + # "treatments": treatments, + # }, context_instance=RequestContext(request)) + + return render(request, 'ck/record_weekly.html', + { + "prevweek": prevweek.date, + "nextweek": nextweek.date, + "weeknumber": Monday.strftime('%G年 第%V週'), + "weekdate": weekdate, + "events": events, + "treatments": treatments, + } + ) + # return response + + +@login_required +def timetable_scheduling(request, date): + if not date: + date = mx.DateTime.today() + + Monday = mx.DateTime.DateTimeFrom(date) + mx.DateTime.RelativeDateTime(days=+6,weekday=(mx.DateTime.Monday,0)) + NextMonday = Monday + mx.DateTime.RelativeDateTime(days=+7) + prevweek = mx.DateTime.DateTimeFrom(date) + mx.DateTime.RelativeDateTime(days=-7) + nextweek = mx.DateTime.DateTimeFrom(date) + mx.DateTime.RelativeDateTime(days=+7) +# print NextMonday, NNMonday + sMonday = str(Monday) + sNextMonday = str(NextMonday) + qset = ( + Q(DTSTART__range=(sMonday, sNextMonday)) + ) + + treatments = Treatment.objects.filter(output__id__lt=900) + + weekday = ['mon', 'tue', 'wed', 'thu', 'fri'] + + weekdate = {} + d = Monday + for day in weekday: + weekdate[day] = d.strftime('%m/%d') + d = d + mx.DateTime.RelativeDateTime(days=+1) + + timetable = [] + for treatment in treatments: + if treatment.vevent_set.filter(qset): + r = {} + patient = treatment.patient + r['name'] = patient.name + r['medical_records'] = patient.medical_records + r['indications'] = str(treatment.surgeon) + '\n' + str(treatment.oncologist) + r['diagnosis_site'] = treatment.other_diagnosis + r['number'] = '' + r['node'] = '' + r['mode'] = '' + r['time'] = '' + r['actual_treatment'] = '' + for day in weekday: + r[day] = '' + for event in treatment.vevent_set.order_by('DTSTART'): + wd = (event.DTSTART.date() - datetime.datetime.fromtimestamp(Monday).date()).days + if wd in range(0, 6): + r[weekday[wd]] += event.DTSTART.strftime('%H:%M') + ' ' + event.get_mode_display() + '\n' + timetable.append(r) + + +# print timetable + + # response = render_to_response("ck/timetable_scheduling.html", + # { + # "prevweek": prevweek.date, + # "nextweek": nextweek.date, + # "timetable": timetable, + # "weekdate": weekdate, + # }, context_instance=RequestContext(request)) + return render(request, 'ck/timetable_scheduling.html', + { + "prevweek": prevweek.date, + "nextweek": nextweek.date, + "timetable": timetable, + "weekdate": weekdate, + } + ) + return response + + +@login_required +def treatment_detail(request, object_id): + if object_id=='': + object_id = request.session.get('treatment') + treatment = Treatment.objects.get(id=object_id) + patient = Patient.objects.get(id=treatment.patient_id) +# response.set_cookie('patient', patient.id) + request.session['patient'] = patient.id + if object_id: + qset = ( + Q(treatment=object_id) + ) + vevents = VEVENT.objects.filter(qset).distinct().order_by('DTSTART') + lesions = Lesion.objects.filter(qset).distinct() + else: + vevents = [] + lesions = [] + +# update treatment date_completed + + for vevent in vevents: + vevent.SUMMARY = vevent.treatment.patient.name + vevent.get_mode_display() + if vevent.mode_remark: + vevent.SUMMARY += vevent.mode_remark + vevent.save() + + ds = False + dc = False + + for lesion in lesions: + if lesion.start_date != None: + if not ds or lesion.start_date < ds: + ds = lesion.start_date + if lesion.end_date != None: + if not dc or lesion.end_date > dc: + dc = lesion.end_date + + if not ds: + for vevent in vevents: + if vevent.mode != 310: + continue + if not ds or vevent.DTSTART.date() < ds: + ds = vevent.DTSTART.date() + if not dc or vevent.DTSTART.date() > dc: + dc = vevent.DTSTART.date() + + if not ds: + for vevent in vevents: + if not ds or vevent.DTSTART.date() < ds: + ds = vevent.DTSTART.date() + if not dc or vevent.DTSTART.date() > dc: + dc = vevent.DTSTART.date() + + if ds and treatment.date_started != ds: + treatment.date_started = ds + treatment.save() + if dc and treatment.date_completed != dc: + treatment.date_completed = dc + treatment.save() + + nhiorders = NHIOrder.objects.filter(ChartNo=patient.medical_records) + + # response = render_to_response("ck/treatment_detail.html", + # { + # "patient": patient, + # "treatment": treatment, + # "vevents": vevents, + # "lesions": lesions, + # }, context_instance=RequestContext(request)) + response = render(request, 'ck/treatment_detail.html', + { + "patient": patient, + "treatment": treatment, + "vevents": vevents, + "lesions": lesions, + "nhiorders": nhiorders, + } + ) + response.set_cookie('patient', patient.id) + request.session['patient'] = patient.id + response.set_cookie('treatment', object_id) + request.session['treatment'] = object_id + return response + + + +@login_required +def treatment_print(request, object_id): + if object_id=='': + object_id = request.session.get('treatment') + treatment = Treatment.objects.get(id=object_id) + patient = Patient.objects.get(id=treatment.patient_id) + if object_id: + qset = ( + Q(treatment=object_id) + ) + vevents = VEVENT.objects.filter(qset).distinct().order_by('DTSTART') + lesions = Lesion.objects.filter(qset).distinct() + else: + vevents = [] + lesions = [] + +# update treatment date_completed + + dc = treatment.date_completed + + for vevent in vevents: + vevent.SUMMARY = vevent.treatment.patient.name + vevent.get_mode_display() + if vevent.mode_remark: + vevent.SUMMARY += vevent.mode_remark + vevent.save() + if vevent.DTSTART.date() > dc: + dc = vevent.DTSTART.date() + + if treatment.date_completed != dc: + treatment.date_completed = dc + treatment.save() + + paginator = Paginator(lesions, 3) # Show 3 lesions per page + + # Make sure page request is an int. If not, deliver first page. + try: + page = int(request.GET.get('page', '1')) + except ValueError: + page = 1 + + # If page request (9999) is out of range, deliver last page of results. + try: + contacts = paginator.page(page) + except (EmptyPage, InvalidPage): + contacts = paginator.page(paginator.num_pages) + + # response = render_to_response("ck/treatment_print.html", + # { + # "patient": patient, + # "treatment": treatment, + # "vevents": vevents, + # "contacts": contacts, + # }, context_instance=RequestContext(request)) + response = render(request, 'ck/treatment_print.html', + { + "patient": patient, + "treatment": treatment, + "vevents": vevents, + "contacts": contacts, + } + ) + response.set_cookie('patient', object_id) + request.session['patient'] = object_id + response.set_cookie('treatment', object_id) + request.session['treatment'] = object_id + return response + + +@login_required +def treatment_record(request, object_id): + if object_id=='': + object_id = request.session.get('treatment') + treatment = Treatment.objects.get(id=object_id) + patient = Patient.objects.get(id=treatment.patient_id) + if object_id: + qset = ( + Q(treatment=object_id) + ) + vevents = VEVENT.objects.filter(qset).distinct().order_by('DTSTART') + lesions = Lesion.objects.filter(qset).distinct() + else: + vevents = [] + lesions = [] + +# update treatment date_completed + + dc = treatment.date_completed + + for vevent in vevents: + vevent.SUMMARY = vevent.treatment.patient.name + vevent.get_mode_display() + if vevent.mode_remark: + vevent.SUMMARY += vevent.mode_remark + vevent.save() + if vevent.DTSTART.date() > dc: + dc = vevent.DTSTART.date() + + if treatment.date_completed != dc: + treatment.date_completed = dc + treatment.save() + +# response = render_to_response("ck/treatment_record.html", + # response = render_to_response("ck/brief_history.html", + # { + # "patient": patient, + # "treatment": treatment, + # "vevents": vevents, + # "lesions": lesions, + # }, context_instance=RequestContext(request)) + response = render(request, 'ck/brief_history.html', + { + "patient": patient, + "treatment": treatment, + "vevents": vevents, + "lesions": lesions, + } + ) + response.set_cookie('patient', object_id) + request.session['patient'] = object_id + response.set_cookie('treatment', object_id) + request.session['treatment'] = object_id + return response + + +@login_required +def treatment_report(request, object_id): + if object_id=='': + object_id = request.session.get('treatment') + treatment = Treatment.objects.get(id=object_id) + patient = Patient.objects.get(id=treatment.patient_id) + if object_id: + qset = ( + Q(treatment=object_id) + ) + vevents = VEVENT.objects.filter(qset).distinct().order_by('DTSTART') + lesions = Lesion.objects.filter(qset).distinct() + else: + vevents = [] + lesions = [] + +# update treatment date_completed + + dc = treatment.date_completed + + for vevent in vevents: + vevent.SUMMARY = vevent.treatment.patient.name + vevent.get_mode_display() + if vevent.mode_remark: + vevent.SUMMARY += vevent.mode_remark + vevent.save() + if vevent.DTSTART.date() > dc: + dc = vevent.DTSTART.date() + + if treatment.date_completed != dc: + treatment.date_completed = dc + treatment.save() + + paginator = Paginator(lesions, 5) # Show 25 contacts per page + + # Make sure page request is an int. If not, deliver first page. + try: + page = int(request.GET.get('page', '1')) + except ValueError: + page = 1 + + # If page request (9999) is out of range, deliver last page of results. + try: + contacts = paginator.page(page) + except (EmptyPage, InvalidPage): + contacts = paginator.page(paginator.num_pages) + + # response = render_to_response("ck/treatment_report.html", + # { + # "patient": patient, + # "treatment": treatment, + # "vevents": vevents, + # "contacts": contacts, + # }, context_instance=RequestContext(request)) + response = render(request, 'ck/treatment_report.html', + { + "patient": patient, + "treatment": treatment, + "vevents": vevents, + "contacts": contacts, + } + ) + response.set_cookie('patient', object_id) + request.session['patient'] = object_id + response.set_cookie('treatment', object_id) + request.session['treatment'] = object_id + return response + + +class TreatmentUpdate(UpdateView): + model = Treatment + form_class = TreatmentForm + + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + print(context) + context["topicd10"] = top_icd10 + context['nhiorders'] = NHIOrder.objects.filter(ChartNo=self.object.patient.medical_records) + return context + + +@login_required +def treatment_update(request, object_id): + if request.method == 'POST': +# TreatmentForm = form_for_model(Treatment) + form = TreatmentForm(request.POST) + # print dir(form) + logging.info(dir(form)) + form.save() + return HttpResponseRedirect('/treatment/list/') + + treatment = Treatment.objects.get(id=object_id) + patient = Patient.objects.get(id=treatment.patient.id) +# TreatmentForm = form_for_instance(treatment) + form = TreatmentForm(instance=treatment) +# response = render_to_response("ck/treatment_form2.html", + # response = render_to_response("ck/treatment_form.html", + # { + # "form": form, + # "patient": patient, + # }, context_instance=RequestContext(request)) + response = render(request, "ck/treatment_form.html", + { + "form": form, + "patient": patient, + } + ) + response.set_cookie('treatment', object_id) + request.session['treatment'] = object_id + return response + + +class TreatmentDatatableView(XEditableDatatableView): + model = Treatment + + def setup(self, request, *args, **kwargs): + super().setup(request, *args, **kwargs) + if request.GET.get('download') is not None: + QueryMS() + + class datatable_class(Datatable): + + + patient_name = columns.TextColumn ('Name', sources=['patient__name']) + medical_records = columns.TextColumn ('MRN', sources=['patient__medical_records']) + date = columns.CompoundColumn('Date', sources=['date_started', 'date_completed']) + get_accounting_display = columns.TextColumn ('記帳', sources=['get_accounting_display']) + + # django.core.exceptions.FieldError: Related Field got invalid lookup: icontains + icd10 = columns.TextColumn ('ICD10', processor='ProcessICD10', sources=['icd10cm__ICD10CM']) + icd9 = columns.TextColumn ('ICD9', processor='ProcessICD9', sources=['icd9__code']) + + detail = columns.DisplayColumn('Detail' , processor='ProcessDetail') + operations = columns.DisplayColumn('Operations', processor='ProcessOperations') + + def ProcessICD10(self, *args, **kwargs): + data = args[0] + + if data.icd10cm is None: + return f'
None
' + if data.icd10cm.ICD10CM not in top_icd10_list(10): + return f'
{data.icd10cm.ICD10CM}
' + if data.icd10cm.ICD10CM not in top_icd10_list(5): + return f'
{data.icd10cm.ICD10CM}
' + + return f'
{data.icd10cm.ICD10CM}
' + return str(data.icd10cm) + if data.icd10cm is None: + return None + return f'{data.icd10cm.ICD10CM}' + + def ProcessICD9(self, *args, **kwargs): + data = args[0] + if data.icd9 is None: + return '
None
' + return f'
{data.icd9.code}
' + return str(data.icd9) + + def ProcessDetail(self, *args, **kwargs): + data = args[0] + return f''' + launch + ''' + + def ProcessOperations(self, *args, **kwargs): + data = args[0] + # print(data) + # default_value = kwargs['default_value'] + return f''' + edit + delete + ''' + + class Meta: + ordering = ['-id'] + + columns = [ + 'detail', + + 'id', + 'patient_name', + 'medical_records', + # 'date_started', + # 'date_completed', + 'date', + 'oncologist', + 'surgeon', + 'get_accounting_display', + 'disease_stage', + 'primary_tumor_site', + # 'icd10cm', + 'icd10', + 'icd9', + 'other_diagnosis', + 'input', + 'output', + 'bed', + 'memo', + + 'operations', + ] + + processors = { + 'memo': helpers.make_xeditable(), + } + + # request_method = 'POST' # make_xeditable will not work with post?? + + # search_fields = [ + # # 'patient__medical_records' + # 'memo', + # ] + + +class FinishedTreatmentDatatableView(TreatmentDatatableView): + def get_queryset(self): + queryset = super().get_queryset() + return queryset.filter(**self.request.GET.dict()) + +@login_required +def followup_newimages(request): + + renew = request.REQUEST.get('renew', False) + + if renew: + kd22.renew(PACSImage) + + date_query = Treatment.objects.values('patient_id').annotate(started=Min('date_started'),completed=Max('date_completed')) + images = PACSImage.objects.filter(Q(Saved = 0),Q(Modality__startswith='CT')|Q(Modality__startswith='MR')).order_by('-ExamDate')[:100] + results = [] + + + + blank = 0 + + for image in images: + if blank > 50: + break + try: + treat_date = date_query.get(patient=image.patient) + except: + continue + if image.ExamDate > treat_date['completed']: + try: + LF = LesionFollow.objects.get(Q(Lesion__treatment__patient = image.patient),Q(Date = image.ExamDate)) + image.Saved = 10 #有輸入 + except: + pass + results.append(image) + if image.Saved == 0: + blank += 1 + + return render(request, "ck/followup_newimages.html", + { + "images": results, + } + ) + return render_to_response("ck/followup_newimages.html", + { + "images": results, + }, context_instance=RequestContext(request)) + +@login_required +def followup_markimages(request, RequestSheetNo, Saved): + image = PACSImage.objects.get(Q(RequestSheetNo = RequestSheetNo)) + image.Saved = Saved + image.save() + return HttpResponseRedirect('/followup/newimages/') + +@login_required +def followup_nosee1(request): + treatment_date = Treatment.objects.values('patient_id').annotate(first=Min('date_started'),last=Max('date_completed')) + followup_date = Followup.objects.values('patient_id').annotate(first=Min('date'),last=Max('date')) + record_date = MedicalRecord.objects.values('patient_id').annotate(first=Min('InDate'),last=Max('InDate')) + image_date = PACSImage.objects.values('patient_id').annotate(first=Min('ExamDate'),last=Max('ExamDate')) + + patients = Patient.objects.all() + results = [] +# n = datetime.datetime.now() + for patient in patients: + if patient.dead: + continue + + try: + d = treatment_date.get(patient=patient) + date = d['last'] + except: +# print "%s no treatment" % patient.id + continue + + try: + d = followup_date.get(patient=patient) + if d['last'] > date: + date = d['last'] + except: +# print "%s no follow" % patient.id + pass + + try: + d = record_date.get(patient=patient) + if d['last'] > date: + date = d['last'] + except: +# print "%s no record" % patient.id + pass + + try: + d = image_date.get(patient=patient) + if d['last'] > date: + date = d['last'] + except: +# print "%s no image" % patient.id + pass + +# results['patient.id']=date + results.append((patient, date)) + +# print results + results = sorted(results, key=lambda last: last[1])[:25] +# print datetime.datetime.now() - n +# print results + + return render(request, "ck/followup_nosee.html", + { + "results": results, + } + ) + return render_to_response("ck/followup_nosee.html", + { + "results": results, + }, context_instance=RequestContext(request)) + +@login_required +def followup_nosee(request): + ###Load all dates into hash first + treatment_date = Treatment.objects.values('patient_id').annotate(first=Min('date_started'),last=Max('date_completed')) + t = {} + for item in treatment_date: + t[item['patient_id']] = item['last'] + + followup_date = Followup.objects.values('patient_id').annotate(first=Min('date'),last=Max('date')) + f = {} + for item in followup_date: + f[item['patient_id']] = item['last'] + + record_date = MedicalRecord.objects.values('patient_id').annotate(first=Min('InDate'),last=Max('InDate')) + r = {} + for item in record_date: + r[item['patient_id']] = item['last'] + + image_date = PACSImage.objects.values('patient_id').annotate(first=Min('ExamDate'),last=Max('ExamDate')) + i = {} + for item in image_date: + i[item['patient_id']] = item['last'] + + patients = Patient.objects.all() + results = [] +# n = datetime.datetime.now() + for patient in patients: + if patient.dead: + continue + + try: + d = t[patient.id] + date = d + except: +# print "%s no treatment" % patient.id + continue + + try: + d = f[patient.id] + if d > date: + date = d + except: +# print "%s no follow" % patient.id + pass + + try: + d = r[patient.id] + if d > date: + date = d + except: +# print "%s no record" % patient.id + pass + + try: + d = i[patient.id] + if d > date: + date = d + except: +# print "%s no image" % patient.id + pass + +# results['patient.id']=date + results.append((patient, date)) + +# print results + results = sorted(results, key=lambda last: last[1])[:25] +# print datetime.datetime.now() - n +# print results + + model = Patient + form_class = None + model, form_class = create_update.get_model_and_form_class(model, form_class) + form = form_class() + + return render(request, "ck/followup_nosee.html", + { + "results": results, + "form": form, + } + ) + return render_to_response("ck/followup_nosee.html", + { + "results": results, + "form": form, + }, context_instance=RequestContext(request)) + +@login_required +def followup_image_long(request): + ###Load all dates into hash first + treatment_date = Treatment.objects.values('patient_id').annotate(first=Min('date_started'),last=Max('date_completed')) + t = {} + for item in treatment_date: + t[item['patient_id']] = item['first'] + + image_date = PACSImage.objects.filter(Saved__in=[0,10]).values('patient_id').annotate(first=Min('ExamDate'),last=Max('ExamDate')) + i = {} + for item in image_date: + i[item['patient_id']] = item['last'] + + v = {} + follows = LesionFollow.objects.select_related().all() +# print follows + for follow in follows: + if not v.has_key(follow.Lesion.treatment.patient.id): + v[follow.Lesion.treatment.patient.id] = follow.Date + else: + v[follow.Lesion.treatment.patient.id] = max(follow.Date, v[follow.Lesion.treatment.patient.id]) + +# print v + + + +# patients = Patient.objects.select_related().all() + patients = Patient.objects.all() + + results = [] +# n = datetime.datetime.now() +# print t +# print i + for patient in patients: + if patient.dead: + continue + + try: + d = t[patient.id] + tdate = d + except: +# print "%s no treatment" % patient.id + continue + + try: + d = i[patient.id] + idate = d + except: +# print "%s no image" % patient.id + continue + + daydiff = (idate-tdate).days + if daydiff < 365: + continue + + try: + d = v[patient.id] + vdate = d + except: +# print "%s no image" % patient.id + vdate = '' + + + +# results['patient.id']=date + results.append((patient, daydiff, tdate, idate, vdate)) + +# print type(idate-tdate) +# print results + results = sorted(results, key=lambda last: -last[1]) +# print datetime.datetime.now() - n +# print results + +# model = Patient +# form_class = None +# model, form_class = create_update.get_model_and_form_class(model, form_class) +# form = form_class() + + return render(request, "ck/followup_image_long.html", + { + "results": results, + } + ) + return render_to_response("ck/followup_image_long.html", + { + "results": results, +# "form": form, + }, context_instance=RequestContext(request)) + + +@login_required +def followup_new_volume(request,object_id): +# print request +# print 'object_id=', object_id + + idate = '' + + p = request.POST +# print p + if p.has_key('Lesion'): + lesion = Lesion.objects.get(id=p['Lesion']) + + f = lambda x:None if x == '' else x + + l = LesionFollow( + Lesion = lesion, + Date = p['Date'], + Volume = f(p['Volume']), + A = f(p['A']), + B = f(p['B']), + C = f(p['C']), + Memo = p['Memo'], + ) + l.save() + idate = p['Date'] + + try: + idate = request.GET['idate'] + except: + idate = request.COOKIES['date'] + + try: + patient = Patient.objects.get(id=object_id) + except: + patient = Patient.objects.get(id=request.COOKIES['patient']) + + model = LesionFollow + form_class = None + model, form_class = create_update.get_model_and_form_class(model, form_class) + form = form_class() + + # response = render_to_response("ck/followup_new_volume.html", + # { + # "patient": patient, + # "idate": idate, + # "form": form, + # }, context_instance=RequestContext(request)) + response = render(request, "ck/followup_new_volume.html", + { + "patient": patient, + "idate": idate, + "form": form, + } + ) + response.set_cookie('patient', patient.id) + response.set_cookie('date', idate) + return response + + +########## AJAX + +@login_required +def below(request): + return render(reuqest, 'ck/below.html') + return render_to_response('ck/below.html') + +@login_required +def get_target_location(request): +# return HttpResponse(django.core.serializers.serialize("xml", TargetLocation.objects.all())) + return HttpResponse(django.core.serializers.serialize("json", TargetLocation.objects.all())) + +@login_required +def get_sublocation(request): + i = request.GET.get('id', None) + if i: + return HttpResponse(django.core.serializers.serialize("json", SubLocation.objects.filter(id=i))) + target = request.GET.get('target', None) + return HttpResponse(django.core.serializers.serialize("json", SubLocation.objects.filter(target_location=target))) + +@login_required +def get_pathology(request): + sl = request.GET.get('sublocation', '') + return HttpResponse(django.core.serializers.serialize("json", Pathology.objects.filter(sublocation=sl))) + +def get_icd9cm(request): + id = request.GET.get('id', False) + name = request.GET.get('q', '') + limit = request.GET.get('s', 99) + + if (name.count('.')): + name = name.replace('.', '')[0:5].rstrip() + if id: + codes = ICD9Diag.objects.filter(code=id) + elif len(name): + qset = ( + Q(code__istartswith=name) | +# Q(code__istartswith='0'+name) | +# Q(code__istartswith='00'+name) | + Q(desc__icontains=name) + ) + codes = ICD9Diag.objects.filter(qset)[:100] + else: + codes =ICD9Diag.objects.all()[:100] + + ret = """ +[ +""" + +# ret = '{"results":[' + + for code in codes: +# ret += '["%s","%s"],' % (code.code, code) + ret += '["%s","%s"],' % (code, code.code) +# ret += '\n{"id":"%s","name":"%s"},' % (code.code, code) + + + ret = ret[:-1]+""" +] +""" + + + return HttpResponse(ret) + + +def get_icd9cm_old(request): + id = request.GET.get('id', False) + name = request.GET.get('name', '')[:-1] + if (name.count('.')): + name = name.replace('.', '')[0:5].rstrip() + if id: + codes = ICD9Diag.objects.filter(code=id) + elif len(name): + qset = ( + Q(code__istartswith=name) | +# Q(code__istartswith='0'+name) | +# Q(code__istartswith='00'+name) | + Q(desc__icontains=name) + ) + codes = ICD9Diag.objects.filter(qset)[:100] + else: + codes =ICD9Diag.objects.all()[:100] + + ret = """ +{ 'identifier': 'code', + 'label': 'name', + 'items': [ +""" + +# ret = '{"results":[' + + for code in codes: + ret += '\n{"code":"%s","name":"%s"},' % (code.code, code) +# ret += '\n{"id":"%s","name":"%s"},' % (code.code, code) + + + ret = ret[:-1]+"]}" + + + return HttpResponse(ret) + + +def get_followup(request): + date = request.GET.get('date', '') + if date: + d = mx.DateTime.DateTimeFrom(date) + fr = d + mx.DateTime.RelativeDateTime(weeks=-6) + to = d + mx.DateTime.RelativeDateTime(weeks=+6) + events = Patient.objects.filter(next_followup__range=(fr, to)) + else: + events = Patient.objects.all() + + return HttpResponse(django.core.serializers.serialize("json", events, ensure_ascii=False)) + + +def get_vevent_old(request): + date = request.GET.get('date', '') + if date: + d = mx.DateTime.DateTimeFrom(date) + fr = d + mx.DateTime.RelativeDateTime(weeks=-6) + to = d + mx.DateTime.RelativeDateTime(weeks=+6) + events = VEVENT.objects.filter(DTSTART__range=(fr, to)) + else: + events = VEVENT.objects.all() + + return HttpResponse(django.core.serializers.serialize("json", events, ensure_ascii=False)) + +# ''' +# DataDumper +# ''' +# +# import types +# from django.db import models +# import pyxslt.serialize +# from django.utils import simplejson as json +# from django.core.serializers.json import DateTimeAwareJSONEncoder +# from decimal import * +# +# class DataDumper: +# fields = {} +# def selectObjectFields(self,objectType,fields = []): +# self.fields[objectType] = fields +# +# def dump(self,data,format='xml'): +# """ +# The main issues with django's default json serializer is that properties that +# had been added to a object dynamically are being ignored (and it also has +# problems with some models). +# """ +# +# def _any(data): +# ret = None +# if type(data) is types.ListType: +# ret = _list(data) +# elif type(data) is types.DictType: +# ret = _dict(data) +# elif isinstance(data, Decimal): +# # json.dumps() cant handle Decimal +# ret = str(data) +# elif isinstance(data, models.query.QuerySet): +# # Actually its the same as a list ... +# ret = _list(data) +# elif isinstance(data, models.Model): +# ret = _model(data) +# else: +# ret = data +# return ret +# +# def _model(data): +# ret = {} +# # If we only have a model, we only want to encode the fields. +# objType = data.__class__.__name__ +# for f in data._meta.fields: +# if (self.fields[objType]) and (f.attname in self.fields[objType]): +# ret[f.attname] = _any(getattr(data, f.attname)) +# # And additionally encode arbitrary properties that had been added. +# fields = dir(data.__class__) + ret.keys() +# add_ons = [k for k in dir(data) if k not in fields] +# for k in add_ons: +# if (self.fields[objType]) and (k in self.fields[objType]): +# ret[k] = _any(getattr(data, k)) +# return ret +# def _list(data): +# ret = [] +# for v in data: +# ret.append(_any(v)) +# return ret +# +# def _dict(data): +# ret = {} +# for k,v in data.items(): +# ret[k] = _any(v) +# return ret +# +# ret = _any(data) +# if(format == 'xml'): +# return pyxslt.serialize.toString(prettyPrintXml=False,data=ret,) +# else: +# return json.dumps(ret, cls=DateTimeAwareJSONEncoder) +# +# ''' +# DataDumper +# ''' + +@login_required +def get_vevent(request): + events = VEVENT.objects.extra(select={ + 'title' : "SUMMARY", + 'allDay': "false", +# 'start' : "UNIX_TIMESTAMP(DATE_SUB(DTSTART, INTERVAL 8 HOUR))", +# 'end' : "UNIX_TIMESTAMP(ADDTIME(DATE_SUB(DTSTART, INTERVAL 8 HOUR),DURATION))", + 'start' : "UNIX_TIMESTAMP(DTSTART)", + 'end' : "UNIX_TIMESTAMP(ADDTIME(DTSTART,DURATION))", +# 'end' : "UNIX_TIMESTAMP(ADDTIME(DTSTART,DURATION))", +# 'end' : "UNIX_TIMESTAMP(ADDTIME(DTSTART,MAX(DURATION,'00:30:00')))", + 'url' : "CONCAT('/event/update/',id,'/')", + }) + + start = request.GET.get('start', '') + end = request.GET.get('end' , '') + + if start: + # fr = datetime.datetime.fromtimestamp(float(start)) + # to = datetime.datetime.fromtimestamp(float(end)) + fr = start + to = end + events = events.filter(DTSTART__range=(fr, to)) + + # dumper = DataDumper() + # dumper.selectObjectFields('VEVENT', ['id', 'title', 'allDay', 'start', 'end', 'url']) + # dumper.dump(events,'json') + + # return HttpResponse(dumper.dump(events,'json')) + + return HttpResponse(django.core.serializers.serialize("json", events)) + +# return HttpResponse(django.core.serializers.serialize("json", events, ensure_ascii=False)) + +# entries = [] +# for event in events: +# starttime = mx.DateTime.DateTimeFrom(event.DTSTART.isoformat()) +# duration = mx.DateTime.DateTimeDeltaFrom(hours=event.DURATION.hour, minutes=event.DURATION.minute) +# endtime = starttime + duration +# entry = { +# 'id': event.id, +# 'starttime': starttime.strftime('%Y-%m-%dT%H:%M:%S'), +# 'endtime': starttime.strftime('%Y-%m-%dT%H:%M:%S'), +# 'allday': False, +# 'repeated': False, +# 'title': event.treatment.patient.name + event.get_mode_display(), +# 'url': "/treatment/detail/%i/" % event.treatment.id, +# 'body': event.SUMMARY, +# 'attributes': { +# 'Oncologist': event.treatment.oncologist.name, +# 'Surgeon': event.treatment.surgeon.name, +# }, +# 'type': [event.get_mode_display(), event.get_mode_display()] +# } +# entries.append(entry) +# return HttpResponse(django.core.serializers.serialize("xml", entries, ensure_ascii=False)) + +@login_required +def event_drop(request): + + id = request.GET.get('id' , '') + dayDelta = int(request.GET.get('dayDelta' , '')) + minuteDelta = int(request.GET.get('minuteDelta', '')) + + vevent = VEVENT.objects.get(id=id) + t = vevent.DTSTART + start = mx.DateTime.DateTime(t.year,t.month,t.day,t.hour,t.minute,t.second+1e-6*t.microsecond) + start = start + mx.DateTime.RelativeDateTime(days=dayDelta) + mx.DateTime.RelativeDateTime(minutes=minuteDelta) + vevent.DTSTART = datetime.datetime.fromtimestamp(start) + vevent.save() + + return HttpResponse(django.core.serializers.serialize("json", VEVENT.objects.filter(id=id), ensure_ascii=False)) + +@login_required +def event_resize(request): + + id = request.GET.get('id' , '') + dayDelta = int(request.GET.get('dayDelta' , '')) + minuteDelta = int(request.GET.get('minuteDelta', '')) + + vevent = VEVENT.objects.get(id=id) + t = vevent.DURATION + d = datetime.timedelta(days=dayDelta,minutes=minuteDelta) + dt = datetime.datetime.combine(datetime.date.today(), t) + d + vevent.DURATION = dt.time() + vevent.save() + + return HttpResponse(django.core.serializers.serialize("json", VEVENT.objects.filter(id=id), ensure_ascii=False)) + +@login_required +def update_vevent(request): + +# id = request.GET.get('id', '') +# starttime = request.GET.get('starttime', '') +# endtime = request.GET.get('endtime', '') + + id = request.POST.get('id', '') + starttime = mx.DateTime.DateTimeFrom(request.POST.get('starttime', '')[:-6]) + endtime = mx.DateTime.DateTimeFrom(request.POST.get('endtime', '')[:-6]) + duration = mx.DateTime.Age(endtime, starttime) + duration = str(duration.hours)+':'+str(duration.minutes) + + logging.info(id, starttime, endtime, duration) + + vevent = VEVENT.objects.get(id=id) + vevent.DTSTART = starttime +# vevent.DURATION = duration + vevent.save() + + return HttpResponse(django.core.serializers.serialize("json", VEVENT.objects.filter(id=id), ensure_ascii=False)) +# return HttpResponse("") + + +def listCalendarByRange(sd, ed, cnt): +# print ret +# $title = array('team meeting', 'remote meeting', 'project plan review', 'annual report', 'go to dinner'); +# $location = array('Lodan', 'Newswer', 'Belion', 'Moore', 'Bytelin'); + + + events = VEVENT.objects.extra(select={ + 'title' : "SUMMARY", + 'allDay': "false", +# 'start' : "UNIX_TIMESTAMP(DATE_SUB(DTSTART, INTERVAL 8 HOUR))", +# 'end' : "UNIX_TIMESTAMP(ADDTIME(DATE_SUB(DTSTART, INTERVAL 8 HOUR),DURATION))", + 'start' : "UNIX_TIMESTAMP(DTSTART)", + 'end' : "UNIX_TIMESTAMP(ADDTIME(DTSTART,DURATION))", +# 'end' : "UNIX_TIMESTAMP(ADDTIME(DTSTART,DURATION))", +# 'end' : "UNIX_TIMESTAMP(ADDTIME(DTSTART,MAX(DURATION,'00:30:00')))", + 'url' : "CONCAT('/event/update/',id,'/')", + }) + + events = events.filter(DTSTART__range=(sd, ed)) +# print events + + revents = [] + + for event in events: + d = event.DURATION + revent = (event.id, + event.title, + event.DTSTART.isoformat(), + (event.DTSTART+datetime.timedelta(minutes=d.minute, hours=d.hour)).isoformat(), + 0, #IsAllDayEvent + 0, #more than one day event + 0, #Recurring event + event.id % 14, #Color + 1, #editable + dict(event.MODE_CHOICES).get(event.mode,''), #Location + '', #attends + ) + logging.info(revent) + revents.append(revent) + + ret = {} + ret['events'] = revents + ret["issort"] = True + ret["start"] = sd.isoformat() + ret["end"] = ed.isoformat() + ret['error'] = None + + return ret + + +def listCalendar(day, type): + date = datetime.datetime.strptime(day, '%m/%d/%Y') + logging.info(date) + if type == 'month': + st = date - datetime.timedelta(31) + et = date + datetime.timedelta(31) + cnt = 50 + elif type == 'week': + st = date - datetime.timedelta(7) + et = date + datetime.timedelta(7) + cnt = 20 + elif type == 'day': + st = date - datetime.timedelta(1) + et = date + datetime.timedelta(1) + cnt = 5 + + return listCalendarByRange(st, et, cnt) + +#@login_required +def datafeed(request): + + try: + + # print request + method = request.GET['method'] + # print method + + if method == 'add': + pass + elif method == 'list': + ret = listCalendar(request.POST['showdate'], request.POST['viewtype']) + elif method == 'update': + pass + elif method == 'remove': + pass + elif method == 'adddetails': + pass + + except: + ret = listCalendar('8/3/2011', 'month') + + dumper = DataDumper() + return HttpResponse(dumper.dump(ret,'json')) + +# class VEVENT_ViewSet(viewsets.ModelViewSet): +class VEVENT_List(generics.ListAPIView): + + """ + API endpoint that allows groups to be viewed or edited. + """ + # queryset = VEVENT.objects.all() + serializer_class = VEVENT_Serializer + + def get_queryset(self): + """ + Optionally restricts the returned purchases to a given user, + by filtering against a `username` query parameter in the URL. + """ + queryset = VEVENT.objects.all() + queryset = VEVENT.objects.all() + start = self.request.query_params.get('start', None) + end = self.request.query_params.get('end', None) + if start is not None and end is not None: + queryset = queryset.filter(DTSTART__range=(start, end)).filter(mode__gt=100) + return queryset + + + + +class NHIOrderList(ListView): + model = NHIOrder + paginate_by = 25 + + # context_object_name = 'my_book_list' # your own name for the list as a template variable + # queryset = Book.objects.filter(title__icontains='war')[:5] # Get 5 books containing the title war + # template_name = 'books/my_arbitrary_template_name_list.html' # Specify your own template name/location + +# class MyDatatable(Datatable): +# model = NHIOrder +# class Meta: +# exclude = ['id', 'timestamp', 'updated'] + +# class NHIOrderDatatableView(DatatableView): +# model = NHIOrder + +# datatable_class = MyDatatable + +# Args: (,) +# Kwargs: {'default_value': '', 'rich_value': '', 'localize': False, 'datatable': , 'view': + +# Empty + + + +# @cache +def AllDoctors(NhiDeptName): + + # if NhiDeptName == '放射腫瘤科': + # dr, count = zip(*list(Treatment.objects.values_list("oncologist__name").annotate(Count("id")).order_by('-id__count'))) + # dr2 = Oncologist.objects.values_list('name', flat=True) + # else: + # dr, count = zip(*list(Treatment.objects.values_list("surgeon__name").annotate(Count("id")).order_by('-id__count'))) + # dr2 = Surgeon.objects.values_list('name', flat=True) + # return list(dr) + [d for d in list(dr2) if d not in dr] + + dr, count = zip(*list(Treatment.objects.values_list("oncologist__name").annotate(Count("id")).order_by('-id__count'))) + dr2 = Oncologist.objects.values_list('name', flat=True) + onco = list(dr) + [d for d in list(dr2) if d not in dr] + + dr, count = zip(*list(Treatment.objects.values_list("surgeon__name").annotate(Count("id")).order_by('-id__count'))) + dr2 = Surgeon.objects.values_list('name', flat=True) + surg = list(dr) + [d for d in list(dr2) if d not in dr] + + if NhiDeptName == '放射腫瘤科': + return [d for d in onco+surg if d is not None] + + return [d for d in surg+onco if d is not None] + + +@cache +def DoctorOptionByChartNo(ChartNo,NhiDeptName): + all = AllDoctors(NhiDeptName) + + # records = portal.PatientMedicalRecordListQuery(ChartNo) + # records = records['Emergency']+records['InPat']+records['OutPat'] + # # print(records) + + # doctors = set() + # for record in records: + # MainDrName = record['MainDrName'] + # if MainDrName is not None: + # MainDrName = MainDrName.replace('\ue09b', 'å³°') #'許峰銘' + # doctors.add(MainDrName) + + # # print(doctors) + + # # print(all) + # # print(doctors) + # intersect = [x for x in all if x in doctors] + + # if not intersect: + # intersect = all + + res = [] + + for d in all: + res.append({'value': d, 'text': d}) + + # res = [{'value': 1, 'text': "text1"}, {'value': 2, 'text': "text2"}] + + return JsonResponse(res, safe=False) + + +# [{value: 1, text: "text1"}, {value: 2, text: "text2"}, ...] +def DoctorOption(request): + + id = request.GET.get('id', '') + data = NHIOrder.objects.get(id=id) + return DoctorOptionByChartNo(data.ChartNo,data.NhiDeptName) + +def GetDoctorByCode(code): + # print(f'--{code}--') + dr = Surgeon.objects.filter(staff_code=code).first() + if dr: + return dr + dr = Oncologist.objects.filter(staff_code=code).first() + if dr: + return dr + return None + + +class NHIOrderDatatableView(XEditableDatatableView): + model = NHIOrder + + def filter_queryset(self, qs): + print(123) + + def get_queryset(self): + + order = None + + ChartNo = self.request.GET.get('ChartNo') + own = self.request.GET.get('own') + if (ChartNo is not None) and len(ChartNo) > 1: + if own is not None: + PackageTime = datetime.datetime.today().strftime('%Y-%m-%d') + id = ChartNo+'_'+PackageTime[:7] + order = NHIOrder.objects.filter(id=id).first() + + if order is None: + pat = portal.QueryModifyPatBase({'ChartNo': ChartNo}) + print(pat) + order = NHIOrder() + order.ChartNo = ChartNo + order.PackageTime = datetime.datetime.today().strftime('%Y-%m-%d') + order.id = order.ChartNo+'_'+order.PackageTime[:7] + order.PatientName = pat['ChtName'] + order.ApplyTypeDesc = '自費' + order.Priority = 1 + order.save() + + NHIOrder_id = self.request.GET.get('NHIOrder') + if NHIOrder_id is not None: + order = NHIOrder.objects.get(id=NHIOrder_id) + + if order is not None: + dr = GetDoctorByCode(self.request.user.username) + if dr is not None: + order.ApplyDoctor = dr.name + order.save() + + queryset = super().get_queryset() + + if self.request.user.is_staff: + # if self.request.GET.get('search[value]')=="None": + # return NHIOrder.objects.filter(ApplyDoctor__isnull=True) + return queryset + + # print(self.request.user) + # print(self.request.user.is_staff) + + dr = GetDoctorByCode(self.request.user.username) + # print(dr) + if dr: + return queryset.filter(ApplyDoctor=dr.name) + + + return queryset.none() + return queryset.filter(**self.request.GET.dict()) + + + def get_context_data(self, **kwargs): + # Call the base implementation first to get a context + context = super().get_context_data(**kwargs) + # Add in the publisher + # context['publisher'] = self.publisher + + qs = NHIOrder.objects.filter(Priority__gt=0) + context['total'] = qs.count() + # context['waiting_list'] = NHIOrder.objects.filter(Priority__gt=0).values('ApplyDoctor').annotate(count=Count('ApplyDoctor')).order_by('-count') + context['waiting_list'] = qs.values('ApplyDoctor').annotate(count=Count('*')).order_by('-count') + + + + if self.request.GET.get('refresh') is not None: + SortNHI(CheckTreated=False) + + + # context['ChartNo'] = self.request.GET.get('ChartNo') + NHIOrder_id = self.request.GET.get('NHIOrder') + if NHIOrder_id: + context['search'] = NHIOrder_id.split('_')[0] + + ChartNo = self.request.GET.get('ChartNo') + if ChartNo: + context['search'] = ChartNo + + return context + + class datatable_class(Datatable): + + # search for Empty ApplyDoctor + def search(self, queryset): + if 'None' in self.config['search']: + return queryset.filter(ApplyDoctor__isnull=True,Priority__gt=0) + return super().search(queryset) + + def ProcessQuantity(self, *args, **kwargs): + # print(f' Args: {args}' ) + # print(f' Kwargs: {kwargs}' ) + + data = args[0] + + default_value = kwargs['default_value'] + + title = '' + + if data.Reason: + title += data.Reason+' ' + + if data.ExamineReasonDesc: + title += data.ExamineReasonDesc + + if title: + return f'{default_value}' + + return f'{default_value}' + + + if ExamineReasonDesc is None: + # return f'{default_value}info' + return f'{default_value}' + + return f'{default_value}' + + def ProcessDiagnosis(self, *args, **kwargs): + data = args[0] + default_value = kwargs['default_value'] + title = '' + + # print(f'-{default_value}-') + + # if default_value: + + icd10 = ICD10CMfinal.objects.filter(ICD10CM=default_value).first() + if icd10 is not None: + title = icd10.ICD10CM_Chinese + + # return f'{default_value}' + return f'{default_value} {title}' + + + PriorityStyle = { + 1: 'background:red', + 2: 'background:yellow', + 3: 'background:green', + 4: 'background:white', + '': '', + } + + def ProcessPriority(self, *args, **kwargs): + data = args[0] + default_value = kwargs['default_value'] + + # if default_value== is None or : + # style = "" + # else: + style = PriorityStyle[default_value] + + # return ''' + # %s + # ''' % (data.id, default_value) + + # data-source="[{value: 1}, {value: 2}, {value: 3}, {value: 4}]" + + return ''' + %s + ''' % (data.id, default_value, style, default_value) + + + def ProcessChartNo(self, *args, **kwargs): + data = args[0] + default_value = kwargs['default_value'] + return f''' + {default_value} + ''' + + + def ProcessPatientName(self, *args, **kwargs): + data = args[0] + default_value = kwargs['default_value'] + return f''' + {default_value} + ''' + + def DoctorSelect(self, *args, **kwargs): + # print(f' Args: {args}' ) + # print(f' Kwargs: {kwargs}' ) + + data = args[0] + default_value = kwargs['default_value'] + + # if default_value=="": + # default_value = "zzz" + + # print('---',default_value,'---') + + # XEditableDatatableView will fix the css class and empty text later + + if kwargs['view'].request.user.is_staff: + return ''' + %s + ''' % (data.id, data.id, data.id, default_value, default_value) + else: + return default_value + + class Meta: + # exclude = ['id', 'timestamp', 'updated', '', ''] + + + columns = [ + 'ChartNo', + 'PatientName', + 'ApplyTypeDesc', + 'StatusDesc', + 'PackageTime', + 'OrderCode', + # 'OrderName', + # 'ResultDesc', + 'Quantity', + 'ExamineQuantity', + 'ExamineDate', + + 'Diagnosis', + 'other_diagnosis', + 'num_sessions', + + 'NhiDeptName', + 'MainDrName', + 'ApplyDoctor', + # 'ExamineReasonDesc', + + 'Priority', + 'Memo', + ] + + ordering = ['-Priority', 'PackageTime'] + + processors = { + # 'ChartNo': 'ProcessChartNo', + # 'PatientName': ProcessPatientName, + 'Quantity': 'ProcessQuantity', + 'Diagnosis': 'ProcessDiagnosis', + 'other_diagnosis': helpers.make_xeditable(), + 'num_sessions': helpers.make_xeditable(), + 'ApplyDoctor': 'DoctorSelect', + + # 'Priority': helpers.make_xeditable(type='select', + # source='[{value: 1, text: "1"}, {value: 2, text: "2"}, {value: 3, text: "3"}]' + # ), + + 'Priority': helpers.make_xeditable(), + 'Memo': helpers.make_xeditable(), + + + } + + structure_template = "datatableview/bootstrap_structure.html" + +def pre_add(request): + ChartNo = request.GET.get('ChartNo') + + ### A little bit too slow? + if False and (ChartNo is not None) and len(ChartNo) > 1: + for case in portal.QueryCaseByChartNo(ChartNo): + print(case) + UpdateNHICase(case) + + nhiorders = NHIOrder.objects.filter(ChartNo=ChartNo) + context = { + 'ChartNo': ChartNo, + 'nhiorders': nhiorders, + } + + if not nhiorders: + pat = portal.QueryModifyPatBase({'ChartNo': ChartNo,}) + + context['pat']=pat + + template = loader.get_template('ck/nhiorder_add.html') + return HttpResponse(template.render(context, request)) + +class LesionCreate(CreateView): + # model = Lesion + form_class = LesionForm + template_name = 'ck/lesion_form.html' + + # Need this to set treatment_id + def form_valid(self, form): + # lesion = form.save(commit=False) + # lesion.treatment_id = self.kwargs.get('treatment_id') + #article.save() # This is redundant, see comments. + form.instance.treatment_id = self.kwargs['treatment_id'] + return super().form_valid(form) + + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + context["treatment"] = get_object_or_404(Treatment, pk=self.kwargs.get('treatment_id')) + return context + + +class LesionUpdate(UpdateView): + model = Lesion + form_class = LesionForm + +class LesionDelete(DeleteView): + model = Lesion + + # success_url = reverse_lazy('treatment-detail') + def get_success_url(self): + # Assuming there is a ForeignKey from Comment to Post in your model + return reverse_lazy( 'treatment-detail', kwargs={'object_id': self.object.treatment_id}) + + +def CalendarIndex(request): + if request.GET.get('download') is not None: + QueryMS() + context={} + return render(request, 'calendar/index.html', context) + diff --git a/mysite/ck/vs.csv b/mysite/ck/vs.csv new file mode 100755 index 0000000..83d1565 --- /dev/null +++ b/mysite/ck/vs.csv @@ -0,0 +1,62 @@ +CS,å¾ç´¹å‹› +CS,æŽå…ƒéº’ +CS,æŽç« éŠ˜ +CS,陳晉興 +CS,黃培銘 +CVS,峿¯…暉 +CVS,周迺寬 +CVS,å¼µé‡ç¾© +CVS,王æ¤è³¢ +CVS,王水深 +CVS,紀乃新 +CVS,虞希禹 +CVS,許榮彬 +CVS,邱英世 +CVS,陳益祥 +CVS,é»ƒæ›¸å¥ +GS,何承懋 +GS,何明志 +GS,å³è€€éŠ˜ +GS,張金堅 +GS,æŽä¼¯çš‡ +GS,林明燦 +GS,æž—æœ¬ä» +GS,æ¢é‡‘銅 +GS,楊å¿å ¯ +GS,王明暘 +GS,ç”°éƒæ–‡ +GS,èƒ¡ç‘žæ† +GS,蔡孟昆 +GS,è¢ç‘žæ™ƒ +GS,賴逸儒 +GS,éƒ­æ–‡å® +GS,陳夿º +GS,陳炯年 +GS,é»ƒä¿Šå‡ +GS,黃凱文 +GS,黃約翰 +ICU,柯文哲 +NS,曾å‹å¼˜ +NS,曾漢民 +NS,æœæ°¸å…‰ +NS,楊士弘 +NS,çŽ‹åœ‹å· +NS,蔡瑞章 +NS,è•­è¼”ä» +NS,è³´é”æ˜Ž +NS,éƒ­å¤¢è² +NS,陳敞牧 +NS,黃å‹å … +PED,林文熙 +PED,蔡明憲 +PED,許文明 +PED,賴鴻緒 +PS,戴浩志 +PS,æ¥Šæ°¸å¥ +PS,洪學義 +PS,湯月碧 +PS,簡雄飛 +PS,è¬å­Ÿç¥¥ +PS,è¬æ¦®è³¢ +PS,éƒ­æºæ¾ +PS,鄭乃禎 diff --git a/mysite/ck/vs0.csv b/mysite/ck/vs0.csv new file mode 100755 index 0000000..6bb2caa --- /dev/null +++ b/mysite/ck/vs0.csv @@ -0,0 +1,62 @@ +GS,§õ§B¬Ó +PED,¿àÂEºü +GS,°K·ç®Ì +GS,¶À«T¤É +GS,ªL©úÀé +PS,´ö¤ëºÑ +ICU,¬_¤å­õ +CS,§õ¤¸ÄQ +GS,­J·ç«í +NS,§ù¥Ã¥ú +PED,ªL¤åº³ +CS,®}²Ð³Ô +NS,³¯´¯ªª +PS,³¢·½ªQ +GS,³¯©[·½ +GS,¦ó©ú§Ó +CVS,©P°i¼e +PS,²¶¯­¸ +GS,¥Ð­§¤å +NS,¿à¹F©ú +CVS,ªô­^¥@ +GS,±çª÷»É +CVS,³¯¯q²» +PS,¬x¾Ç¸q +GS,³¯¬³¦~ +PS,À¹¯E§Ó +GS,³¢¤å§» +CVS,³\ºa±l +CS,§õ³¹»Ê +PED,½²©ú¾Ë +NS,¤ý°ê¤t +PS,¾G¤DºÕ +NS,¶À³Ó°í +CS,³¯®Ê¿³ +GS,§dÄ£»Ê +PS,·¨¥Ã°· +NS,´¿º~¥Á +NS,´¿³Ó¥° +CVS,¤ý¤ô²` +CVS,±i­«¸q +PS,Á©s²» +GS,¿à¶h¾§ +GS,½²©s©ø +CVS,¸·§Æ¬ê +PED,³\¤å©ú +CS,¶À°ö»Ê +CVS,¶À®Ñ°· +GS,·¨­ë³ó +NS,½²·ç³¹ +NS,³¢¹Úµá +GS,ªL¥»¤¯ +NS,·¨¤h¥° +PS,Áºa½å +NS,¿½»²¤¯ +GS,¦ó©ÓÀ· +CVS,¤ý´Ó½å +CVS,§d¼Ý·u +GS,±iª÷°í +GS,¶À¬ù¿« +GS,¶À³Í¤å +GS,¤ý©ú·z +CVS,¬ö¤D·s diff --git a/mysite/ck_cron.py b/mysite/ck_cron.py new file mode 100755 index 0000000..baa5746 --- /dev/null +++ b/mysite/ck_cron.py @@ -0,0 +1,380 @@ +#!/usr/bin/python +# coding=utf-8 + +from __future__ import unicode_literals + +import datetime +import os +import re +import subprocess +import time + + +import django + +os.environ['DJANGO_SETTINGS_MODULE'] = 'mysite.settings' +# os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings") +django.setup() + + +from django.db.models import Count + + +from import_export import resources +from import_export.fields import Field +# import rotate_backups + +# from mechanize import Browser +# br = Browser() +# br.set_handle_robots(False) + +from ck.models import * + +from ck.common import SortNHI, UpdateNHICase, UpdateNHICase2, AddPatient, QueryMS, GetCaseForCyberKnifeList + +# from ntuhgov import intra +import ntuhgov.portal_selenium as portal + +from ntuhgov.portal_selenium import QueryCase, QueryCaseByPass + + +QUEUE_DIR='/tmp/queue' +QUEUE_DIR='/mnt/pve/Public/queue' + +# MAX_PAT = 200 + +def PortalRefresh(): + + patients = Patient.objects.filter(dead__isnull=True).order_by('timestamp') + MAX_PAT = int(patients.count() / 30) + # patients = Patient.objects.all() +# patients = patients.filter(medical_records='5619422') + SESSION = portal.Login() + n_pat = 0 + for patient in patients: + if n_pat>MAX_PAT: + break + + if patient.dead: + continue + + print(n_pat,'/',MAX_PAT) + + n_pat += 1 + + # Update ElectronicMedicalReport + + patient.save() # update timestamp + + print(patient.id, patient.medical_records, patient) + excluded = patient.electronicmedicalreport_set.all().values_list('report_key', flat=True) + # print(excluded) + + # reports = portal.ElectronicMedicalReportViewer(patient.medical_records, startswith='T0', excluded=excluded) + reports = portal.ElectronicMedicalReportViewer(patient.medical_records, excluded=excluded) + # print(len(reports)) + for report in reports: + + # 沒報告? + if report['檢查日期'] == '*' or report['報告日期'] == '*': + continue + + r = ElectronicMedicalReport(patient=patient) + r.report_key = report['ReportKey'] + r.report_class = report['報告類別'] + r.check_date = datetime.datetime.strptime(report['檢查日期'], "%Y/%m/%d") + r.report_date = datetime.datetime.strptime(report['報告日期'], "%Y/%m/%d") + r.report_code = report['ReportCode'] + r.report = report['html'] + + r.save() + + if patient.id_cards.find(u' ') != -1: + # print '"%s"' % patient.id_cards + patient.id_cards = patient.id_cards.replace(u' ','') + # print '"%s"' % patient.id_cards + patient.save() + + q = PACSImage.objects.filter(patient=patient) + + #Update PACSImageShowList + # print(patient.id_cards) + PACSList = portal.PACSImageShowList(patient.id_cards, SESSION) + for pacs in PACSList: + # print(pacs) + qq = q.filter(RequestSheetNo=pacs['RequestSheetNo']) + if len(qq) == 0: + # print pacs + p = PACSImage(patient=patient) + p.PatChartNo = pacs['PatChartNo'] + p.RequestSheetNo = pacs['RequestSheetNo'] + try: + p.ExamDate = datetime.datetime.strptime(pacs['ExamDate'],'%Y%m%d') + except: + continue + p.LinkOrderName = pacs['LinkOrderName'] + p.Modality = pacs['Modality'] + p.VerifiedStateString = pacs['VerifiedStateString'] + p.Saved = 0 #Not saved + p.save() + +# continue #for debug + + #Read from old intra system, Dysfunction +# Xray = XrayExam(patient.medical_records) +# for x in Xray: +# qq = q.filter(RequestSheetNo=x['ReferNo']) +# if len(qq) == 0: +# print x +# p = PACSImage(patient=patient) +# p.PatChartNo = x['ChartNo'] +# p.RequestSheetNo = x['ReferNo'] +# p.ExamDate = datetime.datetime.strptime(x['ExamDate'],'%Y-%m-%d') +# p.LinkOrderName = x['LinkOrderName'] +# p.Modality = x['Modality'] +# p.VerifiedStateString = x['status'] +# p.Saved = 0 #Not saved +# p.save() + + #Update MedicalRecord + print(patient.medical_records) + MR = portal.PatientMedicalRecordListQuery(patient.medical_records, SESSION=SESSION) + try: + print(MR['Description']) + print('%d %s %s %s'% (patient.id, patient.medical_records, MR['extra'], MR['dead'])) + except: + print('************************************************************') + # exit() + q = MedicalRecord.objects.filter(patient=patient) + + for mr in MR['InPat']: + qq = q.filter(InDate=mr['InDate']) + if len(qq)==0 or qq[0].OutDate==None: + # print mr + if len(qq)==0: + m = MedicalRecord(patient=patient) + else: + m = qq[0] + m.Record = 'ä½' # 使€¥é–€ + m.HospName = mr['HospName'] + m.DeptName = mr['DeptName'] + m.InDate = mr['InDate'] + m.OutDate = mr['OutDate'] + m.WardName = mr['WardName'] + m.RoomName = mr['RoomName'] + m.BedName = mr['BedName'] + m.MainDrName = mr['MainDrName'] + m.MainDiagnosisName = mr['MainDiagnosisName'] + m.StatusName = mr['StatusName'] + m.save() + + for mr in MR['Emergency']: + qq = q.filter(InDate=mr['ComeClinicDate']) + if len(qq)==0 or qq[0].OutDate==None: + if len(qq)==0: + m = MedicalRecord(patient=patient) + else: + if mr['DischargeDate'] == None: + continue + m = qq[0] + # print mr + m.Record = '急' # 使€¥é–€ + m.HospName = mr['HospName'] + m.DeptName = mr['DeptName'] + m.InDate = mr['ComeClinicDate'] + m.OutDate = mr['DischargeDate'] + m.MainDrName = mr['MainDrName'] + m.MainDiagnosisName = mr['MainDiagnosisName'] + m.StatusName = mr['StatusName'] + m.BedName = mr['TempBedID'] + m.save() + + for mr in MR['OutPat']: + qq = q.filter(InDate=mr['ComeClinicDate']) + if len(qq) == 0: + # print mr + m = MedicalRecord(patient=patient) + m.Record = 'é–€' # 使€¥é–€ + m.HospName = mr['HospName'] + m.DeptName = mr['DeptName'] + m.InDate = mr['ComeClinicDate'] + m.SpecialCureName = mr['SpecialCureName'] + m.MainDrName = mr['MainDrName'] + m.MainDiagnosisName = mr['MainDiagnosisName'] + m.StatusName = mr['AccountStatusName'] + m.save() + + if MR['dead']: + patient.dead = MR['dead'] + patient.save() + + +def PatientsRefresh(): + url = "https://content.wuala.com/contents/xiao/Shared/patients.txt?key=IKlcEMNcgZZg" + response = br.open(url) + body = response.read() +# print body +# print dir(PACSImageShowList) + images = PACSImage.objects.all() + for image in images: + pattern = ".*%s/.*%s" % (image.PatChartNo, image.ExamDate.strftime('%Y%m%d')) +# print pattern + matches = re.findall(pattern, body) + if len(matches): +# print matches + image.Saved = 10 #Saved + image.save() + +# ImageDir = '%s/%s' % (image.PatChartNo, image.ExamDate.strftime('%Y%m%d')) +## print ImageDir +# if body.find(ImageDir) != -1: +## print ImageDir +# image.Saved = 10 #Saved +# image.save() + +o = Oncologist.objects.values_list('name', flat=True) +s = Surgeon.objects.values_list('name', flat=True) +AllDr = set(o)|set(s) + +def GetMainDrName(ChartNo): + records = portal.PatientMedicalRecordListQuery(ChartNo) + records = records['Emergency']+records['InPat']+records['OutPat'] + + doctors = set() + for record in records: + MainDrName = record['MainDrName'] + if MainDrName is not None: + MainDrName = MainDrName.replace('\ue09b', '峯') #'許峯銘' + doctors.add(MainDrName) + + return ' '.join(list(doctors&AllDr)) + +def UpdateNHI(): + + for case in GetCaseForCyberKnifeList(): + print(case) + UpdateNHICase2(case) + + # for case in QueryCase(ApplySDate='2020/02/07'): + for case in QueryCase(): + print(case) + UpdateNHICase(case) + + # for case in QueryCaseByPass('018522','ah651223'): + # print(case) + # UpdateNHICase(case) + + for order in NHIOrder.objects.filter(ApplyDoctor__isnull=True, MainDrName__isnull=True): + # for order in NHIOrder.objects.filter(MainDrName__isnull=True): + order.MainDrName = GetMainDrName(order.ChartNo) + print(order.ChartNo, order.MainDrName ) + order.save() + + +class NHIOrderResource(resources.ModelResource): + + # order = Field(column_name='é †åº') + + + # def dehydrate_order(self, nhi_order): + # return '%s by %s' % (book.name, book.author.name) + + + def get_export_headers(self): + headers = [] + for field in self.get_export_fields(): + headers.append(self.Meta.model._meta.get_field(field.column_name).verbose_name) + return headers + + class Meta: + model = NHIOrder + fields = ('Priority', 'ChartNo', 'PatientName', 'ExamineDate', 'Quantity', 'ApplyDoctor', 'other_diagnosis', 'num_sessions', 'Memo',) + export_order = fields + +def ExportExcel(): + queryset = NHIOrder.objects.filter().order_by('-Priority', 'PackageTime') + dataset = NHIOrderResource().export(queryset) + + # TODAY_DIR = os.path.join(QUEUE_DIR, datetime.datetime.today().strftime('%Y-%m-%d')) + # print(time.strftime('%Y-%m-%d %H:%M:%S')) + TODAY_DIR = os.path.join(QUEUE_DIR, time.strftime('%Y-%m-%d')) + print(TODAY_DIR) + + os.makedirs(TODAY_DIR, exist_ok=True) + + with open(os.path.join(TODAY_DIR, 'All.xls'), 'wb') as f: + f.write(dataset.export('xls')) + + for v in NHIOrder.objects.values('ApplyDoctor').distinct(): + + queryset = NHIOrder.objects.filter(ApplyDoctor=v['ApplyDoctor'],Priority__gt=0).order_by('-Priority', 'PackageTime') + dataset = NHIOrderResource().export(queryset) + + if v['ApplyDoctor'] is None: + output = os.path.join(TODAY_DIR, 'None.xls') + else: + output = os.path.join(TODAY_DIR, v['ApplyDoctor']+'.xls') + + + with open(output, 'wb') as f: + f.write(dataset.export('xls')) + + # print(type(dataset)) + # print(dataset.csv) + # exit() + +def CountICD10(): + # qs = Treatment.objects.all().values('icd10cm').annotate(count=Count('icd10cm')).order_by('-count') + # for i in qs: + # print(i) + # if i['icd10cm']: + # # c = ICD10Count(icd10cm=ICD10CMfinal.objects.get(pk=i['icd10cm'])) + # c, created = ICD10Count.objects.get_or_create(icd10cm_id=i['icd10cm']) + # c.count=i['count'] + # c.save() + + # count icd9 and return icd10 + # qs = Treatment.objects.all().values('icd9').annotate(count=Count('icd9')).order_by('-count') + qs = Treatment.objects.all().values('icd9').annotate(count=Count('icd9')).order_by('count') + for i in qs: + # print(i) + if i['icd9']: + ICD9CM_code = i['icd9'][:3]+'.'+i['icd9'][3:] + # icd10 = ICD10CMfinal.objects.filter(ICD9CM_code=ICD9CM_code).first() + qs10 = Treatment.objects.filter(icd9=i['icd9'],icd10cm__isnull=False).values('icd10cm').annotate(count=Count('icd10cm')).order_by('-count') + # print(ICD9CM_code, qs10) + icd10 = qs10.first() + print(ICD9CM_code, i['count'], icd10) + if icd10 is not None: + # c = ICD10Count(icd10cm=ICD10CMfinal.objects.get(pk=i['icd10cm'])) + c, created = ICD10Count.objects.get_or_create(icd10cm_id=icd10['icd10cm']) + c.count=i['count'] + c.save() + + +def BackupMSSQL(): + TODAY_FILENAME = f'mssql-ntuh-{time.strftime("%Y-%m-%d")}.bak' + + subprocess.run(["/opt/mssql-tools/bin/sqlcmd", "-S", "172.16.40.43", "-U", "SA", "-P", "!QAZ2wsx", "-Q", + f"BACKUP DATABASE [ntuh] TO DISK = N'P:\dump\{TODAY_FILENAME}' WITH NOFORMAT, NOINIT, NAME = 'demodb-full', SKIP, NOREWIND, NOUNLOAD, STATS = 10"]) + +if __name__ == "__main__": + + + # UpdateNHI() + # exit() + + CountICD10() + + UpdateNHI() + SortNHI() + ExportExcel() + + # this has been firewalled sometimes + BackupMSSQL() + # QueryMS() + + PortalRefresh() +# PatientsRefresh() + + diff --git a/mysite/ck_emr.py b/mysite/ck_emr.py new file mode 100755 index 0000000..969daec --- /dev/null +++ b/mysite/ck_emr.py @@ -0,0 +1,49 @@ +#!/usr/bin/python +# coding=utf-8 + +from __future__ import unicode_literals + +import datetime +import os +import re + +import django + +os.environ['DJANGO_SETTINGS_MODULE'] = 'mysite.settings' +# os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings") +django.setup() + +# from mechanize import Browser +# br = Browser() +# br.set_handle_robots(False) + +from ck.models import * +# from ntuhgov import intra +import ntuhgov.portal_selenium as portal + + +REGISTER_PATH = '/media/cifs/ST14/shares/Public/register3_result/' + +def GetReg(): + for pat in os.listdir(REGISTER_PATH): + for img in os.listdir(os.path.join(REGISTER_PATH, pat)): + print (pat, img) + exit() + +def ExportEMR(): + + patients = Patient.objects.all() + for patient in patients: + + for e in patient.electronicmedicalreport_set.filter(report_code='XrayTextReport'): + + print(e) + + exit() + + + + +if __name__ == "__main__": + GetReg() + ExportEMR() diff --git a/mysite/ck_select.py b/mysite/ck_select.py new file mode 100644 index 0000000..a44e9e4 --- /dev/null +++ b/mysite/ck_select.py @@ -0,0 +1,53 @@ +import os + +from django.db.models import Q +from django.forms.models import model_to_dict + +import django +import pandas as pd + +os.environ['DJANGO_SETTINGS_MODULE'] = 'mysite.settings' +# os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings") +django.setup() + +from ck.models import * + +# patients = Patient.objects.filter(dead__isnull=True).order_by('timestamp') + +L = [] + +for p in Patient.objects.order_by('id')[:10000]: + print(p.id) + + t = p.treatment_set.order_by('date_started').first() + if t is None: + continue + + # report = p.electronicmedicalreport_set.filter(report_code='XrayTextReport').order_by('-check_date').first() + r = p.electronicmedicalreport_set.filter( + Q(report_class__icontains='MRI') | + Q(report_class__icontains='M.R.I') + ).order_by('-check_date').first() + if r is None: + continue + + tdate = t.date_started + if tdate is None: + tdate = t.date_completed + if tdate is None: + continue + + f = r.check_date-tdate + print(f, p, t.date_started, r.check_date, r.report_class) + + d = {'followup': f} + d.update(model_to_dict(p)) + d.update(model_to_dict(t)) + d.update(model_to_dict(r)) + + L.append(d) + +df=pd.DataFrame(L) + +df.to_excel('ck_select.xlsx') + diff --git a/mysite/manage.py b/mysite/manage.py new file mode 100755 index 0000000..8a50ec0 --- /dev/null +++ b/mysite/manage.py @@ -0,0 +1,10 @@ +#!/usr/bin/env python +import os +import sys + +if __name__ == "__main__": + os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings") + + from django.core.management import execute_from_command_line + + execute_from_command_line(sys.argv) diff --git a/mysite/mrn2hash.py b/mysite/mrn2hash.py new file mode 100644 index 0000000..0a967d4 --- /dev/null +++ b/mysite/mrn2hash.py @@ -0,0 +1,46 @@ +import base64 +import hashlib +import os + +import pandas as pd + +import django + +os.environ['DJANGO_SETTINGS_MODULE'] = 'mysite.settings' +# os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings") +django.setup() + +from django.db.models import Count + +from ck.models import * + + +def hashptid(mrn, hosp='NTUH'): + + ptsalt = (mrn+hosp).upper().encode() + hash_in_bytes = hashlib.md5(ptsalt) + + md5 = hash_in_bytes.hexdigest() + hash = base64.b32encode(hash_in_bytes.digest())[:8].decode() + + + # hash32 = base64.b32encode(hash_in_bytes)[:8].decode() + # hash10 = str(int(hashlib.md5(ptsalt).hexdigest(), 16))[-8:] + + return md5, hash + +PATIENTS = [] + + +for p in Patient.objects.all(): + md5, hash = hashptid(p.medical_records) + print (p.medical_records, hash) + PATIENTS.append({ + 'ChartNo': p.medical_records, + 'hash': hash, + }) + + +df = pd.DataFrame(PATIENTS) + +df.to_excel('hash.xlsx') diff --git a/mysite/mssql_ntuh/__init__.py b/mysite/mssql_ntuh/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/mysite/mssql_ntuh/admin.py b/mysite/mssql_ntuh/admin.py new file mode 100644 index 0000000..8c38f3f --- /dev/null +++ b/mysite/mssql_ntuh/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/mysite/mssql_ntuh/apps.py b/mysite/mssql_ntuh/apps.py new file mode 100644 index 0000000..e433321 --- /dev/null +++ b/mysite/mssql_ntuh/apps.py @@ -0,0 +1,5 @@ +from django.apps import AppConfig + + +class MssqlNtuhConfig(AppConfig): + name = 'mssql_ntuh' diff --git a/mysite/mssql_ntuh/migrations/__init__.py b/mysite/mssql_ntuh/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/mysite/mssql_ntuh/models.py b/mysite/mssql_ntuh/models.py new file mode 100644 index 0000000..fb9731c --- /dev/null +++ b/mysite/mssql_ntuh/models.py @@ -0,0 +1,348 @@ +# This is an auto-generated Django model module. +# You'll have to do the following manually to clean this up: +# * Rearrange models' order +# * Make sure each model has one field with primary_key=True +# * Make sure each ForeignKey and OneToOneField has `on_delete` set to the desired behavior +# * Remove `managed = False` lines if you wish to allow Django to create, modify, and delete the table +# Feel free to rename the models, but don't rename db_table values or field names. +from django.db import models + + +class Dataname(models.Model): + iid = models.AutoField(primary_key=True) + main_iid = models.IntegerField(blank=True, null=True) + title_theme = models.CharField(max_length=100, blank=True, null=True) + upfile_path = models.CharField(max_length=10, blank=True, null=True) + admin = models.CharField(max_length=255, blank=True, null=True) + link_type = models.IntegerField(blank=True, null=True) + out_html = models.CharField(max_length=255, blank=True, null=True) + contents = models.TextField(blank=True, null=True) + out_link = models.CharField(max_length=255, blank=True, null=True) + modekind = models.IntegerField(blank=True, null=True) + update_date = models.DateTimeField(blank=True, null=True) + c_title = models.TextField(blank=True, null=True) + ltitle = models.CharField(max_length=50, blank=True, null=True) + rtitle = models.CharField(max_length=50, blank=True, null=True) + orders = models.IntegerField(blank=True, null=True) + newfun_id = models.IntegerField(blank=True, null=True) + showyn = models.CharField(max_length=1, blank=True, null=True) + idpath = models.CharField(max_length=200, blank=True, null=True) + userid = models.CharField(max_length=20, blank=True, null=True) + publicid = models.IntegerField(blank=True, null=True) + titlepic = models.CharField(max_length=30, blank=True, null=True) + webkind = models.CharField(max_length=4, blank=True, null=True) + mobilemenu = models.IntegerField(blank=True, null=True) + topmenu = models.TextField(blank=True, null=True) + btitle = models.CharField(max_length=50, blank=True, null=True) + onsub = models.IntegerField(blank=True, null=True) + mag = models.IntegerField(blank=True, null=True) + + class Meta: + managed = False + db_table = 'dataname' + + +class Doctor(models.Model): + cname = models.CharField(max_length=50, blank=True, null=True) + mobile = models.CharField(max_length=50, blank=True, null=True) + job = models.CharField(max_length=50, blank=True, null=True) + sid = models.IntegerField(blank=True, null=True) + adduser = models.CharField(max_length=50, blank=True, null=True) + adddate = models.DateTimeField(blank=True, null=True) + editdate = models.DateTimeField(blank=True, null=True) + edituser = models.CharField(max_length=50, blank=True, null=True) + typs = models.IntegerField(blank=True, null=True) + + class Meta: + managed = False + db_table = 'doctor' + + +class Editrec(models.Model): + iid = models.AutoField(primary_key=True) + editrec = models.CharField(max_length=10, blank=True, null=True) + edituser = models.CharField(max_length=10, blank=True, null=True) + editusernm = models.CharField(max_length=50, blank=True, null=True) + editdate = models.DateTimeField(blank=True, null=True) + action = models.CharField(max_length=50, blank=True, null=True) + edititem = models.CharField(max_length=50, blank=True, null=True) + aid = models.IntegerField(blank=True, null=True) + + class Meta: + managed = False + db_table = 'editrec' + + +class F00(models.Model): + user_id = models.CharField(max_length=20) + user_name = models.CharField(max_length=30, blank=True, null=True) + passwd = models.CharField(max_length=50, blank=True, null=True) + levels = models.IntegerField(blank=True, null=True) + password = models.CharField(max_length=25, blank=True, null=True) + email = models.CharField(max_length=100, blank=True, null=True) + position2 = models.IntegerField(blank=True, null=True) + editdate = models.DateTimeField(blank=True, null=True) + edituser = models.CharField(max_length=20, blank=True, null=True) + mobilephone = models.CharField(max_length=50, blank=True, null=True) + usertimes = models.IntegerField(blank=True, null=True) + stopuse = models.CharField(max_length=1, blank=True, null=True) + checkdate = models.DateTimeField(blank=True, null=True) + leavedate = models.DateTimeField(blank=True, null=True) + allowiid = models.TextField(blank=True, null=True) + adduser = models.CharField(max_length=50, blank=True, null=True) + adddate = models.DateTimeField(blank=True, null=True) + + class Meta: + managed = False + db_table = 'f00' + + +class Marquee(models.Model): + roomid = models.CharField(max_length=10, blank=True, null=True) + marqueetext = models.TextField(blank=True, null=True) + edituser = models.CharField(max_length=50, blank=True, null=True) + editdate = models.DateTimeField(blank=True, null=True) + + class Meta: + managed = False + db_table = 'marquee' + + +class Meeting(models.Model): + iid = models.AutoField(primary_key=True) + week = models.CharField(max_length=50, blank=True, null=True) + title = models.CharField(max_length=200, blank=True, null=True) + people = models.TextField(blank=True, null=True) + sdate = models.DateTimeField(blank=True, null=True) + stime = models.CharField(max_length=100, blank=True, null=True) + edate = models.DateTimeField(blank=True, null=True) + memo = models.TextField(blank=True, null=True) + filenamea = models.CharField(max_length=200, blank=True, null=True) + place = models.CharField(max_length=255, blank=True, null=True) + sid = models.CharField(max_length=255, blank=True, null=True) + build_date = models.DateTimeField(blank=True, null=True) + stime1 = models.CharField(max_length=50, blank=True, null=True) + stime2 = models.CharField(max_length=50, blank=True, null=True) + + class Meta: + managed = False + db_table = 'meeting' + + +class Mem(models.Model): + iid = models.AutoField(primary_key=True) + sid = models.IntegerField(blank=True, null=True) + mno = models.CharField(max_length=10, blank=True, null=True) + eid = models.CharField(max_length=10, blank=True, null=True) + cnm = models.CharField(max_length=50, blank=True, null=True) + enm = models.CharField(max_length=50, blank=True, null=True) + birthday = models.DateTimeField(blank=True, null=True) + sex = models.CharField(max_length=1, blank=True, null=True) + addr1 = models.CharField(max_length=255, blank=True, null=True) + ondate = models.DateTimeField(blank=True, null=True) + inter = models.IntegerField(blank=True, null=True) + out_date = models.TextField(blank=True, null=True) + mobile = models.CharField(max_length=50, blank=True, null=True) + phone = models.CharField(max_length=50, blank=True, null=True) + update_date = models.DateTimeField(blank=True, null=True) + update_userid = models.CharField(max_length=50, blank=True, null=True) + remarks = models.TextField(blank=True, null=True) + maindiagnose = models.CharField(db_column='mainDiagnose', max_length=50, blank=True, null=True) # Field name made lowercase. + maindoctor = models.CharField(db_column='mainDoctor', max_length=10, blank=True, null=True) # Field name made lowercase. + treatmentroom = models.CharField(db_column='treatmentRoom', max_length=20, blank=True, null=True) # Field name made lowercase. + hospitalizedstatus = models.IntegerField(db_column='hospitalizedStatus', blank=True, null=True) # Field name made lowercase. + shift = models.CharField(db_column='Shift', max_length=1, blank=True, null=True) # Field name made lowercase. + undone = models.CharField(max_length=1, blank=True, null=True) + detailmaindigonse = models.TextField(db_column='detailMainDigonse', blank=True, null=True) # Field name made lowercase. + treatmentcount = models.IntegerField(db_column='TreatmentCount', blank=True, null=True) # Field name made lowercase. + fallrisktime = models.DateTimeField(db_column='fallRiskTime', blank=True, null=True) # Field name made lowercase. + fallrisk = models.IntegerField(db_column='fallRisk', blank=True, null=True) # Field name made lowercase. + makewill = models.IntegerField(db_column='makeWill', blank=True, null=True) # Field name made lowercase. + willtime = models.DateTimeField(db_column='willTime', blank=True, null=True) # Field name made lowercase. + + class Meta: + managed = False + db_table = 'mem' + + +class Patient(models.Model): + record_no = models.CharField(max_length=100, blank=True, null=True) + name = models.CharField(max_length=50, blank=True, null=True) + enname = models.CharField(max_length=255, blank=True, null=True) + roc_id = models.CharField(max_length=10, blank=True, null=True) + sex = models.CharField(max_length=2, blank=True, null=True) + birthday = models.CharField(max_length=10, blank=True, null=True) + family_name = models.CharField(max_length=10, blank=True, null=True) + home_phone_number = models.CharField(max_length=50, blank=True, null=True) + mobile_phone = models.CharField(max_length=50, blank=True, null=True) + contact_home_number = models.CharField(max_length=50, blank=True, null=True) + contact_phone_number = models.CharField(max_length=100, blank=True, null=True) + edituser = models.CharField(max_length=50, blank=True, null=True) + editdate = models.DateTimeField(blank=True, null=True) + + class Meta: + managed = False + db_table = 'patient' + + +class PatientAppointment(models.Model): + appointment_date = models.DateTimeField(blank=True, null=True) + appointment_hour = models.CharField(max_length=2, blank=True, null=True) + appointment_minutes = models.CharField(max_length=2, blank=True, null=True) + create_datetime = models.DateTimeField(blank=True, null=True) + endstatus = models.CharField(db_column='endStatus', max_length=10, blank=True, null=True) # Field name made lowercase. + finished_times = models.IntegerField(blank=True, null=True) + main_diagnose = models.TextField(blank=True, null=True) + main_doctor = models.CharField(max_length=50, blank=True, null=True) + rt_doctor = models.CharField(db_column='RT_doctor', max_length=50, blank=True, null=True) # Field name made lowercase. + mobile_phone_number = models.CharField(max_length=10, blank=True, null=True) + record_no = models.CharField(max_length=100, blank=True, null=True) + shift = models.CharField(max_length=1, blank=True, null=True) + tip_note = models.TextField(blank=True, null=True) + treatment_room = models.CharField(max_length=50, blank=True, null=True) + treatment_times = models.IntegerField(blank=True, null=True) + dropsize = models.CharField(db_column='dropSize', max_length=2, blank=True, null=True) # Field name made lowercase. + fallrisk = models.CharField(db_column='fallRisk', max_length=1, blank=True, null=True) # Field name made lowercase. + fallrisktime = models.DateTimeField(db_column='fallRiskTime', blank=True, null=True) # Field name made lowercase. + makewill = models.CharField(db_column='makeWill', max_length=1, blank=True, null=True) # Field name made lowercase. + willtime = models.DateTimeField(db_column='willTime', blank=True, null=True) # Field name made lowercase. + editdate = models.DateTimeField(blank=True, null=True) + edituser = models.CharField(max_length=10, blank=True, null=True) + comments = models.TextField(blank=True, null=True) + note = models.TextField(blank=True, null=True) + endallschudle = models.CharField(db_column='endAllSchudle', max_length=50, blank=True, null=True) # Field name made lowercase. + cre = models.CharField(max_length=50, blank=True, null=True) + locationappointment = models.TextField(db_column='locationAppointment', blank=True, null=True) # Field name made lowercase. + hospitalized_status = models.CharField(max_length=50, blank=True, null=True) + mrid = models.IntegerField(blank=True, null=True) + planstatus = models.IntegerField(db_column='Planstatus', blank=True, null=True) # Field name made lowercase. + plandate = models.DateTimeField(db_column='Plandate', blank=True, null=True) # Field name made lowercase. + onlineok = models.IntegerField(db_column='ONLINEOK', blank=True, null=True) # Field name made lowercase. + ide = models.CharField(db_column='IDE', max_length=50, blank=True, null=True) # Field name made lowercase. + goals = models.CharField(max_length=50, blank=True, null=True) + + class Meta: + managed = False + db_table = 'patient_appointment' + + +class PatientAppointmentSchedule(models.Model): + appointment_date = models.DateTimeField(blank=True, null=True) + appointment_hour = models.CharField(max_length=2, blank=True, null=True) + appointment_minutes = models.CharField(max_length=2, blank=True, null=True) + calling = models.CharField(max_length=1, blank=True, null=True) + calling_right = models.CharField(max_length=1, blank=True, null=True) + checkin_datetime = models.DateTimeField(blank=True, null=True) + checkin_late = models.BooleanField(blank=True, null=True) + checkin_status = models.CharField(max_length=5, blank=True, null=True) + comments = models.CharField(max_length=500, blank=True, null=True) + complex_segments = models.CharField(max_length=2, blank=True, null=True) + hospitalized_status = models.CharField(max_length=100, blank=True, null=True) + mapping_appointment = models.IntegerField(blank=True, null=True) + mapping_patient = models.IntegerField(blank=True, null=True) + queue_datetime = models.DateTimeField(blank=True, null=True) + queue_status = models.CharField(max_length=5, blank=True, null=True) + record_no = models.CharField(max_length=100, blank=True, null=True) + room_calling = models.CharField(max_length=1, blank=True, null=True) + schedule_status = models.CharField(max_length=1, blank=True, null=True) + second_time = models.CharField(max_length=1, blank=True, null=True) + shift = models.CharField(max_length=1, blank=True, null=True) + simple_segments = models.CharField(max_length=2, blank=True, null=True) + treatment_complete_datetime = models.DateTimeField(blank=True, null=True) + treatment_count = models.IntegerField(blank=True, null=True) + treatment_room = models.CharField(max_length=50, blank=True, null=True) + treatment_start_datetime = models.DateTimeField(blank=True, null=True) + treatment_status = models.CharField(max_length=10, blank=True, null=True) + finish_calling = models.CharField(max_length=1, blank=True, null=True) + finish_calling_right = models.CharField(max_length=1, blank=True, null=True) + fallrisk = models.CharField(db_column='fallRisk', max_length=1, blank=True, null=True) # Field name made lowercase. + fallrisktime = models.DateTimeField(db_column='fallRiskTime', blank=True, null=True) # Field name made lowercase. + makewill = models.CharField(db_column='makeWill', max_length=1, blank=True, null=True) # Field name made lowercase. + willtime = models.DateTimeField(db_column='willTime', blank=True, null=True) # Field name made lowercase. + editdate = models.DateTimeField(blank=True, null=True) + edituser = models.CharField(max_length=10, blank=True, null=True) + main_doctor = models.CharField(max_length=50, blank=True, null=True) + rt_doctor = models.CharField(db_column='RT_doctor', max_length=50, blank=True, null=True) # Field name made lowercase. + main_diagnose = models.TextField(blank=True, null=True) + smsstatus = models.CharField(db_column='smsStatus', max_length=1, blank=True, null=True) # Field name made lowercase. + smsmsg = models.CharField(db_column='smsMsg', max_length=50, blank=True, null=True) # Field name made lowercase. + ctnm = models.CharField(db_column='CTnm', max_length=50, blank=True, null=True) # Field name made lowercase. + onlinestatus = models.IntegerField(db_column='Onlinestatus', blank=True, null=True) # Field name made lowercase. + okdate = models.DateTimeField(blank=True, null=True) + onlineokdate = models.DateTimeField(db_column='ONLINEOKDATE', blank=True, null=True) # Field name made lowercase. + okstatus = models.IntegerField(blank=True, null=True) + period = models.IntegerField(blank=True, null=True) + onlineok = models.CharField(db_column='ONLINEOK', max_length=1, blank=True, null=True) # Field name made lowercase. + + class Meta: + managed = False + db_table = 'patient_appointment_schedule' + + +class Sms(models.Model): + smsway = models.CharField(db_column='smsWay', max_length=50, blank=True, null=True) # Field name made lowercase. + smsdate = models.DateTimeField(db_column='smsDate', blank=True, null=True) # Field name made lowercase. + hour = models.CharField(max_length=2, blank=True, null=True) + minute = models.CharField(max_length=2, blank=True, null=True) + cname = models.CharField(max_length=50, blank=True, null=True) + smscontent = models.TextField(db_column='smsContent', blank=True, null=True) # Field name made lowercase. + userid = models.CharField(db_column='userId', max_length=50, blank=True, null=True) # Field name made lowercase. + history = models.CharField(db_column='History', max_length=50, blank=True, null=True) # Field name made lowercase. + getlogs = models.CharField(db_column='getLogs', max_length=50, blank=True, null=True) # Field name made lowercase. + roomid = models.CharField(max_length=10, blank=True, null=True) + mobile = models.CharField(max_length=50, blank=True, null=True) + smsresult = models.CharField(db_column='smsResult', max_length=100, blank=True, null=True) # Field name made lowercase. + adddate = models.DateTimeField(blank=True, null=True) + adduser = models.CharField(max_length=50, blank=True, null=True) + types = models.CharField(max_length=1, blank=True, null=True) + smsstatus = models.CharField(db_column='smsStatus', max_length=100, blank=True, null=True) # Field name made lowercase. + targetuser = models.CharField(db_column='targetUser', max_length=1, blank=True, null=True) # Field name made lowercase. + senddate = models.DateTimeField(blank=True, null=True) + + class Meta: + managed = False + db_table = 'sms' + + +class Smslog(models.Model): + username = models.CharField(db_column='UserName', max_length=50, blank=True, null=True) # Field name made lowercase. + smsdatetime = models.DateTimeField(db_column='smsDateTime', blank=True, null=True) # Field name made lowercase. + createdatetime = models.DateTimeField(db_column='CreateDateTime', blank=True, null=True) # Field name made lowercase. + smscontent = models.TextField(db_column='smsContent', blank=True, null=True) # Field name made lowercase. + sendstatus = models.CharField(db_column='sendStatus', max_length=100, blank=True, null=True) # Field name made lowercase. + statuscode = models.CharField(db_column='statusCode', max_length=50, blank=True, null=True) # Field name made lowercase. + smsid = models.IntegerField(blank=True, null=True) + msgseq = models.CharField(db_column='msgSeq', max_length=10, blank=True, null=True) # Field name made lowercase. + smsnum = models.CharField(max_length=10, blank=True, null=True) + + class Meta: + managed = False + db_table = 'smsLog' + + +class Smshistory(models.Model): + id = models.AutoField(primary_key=True) + smsbody = models.TextField(db_column='Smsbody', blank=True, null=True) # Field name made lowercase. + smstitle = models.CharField(max_length=50, blank=True, null=True) + type = models.CharField(max_length=1, blank=True, null=True) + roomid = models.CharField(max_length=50, blank=True, null=True) + + class Meta: + managed = False + db_table = 'smshistory' + + +class TreatmentRoom(models.Model): + id = models.CharField(primary_key=True, max_length=50) + room_name = models.CharField(max_length=50, blank=True, null=True) + room_show_name = models.CharField(max_length=50, blank=True, null=True) + room_status = models.CharField(max_length=1, blank=True, null=True) + editdate = models.DateTimeField(blank=True, null=True) + edituser = models.CharField(max_length=50, blank=True, null=True) + tv_status = models.CharField(max_length=1, blank=True, null=True) + capacity = models.IntegerField(blank=True, null=True) + isshow = models.IntegerField(blank=True, null=True) + + class Meta: + managed = False + db_table = 'treatment_room' diff --git a/mysite/mssql_ntuh/tests.py b/mysite/mssql_ntuh/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/mysite/mssql_ntuh/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/mysite/mssql_ntuh/views.py b/mysite/mssql_ntuh/views.py new file mode 100644 index 0000000..91ea44a --- /dev/null +++ b/mysite/mssql_ntuh/views.py @@ -0,0 +1,3 @@ +from django.shortcuts import render + +# Create your views here. diff --git a/mysite/mysite/__init__.py b/mysite/mysite/__init__.py new file mode 100755 index 0000000..e69de29 diff --git a/mysite/mysite/settings.py b/mysite/mysite/settings.py new file mode 100755 index 0000000..83583be --- /dev/null +++ b/mysite/mysite/settings.py @@ -0,0 +1,331 @@ +""" +Django settings for mysite project. + +For more information on this file, see +https://docs.djangoproject.com/en/1.7/topics/settings/ + +For the full list of settings and their values, see +https://docs.djangoproject.com/en/1.7/ref/settings/ +""" + +# Build paths inside the project like this: os.path.join(BASE_DIR, ...) +import os +BASE_DIR = os.path.dirname(os.path.dirname(__file__)) + +PROJECT_ROOT = os.path.abspath( + os.path.join(os.path.dirname(__file__), ".."), +) + +# Quick-start development settings - unsuitable for production +# See https://docs.djangoproject.com/en/1.7/howto/deployment/checklist/ + +# SECURITY WARNING: keep the secret key used in production secret! +SECRET_KEY = '&t&czmg=xh$7*d!5eagw!=_v@kfm9e*t78pnz12%ql^(r)9))h' + +# SECURITY WARNING: don't run with debug turned on in production! +DEBUG = True + +# TEMPLATE_DEBUG = True + +ALLOWED_HOSTS = [ + 'ck.ntuh.net', + 'dev', + 'dev18', + 'dev.xiao.tw', + 'localhost', + '192.168.11.178', +] + +ALLOWED_HOSTS = [ '*' ] + +# Application definition + +INSTALLED_APPS = ( + + 'django.contrib.admin', + 'django.contrib.auth', + 'django.contrib.contenttypes', + 'django.contrib.sessions', + 'django.contrib.messages', + 'django.contrib.staticfiles', + +# 'autocomplete_light', + # 'debug_toolbar.apps.DebugToolbarConfig', + # 'cacheops', + 'dal', + 'dal_select2', + 'datatableview', + 'debug_toolbar', + 'djangobower', + # 'django_python3_ldap', + 'django_tables2', + + 'rest_framework', + 'rest_framework_datatables', + # 'schedule', + + 'ck', + 'calculator', + 'nsclc', + 'mssql_ntuh', + +) + +# MIDDLEWARE_CLASSES = ( +MIDDLEWARE = ( + 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.middleware.common.CommonMiddleware', + 'django.middleware.csrf.CsrfViewMiddleware', + 'django.contrib.auth.middleware.AuthenticationMiddleware', + # 'django.contrib.auth.middleware.SessionAuthenticationMiddleware', + 'django.contrib.messages.middleware.MessageMiddleware', + 'django.middleware.clickjacking.XFrameOptionsMiddleware', + + 'debug_toolbar.middleware.DebugToolbarMiddleware', +) + +ROOT_URLCONF = 'mysite.urls' + +WSGI_APPLICATION = 'mysite.wsgi.application' + + +# Database +# https://docs.djangoproject.com/en/1.7/ref/settings/#databases + +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.sqlite3', + 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), + }, +} + +# Internationalization +# https://docs.djangoproject.com/en/1.7/topics/i18n/ + +LANGUAGE_CODE = 'en-us' + +TIME_ZONE = 'UTC' +TIME_ZONE = 'Asia/Taipei' + +USE_I18N = True + +USE_L10N = True + +USE_TZ = True + + +# Static files (CSS, JavaScript, Images) +# https://docs.djangoproject.com/en/1.7/howto/static-files/ + +STATIC_URL = '/static/' +STATIC_ROOT = os.path.join(PROJECT_ROOT, 'static') +STATIC_ROOT = '/home/cks/public_html/static' + +BOWER_COMPONENTS_ROOT = os.path.join(PROJECT_ROOT, 'components') + +STATICFILES_FINDERS = ( + 'django.contrib.staticfiles.finders.FileSystemFinder', + 'django.contrib.staticfiles.finders.AppDirectoriesFinder', + 'djangobower.finders.BowerFinder', +) + +TEMPLATES = [ + { + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'DIRS': [ + # '/home/xfr/workspace/ntuh/fileupload/templates', + # '/home/xfr/Titanium Studio Workspace/xfr/ntuh/templates', + # '/home/xfr/workspace/ntuh/templates', + # '/home/ntuh/domains/adm.ntuh.net/ntuh/templates', + os.path.join(BASE_DIR, 'templates').replace('\\','/'), + ], + 'APP_DIRS': True, + 'OPTIONS': { + 'context_processors': [ + 'django.template.context_processors.debug', + 'django.template.context_processors.request', + 'django.contrib.auth.context_processors.auth', + 'django.contrib.messages.context_processors.messages', + ], + 'debug': True, + }, + }, +] + + +INTERNAL_IPS = ( + # '127.0.0.1', + '192.168.11.133', + '192.168.11.175', + '192.168.10.100', + '192.168.11.17', + ) + +LOGOUT_REDIRECT_URL = '/' + +def is_ajax(request): + return request.META.get('HTTP_X_REQUESTED_WITH') == 'XMLHttpRequest' + +def show_toolbar(request): + # return not request.is_ajax() and request.user and request.user.username == "xfr" + return not is_ajax(request=request) and request.user and request.user.username == "xfr" + +DEBUG_TOOLBAR_CONFIG = { + 'SHOW_TOOLBAR_CALLBACK': 'mysite.settings.show_toolbar', + # Rest of config +} + +BOWER_INSTALLED_APPS = ( + 'bootstrap', + 'https://github.com/Talv/x-editable.git#develop', + 'fullcalendar', + # 'jquery', + # 'underscore', +) + +# REST_FRAMEWORK = { +# 'DEFAULT_RENDERER_CLASSES': ( +# 'rest_framework.renderers.JSONRenderer', +# 'rest_framework.renderers.BrowsableAPIRenderer', +# 'rest_framework_datatables.renderers.DatatablesRenderer', +# ), +# 'DEFAULT_FILTER_BACKENDS': ( +# 'rest_framework_datatables.filters.DatatablesFilterBackend', +# ), +# 'DEFAULT_PAGINATION_CLASS': 'rest_framework_datatables.pagination.DatatablesPageNumberPagination', +# 'PAGE_SIZE': 50, +# } + +CACHEOPS_REDIS = { + 'host': 'localhost', # redis-server is on same machine + 'port': 6379, # default redis port + 'db': 1, # SELECT non-default redis database + # using separate redis db or redis instance + # is highly recommended + + # 'socket_timeout': 3, # connection timeout in seconds, optional + # 'password': '...', # optional + # 'unix_socket_path': '' # replaces host and port +} + +CACHEOPS = { + 'ck.ICD10CMfinal': { + 'ops': 'all', + 'timeout': 31556926, # 1 year + 'local_get': True, + }, + # '*.*': {}, +} + +# CACHEOPS_DEGRADE_ON_FAILURE = True + + +CELERY_TIMEZONE = "Asia/Taipei" +CELERY_TASK_TRACK_STARTED = True +CELERY_TASK_TIME_LIMIT = 30 * 60 + +# django-python3-ldap +AUTHENTICATION_BACKENDS=("django_python3_ldap.auth.LDAPBackend",) + +# The URL of the LDAP server. +LDAP_AUTH_URL = "ldap://localhost:389" +LDAP_AUTH_URL = "ldap://172.16.3.33:389" + + +# ldap://172.16.3.33:389/DC=ntuh,DC=gov,DC=tw + +# Initiate TLS on connection. +LDAP_AUTH_USE_TLS = False + +# The LDAP search base for looking up users. +LDAP_AUTH_SEARCH_BASE = "ou=people,dc=example,dc=com" +LDAP_AUTH_SEARCH_BASE = "DC=ntuh,DC=gov,DC=tw" + +# The LDAP class that represents a user. +LDAP_AUTH_OBJECT_CLASS = "inetOrgPerson" +LDAP_AUTH_OBJECT_CLASS = "user" + +# User model fields mapped to the LDAP +# attributes that represent them. +LDAP_AUTH_USER_FIELDS = { + "username": "uid", + "first_name": "givenName", + "last_name": "sn", + "email": "mail", +} +LDAP_AUTH_USER_FIELDS = { + "username": "sAMAccountName", + "first_name": "givenName", + "last_name": "sn", + "email": "mail", +} + +# A tuple of django model fields used to uniquely identify a user. +LDAP_AUTH_USER_LOOKUP_FIELDS = ("username",) + +# Path to a callable that takes a dict of {model_field_name: value}, +# returning a dict of clean model data. +# Use this to customize how data loaded from LDAP is saved to the User model. +LDAP_AUTH_CLEAN_USER_DATA = "django_python3_ldap.utils.clean_user_data" + +# Path to a callable that takes a user model and a dict of {ldap_field_name: [value]}, +# and saves any additional user relationships based on the LDAP data. +# Use this to customize how data loaded from LDAP is saved to User model relations. +# For customizing non-related User model fields, use LDAP_AUTH_CLEAN_USER_DATA. +LDAP_AUTH_SYNC_USER_RELATIONS = "django_python3_ldap.utils.sync_user_relations" + +# Path to a callable that takes a dict of {ldap_field_name: value}, +# returning a list of [ldap_search_filter]. The search filters will then be AND'd +# together when creating the final search filter. +LDAP_AUTH_FORMAT_SEARCH_FILTERS = "django_python3_ldap.utils.format_search_filters" + +# Path to a callable that takes a dict of {model_field_name: value}, and returns +# a string of the username to bind to the LDAP server. +# Use this to support different types of LDAP server. +LDAP_AUTH_FORMAT_USERNAME = "django_python3_ldap.utils.format_username_openldap" +LDAP_AUTH_FORMAT_USERNAME = "django_python3_ldap.utils.format_username_active_directory" + +# Sets the login domain for Active Directory users. +LDAP_AUTH_ACTIVE_DIRECTORY_DOMAIN = None + +# The LDAP username and password of a user for querying the LDAP database for user +# details. If None, then the authenticated user will be used for querying, and +# the `ldap_sync_users` command will perform an anonymous query. +LDAP_AUTH_CONNECTION_USERNAME = None +LDAP_AUTH_CONNECTION_PASSWORD = None +LDAP_AUTH_CONNECTION_USERNAME = '123456@example.com' +LDAP_AUTH_CONNECTION_PASSWORD = '123456' + +# Set connection/receive timeouts (in seconds) on the underlying `ldap3` library. +LDAP_AUTH_CONNECT_TIMEOUT = None +LDAP_AUTH_RECEIVE_TIMEOUT = None + +# django-auth-ldap +AUTHENTICATION_BACKENDS = [ + "django_auth_ldap.backend.LDAPBackend", + "django.contrib.auth.backends.ModelBackend", +] + +AUTH_LDAP_SERVER_URI = "ldap://172.16.3.33:389" + + +import ldap +from django_auth_ldap.config import LDAPSearch + +AUTH_LDAP_BIND_DN = "123456@example.com" +AUTH_LDAP_BIND_PASSWORD = "123456" +AUTH_LDAP_USER_SEARCH = LDAPSearch( + "DC=ntuh,DC=gov,DC=tw", ldap.SCOPE_SUBTREE, "(sAMAccountName=%(user)s)" +) + +AUTH_LDAP_CONNECTION_OPTIONS = { ldap.OPT_DEBUG_LEVEL: 1, ldap.OPT_REFERRALS: 0, } + +try: + from .local_settings import * +except ImportError: + pass + +if 'workspace' in BASE_DIR or 'git' in BASE_DIR: + DATABASES['default'] = DATABASES['ck_dev'] +else: + DATABASES['default'] = DATABASES['cks'] diff --git a/mysite/mysite/site_media/css/0m4r.table.css b/mysite/mysite/site_media/css/0m4r.table.css new file mode 100755 index 0000000..9aefebd --- /dev/null +++ b/mysite/mysite/site_media/css/0m4r.table.css @@ -0,0 +1,49 @@ +table{ + border: 0px solid black; + border-spacing: 0px; +} + +table thead tr{ + font-family: Arial, monospace; + font-size: 14px; +} + +table thead tr th{ + border-bottom: 2px solid black; + border-top: 1px solid black; + margin: 0px; + padding: 2px; + background-color: #cccccc; +} + +table tr { + font-family: arial, monospace; + color: black; + font-size:12px; + background-color: white; +} + +table tr.odd { + background-color: #AAAAAA; +} + +table tr td, th{ + border-bottom: 1px solid black; + padding: 2px; +} + +a:link{ + font-family:arial, monospace; + text-decoration: none; + color: teal; +} + +a:hover{ + text-decoration: underline; +} + +a:visited{ + color:black; + text-decoration: none; +} + diff --git a/mysite/mysite/site_media/css/acuity.css b/mysite/mysite/site_media/css/acuity.css new file mode 100755 index 0000000..5582260 --- /dev/null +++ b/mysite/mysite/site_media/css/acuity.css @@ -0,0 +1,72 @@ +table { + border-collapse: collapse; + border: none; + font: normal 11px helvetica, verdana, arial, sans-serif; + background-image: url(http://www.acuity.com.br/extern/icant.co.uk/bg_acuity.gif); + background-repeat: repeat; + +border-spacing: 1px; + } +caption { + text-align: left; + font: normal 11px helvetica, verdana, arial, sans-serif; + background: transparent; + } +td, th { + border: none; + padding: .8em; + color: #6E6E6E; + } +thead th, tfoot th { + font: bold 10px helvetica, verdana, arial, sans-serif; + border: none; + text-align: left; + background: #000000; + color: #00FF0C; + padding-top:4px; + } +tbody td a { + background: transparent; + text-decoration: none; + color: #9F9F9F; + } +tbody td a:hover { + background: transparent; + color: #00FF0C; + } +tbody th a { + font: bold 11px helvetica, verdana, arial, sans-serif; + background: transparent; + text-decoration: none; + font-weight:normal; + color: #9F9F9F; + } + + +tbody td+td+td+td a { + padding-right: 14px; + background: url(http://www.acuity.com.br/extern/icant.co.uk/arrow.gif) transparent no-repeat bottom right; + } + tbody td+td+td+td a:hover { + padding-right: 14px; + background: url(http://www.acuity.com.br/extern/icant.co.uk/arrow.gif) transparent no-repeat bottom right; + } +tbody th a:hover { + background: transparent; + color: #00FF0C; + } +tbody th, tbody td { + vertical-align: top; + text-align: left; + } + +.odd { + background: #000000; + } +tbody tr:hover { + background: #0E0E0E; + } +tbody tr:hover th, +tbody tr.odd:hover th { + background: #0E0E0E; + } diff --git a/mysite/mysite/site_media/css/arrow_bullet_list_menu.css b/mysite/mysite/site_media/css/arrow_bullet_list_menu.css new file mode 100755 index 0000000..d650db7 --- /dev/null +++ b/mysite/mysite/site_media/css/arrow_bullet_list_menu.css @@ -0,0 +1,47 @@ +/*Credits: Dynamic Drive CSS Library */ +/*URL: http://www.dynamicdrive.com/style/ */ + +.arrowlistmenu{ +width: 180px; /*width of menu*/ +} + +.arrowlistmenu .headerbar{ +font: bold 14px Arial; +color: white; +background: black url(media/titlebar.png) repeat-x center left; +margin-bottom: 10px; /*bottom spacing between header and rest of content*/ +text-transform: uppercase; +padding: 4px 0 4px 10px; /*header text is indented 10px*/ +} + +.arrowlistmenu ul{ +list-style-type: none; +margin: 0; +padding: 0; +margin-bottom: 8px; /*bottom spacing between each UL and rest of content*/ +} + +.arrowlistmenu ul li{ +padding-bottom: 2px; /*bottom spacing between menu items*/ +} + +.arrowlistmenu ul li a{ +color: #A70303; +background: url(media/arrowbullet.png) no-repeat center left; /*custom bullet list image*/ +display: block; +padding: 2px 0; +padding-left: 19px; /*link text is indented 19px*/ +text-decoration: none; +font-weight: bold; +border-bottom: 1px solid #dadada; +font-size: 90%; +} + +.arrowlistmenu ul li a:visited{ +color: #A70303; +} + +.arrowlistmenu ul li a:hover{ /*hover state CSS*/ +color: #A70303; +background-color: #F3F3F3; +} diff --git a/mysite/mysite/site_media/css/css-liquid-layout-21-fixed-fluid.css b/mysite/mysite/site_media/css/css-liquid-layout-21-fixed-fluid.css new file mode 100755 index 0000000..6f31ae0 --- /dev/null +++ b/mysite/mysite/site_media/css/css-liquid-layout-21-fixed-fluid.css @@ -0,0 +1,55 @@ +body{ +margin:0; +padding:0; +line-height: 1.5em; +} + +b{font-size: 110%;} +em{color: red;} + + +#topsection{ +background: #EAEAEA; +height: 90px; /*Height of top section*/ +} + +#topsection h1{ +margin: 0; +padding-top: 15px; +} + +#contentwrapper{ +float: left; +width: 100%; +} + +#contentcolumn{ +/*margin-left: 200px; /*Set left margin to LeftColumnWidth*/ +margin-left: 180px; /*Set left margin to LeftColumnWidth*/ +} + +#leftcolumn{ +float: left; +/*width: 200px; /*Width of left column*/ +width: 180px; /*Width of left column*/ +margin-left: -100%; +background: #C8FC98; +} + +#footer{ +clear: left; +width: 100%; +background: black; +color: #FFF; +text-align: center; +padding: 4px 0; +} + +#footer a{ +color: #FFFF80; +} + +.innertube{ +margin: 10px; /*Margins for inner DIV inside each column (to provide padding)*/ +margin-top: 0; +} diff --git a/mysite/mysite/site_media/css/css-liquid-layout-31-fixed-fluid-fixed.css b/mysite/mysite/site_media/css/css-liquid-layout-31-fixed-fluid-fixed.css new file mode 100755 index 0000000..232d721 --- /dev/null +++ b/mysite/mysite/site_media/css/css-liquid-layout-31-fixed-fluid-fixed.css @@ -0,0 +1,63 @@ +body{ +margin:0; +padding:0; +line-height: 1.5em; +} + +b{font-size: 110%;} +em{color: red;} + +#topsection{ +background: #EAEAEA; +height: 90px; /*Height of top section*/ +} + +#topsection h1{ +margin: 0; +padding-top: 15px; +} + +#contentwrapper{ +float: left; +width: 100%; +} + +#contentcolumn{ +/*margin: 0 200px 0 230px; /*Margins for content column. Should be "0 RightColumnWidth 0 LeftColumnWidth*/ +margin: 0 160px 0 180px; /*Margins for content column. Should be "0 RightColumnWidth 0 LeftColumnWidth*/ +} + +#leftcolumn{ +float: left; +/*width: 230px; /*Width of left column*/ +width: 180px; /*Width of left column*/ +margin-left: -100%; +background: #C8FC98; +} + +#rightcolumn{ +float: left; +/*width: 200px; /*Width of right column*/ +/*margin-left: -200px; /*Set left marginto -(RightColumnWidth)*/ +width: 160px; /*Width of right column*/ +margin-left: -160px; /*Set left marginto -(RightColumnWidth)*/ +background: #FDE95E; +} + +#footer{ +clear: left; +width: 100%; +background: black; +color: #FFF; +text-align: center; +padding: 4px 0; +} + +#footer a{ +color: #FFFF80; +} + +.innertube{ +margin: 10px; /*Margins for inner DIV inside each column (to provide padding)*/ +margin-top: 0; +} diff --git a/mysite/mysite/site_media/css/css-liquid-layout-32-fluid-fluid-fixed.css b/mysite/mysite/site_media/css/css-liquid-layout-32-fluid-fluid-fixed.css new file mode 100755 index 0000000..c2c4b04 --- /dev/null +++ b/mysite/mysite/site_media/css/css-liquid-layout-32-fluid-fluid-fixed.css @@ -0,0 +1,109 @@ + + + + +Dynamic Drive: CSS Liquid Layout #3.2- (Fluid-Fluid-Fixed) + + + + + + +
+ +

CSS Liquid Layout #3.2- (Fluid-Fluid-Fixed)

+ +
+
+
Content Column: Fluid
+
+
+ +
+
Left Column: 25%
+ +
+ +
+
Right Column: 200px
+
+ + + +
+ + diff --git a/mysite/mysite/site_media/css/css-liquid-layout-33-fluid-fluid-fluid.css b/mysite/mysite/site_media/css/css-liquid-layout-33-fluid-fluid-fluid.css new file mode 100755 index 0000000..386b7bb --- /dev/null +++ b/mysite/mysite/site_media/css/css-liquid-layout-33-fluid-fluid-fluid.css @@ -0,0 +1,60 @@ +body{ +margin:0; +padding:0; +line-height: 1.5em; +} + +b{font-size: 110%;} +em{color: red;} + + +#topsection{ +background: #EAEAEA; +height: 90px; /*Height of top section*/ +} + +#topsection h1{ +margin: 0; +padding-top: 15px; +} + +#contentwrapper{ +float: left; +width: 100%; +} + +#contentcolumn{ +margin: 0 15% 0 20%; /*Margins for content column. Should be "0 RightColumnWidth 0 LeftColumnWidth*/ +} + +#leftcolumn{ +float: left; +width: 20%; /*Width of left column in percentage*/ +margin-left: -100%; +background: #C8FC98; +} + +#rightcolumn{ +float: left; +width: 15%; /*Width of right column in pixels*/ +margin-left: -15%; /*Set margin to that of -(RightColumnWidth)*/ +background: #FDE95E; +} + +#footer{ +clear: left; +width: 100%; +background: black; +color: #FFF; +text-align: center; +padding: 4px 0; +} + +#footer a{ +color: #FFFF80; +} + +.innertube{ +margin: 10px; /*Margins for inner DIV inside each column (to provide padding)*/ +margin-top: 0; +} diff --git a/mysite/mysite/site_media/css/css-up2date.css b/mysite/mysite/site_media/css/css-up2date.css new file mode 100755 index 0000000..f58ea45 --- /dev/null +++ b/mysite/mysite/site_media/css/css-up2date.css @@ -0,0 +1,74 @@ +/* + project: CSS - table design + type: stylesheet + description: aqua + edited: 19.11.2007, Matthias Richter +*/ +table { + border-collapse: collapse; + border: 1px solid #a4c7db; + font: Verdana, Arial, Helvetica, sans-serif; + font-size: 0.8em; + color: #fff; + background: #151a25; +} +caption { + padding: 0 .4em .4em; + text-align: left; + font-size: 1em; + font-weight: bold; + text-transform: uppercase; + color: #fff; + background: transparent; +} +td, th { + color: #fff; + border: 1px solid #a4c7db; + padding: .3em; + font-family: Verdana, Arial, Helvetica, sans-serif; +} +thead th, tfoot th { + border: transparent; + text-align: left; + font-size: 1.0em; + font-weight: bold; + color: #fff; + background: #151a25; +} +tbody td a { + background: transparent; + color: #fff; + text-decoration: none; +} +tbody td a:hover { + background: transparent; + color: #fff; +} +tbody th a { + background: transparent; + color: #fff; + text-decoration: none; + font-weight:normal; +} +tbody th a:hover { + background: transparent; + color: #ccc; +} +tbody th, tbody td { + vertical-align: top; + text-align: left; +} +tfoot td { + border: 1px solid #a4c7db; + background: #C5BA85; +} +.odd { + background: #8093bc; +} +tbody tr:hover { + color: #333444; + background: #65728d; +} +tbody tr:hover th, tbody tr.odd:hover th { + background: #65728d; +} diff --git a/mysite/mysite/site_media/css/glossy_horizontal_menu.css b/mysite/mysite/site_media/css/glossy_horizontal_menu.css new file mode 100755 index 0000000..bc61258 --- /dev/null +++ b/mysite/mysite/site_media/css/glossy_horizontal_menu.css @@ -0,0 +1,47 @@ +/*Credits: By Santosh Setty (http://webdesigninfo.wordpress.com) */ +/*Posted to: Dynamic Drive CSS Library (http://www.dynamicdrive.com/style/) */ + +.glossymenu{ + position: relative; + padding: 0 0 0 34px; + margin: 0 auto 0 auto; + background: url(media/menur_bg.gif) repeat-x; /*tab background image path*/ + height: 46px; + list-style: none; +} + +.glossymenu li{ + float:left; +} + +.glossymenu li a{ + float: left; + display: block; + color:#000; + text-decoration: none; + font-family: sans-serif; + font-size: 13px; + font-weight: bold; + padding:0 0 0 16px; /*Padding to accomodate left tab image. Do not change*/ + height: 46px; + line-height: 46px; + text-align: center; + cursor: pointer; +} + +.glossymenu li a b{ + float: left; + display: block; + padding: 0 24px 0 8px; /*Padding of menu items*/ +} + +.glossymenu li.current a, .glossymenu li a:hover{ + color: #fff; + background: url(media/menur_hover_left.gif) no-repeat; /*left tab image path*/ + background-position: left; +} + +.glossymenu li.current a b, .glossymenu li a:hover b{ + color: #fff; + background: url(media/menur_hover_right.gif) no-repeat right top; /*right tab image path*/ +} diff --git a/mysite/mysite/site_media/css/media/Thumbs.db b/mysite/mysite/site_media/css/media/Thumbs.db new file mode 100755 index 0000000..23b80a6 Binary files /dev/null and b/mysite/mysite/site_media/css/media/Thumbs.db differ diff --git a/mysite/mysite/site_media/css/media/arrowbullet.png b/mysite/mysite/site_media/css/media/arrowbullet.png new file mode 100755 index 0000000..bba0330 Binary files /dev/null and b/mysite/mysite/site_media/css/media/arrowbullet.png differ diff --git a/mysite/mysite/site_media/css/media/arrowstop.gif b/mysite/mysite/site_media/css/media/arrowstop.gif new file mode 100755 index 0000000..e0be658 Binary files /dev/null and b/mysite/mysite/site_media/css/media/arrowstop.gif differ diff --git a/mysite/mysite/site_media/css/media/logo.gif b/mysite/mysite/site_media/css/media/logo.gif new file mode 100755 index 0000000..e0819d1 Binary files /dev/null and b/mysite/mysite/site_media/css/media/logo.gif differ diff --git a/mysite/mysite/site_media/css/media/menur_bg.gif b/mysite/mysite/site_media/css/media/menur_bg.gif new file mode 100755 index 0000000..1c2c07b Binary files /dev/null and b/mysite/mysite/site_media/css/media/menur_bg.gif differ diff --git a/mysite/mysite/site_media/css/media/menur_hover_left.gif b/mysite/mysite/site_media/css/media/menur_hover_left.gif new file mode 100755 index 0000000..34f686c Binary files /dev/null and b/mysite/mysite/site_media/css/media/menur_hover_left.gif differ diff --git a/mysite/mysite/site_media/css/media/menur_hover_right.gif b/mysite/mysite/site_media/css/media/menur_hover_right.gif new file mode 100755 index 0000000..2cc7a3c Binary files /dev/null and b/mysite/mysite/site_media/css/media/menur_hover_right.gif differ diff --git a/mysite/mysite/site_media/css/media/titlebar.png b/mysite/mysite/site_media/css/media/titlebar.png new file mode 100755 index 0000000..f028a91 Binary files /dev/null and b/mysite/mysite/site_media/css/media/titlebar.png differ diff --git a/mysite/mysite/site_media/css/smoothness/images/ui-bg_flat_0_aaaaaa_40x100.png b/mysite/mysite/site_media/css/smoothness/images/ui-bg_flat_0_aaaaaa_40x100.png new file mode 100755 index 0000000..5b5dab2 Binary files /dev/null and b/mysite/mysite/site_media/css/smoothness/images/ui-bg_flat_0_aaaaaa_40x100.png differ diff --git a/mysite/mysite/site_media/css/smoothness/images/ui-bg_flat_75_ffffff_40x100.png b/mysite/mysite/site_media/css/smoothness/images/ui-bg_flat_75_ffffff_40x100.png new file mode 100755 index 0000000..ac8b229 Binary files /dev/null and b/mysite/mysite/site_media/css/smoothness/images/ui-bg_flat_75_ffffff_40x100.png differ diff --git a/mysite/mysite/site_media/css/smoothness/images/ui-bg_glass_55_fbf9ee_1x400.png b/mysite/mysite/site_media/css/smoothness/images/ui-bg_glass_55_fbf9ee_1x400.png new file mode 100755 index 0000000..ad3d634 Binary files /dev/null and b/mysite/mysite/site_media/css/smoothness/images/ui-bg_glass_55_fbf9ee_1x400.png differ diff --git a/mysite/mysite/site_media/css/smoothness/images/ui-bg_glass_65_ffffff_1x400.png b/mysite/mysite/site_media/css/smoothness/images/ui-bg_glass_65_ffffff_1x400.png new file mode 100755 index 0000000..42ccba2 Binary files /dev/null and b/mysite/mysite/site_media/css/smoothness/images/ui-bg_glass_65_ffffff_1x400.png differ diff --git a/mysite/mysite/site_media/css/smoothness/images/ui-bg_glass_75_dadada_1x400.png b/mysite/mysite/site_media/css/smoothness/images/ui-bg_glass_75_dadada_1x400.png new file mode 100755 index 0000000..5a46b47 Binary files /dev/null and b/mysite/mysite/site_media/css/smoothness/images/ui-bg_glass_75_dadada_1x400.png differ diff --git a/mysite/mysite/site_media/css/smoothness/images/ui-bg_glass_75_e6e6e6_1x400.png b/mysite/mysite/site_media/css/smoothness/images/ui-bg_glass_75_e6e6e6_1x400.png new file mode 100755 index 0000000..86c2baa Binary files /dev/null and b/mysite/mysite/site_media/css/smoothness/images/ui-bg_glass_75_e6e6e6_1x400.png differ diff --git a/mysite/mysite/site_media/css/smoothness/images/ui-bg_glass_95_fef1ec_1x400.png b/mysite/mysite/site_media/css/smoothness/images/ui-bg_glass_95_fef1ec_1x400.png new file mode 100755 index 0000000..4443fdc Binary files /dev/null and b/mysite/mysite/site_media/css/smoothness/images/ui-bg_glass_95_fef1ec_1x400.png differ diff --git a/mysite/mysite/site_media/css/smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.png b/mysite/mysite/site_media/css/smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.png new file mode 100755 index 0000000..7c9fa6c Binary files /dev/null and b/mysite/mysite/site_media/css/smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.png differ diff --git a/mysite/mysite/site_media/css/smoothness/images/ui-icons_222222_256x240.png b/mysite/mysite/site_media/css/smoothness/images/ui-icons_222222_256x240.png new file mode 100755 index 0000000..b273ff1 Binary files /dev/null and b/mysite/mysite/site_media/css/smoothness/images/ui-icons_222222_256x240.png differ diff --git a/mysite/mysite/site_media/css/smoothness/images/ui-icons_2e83ff_256x240.png b/mysite/mysite/site_media/css/smoothness/images/ui-icons_2e83ff_256x240.png new file mode 100755 index 0000000..09d1cdc Binary files /dev/null and b/mysite/mysite/site_media/css/smoothness/images/ui-icons_2e83ff_256x240.png differ diff --git a/mysite/mysite/site_media/css/smoothness/images/ui-icons_454545_256x240.png b/mysite/mysite/site_media/css/smoothness/images/ui-icons_454545_256x240.png new file mode 100755 index 0000000..59bd45b Binary files /dev/null and b/mysite/mysite/site_media/css/smoothness/images/ui-icons_454545_256x240.png differ diff --git a/mysite/mysite/site_media/css/smoothness/images/ui-icons_888888_256x240.png b/mysite/mysite/site_media/css/smoothness/images/ui-icons_888888_256x240.png new file mode 100755 index 0000000..6d02426 Binary files /dev/null and b/mysite/mysite/site_media/css/smoothness/images/ui-icons_888888_256x240.png differ diff --git a/mysite/mysite/site_media/css/smoothness/images/ui-icons_cd0a0a_256x240.png b/mysite/mysite/site_media/css/smoothness/images/ui-icons_cd0a0a_256x240.png new file mode 100755 index 0000000..2ab019b Binary files /dev/null and b/mysite/mysite/site_media/css/smoothness/images/ui-icons_cd0a0a_256x240.png differ diff --git a/mysite/mysite/site_media/css/smoothness/jquery-ui-1.8.16.custom.css b/mysite/mysite/site_media/css/smoothness/jquery-ui-1.8.16.custom.css new file mode 100755 index 0000000..0f1a7e7 --- /dev/null +++ b/mysite/mysite/site_media/css/smoothness/jquery-ui-1.8.16.custom.css @@ -0,0 +1,568 @@ +/* + * jQuery UI CSS Framework 1.8.16 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Theming/API + */ + +/* Layout helpers +----------------------------------*/ +.ui-helper-hidden { display: none; } +.ui-helper-hidden-accessible { position: absolute !important; clip: rect(1px 1px 1px 1px); clip: rect(1px,1px,1px,1px); } +.ui-helper-reset { margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none; } +.ui-helper-clearfix:after { content: "."; display: block; height: 0; clear: both; visibility: hidden; } +.ui-helper-clearfix { display: inline-block; } +/* required comment for clearfix to work in Opera \*/ +* html .ui-helper-clearfix { height:1%; } +.ui-helper-clearfix { display:block; } +/* end clearfix */ +.ui-helper-zfix { width: 100%; height: 100%; top: 0; left: 0; position: absolute; opacity: 0; filter:Alpha(Opacity=0); } + + +/* Interaction Cues +----------------------------------*/ +.ui-state-disabled { cursor: default !important; } + + +/* Icons +----------------------------------*/ + +/* states and images */ +.ui-icon { display: block; text-indent: -99999px; overflow: hidden; background-repeat: no-repeat; } + + +/* Misc visuals +----------------------------------*/ + +/* Overlays */ +.ui-widget-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; } + + +/* + * jQuery UI CSS Framework 1.8.16 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Theming/API + * + * To view and modify this theme, visit http://jqueryui.com/themeroller/?ffDefault=Verdana,Arial,sans-serif&fwDefault=normal&fsDefault=1.1em&cornerRadius=4px&bgColorHeader=cccccc&bgTextureHeader=03_highlight_soft.png&bgImgOpacityHeader=75&borderColorHeader=aaaaaa&fcHeader=222222&iconColorHeader=222222&bgColorContent=ffffff&bgTextureContent=01_flat.png&bgImgOpacityContent=75&borderColorContent=aaaaaa&fcContent=222222&iconColorContent=222222&bgColorDefault=e6e6e6&bgTextureDefault=02_glass.png&bgImgOpacityDefault=75&borderColorDefault=d3d3d3&fcDefault=555555&iconColorDefault=888888&bgColorHover=dadada&bgTextureHover=02_glass.png&bgImgOpacityHover=75&borderColorHover=999999&fcHover=212121&iconColorHover=454545&bgColorActive=ffffff&bgTextureActive=02_glass.png&bgImgOpacityActive=65&borderColorActive=aaaaaa&fcActive=212121&iconColorActive=454545&bgColorHighlight=fbf9ee&bgTextureHighlight=02_glass.png&bgImgOpacityHighlight=55&borderColorHighlight=fcefa1&fcHighlight=363636&iconColorHighlight=2e83ff&bgColorError=fef1ec&bgTextureError=02_glass.png&bgImgOpacityError=95&borderColorError=cd0a0a&fcError=cd0a0a&iconColorError=cd0a0a&bgColorOverlay=aaaaaa&bgTextureOverlay=01_flat.png&bgImgOpacityOverlay=0&opacityOverlay=30&bgColorShadow=aaaaaa&bgTextureShadow=01_flat.png&bgImgOpacityShadow=0&opacityShadow=30&thicknessShadow=8px&offsetTopShadow=-8px&offsetLeftShadow=-8px&cornerRadiusShadow=8px + */ + + +/* Component containers +----------------------------------*/ +.ui-widget { font-family: Verdana,Arial,sans-serif; font-size: 1.1em; } +.ui-widget .ui-widget { font-size: 1em; } +.ui-widget input, .ui-widget select, .ui-widget textarea, .ui-widget button { font-family: Verdana,Arial,sans-serif; font-size: 1em; } +.ui-widget-content { border: 1px solid #aaaaaa; background: #ffffff url(images/ui-bg_flat_75_ffffff_40x100.png) 50% 50% repeat-x; color: #222222; } +.ui-widget-content a { color: #222222; } +.ui-widget-header { border: 1px solid #aaaaaa; background: #cccccc url(images/ui-bg_highlight-soft_75_cccccc_1x100.png) 50% 50% repeat-x; color: #222222; font-weight: bold; } +.ui-widget-header a { color: #222222; } + +/* Interaction states +----------------------------------*/ +.ui-state-default, .ui-widget-content .ui-state-default, .ui-widget-header .ui-state-default { border: 1px solid #d3d3d3; background: #e6e6e6 url(images/ui-bg_glass_75_e6e6e6_1x400.png) 50% 50% repeat-x; font-weight: normal; color: #555555; } +.ui-state-default a, .ui-state-default a:link, .ui-state-default a:visited { color: #555555; text-decoration: none; } +.ui-state-hover, .ui-widget-content .ui-state-hover, .ui-widget-header .ui-state-hover, .ui-state-focus, .ui-widget-content .ui-state-focus, .ui-widget-header .ui-state-focus { border: 1px solid #999999; background: #dadada url(images/ui-bg_glass_75_dadada_1x400.png) 50% 50% repeat-x; font-weight: normal; color: #212121; } +.ui-state-hover a, .ui-state-hover a:hover { color: #212121; text-decoration: none; } +.ui-state-active, .ui-widget-content .ui-state-active, .ui-widget-header .ui-state-active { border: 1px solid #aaaaaa; background: #ffffff url(images/ui-bg_glass_65_ffffff_1x400.png) 50% 50% repeat-x; font-weight: normal; color: #212121; } +.ui-state-active a, .ui-state-active a:link, .ui-state-active a:visited { color: #212121; text-decoration: none; } +.ui-widget :active { outline: none; } + +/* Interaction Cues +----------------------------------*/ +.ui-state-highlight, .ui-widget-content .ui-state-highlight, .ui-widget-header .ui-state-highlight {border: 1px solid #fcefa1; background: #fbf9ee url(images/ui-bg_glass_55_fbf9ee_1x400.png) 50% 50% repeat-x; color: #363636; } +.ui-state-highlight a, .ui-widget-content .ui-state-highlight a,.ui-widget-header .ui-state-highlight a { color: #363636; } +.ui-state-error, .ui-widget-content .ui-state-error, .ui-widget-header .ui-state-error {border: 1px solid #cd0a0a; background: #fef1ec url(images/ui-bg_glass_95_fef1ec_1x400.png) 50% 50% repeat-x; color: #cd0a0a; } +.ui-state-error a, .ui-widget-content .ui-state-error a, .ui-widget-header .ui-state-error a { color: #cd0a0a; } +.ui-state-error-text, .ui-widget-content .ui-state-error-text, .ui-widget-header .ui-state-error-text { color: #cd0a0a; } +.ui-priority-primary, .ui-widget-content .ui-priority-primary, .ui-widget-header .ui-priority-primary { font-weight: bold; } +.ui-priority-secondary, .ui-widget-content .ui-priority-secondary, .ui-widget-header .ui-priority-secondary { opacity: .7; filter:Alpha(Opacity=70); font-weight: normal; } +.ui-state-disabled, .ui-widget-content .ui-state-disabled, .ui-widget-header .ui-state-disabled { opacity: .35; filter:Alpha(Opacity=35); background-image: none; } + +/* Icons +----------------------------------*/ + +/* states and images */ +.ui-icon { width: 16px; height: 16px; background-image: url(images/ui-icons_222222_256x240.png); } +.ui-widget-content .ui-icon {background-image: url(images/ui-icons_222222_256x240.png); } +.ui-widget-header .ui-icon {background-image: url(images/ui-icons_222222_256x240.png); } +.ui-state-default .ui-icon { background-image: url(images/ui-icons_888888_256x240.png); } +.ui-state-hover .ui-icon, .ui-state-focus .ui-icon {background-image: url(images/ui-icons_454545_256x240.png); } +.ui-state-active .ui-icon {background-image: url(images/ui-icons_454545_256x240.png); } +.ui-state-highlight .ui-icon {background-image: url(images/ui-icons_2e83ff_256x240.png); } +.ui-state-error .ui-icon, .ui-state-error-text .ui-icon {background-image: url(images/ui-icons_cd0a0a_256x240.png); } + +/* positioning */ +.ui-icon-carat-1-n { background-position: 0 0; } +.ui-icon-carat-1-ne { background-position: -16px 0; } +.ui-icon-carat-1-e { background-position: -32px 0; } +.ui-icon-carat-1-se { background-position: -48px 0; } +.ui-icon-carat-1-s { background-position: -64px 0; } +.ui-icon-carat-1-sw { background-position: -80px 0; } +.ui-icon-carat-1-w { background-position: -96px 0; } +.ui-icon-carat-1-nw { background-position: -112px 0; } +.ui-icon-carat-2-n-s { background-position: -128px 0; } +.ui-icon-carat-2-e-w { background-position: -144px 0; } +.ui-icon-triangle-1-n { background-position: 0 -16px; } +.ui-icon-triangle-1-ne { background-position: -16px -16px; } +.ui-icon-triangle-1-e { background-position: -32px -16px; } +.ui-icon-triangle-1-se { background-position: -48px -16px; } +.ui-icon-triangle-1-s { background-position: -64px -16px; } +.ui-icon-triangle-1-sw { background-position: -80px -16px; } +.ui-icon-triangle-1-w { background-position: -96px -16px; } +.ui-icon-triangle-1-nw { background-position: -112px -16px; } +.ui-icon-triangle-2-n-s { background-position: -128px -16px; } +.ui-icon-triangle-2-e-w { background-position: -144px -16px; } +.ui-icon-arrow-1-n { background-position: 0 -32px; } +.ui-icon-arrow-1-ne { background-position: -16px -32px; } +.ui-icon-arrow-1-e { background-position: -32px -32px; } +.ui-icon-arrow-1-se { background-position: -48px -32px; } +.ui-icon-arrow-1-s { background-position: -64px -32px; } +.ui-icon-arrow-1-sw { background-position: -80px -32px; } +.ui-icon-arrow-1-w { background-position: -96px -32px; } +.ui-icon-arrow-1-nw { background-position: -112px -32px; } +.ui-icon-arrow-2-n-s { background-position: -128px -32px; } +.ui-icon-arrow-2-ne-sw { background-position: -144px -32px; } +.ui-icon-arrow-2-e-w { background-position: -160px -32px; } +.ui-icon-arrow-2-se-nw { background-position: -176px -32px; } +.ui-icon-arrowstop-1-n { background-position: -192px -32px; } +.ui-icon-arrowstop-1-e { background-position: -208px -32px; } +.ui-icon-arrowstop-1-s { background-position: -224px -32px; } +.ui-icon-arrowstop-1-w { background-position: -240px -32px; } +.ui-icon-arrowthick-1-n { background-position: 0 -48px; } +.ui-icon-arrowthick-1-ne { background-position: -16px -48px; } +.ui-icon-arrowthick-1-e { background-position: -32px -48px; } +.ui-icon-arrowthick-1-se { background-position: -48px -48px; } +.ui-icon-arrowthick-1-s { background-position: -64px -48px; } +.ui-icon-arrowthick-1-sw { background-position: -80px -48px; } +.ui-icon-arrowthick-1-w { background-position: -96px -48px; } +.ui-icon-arrowthick-1-nw { background-position: -112px -48px; } +.ui-icon-arrowthick-2-n-s { background-position: -128px -48px; } +.ui-icon-arrowthick-2-ne-sw { background-position: -144px -48px; } +.ui-icon-arrowthick-2-e-w { background-position: -160px -48px; } +.ui-icon-arrowthick-2-se-nw { background-position: -176px -48px; } +.ui-icon-arrowthickstop-1-n { background-position: -192px -48px; } +.ui-icon-arrowthickstop-1-e { background-position: -208px -48px; } +.ui-icon-arrowthickstop-1-s { background-position: -224px -48px; } +.ui-icon-arrowthickstop-1-w { background-position: -240px -48px; } +.ui-icon-arrowreturnthick-1-w { background-position: 0 -64px; } +.ui-icon-arrowreturnthick-1-n { background-position: -16px -64px; } +.ui-icon-arrowreturnthick-1-e { background-position: -32px -64px; } +.ui-icon-arrowreturnthick-1-s { background-position: -48px -64px; } +.ui-icon-arrowreturn-1-w { background-position: -64px -64px; } +.ui-icon-arrowreturn-1-n { background-position: -80px -64px; } +.ui-icon-arrowreturn-1-e { background-position: -96px -64px; } +.ui-icon-arrowreturn-1-s { background-position: -112px -64px; } +.ui-icon-arrowrefresh-1-w { background-position: -128px -64px; } +.ui-icon-arrowrefresh-1-n { background-position: -144px -64px; } +.ui-icon-arrowrefresh-1-e { background-position: -160px -64px; } +.ui-icon-arrowrefresh-1-s { background-position: -176px -64px; } +.ui-icon-arrow-4 { background-position: 0 -80px; } +.ui-icon-arrow-4-diag { background-position: -16px -80px; } +.ui-icon-extlink { background-position: -32px -80px; } +.ui-icon-newwin { background-position: -48px -80px; } +.ui-icon-refresh { background-position: -64px -80px; } +.ui-icon-shuffle { background-position: -80px -80px; } +.ui-icon-transfer-e-w { background-position: -96px -80px; } +.ui-icon-transferthick-e-w { background-position: -112px -80px; } +.ui-icon-folder-collapsed { background-position: 0 -96px; } +.ui-icon-folder-open { background-position: -16px -96px; } +.ui-icon-document { background-position: -32px -96px; } +.ui-icon-document-b { background-position: -48px -96px; } +.ui-icon-note { background-position: -64px -96px; } +.ui-icon-mail-closed { background-position: -80px -96px; } +.ui-icon-mail-open { background-position: -96px -96px; } +.ui-icon-suitcase { background-position: -112px -96px; } +.ui-icon-comment { background-position: -128px -96px; } +.ui-icon-person { background-position: -144px -96px; } +.ui-icon-print { background-position: -160px -96px; } +.ui-icon-trash { background-position: -176px -96px; } +.ui-icon-locked { background-position: -192px -96px; } +.ui-icon-unlocked { background-position: -208px -96px; } +.ui-icon-bookmark { background-position: -224px -96px; } +.ui-icon-tag { background-position: -240px -96px; } +.ui-icon-home { background-position: 0 -112px; } +.ui-icon-flag { background-position: -16px -112px; } +.ui-icon-calendar { background-position: -32px -112px; } +.ui-icon-cart { background-position: -48px -112px; } +.ui-icon-pencil { background-position: -64px -112px; } +.ui-icon-clock { background-position: -80px -112px; } +.ui-icon-disk { background-position: -96px -112px; } +.ui-icon-calculator { background-position: -112px -112px; } +.ui-icon-zoomin { background-position: -128px -112px; } +.ui-icon-zoomout { background-position: -144px -112px; } +.ui-icon-search { background-position: -160px -112px; } +.ui-icon-wrench { background-position: -176px -112px; } +.ui-icon-gear { background-position: -192px -112px; } +.ui-icon-heart { background-position: -208px -112px; } +.ui-icon-star { background-position: -224px -112px; } +.ui-icon-link { background-position: -240px -112px; } +.ui-icon-cancel { background-position: 0 -128px; } +.ui-icon-plus { background-position: -16px -128px; } +.ui-icon-plusthick { background-position: -32px -128px; } +.ui-icon-minus { background-position: -48px -128px; } +.ui-icon-minusthick { background-position: -64px -128px; } +.ui-icon-close { background-position: -80px -128px; } +.ui-icon-closethick { background-position: -96px -128px; } +.ui-icon-key { background-position: -112px -128px; } +.ui-icon-lightbulb { background-position: -128px -128px; } +.ui-icon-scissors { background-position: -144px -128px; } +.ui-icon-clipboard { background-position: -160px -128px; } +.ui-icon-copy { background-position: -176px -128px; } +.ui-icon-contact { background-position: -192px -128px; } +.ui-icon-image { background-position: -208px -128px; } +.ui-icon-video { background-position: -224px -128px; } +.ui-icon-script { background-position: -240px -128px; } +.ui-icon-alert { background-position: 0 -144px; } +.ui-icon-info { background-position: -16px -144px; } +.ui-icon-notice { background-position: -32px -144px; } +.ui-icon-help { background-position: -48px -144px; } +.ui-icon-check { background-position: -64px -144px; } +.ui-icon-bullet { background-position: -80px -144px; } +.ui-icon-radio-off { background-position: -96px -144px; } +.ui-icon-radio-on { background-position: -112px -144px; } +.ui-icon-pin-w { background-position: -128px -144px; } +.ui-icon-pin-s { background-position: -144px -144px; } +.ui-icon-play { background-position: 0 -160px; } +.ui-icon-pause { background-position: -16px -160px; } +.ui-icon-seek-next { background-position: -32px -160px; } +.ui-icon-seek-prev { background-position: -48px -160px; } +.ui-icon-seek-end { background-position: -64px -160px; } +.ui-icon-seek-start { background-position: -80px -160px; } +/* ui-icon-seek-first is deprecated, use ui-icon-seek-start instead */ +.ui-icon-seek-first { background-position: -80px -160px; } +.ui-icon-stop { background-position: -96px -160px; } +.ui-icon-eject { background-position: -112px -160px; } +.ui-icon-volume-off { background-position: -128px -160px; } +.ui-icon-volume-on { background-position: -144px -160px; } +.ui-icon-power { background-position: 0 -176px; } +.ui-icon-signal-diag { background-position: -16px -176px; } +.ui-icon-signal { background-position: -32px -176px; } +.ui-icon-battery-0 { background-position: -48px -176px; } +.ui-icon-battery-1 { background-position: -64px -176px; } +.ui-icon-battery-2 { background-position: -80px -176px; } +.ui-icon-battery-3 { background-position: -96px -176px; } +.ui-icon-circle-plus { background-position: 0 -192px; } +.ui-icon-circle-minus { background-position: -16px -192px; } +.ui-icon-circle-close { background-position: -32px -192px; } +.ui-icon-circle-triangle-e { background-position: -48px -192px; } +.ui-icon-circle-triangle-s { background-position: -64px -192px; } +.ui-icon-circle-triangle-w { background-position: -80px -192px; } +.ui-icon-circle-triangle-n { background-position: -96px -192px; } +.ui-icon-circle-arrow-e { background-position: -112px -192px; } +.ui-icon-circle-arrow-s { background-position: -128px -192px; } +.ui-icon-circle-arrow-w { background-position: -144px -192px; } +.ui-icon-circle-arrow-n { background-position: -160px -192px; } +.ui-icon-circle-zoomin { background-position: -176px -192px; } +.ui-icon-circle-zoomout { background-position: -192px -192px; } +.ui-icon-circle-check { background-position: -208px -192px; } +.ui-icon-circlesmall-plus { background-position: 0 -208px; } +.ui-icon-circlesmall-minus { background-position: -16px -208px; } +.ui-icon-circlesmall-close { background-position: -32px -208px; } +.ui-icon-squaresmall-plus { background-position: -48px -208px; } +.ui-icon-squaresmall-minus { background-position: -64px -208px; } +.ui-icon-squaresmall-close { background-position: -80px -208px; } +.ui-icon-grip-dotted-vertical { background-position: 0 -224px; } +.ui-icon-grip-dotted-horizontal { background-position: -16px -224px; } +.ui-icon-grip-solid-vertical { background-position: -32px -224px; } +.ui-icon-grip-solid-horizontal { background-position: -48px -224px; } +.ui-icon-gripsmall-diagonal-se { background-position: -64px -224px; } +.ui-icon-grip-diagonal-se { background-position: -80px -224px; } + + +/* Misc visuals +----------------------------------*/ + +/* Corner radius */ +.ui-corner-all, .ui-corner-top, .ui-corner-left, .ui-corner-tl { -moz-border-radius-topleft: 4px; -webkit-border-top-left-radius: 4px; -khtml-border-top-left-radius: 4px; border-top-left-radius: 4px; } +.ui-corner-all, .ui-corner-top, .ui-corner-right, .ui-corner-tr { -moz-border-radius-topright: 4px; -webkit-border-top-right-radius: 4px; -khtml-border-top-right-radius: 4px; border-top-right-radius: 4px; } +.ui-corner-all, .ui-corner-bottom, .ui-corner-left, .ui-corner-bl { -moz-border-radius-bottomleft: 4px; -webkit-border-bottom-left-radius: 4px; -khtml-border-bottom-left-radius: 4px; border-bottom-left-radius: 4px; } +.ui-corner-all, .ui-corner-bottom, .ui-corner-right, .ui-corner-br { -moz-border-radius-bottomright: 4px; -webkit-border-bottom-right-radius: 4px; -khtml-border-bottom-right-radius: 4px; border-bottom-right-radius: 4px; } + +/* Overlays */ +.ui-widget-overlay { background: #aaaaaa url(images/ui-bg_flat_0_aaaaaa_40x100.png) 50% 50% repeat-x; opacity: .30;filter:Alpha(Opacity=30); } +.ui-widget-shadow { margin: -8px 0 0 -8px; padding: 8px; background: #aaaaaa url(images/ui-bg_flat_0_aaaaaa_40x100.png) 50% 50% repeat-x; opacity: .30;filter:Alpha(Opacity=30); -moz-border-radius: 8px; -khtml-border-radius: 8px; -webkit-border-radius: 8px; border-radius: 8px; }/* + * jQuery UI Resizable 1.8.16 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Resizable#theming + */ +.ui-resizable { position: relative;} +.ui-resizable-handle { position: absolute;font-size: 0.1px;z-index: 99999; display: block; } +.ui-resizable-disabled .ui-resizable-handle, .ui-resizable-autohide .ui-resizable-handle { display: none; } +.ui-resizable-n { cursor: n-resize; height: 7px; width: 100%; top: -5px; left: 0; } +.ui-resizable-s { cursor: s-resize; height: 7px; width: 100%; bottom: -5px; left: 0; } +.ui-resizable-e { cursor: e-resize; width: 7px; right: -5px; top: 0; height: 100%; } +.ui-resizable-w { cursor: w-resize; width: 7px; left: -5px; top: 0; height: 100%; } +.ui-resizable-se { cursor: se-resize; width: 12px; height: 12px; right: 1px; bottom: 1px; } +.ui-resizable-sw { cursor: sw-resize; width: 9px; height: 9px; left: -5px; bottom: -5px; } +.ui-resizable-nw { cursor: nw-resize; width: 9px; height: 9px; left: -5px; top: -5px; } +.ui-resizable-ne { cursor: ne-resize; width: 9px; height: 9px; right: -5px; top: -5px;}/* + * jQuery UI Selectable 1.8.16 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Selectable#theming + */ +.ui-selectable-helper { position: absolute; z-index: 100; border:1px dotted black; } +/* + * jQuery UI Accordion 1.8.16 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Accordion#theming + */ +/* IE/Win - Fix animation bug - #4615 */ +.ui-accordion { width: 100%; } +.ui-accordion .ui-accordion-header { cursor: pointer; position: relative; margin-top: 1px; zoom: 1; } +.ui-accordion .ui-accordion-li-fix { display: inline; } +.ui-accordion .ui-accordion-header-active { border-bottom: 0 !important; } +.ui-accordion .ui-accordion-header a { display: block; font-size: 1em; padding: .5em .5em .5em .7em; } +.ui-accordion-icons .ui-accordion-header a { padding-left: 2.2em; } +.ui-accordion .ui-accordion-header .ui-icon { position: absolute; left: .5em; top: 50%; margin-top: -8px; } +.ui-accordion .ui-accordion-content { padding: 1em 2.2em; border-top: 0; margin-top: -2px; position: relative; top: 1px; margin-bottom: 2px; overflow: auto; display: none; zoom: 1; } +.ui-accordion .ui-accordion-content-active { display: block; } +/* + * jQuery UI Autocomplete 1.8.16 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Autocomplete#theming + */ +.ui-autocomplete { position: absolute; cursor: default; } + +/* workarounds */ +* html .ui-autocomplete { width:1px; } /* without this, the menu expands to 100% in IE6 */ + +/* + * jQuery UI Menu 1.8.16 + * + * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Menu#theming + */ +.ui-menu { + list-style:none; + padding: 2px; + margin: 0; + display:block; + float: left; +} +.ui-menu .ui-menu { + margin-top: -3px; +} +.ui-menu .ui-menu-item { + margin:0; + padding: 0; + zoom: 1; + float: left; + clear: left; + width: 100%; +} +.ui-menu .ui-menu-item a { + text-decoration:none; + display:block; + padding:.2em .4em; + line-height:1.5; + zoom:1; +} +.ui-menu .ui-menu-item a.ui-state-hover, +.ui-menu .ui-menu-item a.ui-state-active { + font-weight: normal; + margin: -1px; +} +/* + * jQuery UI Button 1.8.16 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Button#theming + */ +.ui-button { display: inline-block; position: relative; padding: 0; margin-right: .1em; text-decoration: none !important; cursor: pointer; text-align: center; zoom: 1; overflow: visible; } /* the overflow property removes extra width in IE */ +.ui-button-icon-only { width: 2.2em; } /* to make room for the icon, a width needs to be set here */ +button.ui-button-icon-only { width: 2.4em; } /* button elements seem to need a little more width */ +.ui-button-icons-only { width: 3.4em; } +button.ui-button-icons-only { width: 3.7em; } + +/*button text element */ +.ui-button .ui-button-text { display: block; line-height: 1.4; } +.ui-button-text-only .ui-button-text { padding: .4em 1em; } +.ui-button-icon-only .ui-button-text, .ui-button-icons-only .ui-button-text { padding: .4em; text-indent: -9999999px; } +.ui-button-text-icon-primary .ui-button-text, .ui-button-text-icons .ui-button-text { padding: .4em 1em .4em 2.1em; } +.ui-button-text-icon-secondary .ui-button-text, .ui-button-text-icons .ui-button-text { padding: .4em 2.1em .4em 1em; } +.ui-button-text-icons .ui-button-text { padding-left: 2.1em; padding-right: 2.1em; } +/* no icon support for input elements, provide padding by default */ +input.ui-button { padding: .4em 1em; } + +/*button icon element(s) */ +.ui-button-icon-only .ui-icon, .ui-button-text-icon-primary .ui-icon, .ui-button-text-icon-secondary .ui-icon, .ui-button-text-icons .ui-icon, .ui-button-icons-only .ui-icon { position: absolute; top: 50%; margin-top: -8px; } +.ui-button-icon-only .ui-icon { left: 50%; margin-left: -8px; } +.ui-button-text-icon-primary .ui-button-icon-primary, .ui-button-text-icons .ui-button-icon-primary, .ui-button-icons-only .ui-button-icon-primary { left: .5em; } +.ui-button-text-icon-secondary .ui-button-icon-secondary, .ui-button-text-icons .ui-button-icon-secondary, .ui-button-icons-only .ui-button-icon-secondary { right: .5em; } +.ui-button-text-icons .ui-button-icon-secondary, .ui-button-icons-only .ui-button-icon-secondary { right: .5em; } + +/*button sets*/ +.ui-buttonset { margin-right: 7px; } +.ui-buttonset .ui-button { margin-left: 0; margin-right: -.3em; } + +/* workarounds */ +button.ui-button::-moz-focus-inner { border: 0; padding: 0; } /* reset extra padding in Firefox */ +/* + * jQuery UI Dialog 1.8.16 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Dialog#theming + */ +.ui-dialog { position: absolute; padding: .2em; width: 300px; overflow: hidden; } +.ui-dialog .ui-dialog-titlebar { padding: .4em 1em; position: relative; } +.ui-dialog .ui-dialog-title { float: left; margin: .1em 16px .1em 0; } +.ui-dialog .ui-dialog-titlebar-close { position: absolute; right: .3em; top: 50%; width: 19px; margin: -10px 0 0 0; padding: 1px; height: 18px; } +.ui-dialog .ui-dialog-titlebar-close span { display: block; margin: 1px; } +.ui-dialog .ui-dialog-titlebar-close:hover, .ui-dialog .ui-dialog-titlebar-close:focus { padding: 0; } +.ui-dialog .ui-dialog-content { position: relative; border: 0; padding: .5em 1em; background: none; overflow: auto; zoom: 1; } +.ui-dialog .ui-dialog-buttonpane { text-align: left; border-width: 1px 0 0 0; background-image: none; margin: .5em 0 0 0; padding: .3em 1em .5em .4em; } +.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset { float: right; } +.ui-dialog .ui-dialog-buttonpane button { margin: .5em .4em .5em 0; cursor: pointer; } +.ui-dialog .ui-resizable-se { width: 14px; height: 14px; right: 3px; bottom: 3px; } +.ui-draggable .ui-dialog-titlebar { cursor: move; } +/* + * jQuery UI Slider 1.8.16 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Slider#theming + */ +.ui-slider { position: relative; text-align: left; } +.ui-slider .ui-slider-handle { position: absolute; z-index: 2; width: 1.2em; height: 1.2em; cursor: default; } +.ui-slider .ui-slider-range { position: absolute; z-index: 1; font-size: .7em; display: block; border: 0; background-position: 0 0; } + +.ui-slider-horizontal { height: .8em; } +.ui-slider-horizontal .ui-slider-handle { top: -.3em; margin-left: -.6em; } +.ui-slider-horizontal .ui-slider-range { top: 0; height: 100%; } +.ui-slider-horizontal .ui-slider-range-min { left: 0; } +.ui-slider-horizontal .ui-slider-range-max { right: 0; } + +.ui-slider-vertical { width: .8em; height: 100px; } +.ui-slider-vertical .ui-slider-handle { left: -.3em; margin-left: 0; margin-bottom: -.6em; } +.ui-slider-vertical .ui-slider-range { left: 0; width: 100%; } +.ui-slider-vertical .ui-slider-range-min { bottom: 0; } +.ui-slider-vertical .ui-slider-range-max { top: 0; }/* + * jQuery UI Tabs 1.8.16 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Tabs#theming + */ +.ui-tabs { position: relative; padding: .2em; zoom: 1; } /* position: relative prevents IE scroll bug (element with position: relative inside container with overflow: auto appear as "fixed") */ +.ui-tabs .ui-tabs-nav { margin: 0; padding: .2em .2em 0; } +.ui-tabs .ui-tabs-nav li { list-style: none; float: left; position: relative; top: 1px; margin: 0 .2em 1px 0; border-bottom: 0 !important; padding: 0; white-space: nowrap; } +.ui-tabs .ui-tabs-nav li a { float: left; padding: .5em 1em; text-decoration: none; } +.ui-tabs .ui-tabs-nav li.ui-tabs-selected { margin-bottom: 0; padding-bottom: 1px; } +.ui-tabs .ui-tabs-nav li.ui-tabs-selected a, .ui-tabs .ui-tabs-nav li.ui-state-disabled a, .ui-tabs .ui-tabs-nav li.ui-state-processing a { cursor: text; } +.ui-tabs .ui-tabs-nav li a, .ui-tabs.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-selected a { cursor: pointer; } /* first selector in group seems obsolete, but required to overcome bug in Opera applying cursor: text overall if defined elsewhere... */ +.ui-tabs .ui-tabs-panel { display: block; border-width: 0; padding: 1em 1.4em; background: none; } +.ui-tabs .ui-tabs-hide { display: none !important; } +/* + * jQuery UI Datepicker 1.8.16 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Datepicker#theming + */ +.ui-datepicker { width: 17em; padding: .2em .2em 0; display: none; } +.ui-datepicker .ui-datepicker-header { position:relative; padding:.2em 0; } +.ui-datepicker .ui-datepicker-prev, .ui-datepicker .ui-datepicker-next { position:absolute; top: 2px; width: 1.8em; height: 1.8em; } +.ui-datepicker .ui-datepicker-prev-hover, .ui-datepicker .ui-datepicker-next-hover { top: 1px; } +.ui-datepicker .ui-datepicker-prev { left:2px; } +.ui-datepicker .ui-datepicker-next { right:2px; } +.ui-datepicker .ui-datepicker-prev-hover { left:1px; } +.ui-datepicker .ui-datepicker-next-hover { right:1px; } +.ui-datepicker .ui-datepicker-prev span, .ui-datepicker .ui-datepicker-next span { display: block; position: absolute; left: 50%; margin-left: -8px; top: 50%; margin-top: -8px; } +.ui-datepicker .ui-datepicker-title { margin: 0 2.3em; line-height: 1.8em; text-align: center; } +.ui-datepicker .ui-datepicker-title select { font-size:1em; margin:1px 0; } +.ui-datepicker select.ui-datepicker-month-year {width: 100%;} +.ui-datepicker select.ui-datepicker-month, +.ui-datepicker select.ui-datepicker-year { width: 49%;} +.ui-datepicker table {width: 100%; font-size: .9em; border-collapse: collapse; margin:0 0 .4em; } +.ui-datepicker th { padding: .7em .3em; text-align: center; font-weight: bold; border: 0; } +.ui-datepicker td { border: 0; padding: 1px; } +.ui-datepicker td span, .ui-datepicker td a { display: block; padding: .2em; text-align: right; text-decoration: none; } +.ui-datepicker .ui-datepicker-buttonpane { background-image: none; margin: .7em 0 0 0; padding:0 .2em; border-left: 0; border-right: 0; border-bottom: 0; } +.ui-datepicker .ui-datepicker-buttonpane button { float: right; margin: .5em .2em .4em; cursor: pointer; padding: .2em .6em .3em .6em; width:auto; overflow:visible; } +.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current { float:left; } + +/* with multiple calendars */ +.ui-datepicker.ui-datepicker-multi { width:auto; } +.ui-datepicker-multi .ui-datepicker-group { float:left; } +.ui-datepicker-multi .ui-datepicker-group table { width:95%; margin:0 auto .4em; } +.ui-datepicker-multi-2 .ui-datepicker-group { width:50%; } +.ui-datepicker-multi-3 .ui-datepicker-group { width:33.3%; } +.ui-datepicker-multi-4 .ui-datepicker-group { width:25%; } +.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header { border-left-width:0; } +.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header { border-left-width:0; } +.ui-datepicker-multi .ui-datepicker-buttonpane { clear:left; } +.ui-datepicker-row-break { clear:both; width:100%; font-size:0em; } + +/* RTL support */ +.ui-datepicker-rtl { direction: rtl; } +.ui-datepicker-rtl .ui-datepicker-prev { right: 2px; left: auto; } +.ui-datepicker-rtl .ui-datepicker-next { left: 2px; right: auto; } +.ui-datepicker-rtl .ui-datepicker-prev:hover { right: 1px; left: auto; } +.ui-datepicker-rtl .ui-datepicker-next:hover { left: 1px; right: auto; } +.ui-datepicker-rtl .ui-datepicker-buttonpane { clear:right; } +.ui-datepicker-rtl .ui-datepicker-buttonpane button { float: left; } +.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current { float:right; } +.ui-datepicker-rtl .ui-datepicker-group { float:right; } +.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header { border-right-width:0; border-left-width:1px; } +.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header { border-right-width:0; border-left-width:1px; } + +/* IE6 IFRAME FIX (taken from datepicker 1.5.3 */ +.ui-datepicker-cover { + display: none; /*sorry for IE5*/ + display/**/: block; /*sorry for IE5*/ + position: absolute; /*must have*/ + z-index: -1; /*must have*/ + filter: mask(); /*must have*/ + top: -4px; /*must have*/ + left: -4px; /*must have*/ + width: 200px; /*must have*/ + height: 200px; /*must have*/ +}/* + * jQuery UI Progressbar 1.8.16 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Progressbar#theming + */ +.ui-progressbar { height:2em; text-align: left; } +.ui-progressbar .ui-progressbar-value {margin: -1px; height:100%; } \ No newline at end of file diff --git a/mysite/mysite/site_media/css/tableless-form.css b/mysite/mysite/site_media/css/tableless-form.css new file mode 100755 index 0000000..7527116 --- /dev/null +++ b/mysite/mysite/site_media/css/tableless-form.css @@ -0,0 +1,34 @@ +.cssform p{ +width: 300px; +clear: left; +margin: 0; +padding: 5px 0 8px 0; +padding-left: 155px; /*width of left column containing the label elements*/ +border-top: 1px dashed gray; +height: 1%; +} + +.cssform label{ +font-weight: bold; +float: left; +margin-left: -155px; /*width of left column*/ +width: 150px; /*width of labels. Should be smaller than left column (155px) to create some right margin*/ +} + +.cssform input[type="text"]{ /*width of text boxes. IE6 does not understand this attribute*/ +width: 180px; +} + +.cssform textarea{ +width: 250px; +height: 150px; +} + +/*.threepxfix class below: +Targets IE6- ONLY. Adds 3 pixel indent for multi-line form contents. +to account for 3 pixel bug: http://www.positioniseverything.net/explorer/threepxtest.html +*/ + +* html .threepxfix{ +margin-left: 3px; +} diff --git a/mysite/mysite/site_media/css/tagbox.css b/mysite/mysite/site_media/css/tagbox.css new file mode 100755 index 0000000..48a1f2c --- /dev/null +++ b/mysite/mysite/site_media/css/tagbox.css @@ -0,0 +1,76 @@ +/* + TagBox table styles + written by TagBox http://www.tagbox.de +*/ +table { + border-collapse: collapse; + border: 1px solid #03476F; + font: normal 11px verdana, arial, helvetica, sans-serif; + color: #363636; + background: #92C428; + } +caption { + text-align: center; + font: bold 18px arial, helvetica, sans-serif; + background: transparent; + padding:6px 4px 8px 0px; + color: #03476F; + text-transform: uppercase; + } +td, th { + border: 1px dotted #03476F; + padding: .4em; + color: #363636; + } + +thead th, tfoot th { + font: bold 11px verdana, arial, helvetica, sans-serif; + border: 1px solid #03476F;; + text-align: left; + background: #4591AD; + color: #FFFFFF; + padding-top:3px; + } +tbody td a { + background: transparent; + text-decoration: none; + color: #363636; + } +tbody td a:hover { + background: #C2F64D; + color: #363636; + } +tbody th a { + font: normal 11px verdana, arial, helvetica, sans-serif; + background: transparent; + text-decoration: none; + font-weight:normal; + color: #363636; + } +tbody th a:hover { + background: transparent; + color: #363636; + } +tbody th, tbody td { + vertical-align: top; + text-align: left; + } +tfoot td { + border: 1px solid #03476F; + background: #4591AD; + padding-top:3px; + color: #FFFFFF; + } +.odd { + background: #AEE239; + } +tbody tr:hover { + background: #FFD800; + border: 1px solid #03476F; + color: #FFFFFF; + } +tbody tr:hover th, +tbody tr.odd:hover th { + background: #FFD800; + color: #FFFFFF; + } \ No newline at end of file diff --git a/mysite/mysite/site_media/css/urban_grey_side_menu.css b/mysite/mysite/site_media/css/urban_grey_side_menu.css new file mode 100755 index 0000000..70dd917 --- /dev/null +++ b/mysite/mysite/site_media/css/urban_grey_side_menu.css @@ -0,0 +1,50 @@ + diff --git a/mysite/mysite/site_media/datetimepicker_css.js b/mysite/mysite/site_media/datetimepicker_css.js new file mode 100644 index 0000000..95fa8d7 --- /dev/null +++ b/mysite/mysite/site_media/datetimepicker_css.js @@ -0,0 +1,1341 @@ +//Javasript name: My Date Time Picker +//Date created: 16-Nov-2003 23:19 +//Creator: TengYong Ng +//Website: http://www.rainforestnet.com +//Copyright (c) 2003 TengYong Ng +//FileName: DateTimePicker_css.js +//Version: 2.2.4 +// Note: Permission given to use and modify this script in ANY kind of applications if +// header lines are left unchanged. +//Permission is granted to redistribute and modify this javascript under a FreeBSD License. +//New Css style version added by Yvan Lavoie (Québec, Canada) 29-Jan-2009 +//Formatted for JSLint compatibility by Labsmedia.com (30-Dec-2010) + + +//Global variables + +var winCal; +var dtToday; +var Cal; +var MonthName; +var WeekDayName1; +var WeekDayName2; +var exDateTime;//Existing Date and Time +var selDate;//selected date. version 1.7 +var calSpanID = "calBorder"; // span ID +var domStyle = null; // span DOM object with style +var cnLeft = "0";//left coordinate of calendar span +var cnTop = "0";//top coordinate of calendar span +var xpos = 0; // mouse x position +var ypos = 0; // mouse y position +var calHeight = 0; // calendar height +var CalWidth = 208;// calendar width +var CellWidth = 30;// width of day cell. +var TimeMode = 24;// TimeMode value. 12 or 24 +var StartYear = 1940; //First Year in drop down year selection +var EndYear = 5; // The last year of pickable date. if current year is 2011, the last year that still picker will be 2016 (2011+5) +var CalPosOffsetX = -1; //X position offset relative to calendar icon, can be negative value +var CalPosOffsetY = 0; //Y position offset relative to calendar icon, can be negative value + +//Configurable parameters start +var SpanBorderColor = "#000000";//span border color +var SpanBgColor = "#FFFFFF"; //span background color +var MonthYearColor = "#cc0033"; //Font Color of Month and Year in Calendar header. +var WeekHeadColor = "#18861B"; //var WeekHeadColor="#18861B";//Background Color in Week header. +var SundayColor = "#C0F64F"; //var SundayColor="#C0F64F";//Background color of Sunday. +var SaturdayColor = "#C0F64F"; //Background color of Saturday. +var WeekDayColor = "#FFEDA6"; //Background color of weekdays. +var FontColor = "blue"; //color of font in Calendar day cell. +var TodayColor = "#ffbd35"; //var TodayColor="#FFFF33";//Background color of today. +var SelDateColor = "#8DD53C"; //var SelDateColor = "#8DD53C";//Backgrond color of selected date in textbox. +var YrSelColor = "#cc0033"; //color of font of Year selector. +var MthSelColor = "#cc0033"; //color of font of Month selector if "MonthSelector" is "arrow". +var HoverColor = "#E0FF38"; //color when mouse move over. +var DisableColor = "#999966"; //color of disabled cell. +var CalBgColor = "#ffffff"; //Background color of Calendar window. + +var WeekChar = 2;//number of character for week day. if 2 then Mo,Tu,We. if 3 then Mon,Tue,Wed. +var DateSeparator = "-";//Date Separator, you can change it to "-" if you want. +var ShowLongMonth = true;//Show long month name in Calendar header. example: "January". +var ShowMonthYear = true;//Show Month and Year in Calendar header. +var ThemeBg = "";//Background image of Calendar window. +var PrecedeZero = true;//Preceding zero [true|false] +var MondayFirstDay = true;//true:Use Monday as first day; false:Sunday as first day. [true|false] //added in version 1.7 +var UseImageFiles = true;//Use image files with "arrows" and "close" button +var imageFilesPath = "images2/"; +//Configurable parameters end + +//use the Month and Weekday in your preferred language. +var MonthName = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"]; +var WeekDayName1 = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]; +var WeekDayName2 = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"]; + + +//end Configurable parameters + +//end Global variable + + +// Calendar prototype +function Calendar(pDate, pCtrl) +{ + //Properties + this.Date = pDate.getDate();//selected date + this.Month = pDate.getMonth();//selected month number + this.Year = pDate.getFullYear();//selected year in 4 digits + this.Hours = pDate.getHours(); + + if (pDate.getMinutes() < 10) + { + this.Minutes = "0" + pDate.getMinutes(); + } + else + { + this.Minutes = pDate.getMinutes(); + } + + if (pDate.getSeconds() < 10) + { + this.Seconds = "0" + pDate.getSeconds(); + } + else + { + this.Seconds = pDate.getSeconds(); + } + this.MyWindow = winCal; + this.Ctrl = pCtrl; + this.Format = "ddMMyyyy"; + this.Separator = DateSeparator; + this.ShowTime = false; + this.Scroller = "DROPDOWN"; + if (pDate.getHours() < 12) + { + this.AMorPM = "AM"; + } + else + { + this.AMorPM = "PM"; + } + this.ShowSeconds = false; + this.EnableDateMode = "" +} + +Calendar.prototype.GetMonthIndex = function (shortMonthName) +{ + for (var i = 0; i < 12; i += 1) + { + if (MonthName[i].substring(0, 3).toUpperCase() === shortMonthName.toUpperCase()) + { + return i; + } + } +}; + +Calendar.prototype.IncYear = function () { + if (Cal.Year <= dtToday.getFullYear()+EndYear) + Cal.Year += 1; +}; + +Calendar.prototype.DecYear = function () { + if (Cal.Year > StartYear) + Cal.Year -= 1; +}; + +Calendar.prototype.IncMonth = function() { + if (Cal.Year <= dtToday.getFullYear() + EndYear) { + Cal.Month += 1; + if (Cal.Month >= 12) { + Cal.Month = 0; + Cal.IncYear(); + } + } +}; + +Calendar.prototype.DecMonth = function() { + if (Cal.Year >= StartYear) { + Cal.Month -= 1; + if (Cal.Month < 0) { + Cal.Month = 11; + Cal.DecYear(); + } + } +}; + +Calendar.prototype.SwitchMth = function (intMth) +{ + Cal.Month = parseInt(intMth, 10); +}; + +Calendar.prototype.SwitchYear = function (intYear) +{ + Cal.Year = parseInt(intYear, 10); +}; + +Calendar.prototype.SetHour = function(intHour) { + var MaxHour, + MinHour, + HourExp = new RegExp("^\\d\\d"), + SingleDigit = new RegExp("^\\d{1}$"); + + if (TimeMode === 24) { + MaxHour = 23; + MinHour = 0; + } + else if (TimeMode === 12) { + MaxHour = 12; + MinHour = 1; + } + else { + alert("TimeMode can only be 12 or 24"); + } + + if ((HourExp.test(intHour) || SingleDigit.test(intHour)) && (parseInt(intHour, 10) > MaxHour)) { + intHour = MinHour; + } + + else if ((HourExp.test(intHour) || SingleDigit.test(intHour)) && (parseInt(intHour, 10) < MinHour)) { + intHour = MaxHour; + } + + intHour = parseInt(intHour, 10); + if (SingleDigit.test(intHour)) { + intHour = "0" + intHour; + } + + if (HourExp.test(intHour) && (parseInt(intHour, 10) <= MaxHour) && (parseInt(intHour, 10) >= MinHour)) { + if ((TimeMode === 12) && (Cal.AMorPM === "PM")) { + if (parseInt(intHour, 10) === 12) { + Cal.Hours = 12; + } + else { + Cal.Hours = parseInt(intHour, 10) + 12; + } + } + + else if ((TimeMode === 12) && (Cal.AMorPM === "AM")) { + if (intHour === 12) { + intHour -= 12; + } + + Cal.Hours = parseInt(intHour, 10); + } + + else if (TimeMode === 24) { + Cal.Hours = parseInt(intHour, 10); + } + } + +}; + +Calendar.prototype.SetMinute = function (intMin) +{ + var MaxMin = 59, + MinMin = 0, + + SingleDigit = new RegExp("\\d"), + SingleDigit2 = new RegExp("^\\d{1}$"), + MinExp = new RegExp("^\\d{2}$"), + + strMin = 0; + + if ((MinExp.test(intMin) || SingleDigit.test(intMin)) && (parseInt(intMin, 10) > MaxMin)) + { + intMin = MinMin; + } + + else if ((MinExp.test(intMin) || SingleDigit.test(intMin)) && (parseInt(intMin, 10) < MinMin)) + { + intMin = MaxMin; + } + + strMin = intMin + ""; + if (SingleDigit2.test(intMin)) + { + strMin = "0" + strMin; + } + + if ((MinExp.test(intMin) || SingleDigit.test(intMin)) && (parseInt(intMin, 10) <= 59) && (parseInt(intMin, 10) >= 0)) + { + Cal.Minutes = strMin; + } +}; + +Calendar.prototype.SetSecond = function (intSec) +{ + var MaxSec = 59, + MinSec = 0, + + SingleDigit = new RegExp("\\d"), + SingleDigit2 = new RegExp("^\\d{1}$"), + SecExp = new RegExp("^\\d{2}$"), + + strSec = 0; + + if ((SecExp.test(intSec) || SingleDigit.test(intSec)) && (parseInt(intSec, 10) > MaxSec)) + { + intSec = MinSec; + } + + else if ((SecExp.test(intSec) || SingleDigit.test(intSec)) && (parseInt(intSec, 10) < MinSec)) + { + intSec = MaxSec; + } + + strSec = intSec + ""; + if (SingleDigit2.test(intSec)) + { + strSec = "0" + strSec; + } + + if ((SecExp.test(intSec) || SingleDigit.test(intSec)) && (parseInt(intSec, 10) <= 59) && (parseInt(intSec, 10) >= 0)) + { + Cal.Seconds = strSec; + } + +}; + +Calendar.prototype.SetAmPm = function (pvalue) +{ + this.AMorPM = pvalue; + if (pvalue === "PM") + { + this.Hours = parseInt(this.Hours, 10) + 12; + if (this.Hours === 24) + { + this.Hours = 12; + } + } + + else if (pvalue === "AM") + { + this.Hours -= 12; + } +}; + +Calendar.prototype.getShowHour = function() { + var finalHour; + + if (TimeMode === 12) { + if (parseInt(this.Hours, 10) === 0) { + this.AMorPM = "AM"; + finalHour = parseInt(this.Hours, 10) + 12; + } + + else if (parseInt(this.Hours, 10) === 12) { + this.AMorPM = "PM"; + finalHour = 12; + } + + else if (this.Hours > 12) { + this.AMorPM = "PM"; + if ((this.Hours - 12) < 10) { + finalHour = "0" + ((parseInt(this.Hours, 10)) - 12); + } + else { + finalHour = parseInt(this.Hours, 10) - 12; + } + } + else { + this.AMorPM = "AM"; + if (this.Hours < 10) { + finalHour = "0" + parseInt(this.Hours, 10); + } + else { + finalHour = this.Hours; + } + } + } + + else if (TimeMode === 24) { + if (this.Hours < 10) { + finalHour = "0" + parseInt(this.Hours, 10); + } + else { + finalHour = this.Hours; + } + } + + return finalHour; +}; + +Calendar.prototype.getShowAMorPM = function () +{ + return this.AMorPM; +}; + +Calendar.prototype.GetMonthName = function (IsLong) +{ + var Month = MonthName[this.Month]; + if (IsLong) + { + return Month; + } + else + { + return Month.substr(0, 3); + } +}; + +Calendar.prototype.GetMonDays = function() { //Get number of days in a month + + var DaysInMonth = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]; + if (Cal.IsLeapYear()) { + DaysInMonth[1] = 29; + } + + return DaysInMonth[this.Month]; +}; + +Calendar.prototype.IsLeapYear = function () +{ + if ((this.Year % 4) === 0) + { + if ((this.Year % 100 === 0) && (this.Year % 400) !== 0) + { + return false; + } + else + { + return true; + } + } + else + { + return false; + } +}; + +Calendar.prototype.FormatDate = function (pDate) +{ + var MonthDigit = this.Month + 1; + if (PrecedeZero === true) + { + if ((pDate < 10) && String(pDate).length===1) //length checking added in version 2.2 + { + pDate = "0" + pDate; + } + if (MonthDigit < 10) + { + MonthDigit = "0" + MonthDigit; + } + } + + switch (this.Format.toUpperCase()) + { + case "DDMMYYYY": + return (pDate + DateSeparator + MonthDigit + DateSeparator + this.Year); + case "DDMMMYYYY": + return (pDate + DateSeparator + this.GetMonthName(false) + DateSeparator + this.Year); + case "MMDDYYYY": + return (MonthDigit + DateSeparator + pDate + DateSeparator + this.Year); + case "MMMDDYYYY": + return (this.GetMonthName(false) + DateSeparator + pDate + DateSeparator + this.Year); + case "YYYYMMDD": + return (this.Year + DateSeparator + MonthDigit + DateSeparator + pDate); + case "YYMMDD": + return (String(this.Year).substring(2, 4) + DateSeparator + MonthDigit + DateSeparator + pDate); + case "YYMMMDD": + return (String(this.Year).substring(2, 4) + DateSeparator + this.GetMonthName(false) + DateSeparator + pDate); + case "YYYYMMMDD": + return (this.Year + DateSeparator + this.GetMonthName(false) + DateSeparator + pDate); + default: + return (pDate + DateSeparator + (this.Month + 1) + DateSeparator + this.Year); + } +}; + +// end Calendar prototype + +function GenCell(pValue, pHighLight, pColor, pClickable) +{ //Generate table cell with value + var PValue, + PCellStr, + PClickable, + vTimeStr; + + if (!pValue) + { + PValue = ""; + } + else + { + PValue = pValue; + } + + if (pColor === undefined) + pColor = CalBgColor; + + if (pClickable !== undefined){ + PClickable = pClickable; + } + else{ + PClickable = true; + } + + if (Cal.ShowTime) + { + vTimeStr = ' ' + Cal.Hours + ':' + Cal.Minutes; + if (Cal.ShowSeconds) + { + vTimeStr += ':' + Cal.Seconds; + } + if (TimeMode === 12) + { + vTimeStr += ' ' + Cal.AMorPM; + } + } + + else + { + vTimeStr = ""; + } + + if (PValue !== "") + { + if (PClickable === true) { + if (Cal.ShowTime === true) + { PCellStr = "" + PValue + ""; } + else { PCellStr = "" + PValue + ""; } + } + else + { PCellStr = ""+PValue+""; } + } + else + { PCellStr = " "; } + + return PCellStr; +} + +function RenderCssCal(bNewCal) +{ + if (typeof bNewCal === "undefined" || bNewCal !== true) + { + bNewCal = false; + } + var vCalHeader, + vCalData, + vCalTime = "", + vCalClosing = "", + winCalData = "", + CalDate, + + i, + j, + + SelectStr, + vDayCount = 0, + vFirstDay, + + WeekDayName = [],//Added version 1.7 + strCell, + + showHour, + ShowArrows = false, + HourCellWidth = "35px", //cell width with seconds. + + SelectAm, + SelectPm, + + funcCalback, + + headID, + e, + cssStr, + style, + cssText, + span; + + calHeight = 0; // reset the window height on refresh + + // Set the default cursor for the calendar + + winCalData = ""; + vCalHeader = ""; + + //Table for Month & Year Selector + + vCalHeader += ""; + + //******************End Month and Year selector in arrow****************************** + + //Calendar header shows Month and Year + if (ShowMonthYear && Cal.Scroller === "DROPDOWN") + { + vCalHeader += ""; + calHeight += 19; + } + + //Week day header + + vCalHeader += ""; + + + //Time picker + if (Cal.ShowTime === true) + { + showHour = Cal.getShowHour(); + + if (Cal.ShowSeconds === false && TimeMode === 24) + { + ShowArrows = true; + HourCellWidth = "10px"; + } + + vCalTime = ""; + calHeight += 31; + vCalClosing += "
"; + //******************Month and Year selector in dropdown list************************ + + if (Cal.Scroller === "DROPDOWN") + { + vCalHeader += ""; + //Year selector + + vCalHeader += "\n"; + calHeight += 30; + } + + //******************End Month and Year selector in dropdown list********************* + + //******************Month and Year selector in arrow********************************* + + else if (Cal.Scroller === "ARROW") + { + if (UseImageFiles) + { + vCalHeader += "\n";//Year scroller (decrease 1 year) + vCalHeader += "\n"; //Month scroller (decrease 1 month) + vCalHeader += ""; //Month and Year + vCalHeader += "\n"; //Month scroller (increase 1 month) + vCalHeader += "\n"; //Year scroller (increase 1 year) + calHeight += 22; + } + else + { + vCalHeader += "";//Year scroller (decrease 1 year) + vCalHeader += "\n";//Month scroller (decrease 1 month) + vCalHeader += "\n"; //Month and Year + vCalHeader += "\n";//Month scroller (increase 1 month) + vCalHeader += "\n";//Year scroller (increase 1 year) + calHeight += 22; + } + } + + vCalHeader += "
"+ Cal.GetMonthName(ShowLongMonth) + " " + Cal.Year + "-<" + Cal.GetMonthName(ShowLongMonth) + " " + Cal.Year + ">+
" + Cal.GetMonthName(ShowLongMonth) + " " + Cal.Year + "
"; + if (MondayFirstDay === true) + { + WeekDayName = WeekDayName2; + } + else + { + WeekDayName = WeekDayName1; + } + for (i = 0; i < 7; i += 1) + { + vCalHeader += ""; + } + + calHeight += 19; + vCalHeader += ""; + //Calendar detail + CalDate = new Date(Cal.Year, Cal.Month); + CalDate.setDate(1); + + vFirstDay = CalDate.getDay(); + + //Added version 1.7 + if (MondayFirstDay === true) + { + vFirstDay -= 1; + if (vFirstDay === -1) + { + vFirstDay = 6; + } + } + + //Added version 1.7 + vCalData = ""; + calHeight += 19; + for (i = 0; i < vFirstDay; i += 1) + { + vCalData = vCalData + GenCell(); + vDayCount = vDayCount + 1; + } + + //Added version 1.7 + for (j = 1; j <= Cal.GetMonDays(); j += 1) + { + if ((vDayCount % 7 === 0) && (j > 1)) + { + vCalData = vCalData + ""; + } + + vDayCount = vDayCount + 1; + //added version 2.1.2 + if (Cal.EnableDateMode === "future" && ((j < dtToday.getDate()) && (Cal.Month === dtToday.getMonth()) && (Cal.Year === dtToday.getFullYear()) || (Cal.Month < dtToday.getMonth()) && (Cal.Year === dtToday.getFullYear()) || (Cal.Year < dtToday.getFullYear()))) + { + strCell = GenCell(j, false, DisableColor, false); //Before today's date is not clickable + } + else if (Cal.EnableDateMode === "past" && ((j >= dtToday.getDate()) && (Cal.Month === dtToday.getMonth()) && (Cal.Year === dtToday.getFullYear()) || (Cal.Month > dtToday.getMonth()) && (Cal.Year === dtToday.getFullYear()) || (Cal.Year > dtToday.getFullYear()))) { + strCell = GenCell(j, false, DisableColor, false); //After today's date is not clickable + } + //if End Year + Current Year = Cal.Year. Disable. + else if (Cal.Year > (dtToday.getFullYear()+EndYear)) + { + strCell = GenCell(j, false, DisableColor, false); + } + else if ((j === dtToday.getDate()) && (Cal.Month === dtToday.getMonth()) && (Cal.Year === dtToday.getFullYear())) + { + strCell = GenCell(j, true, TodayColor);//Highlight today's date + } + else + { + if ((j === selDate.getDate()) && (Cal.Month === selDate.getMonth()) && (Cal.Year === selDate.getFullYear())){ + //modified version 1.7 + strCell = GenCell(j, true, SelDateColor); + } + else + { + if (MondayFirstDay === true) + { + if (vDayCount % 7 === 0) + { + strCell = GenCell(j, false, SundayColor); + } + else if ((vDayCount + 1) % 7 === 0) + { + strCell = GenCell(j, false, SaturdayColor); + } + else + { + strCell = GenCell(j, null, WeekDayColor); + } + } + else + { + if (vDayCount % 7 === 0) + { + strCell = GenCell(j, false, SaturdayColor); + } + else if ((vDayCount + 6) % 7 === 0) + { + strCell = GenCell(j, false, SundayColor); + } + else + { + strCell = GenCell(j, null, WeekDayColor); + } + } + } + } + + vCalData = vCalData + strCell; + + if ((vDayCount % 7 === 0) && (j < Cal.GetMonDays())) + { + vCalData = vCalData + ""; + calHeight += 19; + } + } + + // finish the table proper + + if (vDayCount % 7 !== 0) + { + while (vDayCount % 7 !== 0) + { + vCalData = vCalData + GenCell(); + vDayCount = vDayCount + 1; + } + } + + vCalData = vCalData + "
" + WeekDayName[i].substr(0, WeekChar) + "
"; + + if (ShowArrows && UseImageFiles) //this is where the up and down arrow control the hour. + { + vCalTime += "\n"; + } + + vCalTime += "\n\n"; + vCalTime += ""; + } + else //if not to show time. + { + vCalTime += "\n\n"; + } + else { + vCalClosing += "x"; + } + vCalClosing += ""; + } + vCalClosing += "
 
"; + vCalTime += ":"; + vCalTime += ""; + + if (Cal.ShowSeconds) + { + vCalTime += ":"; + vCalTime += ""; + } + + if (TimeMode === 12) + { + SelectAm = (Cal.AMorPM === "AM") ? "Selected" : ""; + SelectPm = (Cal.AMorPM === "PM") ? "Selected" : ""; + + vCalTime += ""; + vCalTime += ""; + } + + if (ShowArrows && UseImageFiles) //this is where the up and down arrow to change the "Minute". + { + vCalTime += "
"; + } + + vCalTime += "
 
"; + //close button + if (UseImageFiles) { + vCalClosing += "
\n
"; + + //end time picker + funcCalback = "function callback(id, datum) {"; + funcCalback += " var CalId = document.getElementById(id);if (datum=== 'undefined') { var d = new Date(); datum = d.getDate() + '/' +(d.getMonth()+1) + '/' + d.getFullYear(); } window.calDatum=datum;CalId.value=datum;"; + funcCalback += " if(Cal.ShowTime){"; + funcCalback += " CalId.value+=' '+Cal.getShowHour()+':'+Cal.Minutes;"; + funcCalback += " if (Cal.ShowSeconds) CalId.value+=':'+Cal.Seconds;"; + funcCalback += " if (TimeMode === 12) CalId.value+=''+Cal.getShowAMorPM();"; + funcCalback += "}if(CalId.onchange!=undefined) CalId.onchange();CalId.focus();winCal.style.visibility='hidden';}"; + + + // determines if there is enough space to open the cal above the position where it is called + if (ypos > calHeight) + { + ypos = ypos - calHeight; + } + + if (!winCal) + { + headID = document.getElementsByTagName("head")[0]; + + // add javascript function to the span cal + e = document.createElement("script"); + e.type = "text/javascript"; + e.language = "javascript"; + e.text = funcCalback; + headID.appendChild(e); + // add stylesheet to the span cal + + cssStr = ".calTD {font-family: verdana; font-size: 12px; text-align: center; border:0; }\n"; + cssStr += ".calR {font-family: verdana; font-size: 12px; text-align: center; font-weight: bold;}"; + + style = document.createElement("style"); + style.type = "text/css"; + style.rel = "stylesheet"; + if (style.styleSheet) + { // IE + style.styleSheet.cssText = cssStr; + } + + else + { // w3c + cssText = document.createTextNode(cssStr); + style.appendChild(cssText); + } + + headID.appendChild(style); + // create the outer frame that allows the cal. to be moved + span = document.createElement("span"); + span.id = calSpanID; + span.style.position = "absolute"; + span.style.left = (xpos + CalPosOffsetX) + 'px'; + span.style.top = (ypos - CalPosOffsetY) + 'px'; + span.style.width = CalWidth + 'px'; + span.style.border = "solid 1pt " + SpanBorderColor; + span.style.padding = "0"; + span.style.cursor = "move"; + span.style.backgroundColor = SpanBgColor; + span.style.zIndex = 100; + document.body.appendChild(span); + winCal = document.getElementById(calSpanID); + } + + else + { + winCal.style.visibility = "visible"; + winCal.style.Height = calHeight; + + // set the position for a new calendar only + if (bNewCal === true) + { + winCal.style.left = (xpos + CalPosOffsetX) + 'px'; + winCal.style.top = (ypos - CalPosOffsetY) + 'px'; + } + } + + winCal.innerHTML = winCalData + vCalHeader + vCalData + vCalTime + vCalClosing; + return true; +} + + +function NewCssCal(pCtrl, pFormat, pScroller, pShowTime, pTimeMode, pShowSeconds, pEnableDateMode) +{ + // get current date and time + + dtToday = new Date(); + Cal = new Calendar(dtToday); + + if (pShowTime !== undefined) + { + if (pShowTime) { + Cal.ShowTime = true; + } + else { + Cal.ShowTime = false; + } + + if (pTimeMode) + { + pTimeMode = parseInt(pTimeMode, 10); + } + if (pTimeMode === 12 || pTimeMode === 24) + { + TimeMode = pTimeMode; + } + else + { + TimeMode = 24; + } + + if (pShowSeconds !== undefined) + { + if (pShowSeconds) + { + Cal.ShowSeconds = true; + } + else + { + Cal.ShowSeconds = false; + } + } + else + { + Cal.ShowSeconds = false; + } + + } + + if (pCtrl !== undefined) + { + Cal.Ctrl = pCtrl; + } + + if (pFormat!== undefined && pFormat !=="") + { + Cal.Format = pFormat.toUpperCase(); + } + else + { + Cal.Format = "MMDDYYYY"; + } + + if (pScroller!== undefined && pScroller!=="") + { + if (pScroller.toUpperCase() === "ARROW") + { + Cal.Scroller = "ARROW"; + } + else + { + Cal.Scroller = "DROPDOWN"; + } + } + + if (pEnableDateMode !== undefined && (pEnableDateMode === "future" || pEnableDateMode === "past")) { + Cal.EnableDateMode= pEnableDateMode; + } + + exDateTime = document.getElementById(pCtrl).value; //Existing Date Time value in textbox. + + if (exDateTime) + { //Parse existing Date String + var Sp1 = exDateTime.indexOf(DateSeparator, 0),//Index of Date Separator 1 + Sp2 = exDateTime.indexOf(DateSeparator, parseInt(Sp1, 10) + 1),//Index of Date Separator 2 + tSp1,//Index of Time Separator 1 + tSp2,//Index of Time Separator 2 + strMonth, + strDate, + strYear, + intMonth, + YearPattern, + strHour, + strMinute, + strSecond, + winHeight, + offset = parseInt(Cal.Format.toUpperCase().lastIndexOf("M"), 10) - parseInt(Cal.Format.toUpperCase().indexOf("M"), 10) - 1, + strAMPM = ""; + //parse month + + if (Cal.Format.toUpperCase() === "DDMMYYYY" || Cal.Format.toUpperCase() === "DDMMMYYYY") + { + if (DateSeparator === "") + { + strMonth = exDateTime.substring(2, 4 + offset); + strDate = exDateTime.substring(0, 2); + strYear = exDateTime.substring(4 + offset, 8 + offset); + } + else + { + if (exDateTime.indexOf("D*") !== -1) + { //DTG + strMonth = exDateTime.substring(8, 11); + strDate = exDateTime.substring(0, 2); + strYear = "20" + exDateTime.substring(11, 13); //Hack, nur für Jahreszahlen ab 2000 + } + else + { + strMonth = exDateTime.substring(Sp1 + 1, Sp2); + strDate = exDateTime.substring(0, Sp1); + strYear = exDateTime.substring(Sp2 + 1, Sp2 + 5); + } + } + } + + else if (Cal.Format.toUpperCase() === "MMDDYYYY" || Cal.Format.toUpperCase() === "MMMDDYYYY"){ + if (DateSeparator === ""){ + strMonth = exDateTime.substring(0, 2 + offset); + strDate = exDateTime.substring(2 + offset, 4 + offset); + strYear = exDateTime.substring(4 + offset, 8 + offset); + } + else{ + strMonth = exDateTime.substring(0, Sp1); + strDate = exDateTime.substring(Sp1 + 1, Sp2); + strYear = exDateTime.substring(Sp2 + 1, Sp2 + 5); + } + } + + else if (Cal.Format.toUpperCase() === "YYYYMMDD" || Cal.Format.toUpperCase() === "YYYYMMMDD") + { + if (DateSeparator === ""){ + strMonth = exDateTime.substring(4, 6 + offset); + strDate = exDateTime.substring(6 + offset, 8 + offset); + strYear = exDateTime.substring(0, 4); + } + else{ + strMonth = exDateTime.substring(Sp1 + 1, Sp2); + strDate = exDateTime.substring(Sp2 + 1, Sp2 + 3); + strYear = exDateTime.substring(0, Sp1); + } + } + + else if (Cal.Format.toUpperCase() === "YYMMDD" || Cal.Format.toUpperCase() === "YYMMMDD") + { + if (DateSeparator === "") + { + strMonth = exDateTime.substring(2, 4 + offset); + strDate = exDateTime.substring(4 + offset, 6 + offset); + strYear = exDateTime.substring(0, 2); + } + else + { + strMonth = exDateTime.substring(Sp1 + 1, Sp2); + strDate = exDateTime.substring(Sp2 + 1, Sp2 + 3); + strYear = exDateTime.substring(0, Sp1); + } + } + + if (isNaN(strMonth)){ + intMonth = Cal.GetMonthIndex(strMonth); + } + else{ + intMonth = parseInt(strMonth, 10) - 1; + } + if ((parseInt(intMonth, 10) >= 0) && (parseInt(intMonth, 10) < 12)) { + Cal.Month = intMonth; + } + //end parse month + + //parse year + YearPattern = /^\d{4}$/; + if (YearPattern.test(strYear)) { + if ((parseInt(strYear, 10)>=StartYear) && (parseInt(strYear, 10)<= (dtToday.getFullYear()+EndYear))) + Cal.Year = parseInt(strYear, 10); + } + //end parse year + + //parse Date + if ((parseInt(strDate, 10) <= Cal.GetMonDays()) && (parseInt(strDate, 10) >= 1)) { + Cal.Date = strDate; + } + //end parse Date + + //parse time + + if (Cal.ShowTime === true) + { + //parse AM or PM + if (TimeMode === 12) + { + strAMPM = exDateTime.substring(exDateTime.length - 2, exDateTime.length); + Cal.AMorPM = strAMPM; + } + + tSp1 = exDateTime.indexOf(":", 0); + tSp2 = exDateTime.indexOf(":", (parseInt(tSp1, 10) + 1)); + if (tSp1 > 0) + { + strHour = exDateTime.substring(tSp1, tSp1 - 2); + Cal.SetHour(strHour); + + strMinute = exDateTime.substring(tSp1 + 1, tSp1 + 3); + Cal.SetMinute(strMinute); + + strSecond = exDateTime.substring(tSp2 + 1, tSp2 + 3); + Cal.SetSecond(strSecond); + + } + else if (exDateTime.indexOf("D*") !== -1) + { //DTG + strHour = exDateTime.substring(2, 4); + Cal.SetHour(strHour); + strMinute = exDateTime.substring(4, 6); + Cal.SetMinute(strMinute); + + } + } + + } + selDate = new Date(Cal.Year, Cal.Month, Cal.Date);//version 1.7 + RenderCssCal(true); +} + +function closewin(id) { + if (Cal.ShowTime === true) { + var MaxYear = dtToday.getFullYear() + EndYear; + var beforeToday = + (Cal.Date < dtToday.getDate()) && + (Cal.Month === dtToday.getMonth()) && + (Cal.Year === dtToday.getFullYear()) + || + (Cal.Month < dtToday.getMonth()) && + (Cal.Year === dtToday.getFullYear()) + || + (Cal.Year < dtToday.getFullYear()); + + if ((Cal.Year <= MaxYear) && (Cal.Year >= StartYear) && (Cal.Month === selDate.getMonth()) && (Cal.Year === selDate.getFullYear())) { + if (Cal.EnableDateMode === "future") { + if (beforeToday === false) { + callback(id, Cal.FormatDate(Cal.Date)); + } + } + else + callback(id, Cal.FormatDate(Cal.Date)); + } + } + + var CalId = document.getElementById(id); + CalId.focus(); + winCal.style.visibility = 'hidden'; +} + +function changeBorder(element, col, oldBgColor) +{ + if (col === 0) + { + element.style.background = HoverColor; + element.style.borderColor = "black"; + element.style.cursor = "pointer"; + } + + else + { + if (oldBgColor) + { + element.style.background = oldBgColor; + } + else + { + element.style.background = "white"; + } + element.style.borderColor = "white"; + element.style.cursor = "auto"; + } +} + +function selectDate(element, date) { + Cal.Date = date; + selDate = new Date(Cal.Year, Cal.Month, Cal.Date); + element.style.background = SelDateColor; + RenderCssCal(); +} + +function pickIt(evt) +{ + var objectID, + dom, + de, + b; + // accesses the element that generates the event and retrieves its ID + if (document.addEventListener) + { // w3c + objectID = evt.target.id; + if (objectID.indexOf(calSpanID) !== -1) + { + dom = document.getElementById(objectID); + cnLeft = evt.pageX; + cnTop = evt.pageY; + + if (dom.offsetLeft) + { + cnLeft = (cnLeft - dom.offsetLeft); + cnTop = (cnTop - dom.offsetTop); + } + } + + // get mouse position on click + xpos = (evt.pageX); + ypos = (evt.pageY); + } + + else + { // IE + objectID = event.srcElement.id; + cnLeft = event.offsetX; + cnTop = (event.offsetY); + + // get mouse position on click + de = document.documentElement; + b = document.body; + + xpos = event.clientX + (de.scrollLeft || b.scrollLeft) - (de.clientLeft || 0); + ypos = event.clientY + (de.scrollTop || b.scrollTop) - (de.clientTop || 0); + } + + // verify if this is a valid element to pick + if (objectID.indexOf(calSpanID) !== -1) + { + domStyle = document.getElementById(objectID).style; + } + + if (domStyle) + { + domStyle.zIndex = 100; + return false; + } + + else + { + domStyle = null; + return; + } +} + + + +function dragIt(evt) +{ + if (domStyle) + { + if (document.addEventListener) + { //for IE + domStyle.left = (event.clientX - cnLeft + document.body.scrollLeft) + 'px'; + domStyle.top = (event.clientY - cnTop + document.body.scrollTop) + 'px'; + } + else + { //Firefox + domStyle.left = (evt.clientX - cnLeft + document.body.scrollLeft) + 'px'; + domStyle.top = (evt.clientY - cnTop + document.body.scrollTop) + 'px'; + } + } +} + +// performs a single increment or decrement +function nextStep(whatSpinner, direction) +{ + if (whatSpinner === "Hour") + { + if (direction === "plus") + { + Cal.SetHour(Cal.Hours + 1); + RenderCssCal(); + } + else if (direction === "minus") + { + Cal.SetHour(Cal.Hours - 1); + RenderCssCal(); + } + } + else if (whatSpinner === "Minute") + { + if (direction === "plus") + { + Cal.SetMinute(parseInt(Cal.Minutes, 10) + 1); + RenderCssCal(); + } + else if (direction === "minus") + { + Cal.SetMinute(parseInt(Cal.Minutes, 10) - 1); + RenderCssCal(); + } + } + +} + +// starts the time spinner +function startSpin(whatSpinner, direction) +{ + document.thisLoop = setInterval(function () + { + nextStep(whatSpinner, direction); + }, 125); //125 ms +} + +//stops the time spinner +function stopSpin() +{ + clearInterval(document.thisLoop); +} + +function dropIt() +{ + stopSpin(); + + if (domStyle) + { + domStyle = null; + } +} + +// Default events configuration + +document.onmousedown = pickIt; +document.onmousemove = dragIt; +document.onmouseup = dropIt; diff --git a/mysite/mysite/site_media/datetimepicker_css.js.bak b/mysite/mysite/site_media/datetimepicker_css.js.bak new file mode 100755 index 0000000..90bcc6c Binary files /dev/null and b/mysite/mysite/site_media/datetimepicker_css.js.bak differ diff --git a/mysite/mysite/site_media/fullcalendar/changelog.txt b/mysite/mysite/site_media/fullcalendar/changelog.txt new file mode 100755 index 0000000..409aadf --- /dev/null +++ b/mysite/mysite/site_media/fullcalendar/changelog.txt @@ -0,0 +1,230 @@ + +version 1.4.7 (7/5/10) + - "dropping" external objects onto the calendar + - droppable (boolean, to turn on/off) + - dropAccept (to filter which events the calendar will accept) + - drop (trigger) + - selectable options can now be specified with a View Option Hash + - bugfixes + - dragged & reverted events having wrong time text (issue 406) + - bug rendering events that have an endtime with seconds, but no hours/minutes (issue 477) + - gotoDate date overflow bug (issue 429) + - wrong date reported when clicking on edge of last column in agenda views (412) + - support newlines in event titles + - select/unselect callbacks now passes native js event + +version 1.4.6 (5/31/10) + - "selecting" days or timeslots + - options: selectable, selectHelper, unselectAuto, unselectCancel + - callbacks: select, unselect + - methods: select, unselect + - when dragging an event, the highlighting reflects the duration of the event + - code compressing by Google Closure Compiler + - bundled with jQuery 1.4.2 and jQuery UI 1.8.1 + +version 1.4.5 (2/21/10) + - lazyFetching option, which can force the calendar to fetch events on every view/date change + - scroll state of agenda views are preserved when switching back to view + - bugfixes + - calling methods on an uninitialized fullcalendar throws error + - IE6/7 bug where an entire view becomes invisible (issue 320) + - error when rendering a hidden calendar (in jquery ui tabs for example) in IE (issue 340) + - interconnected bugs related to calendar resizing and scrollbars + - when switching views or clicking prev/next, calendar would "blink" (issue 333) + - liquid-width calendar's events shifted (depending on initial height of browser) (issue 341) + - more robust underlying algorithm for calendar resizing + +version 1.4.4 (2/3/10) + - optimized event rendering in all views (events render in 1/10 the time) + - gotoDate() does not force the calendar to unnecessarily rerender + - render() method now correctly readjusts height + +version 1.4.3 (12/22/09) + - added destroy method + - Google Calendar event pages respect currentTimezone + - caching now handled by jQuery's ajax + - protection from setting aspectRatio to zero + - bugfixes + - parseISO8601 and DST caused certain events to display day before + - button positioning problem in IE6 + - ajax event source removed after recently being added, events still displayed + - event not displayed when end is an empty string + - dynamically setting calendar height when no events have been fetched, throws error + +version 1.4.2 (12/02/09) + - eventAfterRender trigger + - getDate & getView methods + - height & contentHeight options (explicitly sets the pixel height) + - minTime & maxTime options (restricts shown hours in agenda view) + - getters [for all options] and setters [for height, contentHeight, and aspectRatio ONLY! stay tuned..] + - render method now readjusts calendar's size + - bugfixes + - lightbox scripts that use iframes (like fancybox) + - day-of-week classNames were off when firstDay=1 + - guaranteed space on right side of agenda events (even when stacked) + - accepts ISO8601 dates with a space (instead of 'T') + +version 1.4.1 (10/31/09) + - can exclude weekends with new 'weekends' option + - gcal feed 'currentTimezone' option + - bugfixes + - year/month/date option sometimes wouldn't set correctly (depending on current date) + - daylight savings issue caused agenda views to start at 1am (for BST users) + - cleanup of gcal.js code + +version 1.4 (10/19/09) + - agendaWeek and agendaDay views + - added some options for agenda views: + - allDaySlot + - allDayText + - firstHour + - slotMinutes + - defaultEventMinutes + - axisFormat + - modified some existing options/triggers to work with agenda views: + - dragOpacity and timeFormat can now accept a "View Hash" (a new concept) + - dayClick now has an allDay parameter + - eventDrop now has an an allDay parameter + (this will affect those who use revertFunc, adjust parameter list) + - added 'prevYear' and 'nextYear' for buttons in header + - minor change for theme users, ui-state-hover not applied to active/inactive buttons + - added event-color-changing example in docs + - better defaults for right-to-left themed button icons + +version 1.3.2 (10/13/09) + - Bugfixes (please upgrade from 1.3.1!) + - squashed potential infinite loop when addMonths and addDays + is called with an invalid date + - $.fullCalendar.parseDate() now correctly parses IETF format + - when switching views, the 'today' button sticks inactive, fixed + - gotoDate now can accept a single Date argument + - documentation for changes in 1.3.1 and 1.3.2 now on website + +version 1.3.1 (9/30/09) + - Important Bugfixes (please upgrade from 1.3!) + - When current date was late in the month, for long months, and prev/next buttons + were clicked in month-view, some months would be skipped/repeated + - In certain time zones, daylight savings time would cause certain days + to be misnumbered in month-view + - Subtle change in way week interval is chosen when switching from month to basicWeek/basicDay view + - Added 'allDayDefault' option + - Added 'changeView' and 'render' methods + +version 1.3 (9/21/09) + - different 'views': month/basicWeek/basicDay + - more flexible 'header' system for buttons + - themable by jQuery UI themes + - resizable events (require jQuery UI resizable plugin) + - rescoped & rewritten CSS, enhanced default look + - cleaner css & rendering techniques for right-to-left + - reworked options & API to support multiple views / be consistent with jQuery UI + - refactoring of entire codebase + - broken into different JS & CSS files, assembled w/ build scripts + - new test suite for new features, uses firebug-lite + - refactored docs + - Options + + date + + defaultView + + aspectRatio + + disableResizing + + monthNames (use instead of $.fullCalendar.monthNames) + + monthNamesShort (use instead of $.fullCalendar.monthAbbrevs) + + dayNames (use instead of $.fullCalendar.dayNames) + + dayNamesShort (use instead of $.fullCalendar.dayAbbrevs) + + theme + + buttonText + + buttonIcons + x draggable -> editable/disableDragging + x fixedWeeks -> weekMode + x abbrevDayHeadings -> columnFormat + x buttons/title -> header + x eventDragOpacity -> dragOpacity + x eventRevertDuration -> dragRevertDuration + x weekStart -> firstDay + x rightToLeft -> isRTL + x showTime (use 'allDay' CalEvent property instead) + - Triggered Actions + + eventResizeStart + + eventResizeStop + + eventResize + x monthDisplay -> viewDisplay + x resize -> windowResize + 'eventDrop' params changed, can revert if ajax cuts out + - CalEvent Properties + x showTime -> allDay + x draggable -> editable + 'end' is now INCLUSIVE when allDay=true + 'url' now produces a real tag, more native clicking/tab behavior + - Methods: + + renderEvent + x prevMonth -> prev + x nextMonth -> next + x prevYear/nextYear -> moveDate + x refresh -> rerenderEvents/refetchEvents + x removeEvent -> removeEvents + x getEventsByID -> clientEvents + - Utilities: + 'formatDate' format string completely changed (inspired by jQuery UI datepicker + datejs) + 'formatDates' added to support date-ranges + - Google Calendar Options: + x draggable -> editable + - Bugfixes + - gcal extension fetched 25 results max, now fetches all + +version 1.2.1 (6/29/09) + - bugfixes + - allows and corrects invalid end dates for events + - doesn't throw an error in IE while rendering when display:none + - fixed 'loading' callback when used w/ multiple addEventSource calls + - gcal className can now be an array + +version 1.2 (5/31/09) + - expanded API + - 'className' CalEvent attribute + - 'source' CalEvent attribute + - dynamically get/add/remove/update events of current month + - locale improvements: change month/day name text + - better date formatting ($.fullCalendar.formatDate) + - multiple 'event sources' allowed + - dynamically add/remove event sources + - options for prevYear and nextYear buttons + - docs have been reworked (include addition of Google Calendar docs) + - changed behavior of parseDate for number strings + (now interpets as unix timestamp, not MS times) + - bugfixes + - rightToLeft month start bug + - off-by-one errors with month formatting commands + - events from previous months sticking when clicking prev/next quickly + - Google Calendar API changed to work w/ multiple event sources + - can also provide 'className' and 'draggable' options + - date utilties moved from $ to $.fullCalendar + - more documentation in source code + - minified version of fullcalendar.js + - test suit (available from svn) + - top buttons now use ').click(function(){h.click.apply(b.element[0],arguments)}).appendTo(g);c.each(h,function(j,k){if(j!=="click")j in o?i[j](k):i.attr(j,k)});c.fn.button&&i.button()});e.appendTo(b.uiDialog)}},_makeDraggable:function(){function a(f){return{position:f.position,offset:f.offset}}var b=this,d=b.options,e=c(document),g;b.uiDialog.draggable({cancel:".ui-dialog-content, .ui-dialog-titlebar-close", +handle:".ui-dialog-titlebar",containment:"document",start:function(f,h){g=d.height==="auto"?"auto":c(this).height();c(this).height(c(this).height()).addClass("ui-dialog-dragging");b._trigger("dragStart",f,a(h))},drag:function(f,h){b._trigger("drag",f,a(h))},stop:function(f,h){d.position=[h.position.left-e.scrollLeft(),h.position.top-e.scrollTop()];c(this).removeClass("ui-dialog-dragging").height(g);b._trigger("dragStop",f,a(h));c.ui.dialog.overlay.resize()}})},_makeResizable:function(a){function b(f){return{originalPosition:f.originalPosition, +originalSize:f.originalSize,position:f.position,size:f.size}}a=a===l?this.options.resizable:a;var d=this,e=d.options,g=d.uiDialog.css("position");a=typeof a==="string"?a:"n,e,s,w,se,sw,ne,nw";d.uiDialog.resizable({cancel:".ui-dialog-content",containment:"document",alsoResize:d.element,maxWidth:e.maxWidth,maxHeight:e.maxHeight,minWidth:e.minWidth,minHeight:d._minHeight(),handles:a,start:function(f,h){c(this).addClass("ui-dialog-resizing");d._trigger("resizeStart",f,b(h))},resize:function(f,h){d._trigger("resize", +f,b(h))},stop:function(f,h){c(this).removeClass("ui-dialog-resizing");e.height=c(this).height();e.width=c(this).width();d._trigger("resizeStop",f,b(h));c.ui.dialog.overlay.resize()}}).css("position",g).find(".ui-resizable-se").addClass("ui-icon ui-icon-grip-diagonal-se")},_minHeight:function(){var a=this.options;return a.height==="auto"?a.minHeight:Math.min(a.minHeight,a.height)},_position:function(a){var b=[],d=[0,0],e;if(a){if(typeof a==="string"||typeof a==="object"&&"0"in a){b=a.split?a.split(" "): +[a[0],a[1]];if(b.length===1)b[1]=b[0];c.each(["left","top"],function(g,f){if(+b[g]===b[g]){d[g]=b[g];b[g]=f}});a={my:b.join(" "),at:b.join(" "),offset:d.join(" ")}}a=c.extend({},c.ui.dialog.prototype.options.position,a)}else a=c.ui.dialog.prototype.options.position;(e=this.uiDialog.is(":visible"))||this.uiDialog.show();this.uiDialog.css({top:0,left:0}).position(c.extend({of:window},a));e||this.uiDialog.hide()},_setOptions:function(a){var b=this,d={},e=false;c.each(a,function(g,f){b._setOption(g,f); +if(g in m)e=true;if(g in n)d[g]=f});e&&this._size();this.uiDialog.is(":data(resizable)")&&this.uiDialog.resizable("option",d)},_setOption:function(a,b){var d=this,e=d.uiDialog;switch(a){case "beforeclose":a="beforeClose";break;case "buttons":d._createButtons(b);break;case "closeText":d.uiDialogTitlebarCloseText.text(""+b);break;case "dialogClass":e.removeClass(d.options.dialogClass).addClass("ui-dialog ui-widget ui-widget-content ui-corner-all "+b);break;case "disabled":b?e.addClass("ui-dialog-disabled"): +e.removeClass("ui-dialog-disabled");break;case "draggable":var g=e.is(":data(draggable)");g&&!b&&e.draggable("destroy");!g&&b&&d._makeDraggable();break;case "position":d._position(b);break;case "resizable":(g=e.is(":data(resizable)"))&&!b&&e.resizable("destroy");g&&typeof b==="string"&&e.resizable("option","handles",b);!g&&b!==false&&d._makeResizable(b);break;case "title":c(".ui-dialog-title",d.uiDialogTitlebar).html(""+(b||" "));break}c.Widget.prototype._setOption.apply(d,arguments)},_size:function(){var a= +this.options,b,d,e=this.uiDialog.is(":visible");this.element.show().css({width:"auto",minHeight:0,height:0});if(a.minWidth>a.width)a.width=a.minWidth;b=this.uiDialog.css({height:"auto",width:a.width}).height();d=Math.max(0,a.minHeight-b);if(a.height==="auto")if(c.support.minHeight)this.element.css({minHeight:d,height:"auto"});else{this.uiDialog.show();a=this.element.css("height","auto").height();e||this.uiDialog.hide();this.element.height(Math.max(a,d))}else this.element.height(Math.max(a.height- +b,0));this.uiDialog.is(":data(resizable)")&&this.uiDialog.resizable("option","minHeight",this._minHeight())}});c.extend(c.ui.dialog,{version:"1.8.16",uuid:0,maxZ:0,getTitleId:function(a){a=a.attr("id");if(!a){this.uuid+=1;a=this.uuid}return"ui-dialog-title-"+a},overlay:function(a){this.$el=c.ui.dialog.overlay.create(a)}});c.extend(c.ui.dialog.overlay,{instances:[],oldInstances:[],maxZ:0,events:c.map("focus,mousedown,mouseup,keydown,keypress,click".split(","),function(a){return a+".dialog-overlay"}).join(" "), +create:function(a){if(this.instances.length===0){setTimeout(function(){c.ui.dialog.overlay.instances.length&&c(document).bind(c.ui.dialog.overlay.events,function(d){if(c(d.target).zIndex()").addClass("ui-widget-overlay")).appendTo(document.body).css({width:this.width(),height:this.height()});c.fn.bgiframe&&b.bgiframe();this.instances.push(b);return b},destroy:function(a){var b=c.inArray(a,this.instances);b!=-1&&this.oldInstances.push(this.instances.splice(b,1)[0]);this.instances.length===0&&c([document,window]).unbind(".dialog-overlay");a.remove();var d=0;c.each(this.instances,function(){d=Math.max(d,this.css("z-index"))});this.maxZ=d},height:function(){var a,b;if(c.browser.msie&& +c.browser.version<7){a=Math.max(document.documentElement.scrollHeight,document.body.scrollHeight);b=Math.max(document.documentElement.offsetHeight,document.body.offsetHeight);return a").appendTo(this.element).addClass("ui-slider-range ui-widget-header"+(b.range==="min"||b.range==="max"?" ui-slider-range-"+b.range:""))}for(var j=c.length;j"); +this.handles=c.add(d(e.join("")).appendTo(a.element));this.handle=this.handles.eq(0);this.handles.add(this.range).filter("a").click(function(g){g.preventDefault()}).hover(function(){b.disabled||d(this).addClass("ui-state-hover")},function(){d(this).removeClass("ui-state-hover")}).focus(function(){if(b.disabled)d(this).blur();else{d(".ui-slider .ui-state-focus").removeClass("ui-state-focus");d(this).addClass("ui-state-focus")}}).blur(function(){d(this).removeClass("ui-state-focus")});this.handles.each(function(g){d(this).data("index.ui-slider-handle", +g)});this.handles.keydown(function(g){var k=true,l=d(this).data("index.ui-slider-handle"),i,h,m;if(!a.options.disabled){switch(g.keyCode){case d.ui.keyCode.HOME:case d.ui.keyCode.END:case d.ui.keyCode.PAGE_UP:case d.ui.keyCode.PAGE_DOWN:case d.ui.keyCode.UP:case d.ui.keyCode.RIGHT:case d.ui.keyCode.DOWN:case d.ui.keyCode.LEFT:k=false;if(!a._keySliding){a._keySliding=true;d(this).addClass("ui-state-active");i=a._start(g,l);if(i===false)return}break}m=a.options.step;i=a.options.values&&a.options.values.length? +(h=a.values(l)):(h=a.value());switch(g.keyCode){case d.ui.keyCode.HOME:h=a._valueMin();break;case d.ui.keyCode.END:h=a._valueMax();break;case d.ui.keyCode.PAGE_UP:h=a._trimAlignValue(i+(a._valueMax()-a._valueMin())/5);break;case d.ui.keyCode.PAGE_DOWN:h=a._trimAlignValue(i-(a._valueMax()-a._valueMin())/5);break;case d.ui.keyCode.UP:case d.ui.keyCode.RIGHT:if(i===a._valueMax())return;h=a._trimAlignValue(i+m);break;case d.ui.keyCode.DOWN:case d.ui.keyCode.LEFT:if(i===a._valueMin())return;h=a._trimAlignValue(i- +m);break}a._slide(g,l,h);return k}}).keyup(function(g){var k=d(this).data("index.ui-slider-handle");if(a._keySliding){a._keySliding=false;a._stop(g,k);a._change(g,k);d(this).removeClass("ui-state-active")}});this._refreshValue();this._animateOff=false},destroy:function(){this.handles.remove();this.range.remove();this.element.removeClass("ui-slider ui-slider-horizontal ui-slider-vertical ui-slider-disabled ui-widget ui-widget-content ui-corner-all").removeData("slider").unbind(".slider");this._mouseDestroy(); +return this},_mouseCapture:function(a){var b=this.options,c,f,e,j,g;if(b.disabled)return false;this.elementSize={width:this.element.outerWidth(),height:this.element.outerHeight()};this.elementOffset=this.element.offset();c=this._normValueFromMouse({x:a.pageX,y:a.pageY});f=this._valueMax()-this._valueMin()+1;j=this;this.handles.each(function(k){var l=Math.abs(c-j.values(k));if(f>l){f=l;e=d(this);g=k}});if(b.range===true&&this.values(1)===b.min){g+=1;e=d(this.handles[g])}if(this._start(a,g)===false)return false; +this._mouseSliding=true;j._handleIndex=g;e.addClass("ui-state-active").focus();b=e.offset();this._clickOffset=!d(a.target).parents().andSelf().is(".ui-slider-handle")?{left:0,top:0}:{left:a.pageX-b.left-e.width()/2,top:a.pageY-b.top-e.height()/2-(parseInt(e.css("borderTopWidth"),10)||0)-(parseInt(e.css("borderBottomWidth"),10)||0)+(parseInt(e.css("marginTop"),10)||0)};this.handles.hasClass("ui-state-hover")||this._slide(a,g,c);return this._animateOff=true},_mouseStart:function(){return true},_mouseDrag:function(a){var b= +this._normValueFromMouse({x:a.pageX,y:a.pageY});this._slide(a,this._handleIndex,b);return false},_mouseStop:function(a){this.handles.removeClass("ui-state-active");this._mouseSliding=false;this._stop(a,this._handleIndex);this._change(a,this._handleIndex);this._clickOffset=this._handleIndex=null;return this._animateOff=false},_detectOrientation:function(){this.orientation=this.options.orientation==="vertical"?"vertical":"horizontal"},_normValueFromMouse:function(a){var b;if(this.orientation==="horizontal"){b= +this.elementSize.width;a=a.x-this.elementOffset.left-(this._clickOffset?this._clickOffset.left:0)}else{b=this.elementSize.height;a=a.y-this.elementOffset.top-(this._clickOffset?this._clickOffset.top:0)}b=a/b;if(b>1)b=1;if(b<0)b=0;if(this.orientation==="vertical")b=1-b;a=this._valueMax()-this._valueMin();return this._trimAlignValue(this._valueMin()+b*a)},_start:function(a,b){var c={handle:this.handles[b],value:this.value()};if(this.options.values&&this.options.values.length){c.value=this.values(b); +c.values=this.values()}return this._trigger("start",a,c)},_slide:function(a,b,c){var f;if(this.options.values&&this.options.values.length){f=this.values(b?0:1);if(this.options.values.length===2&&this.options.range===true&&(b===0&&c>f||b===1&&c1){this.options.values[a]=this._trimAlignValue(b);this._refreshValue();this._change(null,a)}else if(arguments.length)if(d.isArray(arguments[0])){c=this.options.values;f=arguments[0];for(e=0;e=this._valueMax())return this._valueMax();var b=this.options.step>0?this.options.step:1,c=(a-this._valueMin())%b;a=a-c;if(Math.abs(c)*2>=b)a+=c>0?b:-b;return parseFloat(a.toFixed(5))},_valueMin:function(){return this.options.min},_valueMax:function(){return this.options.max},_refreshValue:function(){var a= +this.options.range,b=this.options,c=this,f=!this._animateOff?b.animate:false,e,j={},g,k,l,i;if(this.options.values&&this.options.values.length)this.handles.each(function(h){e=(c.values(h)-c._valueMin())/(c._valueMax()-c._valueMin())*100;j[c.orientation==="horizontal"?"left":"bottom"]=e+"%";d(this).stop(1,1)[f?"animate":"css"](j,b.animate);if(c.options.range===true)if(c.orientation==="horizontal"){if(h===0)c.range.stop(1,1)[f?"animate":"css"]({left:e+"%"},b.animate);if(h===1)c.range[f?"animate":"css"]({width:e- +g+"%"},{queue:false,duration:b.animate})}else{if(h===0)c.range.stop(1,1)[f?"animate":"css"]({bottom:e+"%"},b.animate);if(h===1)c.range[f?"animate":"css"]({height:e-g+"%"},{queue:false,duration:b.animate})}g=e});else{k=this.value();l=this._valueMin();i=this._valueMax();e=i!==l?(k-l)/(i-l)*100:0;j[c.orientation==="horizontal"?"left":"bottom"]=e+"%";this.handle.stop(1,1)[f?"animate":"css"](j,b.animate);if(a==="min"&&this.orientation==="horizontal")this.range.stop(1,1)[f?"animate":"css"]({width:e+"%"}, +b.animate);if(a==="max"&&this.orientation==="horizontal")this.range[f?"animate":"css"]({width:100-e+"%"},{queue:false,duration:b.animate});if(a==="min"&&this.orientation==="vertical")this.range.stop(1,1)[f?"animate":"css"]({height:e+"%"},b.animate);if(a==="max"&&this.orientation==="vertical")this.range[f?"animate":"css"]({height:100-e+"%"},{queue:false,duration:b.animate})}}});d.extend(d.ui.slider,{version:"1.8.16"})})(jQuery); +;/* + * jQuery UI Tabs 1.8.16 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Tabs + * + * Depends: + * jquery.ui.core.js + * jquery.ui.widget.js + */ +(function(d,p){function u(){return++v}function w(){return++x}var v=0,x=0;d.widget("ui.tabs",{options:{add:null,ajaxOptions:null,cache:false,cookie:null,collapsible:false,disable:null,disabled:[],enable:null,event:"click",fx:null,idPrefix:"ui-tabs-",load:null,panelTemplate:"
",remove:null,select:null,show:null,spinner:"Loading…",tabTemplate:"
  • #{label}
  • "},_create:function(){this._tabify(true)},_setOption:function(b,e){if(b=="selected")this.options.collapsible&& +e==this.options.selected||this.select(e);else{this.options[b]=e;this._tabify()}},_tabId:function(b){return b.title&&b.title.replace(/\s/g,"_").replace(/[^\w\u00c0-\uFFFF-]/g,"")||this.options.idPrefix+u()},_sanitizeSelector:function(b){return b.replace(/:/g,"\\:")},_cookie:function(){var b=this.cookie||(this.cookie=this.options.cookie.name||"ui-tabs-"+w());return d.cookie.apply(null,[b].concat(d.makeArray(arguments)))},_ui:function(b,e){return{tab:b,panel:e,index:this.anchors.index(b)}},_cleanup:function(){this.lis.filter(".ui-state-processing").removeClass("ui-state-processing").find("span:data(label.tabs)").each(function(){var b= +d(this);b.html(b.data("label.tabs")).removeData("label.tabs")})},_tabify:function(b){function e(g,f){g.css("display","");!d.support.opacity&&f.opacity&&g[0].style.removeAttribute("filter")}var a=this,c=this.options,h=/^#.+/;this.list=this.element.find("ol,ul").eq(0);this.lis=d(" > li:has(a[href])",this.list);this.anchors=this.lis.map(function(){return d("a",this)[0]});this.panels=d([]);this.anchors.each(function(g,f){var i=d(f).attr("href"),l=i.split("#")[0],q;if(l&&(l===location.toString().split("#")[0]|| +(q=d("base")[0])&&l===q.href)){i=f.hash;f.href=i}if(h.test(i))a.panels=a.panels.add(a.element.find(a._sanitizeSelector(i)));else if(i&&i!=="#"){d.data(f,"href.tabs",i);d.data(f,"load.tabs",i.replace(/#.*$/,""));i=a._tabId(f);f.href="#"+i;f=a.element.find("#"+i);if(!f.length){f=d(c.panelTemplate).attr("id",i).addClass("ui-tabs-panel ui-widget-content ui-corner-bottom").insertAfter(a.panels[g-1]||a.list);f.data("destroy.tabs",true)}a.panels=a.panels.add(f)}else c.disabled.push(g)});if(b){this.element.addClass("ui-tabs ui-widget ui-widget-content ui-corner-all"); +this.list.addClass("ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all");this.lis.addClass("ui-state-default ui-corner-top");this.panels.addClass("ui-tabs-panel ui-widget-content ui-corner-bottom");if(c.selected===p){location.hash&&this.anchors.each(function(g,f){if(f.hash==location.hash){c.selected=g;return false}});if(typeof c.selected!=="number"&&c.cookie)c.selected=parseInt(a._cookie(),10);if(typeof c.selected!=="number"&&this.lis.filter(".ui-tabs-selected").length)c.selected= +this.lis.index(this.lis.filter(".ui-tabs-selected"));c.selected=c.selected||(this.lis.length?0:-1)}else if(c.selected===null)c.selected=-1;c.selected=c.selected>=0&&this.anchors[c.selected]||c.selected<0?c.selected:0;c.disabled=d.unique(c.disabled.concat(d.map(this.lis.filter(".ui-state-disabled"),function(g){return a.lis.index(g)}))).sort();d.inArray(c.selected,c.disabled)!=-1&&c.disabled.splice(d.inArray(c.selected,c.disabled),1);this.panels.addClass("ui-tabs-hide");this.lis.removeClass("ui-tabs-selected ui-state-active"); +if(c.selected>=0&&this.anchors.length){a.element.find(a._sanitizeSelector(a.anchors[c.selected].hash)).removeClass("ui-tabs-hide");this.lis.eq(c.selected).addClass("ui-tabs-selected ui-state-active");a.element.queue("tabs",function(){a._trigger("show",null,a._ui(a.anchors[c.selected],a.element.find(a._sanitizeSelector(a.anchors[c.selected].hash))[0]))});this.load(c.selected)}d(window).bind("unload",function(){a.lis.add(a.anchors).unbind(".tabs");a.lis=a.anchors=a.panels=null})}else c.selected=this.lis.index(this.lis.filter(".ui-tabs-selected")); +this.element[c.collapsible?"addClass":"removeClass"]("ui-tabs-collapsible");c.cookie&&this._cookie(c.selected,c.cookie);b=0;for(var j;j=this.lis[b];b++)d(j)[d.inArray(b,c.disabled)!=-1&&!d(j).hasClass("ui-tabs-selected")?"addClass":"removeClass"]("ui-state-disabled");c.cache===false&&this.anchors.removeData("cache.tabs");this.lis.add(this.anchors).unbind(".tabs");if(c.event!=="mouseover"){var k=function(g,f){f.is(":not(.ui-state-disabled)")&&f.addClass("ui-state-"+g)},n=function(g,f){f.removeClass("ui-state-"+ +g)};this.lis.bind("mouseover.tabs",function(){k("hover",d(this))});this.lis.bind("mouseout.tabs",function(){n("hover",d(this))});this.anchors.bind("focus.tabs",function(){k("focus",d(this).closest("li"))});this.anchors.bind("blur.tabs",function(){n("focus",d(this).closest("li"))})}var m,o;if(c.fx)if(d.isArray(c.fx)){m=c.fx[0];o=c.fx[1]}else m=o=c.fx;var r=o?function(g,f){d(g).closest("li").addClass("ui-tabs-selected ui-state-active");f.hide().removeClass("ui-tabs-hide").animate(o,o.duration||"normal", +function(){e(f,o);a._trigger("show",null,a._ui(g,f[0]))})}:function(g,f){d(g).closest("li").addClass("ui-tabs-selected ui-state-active");f.removeClass("ui-tabs-hide");a._trigger("show",null,a._ui(g,f[0]))},s=m?function(g,f){f.animate(m,m.duration||"normal",function(){a.lis.removeClass("ui-tabs-selected ui-state-active");f.addClass("ui-tabs-hide");e(f,m);a.element.dequeue("tabs")})}:function(g,f){a.lis.removeClass("ui-tabs-selected ui-state-active");f.addClass("ui-tabs-hide");a.element.dequeue("tabs")}; +this.anchors.bind(c.event+".tabs",function(){var g=this,f=d(g).closest("li"),i=a.panels.filter(":not(.ui-tabs-hide)"),l=a.element.find(a._sanitizeSelector(g.hash));if(f.hasClass("ui-tabs-selected")&&!c.collapsible||f.hasClass("ui-state-disabled")||f.hasClass("ui-state-processing")||a.panels.filter(":animated").length||a._trigger("select",null,a._ui(this,l[0]))===false){this.blur();return false}c.selected=a.anchors.index(this);a.abort();if(c.collapsible)if(f.hasClass("ui-tabs-selected")){c.selected= +-1;c.cookie&&a._cookie(c.selected,c.cookie);a.element.queue("tabs",function(){s(g,i)}).dequeue("tabs");this.blur();return false}else if(!i.length){c.cookie&&a._cookie(c.selected,c.cookie);a.element.queue("tabs",function(){r(g,l)});a.load(a.anchors.index(this));this.blur();return false}c.cookie&&a._cookie(c.selected,c.cookie);if(l.length){i.length&&a.element.queue("tabs",function(){s(g,i)});a.element.queue("tabs",function(){r(g,l)});a.load(a.anchors.index(this))}else throw"jQuery UI Tabs: Mismatching fragment identifier."; +d.browser.msie&&this.blur()});this.anchors.bind("click.tabs",function(){return false})},_getIndex:function(b){if(typeof b=="string")b=this.anchors.index(this.anchors.filter("[href$="+b+"]"));return b},destroy:function(){var b=this.options;this.abort();this.element.unbind(".tabs").removeClass("ui-tabs ui-widget ui-widget-content ui-corner-all ui-tabs-collapsible").removeData("tabs");this.list.removeClass("ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all");this.anchors.each(function(){var e= +d.data(this,"href.tabs");if(e)this.href=e;var a=d(this).unbind(".tabs");d.each(["href","load","cache"],function(c,h){a.removeData(h+".tabs")})});this.lis.unbind(".tabs").add(this.panels).each(function(){d.data(this,"destroy.tabs")?d(this).remove():d(this).removeClass("ui-state-default ui-corner-top ui-tabs-selected ui-state-active ui-state-hover ui-state-focus ui-state-disabled ui-tabs-panel ui-widget-content ui-corner-bottom ui-tabs-hide")});b.cookie&&this._cookie(null,b.cookie);return this},add:function(b, +e,a){if(a===p)a=this.anchors.length;var c=this,h=this.options;e=d(h.tabTemplate.replace(/#\{href\}/g,b).replace(/#\{label\}/g,e));b=!b.indexOf("#")?b.replace("#",""):this._tabId(d("a",e)[0]);e.addClass("ui-state-default ui-corner-top").data("destroy.tabs",true);var j=c.element.find("#"+b);j.length||(j=d(h.panelTemplate).attr("id",b).data("destroy.tabs",true));j.addClass("ui-tabs-panel ui-widget-content ui-corner-bottom ui-tabs-hide");if(a>=this.lis.length){e.appendTo(this.list);j.appendTo(this.list[0].parentNode)}else{e.insertBefore(this.lis[a]); +j.insertBefore(this.panels[a])}h.disabled=d.map(h.disabled,function(k){return k>=a?++k:k});this._tabify();if(this.anchors.length==1){h.selected=0;e.addClass("ui-tabs-selected ui-state-active");j.removeClass("ui-tabs-hide");this.element.queue("tabs",function(){c._trigger("show",null,c._ui(c.anchors[0],c.panels[0]))});this.load(0)}this._trigger("add",null,this._ui(this.anchors[a],this.panels[a]));return this},remove:function(b){b=this._getIndex(b);var e=this.options,a=this.lis.eq(b).remove(),c=this.panels.eq(b).remove(); +if(a.hasClass("ui-tabs-selected")&&this.anchors.length>1)this.select(b+(b+1=b?--h:h});this._tabify();this._trigger("remove",null,this._ui(a.find("a")[0],c[0]));return this},enable:function(b){b=this._getIndex(b);var e=this.options;if(d.inArray(b,e.disabled)!=-1){this.lis.eq(b).removeClass("ui-state-disabled");e.disabled=d.grep(e.disabled,function(a){return a!=b});this._trigger("enable",null, +this._ui(this.anchors[b],this.panels[b]));return this}},disable:function(b){b=this._getIndex(b);var e=this.options;if(b!=e.selected){this.lis.eq(b).addClass("ui-state-disabled");e.disabled.push(b);e.disabled.sort();this._trigger("disable",null,this._ui(this.anchors[b],this.panels[b]))}return this},select:function(b){b=this._getIndex(b);if(b==-1)if(this.options.collapsible&&this.options.selected!=-1)b=this.options.selected;else return this;this.anchors.eq(b).trigger(this.options.event+".tabs");return this}, +load:function(b){b=this._getIndex(b);var e=this,a=this.options,c=this.anchors.eq(b)[0],h=d.data(c,"load.tabs");this.abort();if(!h||this.element.queue("tabs").length!==0&&d.data(c,"cache.tabs"))this.element.dequeue("tabs");else{this.lis.eq(b).addClass("ui-state-processing");if(a.spinner){var j=d("span",c);j.data("label.tabs",j.html()).html(a.spinner)}this.xhr=d.ajax(d.extend({},a.ajaxOptions,{url:h,success:function(k,n){e.element.find(e._sanitizeSelector(c.hash)).html(k);e._cleanup();a.cache&&d.data(c, +"cache.tabs",true);e._trigger("load",null,e._ui(e.anchors[b],e.panels[b]));try{a.ajaxOptions.success(k,n)}catch(m){}},error:function(k,n){e._cleanup();e._trigger("load",null,e._ui(e.anchors[b],e.panels[b]));try{a.ajaxOptions.error(k,n,b,c)}catch(m){}}}));e.element.dequeue("tabs");return this}},abort:function(){this.element.queue([]);this.panels.stop(false,true);this.element.queue("tabs",this.element.queue("tabs").splice(-2,2));if(this.xhr){this.xhr.abort();delete this.xhr}this._cleanup();return this}, +url:function(b,e){this.anchors.eq(b).removeData("cache.tabs").data("load.tabs",e);return this},length:function(){return this.anchors.length}});d.extend(d.ui.tabs,{version:"1.8.16"});d.extend(d.ui.tabs.prototype,{rotation:null,rotate:function(b,e){var a=this,c=this.options,h=a._rotate||(a._rotate=function(j){clearTimeout(a.rotation);a.rotation=setTimeout(function(){var k=c.selected;a.select(++k'))}function N(a){return a.bind("mouseout", +function(b){b=d(b.target).closest("button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a");b.length&&b.removeClass("ui-state-hover ui-datepicker-prev-hover ui-datepicker-next-hover")}).bind("mouseover",function(b){b=d(b.target).closest("button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a");if(!(d.datepicker._isDisabledDatepicker(J.inline?a.parent()[0]:J.input[0])||!b.length)){b.parents(".ui-datepicker-calendar").find("a").removeClass("ui-state-hover"); +b.addClass("ui-state-hover");b.hasClass("ui-datepicker-prev")&&b.addClass("ui-datepicker-prev-hover");b.hasClass("ui-datepicker-next")&&b.addClass("ui-datepicker-next-hover")}})}function H(a,b){d.extend(a,b);for(var c in b)if(b[c]==null||b[c]==C)a[c]=b[c];return a}d.extend(d.ui,{datepicker:{version:"1.8.16"}});var B=(new Date).getTime(),J;d.extend(M.prototype,{markerClassName:"hasDatepicker",maxRows:4,log:function(){this.debug&&console.log.apply("",arguments)},_widgetDatepicker:function(){return this.dpDiv}, +setDefaults:function(a){H(this._defaults,a||{});return this},_attachDatepicker:function(a,b){var c=null;for(var e in this._defaults){var f=a.getAttribute("date:"+e);if(f){c=c||{};try{c[e]=eval(f)}catch(h){c[e]=f}}}e=a.nodeName.toLowerCase();f=e=="div"||e=="span";if(!a.id){this.uuid+=1;a.id="dp"+this.uuid}var i=this._newInst(d(a),f);i.settings=d.extend({},b||{},c||{});if(e=="input")this._connectDatepicker(a,i);else f&&this._inlineDatepicker(a,i)},_newInst:function(a,b){return{id:a[0].id.replace(/([^A-Za-z0-9_-])/g, +"\\\\$1"),input:a,selectedDay:0,selectedMonth:0,selectedYear:0,drawMonth:0,drawYear:0,inline:b,dpDiv:!b?this.dpDiv:N(d('
    '))}},_connectDatepicker:function(a,b){var c=d(a);b.append=d([]);b.trigger=d([]);if(!c.hasClass(this.markerClassName)){this._attachments(c,b);c.addClass(this.markerClassName).keydown(this._doKeyDown).keypress(this._doKeyPress).keyup(this._doKeyUp).bind("setData.datepicker", +function(e,f,h){b.settings[f]=h}).bind("getData.datepicker",function(e,f){return this._get(b,f)});this._autoSize(b);d.data(a,"datepicker",b);b.settings.disabled&&this._disableDatepicker(a)}},_attachments:function(a,b){var c=this._get(b,"appendText"),e=this._get(b,"isRTL");b.append&&b.append.remove();if(c){b.append=d(''+c+"");a[e?"before":"after"](b.append)}a.unbind("focus",this._showDatepicker);b.trigger&&b.trigger.remove();c=this._get(b,"showOn");if(c== +"focus"||c=="both")a.focus(this._showDatepicker);if(c=="button"||c=="both"){c=this._get(b,"buttonText");var f=this._get(b,"buttonImage");b.trigger=d(this._get(b,"buttonImageOnly")?d("").addClass(this._triggerClass).attr({src:f,alt:c,title:c}):d('').addClass(this._triggerClass).html(f==""?c:d("").attr({src:f,alt:c,title:c})));a[e?"before":"after"](b.trigger);b.trigger.click(function(){d.datepicker._datepickerShowing&&d.datepicker._lastInput==a[0]?d.datepicker._hideDatepicker(): +d.datepicker._showDatepicker(a[0]);return false})}},_autoSize:function(a){if(this._get(a,"autoSize")&&!a.inline){var b=new Date(2009,11,20),c=this._get(a,"dateFormat");if(c.match(/[DM]/)){var e=function(f){for(var h=0,i=0,g=0;gh){h=f[g].length;i=g}return i};b.setMonth(e(this._get(a,c.match(/MM/)?"monthNames":"monthNamesShort")));b.setDate(e(this._get(a,c.match(/DD/)?"dayNames":"dayNamesShort"))+20-b.getDay())}a.input.attr("size",this._formatDate(a,b).length)}},_inlineDatepicker:function(a, +b){var c=d(a);if(!c.hasClass(this.markerClassName)){c.addClass(this.markerClassName).append(b.dpDiv).bind("setData.datepicker",function(e,f,h){b.settings[f]=h}).bind("getData.datepicker",function(e,f){return this._get(b,f)});d.data(a,"datepicker",b);this._setDate(b,this._getDefaultDate(b),true);this._updateDatepicker(b);this._updateAlternate(b);b.settings.disabled&&this._disableDatepicker(a);b.dpDiv.css("display","block")}},_dialogDatepicker:function(a,b,c,e,f){a=this._dialogInst;if(!a){this.uuid+= +1;this._dialogInput=d('');this._dialogInput.keydown(this._doKeyDown);d("body").append(this._dialogInput);a=this._dialogInst=this._newInst(this._dialogInput,false);a.settings={};d.data(this._dialogInput[0],"datepicker",a)}H(a.settings,e||{});b=b&&b.constructor==Date?this._formatDate(a,b):b;this._dialogInput.val(b);this._pos=f?f.length?f:[f.pageX,f.pageY]:null;if(!this._pos)this._pos=[document.documentElement.clientWidth/ +2-100+(document.documentElement.scrollLeft||document.body.scrollLeft),document.documentElement.clientHeight/2-150+(document.documentElement.scrollTop||document.body.scrollTop)];this._dialogInput.css("left",this._pos[0]+20+"px").css("top",this._pos[1]+"px");a.settings.onSelect=c;this._inDialog=true;this.dpDiv.addClass(this._dialogClass);this._showDatepicker(this._dialogInput[0]);d.blockUI&&d.blockUI(this.dpDiv);d.data(this._dialogInput[0],"datepicker",a);return this},_destroyDatepicker:function(a){var b= +d(a),c=d.data(a,"datepicker");if(b.hasClass(this.markerClassName)){var e=a.nodeName.toLowerCase();d.removeData(a,"datepicker");if(e=="input"){c.append.remove();c.trigger.remove();b.removeClass(this.markerClassName).unbind("focus",this._showDatepicker).unbind("keydown",this._doKeyDown).unbind("keypress",this._doKeyPress).unbind("keyup",this._doKeyUp)}else if(e=="div"||e=="span")b.removeClass(this.markerClassName).empty()}},_enableDatepicker:function(a){var b=d(a),c=d.data(a,"datepicker");if(b.hasClass(this.markerClassName)){var e= +a.nodeName.toLowerCase();if(e=="input"){a.disabled=false;c.trigger.filter("button").each(function(){this.disabled=false}).end().filter("img").css({opacity:"1.0",cursor:""})}else if(e=="div"||e=="span"){b=b.children("."+this._inlineClass);b.children().removeClass("ui-state-disabled");b.find("select.ui-datepicker-month, select.ui-datepicker-year").removeAttr("disabled")}this._disabledInputs=d.map(this._disabledInputs,function(f){return f==a?null:f})}},_disableDatepicker:function(a){var b=d(a),c=d.data(a, +"datepicker");if(b.hasClass(this.markerClassName)){var e=a.nodeName.toLowerCase();if(e=="input"){a.disabled=true;c.trigger.filter("button").each(function(){this.disabled=true}).end().filter("img").css({opacity:"0.5",cursor:"default"})}else if(e=="div"||e=="span"){b=b.children("."+this._inlineClass);b.children().addClass("ui-state-disabled");b.find("select.ui-datepicker-month, select.ui-datepicker-year").attr("disabled","disabled")}this._disabledInputs=d.map(this._disabledInputs,function(f){return f== +a?null:f});this._disabledInputs[this._disabledInputs.length]=a}},_isDisabledDatepicker:function(a){if(!a)return false;for(var b=0;b-1}},_doKeyUp:function(a){a=d.datepicker._getInst(a.target);if(a.input.val()!=a.lastVal)try{if(d.datepicker.parseDate(d.datepicker._get(a,"dateFormat"),a.input?a.input.val():null,d.datepicker._getFormatConfig(a))){d.datepicker._setDateFromField(a);d.datepicker._updateAlternate(a);d.datepicker._updateDatepicker(a)}}catch(b){d.datepicker.log(b)}return true},_showDatepicker:function(a){a=a.target||a;if(a.nodeName.toLowerCase()!="input")a=d("input", +a.parentNode)[0];if(!(d.datepicker._isDisabledDatepicker(a)||d.datepicker._lastInput==a)){var b=d.datepicker._getInst(a);if(d.datepicker._curInst&&d.datepicker._curInst!=b){d.datepicker._datepickerShowing&&d.datepicker._triggerOnClose(d.datepicker._curInst);d.datepicker._curInst.dpDiv.stop(true,true)}var c=d.datepicker._get(b,"beforeShow");c=c?c.apply(a,[a,b]):{};if(c!==false){H(b.settings,c);b.lastVal=null;d.datepicker._lastInput=a;d.datepicker._setDateFromField(b);if(d.datepicker._inDialog)a.value= +"";if(!d.datepicker._pos){d.datepicker._pos=d.datepicker._findPos(a);d.datepicker._pos[1]+=a.offsetHeight}var e=false;d(a).parents().each(function(){e|=d(this).css("position")=="fixed";return!e});if(e&&d.browser.opera){d.datepicker._pos[0]-=document.documentElement.scrollLeft;d.datepicker._pos[1]-=document.documentElement.scrollTop}c={left:d.datepicker._pos[0],top:d.datepicker._pos[1]};d.datepicker._pos=null;b.dpDiv.empty();b.dpDiv.css({position:"absolute",display:"block",top:"-1000px"});d.datepicker._updateDatepicker(b); +c=d.datepicker._checkOffset(b,c,e);b.dpDiv.css({position:d.datepicker._inDialog&&d.blockUI?"static":e?"fixed":"absolute",display:"none",left:c.left+"px",top:c.top+"px"});if(!b.inline){c=d.datepicker._get(b,"showAnim");var f=d.datepicker._get(b,"duration"),h=function(){var i=b.dpDiv.find("iframe.ui-datepicker-cover");if(i.length){var g=d.datepicker._getBorders(b.dpDiv);i.css({left:-g[0],top:-g[1],width:b.dpDiv.outerWidth(),height:b.dpDiv.outerHeight()})}};b.dpDiv.zIndex(d(a).zIndex()+1);d.datepicker._datepickerShowing= +true;d.effects&&d.effects[c]?b.dpDiv.show(c,d.datepicker._get(b,"showOptions"),f,h):b.dpDiv[c||"show"](c?f:null,h);if(!c||!f)h();b.input.is(":visible")&&!b.input.is(":disabled")&&b.input.focus();d.datepicker._curInst=b}}}},_updateDatepicker:function(a){this.maxRows=4;var b=d.datepicker._getBorders(a.dpDiv);J=a;a.dpDiv.empty().append(this._generateHTML(a));var c=a.dpDiv.find("iframe.ui-datepicker-cover");c.length&&c.css({left:-b[0],top:-b[1],width:a.dpDiv.outerWidth(),height:a.dpDiv.outerHeight()}); +a.dpDiv.find("."+this._dayOverClass+" a").mouseover();b=this._getNumberOfMonths(a);c=b[1];a.dpDiv.removeClass("ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4").width("");c>1&&a.dpDiv.addClass("ui-datepicker-multi-"+c).css("width",17*c+"em");a.dpDiv[(b[0]!=1||b[1]!=1?"add":"remove")+"Class"]("ui-datepicker-multi");a.dpDiv[(this._get(a,"isRTL")?"add":"remove")+"Class"]("ui-datepicker-rtl");a==d.datepicker._curInst&&d.datepicker._datepickerShowing&&a.input&&a.input.is(":visible")&& +!a.input.is(":disabled")&&a.input[0]!=document.activeElement&&a.input.focus();if(a.yearshtml){var e=a.yearshtml;setTimeout(function(){e===a.yearshtml&&a.yearshtml&&a.dpDiv.find("select.ui-datepicker-year:first").replaceWith(a.yearshtml);e=a.yearshtml=null},0)}},_getBorders:function(a){var b=function(c){return{thin:1,medium:2,thick:3}[c]||c};return[parseFloat(b(a.css("border-left-width"))),parseFloat(b(a.css("border-top-width")))]},_checkOffset:function(a,b,c){var e=a.dpDiv.outerWidth(),f=a.dpDiv.outerHeight(), +h=a.input?a.input.outerWidth():0,i=a.input?a.input.outerHeight():0,g=document.documentElement.clientWidth+d(document).scrollLeft(),j=document.documentElement.clientHeight+d(document).scrollTop();b.left-=this._get(a,"isRTL")?e-h:0;b.left-=c&&b.left==a.input.offset().left?d(document).scrollLeft():0;b.top-=c&&b.top==a.input.offset().top+i?d(document).scrollTop():0;b.left-=Math.min(b.left,b.left+e>g&&g>e?Math.abs(b.left+e-g):0);b.top-=Math.min(b.top,b.top+f>j&&j>f?Math.abs(f+i):0);return b},_findPos:function(a){for(var b= +this._get(this._getInst(a),"isRTL");a&&(a.type=="hidden"||a.nodeType!=1||d.expr.filters.hidden(a));)a=a[b?"previousSibling":"nextSibling"];a=d(a).offset();return[a.left,a.top]},_triggerOnClose:function(a){var b=this._get(a,"onClose");if(b)b.apply(a.input?a.input[0]:null,[a.input?a.input.val():"",a])},_hideDatepicker:function(a){var b=this._curInst;if(!(!b||a&&b!=d.data(a,"datepicker")))if(this._datepickerShowing){a=this._get(b,"showAnim");var c=this._get(b,"duration"),e=function(){d.datepicker._tidyDialog(b); +this._curInst=null};d.effects&&d.effects[a]?b.dpDiv.hide(a,d.datepicker._get(b,"showOptions"),c,e):b.dpDiv[a=="slideDown"?"slideUp":a=="fadeIn"?"fadeOut":"hide"](a?c:null,e);a||e();d.datepicker._triggerOnClose(b);this._datepickerShowing=false;this._lastInput=null;if(this._inDialog){this._dialogInput.css({position:"absolute",left:"0",top:"-100px"});if(d.blockUI){d.unblockUI();d("body").append(this.dpDiv)}}this._inDialog=false}},_tidyDialog:function(a){a.dpDiv.removeClass(this._dialogClass).unbind(".ui-datepicker-calendar")}, +_checkExternalClick:function(a){if(d.datepicker._curInst){a=d(a.target);a[0].id!=d.datepicker._mainDivId&&a.parents("#"+d.datepicker._mainDivId).length==0&&!a.hasClass(d.datepicker.markerClassName)&&!a.hasClass(d.datepicker._triggerClass)&&d.datepicker._datepickerShowing&&!(d.datepicker._inDialog&&d.blockUI)&&d.datepicker._hideDatepicker()}},_adjustDate:function(a,b,c){a=d(a);var e=this._getInst(a[0]);if(!this._isDisabledDatepicker(a[0])){this._adjustInstDate(e,b+(c=="M"?this._get(e,"showCurrentAtPos"): +0),c);this._updateDatepicker(e)}},_gotoToday:function(a){a=d(a);var b=this._getInst(a[0]);if(this._get(b,"gotoCurrent")&&b.currentDay){b.selectedDay=b.currentDay;b.drawMonth=b.selectedMonth=b.currentMonth;b.drawYear=b.selectedYear=b.currentYear}else{var c=new Date;b.selectedDay=c.getDate();b.drawMonth=b.selectedMonth=c.getMonth();b.drawYear=b.selectedYear=c.getFullYear()}this._notifyChange(b);this._adjustDate(a)},_selectMonthYear:function(a,b,c){a=d(a);var e=this._getInst(a[0]);e["selected"+(c=="M"? +"Month":"Year")]=e["draw"+(c=="M"?"Month":"Year")]=parseInt(b.options[b.selectedIndex].value,10);this._notifyChange(e);this._adjustDate(a)},_selectDay:function(a,b,c,e){var f=d(a);if(!(d(e).hasClass(this._unselectableClass)||this._isDisabledDatepicker(f[0]))){f=this._getInst(f[0]);f.selectedDay=f.currentDay=d("a",e).html();f.selectedMonth=f.currentMonth=b;f.selectedYear=f.currentYear=c;this._selectDate(a,this._formatDate(f,f.currentDay,f.currentMonth,f.currentYear))}},_clearDate:function(a){a=d(a); +this._getInst(a[0]);this._selectDate(a,"")},_selectDate:function(a,b){a=this._getInst(d(a)[0]);b=b!=null?b:this._formatDate(a);a.input&&a.input.val(b);this._updateAlternate(a);var c=this._get(a,"onSelect");if(c)c.apply(a.input?a.input[0]:null,[b,a]);else a.input&&a.input.trigger("change");if(a.inline)this._updateDatepicker(a);else{this._hideDatepicker();this._lastInput=a.input[0];typeof a.input[0]!="object"&&a.input.focus();this._lastInput=null}},_updateAlternate:function(a){var b=this._get(a,"altField"); +if(b){var c=this._get(a,"altFormat")||this._get(a,"dateFormat"),e=this._getDate(a),f=this.formatDate(c,e,this._getFormatConfig(a));d(b).each(function(){d(this).val(f)})}},noWeekends:function(a){a=a.getDay();return[a>0&&a<6,""]},iso8601Week:function(a){a=new Date(a.getTime());a.setDate(a.getDate()+4-(a.getDay()||7));var b=a.getTime();a.setMonth(0);a.setDate(1);return Math.floor(Math.round((b-a)/864E5)/7)+1},parseDate:function(a,b,c){if(a==null||b==null)throw"Invalid arguments";b=typeof b=="object"? +b.toString():b+"";if(b=="")return null;var e=(c?c.shortYearCutoff:null)||this._defaults.shortYearCutoff;e=typeof e!="string"?e:(new Date).getFullYear()%100+parseInt(e,10);for(var f=(c?c.dayNamesShort:null)||this._defaults.dayNamesShort,h=(c?c.dayNames:null)||this._defaults.dayNames,i=(c?c.monthNamesShort:null)||this._defaults.monthNamesShort,g=(c?c.monthNames:null)||this._defaults.monthNames,j=c=-1,l=-1,u=-1,k=false,o=function(p){(p=A+1-1){j=1;l=u;do{e=this._getDaysInMonth(c,j-1);if(l<=e)break;j++;l-=e}while(1)}v=this._daylightSavingAdjust(new Date(c,j-1,l));if(v.getFullYear()!=c||v.getMonth()+1!=j||v.getDate()!=l)throw"Invalid date";return v},ATOM:"yy-mm-dd", +COOKIE:"D, dd M yy",ISO_8601:"yy-mm-dd",RFC_822:"D, d M y",RFC_850:"DD, dd-M-y",RFC_1036:"D, d M y",RFC_1123:"D, d M yy",RFC_2822:"D, d M yy",RSS:"D, d M y",TICKS:"!",TIMESTAMP:"@",W3C:"yy-mm-dd",_ticksTo1970:(718685+Math.floor(492.5)-Math.floor(19.7)+Math.floor(4.925))*24*60*60*1E7,formatDate:function(a,b,c){if(!b)return"";var e=(c?c.dayNamesShort:null)||this._defaults.dayNamesShort,f=(c?c.dayNames:null)||this._defaults.dayNames,h=(c?c.monthNamesShort:null)||this._defaults.monthNamesShort;c=(c?c.monthNames: +null)||this._defaults.monthNames;var i=function(o){(o=k+1 +12?a.getHours()+2:0);return a},_setDate:function(a,b,c){var e=!b,f=a.selectedMonth,h=a.selectedYear;b=this._restrictMinMax(a,this._determineDate(a,b,new Date));a.selectedDay=a.currentDay=b.getDate();a.drawMonth=a.selectedMonth=a.currentMonth=b.getMonth();a.drawYear=a.selectedYear=a.currentYear=b.getFullYear();if((f!=a.selectedMonth||h!=a.selectedYear)&&!c)this._notifyChange(a);this._adjustInstDate(a);if(a.input)a.input.val(e?"":this._formatDate(a))},_getDate:function(a){return!a.currentYear||a.input&& +a.input.val()==""?null:this._daylightSavingAdjust(new Date(a.currentYear,a.currentMonth,a.currentDay))},_generateHTML:function(a){var b=new Date;b=this._daylightSavingAdjust(new Date(b.getFullYear(),b.getMonth(),b.getDate()));var c=this._get(a,"isRTL"),e=this._get(a,"showButtonPanel"),f=this._get(a,"hideIfNoPrevNext"),h=this._get(a,"navigationAsDateFormat"),i=this._getNumberOfMonths(a),g=this._get(a,"showCurrentAtPos"),j=this._get(a,"stepMonths"),l=i[0]!=1||i[1]!=1,u=this._daylightSavingAdjust(!a.currentDay? +new Date(9999,9,9):new Date(a.currentYear,a.currentMonth,a.currentDay)),k=this._getMinMaxDate(a,"min"),o=this._getMinMaxDate(a,"max");g=a.drawMonth-g;var m=a.drawYear;if(g<0){g+=12;m--}if(o){var n=this._daylightSavingAdjust(new Date(o.getFullYear(),o.getMonth()-i[0]*i[1]+1,o.getDate()));for(n=k&&nn;){g--;if(g<0){g=11;m--}}}a.drawMonth=g;a.drawYear=m;n=this._get(a,"prevText");n=!h?n:this.formatDate(n,this._daylightSavingAdjust(new Date(m,g-j,1)),this._getFormatConfig(a)); +n=this._canAdjustMonth(a,-1,m,g)?''+n+"":f?"":''+n+"";var s=this._get(a,"nextText");s=!h?s:this.formatDate(s,this._daylightSavingAdjust(new Date(m, +g+j,1)),this._getFormatConfig(a));f=this._canAdjustMonth(a,+1,m,g)?''+s+"":f?"":''+s+"";j=this._get(a,"currentText");s=this._get(a,"gotoCurrent")&& +a.currentDay?u:b;j=!h?j:this.formatDate(j,s,this._getFormatConfig(a));h=!a.inline?'":"";e=e?'
    '+(c?h:"")+(this._isInRange(a,s)?'":"")+(c?"":h)+"
    ":"";h=parseInt(this._get(a,"firstDay"),10);h=isNaN(h)?0:h;j=this._get(a,"showWeek");s=this._get(a,"dayNames");this._get(a,"dayNamesShort");var q=this._get(a,"dayNamesMin"),A=this._get(a,"monthNames"),v=this._get(a,"monthNamesShort"),p=this._get(a,"beforeShowDay"),D=this._get(a,"showOtherMonths"),K=this._get(a,"selectOtherMonths");this._get(a,"calculateWeek");for(var E=this._getDefaultDate(a),w="",x=0;x1)switch(G){case 0:y+=" ui-datepicker-group-first";t=" ui-corner-"+(c?"right":"left");break;case i[1]-1:y+=" ui-datepicker-group-last";t=" ui-corner-"+(c?"left":"right");break;default:y+=" ui-datepicker-group-middle";t="";break}y+='">'}y+='
    '+(/all|left/.test(t)&& +x==0?c?f:n:"")+(/all|right/.test(t)&&x==0?c?n:f:"")+this._generateMonthYearHeader(a,g,m,k,o,x>0||G>0,A,v)+'
    ';var z=j?'":"";for(t=0;t<7;t++){var r=(t+h)%7;z+="=5?' class="ui-datepicker-week-end"':"")+'>'+q[r]+""}y+=z+"";z=this._getDaysInMonth(m,g);if(m==a.selectedYear&&g==a.selectedMonth)a.selectedDay=Math.min(a.selectedDay, +z);t=(this._getFirstDayOfMonth(m,g)-h+7)%7;z=Math.ceil((t+z)/7);this.maxRows=z=l?this.maxRows>z?this.maxRows:z:z;r=this._daylightSavingAdjust(new Date(m,g,1-t));for(var Q=0;Q";var R=!j?"":'";for(t=0;t<7;t++){var I=p?p.apply(a.input?a.input[0]:null,[r]):[true,""],F=r.getMonth()!=g,L=F&&!K||!I[0]||k&&ro;R+='";r.setDate(r.getDate()+1);r=this._daylightSavingAdjust(r)}y+=R+""}g++;if(g>11){g=0;m++}y+="
    '+this._get(a,"weekHeader")+"
    '+this._get(a,"calculateWeek")(r)+""+(F&&!D?" ":L?''+ +r.getDate()+"":''+r.getDate()+"")+"
    "+(l?""+(i[0]>0&&G==i[1]-1?'
    ':""):"");O+=y}w+=O}w+=e+(d.browser.msie&&parseInt(d.browser.version,10)<7&&!a.inline?'': +"");a._keyEvent=false;return w},_generateMonthYearHeader:function(a,b,c,e,f,h,i,g){var j=this._get(a,"changeMonth"),l=this._get(a,"changeYear"),u=this._get(a,"showMonthAfterYear"),k='
    ',o="";if(h||!j)o+=''+i[b]+"";else{i=e&&e.getFullYear()==c;var m=f&&f.getFullYear()==c;o+='"}u||(k+=o+(h||!(j&&l)?" ":""));if(!a.yearshtml){a.yearshtml="";if(h||!l)k+=''+c+"";else{g=this._get(a,"yearRange").split(":");var s=(new Date).getFullYear();i=function(q){q=q.match(/c[+-].*/)?c+parseInt(q.substring(1),10):q.match(/[+-].*/)?s+parseInt(q,10):parseInt(q,10);return isNaN(q)?s:q};b=i(g[0]);g=Math.max(b,i(g[1]||""));b=e?Math.max(b, +e.getFullYear()):b;g=f?Math.min(g,f.getFullYear()):g;for(a.yearshtml+='";k+=a.yearshtml;a.yearshtml=null}}k+=this._get(a,"yearSuffix");if(u)k+=(h||!(j&&l)?" ":"")+o;k+="
    ";return k},_adjustInstDate:function(a,b,c){var e=a.drawYear+(c=="Y"?b:0),f=a.drawMonth+ +(c=="M"?b:0);b=Math.min(a.selectedDay,this._getDaysInMonth(e,f))+(c=="D"?b:0);e=this._restrictMinMax(a,this._daylightSavingAdjust(new Date(e,f,b)));a.selectedDay=e.getDate();a.drawMonth=a.selectedMonth=e.getMonth();a.drawYear=a.selectedYear=e.getFullYear();if(c=="M"||c=="Y")this._notifyChange(a)},_restrictMinMax:function(a,b){var c=this._getMinMaxDate(a,"min");a=this._getMinMaxDate(a,"max");b=c&&ba?a:b},_notifyChange:function(a){var b=this._get(a,"onChangeMonthYear");if(b)b.apply(a.input? +a.input[0]:null,[a.selectedYear,a.selectedMonth+1,a])},_getNumberOfMonths:function(a){a=this._get(a,"numberOfMonths");return a==null?[1,1]:typeof a=="number"?[1,a]:a},_getMinMaxDate:function(a,b){return this._determineDate(a,this._get(a,b+"Date"),null)},_getDaysInMonth:function(a,b){return 32-this._daylightSavingAdjust(new Date(a,b,32)).getDate()},_getFirstDayOfMonth:function(a,b){return(new Date(a,b,1)).getDay()},_canAdjustMonth:function(a,b,c,e){var f=this._getNumberOfMonths(a);c=this._daylightSavingAdjust(new Date(c, +e+(b<0?b:f[0]*f[1]),1));b<0&&c.setDate(this._getDaysInMonth(c.getFullYear(),c.getMonth()));return this._isInRange(a,c)},_isInRange:function(a,b){var c=this._getMinMaxDate(a,"min");a=this._getMinMaxDate(a,"max");return(!c||b.getTime()>=c.getTime())&&(!a||b.getTime()<=a.getTime())},_getFormatConfig:function(a){var b=this._get(a,"shortYearCutoff");b=typeof b!="string"?b:(new Date).getFullYear()%100+parseInt(b,10);return{shortYearCutoff:b,dayNamesShort:this._get(a,"dayNamesShort"),dayNames:this._get(a, +"dayNames"),monthNamesShort:this._get(a,"monthNamesShort"),monthNames:this._get(a,"monthNames")}},_formatDate:function(a,b,c,e){if(!b){a.currentDay=a.selectedDay;a.currentMonth=a.selectedMonth;a.currentYear=a.selectedYear}b=b?typeof b=="object"?b:this._daylightSavingAdjust(new Date(e,c,b)):this._daylightSavingAdjust(new Date(a.currentYear,a.currentMonth,a.currentDay));return this.formatDate(this._get(a,"dateFormat"),b,this._getFormatConfig(a))}});d.fn.datepicker=function(a){if(!this.length)return this; +if(!d.datepicker.initialized){d(document).mousedown(d.datepicker._checkExternalClick).find("body").append(d.datepicker.dpDiv);d.datepicker.initialized=true}var b=Array.prototype.slice.call(arguments,1);if(typeof a=="string"&&(a=="isDisabled"||a=="getDate"||a=="widget"))return d.datepicker["_"+a+"Datepicker"].apply(d.datepicker,[this[0]].concat(b));if(a=="option"&&arguments.length==2&&typeof arguments[1]=="string")return d.datepicker["_"+a+"Datepicker"].apply(d.datepicker,[this[0]].concat(b));return this.each(function(){typeof a== +"string"?d.datepicker["_"+a+"Datepicker"].apply(d.datepicker,[this].concat(b)):d.datepicker._attachDatepicker(this,a)})};d.datepicker=new M;d.datepicker.initialized=false;d.datepicker.uuid=(new Date).getTime();d.datepicker.version="1.8.16";window["DP_jQuery_"+B]=d})(jQuery); +;/* + * jQuery UI Progressbar 1.8.16 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Progressbar + * + * Depends: + * jquery.ui.core.js + * jquery.ui.widget.js + */ +(function(b,d){b.widget("ui.progressbar",{options:{value:0,max:100},min:0,_create:function(){this.element.addClass("ui-progressbar ui-widget ui-widget-content ui-corner-all").attr({role:"progressbar","aria-valuemin":this.min,"aria-valuemax":this.options.max,"aria-valuenow":this._value()});this.valueDiv=b("
    ").appendTo(this.element);this.oldValue=this._value();this._refreshValue()},destroy:function(){this.element.removeClass("ui-progressbar ui-widget ui-widget-content ui-corner-all").removeAttr("role").removeAttr("aria-valuemin").removeAttr("aria-valuemax").removeAttr("aria-valuenow"); +this.valueDiv.remove();b.Widget.prototype.destroy.apply(this,arguments)},value:function(a){if(a===d)return this._value();this._setOption("value",a);return this},_setOption:function(a,c){if(a==="value"){this.options.value=c;this._refreshValue();this._value()===this.options.max&&this._trigger("complete")}b.Widget.prototype._setOption.apply(this,arguments)},_value:function(){var a=this.options.value;if(typeof a!=="number")a=0;return Math.min(this.options.max,Math.max(this.min,a))},_percentage:function(){return 100* +this._value()/this.options.max},_refreshValue:function(){var a=this.value(),c=this._percentage();if(this.oldValue!==a){this.oldValue=a;this._trigger("change")}this.valueDiv.toggle(a>this.min).toggleClass("ui-corner-right",a===this.options.max).width(c.toFixed(0)+"%");this.element.attr("aria-valuenow",a)}});b.extend(b.ui.progressbar,{version:"1.8.16"})})(jQuery); +;/* + * jQuery UI Effects 1.8.16 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Effects/ + */ +jQuery.effects||function(f,j){function m(c){var a;if(c&&c.constructor==Array&&c.length==3)return c;if(a=/rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(c))return[parseInt(a[1],10),parseInt(a[2],10),parseInt(a[3],10)];if(a=/rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(c))return[parseFloat(a[1])*2.55,parseFloat(a[2])*2.55,parseFloat(a[3])*2.55];if(a=/#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(c))return[parseInt(a[1], +16),parseInt(a[2],16),parseInt(a[3],16)];if(a=/#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(c))return[parseInt(a[1]+a[1],16),parseInt(a[2]+a[2],16),parseInt(a[3]+a[3],16)];if(/rgba\(0, 0, 0, 0\)/.exec(c))return n.transparent;return n[f.trim(c).toLowerCase()]}function s(c,a){var b;do{b=f.curCSS(c,a);if(b!=""&&b!="transparent"||f.nodeName(c,"body"))break;a="backgroundColor"}while(c=c.parentNode);return m(b)}function o(){var c=document.defaultView?document.defaultView.getComputedStyle(this,null):this.currentStyle, +a={},b,d;if(c&&c.length&&c[0]&&c[c[0]])for(var e=c.length;e--;){b=c[e];if(typeof c[b]=="string"){d=b.replace(/\-(\w)/g,function(g,h){return h.toUpperCase()});a[d]=c[b]}}else for(b in c)if(typeof c[b]==="string")a[b]=c[b];return a}function p(c){var a,b;for(a in c){b=c[a];if(b==null||f.isFunction(b)||a in t||/scrollbar/.test(a)||!/color/i.test(a)&&isNaN(parseFloat(b)))delete c[a]}return c}function u(c,a){var b={_:0},d;for(d in a)if(c[d]!=a[d])b[d]=a[d];return b}function k(c,a,b,d){if(typeof c=="object"){d= +a;b=null;a=c;c=a.effect}if(f.isFunction(a)){d=a;b=null;a={}}if(typeof a=="number"||f.fx.speeds[a]){d=b;b=a;a={}}if(f.isFunction(b)){d=b;b=null}a=a||{};b=b||a.duration;b=f.fx.off?0:typeof b=="number"?b:b in f.fx.speeds?f.fx.speeds[b]:f.fx.speeds._default;d=d||a.complete;return[c,a,b,d]}function l(c){if(!c||typeof c==="number"||f.fx.speeds[c])return true;if(typeof c==="string"&&!f.effects[c])return true;return false}f.effects={};f.each(["backgroundColor","borderBottomColor","borderLeftColor","borderRightColor", +"borderTopColor","borderColor","color","outlineColor"],function(c,a){f.fx.step[a]=function(b){if(!b.colorInit){b.start=s(b.elem,a);b.end=m(b.end);b.colorInit=true}b.elem.style[a]="rgb("+Math.max(Math.min(parseInt(b.pos*(b.end[0]-b.start[0])+b.start[0],10),255),0)+","+Math.max(Math.min(parseInt(b.pos*(b.end[1]-b.start[1])+b.start[1],10),255),0)+","+Math.max(Math.min(parseInt(b.pos*(b.end[2]-b.start[2])+b.start[2],10),255),0)+")"}});var n={aqua:[0,255,255],azure:[240,255,255],beige:[245,245,220],black:[0, +0,0],blue:[0,0,255],brown:[165,42,42],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgrey:[169,169,169],darkgreen:[0,100,0],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkviolet:[148,0,211],fuchsia:[255,0,255],gold:[255,215,0],green:[0,128,0],indigo:[75,0,130],khaki:[240,230,140],lightblue:[173,216,230],lightcyan:[224,255,255],lightgreen:[144,238,144],lightgrey:[211, +211,211],lightpink:[255,182,193],lightyellow:[255,255,224],lime:[0,255,0],magenta:[255,0,255],maroon:[128,0,0],navy:[0,0,128],olive:[128,128,0],orange:[255,165,0],pink:[255,192,203],purple:[128,0,128],violet:[128,0,128],red:[255,0,0],silver:[192,192,192],white:[255,255,255],yellow:[255,255,0],transparent:[255,255,255]},q=["add","remove","toggle"],t={border:1,borderBottom:1,borderColor:1,borderLeft:1,borderRight:1,borderTop:1,borderWidth:1,margin:1,padding:1};f.effects.animateClass=function(c,a,b, +d){if(f.isFunction(b)){d=b;b=null}return this.queue(function(){var e=f(this),g=e.attr("style")||" ",h=p(o.call(this)),r,v=e.attr("class");f.each(q,function(w,i){c[i]&&e[i+"Class"](c[i])});r=p(o.call(this));e.attr("class",v);e.animate(u(h,r),{queue:false,duration:a,easing:b,complete:function(){f.each(q,function(w,i){c[i]&&e[i+"Class"](c[i])});if(typeof e.attr("style")=="object"){e.attr("style").cssText="";e.attr("style").cssText=g}else e.attr("style",g);d&&d.apply(this,arguments);f.dequeue(this)}})})}; +f.fn.extend({_addClass:f.fn.addClass,addClass:function(c,a,b,d){return a?f.effects.animateClass.apply(this,[{add:c},a,b,d]):this._addClass(c)},_removeClass:f.fn.removeClass,removeClass:function(c,a,b,d){return a?f.effects.animateClass.apply(this,[{remove:c},a,b,d]):this._removeClass(c)},_toggleClass:f.fn.toggleClass,toggleClass:function(c,a,b,d,e){return typeof a=="boolean"||a===j?b?f.effects.animateClass.apply(this,[a?{add:c}:{remove:c},b,d,e]):this._toggleClass(c,a):f.effects.animateClass.apply(this, +[{toggle:c},a,b,d])},switchClass:function(c,a,b,d,e){return f.effects.animateClass.apply(this,[{add:a,remove:c},b,d,e])}});f.extend(f.effects,{version:"1.8.16",save:function(c,a){for(var b=0;b").addClass("ui-effects-wrapper").css({fontSize:"100%",background:"transparent",border:"none",margin:0,padding:0}), +d=document.activeElement;c.wrap(b);if(c[0]===d||f.contains(c[0],d))f(d).focus();b=c.parent();if(c.css("position")=="static"){b.css({position:"relative"});c.css({position:"relative"})}else{f.extend(a,{position:c.css("position"),zIndex:c.css("z-index")});f.each(["top","left","bottom","right"],function(e,g){a[g]=c.css(g);if(isNaN(parseInt(a[g],10)))a[g]="auto"});c.css({position:"relative",top:0,left:0,right:"auto",bottom:"auto"})}return b.css(a).show()},removeWrapper:function(c){var a,b=document.activeElement; +if(c.parent().is(".ui-effects-wrapper")){a=c.parent().replaceWith(c);if(c[0]===b||f.contains(c[0],b))f(b).focus();return a}return c},setTransition:function(c,a,b,d){d=d||{};f.each(a,function(e,g){unit=c.cssUnit(g);if(unit[0]>0)d[g]=unit[0]*b+unit[1]});return d}});f.fn.extend({effect:function(c){var a=k.apply(this,arguments),b={options:a[1],duration:a[2],callback:a[3]};a=b.options.mode;var d=f.effects[c];if(f.fx.off||!d)return a?this[a](b.duration,b.callback):this.each(function(){b.callback&&b.callback.call(this)}); +return d.call(this,b)},_show:f.fn.show,show:function(c){if(l(c))return this._show.apply(this,arguments);else{var a=k.apply(this,arguments);a[1].mode="show";return this.effect.apply(this,a)}},_hide:f.fn.hide,hide:function(c){if(l(c))return this._hide.apply(this,arguments);else{var a=k.apply(this,arguments);a[1].mode="hide";return this.effect.apply(this,a)}},__toggle:f.fn.toggle,toggle:function(c){if(l(c)||typeof c==="boolean"||f.isFunction(c))return this.__toggle.apply(this,arguments);else{var a=k.apply(this, +arguments);a[1].mode="toggle";return this.effect.apply(this,a)}},cssUnit:function(c){var a=this.css(c),b=[];f.each(["em","px","%","pt"],function(d,e){if(a.indexOf(e)>0)b=[parseFloat(a),e]});return b}});f.easing.jswing=f.easing.swing;f.extend(f.easing,{def:"easeOutQuad",swing:function(c,a,b,d,e){return f.easing[f.easing.def](c,a,b,d,e)},easeInQuad:function(c,a,b,d,e){return d*(a/=e)*a+b},easeOutQuad:function(c,a,b,d,e){return-d*(a/=e)*(a-2)+b},easeInOutQuad:function(c,a,b,d,e){if((a/=e/2)<1)return d/ +2*a*a+b;return-d/2*(--a*(a-2)-1)+b},easeInCubic:function(c,a,b,d,e){return d*(a/=e)*a*a+b},easeOutCubic:function(c,a,b,d,e){return d*((a=a/e-1)*a*a+1)+b},easeInOutCubic:function(c,a,b,d,e){if((a/=e/2)<1)return d/2*a*a*a+b;return d/2*((a-=2)*a*a+2)+b},easeInQuart:function(c,a,b,d,e){return d*(a/=e)*a*a*a+b},easeOutQuart:function(c,a,b,d,e){return-d*((a=a/e-1)*a*a*a-1)+b},easeInOutQuart:function(c,a,b,d,e){if((a/=e/2)<1)return d/2*a*a*a*a+b;return-d/2*((a-=2)*a*a*a-2)+b},easeInQuint:function(c,a,b, +d,e){return d*(a/=e)*a*a*a*a+b},easeOutQuint:function(c,a,b,d,e){return d*((a=a/e-1)*a*a*a*a+1)+b},easeInOutQuint:function(c,a,b,d,e){if((a/=e/2)<1)return d/2*a*a*a*a*a+b;return d/2*((a-=2)*a*a*a*a+2)+b},easeInSine:function(c,a,b,d,e){return-d*Math.cos(a/e*(Math.PI/2))+d+b},easeOutSine:function(c,a,b,d,e){return d*Math.sin(a/e*(Math.PI/2))+b},easeInOutSine:function(c,a,b,d,e){return-d/2*(Math.cos(Math.PI*a/e)-1)+b},easeInExpo:function(c,a,b,d,e){return a==0?b:d*Math.pow(2,10*(a/e-1))+b},easeOutExpo:function(c, +a,b,d,e){return a==e?b+d:d*(-Math.pow(2,-10*a/e)+1)+b},easeInOutExpo:function(c,a,b,d,e){if(a==0)return b;if(a==e)return b+d;if((a/=e/2)<1)return d/2*Math.pow(2,10*(a-1))+b;return d/2*(-Math.pow(2,-10*--a)+2)+b},easeInCirc:function(c,a,b,d,e){return-d*(Math.sqrt(1-(a/=e)*a)-1)+b},easeOutCirc:function(c,a,b,d,e){return d*Math.sqrt(1-(a=a/e-1)*a)+b},easeInOutCirc:function(c,a,b,d,e){if((a/=e/2)<1)return-d/2*(Math.sqrt(1-a*a)-1)+b;return d/2*(Math.sqrt(1-(a-=2)*a)+1)+b},easeInElastic:function(c,a,b, +d,e){c=1.70158;var g=0,h=d;if(a==0)return b;if((a/=e)==1)return b+d;g||(g=e*0.3);if(h").css({position:"absolute",visibility:"visible",left:-f*(h/d),top:-e*(i/c)}).parent().addClass("ui-effects-explode").css({position:"absolute",overflow:"hidden",width:h/d,height:i/c,left:g.left+f*(h/d)+(a.options.mode=="show"?(f-Math.floor(d/2))*(h/d):0),top:g.top+e*(i/c)+(a.options.mode=="show"?(e-Math.floor(c/2))*(i/c):0),opacity:a.options.mode=="show"?0:1}).animate({left:g.left+f*(h/d)+(a.options.mode=="show"?0:(f-Math.floor(d/2))*(h/d)),top:g.top+ +e*(i/c)+(a.options.mode=="show"?0:(e-Math.floor(c/2))*(i/c)),opacity:a.options.mode=="show"?1:0},a.duration||500);setTimeout(function(){a.options.mode=="show"?b.css({visibility:"visible"}):b.css({visibility:"visible"}).hide();a.callback&&a.callback.apply(b[0]);b.dequeue();j("div.ui-effects-explode").remove()},a.duration||500)})}})(jQuery); +;/* + * jQuery UI Effects Fade 1.8.16 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Effects/Fade + * + * Depends: + * jquery.effects.core.js + */ +(function(b){b.effects.fade=function(a){return this.queue(function(){var c=b(this),d=b.effects.setMode(c,a.options.mode||"hide");c.animate({opacity:d},{queue:false,duration:a.duration,easing:a.options.easing,complete:function(){a.callback&&a.callback.apply(this,arguments);c.dequeue()}})})}})(jQuery); +;/* + * jQuery UI Effects Fold 1.8.16 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Effects/Fold + * + * Depends: + * jquery.effects.core.js + */ +(function(c){c.effects.fold=function(a){return this.queue(function(){var b=c(this),j=["position","top","bottom","left","right"],d=c.effects.setMode(b,a.options.mode||"hide"),g=a.options.size||15,h=!!a.options.horizFirst,k=a.duration?a.duration/2:c.fx.speeds._default/2;c.effects.save(b,j);b.show();var e=c.effects.createWrapper(b).css({overflow:"hidden"}),f=d=="show"!=h,l=f?["width","height"]:["height","width"];f=f?[e.width(),e.height()]:[e.height(),e.width()];var i=/([0-9]+)%/.exec(g);if(i)g=parseInt(i[1], +10)/100*f[d=="hide"?0:1];if(d=="show")e.css(h?{height:0,width:g}:{height:g,width:0});h={};i={};h[l[0]]=d=="show"?f[0]:g;i[l[1]]=d=="show"?f[1]:0;e.animate(h,k,a.options.easing).animate(i,k,a.options.easing,function(){d=="hide"&&b.hide();c.effects.restore(b,j);c.effects.removeWrapper(b);a.callback&&a.callback.apply(b[0],arguments);b.dequeue()})})}})(jQuery); +;/* + * jQuery UI Effects Highlight 1.8.16 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Effects/Highlight + * + * Depends: + * jquery.effects.core.js + */ +(function(b){b.effects.highlight=function(c){return this.queue(function(){var a=b(this),e=["backgroundImage","backgroundColor","opacity"],d=b.effects.setMode(a,c.options.mode||"show"),f={backgroundColor:a.css("backgroundColor")};if(d=="hide")f.opacity=0;b.effects.save(a,e);a.show().css({backgroundImage:"none",backgroundColor:c.options.color||"#ffff99"}).animate(f,{queue:false,duration:c.duration,easing:c.options.easing,complete:function(){d=="hide"&&a.hide();b.effects.restore(a,e);d=="show"&&!b.support.opacity&& +this.style.removeAttribute("filter");c.callback&&c.callback.apply(this,arguments);a.dequeue()}})})}})(jQuery); +;/* + * jQuery UI Effects Pulsate 1.8.16 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Effects/Pulsate + * + * Depends: + * jquery.effects.core.js + */ +(function(d){d.effects.pulsate=function(a){return this.queue(function(){var b=d(this),c=d.effects.setMode(b,a.options.mode||"show");times=(a.options.times||5)*2-1;duration=a.duration?a.duration/2:d.fx.speeds._default/2;isVisible=b.is(":visible");animateTo=0;if(!isVisible){b.css("opacity",0).show();animateTo=1}if(c=="hide"&&isVisible||c=="show"&&!isVisible)times--;for(c=0;c').appendTo(document.body).addClass(a.options.className).css({top:d.top,left:d.left,height:b.innerHeight(),width:b.innerWidth(),position:"absolute"}).animate(c,a.duration,a.options.easing,function(){f.remove();a.callback&&a.callback.apply(b[0],arguments); +b.dequeue()})})}})(jQuery); +; \ No newline at end of file diff --git a/mysite/mysite/site_media/js/jquery-ui.min.js b/mysite/mysite/site_media/js/jquery-ui.min.js new file mode 100755 index 0000000..0202506 --- /dev/null +++ b/mysite/mysite/site_media/js/jquery-ui.min.js @@ -0,0 +1,414 @@ +/*! + * jQuery UI 1.8.16 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI + */ +(function(a,d){function c(h,g){var i=h.nodeName.toLowerCase();if("area"===i){g=h.parentNode;i=g.name;if(!h.href||!i||g.nodeName.toLowerCase()!=="map")return false;h=a("img[usemap=#"+i+"]")[0];return!!h&&e(h)}return(/input|select|textarea|button|object/.test(i)?!h.disabled:"a"==i?h.href||g:g)&&e(h)}function e(h){return!a(h).parents().andSelf().filter(function(){return a.curCSS(this,"visibility")==="hidden"||a.expr.filters.hidden(this)}).length}a.ui=a.ui||{};if(!a.ui.version){a.extend(a.ui,{version:"1.8.16", +keyCode:{ALT:18,BACKSPACE:8,CAPS_LOCK:20,COMMA:188,COMMAND:91,COMMAND_LEFT:91,COMMAND_RIGHT:93,CONTROL:17,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,INSERT:45,LEFT:37,MENU:93,NUMPAD_ADD:107,NUMPAD_DECIMAL:110,NUMPAD_DIVIDE:111,NUMPAD_ENTER:108,NUMPAD_MULTIPLY:106,NUMPAD_SUBTRACT:109,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SHIFT:16,SPACE:32,TAB:9,UP:38,WINDOWS:91}});a.fn.extend({propAttr:a.fn.prop||a.fn.attr,_focus:a.fn.focus,focus:function(h,g){return typeof h==="number"?this.each(function(){var i= +this;setTimeout(function(){a(i).focus();g&&g.call(i)},h)}):this._focus.apply(this,arguments)},scrollParent:function(){var h;h=a.browser.msie&&/(static|relative)/.test(this.css("position"))||/absolute/.test(this.css("position"))?this.parents().filter(function(){return/(relative|absolute|fixed)/.test(a.curCSS(this,"position",1))&&/(auto|scroll)/.test(a.curCSS(this,"overflow",1)+a.curCSS(this,"overflow-y",1)+a.curCSS(this,"overflow-x",1))}).eq(0):this.parents().filter(function(){return/(auto|scroll)/.test(a.curCSS(this, +"overflow",1)+a.curCSS(this,"overflow-y",1)+a.curCSS(this,"overflow-x",1))}).eq(0);return/fixed/.test(this.css("position"))||!h.length?a(document):h},zIndex:function(h){if(h!==d)return this.css("zIndex",h);if(this.length){h=a(this[0]);for(var g;h.length&&h[0]!==document;){g=h.css("position");if(g==="absolute"||g==="relative"||g==="fixed"){g=parseInt(h.css("zIndex"),10);if(!isNaN(g)&&g!==0)return g}h=h.parent()}}return 0},disableSelection:function(){return this.bind((a.support.selectstart?"selectstart": +"mousedown")+".ui-disableSelection",function(h){h.preventDefault()})},enableSelection:function(){return this.unbind(".ui-disableSelection")}});a.each(["Width","Height"],function(h,g){function i(l,o,n,k){a.each(b,function(){o-=parseFloat(a.curCSS(l,"padding"+this,true))||0;if(n)o-=parseFloat(a.curCSS(l,"border"+this+"Width",true))||0;if(k)o-=parseFloat(a.curCSS(l,"margin"+this,true))||0});return o}var b=g==="Width"?["Left","Right"]:["Top","Bottom"],f=g.toLowerCase(),j={innerWidth:a.fn.innerWidth,innerHeight:a.fn.innerHeight, +outerWidth:a.fn.outerWidth,outerHeight:a.fn.outerHeight};a.fn["inner"+g]=function(l){if(l===d)return j["inner"+g].call(this);return this.each(function(){a(this).css(f,i(this,l)+"px")})};a.fn["outer"+g]=function(l,o){if(typeof l!=="number")return j["outer"+g].call(this,l);return this.each(function(){a(this).css(f,i(this,l,true,o)+"px")})}});a.extend(a.expr[":"],{data:function(h,g,i){return!!a.data(h,i[3])},focusable:function(h){return c(h,!isNaN(a.attr(h,"tabindex")))},tabbable:function(h){var g=a.attr(h, +"tabindex"),i=isNaN(g);return(i||g>=0)&&c(h,!i)}});a(function(){var h=document.body,g=h.appendChild(g=document.createElement("div"));a.extend(g.style,{minHeight:"100px",height:"auto",padding:0,borderWidth:0});a.support.minHeight=g.offsetHeight===100;a.support.selectstart="onselectstart"in g;h.removeChild(g).style.display="none"});a.extend(a.ui,{plugin:{add:function(h,g,i){h=a.ui[h].prototype;for(var b in i){h.plugins[b]=h.plugins[b]||[];h.plugins[b].push([g,i[b]])}},call:function(h,g,i){if((g=h.plugins[g])&& +h.element[0].parentNode)for(var b=0;b0)return true;h[g]=1;i=h[g]>0;h[g]=0;return i},isOverAxis:function(h,g,i){return h>g&&h=9)&&!c.button)return this._mouseUp(c);if(this._mouseStarted){this._mouseDrag(c);return c.preventDefault()}if(this._mouseDistanceMet(c)&&this._mouseDelayMet(c))(this._mouseStarted=this._mouseStart(this._mouseDownEvent,c)!==false)?this._mouseDrag(c):this._mouseUp(c);return!this._mouseStarted},_mouseUp:function(c){a(document).unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate);if(this._mouseStarted){this._mouseStarted= +false;c.target==this._mouseDownEvent.target&&a.data(c.target,this.widgetName+".preventClickEvent",true);this._mouseStop(c)}return false},_mouseDistanceMet:function(c){return Math.max(Math.abs(this._mouseDownEvent.pageX-c.pageX),Math.abs(this._mouseDownEvent.pageY-c.pageY))>=this.options.distance},_mouseDelayMet:function(){return this.mouseDelayMet},_mouseStart:function(){},_mouseDrag:function(){},_mouseStop:function(){},_mouseCapture:function(){return true}})})(jQuery); +(function(a){a.widget("ui.draggable",a.ui.mouse,{widgetEventPrefix:"drag",options:{addClasses:true,appendTo:"parent",axis:false,connectToSortable:false,containment:false,cursor:"auto",cursorAt:false,grid:false,handle:false,helper:"original",iframeFix:false,opacity:false,refreshPositions:false,revert:false,revertDuration:500,scope:"default",scroll:true,scrollSensitivity:20,scrollSpeed:20,snap:false,snapMode:"both",snapTolerance:20,stack:false,zIndex:false},_create:function(){if(this.options.helper== +"original"&&!/^(?:r|a|f)/.test(this.element.css("position")))this.element[0].style.position="relative";this.options.addClasses&&this.element.addClass("ui-draggable");this.options.disabled&&this.element.addClass("ui-draggable-disabled");this._mouseInit()},destroy:function(){if(this.element.data("draggable")){this.element.removeData("draggable").unbind(".draggable").removeClass("ui-draggable ui-draggable-dragging ui-draggable-disabled");this._mouseDestroy();return this}},_mouseCapture:function(d){var c= +this.options;if(this.helper||c.disabled||a(d.target).is(".ui-resizable-handle"))return false;this.handle=this._getHandle(d);if(!this.handle)return false;if(c.iframeFix)a(c.iframeFix===true?"iframe":c.iframeFix).each(function(){a('
    ').css({width:this.offsetWidth+"px",height:this.offsetHeight+"px",position:"absolute",opacity:"0.001",zIndex:1E3}).css(a(this).offset()).appendTo("body")});return true},_mouseStart:function(d){var c=this.options; +this.helper=this._createHelper(d);this._cacheHelperProportions();if(a.ui.ddmanager)a.ui.ddmanager.current=this;this._cacheMargins();this.cssPosition=this.helper.css("position");this.scrollParent=this.helper.scrollParent();this.offset=this.positionAbs=this.element.offset();this.offset={top:this.offset.top-this.margins.top,left:this.offset.left-this.margins.left};a.extend(this.offset,{click:{left:d.pageX-this.offset.left,top:d.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()}); +this.originalPosition=this.position=this._generatePosition(d);this.originalPageX=d.pageX;this.originalPageY=d.pageY;c.cursorAt&&this._adjustOffsetFromHelper(c.cursorAt);c.containment&&this._setContainment();if(this._trigger("start",d)===false){this._clear();return false}this._cacheHelperProportions();a.ui.ddmanager&&!c.dropBehaviour&&a.ui.ddmanager.prepareOffsets(this,d);this.helper.addClass("ui-draggable-dragging");this._mouseDrag(d,true);a.ui.ddmanager&&a.ui.ddmanager.dragStart(this,d);return true}, +_mouseDrag:function(d,c){this.position=this._generatePosition(d);this.positionAbs=this._convertPositionTo("absolute");if(!c){c=this._uiHash();if(this._trigger("drag",d,c)===false){this._mouseUp({});return false}this.position=c.position}if(!this.options.axis||this.options.axis!="y")this.helper[0].style.left=this.position.left+"px";if(!this.options.axis||this.options.axis!="x")this.helper[0].style.top=this.position.top+"px";a.ui.ddmanager&&a.ui.ddmanager.drag(this,d);return false},_mouseStop:function(d){var c= +false;if(a.ui.ddmanager&&!this.options.dropBehaviour)c=a.ui.ddmanager.drop(this,d);if(this.dropped){c=this.dropped;this.dropped=false}if((!this.element[0]||!this.element[0].parentNode)&&this.options.helper=="original")return false;if(this.options.revert=="invalid"&&!c||this.options.revert=="valid"&&c||this.options.revert===true||a.isFunction(this.options.revert)&&this.options.revert.call(this.element,c)){var e=this;a(this.helper).animate(this.originalPosition,parseInt(this.options.revertDuration, +10),function(){e._trigger("stop",d)!==false&&e._clear()})}else this._trigger("stop",d)!==false&&this._clear();return false},_mouseUp:function(d){this.options.iframeFix===true&&a("div.ui-draggable-iframeFix").each(function(){this.parentNode.removeChild(this)});a.ui.ddmanager&&a.ui.ddmanager.dragStop(this,d);return a.ui.mouse.prototype._mouseUp.call(this,d)},cancel:function(){this.helper.is(".ui-draggable-dragging")?this._mouseUp({}):this._clear();return this},_getHandle:function(d){var c=!this.options.handle|| +!a(this.options.handle,this.element).length?true:false;a(this.options.handle,this.element).find("*").andSelf().each(function(){if(this==d.target)c=true});return c},_createHelper:function(d){var c=this.options;d=a.isFunction(c.helper)?a(c.helper.apply(this.element[0],[d])):c.helper=="clone"?this.element.clone().removeAttr("id"):this.element;d.parents("body").length||d.appendTo(c.appendTo=="parent"?this.element[0].parentNode:c.appendTo);d[0]!=this.element[0]&&!/(fixed|absolute)/.test(d.css("position"))&& +d.css("position","absolute");return d},_adjustOffsetFromHelper:function(d){if(typeof d=="string")d=d.split(" ");if(a.isArray(d))d={left:+d[0],top:+d[1]||0};if("left"in d)this.offset.click.left=d.left+this.margins.left;if("right"in d)this.offset.click.left=this.helperProportions.width-d.right+this.margins.left;if("top"in d)this.offset.click.top=d.top+this.margins.top;if("bottom"in d)this.offset.click.top=this.helperProportions.height-d.bottom+this.margins.top},_getParentOffset:function(){this.offsetParent= +this.helper.offsetParent();var d=this.offsetParent.offset();if(this.cssPosition=="absolute"&&this.scrollParent[0]!=document&&a.ui.contains(this.scrollParent[0],this.offsetParent[0])){d.left+=this.scrollParent.scrollLeft();d.top+=this.scrollParent.scrollTop()}if(this.offsetParent[0]==document.body||this.offsetParent[0].tagName&&this.offsetParent[0].tagName.toLowerCase()=="html"&&a.browser.msie)d={top:0,left:0};return{top:d.top+(parseInt(this.offsetParent.css("borderTopWidth"),10)||0),left:d.left+(parseInt(this.offsetParent.css("borderLeftWidth"), +10)||0)}},_getRelativeOffset:function(){if(this.cssPosition=="relative"){var d=this.element.position();return{top:d.top-(parseInt(this.helper.css("top"),10)||0)+this.scrollParent.scrollTop(),left:d.left-(parseInt(this.helper.css("left"),10)||0)+this.scrollParent.scrollLeft()}}else return{top:0,left:0}},_cacheMargins:function(){this.margins={left:parseInt(this.element.css("marginLeft"),10)||0,top:parseInt(this.element.css("marginTop"),10)||0,right:parseInt(this.element.css("marginRight"),10)||0,bottom:parseInt(this.element.css("marginBottom"), +10)||0}},_cacheHelperProportions:function(){this.helperProportions={width:this.helper.outerWidth(),height:this.helper.outerHeight()}},_setContainment:function(){var d=this.options;if(d.containment=="parent")d.containment=this.helper[0].parentNode;if(d.containment=="document"||d.containment=="window")this.containment=[d.containment=="document"?0:a(window).scrollLeft()-this.offset.relative.left-this.offset.parent.left,d.containment=="document"?0:a(window).scrollTop()-this.offset.relative.top-this.offset.parent.top, +(d.containment=="document"?0:a(window).scrollLeft())+a(d.containment=="document"?document:window).width()-this.helperProportions.width-this.margins.left,(d.containment=="document"?0:a(window).scrollTop())+(a(d.containment=="document"?document:window).height()||document.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top];if(!/^(document|window|parent)$/.test(d.containment)&&d.containment.constructor!=Array){d=a(d.containment);var c=d[0];if(c){d.offset();var e=a(c).css("overflow")!= +"hidden";this.containment=[(parseInt(a(c).css("borderLeftWidth"),10)||0)+(parseInt(a(c).css("paddingLeft"),10)||0),(parseInt(a(c).css("borderTopWidth"),10)||0)+(parseInt(a(c).css("paddingTop"),10)||0),(e?Math.max(c.scrollWidth,c.offsetWidth):c.offsetWidth)-(parseInt(a(c).css("borderLeftWidth"),10)||0)-(parseInt(a(c).css("paddingRight"),10)||0)-this.helperProportions.width-this.margins.left-this.margins.right,(e?Math.max(c.scrollHeight,c.offsetHeight):c.offsetHeight)-(parseInt(a(c).css("borderTopWidth"), +10)||0)-(parseInt(a(c).css("paddingBottom"),10)||0)-this.helperProportions.height-this.margins.top-this.margins.bottom];this.relative_container=d}}else if(d.containment.constructor==Array)this.containment=d.containment},_convertPositionTo:function(d,c){if(!c)c=this.position;d=d=="absolute"?1:-1;var e=this.cssPosition=="absolute"&&!(this.scrollParent[0]!=document&&a.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,h=/(html|body)/i.test(e[0].tagName);return{top:c.top+ +this.offset.relative.top*d+this.offset.parent.top*d-(a.browser.safari&&a.browser.version<526&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollTop():h?0:e.scrollTop())*d),left:c.left+this.offset.relative.left*d+this.offset.parent.left*d-(a.browser.safari&&a.browser.version<526&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():h?0:e.scrollLeft())*d)}},_generatePosition:function(d){var c=this.options,e=this.cssPosition=="absolute"&& +!(this.scrollParent[0]!=document&&a.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,h=/(html|body)/i.test(e[0].tagName),g=d.pageX,i=d.pageY;if(this.originalPosition){var b;if(this.containment){if(this.relative_container){b=this.relative_container.offset();b=[this.containment[0]+b.left,this.containment[1]+b.top,this.containment[2]+b.left,this.containment[3]+b.top]}else b=this.containment;if(d.pageX-this.offset.click.leftb[2])g=b[2]+this.offset.click.left;if(d.pageY-this.offset.click.top>b[3])i=b[3]+this.offset.click.top}if(c.grid){i=c.grid[1]?this.originalPageY+Math.round((i-this.originalPageY)/c.grid[1])*c.grid[1]:this.originalPageY;i=b?!(i-this.offset.click.topb[3])?i:!(i-this.offset.click.topb[2])?g:!(g-this.offset.click.left=0;l--){var o=e.snapElements[l].left,n=o+e.snapElements[l].width,k=e.snapElements[l].top,m=k+e.snapElements[l].height;if(o-g=l&&i<=o||b>=l&&b<=o||io)&&(h>= +f&&h<=j||g>=f&&g<=j||hj);default:return false}};a.ui.ddmanager={current:null,droppables:{"default":[]},prepareOffsets:function(d,c){var e=a.ui.ddmanager.droppables[d.options.scope]||[],h=c?c.type:null,g=(d.currentItem||d.element).find(":data(droppable)").andSelf(),i=0;a:for(;i').css({position:this.element.css("position"),width:this.element.outerWidth(),height:this.element.outerHeight(), +top:this.element.css("top"),left:this.element.css("left")}));this.element=this.element.parent().data("resizable",this.element.data("resizable"));this.elementIsWrapper=true;this.element.css({marginLeft:this.originalElement.css("marginLeft"),marginTop:this.originalElement.css("marginTop"),marginRight:this.originalElement.css("marginRight"),marginBottom:this.originalElement.css("marginBottom")});this.originalElement.css({marginLeft:0,marginTop:0,marginRight:0,marginBottom:0});this.originalResizeStyle= +this.originalElement.css("resize");this.originalElement.css("resize","none");this._proportionallyResizeElements.push(this.originalElement.css({position:"static",zoom:1,display:"block"}));this.originalElement.css({margin:this.originalElement.css("margin")});this._proportionallyResize()}this.handles=h.handles||(!a(".ui-resizable-handle",this.element).length?"e,s,se":{n:".ui-resizable-n",e:".ui-resizable-e",s:".ui-resizable-s",w:".ui-resizable-w",se:".ui-resizable-se",sw:".ui-resizable-sw",ne:".ui-resizable-ne", +nw:".ui-resizable-nw"});if(this.handles.constructor==String){if(this.handles=="all")this.handles="n,e,s,w,se,sw,ne,nw";var g=this.handles.split(",");this.handles={};for(var i=0;i');/sw|se|ne|nw/.test(b)&&f.css({zIndex:++h.zIndex});"se"==b&&f.addClass("ui-icon ui-icon-gripsmall-diagonal-se");this.handles[b]=".ui-resizable-"+b;this.element.append(f)}}this._renderAxis=function(j){j=j||this.element;for(var l in this.handles){if(this.handles[l].constructor== +String)this.handles[l]=a(this.handles[l],this.element).show();if(this.elementIsWrapper&&this.originalElement[0].nodeName.match(/textarea|input|select|button/i)){var o=a(this.handles[l],this.element),n=0;n=/sw|ne|nw|se|n|s/.test(l)?o.outerHeight():o.outerWidth();o=["padding",/ne|nw|n/.test(l)?"Top":/se|sw|s/.test(l)?"Bottom":/^e$/.test(l)?"Right":"Left"].join("");j.css(o,n);this._proportionallyResize()}a(this.handles[l])}};this._renderAxis(this.element);this._handles=a(".ui-resizable-handle",this.element).disableSelection(); +this._handles.mouseover(function(){if(!e.resizing){if(this.className)var j=this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i);e.axis=j&&j[1]?j[1]:"se"}});if(h.autoHide){this._handles.hide();a(this.element).addClass("ui-resizable-autohide").hover(function(){if(!h.disabled){a(this).removeClass("ui-resizable-autohide");e._handles.show()}},function(){if(!h.disabled)if(!e.resizing){a(this).addClass("ui-resizable-autohide");e._handles.hide()}})}this._mouseInit()},destroy:function(){this._mouseDestroy(); +var e=function(g){a(g).removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing").removeData("resizable").unbind(".resizable").find(".ui-resizable-handle").remove()};if(this.elementIsWrapper){e(this.element);var h=this.element;h.after(this.originalElement.css({position:h.css("position"),width:h.outerWidth(),height:h.outerHeight(),top:h.css("top"),left:h.css("left")})).remove()}this.originalElement.css("resize",this.originalResizeStyle);e(this.originalElement);return this},_mouseCapture:function(e){var h= +false;for(var g in this.handles)if(a(this.handles[g])[0]==e.target)h=true;return!this.options.disabled&&h},_mouseStart:function(e){var h=this.options,g=this.element.position(),i=this.element;this.resizing=true;this.documentScroll={top:a(document).scrollTop(),left:a(document).scrollLeft()};if(i.is(".ui-draggable")||/absolute/.test(i.css("position")))i.css({position:"absolute",top:g.top,left:g.left});a.browser.opera&&/relative/.test(i.css("position"))&&i.css({position:"relative",top:"auto",left:"auto"}); +this._renderProxy();g=d(this.helper.css("left"));var b=d(this.helper.css("top"));if(h.containment){g+=a(h.containment).scrollLeft()||0;b+=a(h.containment).scrollTop()||0}this.offset=this.helper.offset();this.position={left:g,top:b};this.size=this._helper?{width:i.outerWidth(),height:i.outerHeight()}:{width:i.width(),height:i.height()};this.originalSize=this._helper?{width:i.outerWidth(),height:i.outerHeight()}:{width:i.width(),height:i.height()};this.originalPosition={left:g,top:b};this.sizeDiff= +{width:i.outerWidth()-i.width(),height:i.outerHeight()-i.height()};this.originalMousePosition={left:e.pageX,top:e.pageY};this.aspectRatio=typeof h.aspectRatio=="number"?h.aspectRatio:this.originalSize.width/this.originalSize.height||1;h=a(".ui-resizable-"+this.axis).css("cursor");a("body").css("cursor",h=="auto"?this.axis+"-resize":h);i.addClass("ui-resizable-resizing");this._propagate("start",e);return true},_mouseDrag:function(e){var h=this.helper,g=this.originalMousePosition,i=this._change[this.axis]; +if(!i)return false;g=i.apply(this,[e,e.pageX-g.left||0,e.pageY-g.top||0]);this._updateVirtualBoundaries(e.shiftKey);if(this._aspectRatio||e.shiftKey)g=this._updateRatio(g,e);g=this._respectSize(g,e);this._propagate("resize",e);h.css({top:this.position.top+"px",left:this.position.left+"px",width:this.size.width+"px",height:this.size.height+"px"});!this._helper&&this._proportionallyResizeElements.length&&this._proportionallyResize();this._updateCache(g);this._trigger("resize",e,this.ui());return false}, +_mouseStop:function(e){this.resizing=false;var h=this.options,g=this;if(this._helper){var i=this._proportionallyResizeElements,b=i.length&&/textarea/i.test(i[0].nodeName);i=b&&a.ui.hasScroll(i[0],"left")?0:g.sizeDiff.height;b=b?0:g.sizeDiff.width;b={width:g.helper.width()-b,height:g.helper.height()-i};i=parseInt(g.element.css("left"),10)+(g.position.left-g.originalPosition.left)||null;var f=parseInt(g.element.css("top"),10)+(g.position.top-g.originalPosition.top)||null;h.animate||this.element.css(a.extend(b, +{top:f,left:i}));g.helper.height(g.size.height);g.helper.width(g.size.width);this._helper&&!h.animate&&this._proportionallyResize()}a("body").css("cursor","auto");this.element.removeClass("ui-resizable-resizing");this._propagate("stop",e);this._helper&&this.helper.remove();return false},_updateVirtualBoundaries:function(e){var h=this.options,g,i,b;h={minWidth:c(h.minWidth)?h.minWidth:0,maxWidth:c(h.maxWidth)?h.maxWidth:Infinity,minHeight:c(h.minHeight)?h.minHeight:0,maxHeight:c(h.maxHeight)?h.maxHeight: +Infinity};if(this._aspectRatio||e){e=h.minHeight*this.aspectRatio;i=h.minWidth/this.aspectRatio;g=h.maxHeight*this.aspectRatio;b=h.maxWidth/this.aspectRatio;if(e>h.minWidth)h.minWidth=e;if(i>h.minHeight)h.minHeight=i;if(ge.width,j=c(e.height)&&h.minHeight&&h.minHeight>e.height;if(f)e.width=h.minWidth;if(j)e.height=h.minHeight;if(i)e.width=h.maxWidth;if(b)e.height=h.maxHeight;var l=this.originalPosition.left+this.originalSize.width,o=this.position.top+this.size.height,n=/sw|nw|w/.test(g);g=/nw|ne|n/.test(g);if(f&&n)e.left=l-h.minWidth;if(i&&n)e.left=l-h.maxWidth;if(j&&g)e.top=o-h.minHeight;if(b&&g)e.top=o-h.maxHeight;if((h=!e.width&&!e.height)&&!e.left&&e.top)e.top=null;else if(h&&!e.top&&e.left)e.left= +null;return e},_proportionallyResize:function(){if(this._proportionallyResizeElements.length)for(var e=this.helper||this.element,h=0;h');var h=a.browser.msie&&a.browser.version<7,g=h?1:0;h=h?2:-1;this.helper.addClass(this._helper).css({width:this.element.outerWidth()+ +h,height:this.element.outerHeight()+h,position:"absolute",left:this.elementOffset.left-g+"px",top:this.elementOffset.top-g+"px",zIndex:++e.zIndex});this.helper.appendTo("body").disableSelection()}else this.helper=this.element},_change:{e:function(e,h){return{width:this.originalSize.width+h}},w:function(e,h){return{left:this.originalPosition.left+h,width:this.originalSize.width-h}},n:function(e,h,g){return{top:this.originalPosition.top+g,height:this.originalSize.height-g}},s:function(e,h,g){return{height:this.originalSize.height+ +g}},se:function(e,h,g){return a.extend(this._change.s.apply(this,arguments),this._change.e.apply(this,[e,h,g]))},sw:function(e,h,g){return a.extend(this._change.s.apply(this,arguments),this._change.w.apply(this,[e,h,g]))},ne:function(e,h,g){return a.extend(this._change.n.apply(this,arguments),this._change.e.apply(this,[e,h,g]))},nw:function(e,h,g){return a.extend(this._change.n.apply(this,arguments),this._change.w.apply(this,[e,h,g]))}},_propagate:function(e,h){a.ui.plugin.call(this,e,[h,this.ui()]); +e!="resize"&&this._trigger(e,h,this.ui())},plugins:{},ui:function(){return{originalElement:this.originalElement,element:this.element,helper:this.helper,position:this.position,size:this.size,originalSize:this.originalSize,originalPosition:this.originalPosition}}});a.extend(a.ui.resizable,{version:"1.8.16"});a.ui.plugin.add("resizable","alsoResize",{start:function(){var e=a(this).data("resizable").options,h=function(g){a(g).each(function(){var i=a(this);i.data("resizable-alsoresize",{width:parseInt(i.width(), +10),height:parseInt(i.height(),10),left:parseInt(i.css("left"),10),top:parseInt(i.css("top"),10),position:i.css("position")})})};if(typeof e.alsoResize=="object"&&!e.alsoResize.parentNode)if(e.alsoResize.length){e.alsoResize=e.alsoResize[0];h(e.alsoResize)}else a.each(e.alsoResize,function(g){h(g)});else h(e.alsoResize)},resize:function(e,h){var g=a(this).data("resizable");e=g.options;var i=g.originalSize,b=g.originalPosition,f={height:g.size.height-i.height||0,width:g.size.width-i.width||0,top:g.position.top- +b.top||0,left:g.position.left-b.left||0},j=function(l,o){a(l).each(function(){var n=a(this),k=a(this).data("resizable-alsoresize"),m={},p=o&&o.length?o:n.parents(h.originalElement[0]).length?["width","height"]:["width","height","top","left"];a.each(p,function(q,s){if((q=(k[s]||0)+(f[s]||0))&&q>=0)m[s]=q||null});if(a.browser.opera&&/relative/.test(n.css("position"))){g._revertToRelativePosition=true;n.css({position:"absolute",top:"auto",left:"auto"})}n.css(m)})};typeof e.alsoResize=="object"&&!e.alsoResize.nodeType? +a.each(e.alsoResize,function(l,o){j(l,o)}):j(e.alsoResize)},stop:function(){var e=a(this).data("resizable"),h=e.options,g=function(i){a(i).each(function(){var b=a(this);b.css({position:b.data("resizable-alsoresize").position})})};if(e._revertToRelativePosition){e._revertToRelativePosition=false;typeof h.alsoResize=="object"&&!h.alsoResize.nodeType?a.each(h.alsoResize,function(i){g(i)}):g(h.alsoResize)}a(this).removeData("resizable-alsoresize")}});a.ui.plugin.add("resizable","animate",{stop:function(e){var h= +a(this).data("resizable"),g=h.options,i=h._proportionallyResizeElements,b=i.length&&/textarea/i.test(i[0].nodeName),f=b&&a.ui.hasScroll(i[0],"left")?0:h.sizeDiff.height;b={width:h.size.width-(b?0:h.sizeDiff.width),height:h.size.height-f};f=parseInt(h.element.css("left"),10)+(h.position.left-h.originalPosition.left)||null;var j=parseInt(h.element.css("top"),10)+(h.position.top-h.originalPosition.top)||null;h.element.animate(a.extend(b,j&&f?{top:j,left:f}:{}),{duration:g.animateDuration,easing:g.animateEasing, +step:function(){var l={width:parseInt(h.element.css("width"),10),height:parseInt(h.element.css("height"),10),top:parseInt(h.element.css("top"),10),left:parseInt(h.element.css("left"),10)};i&&i.length&&a(i[0]).css({width:l.width,height:l.height});h._updateCache(l);h._propagate("resize",e)}})}});a.ui.plugin.add("resizable","containment",{start:function(){var e=a(this).data("resizable"),h=e.element,g=e.options.containment;if(h=g instanceof a?g.get(0):/parent/.test(g)?h.parent().get(0):g){e.containerElement= +a(h);if(/document/.test(g)||g==document){e.containerOffset={left:0,top:0};e.containerPosition={left:0,top:0};e.parentData={element:a(document),left:0,top:0,width:a(document).width(),height:a(document).height()||document.body.parentNode.scrollHeight}}else{var i=a(h),b=[];a(["Top","Right","Left","Bottom"]).each(function(l,o){b[l]=d(i.css("padding"+o))});e.containerOffset=i.offset();e.containerPosition=i.position();e.containerSize={height:i.innerHeight()-b[3],width:i.innerWidth()-b[1]};g=e.containerOffset; +var f=e.containerSize.height,j=e.containerSize.width;j=a.ui.hasScroll(h,"left")?h.scrollWidth:j;f=a.ui.hasScroll(h)?h.scrollHeight:f;e.parentData={element:h,left:g.left,top:g.top,width:j,height:f}}}},resize:function(e){var h=a(this).data("resizable"),g=h.options,i=h.containerOffset,b=h.position;e=h._aspectRatio||e.shiftKey;var f={top:0,left:0},j=h.containerElement;if(j[0]!=document&&/static/.test(j.css("position")))f=i;if(b.left<(h._helper?i.left:0)){h.size.width+=h._helper?h.position.left-i.left: +h.position.left-f.left;if(e)h.size.height=h.size.width/g.aspectRatio;h.position.left=g.helper?i.left:0}if(b.top<(h._helper?i.top:0)){h.size.height+=h._helper?h.position.top-i.top:h.position.top;if(e)h.size.width=h.size.height*g.aspectRatio;h.position.top=h._helper?i.top:0}h.offset.left=h.parentData.left+h.position.left;h.offset.top=h.parentData.top+h.position.top;g=Math.abs((h._helper?h.offset.left-f.left:h.offset.left-f.left)+h.sizeDiff.width);i=Math.abs((h._helper?h.offset.top-f.top:h.offset.top- +i.top)+h.sizeDiff.height);b=h.containerElement.get(0)==h.element.parent().get(0);f=/relative|absolute/.test(h.containerElement.css("position"));if(b&&f)g-=h.parentData.left;if(g+h.size.width>=h.parentData.width){h.size.width=h.parentData.width-g;if(e)h.size.height=h.size.width/h.aspectRatio}if(i+h.size.height>=h.parentData.height){h.size.height=h.parentData.height-i;if(e)h.size.width=h.size.height*h.aspectRatio}},stop:function(){var e=a(this).data("resizable"),h=e.options,g=e.containerOffset,i=e.containerPosition, +b=e.containerElement,f=a(e.helper),j=f.offset(),l=f.outerWidth()-e.sizeDiff.width;f=f.outerHeight()-e.sizeDiff.height;e._helper&&!h.animate&&/relative/.test(b.css("position"))&&a(this).css({left:j.left-i.left-g.left,width:l,height:f});e._helper&&!h.animate&&/static/.test(b.css("position"))&&a(this).css({left:j.left-i.left-g.left,width:l,height:f})}});a.ui.plugin.add("resizable","ghost",{start:function(){var e=a(this).data("resizable"),h=e.options,g=e.size;e.ghost=e.originalElement.clone();e.ghost.css({opacity:0.25, +display:"block",position:"relative",height:g.height,width:g.width,margin:0,left:0,top:0}).addClass("ui-resizable-ghost").addClass(typeof h.ghost=="string"?h.ghost:"");e.ghost.appendTo(e.helper)},resize:function(){var e=a(this).data("resizable");e.ghost&&e.ghost.css({position:"relative",height:e.size.height,width:e.size.width})},stop:function(){var e=a(this).data("resizable");e.ghost&&e.helper&&e.helper.get(0).removeChild(e.ghost.get(0))}});a.ui.plugin.add("resizable","grid",{resize:function(){var e= +a(this).data("resizable"),h=e.options,g=e.size,i=e.originalSize,b=e.originalPosition,f=e.axis;h.grid=typeof h.grid=="number"?[h.grid,h.grid]:h.grid;var j=Math.round((g.width-i.width)/(h.grid[0]||1))*(h.grid[0]||1);h=Math.round((g.height-i.height)/(h.grid[1]||1))*(h.grid[1]||1);if(/^(se|s|e)$/.test(f)){e.size.width=i.width+j;e.size.height=i.height+h}else if(/^(ne)$/.test(f)){e.size.width=i.width+j;e.size.height=i.height+h;e.position.top=b.top-h}else{if(/^(sw)$/.test(f)){e.size.width=i.width+j;e.size.height= +i.height+h}else{e.size.width=i.width+j;e.size.height=i.height+h;e.position.top=b.top-h}e.position.left=b.left-j}}});var d=function(e){return parseInt(e,10)||0},c=function(e){return!isNaN(parseInt(e,10))}})(jQuery); +(function(a){a.widget("ui.selectable",a.ui.mouse,{options:{appendTo:"body",autoRefresh:true,distance:0,filter:"*",tolerance:"touch"},_create:function(){var d=this;this.element.addClass("ui-selectable");this.dragged=false;var c;this.refresh=function(){c=a(d.options.filter,d.element[0]);c.each(function(){var e=a(this),h=e.offset();a.data(this,"selectable-item",{element:this,$element:e,left:h.left,top:h.top,right:h.left+e.outerWidth(),bottom:h.top+e.outerHeight(),startselected:false,selected:e.hasClass("ui-selected"), +selecting:e.hasClass("ui-selecting"),unselecting:e.hasClass("ui-unselecting")})})};this.refresh();this.selectees=c.addClass("ui-selectee");this._mouseInit();this.helper=a("
    ")},destroy:function(){this.selectees.removeClass("ui-selectee").removeData("selectable-item");this.element.removeClass("ui-selectable ui-selectable-disabled").removeData("selectable").unbind(".selectable");this._mouseDestroy();return this},_mouseStart:function(d){var c=this;this.opos=[d.pageX, +d.pageY];if(!this.options.disabled){var e=this.options;this.selectees=a(e.filter,this.element[0]);this._trigger("start",d);a(e.appendTo).append(this.helper);this.helper.css({left:d.clientX,top:d.clientY,width:0,height:0});e.autoRefresh&&this.refresh();this.selectees.filter(".ui-selected").each(function(){var h=a.data(this,"selectable-item");h.startselected=true;if(!d.metaKey){h.$element.removeClass("ui-selected");h.selected=false;h.$element.addClass("ui-unselecting");h.unselecting=true;c._trigger("unselecting", +d,{unselecting:h.element})}});a(d.target).parents().andSelf().each(function(){var h=a.data(this,"selectable-item");if(h){var g=!d.metaKey||!h.$element.hasClass("ui-selected");h.$element.removeClass(g?"ui-unselecting":"ui-selected").addClass(g?"ui-selecting":"ui-unselecting");h.unselecting=!g;h.selecting=g;(h.selected=g)?c._trigger("selecting",d,{selecting:h.element}):c._trigger("unselecting",d,{unselecting:h.element});return false}})}},_mouseDrag:function(d){var c=this;this.dragged=true;if(!this.options.disabled){var e= +this.options,h=this.opos[0],g=this.opos[1],i=d.pageX,b=d.pageY;if(h>i){var f=i;i=h;h=f}if(g>b){f=b;b=g;g=f}this.helper.css({left:h,top:g,width:i-h,height:b-g});this.selectees.each(function(){var j=a.data(this,"selectable-item");if(!(!j||j.element==c.element[0])){var l=false;if(e.tolerance=="touch")l=!(j.left>i||j.rightb||j.bottomh&&j.rightg&&j.bottom *",opacity:false,placeholder:false,revert:false,scroll:true,scrollSensitivity:20,scrollSpeed:20,scope:"default",tolerance:"intersect",zIndex:1E3},_create:function(){var d=this.options;this.containerCache={};this.element.addClass("ui-sortable"); +this.refresh();this.floating=this.items.length?d.axis==="x"||/left|right/.test(this.items[0].item.css("float"))||/inline|table-cell/.test(this.items[0].item.css("display")):false;this.offset=this.element.offset();this._mouseInit()},destroy:function(){this.element.removeClass("ui-sortable ui-sortable-disabled").removeData("sortable").unbind(".sortable");this._mouseDestroy();for(var d=this.items.length-1;d>=0;d--)this.items[d].item.removeData("sortable-item");return this},_setOption:function(d,c){if(d=== +"disabled"){this.options[d]=c;this.widget()[c?"addClass":"removeClass"]("ui-sortable-disabled")}else a.Widget.prototype._setOption.apply(this,arguments)},_mouseCapture:function(d,c){if(this.reverting)return false;if(this.options.disabled||this.options.type=="static")return false;this._refreshItems(d);var e=null,h=this;a(d.target).parents().each(function(){if(a.data(this,"sortable-item")==h){e=a(this);return false}});if(a.data(d.target,"sortable-item")==h)e=a(d.target);if(!e)return false;if(this.options.handle&& +!c){var g=false;a(this.options.handle,e).find("*").andSelf().each(function(){if(this==d.target)g=true});if(!g)return false}this.currentItem=e;this._removeCurrentsFromItems();return true},_mouseStart:function(d,c,e){c=this.options;var h=this;this.currentContainer=this;this.refreshPositions();this.helper=this._createHelper(d);this._cacheHelperProportions();this._cacheMargins();this.scrollParent=this.helper.scrollParent();this.offset=this.currentItem.offset();this.offset={top:this.offset.top-this.margins.top, +left:this.offset.left-this.margins.left};this.helper.css("position","absolute");this.cssPosition=this.helper.css("position");a.extend(this.offset,{click:{left:d.pageX-this.offset.left,top:d.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()});this.originalPosition=this._generatePosition(d);this.originalPageX=d.pageX;this.originalPageY=d.pageY;c.cursorAt&&this._adjustOffsetFromHelper(c.cursorAt);this.domPosition={prev:this.currentItem.prev()[0],parent:this.currentItem.parent()[0]}; +this.helper[0]!=this.currentItem[0]&&this.currentItem.hide();this._createPlaceholder();c.containment&&this._setContainment();if(c.cursor){if(a("body").css("cursor"))this._storedCursor=a("body").css("cursor");a("body").css("cursor",c.cursor)}if(c.opacity){if(this.helper.css("opacity"))this._storedOpacity=this.helper.css("opacity");this.helper.css("opacity",c.opacity)}if(c.zIndex){if(this.helper.css("zIndex"))this._storedZIndex=this.helper.css("zIndex");this.helper.css("zIndex",c.zIndex)}if(this.scrollParent[0]!= +document&&this.scrollParent[0].tagName!="HTML")this.overflowOffset=this.scrollParent.offset();this._trigger("start",d,this._uiHash());this._preserveHelperProportions||this._cacheHelperProportions();if(!e)for(e=this.containers.length-1;e>=0;e--)this.containers[e]._trigger("activate",d,h._uiHash(this));if(a.ui.ddmanager)a.ui.ddmanager.current=this;a.ui.ddmanager&&!c.dropBehaviour&&a.ui.ddmanager.prepareOffsets(this,d);this.dragging=true;this.helper.addClass("ui-sortable-helper");this._mouseDrag(d); +return true},_mouseDrag:function(d){this.position=this._generatePosition(d);this.positionAbs=this._convertPositionTo("absolute");if(!this.lastPositionAbs)this.lastPositionAbs=this.positionAbs;if(this.options.scroll){var c=this.options,e=false;if(this.scrollParent[0]!=document&&this.scrollParent[0].tagName!="HTML"){if(this.overflowOffset.top+this.scrollParent[0].offsetHeight-d.pageY=0;c--){e=this.items[c];var h=e.item[0],g=this._intersectsWithPointer(e);if(g)if(h!=this.currentItem[0]&&this.placeholder[g==1?"next":"prev"]()[0]!=h&&!a.ui.contains(this.placeholder[0],h)&&(this.options.type=="semi-dynamic"?!a.ui.contains(this.element[0], +h):true)){this.direction=g==1?"down":"up";if(this.options.tolerance=="pointer"||this._intersectsWithSides(e))this._rearrange(d,e);else break;this._trigger("change",d,this._uiHash());break}}this._contactContainers(d);a.ui.ddmanager&&a.ui.ddmanager.drag(this,d);this._trigger("sort",d,this._uiHash());this.lastPositionAbs=this.positionAbs;return false},_mouseStop:function(d,c){if(d){a.ui.ddmanager&&!this.options.dropBehaviour&&a.ui.ddmanager.drop(this,d);if(this.options.revert){var e=this;c=e.placeholder.offset(); +e.reverting=true;a(this.helper).animate({left:c.left-this.offset.parent.left-e.margins.left+(this.offsetParent[0]==document.body?0:this.offsetParent[0].scrollLeft),top:c.top-this.offset.parent.top-e.margins.top+(this.offsetParent[0]==document.body?0:this.offsetParent[0].scrollTop)},parseInt(this.options.revert,10)||500,function(){e._clear(d)})}else this._clear(d,c);return false}},cancel:function(){var d=this;if(this.dragging){this._mouseUp({target:null});this.options.helper=="original"?this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper"): +this.currentItem.show();for(var c=this.containers.length-1;c>=0;c--){this.containers[c]._trigger("deactivate",null,d._uiHash(this));if(this.containers[c].containerCache.over){this.containers[c]._trigger("out",null,d._uiHash(this));this.containers[c].containerCache.over=0}}}if(this.placeholder){this.placeholder[0].parentNode&&this.placeholder[0].parentNode.removeChild(this.placeholder[0]);this.options.helper!="original"&&this.helper&&this.helper[0].parentNode&&this.helper.remove();a.extend(this,{helper:null, +dragging:false,reverting:false,_noFinalSort:null});this.domPosition.prev?a(this.domPosition.prev).after(this.currentItem):a(this.domPosition.parent).prepend(this.currentItem)}return this},serialize:function(d){var c=this._getItemsAsjQuery(d&&d.connected),e=[];d=d||{};a(c).each(function(){var h=(a(d.item||this).attr(d.attribute||"id")||"").match(d.expression||/(.+)[-=_](.+)/);if(h)e.push((d.key||h[1]+"[]")+"="+(d.key&&d.expression?h[1]:h[2]))});!e.length&&d.key&&e.push(d.key+"=");return e.join("&")}, +toArray:function(d){var c=this._getItemsAsjQuery(d&&d.connected),e=[];d=d||{};c.each(function(){e.push(a(d.item||this).attr(d.attribute||"id")||"")});return e},_intersectsWith:function(d){var c=this.positionAbs.left,e=c+this.helperProportions.width,h=this.positionAbs.top,g=h+this.helperProportions.height,i=d.left,b=i+d.width,f=d.top,j=f+d.height,l=this.offset.click.top,o=this.offset.click.left;l=h+l>f&&h+li&&c+od[this.floating?"width":"height"]?l:i0?"down":"up")},_getDragHorizontalDirection:function(){var d=this.positionAbs.left-this.lastPositionAbs.left;return d!=0&&(d>0?"right":"left")},refresh:function(d){this._refreshItems(d);this.refreshPositions();return this},_connectWith:function(){var d=this.options;return d.connectWith.constructor==String?[d.connectWith]:d.connectWith},_getItemsAsjQuery:function(d){var c=[],e=[],h=this._connectWith(); +if(h&&d)for(d=h.length-1;d>=0;d--)for(var g=a(h[d]),i=g.length-1;i>=0;i--){var b=a.data(g[i],"sortable");if(b&&b!=this&&!b.options.disabled)e.push([a.isFunction(b.options.items)?b.options.items.call(b.element):a(b.options.items,b.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"),b])}e.push([a.isFunction(this.options.items)?this.options.items.call(this.element,null,{options:this.options,item:this.currentItem}):a(this.options.items,this.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"), +this]);for(d=e.length-1;d>=0;d--)e[d][0].each(function(){c.push(this)});return a(c)},_removeCurrentsFromItems:function(){for(var d=this.currentItem.find(":data(sortable-item)"),c=0;c=0;g--)for(var i=a(h[g]),b=i.length-1;b>=0;b--){var f=a.data(i[b],"sortable");if(f&&f!=this&&!f.options.disabled){e.push([a.isFunction(f.options.items)?f.options.items.call(f.element[0],d,{item:this.currentItem}):a(f.options.items,f.element),f]);this.containers.push(f)}}for(g=e.length-1;g>=0;g--){d=e[g][1];h=e[g][0];b=0;for(i=h.length;b=0;c--){var e=this.items[c];if(!(e.instance!=this.currentContainer&&this.currentContainer&&e.item[0]!=this.currentItem[0])){var h=this.options.toleranceElement?a(this.options.toleranceElement,e.item):e.item;if(!d){e.width=h.outerWidth();e.height=h.outerHeight()}h=h.offset();e.left=h.left;e.top=h.top}}if(this.options.custom&&this.options.custom.refreshContainers)this.options.custom.refreshContainers.call(this);else for(c= +this.containers.length-1;c>=0;c--){h=this.containers[c].element.offset();this.containers[c].containerCache.left=h.left;this.containers[c].containerCache.top=h.top;this.containers[c].containerCache.width=this.containers[c].element.outerWidth();this.containers[c].containerCache.height=this.containers[c].element.outerHeight()}return this},_createPlaceholder:function(d){var c=d||this,e=c.options;if(!e.placeholder||e.placeholder.constructor==String){var h=e.placeholder;e.placeholder={element:function(){var g= +a(document.createElement(c.currentItem[0].nodeName)).addClass(h||c.currentItem[0].className+" ui-sortable-placeholder").removeClass("ui-sortable-helper")[0];if(!h)g.style.visibility="hidden";return g},update:function(g,i){if(!(h&&!e.forcePlaceholderSize)){i.height()||i.height(c.currentItem.innerHeight()-parseInt(c.currentItem.css("paddingTop")||0,10)-parseInt(c.currentItem.css("paddingBottom")||0,10));i.width()||i.width(c.currentItem.innerWidth()-parseInt(c.currentItem.css("paddingLeft")||0,10)-parseInt(c.currentItem.css("paddingRight")|| +0,10))}}}}c.placeholder=a(e.placeholder.element.call(c.element,c.currentItem));c.currentItem.after(c.placeholder);e.placeholder.update(c,c.placeholder)},_contactContainers:function(d){for(var c=null,e=null,h=this.containers.length-1;h>=0;h--)if(!a.ui.contains(this.currentItem[0],this.containers[h].element[0]))if(this._intersectsWith(this.containers[h].containerCache)){if(!(c&&a.ui.contains(this.containers[h].element[0],c.element[0]))){c=this.containers[h];e=h}}else if(this.containers[h].containerCache.over){this.containers[h]._trigger("out", +d,this._uiHash(this));this.containers[h].containerCache.over=0}if(c)if(this.containers.length===1){this.containers[e]._trigger("over",d,this._uiHash(this));this.containers[e].containerCache.over=1}else if(this.currentContainer!=this.containers[e]){c=1E4;h=null;for(var g=this.positionAbs[this.containers[e].floating?"left":"top"],i=this.items.length-1;i>=0;i--)if(a.ui.contains(this.containers[e].element[0],this.items[i].item[0])){var b=this.items[i][this.containers[e].floating?"left":"top"];if(Math.abs(b- +g)this.containment[2])g=this.containment[2]+this.offset.click.left;if(d.pageY-this.offset.click.top>this.containment[3])i=this.containment[3]+this.offset.click.top}if(c.grid){i=this.originalPageY+Math.round((i- +this.originalPageY)/c.grid[1])*c.grid[1];i=this.containment?!(i-this.offset.click.topthis.containment[3])?i:!(i-this.offset.click.topthis.containment[2])?g:!(g-this.offset.click.left=0;h--)if(a.ui.contains(this.containers[h].element[0],this.currentItem[0])&&!c){e.push(function(g){return function(i){g._trigger("receive",i,this._uiHash(this))}}.call(this,this.containers[h]));e.push(function(g){return function(i){g._trigger("update",i,this._uiHash(this))}}.call(this,this.containers[h]))}}for(h=this.containers.length-1;h>=0;h--){c||e.push(function(g){return function(i){g._trigger("deactivate",i,this._uiHash(this))}}.call(this, +this.containers[h]));if(this.containers[h].containerCache.over){e.push(function(g){return function(i){g._trigger("out",i,this._uiHash(this))}}.call(this,this.containers[h]));this.containers[h].containerCache.over=0}}this._storedCursor&&a("body").css("cursor",this._storedCursor);this._storedOpacity&&this.helper.css("opacity",this._storedOpacity);if(this._storedZIndex)this.helper.css("zIndex",this._storedZIndex=="auto"?"":this._storedZIndex);this.dragging=false;if(this.cancelHelperRemoval){if(!c){this._trigger("beforeStop", +d,this._uiHash());for(h=0;h").addClass("ui-effects-wrapper").css({fontSize:"100%",background:"transparent",border:"none",margin:0,padding:0}), +p=document.activeElement;n.wrap(m);if(n[0]===p||a.contains(n[0],p))a(p).focus();m=n.parent();if(n.css("position")=="static"){m.css({position:"relative"});n.css({position:"relative"})}else{a.extend(k,{position:n.css("position"),zIndex:n.css("z-index")});a.each(["top","left","bottom","right"],function(q,s){k[s]=n.css(s);if(isNaN(parseInt(k[s],10)))k[s]="auto"});n.css({position:"relative",top:0,left:0,right:"auto",bottom:"auto"})}return m.css(k).show()},removeWrapper:function(n){var k,m=document.activeElement; +if(n.parent().is(".ui-effects-wrapper")){k=n.parent().replaceWith(n);if(n[0]===m||a.contains(n[0],m))a(m).focus();return k}return n},setTransition:function(n,k,m,p){p=p||{};a.each(k,function(q,s){unit=n.cssUnit(s);if(unit[0]>0)p[s]=unit[0]*m+unit[1]});return p}});a.fn.extend({effect:function(n){var k=b.apply(this,arguments),m={options:k[1],duration:k[2],callback:k[3]};k=m.options.mode;var p=a.effects[n];if(a.fx.off||!p)return k?this[k](m.duration,m.callback):this.each(function(){m.callback&&m.callback.call(this)}); +return p.call(this,m)},_show:a.fn.show,show:function(n){if(f(n))return this._show.apply(this,arguments);else{var k=b.apply(this,arguments);k[1].mode="show";return this.effect.apply(this,k)}},_hide:a.fn.hide,hide:function(n){if(f(n))return this._hide.apply(this,arguments);else{var k=b.apply(this,arguments);k[1].mode="hide";return this.effect.apply(this,k)}},__toggle:a.fn.toggle,toggle:function(n){if(f(n)||typeof n==="boolean"||a.isFunction(n))return this.__toggle.apply(this,arguments);else{var k=b.apply(this, +arguments);k[1].mode="toggle";return this.effect.apply(this,k)}},cssUnit:function(n){var k=this.css(n),m=[];a.each(["em","px","%","pt"],function(p,q){if(k.indexOf(q)>0)m=[parseFloat(k),q]});return m}});a.easing.jswing=a.easing.swing;a.extend(a.easing,{def:"easeOutQuad",swing:function(n,k,m,p,q){return a.easing[a.easing.def](n,k,m,p,q)},easeInQuad:function(n,k,m,p,q){return p*(k/=q)*k+m},easeOutQuad:function(n,k,m,p,q){return-p*(k/=q)*(k-2)+m},easeInOutQuad:function(n,k,m,p,q){if((k/=q/2)<1)return p/ +2*k*k+m;return-p/2*(--k*(k-2)-1)+m},easeInCubic:function(n,k,m,p,q){return p*(k/=q)*k*k+m},easeOutCubic:function(n,k,m,p,q){return p*((k=k/q-1)*k*k+1)+m},easeInOutCubic:function(n,k,m,p,q){if((k/=q/2)<1)return p/2*k*k*k+m;return p/2*((k-=2)*k*k+2)+m},easeInQuart:function(n,k,m,p,q){return p*(k/=q)*k*k*k+m},easeOutQuart:function(n,k,m,p,q){return-p*((k=k/q-1)*k*k*k-1)+m},easeInOutQuart:function(n,k,m,p,q){if((k/=q/2)<1)return p/2*k*k*k*k+m;return-p/2*((k-=2)*k*k*k-2)+m},easeInQuint:function(n,k,m, +p,q){return p*(k/=q)*k*k*k*k+m},easeOutQuint:function(n,k,m,p,q){return p*((k=k/q-1)*k*k*k*k+1)+m},easeInOutQuint:function(n,k,m,p,q){if((k/=q/2)<1)return p/2*k*k*k*k*k+m;return p/2*((k-=2)*k*k*k*k+2)+m},easeInSine:function(n,k,m,p,q){return-p*Math.cos(k/q*(Math.PI/2))+p+m},easeOutSine:function(n,k,m,p,q){return p*Math.sin(k/q*(Math.PI/2))+m},easeInOutSine:function(n,k,m,p,q){return-p/2*(Math.cos(Math.PI*k/q)-1)+m},easeInExpo:function(n,k,m,p,q){return k==0?m:p*Math.pow(2,10*(k/q-1))+m},easeOutExpo:function(n, +k,m,p,q){return k==q?m+p:p*(-Math.pow(2,-10*k/q)+1)+m},easeInOutExpo:function(n,k,m,p,q){if(k==0)return m;if(k==q)return m+p;if((k/=q/2)<1)return p/2*Math.pow(2,10*(k-1))+m;return p/2*(-Math.pow(2,-10*--k)+2)+m},easeInCirc:function(n,k,m,p,q){return-p*(Math.sqrt(1-(k/=q)*k)-1)+m},easeOutCirc:function(n,k,m,p,q){return p*Math.sqrt(1-(k=k/q-1)*k)+m},easeInOutCirc:function(n,k,m,p,q){if((k/=q/2)<1)return-p/2*(Math.sqrt(1-k*k)-1)+m;return p/2*(Math.sqrt(1-(k-=2)*k)+1)+m},easeInElastic:function(n,k,m, +p,q){n=1.70158;var s=0,r=p;if(k==0)return m;if((k/=q)==1)return m+p;s||(s=q*0.3);if(r").css({position:"absolute",visibility:"visible",left:-j*(i/e),top:-f*(b/c)}).parent().addClass("ui-effects-explode").css({position:"absolute",overflow:"hidden",width:i/e,height:b/c,left:g.left+j*(i/e)+(d.options.mode=="show"?(j-Math.floor(e/2))*(i/e):0),top:g.top+f*(b/c)+(d.options.mode=="show"?(f-Math.floor(c/2))*(b/c):0),opacity:d.options.mode=="show"?0:1}).animate({left:g.left+j*(i/e)+(d.options.mode=="show"?0:(j-Math.floor(e/2))*(i/e)),top:g.top+ +f*(b/c)+(d.options.mode=="show"?0:(f-Math.floor(c/2))*(b/c)),opacity:d.options.mode=="show"?1:0},d.duration||500);setTimeout(function(){d.options.mode=="show"?h.css({visibility:"visible"}):h.css({visibility:"visible"}).hide();d.callback&&d.callback.apply(h[0]);h.dequeue();a("div.ui-effects-explode").remove()},d.duration||500)})}})(jQuery); +(function(a){a.effects.fade=function(d){return this.queue(function(){var c=a(this),e=a.effects.setMode(c,d.options.mode||"hide");c.animate({opacity:e},{queue:false,duration:d.duration,easing:d.options.easing,complete:function(){d.callback&&d.callback.apply(this,arguments);c.dequeue()}})})}})(jQuery); +(function(a){a.effects.fold=function(d){return this.queue(function(){var c=a(this),e=["position","top","bottom","left","right"],h=a.effects.setMode(c,d.options.mode||"hide"),g=d.options.size||15,i=!!d.options.horizFirst,b=d.duration?d.duration/2:a.fx.speeds._default/2;a.effects.save(c,e);c.show();var f=a.effects.createWrapper(c).css({overflow:"hidden"}),j=h=="show"!=i,l=j?["width","height"]:["height","width"];j=j?[f.width(),f.height()]:[f.height(),f.width()];var o=/([0-9]+)%/.exec(g);if(o)g=parseInt(o[1], +10)/100*j[h=="hide"?0:1];if(h=="show")f.css(i?{height:0,width:g}:{height:g,width:0});i={};o={};i[l[0]]=h=="show"?j[0]:g;o[l[1]]=h=="show"?j[1]:0;f.animate(i,b,d.options.easing).animate(o,b,d.options.easing,function(){h=="hide"&&c.hide();a.effects.restore(c,e);a.effects.removeWrapper(c);d.callback&&d.callback.apply(c[0],arguments);c.dequeue()})})}})(jQuery); +(function(a){a.effects.highlight=function(d){return this.queue(function(){var c=a(this),e=["backgroundImage","backgroundColor","opacity"],h=a.effects.setMode(c,d.options.mode||"show"),g={backgroundColor:c.css("backgroundColor")};if(h=="hide")g.opacity=0;a.effects.save(c,e);c.show().css({backgroundImage:"none",backgroundColor:d.options.color||"#ffff99"}).animate(g,{queue:false,duration:d.duration,easing:d.options.easing,complete:function(){h=="hide"&&c.hide();a.effects.restore(c,e);h=="show"&&!a.support.opacity&& +this.style.removeAttribute("filter");d.callback&&d.callback.apply(this,arguments);c.dequeue()}})})}})(jQuery); +(function(a){a.effects.pulsate=function(d){return this.queue(function(){var c=a(this),e=a.effects.setMode(c,d.options.mode||"show");times=(d.options.times||5)*2-1;duration=d.duration?d.duration/2:a.fx.speeds._default/2;isVisible=c.is(":visible");animateTo=0;if(!isVisible){c.css("opacity",0).show();animateTo=1}if(e=="hide"&&isVisible||e=="show"&&!isVisible)times--;for(e=0;e').appendTo(document.body).addClass(d.options.className).css({top:h.top,left:h.left,height:c.innerHeight(),width:c.innerWidth(),position:"absolute"}).animate(e,d.duration,d.options.easing,function(){g.remove();d.callback&&d.callback.apply(c[0],arguments); +c.dequeue()})})}})(jQuery); +(function(a){a.widget("ui.accordion",{options:{active:0,animated:"slide",autoHeight:true,clearStyle:false,collapsible:false,event:"click",fillSpace:false,header:"> li > :first-child,> :not(li):even",icons:{header:"ui-icon-triangle-1-e",headerSelected:"ui-icon-triangle-1-s"},navigation:false,navigationFilter:function(){return this.href.toLowerCase()===location.href.toLowerCase()}},_create:function(){var d=this,c=d.options;d.running=0;d.element.addClass("ui-accordion ui-widget ui-helper-reset").children("li").addClass("ui-accordion-li-fix");d.headers= +d.element.find(c.header).addClass("ui-accordion-header ui-helper-reset ui-state-default ui-corner-all").bind("mouseenter.accordion",function(){c.disabled||a(this).addClass("ui-state-hover")}).bind("mouseleave.accordion",function(){c.disabled||a(this).removeClass("ui-state-hover")}).bind("focus.accordion",function(){c.disabled||a(this).addClass("ui-state-focus")}).bind("blur.accordion",function(){c.disabled||a(this).removeClass("ui-state-focus")});d.headers.next().addClass("ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom"); +if(c.navigation){var e=d.element.find("a").filter(c.navigationFilter).eq(0);if(e.length){var h=e.closest(".ui-accordion-header");d.active=h.length?h:e.closest(".ui-accordion-content").prev()}}d.active=d._findActive(d.active||c.active).addClass("ui-state-default ui-state-active").toggleClass("ui-corner-all").toggleClass("ui-corner-top");d.active.next().addClass("ui-accordion-content-active");d._createIcons();d.resize();d.element.attr("role","tablist");d.headers.attr("role","tab").bind("keydown.accordion", +function(g){return d._keydown(g)}).next().attr("role","tabpanel");d.headers.not(d.active||"").attr({"aria-expanded":"false","aria-selected":"false",tabIndex:-1}).next().hide();d.active.length?d.active.attr({"aria-expanded":"true","aria-selected":"true",tabIndex:0}):d.headers.eq(0).attr("tabIndex",0);a.browser.safari||d.headers.find("a").attr("tabIndex",-1);c.event&&d.headers.bind(c.event.split(" ").join(".accordion ")+".accordion",function(g){d._clickHandler.call(d,g,this);g.preventDefault()})},_createIcons:function(){var d= +this.options;if(d.icons){a("").addClass("ui-icon "+d.icons.header).prependTo(this.headers);this.active.children(".ui-icon").toggleClass(d.icons.header).toggleClass(d.icons.headerSelected);this.element.addClass("ui-accordion-icons")}},_destroyIcons:function(){this.headers.children(".ui-icon").remove();this.element.removeClass("ui-accordion-icons")},destroy:function(){var d=this.options;this.element.removeClass("ui-accordion ui-widget ui-helper-reset").removeAttr("role");this.headers.unbind(".accordion").removeClass("ui-accordion-header ui-accordion-disabled ui-helper-reset ui-state-default ui-corner-all ui-state-active ui-state-disabled ui-corner-top").removeAttr("role").removeAttr("aria-expanded").removeAttr("aria-selected").removeAttr("tabIndex"); +this.headers.find("a").removeAttr("tabIndex");this._destroyIcons();var c=this.headers.next().css("display","").removeAttr("role").removeClass("ui-helper-reset ui-widget-content ui-corner-bottom ui-accordion-content ui-accordion-content-active ui-accordion-disabled ui-state-disabled");if(d.autoHeight||d.fillHeight)c.css("height","");return a.Widget.prototype.destroy.call(this)},_setOption:function(d,c){a.Widget.prototype._setOption.apply(this,arguments);d=="active"&&this.activate(c);if(d=="icons"){this._destroyIcons(); +c&&this._createIcons()}if(d=="disabled")this.headers.add(this.headers.next())[c?"addClass":"removeClass"]("ui-accordion-disabled ui-state-disabled")},_keydown:function(d){if(!(this.options.disabled||d.altKey||d.ctrlKey)){var c=a.ui.keyCode,e=this.headers.length,h=this.headers.index(d.target),g=false;switch(d.keyCode){case c.RIGHT:case c.DOWN:g=this.headers[(h+1)%e];break;case c.LEFT:case c.UP:g=this.headers[(h-1+e)%e];break;case c.SPACE:case c.ENTER:this._clickHandler({target:d.target},d.target); +d.preventDefault()}if(g){a(d.target).attr("tabIndex",-1);a(g).attr("tabIndex",0);g.focus();return false}return true}},resize:function(){var d=this.options,c;if(d.fillSpace){if(a.browser.msie){var e=this.element.parent().css("overflow");this.element.parent().css("overflow","hidden")}c=this.element.parent().height();a.browser.msie&&this.element.parent().css("overflow",e);this.headers.each(function(){c-=a(this).outerHeight(true)});this.headers.next().each(function(){a(this).height(Math.max(0,c-a(this).innerHeight()+ +a(this).height()))}).css("overflow","auto")}else if(d.autoHeight){c=0;this.headers.next().each(function(){c=Math.max(c,a(this).height("").height())}).height(c)}return this},activate:function(d){this.options.active=d;d=this._findActive(d)[0];this._clickHandler({target:d},d);return this},_findActive:function(d){return d?typeof d==="number"?this.headers.filter(":eq("+d+")"):this.headers.not(this.headers.not(d)):d===false?a([]):this.headers.filter(":eq(0)")},_clickHandler:function(d,c){var e=this.options; +if(!e.disabled)if(d.target){d=a(d.currentTarget||c);c=d[0]===this.active[0];e.active=e.collapsible&&c?false:this.headers.index(d);if(!(this.running||!e.collapsible&&c)){var h=this.active;f=d.next();i=this.active.next();b={options:e,newHeader:c&&e.collapsible?a([]):d,oldHeader:this.active,newContent:c&&e.collapsible?a([]):f,oldContent:i};var g=this.headers.index(this.active[0])>this.headers.index(d[0]);this.active=c?a([]):d;this._toggle(f,i,b,c,g);h.removeClass("ui-state-active ui-corner-top").addClass("ui-state-default ui-corner-all").children(".ui-icon").removeClass(e.icons.headerSelected).addClass(e.icons.header); +if(!c){d.removeClass("ui-state-default ui-corner-all").addClass("ui-state-active ui-corner-top").children(".ui-icon").removeClass(e.icons.header).addClass(e.icons.headerSelected);d.next().addClass("ui-accordion-content-active")}}}else if(e.collapsible){this.active.removeClass("ui-state-active ui-corner-top").addClass("ui-state-default ui-corner-all").children(".ui-icon").removeClass(e.icons.headerSelected).addClass(e.icons.header);this.active.next().addClass("ui-accordion-content-active");var i=this.active.next(), +b={options:e,newHeader:a([]),oldHeader:e.active,newContent:a([]),oldContent:i},f=this.active=a([]);this._toggle(f,i,b)}},_toggle:function(d,c,e,h,g){var i=this,b=i.options;i.toShow=d;i.toHide=c;i.data=e;var f=function(){if(i)return i._completed.apply(i,arguments)};i._trigger("changestart",null,i.data);i.running=c.size()===0?d.size():c.size();if(b.animated){e={};e=b.collapsible&&h?{toShow:a([]),toHide:c,complete:f,down:g,autoHeight:b.autoHeight||b.fillSpace}:{toShow:d,toHide:c,complete:f,down:g,autoHeight:b.autoHeight|| +b.fillSpace};if(!b.proxied)b.proxied=b.animated;if(!b.proxiedDuration)b.proxiedDuration=b.duration;b.animated=a.isFunction(b.proxied)?b.proxied(e):b.proxied;b.duration=a.isFunction(b.proxiedDuration)?b.proxiedDuration(e):b.proxiedDuration;h=a.ui.accordion.animations;var j=b.duration,l=b.animated;if(l&&!h[l]&&!a.easing[l])l="slide";h[l]||(h[l]=function(o){this.slide(o,{easing:l,duration:j||700})});h[l](e)}else{if(b.collapsible&&h)d.toggle();else{c.hide();d.show()}f(true)}c.prev().attr({"aria-expanded":"false", +"aria-selected":"false",tabIndex:-1}).blur();d.prev().attr({"aria-expanded":"true","aria-selected":"true",tabIndex:0}).focus()},_completed:function(d){this.running=d?0:--this.running;if(!this.running){this.options.clearStyle&&this.toShow.add(this.toHide).css({height:"",overflow:""});this.toHide.removeClass("ui-accordion-content-active");if(this.toHide.length)this.toHide.parent()[0].className=this.toHide.parent()[0].className;this._trigger("change",null,this.data)}}});a.extend(a.ui.accordion,{version:"1.8.16", +animations:{slide:function(d,c){d=a.extend({easing:"swing",duration:300},d,c);if(d.toHide.size())if(d.toShow.size()){var e=d.toShow.css("overflow"),h=0,g={},i={},b;c=d.toShow;b=c[0].style.width;c.width(parseInt(c.parent().width(),10)-parseInt(c.css("paddingLeft"),10)-parseInt(c.css("paddingRight"),10)-(parseInt(c.css("borderLeftWidth"),10)||0)-(parseInt(c.css("borderRightWidth"),10)||0));a.each(["height","paddingTop","paddingBottom"],function(f,j){i[j]="hide";f=(""+a.css(d.toShow[0],j)).match(/^([\d+-.]+)(.*)$/); +g[j]={value:f[1],unit:f[2]||"px"}});d.toShow.css({height:0,overflow:"hidden"}).show();d.toHide.filter(":hidden").each(d.complete).end().filter(":visible").animate(i,{step:function(f,j){if(j.prop=="height")h=j.end-j.start===0?0:(j.now-j.start)/(j.end-j.start);d.toShow[0].style[j.prop]=h*g[j.prop].value+g[j.prop].unit},duration:d.duration,easing:d.easing,complete:function(){d.autoHeight||d.toShow.css("height","");d.toShow.css({width:b,overflow:e});d.complete()}})}else d.toHide.animate({height:"hide", +paddingTop:"hide",paddingBottom:"hide"},d);else d.toShow.animate({height:"show",paddingTop:"show",paddingBottom:"show"},d)},bounceslide:function(d){this.slide(d,{easing:d.down?"easeOutBounce":"swing",duration:d.down?1E3:200})}}})})(jQuery); +(function(a){var d=0;a.widget("ui.autocomplete",{options:{appendTo:"body",autoFocus:false,delay:300,minLength:1,position:{my:"left top",at:"left bottom",collision:"none"},source:null},pending:0,_create:function(){var c=this,e=this.element[0].ownerDocument,h;this.element.addClass("ui-autocomplete-input").attr("autocomplete","off").attr({role:"textbox","aria-autocomplete":"list","aria-haspopup":"true"}).bind("keydown.autocomplete",function(g){if(!(c.options.disabled||c.element.propAttr("readOnly"))){h= +false;var i=a.ui.keyCode;switch(g.keyCode){case i.PAGE_UP:c._move("previousPage",g);break;case i.PAGE_DOWN:c._move("nextPage",g);break;case i.UP:c._move("previous",g);g.preventDefault();break;case i.DOWN:c._move("next",g);g.preventDefault();break;case i.ENTER:case i.NUMPAD_ENTER:if(c.menu.active){h=true;g.preventDefault()}case i.TAB:if(!c.menu.active)return;c.menu.select(g);break;case i.ESCAPE:c.element.val(c.term);c.close(g);break;default:clearTimeout(c.searching);c.searching=setTimeout(function(){if(c.term!= +c.element.val()){c.selectedItem=null;c.search(null,g)}},c.options.delay);break}}}).bind("keypress.autocomplete",function(g){if(h){h=false;g.preventDefault()}}).bind("focus.autocomplete",function(){if(!c.options.disabled){c.selectedItem=null;c.previous=c.element.val()}}).bind("blur.autocomplete",function(g){if(!c.options.disabled){clearTimeout(c.searching);c.closing=setTimeout(function(){c.close(g);c._change(g)},150)}});this._initSource();this.response=function(){return c._response.apply(c,arguments)}; +this.menu=a("
      ").addClass("ui-autocomplete").appendTo(a(this.options.appendTo||"body",e)[0]).mousedown(function(g){var i=c.menu.element[0];a(g.target).closest(".ui-menu-item").length||setTimeout(function(){a(document).one("mousedown",function(b){b.target!==c.element[0]&&b.target!==i&&!a.ui.contains(i,b.target)&&c.close()})},1);setTimeout(function(){clearTimeout(c.closing)},13)}).menu({focus:function(g,i){i=i.item.data("item.autocomplete");false!==c._trigger("focus",g,{item:i})&&/^key/.test(g.originalEvent.type)&& +c.element.val(i.value)},selected:function(g,i){var b=i.item.data("item.autocomplete"),f=c.previous;if(c.element[0]!==e.activeElement){c.element.focus();c.previous=f;setTimeout(function(){c.previous=f;c.selectedItem=b},1)}false!==c._trigger("select",g,{item:b})&&c.element.val(b.value);c.term=c.element.val();c.close(g);c.selectedItem=b},blur:function(){c.menu.element.is(":visible")&&c.element.val()!==c.term&&c.element.val(c.term)}}).zIndex(this.element.zIndex()+1).css({top:0,left:0}).hide().data("menu"); +a.fn.bgiframe&&this.menu.element.bgiframe()},destroy:function(){this.element.removeClass("ui-autocomplete-input").removeAttr("autocomplete").removeAttr("role").removeAttr("aria-autocomplete").removeAttr("aria-haspopup");this.menu.element.remove();a.Widget.prototype.destroy.call(this)},_setOption:function(c,e){a.Widget.prototype._setOption.apply(this,arguments);c==="source"&&this._initSource();if(c==="appendTo")this.menu.element.appendTo(a(e||"body",this.element[0].ownerDocument)[0]);c==="disabled"&& +e&&this.xhr&&this.xhr.abort()},_initSource:function(){var c=this,e,h;if(a.isArray(this.options.source)){e=this.options.source;this.source=function(g,i){i(a.ui.autocomplete.filter(e,g.term))}}else if(typeof this.options.source==="string"){h=this.options.source;this.source=function(g,i){c.xhr&&c.xhr.abort();c.xhr=a.ajax({url:h,data:g,dataType:"json",autocompleteRequest:++d,success:function(b){this.autocompleteRequest===d&&i(b)},error:function(){this.autocompleteRequest===d&&i([])}})}}else this.source= +this.options.source},search:function(c,e){c=c!=null?c:this.element.val();this.term=this.element.val();if(c.length").data("item.autocomplete",e).append(a("").text(e.label)).appendTo(c)},_move:function(c,e){if(this.menu.element.is(":visible"))if(this.menu.first()&&/^previous/.test(c)||this.menu.last()&&/^next/.test(c)){this.element.val(this.term);this.menu.deactivate()}else this.menu[c](e);else this.search(null,e)},widget:function(){return this.menu.element}});a.extend(a.ui.autocomplete,{escapeRegex:function(c){return c.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, +"\\$&")},filter:function(c,e){var h=new RegExp(a.ui.autocomplete.escapeRegex(e),"i");return a.grep(c,function(g){return h.test(g.label||g.value||g)})}})})(jQuery); +(function(a){a.widget("ui.menu",{_create:function(){var d=this;this.element.addClass("ui-menu ui-widget ui-widget-content ui-corner-all").attr({role:"listbox","aria-activedescendant":"ui-active-menuitem"}).click(function(c){if(a(c.target).closest(".ui-menu-item a").length){c.preventDefault();d.select(c)}});this.refresh()},refresh:function(){var d=this;this.element.children("li:not(.ui-menu-item):has(a)").addClass("ui-menu-item").attr("role","menuitem").children("a").addClass("ui-corner-all").attr("tabindex", +-1).mouseenter(function(c){d.activate(c,a(this).parent())}).mouseleave(function(){d.deactivate()})},activate:function(d,c){this.deactivate();if(this.hasScroll()){var e=c.offset().top-this.element.offset().top,h=this.element.scrollTop(),g=this.element.height();if(e<0)this.element.scrollTop(h+e);else e>=g&&this.element.scrollTop(h+e-g+c.height())}this.active=c.eq(0).children("a").addClass("ui-state-hover").attr("id","ui-active-menuitem").end();this._trigger("focus",d,{item:c})},deactivate:function(){if(this.active){this.active.children("a").removeClass("ui-state-hover").removeAttr("id"); +this._trigger("blur");this.active=null}},next:function(d){this.move("next",".ui-menu-item:first",d)},previous:function(d){this.move("prev",".ui-menu-item:last",d)},first:function(){return this.active&&!this.active.prevAll(".ui-menu-item").length},last:function(){return this.active&&!this.active.nextAll(".ui-menu-item").length},move:function(d,c,e){if(this.active){d=this.active[d+"All"](".ui-menu-item").eq(0);d.length?this.activate(e,d):this.activate(e,this.element.children(c))}else this.activate(e, +this.element.children(c))},nextPage:function(d){if(this.hasScroll())if(!this.active||this.last())this.activate(d,this.element.children(".ui-menu-item:first"));else{var c=this.active.offset().top,e=this.element.height(),h=this.element.children(".ui-menu-item").filter(function(){var g=a(this).offset().top-c-e+a(this).height();return g<10&&g>-10});h.length||(h=this.element.children(".ui-menu-item:last"));this.activate(d,h)}else this.activate(d,this.element.children(".ui-menu-item").filter(!this.active|| +this.last()?":first":":last"))},previousPage:function(d){if(this.hasScroll())if(!this.active||this.first())this.activate(d,this.element.children(".ui-menu-item:last"));else{var c=this.active.offset().top,e=this.element.height();result=this.element.children(".ui-menu-item").filter(function(){var h=a(this).offset().top-c+e-a(this).height();return h<10&&h>-10});result.length||(result=this.element.children(".ui-menu-item:first"));this.activate(d,result)}else this.activate(d,this.element.children(".ui-menu-item").filter(!this.active|| +this.first()?":last":":first"))},hasScroll:function(){return this.element.height()").addClass("ui-button-text").html(this.options.label).appendTo(b.empty()).text(),j=this.options.icons,l=j.primary&&j.secondary,o=[];if(j.primary||j.secondary){if(this.options.text)o.push("ui-button-text-icon"+(l?"s":j.primary?"-primary":"-secondary"));j.primary&&b.prepend("");j.secondary&&b.append("");if(!this.options.text){o.push(l?"ui-button-icons-only": +"ui-button-icon-only");this.hasTitle||b.attr("title",f)}}else o.push("ui-button-text-only");b.addClass(o.join(" "))}}});a.widget("ui.buttonset",{options:{items:":button, :submit, :reset, :checkbox, :radio, a, :data(button)"},_create:function(){this.element.addClass("ui-buttonset")},_init:function(){this.refresh()},_setOption:function(b,f){b==="disabled"&&this.buttons.button("option",b,f);a.Widget.prototype._setOption.apply(this,arguments)},refresh:function(){var b=this.element.css("direction")=== +"ltr";this.buttons=this.element.find(this.options.items).filter(":ui-button").button("refresh").end().not(":ui-button").button().end().map(function(){return a(this).button("widget")[0]}).removeClass("ui-corner-all ui-corner-left ui-corner-right").filter(":first").addClass(b?"ui-corner-left":"ui-corner-right").end().filter(":last").addClass(b?"ui-corner-right":"ui-corner-left").end().end()},destroy:function(){this.element.removeClass("ui-buttonset");this.buttons.map(function(){return a(this).button("widget")[0]}).removeClass("ui-corner-left ui-corner-right").end().button("destroy"); +a.Widget.prototype.destroy.call(this)}})})(jQuery); +(function(a,d){function c(){this.debug=false;this._curInst=null;this._keyEvent=false;this._disabledInputs=[];this._inDialog=this._datepickerShowing=false;this._mainDivId="ui-datepicker-div";this._inlineClass="ui-datepicker-inline";this._appendClass="ui-datepicker-append";this._triggerClass="ui-datepicker-trigger";this._dialogClass="ui-datepicker-dialog";this._disableClass="ui-datepicker-disabled";this._unselectableClass="ui-datepicker-unselectable";this._currentClass="ui-datepicker-current-day";this._dayOverClass= +"ui-datepicker-days-cell-over";this.regional=[];this.regional[""]={closeText:"Done",prevText:"Prev",nextText:"Next",currentText:"Today",monthNames:["January","February","March","April","May","June","July","August","September","October","November","December"],monthNamesShort:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],dayNames:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],dayNamesShort:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],dayNamesMin:["Su", +"Mo","Tu","We","Th","Fr","Sa"],weekHeader:"Wk",dateFormat:"mm/dd/yy",firstDay:0,isRTL:false,showMonthAfterYear:false,yearSuffix:""};this._defaults={showOn:"focus",showAnim:"fadeIn",showOptions:{},defaultDate:null,appendText:"",buttonText:"...",buttonImage:"",buttonImageOnly:false,hideIfNoPrevNext:false,navigationAsDateFormat:false,gotoCurrent:false,changeMonth:false,changeYear:false,yearRange:"c-10:c+10",showOtherMonths:false,selectOtherMonths:false,showWeek:false,calculateWeek:this.iso8601Week,shortYearCutoff:"+10", +minDate:null,maxDate:null,duration:"fast",beforeShowDay:null,beforeShow:null,onSelect:null,onChangeMonthYear:null,onClose:null,numberOfMonths:1,showCurrentAtPos:0,stepMonths:1,stepBigMonths:12,altField:"",altFormat:"",constrainInput:true,showButtonPanel:false,autoSize:false,disabled:false};a.extend(this._defaults,this.regional[""]);this.dpDiv=e(a('
      '))}function e(b){return b.bind("mouseout", +function(f){f=a(f.target).closest("button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a");f.length&&f.removeClass("ui-state-hover ui-datepicker-prev-hover ui-datepicker-next-hover")}).bind("mouseover",function(f){f=a(f.target).closest("button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a");if(!(a.datepicker._isDisabledDatepicker(i.inline?b.parent()[0]:i.input[0])||!f.length)){f.parents(".ui-datepicker-calendar").find("a").removeClass("ui-state-hover"); +f.addClass("ui-state-hover");f.hasClass("ui-datepicker-prev")&&f.addClass("ui-datepicker-prev-hover");f.hasClass("ui-datepicker-next")&&f.addClass("ui-datepicker-next-hover")}})}function h(b,f){a.extend(b,f);for(var j in f)if(f[j]==null||f[j]==d)b[j]=f[j];return b}a.extend(a.ui,{datepicker:{version:"1.8.16"}});var g=(new Date).getTime(),i;a.extend(c.prototype,{markerClassName:"hasDatepicker",maxRows:4,log:function(){this.debug&&console.log.apply("",arguments)},_widgetDatepicker:function(){return this.dpDiv}, +setDefaults:function(b){h(this._defaults,b||{});return this},_attachDatepicker:function(b,f){var j=null;for(var l in this._defaults){var o=b.getAttribute("date:"+l);if(o){j=j||{};try{j[l]=eval(o)}catch(n){j[l]=o}}}l=b.nodeName.toLowerCase();o=l=="div"||l=="span";if(!b.id){this.uuid+=1;b.id="dp"+this.uuid}var k=this._newInst(a(b),o);k.settings=a.extend({},f||{},j||{});if(l=="input")this._connectDatepicker(b,k);else o&&this._inlineDatepicker(b,k)},_newInst:function(b,f){return{id:b[0].id.replace(/([^A-Za-z0-9_-])/g, +"\\\\$1"),input:b,selectedDay:0,selectedMonth:0,selectedYear:0,drawMonth:0,drawYear:0,inline:f,dpDiv:!f?this.dpDiv:e(a('
      '))}},_connectDatepicker:function(b,f){var j=a(b);f.append=a([]);f.trigger=a([]);if(!j.hasClass(this.markerClassName)){this._attachments(j,f);j.addClass(this.markerClassName).keydown(this._doKeyDown).keypress(this._doKeyPress).keyup(this._doKeyUp).bind("setData.datepicker", +function(l,o,n){f.settings[o]=n}).bind("getData.datepicker",function(l,o){return this._get(f,o)});this._autoSize(f);a.data(b,"datepicker",f);f.settings.disabled&&this._disableDatepicker(b)}},_attachments:function(b,f){var j=this._get(f,"appendText"),l=this._get(f,"isRTL");f.append&&f.append.remove();if(j){f.append=a(''+j+"");b[l?"before":"after"](f.append)}b.unbind("focus",this._showDatepicker);f.trigger&&f.trigger.remove();j=this._get(f,"showOn");if(j== +"focus"||j=="both")b.focus(this._showDatepicker);if(j=="button"||j=="both"){j=this._get(f,"buttonText");var o=this._get(f,"buttonImage");f.trigger=a(this._get(f,"buttonImageOnly")?a("").addClass(this._triggerClass).attr({src:o,alt:j,title:j}):a('').addClass(this._triggerClass).html(o==""?j:a("").attr({src:o,alt:j,title:j})));b[l?"before":"after"](f.trigger);f.trigger.click(function(){a.datepicker._datepickerShowing&&a.datepicker._lastInput==b[0]?a.datepicker._hideDatepicker(): +a.datepicker._showDatepicker(b[0]);return false})}},_autoSize:function(b){if(this._get(b,"autoSize")&&!b.inline){var f=new Date(2009,11,20),j=this._get(b,"dateFormat");if(j.match(/[DM]/)){var l=function(o){for(var n=0,k=0,m=0;mn){n=o[m].length;k=m}return k};f.setMonth(l(this._get(b,j.match(/MM/)?"monthNames":"monthNamesShort")));f.setDate(l(this._get(b,j.match(/DD/)?"dayNames":"dayNamesShort"))+20-f.getDay())}b.input.attr("size",this._formatDate(b,f).length)}},_inlineDatepicker:function(b, +f){var j=a(b);if(!j.hasClass(this.markerClassName)){j.addClass(this.markerClassName).append(f.dpDiv).bind("setData.datepicker",function(l,o,n){f.settings[o]=n}).bind("getData.datepicker",function(l,o){return this._get(f,o)});a.data(b,"datepicker",f);this._setDate(f,this._getDefaultDate(f),true);this._updateDatepicker(f);this._updateAlternate(f);f.settings.disabled&&this._disableDatepicker(b);f.dpDiv.css("display","block")}},_dialogDatepicker:function(b,f,j,l,o){b=this._dialogInst;if(!b){this.uuid+= +1;this._dialogInput=a('');this._dialogInput.keydown(this._doKeyDown);a("body").append(this._dialogInput);b=this._dialogInst=this._newInst(this._dialogInput,false);b.settings={};a.data(this._dialogInput[0],"datepicker",b)}h(b.settings,l||{});f=f&&f.constructor==Date?this._formatDate(b,f):f;this._dialogInput.val(f);this._pos=o?o.length?o:[o.pageX,o.pageY]:null;if(!this._pos)this._pos=[document.documentElement.clientWidth/ +2-100+(document.documentElement.scrollLeft||document.body.scrollLeft),document.documentElement.clientHeight/2-150+(document.documentElement.scrollTop||document.body.scrollTop)];this._dialogInput.css("left",this._pos[0]+20+"px").css("top",this._pos[1]+"px");b.settings.onSelect=j;this._inDialog=true;this.dpDiv.addClass(this._dialogClass);this._showDatepicker(this._dialogInput[0]);a.blockUI&&a.blockUI(this.dpDiv);a.data(this._dialogInput[0],"datepicker",b);return this},_destroyDatepicker:function(b){var f= +a(b),j=a.data(b,"datepicker");if(f.hasClass(this.markerClassName)){var l=b.nodeName.toLowerCase();a.removeData(b,"datepicker");if(l=="input"){j.append.remove();j.trigger.remove();f.removeClass(this.markerClassName).unbind("focus",this._showDatepicker).unbind("keydown",this._doKeyDown).unbind("keypress",this._doKeyPress).unbind("keyup",this._doKeyUp)}else if(l=="div"||l=="span")f.removeClass(this.markerClassName).empty()}},_enableDatepicker:function(b){var f=a(b),j=a.data(b,"datepicker");if(f.hasClass(this.markerClassName)){var l= +b.nodeName.toLowerCase();if(l=="input"){b.disabled=false;j.trigger.filter("button").each(function(){this.disabled=false}).end().filter("img").css({opacity:"1.0",cursor:""})}else if(l=="div"||l=="span"){f=f.children("."+this._inlineClass);f.children().removeClass("ui-state-disabled");f.find("select.ui-datepicker-month, select.ui-datepicker-year").removeAttr("disabled")}this._disabledInputs=a.map(this._disabledInputs,function(o){return o==b?null:o})}},_disableDatepicker:function(b){var f=a(b),j=a.data(b, +"datepicker");if(f.hasClass(this.markerClassName)){var l=b.nodeName.toLowerCase();if(l=="input"){b.disabled=true;j.trigger.filter("button").each(function(){this.disabled=true}).end().filter("img").css({opacity:"0.5",cursor:"default"})}else if(l=="div"||l=="span"){f=f.children("."+this._inlineClass);f.children().addClass("ui-state-disabled");f.find("select.ui-datepicker-month, select.ui-datepicker-year").attr("disabled","disabled")}this._disabledInputs=a.map(this._disabledInputs,function(o){return o== +b?null:o});this._disabledInputs[this._disabledInputs.length]=b}},_isDisabledDatepicker:function(b){if(!b)return false;for(var f=0;f-1}},_doKeyUp:function(b){b=a.datepicker._getInst(b.target);if(b.input.val()!=b.lastVal)try{if(a.datepicker.parseDate(a.datepicker._get(b,"dateFormat"),b.input?b.input.val():null,a.datepicker._getFormatConfig(b))){a.datepicker._setDateFromField(b);a.datepicker._updateAlternate(b);a.datepicker._updateDatepicker(b)}}catch(f){a.datepicker.log(f)}return true},_showDatepicker:function(b){b=b.target||b;if(b.nodeName.toLowerCase()!="input")b=a("input", +b.parentNode)[0];if(!(a.datepicker._isDisabledDatepicker(b)||a.datepicker._lastInput==b)){var f=a.datepicker._getInst(b);if(a.datepicker._curInst&&a.datepicker._curInst!=f){a.datepicker._datepickerShowing&&a.datepicker._triggerOnClose(a.datepicker._curInst);a.datepicker._curInst.dpDiv.stop(true,true)}var j=a.datepicker._get(f,"beforeShow");j=j?j.apply(b,[b,f]):{};if(j!==false){h(f.settings,j);f.lastVal=null;a.datepicker._lastInput=b;a.datepicker._setDateFromField(f);if(a.datepicker._inDialog)b.value= +"";if(!a.datepicker._pos){a.datepicker._pos=a.datepicker._findPos(b);a.datepicker._pos[1]+=b.offsetHeight}var l=false;a(b).parents().each(function(){l|=a(this).css("position")=="fixed";return!l});if(l&&a.browser.opera){a.datepicker._pos[0]-=document.documentElement.scrollLeft;a.datepicker._pos[1]-=document.documentElement.scrollTop}j={left:a.datepicker._pos[0],top:a.datepicker._pos[1]};a.datepicker._pos=null;f.dpDiv.empty();f.dpDiv.css({position:"absolute",display:"block",top:"-1000px"});a.datepicker._updateDatepicker(f); +j=a.datepicker._checkOffset(f,j,l);f.dpDiv.css({position:a.datepicker._inDialog&&a.blockUI?"static":l?"fixed":"absolute",display:"none",left:j.left+"px",top:j.top+"px"});if(!f.inline){j=a.datepicker._get(f,"showAnim");var o=a.datepicker._get(f,"duration"),n=function(){var k=f.dpDiv.find("iframe.ui-datepicker-cover");if(k.length){var m=a.datepicker._getBorders(f.dpDiv);k.css({left:-m[0],top:-m[1],width:f.dpDiv.outerWidth(),height:f.dpDiv.outerHeight()})}};f.dpDiv.zIndex(a(b).zIndex()+1);a.datepicker._datepickerShowing= +true;a.effects&&a.effects[j]?f.dpDiv.show(j,a.datepicker._get(f,"showOptions"),o,n):f.dpDiv[j||"show"](j?o:null,n);if(!j||!o)n();f.input.is(":visible")&&!f.input.is(":disabled")&&f.input.focus();a.datepicker._curInst=f}}}},_updateDatepicker:function(b){this.maxRows=4;var f=a.datepicker._getBorders(b.dpDiv);i=b;b.dpDiv.empty().append(this._generateHTML(b));var j=b.dpDiv.find("iframe.ui-datepicker-cover");j.length&&j.css({left:-f[0],top:-f[1],width:b.dpDiv.outerWidth(),height:b.dpDiv.outerHeight()}); +b.dpDiv.find("."+this._dayOverClass+" a").mouseover();f=this._getNumberOfMonths(b);j=f[1];b.dpDiv.removeClass("ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4").width("");j>1&&b.dpDiv.addClass("ui-datepicker-multi-"+j).css("width",17*j+"em");b.dpDiv[(f[0]!=1||f[1]!=1?"add":"remove")+"Class"]("ui-datepicker-multi");b.dpDiv[(this._get(b,"isRTL")?"add":"remove")+"Class"]("ui-datepicker-rtl");b==a.datepicker._curInst&&a.datepicker._datepickerShowing&&b.input&&b.input.is(":visible")&& +!b.input.is(":disabled")&&b.input[0]!=document.activeElement&&b.input.focus();if(b.yearshtml){var l=b.yearshtml;setTimeout(function(){l===b.yearshtml&&b.yearshtml&&b.dpDiv.find("select.ui-datepicker-year:first").replaceWith(b.yearshtml);l=b.yearshtml=null},0)}},_getBorders:function(b){var f=function(j){return{thin:1,medium:2,thick:3}[j]||j};return[parseFloat(f(b.css("border-left-width"))),parseFloat(f(b.css("border-top-width")))]},_checkOffset:function(b,f,j){var l=b.dpDiv.outerWidth(),o=b.dpDiv.outerHeight(), +n=b.input?b.input.outerWidth():0,k=b.input?b.input.outerHeight():0,m=document.documentElement.clientWidth+a(document).scrollLeft(),p=document.documentElement.clientHeight+a(document).scrollTop();f.left-=this._get(b,"isRTL")?l-n:0;f.left-=j&&f.left==b.input.offset().left?a(document).scrollLeft():0;f.top-=j&&f.top==b.input.offset().top+k?a(document).scrollTop():0;f.left-=Math.min(f.left,f.left+l>m&&m>l?Math.abs(f.left+l-m):0);f.top-=Math.min(f.top,f.top+o>p&&p>o?Math.abs(o+k):0);return f},_findPos:function(b){for(var f= +this._get(this._getInst(b),"isRTL");b&&(b.type=="hidden"||b.nodeType!=1||a.expr.filters.hidden(b));)b=b[f?"previousSibling":"nextSibling"];b=a(b).offset();return[b.left,b.top]},_triggerOnClose:function(b){var f=this._get(b,"onClose");if(f)f.apply(b.input?b.input[0]:null,[b.input?b.input.val():"",b])},_hideDatepicker:function(b){var f=this._curInst;if(!(!f||b&&f!=a.data(b,"datepicker")))if(this._datepickerShowing){b=this._get(f,"showAnim");var j=this._get(f,"duration"),l=function(){a.datepicker._tidyDialog(f); +this._curInst=null};a.effects&&a.effects[b]?f.dpDiv.hide(b,a.datepicker._get(f,"showOptions"),j,l):f.dpDiv[b=="slideDown"?"slideUp":b=="fadeIn"?"fadeOut":"hide"](b?j:null,l);b||l();a.datepicker._triggerOnClose(f);this._datepickerShowing=false;this._lastInput=null;if(this._inDialog){this._dialogInput.css({position:"absolute",left:"0",top:"-100px"});if(a.blockUI){a.unblockUI();a("body").append(this.dpDiv)}}this._inDialog=false}},_tidyDialog:function(b){b.dpDiv.removeClass(this._dialogClass).unbind(".ui-datepicker-calendar")}, +_checkExternalClick:function(b){if(a.datepicker._curInst){b=a(b.target);b[0].id!=a.datepicker._mainDivId&&b.parents("#"+a.datepicker._mainDivId).length==0&&!b.hasClass(a.datepicker.markerClassName)&&!b.hasClass(a.datepicker._triggerClass)&&a.datepicker._datepickerShowing&&!(a.datepicker._inDialog&&a.blockUI)&&a.datepicker._hideDatepicker()}},_adjustDate:function(b,f,j){b=a(b);var l=this._getInst(b[0]);if(!this._isDisabledDatepicker(b[0])){this._adjustInstDate(l,f+(j=="M"?this._get(l,"showCurrentAtPos"): +0),j);this._updateDatepicker(l)}},_gotoToday:function(b){b=a(b);var f=this._getInst(b[0]);if(this._get(f,"gotoCurrent")&&f.currentDay){f.selectedDay=f.currentDay;f.drawMonth=f.selectedMonth=f.currentMonth;f.drawYear=f.selectedYear=f.currentYear}else{var j=new Date;f.selectedDay=j.getDate();f.drawMonth=f.selectedMonth=j.getMonth();f.drawYear=f.selectedYear=j.getFullYear()}this._notifyChange(f);this._adjustDate(b)},_selectMonthYear:function(b,f,j){b=a(b);var l=this._getInst(b[0]);l["selected"+(j=="M"? +"Month":"Year")]=l["draw"+(j=="M"?"Month":"Year")]=parseInt(f.options[f.selectedIndex].value,10);this._notifyChange(l);this._adjustDate(b)},_selectDay:function(b,f,j,l){var o=a(b);if(!(a(l).hasClass(this._unselectableClass)||this._isDisabledDatepicker(o[0]))){o=this._getInst(o[0]);o.selectedDay=o.currentDay=a("a",l).html();o.selectedMonth=o.currentMonth=f;o.selectedYear=o.currentYear=j;this._selectDate(b,this._formatDate(o,o.currentDay,o.currentMonth,o.currentYear))}},_clearDate:function(b){b=a(b); +this._getInst(b[0]);this._selectDate(b,"")},_selectDate:function(b,f){b=this._getInst(a(b)[0]);f=f!=null?f:this._formatDate(b);b.input&&b.input.val(f);this._updateAlternate(b);var j=this._get(b,"onSelect");if(j)j.apply(b.input?b.input[0]:null,[f,b]);else b.input&&b.input.trigger("change");if(b.inline)this._updateDatepicker(b);else{this._hideDatepicker();this._lastInput=b.input[0];typeof b.input[0]!="object"&&b.input.focus();this._lastInput=null}},_updateAlternate:function(b){var f=this._get(b,"altField"); +if(f){var j=this._get(b,"altFormat")||this._get(b,"dateFormat"),l=this._getDate(b),o=this.formatDate(j,l,this._getFormatConfig(b));a(f).each(function(){a(this).val(o)})}},noWeekends:function(b){b=b.getDay();return[b>0&&b<6,""]},iso8601Week:function(b){b=new Date(b.getTime());b.setDate(b.getDate()+4-(b.getDay()||7));var f=b.getTime();b.setMonth(0);b.setDate(1);return Math.floor(Math.round((f-b)/864E5)/7)+1},parseDate:function(b,f,j){if(b==null||f==null)throw"Invalid arguments";f=typeof f=="object"? +f.toString():f+"";if(f=="")return null;var l=(j?j.shortYearCutoff:null)||this._defaults.shortYearCutoff;l=typeof l!="string"?l:(new Date).getFullYear()%100+parseInt(l,10);for(var o=(j?j.dayNamesShort:null)||this._defaults.dayNamesShort,n=(j?j.dayNames:null)||this._defaults.dayNames,k=(j?j.monthNamesShort:null)||this._defaults.monthNamesShort,m=(j?j.monthNames:null)||this._defaults.monthNames,p=j=-1,q=-1,s=-1,r=false,u=function(z){(z=H+1-1){p=1;q=s;do{l=this._getDaysInMonth(j,p-1);if(q<=l)break;p++;q-=l}while(1)}C=this._daylightSavingAdjust(new Date(j,p-1,q));if(C.getFullYear()!=j||C.getMonth()+1!=p||C.getDate()!=q)throw"Invalid date";return C},ATOM:"yy-mm-dd", +COOKIE:"D, dd M yy",ISO_8601:"yy-mm-dd",RFC_822:"D, d M y",RFC_850:"DD, dd-M-y",RFC_1036:"D, d M y",RFC_1123:"D, d M yy",RFC_2822:"D, d M yy",RSS:"D, d M y",TICKS:"!",TIMESTAMP:"@",W3C:"yy-mm-dd",_ticksTo1970:(718685+Math.floor(492.5)-Math.floor(19.7)+Math.floor(4.925))*24*60*60*1E7,formatDate:function(b,f,j){if(!f)return"";var l=(j?j.dayNamesShort:null)||this._defaults.dayNamesShort,o=(j?j.dayNames:null)||this._defaults.dayNames,n=(j?j.monthNamesShort:null)||this._defaults.monthNamesShort;j=(j?j.monthNames: +null)||this._defaults.monthNames;var k=function(u){(u=r+1 +12?b.getHours()+2:0);return b},_setDate:function(b,f,j){var l=!f,o=b.selectedMonth,n=b.selectedYear;f=this._restrictMinMax(b,this._determineDate(b,f,new Date));b.selectedDay=b.currentDay=f.getDate();b.drawMonth=b.selectedMonth=b.currentMonth=f.getMonth();b.drawYear=b.selectedYear=b.currentYear=f.getFullYear();if((o!=b.selectedMonth||n!=b.selectedYear)&&!j)this._notifyChange(b);this._adjustInstDate(b);if(b.input)b.input.val(l?"":this._formatDate(b))},_getDate:function(b){return!b.currentYear||b.input&& +b.input.val()==""?null:this._daylightSavingAdjust(new Date(b.currentYear,b.currentMonth,b.currentDay))},_generateHTML:function(b){var f=new Date;f=this._daylightSavingAdjust(new Date(f.getFullYear(),f.getMonth(),f.getDate()));var j=this._get(b,"isRTL"),l=this._get(b,"showButtonPanel"),o=this._get(b,"hideIfNoPrevNext"),n=this._get(b,"navigationAsDateFormat"),k=this._getNumberOfMonths(b),m=this._get(b,"showCurrentAtPos"),p=this._get(b,"stepMonths"),q=k[0]!=1||k[1]!=1,s=this._daylightSavingAdjust(!b.currentDay? +new Date(9999,9,9):new Date(b.currentYear,b.currentMonth,b.currentDay)),r=this._getMinMaxDate(b,"min"),u=this._getMinMaxDate(b,"max");m=b.drawMonth-m;var v=b.drawYear;if(m<0){m+=12;v--}if(u){var w=this._daylightSavingAdjust(new Date(u.getFullYear(),u.getMonth()-k[0]*k[1]+1,u.getDate()));for(w=r&&ww;){m--;if(m<0){m=11;v--}}}b.drawMonth=m;b.drawYear=v;w=this._get(b,"prevText");w=!n?w:this.formatDate(w,this._daylightSavingAdjust(new Date(v,m-p,1)),this._getFormatConfig(b)); +w=this._canAdjustMonth(b,-1,v,m)?''+w+"":o?"":''+w+"";var x=this._get(b,"nextText");x=!n?x:this.formatDate(x,this._daylightSavingAdjust(new Date(v, +m+p,1)),this._getFormatConfig(b));o=this._canAdjustMonth(b,+1,v,m)?''+x+"":o?"":''+x+"";p=this._get(b,"currentText");x=this._get(b,"gotoCurrent")&& +b.currentDay?s:f;p=!n?p:this.formatDate(p,x,this._getFormatConfig(b));n=!b.inline?'":"";l=l?'
      '+(j?n:"")+(this._isInRange(b,x)?'":"")+(j?"":n)+"
      ":"";n=parseInt(this._get(b,"firstDay"),10);n=isNaN(n)?0:n;p=this._get(b,"showWeek");x=this._get(b,"dayNames");this._get(b,"dayNamesShort");var y=this._get(b,"dayNamesMin"),H=this._get(b,"monthNames"),C=this._get(b,"monthNamesShort"),z=this._get(b,"beforeShowDay"),I=this._get(b,"showOtherMonths"),N=this._get(b,"selectOtherMonths");this._get(b,"calculateWeek");for(var J=this._getDefaultDate(b),D="",E=0;E1)switch(L){case 0:F+=" ui-datepicker-group-first";B=" ui-corner-"+(j?"right":"left");break;case k[1]-1:F+=" ui-datepicker-group-last";B=" ui-corner-"+(j?"left":"right");break;default:F+=" ui-datepicker-group-middle";B="";break}F+='">'}F+='
      '+(/all|left/.test(B)&& +E==0?j?o:w:"")+(/all|right/.test(B)&&E==0?j?w:o:"")+this._generateMonthYearHeader(b,m,v,r,u,E>0||L>0,H,C)+'
      ';var G=p?'":"";for(B=0;B<7;B++){var A=(B+n)%7;G+="=5?' class="ui-datepicker-week-end"':"")+'>'+y[A]+""}F+=G+"";G=this._getDaysInMonth(v,m);if(v==b.selectedYear&&m==b.selectedMonth)b.selectedDay=Math.min(b.selectedDay, +G);B=(this._getFirstDayOfMonth(v,m)-n+7)%7;G=Math.ceil((B+G)/7);this.maxRows=G=q?this.maxRows>G?this.maxRows:G:G;A=this._daylightSavingAdjust(new Date(v,m,1-B));for(var R=0;R";var S=!p?"":'";for(B=0;B<7;B++){var M=z?z.apply(b.input?b.input[0]:null,[A]):[true,""],K=A.getMonth()!=m,O=K&&!N||!M[0]||r&&Au;S+='";A.setDate(A.getDate()+1);A=this._daylightSavingAdjust(A)}F+=S+""}m++;if(m>11){m=0;v++}F+="
      '+this._get(b,"weekHeader")+"
      '+this._get(b,"calculateWeek")(A)+""+(K&&!I?" ":O?''+ +A.getDate()+"":''+A.getDate()+"")+"
      "+(q?""+(k[0]>0&&L==k[1]-1?'
      ':""):"");P+=F}D+=P}D+=l+(a.browser.msie&&parseInt(a.browser.version,10)<7&&!b.inline?'': +"");b._keyEvent=false;return D},_generateMonthYearHeader:function(b,f,j,l,o,n,k,m){var p=this._get(b,"changeMonth"),q=this._get(b,"changeYear"),s=this._get(b,"showMonthAfterYear"),r='
      ',u="";if(n||!p)u+=''+k[f]+"";else{k=l&&l.getFullYear()==j;var v=o&&o.getFullYear()==j;u+='"}s||(r+=u+(n||!(p&&q)?" ":""));if(!b.yearshtml){b.yearshtml="";if(n||!q)r+=''+j+"";else{m=this._get(b,"yearRange").split(":");var x=(new Date).getFullYear();k=function(y){y=y.match(/c[+-].*/)?j+parseInt(y.substring(1),10):y.match(/[+-].*/)?x+parseInt(y,10):parseInt(y,10);return isNaN(y)?x:y};f=k(m[0]);m=Math.max(f,k(m[1]||""));f=l?Math.max(f, +l.getFullYear()):f;m=o?Math.min(m,o.getFullYear()):m;for(b.yearshtml+='";r+=b.yearshtml;b.yearshtml=null}}r+=this._get(b,"yearSuffix");if(s)r+=(n||!(p&&q)?" ":"")+u;r+="
      ";return r},_adjustInstDate:function(b,f,j){var l=b.drawYear+(j=="Y"?f:0),o=b.drawMonth+ +(j=="M"?f:0);f=Math.min(b.selectedDay,this._getDaysInMonth(l,o))+(j=="D"?f:0);l=this._restrictMinMax(b,this._daylightSavingAdjust(new Date(l,o,f)));b.selectedDay=l.getDate();b.drawMonth=b.selectedMonth=l.getMonth();b.drawYear=b.selectedYear=l.getFullYear();if(j=="M"||j=="Y")this._notifyChange(b)},_restrictMinMax:function(b,f){var j=this._getMinMaxDate(b,"min");b=this._getMinMaxDate(b,"max");f=j&&fb?b:f},_notifyChange:function(b){var f=this._get(b,"onChangeMonthYear");if(f)f.apply(b.input? +b.input[0]:null,[b.selectedYear,b.selectedMonth+1,b])},_getNumberOfMonths:function(b){b=this._get(b,"numberOfMonths");return b==null?[1,1]:typeof b=="number"?[1,b]:b},_getMinMaxDate:function(b,f){return this._determineDate(b,this._get(b,f+"Date"),null)},_getDaysInMonth:function(b,f){return 32-this._daylightSavingAdjust(new Date(b,f,32)).getDate()},_getFirstDayOfMonth:function(b,f){return(new Date(b,f,1)).getDay()},_canAdjustMonth:function(b,f,j,l){var o=this._getNumberOfMonths(b);j=this._daylightSavingAdjust(new Date(j, +l+(f<0?f:o[0]*o[1]),1));f<0&&j.setDate(this._getDaysInMonth(j.getFullYear(),j.getMonth()));return this._isInRange(b,j)},_isInRange:function(b,f){var j=this._getMinMaxDate(b,"min");b=this._getMinMaxDate(b,"max");return(!j||f.getTime()>=j.getTime())&&(!b||f.getTime()<=b.getTime())},_getFormatConfig:function(b){var f=this._get(b,"shortYearCutoff");f=typeof f!="string"?f:(new Date).getFullYear()%100+parseInt(f,10);return{shortYearCutoff:f,dayNamesShort:this._get(b,"dayNamesShort"),dayNames:this._get(b, +"dayNames"),monthNamesShort:this._get(b,"monthNamesShort"),monthNames:this._get(b,"monthNames")}},_formatDate:function(b,f,j,l){if(!f){b.currentDay=b.selectedDay;b.currentMonth=b.selectedMonth;b.currentYear=b.selectedYear}f=f?typeof f=="object"?f:this._daylightSavingAdjust(new Date(l,j,f)):this._daylightSavingAdjust(new Date(b.currentYear,b.currentMonth,b.currentDay));return this.formatDate(this._get(b,"dateFormat"),f,this._getFormatConfig(b))}});a.fn.datepicker=function(b){if(!this.length)return this; +if(!a.datepicker.initialized){a(document).mousedown(a.datepicker._checkExternalClick).find("body").append(a.datepicker.dpDiv);a.datepicker.initialized=true}var f=Array.prototype.slice.call(arguments,1);if(typeof b=="string"&&(b=="isDisabled"||b=="getDate"||b=="widget"))return a.datepicker["_"+b+"Datepicker"].apply(a.datepicker,[this[0]].concat(f));if(b=="option"&&arguments.length==2&&typeof arguments[1]=="string")return a.datepicker["_"+b+"Datepicker"].apply(a.datepicker,[this[0]].concat(f));return this.each(function(){typeof b== +"string"?a.datepicker["_"+b+"Datepicker"].apply(a.datepicker,[this].concat(f)):a.datepicker._attachDatepicker(this,b)})};a.datepicker=new c;a.datepicker.initialized=false;a.datepicker.uuid=(new Date).getTime();a.datepicker.version="1.8.16";window["DP_jQuery_"+g]=a})(jQuery); +(function(a,d){var c={buttons:true,height:true,maxHeight:true,maxWidth:true,minHeight:true,minWidth:true,width:true},e={maxHeight:true,maxWidth:true,minHeight:true,minWidth:true},h=a.attrFn||{val:true,css:true,html:true,text:true,data:true,width:true,height:true,offset:true,click:true};a.widget("ui.dialog",{options:{autoOpen:true,buttons:{},closeOnEscape:true,closeText:"close",dialogClass:"",draggable:true,hide:null,height:"auto",maxHeight:false,maxWidth:false,minHeight:150,minWidth:150,modal:false, +position:{my:"center",at:"center",collision:"fit",using:function(g){var i=a(this).css(g).offset().top;i<0&&a(this).css("top",g.top-i)}},resizable:true,show:null,stack:true,title:"",width:300,zIndex:1E3},_create:function(){this.originalTitle=this.element.attr("title");if(typeof this.originalTitle!=="string")this.originalTitle="";this.options.title=this.options.title||this.originalTitle;var g=this,i=g.options,b=i.title||" ",f=a.ui.dialog.getTitleId(g.element),j=(g.uiDialog=a("
      ")).appendTo(document.body).hide().addClass("ui-dialog ui-widget ui-widget-content ui-corner-all "+ +i.dialogClass).css({zIndex:i.zIndex}).attr("tabIndex",-1).css("outline",0).keydown(function(n){if(i.closeOnEscape&&!n.isDefaultPrevented()&&n.keyCode&&n.keyCode===a.ui.keyCode.ESCAPE){g.close(n);n.preventDefault()}}).attr({role:"dialog","aria-labelledby":f}).mousedown(function(n){g.moveToTop(false,n)});g.element.show().removeAttr("title").addClass("ui-dialog-content ui-widget-content").appendTo(j);var l=(g.uiDialogTitlebar=a("
      ")).addClass("ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix").prependTo(j), +o=a('').addClass("ui-dialog-titlebar-close ui-corner-all").attr("role","button").hover(function(){o.addClass("ui-state-hover")},function(){o.removeClass("ui-state-hover")}).focus(function(){o.addClass("ui-state-focus")}).blur(function(){o.removeClass("ui-state-focus")}).click(function(n){g.close(n);return false}).appendTo(l);(g.uiDialogTitlebarCloseText=a("")).addClass("ui-icon ui-icon-closethick").text(i.closeText).appendTo(o);a("").addClass("ui-dialog-title").attr("id", +f).html(b).prependTo(l);if(a.isFunction(i.beforeclose)&&!a.isFunction(i.beforeClose))i.beforeClose=i.beforeclose;l.find("*").add(l).disableSelection();i.draggable&&a.fn.draggable&&g._makeDraggable();i.resizable&&a.fn.resizable&&g._makeResizable();g._createButtons(i.buttons);g._isOpen=false;a.fn.bgiframe&&j.bgiframe()},_init:function(){this.options.autoOpen&&this.open()},destroy:function(){var g=this;g.overlay&&g.overlay.destroy();g.uiDialog.hide();g.element.unbind(".dialog").removeData("dialog").removeClass("ui-dialog-content ui-widget-content").hide().appendTo("body"); +g.uiDialog.remove();g.originalTitle&&g.element.attr("title",g.originalTitle);return g},widget:function(){return this.uiDialog},close:function(g){var i=this,b,f;if(false!==i._trigger("beforeClose",g)){i.overlay&&i.overlay.destroy();i.uiDialog.unbind("keypress.ui-dialog");i._isOpen=false;if(i.options.hide)i.uiDialog.hide(i.options.hide,function(){i._trigger("close",g)});else{i.uiDialog.hide();i._trigger("close",g)}a.ui.dialog.overlay.resize();if(i.options.modal){b=0;a(".ui-dialog").each(function(){if(this!== +i.uiDialog[0]){f=a(this).css("z-index");isNaN(f)||(b=Math.max(b,f))}});a.ui.dialog.maxZ=b}return i}},isOpen:function(){return this._isOpen},moveToTop:function(g,i){var b=this,f=b.options;if(f.modal&&!g||!f.stack&&!f.modal)return b._trigger("focus",i);if(f.zIndex>a.ui.dialog.maxZ)a.ui.dialog.maxZ=f.zIndex;if(b.overlay){a.ui.dialog.maxZ+=1;b.overlay.$el.css("z-index",a.ui.dialog.overlay.maxZ=a.ui.dialog.maxZ)}g={scrollTop:b.element.scrollTop(),scrollLeft:b.element.scrollLeft()};a.ui.dialog.maxZ+=1; +b.uiDialog.css("z-index",a.ui.dialog.maxZ);b.element.attr(g);b._trigger("focus",i);return b},open:function(){if(!this._isOpen){var g=this,i=g.options,b=g.uiDialog;g.overlay=i.modal?new a.ui.dialog.overlay(g):null;g._size();g._position(i.position);b.show(i.show);g.moveToTop(true);i.modal&&b.bind("keypress.ui-dialog",function(f){if(f.keyCode===a.ui.keyCode.TAB){var j=a(":tabbable",this),l=j.filter(":first");j=j.filter(":last");if(f.target===j[0]&&!f.shiftKey){l.focus(1);return false}else if(f.target=== +l[0]&&f.shiftKey){j.focus(1);return false}}});a(g.element.find(":tabbable").get().concat(b.find(".ui-dialog-buttonpane :tabbable").get().concat(b.get()))).eq(0).focus();g._isOpen=true;g._trigger("open");return g}},_createButtons:function(g){var i=this,b=false,f=a("
      ").addClass("ui-dialog-buttonpane ui-widget-content ui-helper-clearfix"),j=a("
      ").addClass("ui-dialog-buttonset").appendTo(f);i.uiDialog.find(".ui-dialog-buttonpane").remove();typeof g==="object"&&g!==null&&a.each(g, +function(){return!(b=true)});if(b){a.each(g,function(l,o){o=a.isFunction(o)?{click:o,text:l}:o;var n=a('').click(function(){o.click.apply(i.element[0],arguments)}).appendTo(j);a.each(o,function(k,m){if(k!=="click")k in h?n[k](m):n.attr(k,m)});a.fn.button&&n.button()});f.appendTo(i.uiDialog)}},_makeDraggable:function(){function g(l){return{position:l.position,offset:l.offset}}var i=this,b=i.options,f=a(document),j;i.uiDialog.draggable({cancel:".ui-dialog-content, .ui-dialog-titlebar-close", +handle:".ui-dialog-titlebar",containment:"document",start:function(l,o){j=b.height==="auto"?"auto":a(this).height();a(this).height(a(this).height()).addClass("ui-dialog-dragging");i._trigger("dragStart",l,g(o))},drag:function(l,o){i._trigger("drag",l,g(o))},stop:function(l,o){b.position=[o.position.left-f.scrollLeft(),o.position.top-f.scrollTop()];a(this).removeClass("ui-dialog-dragging").height(j);i._trigger("dragStop",l,g(o));a.ui.dialog.overlay.resize()}})},_makeResizable:function(g){function i(l){return{originalPosition:l.originalPosition, +originalSize:l.originalSize,position:l.position,size:l.size}}g=g===d?this.options.resizable:g;var b=this,f=b.options,j=b.uiDialog.css("position");g=typeof g==="string"?g:"n,e,s,w,se,sw,ne,nw";b.uiDialog.resizable({cancel:".ui-dialog-content",containment:"document",alsoResize:b.element,maxWidth:f.maxWidth,maxHeight:f.maxHeight,minWidth:f.minWidth,minHeight:b._minHeight(),handles:g,start:function(l,o){a(this).addClass("ui-dialog-resizing");b._trigger("resizeStart",l,i(o))},resize:function(l,o){b._trigger("resize", +l,i(o))},stop:function(l,o){a(this).removeClass("ui-dialog-resizing");f.height=a(this).height();f.width=a(this).width();b._trigger("resizeStop",l,i(o));a.ui.dialog.overlay.resize()}}).css("position",j).find(".ui-resizable-se").addClass("ui-icon ui-icon-grip-diagonal-se")},_minHeight:function(){var g=this.options;return g.height==="auto"?g.minHeight:Math.min(g.minHeight,g.height)},_position:function(g){var i=[],b=[0,0],f;if(g){if(typeof g==="string"||typeof g==="object"&&"0"in g){i=g.split?g.split(" "): +[g[0],g[1]];if(i.length===1)i[1]=i[0];a.each(["left","top"],function(j,l){if(+i[j]===i[j]){b[j]=i[j];i[j]=l}});g={my:i.join(" "),at:i.join(" "),offset:b.join(" ")}}g=a.extend({},a.ui.dialog.prototype.options.position,g)}else g=a.ui.dialog.prototype.options.position;(f=this.uiDialog.is(":visible"))||this.uiDialog.show();this.uiDialog.css({top:0,left:0}).position(a.extend({of:window},g));f||this.uiDialog.hide()},_setOptions:function(g){var i=this,b={},f=false;a.each(g,function(j,l){i._setOption(j,l); +if(j in c)f=true;if(j in e)b[j]=l});f&&this._size();this.uiDialog.is(":data(resizable)")&&this.uiDialog.resizable("option",b)},_setOption:function(g,i){var b=this,f=b.uiDialog;switch(g){case "beforeclose":g="beforeClose";break;case "buttons":b._createButtons(i);break;case "closeText":b.uiDialogTitlebarCloseText.text(""+i);break;case "dialogClass":f.removeClass(b.options.dialogClass).addClass("ui-dialog ui-widget ui-widget-content ui-corner-all "+i);break;case "disabled":i?f.addClass("ui-dialog-disabled"): +f.removeClass("ui-dialog-disabled");break;case "draggable":var j=f.is(":data(draggable)");j&&!i&&f.draggable("destroy");!j&&i&&b._makeDraggable();break;case "position":b._position(i);break;case "resizable":(j=f.is(":data(resizable)"))&&!i&&f.resizable("destroy");j&&typeof i==="string"&&f.resizable("option","handles",i);!j&&i!==false&&b._makeResizable(i);break;case "title":a(".ui-dialog-title",b.uiDialogTitlebar).html(""+(i||" "));break}a.Widget.prototype._setOption.apply(b,arguments)},_size:function(){var g= +this.options,i,b,f=this.uiDialog.is(":visible");this.element.show().css({width:"auto",minHeight:0,height:0});if(g.minWidth>g.width)g.width=g.minWidth;i=this.uiDialog.css({height:"auto",width:g.width}).height();b=Math.max(0,g.minHeight-i);if(g.height==="auto")if(a.support.minHeight)this.element.css({minHeight:b,height:"auto"});else{this.uiDialog.show();g=this.element.css("height","auto").height();f||this.uiDialog.hide();this.element.height(Math.max(g,b))}else this.element.height(Math.max(g.height- +i,0));this.uiDialog.is(":data(resizable)")&&this.uiDialog.resizable("option","minHeight",this._minHeight())}});a.extend(a.ui.dialog,{version:"1.8.16",uuid:0,maxZ:0,getTitleId:function(g){g=g.attr("id");if(!g){this.uuid+=1;g=this.uuid}return"ui-dialog-title-"+g},overlay:function(g){this.$el=a.ui.dialog.overlay.create(g)}});a.extend(a.ui.dialog.overlay,{instances:[],oldInstances:[],maxZ:0,events:a.map("focus,mousedown,mouseup,keydown,keypress,click".split(","),function(g){return g+".dialog-overlay"}).join(" "), +create:function(g){if(this.instances.length===0){setTimeout(function(){a.ui.dialog.overlay.instances.length&&a(document).bind(a.ui.dialog.overlay.events,function(b){if(a(b.target).zIndex()").addClass("ui-widget-overlay")).appendTo(document.body).css({width:this.width(),height:this.height()});a.fn.bgiframe&&i.bgiframe();this.instances.push(i);return i},destroy:function(g){var i=a.inArray(g,this.instances);i!=-1&&this.oldInstances.push(this.instances.splice(i,1)[0]);this.instances.length===0&&a([document,window]).unbind(".dialog-overlay");g.remove();var b=0;a.each(this.instances,function(){b=Math.max(b,this.css("z-index"))});this.maxZ=b},height:function(){var g,i;if(a.browser.msie&& +a.browser.version<7){g=Math.max(document.documentElement.scrollHeight,document.body.scrollHeight);i=Math.max(document.documentElement.offsetHeight,document.body.offsetHeight);return g0?g.left-b:Math.max(g.left-i.collisionPosition.left,g.left)},top:function(g,i){var b=a(window);b=i.collisionPosition.top+i.collisionHeight-b.height()-b.scrollTop();g.top=b>0?g.top-b:Math.max(g.top-i.collisionPosition.top,g.top)}},flip:{left:function(g,i){if(i.at[0]!=="center"){var b=a(window);b=i.collisionPosition.left+i.collisionWidth-b.width()-b.scrollLeft();var f=i.my[0]==="left"?-i.elemWidth:i.my[0]==="right"?i.elemWidth:0,j=i.at[0]==="left"?i.targetWidth:-i.targetWidth,l=-2*i.offset[0];g.left+= +i.collisionPosition.left<0?f+j+l:b>0?f+j+l:0}},top:function(g,i){if(i.at[1]!=="center"){var b=a(window);b=i.collisionPosition.top+i.collisionHeight-b.height()-b.scrollTop();var f=i.my[1]==="top"?-i.elemHeight:i.my[1]==="bottom"?i.elemHeight:0,j=i.at[1]==="top"?i.targetHeight:-i.targetHeight,l=-2*i.offset[1];g.top+=i.collisionPosition.top<0?f+j+l:b>0?f+j+l:0}}}};if(!a.offset.setOffset){a.offset.setOffset=function(g,i){if(/static/.test(a.curCSS(g,"position")))g.style.position="relative";var b=a(g), +f=b.offset(),j=parseInt(a.curCSS(g,"top",true),10)||0,l=parseInt(a.curCSS(g,"left",true),10)||0;f={top:i.top-f.top+j,left:i.left-f.left+l};"using"in i?i.using.call(g,f):b.css(f)};a.fn.offset=function(g){var i=this[0];if(!i||!i.ownerDocument)return null;if(g)return this.each(function(){a.offset.setOffset(this,g)});return h.call(this)}}})(jQuery); +(function(a,d){a.widget("ui.progressbar",{options:{value:0,max:100},min:0,_create:function(){this.element.addClass("ui-progressbar ui-widget ui-widget-content ui-corner-all").attr({role:"progressbar","aria-valuemin":this.min,"aria-valuemax":this.options.max,"aria-valuenow":this._value()});this.valueDiv=a("
      ").appendTo(this.element);this.oldValue=this._value();this._refreshValue()},destroy:function(){this.element.removeClass("ui-progressbar ui-widget ui-widget-content ui-corner-all").removeAttr("role").removeAttr("aria-valuemin").removeAttr("aria-valuemax").removeAttr("aria-valuenow"); +this.valueDiv.remove();a.Widget.prototype.destroy.apply(this,arguments)},value:function(c){if(c===d)return this._value();this._setOption("value",c);return this},_setOption:function(c,e){if(c==="value"){this.options.value=e;this._refreshValue();this._value()===this.options.max&&this._trigger("complete")}a.Widget.prototype._setOption.apply(this,arguments)},_value:function(){var c=this.options.value;if(typeof c!=="number")c=0;return Math.min(this.options.max,Math.max(this.min,c))},_percentage:function(){return 100* +this._value()/this.options.max},_refreshValue:function(){var c=this.value(),e=this._percentage();if(this.oldValue!==c){this.oldValue=c;this._trigger("change")}this.valueDiv.toggle(c>this.min).toggleClass("ui-corner-right",c===this.options.max).width(e.toFixed(0)+"%");this.element.attr("aria-valuenow",c)}});a.extend(a.ui.progressbar,{version:"1.8.16"})})(jQuery); +(function(a){a.widget("ui.slider",a.ui.mouse,{widgetEventPrefix:"slide",options:{animate:false,distance:0,max:100,min:0,orientation:"horizontal",range:false,step:1,value:0,values:null},_create:function(){var d=this,c=this.options,e=this.element.find(".ui-slider-handle").addClass("ui-state-default ui-corner-all"),h=c.values&&c.values.length||1,g=[];this._mouseSliding=this._keySliding=false;this._animateOff=true;this._handleIndex=null;this._detectOrientation();this._mouseInit();this.element.addClass("ui-slider ui-slider-"+ +this.orientation+" ui-widget ui-widget-content ui-corner-all"+(c.disabled?" ui-slider-disabled ui-disabled":""));this.range=a([]);if(c.range){if(c.range===true){if(!c.values)c.values=[this._valueMin(),this._valueMin()];if(c.values.length&&c.values.length!==2)c.values=[c.values[0],c.values[0]]}this.range=a("
      ").appendTo(this.element).addClass("ui-slider-range ui-widget-header"+(c.range==="min"||c.range==="max"?" ui-slider-range-"+c.range:""))}for(var i=e.length;i"); +this.handles=e.add(a(g.join("")).appendTo(d.element));this.handle=this.handles.eq(0);this.handles.add(this.range).filter("a").click(function(b){b.preventDefault()}).hover(function(){c.disabled||a(this).addClass("ui-state-hover")},function(){a(this).removeClass("ui-state-hover")}).focus(function(){if(c.disabled)a(this).blur();else{a(".ui-slider .ui-state-focus").removeClass("ui-state-focus");a(this).addClass("ui-state-focus")}}).blur(function(){a(this).removeClass("ui-state-focus")});this.handles.each(function(b){a(this).data("index.ui-slider-handle", +b)});this.handles.keydown(function(b){var f=true,j=a(this).data("index.ui-slider-handle"),l,o,n;if(!d.options.disabled){switch(b.keyCode){case a.ui.keyCode.HOME:case a.ui.keyCode.END:case a.ui.keyCode.PAGE_UP:case a.ui.keyCode.PAGE_DOWN:case a.ui.keyCode.UP:case a.ui.keyCode.RIGHT:case a.ui.keyCode.DOWN:case a.ui.keyCode.LEFT:f=false;if(!d._keySliding){d._keySliding=true;a(this).addClass("ui-state-active");l=d._start(b,j);if(l===false)return}break}n=d.options.step;l=d.options.values&&d.options.values.length? +(o=d.values(j)):(o=d.value());switch(b.keyCode){case a.ui.keyCode.HOME:o=d._valueMin();break;case a.ui.keyCode.END:o=d._valueMax();break;case a.ui.keyCode.PAGE_UP:o=d._trimAlignValue(l+(d._valueMax()-d._valueMin())/5);break;case a.ui.keyCode.PAGE_DOWN:o=d._trimAlignValue(l-(d._valueMax()-d._valueMin())/5);break;case a.ui.keyCode.UP:case a.ui.keyCode.RIGHT:if(l===d._valueMax())return;o=d._trimAlignValue(l+n);break;case a.ui.keyCode.DOWN:case a.ui.keyCode.LEFT:if(l===d._valueMin())return;o=d._trimAlignValue(l- +n);break}d._slide(b,j,o);return f}}).keyup(function(b){var f=a(this).data("index.ui-slider-handle");if(d._keySliding){d._keySliding=false;d._stop(b,f);d._change(b,f);a(this).removeClass("ui-state-active")}});this._refreshValue();this._animateOff=false},destroy:function(){this.handles.remove();this.range.remove();this.element.removeClass("ui-slider ui-slider-horizontal ui-slider-vertical ui-slider-disabled ui-widget ui-widget-content ui-corner-all").removeData("slider").unbind(".slider");this._mouseDestroy(); +return this},_mouseCapture:function(d){var c=this.options,e,h,g,i,b;if(c.disabled)return false;this.elementSize={width:this.element.outerWidth(),height:this.element.outerHeight()};this.elementOffset=this.element.offset();e=this._normValueFromMouse({x:d.pageX,y:d.pageY});h=this._valueMax()-this._valueMin()+1;i=this;this.handles.each(function(f){var j=Math.abs(e-i.values(f));if(h>j){h=j;g=a(this);b=f}});if(c.range===true&&this.values(1)===c.min){b+=1;g=a(this.handles[b])}if(this._start(d,b)===false)return false; +this._mouseSliding=true;i._handleIndex=b;g.addClass("ui-state-active").focus();c=g.offset();this._clickOffset=!a(d.target).parents().andSelf().is(".ui-slider-handle")?{left:0,top:0}:{left:d.pageX-c.left-g.width()/2,top:d.pageY-c.top-g.height()/2-(parseInt(g.css("borderTopWidth"),10)||0)-(parseInt(g.css("borderBottomWidth"),10)||0)+(parseInt(g.css("marginTop"),10)||0)};this.handles.hasClass("ui-state-hover")||this._slide(d,b,e);return this._animateOff=true},_mouseStart:function(){return true},_mouseDrag:function(d){var c= +this._normValueFromMouse({x:d.pageX,y:d.pageY});this._slide(d,this._handleIndex,c);return false},_mouseStop:function(d){this.handles.removeClass("ui-state-active");this._mouseSliding=false;this._stop(d,this._handleIndex);this._change(d,this._handleIndex);this._clickOffset=this._handleIndex=null;return this._animateOff=false},_detectOrientation:function(){this.orientation=this.options.orientation==="vertical"?"vertical":"horizontal"},_normValueFromMouse:function(d){var c;if(this.orientation==="horizontal"){c= +this.elementSize.width;d=d.x-this.elementOffset.left-(this._clickOffset?this._clickOffset.left:0)}else{c=this.elementSize.height;d=d.y-this.elementOffset.top-(this._clickOffset?this._clickOffset.top:0)}c=d/c;if(c>1)c=1;if(c<0)c=0;if(this.orientation==="vertical")c=1-c;d=this._valueMax()-this._valueMin();return this._trimAlignValue(this._valueMin()+c*d)},_start:function(d,c){var e={handle:this.handles[c],value:this.value()};if(this.options.values&&this.options.values.length){e.value=this.values(c); +e.values=this.values()}return this._trigger("start",d,e)},_slide:function(d,c,e){var h;if(this.options.values&&this.options.values.length){h=this.values(c?0:1);if(this.options.values.length===2&&this.options.range===true&&(c===0&&e>h||c===1&&e1){this.options.values[d]=this._trimAlignValue(c);this._refreshValue();this._change(null,d)}else if(arguments.length)if(a.isArray(arguments[0])){e=this.options.values;h=arguments[0];for(g=0;g=this._valueMax())return this._valueMax();var c=this.options.step>0?this.options.step:1,e=(d-this._valueMin())%c;d=d-e;if(Math.abs(e)*2>=c)d+=e>0?c:-c;return parseFloat(d.toFixed(5))},_valueMin:function(){return this.options.min},_valueMax:function(){return this.options.max},_refreshValue:function(){var d= +this.options.range,c=this.options,e=this,h=!this._animateOff?c.animate:false,g,i={},b,f,j,l;if(this.options.values&&this.options.values.length)this.handles.each(function(o){g=(e.values(o)-e._valueMin())/(e._valueMax()-e._valueMin())*100;i[e.orientation==="horizontal"?"left":"bottom"]=g+"%";a(this).stop(1,1)[h?"animate":"css"](i,c.animate);if(e.options.range===true)if(e.orientation==="horizontal"){if(o===0)e.range.stop(1,1)[h?"animate":"css"]({left:g+"%"},c.animate);if(o===1)e.range[h?"animate":"css"]({width:g- +b+"%"},{queue:false,duration:c.animate})}else{if(o===0)e.range.stop(1,1)[h?"animate":"css"]({bottom:g+"%"},c.animate);if(o===1)e.range[h?"animate":"css"]({height:g-b+"%"},{queue:false,duration:c.animate})}b=g});else{f=this.value();j=this._valueMin();l=this._valueMax();g=l!==j?(f-j)/(l-j)*100:0;i[e.orientation==="horizontal"?"left":"bottom"]=g+"%";this.handle.stop(1,1)[h?"animate":"css"](i,c.animate);if(d==="min"&&this.orientation==="horizontal")this.range.stop(1,1)[h?"animate":"css"]({width:g+"%"}, +c.animate);if(d==="max"&&this.orientation==="horizontal")this.range[h?"animate":"css"]({width:100-g+"%"},{queue:false,duration:c.animate});if(d==="min"&&this.orientation==="vertical")this.range.stop(1,1)[h?"animate":"css"]({height:g+"%"},c.animate);if(d==="max"&&this.orientation==="vertical")this.range[h?"animate":"css"]({height:100-g+"%"},{queue:false,duration:c.animate})}}});a.extend(a.ui.slider,{version:"1.8.16"})})(jQuery); +(function(a,d){function c(){return++h}function e(){return++g}var h=0,g=0;a.widget("ui.tabs",{options:{add:null,ajaxOptions:null,cache:false,cookie:null,collapsible:false,disable:null,disabled:[],enable:null,event:"click",fx:null,idPrefix:"ui-tabs-",load:null,panelTemplate:"
      ",remove:null,select:null,show:null,spinner:"Loading…",tabTemplate:"
    • #{label}
    • "},_create:function(){this._tabify(true)},_setOption:function(i,b){if(i=="selected")this.options.collapsible&& +b==this.options.selected||this.select(b);else{this.options[i]=b;this._tabify()}},_tabId:function(i){return i.title&&i.title.replace(/\s/g,"_").replace(/[^\w\u00c0-\uFFFF-]/g,"")||this.options.idPrefix+c()},_sanitizeSelector:function(i){return i.replace(/:/g,"\\:")},_cookie:function(){var i=this.cookie||(this.cookie=this.options.cookie.name||"ui-tabs-"+e());return a.cookie.apply(null,[i].concat(a.makeArray(arguments)))},_ui:function(i,b){return{tab:i,panel:b,index:this.anchors.index(i)}},_cleanup:function(){this.lis.filter(".ui-state-processing").removeClass("ui-state-processing").find("span:data(label.tabs)").each(function(){var i= +a(this);i.html(i.data("label.tabs")).removeData("label.tabs")})},_tabify:function(i){function b(r,u){r.css("display","");!a.support.opacity&&u.opacity&&r[0].style.removeAttribute("filter")}var f=this,j=this.options,l=/^#.+/;this.list=this.element.find("ol,ul").eq(0);this.lis=a(" > li:has(a[href])",this.list);this.anchors=this.lis.map(function(){return a("a",this)[0]});this.panels=a([]);this.anchors.each(function(r,u){var v=a(u).attr("href"),w=v.split("#")[0],x;if(w&&(w===location.toString().split("#")[0]|| +(x=a("base")[0])&&w===x.href)){v=u.hash;u.href=v}if(l.test(v))f.panels=f.panels.add(f.element.find(f._sanitizeSelector(v)));else if(v&&v!=="#"){a.data(u,"href.tabs",v);a.data(u,"load.tabs",v.replace(/#.*$/,""));v=f._tabId(u);u.href="#"+v;u=f.element.find("#"+v);if(!u.length){u=a(j.panelTemplate).attr("id",v).addClass("ui-tabs-panel ui-widget-content ui-corner-bottom").insertAfter(f.panels[r-1]||f.list);u.data("destroy.tabs",true)}f.panels=f.panels.add(u)}else j.disabled.push(r)});if(i){this.element.addClass("ui-tabs ui-widget ui-widget-content ui-corner-all"); +this.list.addClass("ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all");this.lis.addClass("ui-state-default ui-corner-top");this.panels.addClass("ui-tabs-panel ui-widget-content ui-corner-bottom");if(j.selected===d){location.hash&&this.anchors.each(function(r,u){if(u.hash==location.hash){j.selected=r;return false}});if(typeof j.selected!=="number"&&j.cookie)j.selected=parseInt(f._cookie(),10);if(typeof j.selected!=="number"&&this.lis.filter(".ui-tabs-selected").length)j.selected= +this.lis.index(this.lis.filter(".ui-tabs-selected"));j.selected=j.selected||(this.lis.length?0:-1)}else if(j.selected===null)j.selected=-1;j.selected=j.selected>=0&&this.anchors[j.selected]||j.selected<0?j.selected:0;j.disabled=a.unique(j.disabled.concat(a.map(this.lis.filter(".ui-state-disabled"),function(r){return f.lis.index(r)}))).sort();a.inArray(j.selected,j.disabled)!=-1&&j.disabled.splice(a.inArray(j.selected,j.disabled),1);this.panels.addClass("ui-tabs-hide");this.lis.removeClass("ui-tabs-selected ui-state-active"); +if(j.selected>=0&&this.anchors.length){f.element.find(f._sanitizeSelector(f.anchors[j.selected].hash)).removeClass("ui-tabs-hide");this.lis.eq(j.selected).addClass("ui-tabs-selected ui-state-active");f.element.queue("tabs",function(){f._trigger("show",null,f._ui(f.anchors[j.selected],f.element.find(f._sanitizeSelector(f.anchors[j.selected].hash))[0]))});this.load(j.selected)}a(window).bind("unload",function(){f.lis.add(f.anchors).unbind(".tabs");f.lis=f.anchors=f.panels=null})}else j.selected=this.lis.index(this.lis.filter(".ui-tabs-selected")); +this.element[j.collapsible?"addClass":"removeClass"]("ui-tabs-collapsible");j.cookie&&this._cookie(j.selected,j.cookie);i=0;for(var o;o=this.lis[i];i++)a(o)[a.inArray(i,j.disabled)!=-1&&!a(o).hasClass("ui-tabs-selected")?"addClass":"removeClass"]("ui-state-disabled");j.cache===false&&this.anchors.removeData("cache.tabs");this.lis.add(this.anchors).unbind(".tabs");if(j.event!=="mouseover"){var n=function(r,u){u.is(":not(.ui-state-disabled)")&&u.addClass("ui-state-"+r)},k=function(r,u){u.removeClass("ui-state-"+ +r)};this.lis.bind("mouseover.tabs",function(){n("hover",a(this))});this.lis.bind("mouseout.tabs",function(){k("hover",a(this))});this.anchors.bind("focus.tabs",function(){n("focus",a(this).closest("li"))});this.anchors.bind("blur.tabs",function(){k("focus",a(this).closest("li"))})}var m,p;if(j.fx)if(a.isArray(j.fx)){m=j.fx[0];p=j.fx[1]}else m=p=j.fx;var q=p?function(r,u){a(r).closest("li").addClass("ui-tabs-selected ui-state-active");u.hide().removeClass("ui-tabs-hide").animate(p,p.duration||"normal", +function(){b(u,p);f._trigger("show",null,f._ui(r,u[0]))})}:function(r,u){a(r).closest("li").addClass("ui-tabs-selected ui-state-active");u.removeClass("ui-tabs-hide");f._trigger("show",null,f._ui(r,u[0]))},s=m?function(r,u){u.animate(m,m.duration||"normal",function(){f.lis.removeClass("ui-tabs-selected ui-state-active");u.addClass("ui-tabs-hide");b(u,m);f.element.dequeue("tabs")})}:function(r,u){f.lis.removeClass("ui-tabs-selected ui-state-active");u.addClass("ui-tabs-hide");f.element.dequeue("tabs")}; +this.anchors.bind(j.event+".tabs",function(){var r=this,u=a(r).closest("li"),v=f.panels.filter(":not(.ui-tabs-hide)"),w=f.element.find(f._sanitizeSelector(r.hash));if(u.hasClass("ui-tabs-selected")&&!j.collapsible||u.hasClass("ui-state-disabled")||u.hasClass("ui-state-processing")||f.panels.filter(":animated").length||f._trigger("select",null,f._ui(this,w[0]))===false){this.blur();return false}j.selected=f.anchors.index(this);f.abort();if(j.collapsible)if(u.hasClass("ui-tabs-selected")){j.selected= +-1;j.cookie&&f._cookie(j.selected,j.cookie);f.element.queue("tabs",function(){s(r,v)}).dequeue("tabs");this.blur();return false}else if(!v.length){j.cookie&&f._cookie(j.selected,j.cookie);f.element.queue("tabs",function(){q(r,w)});f.load(f.anchors.index(this));this.blur();return false}j.cookie&&f._cookie(j.selected,j.cookie);if(w.length){v.length&&f.element.queue("tabs",function(){s(r,v)});f.element.queue("tabs",function(){q(r,w)});f.load(f.anchors.index(this))}else throw"jQuery UI Tabs: Mismatching fragment identifier."; +a.browser.msie&&this.blur()});this.anchors.bind("click.tabs",function(){return false})},_getIndex:function(i){if(typeof i=="string")i=this.anchors.index(this.anchors.filter("[href$="+i+"]"));return i},destroy:function(){var i=this.options;this.abort();this.element.unbind(".tabs").removeClass("ui-tabs ui-widget ui-widget-content ui-corner-all ui-tabs-collapsible").removeData("tabs");this.list.removeClass("ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all");this.anchors.each(function(){var b= +a.data(this,"href.tabs");if(b)this.href=b;var f=a(this).unbind(".tabs");a.each(["href","load","cache"],function(j,l){f.removeData(l+".tabs")})});this.lis.unbind(".tabs").add(this.panels).each(function(){a.data(this,"destroy.tabs")?a(this).remove():a(this).removeClass("ui-state-default ui-corner-top ui-tabs-selected ui-state-active ui-state-hover ui-state-focus ui-state-disabled ui-tabs-panel ui-widget-content ui-corner-bottom ui-tabs-hide")});i.cookie&&this._cookie(null,i.cookie);return this},add:function(i, +b,f){if(f===d)f=this.anchors.length;var j=this,l=this.options;b=a(l.tabTemplate.replace(/#\{href\}/g,i).replace(/#\{label\}/g,b));i=!i.indexOf("#")?i.replace("#",""):this._tabId(a("a",b)[0]);b.addClass("ui-state-default ui-corner-top").data("destroy.tabs",true);var o=j.element.find("#"+i);o.length||(o=a(l.panelTemplate).attr("id",i).data("destroy.tabs",true));o.addClass("ui-tabs-panel ui-widget-content ui-corner-bottom ui-tabs-hide");if(f>=this.lis.length){b.appendTo(this.list);o.appendTo(this.list[0].parentNode)}else{b.insertBefore(this.lis[f]); +o.insertBefore(this.panels[f])}l.disabled=a.map(l.disabled,function(n){return n>=f?++n:n});this._tabify();if(this.anchors.length==1){l.selected=0;b.addClass("ui-tabs-selected ui-state-active");o.removeClass("ui-tabs-hide");this.element.queue("tabs",function(){j._trigger("show",null,j._ui(j.anchors[0],j.panels[0]))});this.load(0)}this._trigger("add",null,this._ui(this.anchors[f],this.panels[f]));return this},remove:function(i){i=this._getIndex(i);var b=this.options,f=this.lis.eq(i).remove(),j=this.panels.eq(i).remove(); +if(f.hasClass("ui-tabs-selected")&&this.anchors.length>1)this.select(i+(i+1=i?--l:l});this._tabify();this._trigger("remove",null,this._ui(f.find("a")[0],j[0]));return this},enable:function(i){i=this._getIndex(i);var b=this.options;if(a.inArray(i,b.disabled)!=-1){this.lis.eq(i).removeClass("ui-state-disabled");b.disabled=a.grep(b.disabled,function(f){return f!=i});this._trigger("enable",null, +this._ui(this.anchors[i],this.panels[i]));return this}},disable:function(i){i=this._getIndex(i);var b=this.options;if(i!=b.selected){this.lis.eq(i).addClass("ui-state-disabled");b.disabled.push(i);b.disabled.sort();this._trigger("disable",null,this._ui(this.anchors[i],this.panels[i]))}return this},select:function(i){i=this._getIndex(i);if(i==-1)if(this.options.collapsible&&this.options.selected!=-1)i=this.options.selected;else return this;this.anchors.eq(i).trigger(this.options.event+".tabs");return this}, +load:function(i){i=this._getIndex(i);var b=this,f=this.options,j=this.anchors.eq(i)[0],l=a.data(j,"load.tabs");this.abort();if(!l||this.element.queue("tabs").length!==0&&a.data(j,"cache.tabs"))this.element.dequeue("tabs");else{this.lis.eq(i).addClass("ui-state-processing");if(f.spinner){var o=a("span",j);o.data("label.tabs",o.html()).html(f.spinner)}this.xhr=a.ajax(a.extend({},f.ajaxOptions,{url:l,success:function(n,k){b.element.find(b._sanitizeSelector(j.hash)).html(n);b._cleanup();f.cache&&a.data(j, +"cache.tabs",true);b._trigger("load",null,b._ui(b.anchors[i],b.panels[i]));try{f.ajaxOptions.success(n,k)}catch(m){}},error:function(n,k){b._cleanup();b._trigger("load",null,b._ui(b.anchors[i],b.panels[i]));try{f.ajaxOptions.error(n,k,i,j)}catch(m){}}}));b.element.dequeue("tabs");return this}},abort:function(){this.element.queue([]);this.panels.stop(false,true);this.element.queue("tabs",this.element.queue("tabs").splice(-2,2));if(this.xhr){this.xhr.abort();delete this.xhr}this._cleanup();return this}, +url:function(i,b){this.anchors.eq(i).removeData("cache.tabs").data("load.tabs",b);return this},length:function(){return this.anchors.length}});a.extend(a.ui.tabs,{version:"1.8.16"});a.extend(a.ui.tabs.prototype,{rotation:null,rotate:function(i,b){var f=this,j=this.options,l=f._rotate||(f._rotate=function(o){clearTimeout(f.rotation);f.rotation=setTimeout(function(){var n=j.selected;f.select(++n 1 && String(value) !== "[object Object]") { + options = jQuery.extend({}, options); + + if (value === null || value === undefined) { + options.expires = -1; + } + + if (typeof options.expires === 'number') { + var days = options.expires, t = options.expires = new Date(); + t.setDate(t.getDate() + days); + } + + value = String(value); + + return (document.cookie = [ + encodeURIComponent(key), '=', + options.raw ? value : encodeURIComponent(value), + options.expires ? '; expires=' + options.expires.toUTCString() : '', // use expires attribute, max-age is not supported by IE + options.path ? '; path=' + options.path : '', + options.domain ? '; domain=' + options.domain : '', + options.secure ? '; secure' : '' + ].join('')); + } + + // key and possibly options given, get cookie... + options = value || {}; + var result, decode = options.raw ? function (s) { return s; } : decodeURIComponent; + return (result = new RegExp('(?:^|; )' + encodeURIComponent(key) + '=([^;]*)').exec(document.cookie)) ? decode(result[1]) : null; +}; diff --git a/mysite/mysite/site_media/js/jquery.lazyload-ad-1.4.min.js b/mysite/mysite/site_media/js/jquery.lazyload-ad-1.4.min.js new file mode 100755 index 0000000..f0e6e21 --- /dev/null +++ b/mysite/mysite/site_media/js/jquery.lazyload-ad-1.4.min.js @@ -0,0 +1,19 @@ +var LazyLoader={};LazyLoader.timer={};LazyLoader.scripts=[];LazyLoader.load=function(url,context,callback){var classname=null;var properties=null;try{LazyLoader.scripts.push(url);var script=document.createElement("script");script.src=url;script.type="text/javascript";context.get(0).appendChild(script);if(callback){script.onreadystatechange=function(){if(script.readyState=='loaded'||script.readyState=='complete'){callback();$(script).remove();}} +script.onload=function(){callback();$(script).remove();return;} +try{if(($.browser.webkit&&!navigator.userAgent.match(/Version\/3/))||$.browser.opera){LazyLoader.timer[url]=setInterval(function(){if(/loaded|complete/.test(document.readyState)){clearInterval(LazyLoader.timer[url]);callback();}},10);}}catch(e){}}}catch(e){alert(e);}};var xrayAd={div:null,viewport:null,thresold:200,elements:[],adBlockCount:0,w:160,h:200,init:function(){this.div=$('#xrayAd');if(!this.div){this.div=$('
      ',{id:'xrayAd',css:{position:'fixed',top:10,left:10,width:this.w,height:this.h,zIndex:10000,background:'rgba(0,0,0, 0.5)'}});this.div.appendTo($('body'));}},viewportUpdate:function(){if(!this.viewport){this.viewport=$('
      ',{id:'xrayAdViewport',css:{position:'absolute',width:this.w,height:10,zIndex:10001,background:'rgba(255,255,255, 0.3)'}});this.viewport.appendTo(this.div);} +if(!this.viewThresoldTop){this.viewThresoldTop=$('
      ',{id:'xrayAdThresold',css:{position:'absolute',width:this.w,height:1,zIndex:10002,background:'rgba(255,0,0, 0.5)'}});this.viewThresoldTop.appendTo(this.div);this.viewThresoldBottom=this.viewThresoldTop.clone().appendTo(this.div);} +this.bodyHeight=$(document).height();this.bodyWidth=$(window).width();var vH=($(window).height()/this.bodyHeight)*xrayAd.h,vT=($(window).scrollTop()/this.bodyHeight)*xrayAd.h;this.viewport.css({height:vH,top:vT});this.viewThresoldTop.css({top:(($(window).scrollTop()-xrayAd.thresold)/this.bodyHeight)*xrayAd.h});this.viewThresoldBottom.css({top:(($(window).scrollTop()+xrayAd.thresold)/this.bodyHeight)*xrayAd.h+vH-1});if(this.div&&this.div.length){var blocks=this.div.find('.xrayAdBlock');$.each(blocks,function(key,val){var xrayBlock=$(this);var adBlock=$(xrayAd.elements[key]);if(xrayBlock.length&&adBlock.length){var size={};size.off=adBlock.offset();if(size.off){size.top=(size.off.top/xrayAd.bodyHeight)*xrayAd.h;size.left=(size.off.left/xrayAd.bodyWidth)*xrayAd.w;size.w=(Math.max(adBlock.width(),10)/xrayAd.bodyWidth)*xrayAd.w;size.h=(Math.max(adBlock.height(),10)/xrayAd.bodyHeight)*xrayAd.h;var bgColor='#FF0071';bgColor=(adBlock.data('loading')=='true'?'orange':bgColor);bgColor=(adBlock.data('loaded')=='true'?'#00FF00':bgColor);xrayBlock.css({top:size.top,left:size.left,width:size.w,height:size.h,borderColor:bgColor});}}});}},load:function(el,thresold){this.thresold=thresold||0;this.init();var adBlock=$('
      ',{'class':'xrayAdBlock','css':{position:'absolute',background:'#ffffff',border:'1px solid #FF0071',top:0,left:0,width:0,height:0,zIndex:10003}});$.each(el,function(){adBlock.clone().attr('xrayblock','xrayAdBlock_'+(xrayAd.adBlockCount++)).appendTo(xrayAd.div);$(this).bind('onCompleteXray',function(){xrayAd.viewportUpdate();});$(this).bind('onLoadXray',function(){xrayAd.viewportUpdate();});xrayAd.elements.push(this);});xrayAd.viewportUpdate();$(window).bind("scroll",function(event){xrayAd.viewportUpdate();});}};(function($){$.lazyLoadAdRunning=false;$.lazyLoadAdTimers=[];$.fn.lazyLoadAd=function(options){var settings={threshold:0,failurelimit:1,forceLoad:false,event:"scroll",viewport:window,placeholder:false,onLoad:false,onComplete:false,timeout:1500,debug:false,xray:false};if(options){$.extend(settings,options);} +function _debug(){if(typeof console!='undefined'&&settings.debug){var args=[];for(var i=0;isettings.failurelimit){return false;}}});var temp=$.grep(elements,function(element){return!(($(element).data('loaded')=='true')?true:false);});elements=$(temp);});if("scroll"==settings.event){$(settings.viewport).bind("scroll",function(event){if(elements.length==0)return false;$(settings.viewport).trigger("checkLazyLoadAd");});} +this.each(function(_index,_value){var self=$(this);if(undefined==self.attr("original")){self.attr("original",self.attr("src"));} +self.isLoaded=function(){return((self.data('loaded')=='true')?true:false);};self.bind("debug",function(e,status){status=status||'start';if(settings.xray){if(status=='start')self.trigger('onLoadXray');else if(status=='error')self.trigger('onErrorXray');else if(status=='complete')self.trigger('onCompleteXray');} +if(settings.debug){if(status=='start')self.css({border:'3px solid orange'});else if(status=='error')self.css({border:'3px solid red'});else if(status=='complete')self.css({border:'3px solid green'});}});self.one('onComplete',function(){_debug('---> lazyLoadComplete');$(self).removeAttr("original");$.lazyLoadAdRunning=false;self.data('loaded','true');self.trigger('debug','complete');if(typeof settings.onComplete=='function'){try{settings.onComplete()}catch(e){};}});self.stack=[];self.makinaBlock=false;self.bind('makina_go',function(){if(self.makinaBlock)return false;if(self.stack.length>0){var el=self.stack.shift();var wrapAd=self.find('.wrapAd');if(!wrapAd.length){wrapAd=$('
      ').clone();wrapAd.appendTo(self);} +var wrap=$('
      ').clone().appendTo(wrapAd);if(typeof el=='string'){wrap.replaceWith(el);}else if(typeof el=='object'){if(el.is('script')){if(el.attr('src')){_debug('JS to load !! --> '+el.attr('src'));LazyLoader.load(el.attr('src'),self,function(){self.makinaBlock=false;_debug('JS to load !! ++> '+el.attr('src'));self.trigger('makina_go');});} +else{wrap.replaceWith(el);}}else{wrap.replaceWith(el);}} +self.trigger('makina_go');}else{if($.lazyLoadAdTimers.loadJS)clearTimeout($.lazyLoadAdTimers.loadJS);$.lazyLoadAdTimers.loadJS=setTimeout(function(){self.trigger('onComplete');},settings.timeout);}});self.bind('docWrite_direct',function(e,html){var el=$(html);_debug('Fragment Direct Write : ',el,el.length);$.each(el,function(){self.stack.push($(this));});self.trigger('makina_go');});self.bind('docWrite_delayed',function(e,html){_debug('Fragment Delayed Write : ',html);self.numWrappers--;_debug("Fragment append : ",self.numWrappers,html);self.docHtmlCurrent+=html;if(self.numWrappers==0){html=self.docHtmlCurrent;self.docHtmlCurrent='';setTimeout(function(){self.stack.push(html);self.docHtmlCurrent='';self.trigger('makina_go');},0);}});self.numWrappers=0;self.docHtmlCurrent='';self.bind('docWrite_overload',function(){document._writeOriginal=document.write;document.write=document.writeln=function(){var args=arguments,id=null;var html='';for(var i=0;i]*>([\s\S]*?)<\/code>/gi;while((script=regexp.exec(self.html()))){var _s=script[1];_s=_s.replace('','').replace('','');_s=_s.replace(/\>\;/g,'>').replace(/\<\;/g,'<');scripts.push($.trim(_s));} +try{scripts=(scripts.length?scripts.join('\n'):'');_debug('Script to eval : ',scripts);if(scripts!='')eval(scripts);}catch(e){};});self.bind('loadJS',function(e,js2load){var callback=null,script=null;if(js2load.src){callback=js2load.callback|| null;js2load=js2load.src;} +if(js2load.indexOf('?')==-1){js2load+='?_='+(new Date().getTime());}else{js2load+='&_='+(new Date().getTime());} +_debug('loadJS :: ',js2load);LazyLoader.load(js2load,self,function(){_debug('loadJS COMPLETE :: '+js2load);if(callback){callback();} else{$.lazyLoadAdTimers.loadJS=setTimeout(function(){self.trigger('onComplete');},settings.timeout);}});});self.one("load",function(){if(!self.isLoaded()){$.lazyLoadAdRunning=true;self.data('loading','true');self.trigger('debug','start');var srcOriginal=$(self).attr("original");self.history={};_debug('------------------------------ Lazy Load Ad CALL ----');_debug('Context : ',self);self.trigger('docWrite_overload');self.trigger('evalCode');if(srcOriginal){self.trigger('loadJS',srcOriginal);}};});if("scroll"!=settings.event){self.bind(settings.event,function(event){if(!self.isLoaded()){self.trigger("load");}});}});$(settings.viewport).trigger('checkLazyLoadAd');return this;};$.belowthefold=function(element,settings){if(settings.viewport===undefined||settings.viewport===window){var fold=$(window).height()+$(window).scrollTop();}else{var fold=$(settings.viewport).offset().top+$(settings.viewport).height();} +return fold<=$(element).offset().top-settings.threshold;};$.abovethetop=function(element,settings){if(settings.viewport===undefined||settings.viewport===window){var fold=$(window).scrollTop();}else{var fold=$(settings.viewport).offset().top;} +return fold>=$(element).offset().top+settings.threshold+$(element).height();};})(jQuery); \ No newline at end of file diff --git a/mysite/mysite/site_media/js/select-chain.js b/mysite/mysite/site_media/js/select-chain.js new file mode 100755 index 0000000..7049d32 --- /dev/null +++ b/mysite/mysite/site_media/js/select-chain.js @@ -0,0 +1,59 @@ +(function ($) { + $.fn.selectChain = function (options) { + var defaults = { + key: "id", + value: "label" + }; + + var settings = $.extend({}, defaults, options); + + if (!(settings.target instanceof $)) settings.target = $(settings.target); + + return this.each(function () { + var $$ = $(this); + + $$.change(function () { + var data = null; + if (typeof settings.data == 'string') { + data = settings.data + '&' + this.name + '=' + $$.val(); + } else if (typeof settings.data == 'object') { + data = settings.data; + data[this.name] = $$.val(); + } + + settings.target.empty(); + + $.ajax({ + url: settings.url, + data: data, + type: (settings.type || 'get'), + dataType: 'json', + success: function (j) { + var options = [], i = 0, o = null; + + for (i = 0; i < j.length; i++) { + // required to get around IE bug (http://support.microsoft.com/?scid=kb%3Ben-us%3B276228) + o = document.createElement("OPTION"); + o.value = typeof j[i] == 'object' ? j[i][settings.key] : j[i]; + o.text = typeof j[i] == 'object' ? j[i][settings.value] : j[i]; + settings.target.get(0).options[i] = o; + } + + // hand control back to browser for a moment + setTimeout(function () { + settings.target + .find('option:first') + .attr('selected', 'selected') + .parent('select') + .trigger('change'); + }, 0); + }, + error: function (xhr, desc, er) { + // add whatever debug you want here. + alert("an error occurred"); + } + }); + }); + }); + }; +})(jQuery); diff --git a/mysite/mysite/site_media/quickselect/Readme.textile b/mysite/mysite/site_media/quickselect/Readme.textile new file mode 100755 index 0000000..57fb81f --- /dev/null +++ b/mysite/mysite/site_media/quickselect/Readme.textile @@ -0,0 +1,67 @@ +h1. jQuery: QuickSelect + +The QuickSelect plugin allows you to create a text input with a list of specified options, and as you type, those options show up in a list below the input box. You can choose to have it auto-fill the top result into the input box as you type, or select an option using the arrow keys. + +There are a few special powers of this plugin: +# QuickSilver selection mode: As you type, it will use quicksilver ranking mode, and the top result will automatically be selected when you exit the field. +# Select/Options transformation: If you run .quickselect() on a select element, the data from the options will be stored and the select will be turned into an input box of the same id and className(s), and a hidden input of the same name. That way, instead of using a select, the user can simply type what they want and choose from the list. Just render your HTML page with a select and options, and run this plugin to turn it into a quickselect. +# Multiple-field update: Send a jquery object containing multiple input elements, and include a corresponding number of values in the results data, and each input element will be updated with its corresponding value from the data when an item is selected from the drop-down list. + +h4. Installation + +# Include the jquery library in your project. +# Then you'll need the following files for this plugin: +#* "quicksilver.js":http://github.com/dcparker/jquery_plugins/raw/master/quickselect/quicksilver.js +#* OR "string_score.min.js":https://github.com/joshaven/string_score/raw/master/string_score.min.js (a quicksilver-like matcher on magical steroids) +#* "jquery.quickselect.js":http://github.com/dcparker/jquery_plugins/raw/master/quickselect/jquery.quickselect.js +#* "jquery.quickselect.css":http://github.com/dcparker/jquery_plugins/raw/master/quickselect/jquery.quickselect.css + +h4. Usage + +There are several modes in which you can use this plugin... + +The simplest may be just transforming a select/options group into a text input with drop-down. $("select").quickselect(); will do the trick. Running this on a select element will use default options that work best for this type of quickselect control. + +The next mode you might use is ajax. $("input#city_name_field").quickselect({url:'/ajax/cities.json'}); should do the trick. + +Try this mode to make a richer application. Same as the ajax, but include more fields in your json data: $("input#city_name_field").quickselect({url:'/ajax/cities.json', additionalFields:$("input#zipcode_field")}); In your json data, instead of just spitting out an array of city names, make each array element be a two-element array, the first element being the city name (for the field you're typing in), and the second being the corresponding zip code for that city. That way when you select a city, it'll automatically populate the zipcode too! This also works really well for when you need to select a human-readable label but have the actual value be a resource id. Just make a visible text input into a quickselect but in your additionalFields mention a hidden field, and in your data just include the label and the id. + +Note, if you include quicksilver.js or similar.js, quickselect will automatically default to using their pretty smart similarity matching methods. + +* Sample simple option selection: $("input[type=text]#sample1").quickselect({data : ['Option 1', 'Option 2', 'Option 3']}) +* Identical Sample, using data as second argument instead of part of options: $("input[type=text]#sample1").quickselect({}, ['Option 1', 'Option 2', 'Option 3']) +* Sample Zip selection by city json data: $("input[type=text]#sample2_zip").quickselect({data : [{label:'Jonstown',value:22781}, {label:'Hilariton',value:91287}, {label:'Chicago',value:60610}]}) +* Sample City & Zip selection by City name: $("input[type=text]#sample3_city").quickselect({additionalFields : $("#sample3_zip"), data : [{label:'Jonstown',values:['Jonstown',22781]}, {label:'Chicago',values:['Chicago',60610]}]}) + +h4. Options + +Two modes for data: Data, and Ajax. +* data: Include the array of selectable options here, either a flat array: "['option 1', 'option 2']" or expanded with item options: "[{label : 'option 1', value : 'value 1', className : 'type_A'}, {label : 'option 2', value : 'value 2', className : 'type_B'}]". +* ajax: if you want to load data via ajax, put the ajax url here. The query text will be appended as ?q=$value. +* ajaxParams: extra parameters for the ajax url if necessary. These will be encoded into a query string, along with the query ('q') value. +* additionalFields: (element or array of elements to be updated) one or more fields to update with the extra data. Not honored when converting a select/option group to a quickselect control. For example, you may want to provide quickselect on a zipcode field, but when selected, update the city and state field automatically with the results. +* delay: number of milliseconds after typing that the results are re-evaluated. Make this longer if your ajax is bogging down. +* minChars: the minimum number of characters before triggering the drop-down (and ajax, if applicable). +* matchCase: true/false - specify that the drop-down should be case-sensitive. +* matchMethod: One of 'quicksilver', 'contains', or 'startsWith'. If not specified, 'contains' is default, unless quicksilver.js or similar.js is auto-detected (String.prototype.score() is defined), then 'quicksilver' is default, which matches that the first letter of query and result are equal (case-insensitive), and quicksilver matching on the rest of the query. +* autoSelectFirst: (default: true) always have the first matched item selected until the selection is manually changed; tab or enter will choose the top selection. +* selectSingleMatch: use this if NOT using autoSelectFirst, to make the control automatically select the top item when there is only one matched item left. +* exactMatch: use this if you absolutely need the typed value to end up matching one of the list items in the end. If something is typed but no match is found, the text field and all fields specified in additionalFields instantly get blank values. +* autoFill: true/false - use this if you want the text input to automatically try to finish what you're typing as you type, based on the top match. This only works with the 'startsWith' match method. +* maxVisibleItems: limit the number of items shown in the list at any one time. +* onBlank: supply a callback function to be run when there are no results to a query. Do whatever you want to happen when no results are found. Return true to trigger setting all additionalFields to blank values, or false to skip blanking them. +* extraOption: optional, add an extra option to always appear at the bottom of the results list. +* noResultsDefault: optional, add an extra option that only shows up when there are no results, and its associated values will be set to the additionalFields, if any. +* formatItem: optional, assign a function that will transform the item list labels. The function is called for each item with three arguments (item, index, total_count), and is expected to return a string. +* cssFlavor: choose one of the built-in flavors. Default is named 'quickselect'. This causes the next four css classes to be set based on this flavor name, unless you set them explicitly. +* inputClass: css class for styling the text input box. Default options.cssFlavor+'_input' +* loadingClass: css class for styling the text input while loading ajax. Default options.cssFlavor+'_loading' +* resultsClass: css class for styling the drop-down items list. Default options.cssFlavor+'_results' +* selectedClass: css class for styling the currently-selected item in the drop-down list. Default options.cssFlavor+'_selected' +* width: sets the width of the drop-down list. (default: calculated width of the input element) + +h4. Credit + +"http://www.pengoworks.com/workshop/jquery/autocomplete.htm":http://www.pengoworks.com/workshop/jquery/autocomplete.htm - original starting point + +Thank you to "Sabretech":http://www.sabretechllc.com/ and "Argent":http://www.argenttitleresearch.com/ for commissioning this project! diff --git a/mysite/mysite/site_media/quickselect/ask.json b/mysite/mysite/site_media/quickselect/ask.json new file mode 100755 index 0000000..29bc101 --- /dev/null +++ b/mysite/mysite/site_media/quickselect/ask.json @@ -0,0 +1 @@ +[["Alephant", "funny place"], ["Asa", "short name"], ["Adamsvillage", "early town"], ["Adderston", "snakes!"], ["Adelphius", "greeky"], ["Adena Mathena", "Mother Theresa"], ["Adrian", "that's nearby"], ["Akron", "some other place"], ["Albany", "in New York"]] \ No newline at end of file diff --git a/mysite/mysite/site_media/quickselect/jquery-1.2.6.pack.js b/mysite/mysite/site_media/quickselect/jquery-1.2.6.pack.js new file mode 100755 index 0000000..e4199e2 --- /dev/null +++ b/mysite/mysite/site_media/quickselect/jquery-1.2.6.pack.js @@ -0,0 +1,154 @@ +/*! + * jQuery JavaScript Library v1.4.2 + * http://jquery.com/ + * + * Copyright 2010, John Resig + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * Includes Sizzle.js + * http://sizzlejs.com/ + * Copyright 2010, The Dojo Foundation + * Released under the MIT, BSD, and GPL Licenses. + * + * Date: Sat Feb 13 22:33:48 2010 -0500 + */ +(function(A,w){function ma(){if(!c.isReady){try{s.documentElement.doScroll("left")}catch(a){setTimeout(ma,1);return}c.ready()}}function Qa(a,b){b.src?c.ajax({url:b.src,async:false,dataType:"script"}):c.globalEval(b.text||b.textContent||b.innerHTML||"");b.parentNode&&b.parentNode.removeChild(b)}function X(a,b,d,f,e,j){var i=a.length;if(typeof b==="object"){for(var o in b)X(a,o,b[o],f,e,d);return a}if(d!==w){f=!j&&f&&c.isFunction(d);for(o=0;o)[^>]*$|^#([\w-]+)$/,Ua=/^.[^:#\[\.,]*$/,Va=/\S/, +Wa=/^(\s|\u00A0)+|(\s|\u00A0)+$/g,Xa=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,P=navigator.userAgent,xa=false,Q=[],L,$=Object.prototype.toString,aa=Object.prototype.hasOwnProperty,ba=Array.prototype.push,R=Array.prototype.slice,ya=Array.prototype.indexOf;c.fn=c.prototype={init:function(a,b){var d,f;if(!a)return this;if(a.nodeType){this.context=this[0]=a;this.length=1;return this}if(a==="body"&&!b){this.context=s;this[0]=s.body;this.selector="body";this.length=1;return this}if(typeof a==="string")if((d=Ta.exec(a))&& +(d[1]||!b))if(d[1]){f=b?b.ownerDocument||b:s;if(a=Xa.exec(a))if(c.isPlainObject(b)){a=[s.createElement(a[1])];c.fn.attr.call(a,b,true)}else a=[f.createElement(a[1])];else{a=sa([d[1]],[f]);a=(a.cacheable?a.fragment.cloneNode(true):a.fragment).childNodes}return c.merge(this,a)}else{if(b=s.getElementById(d[2])){if(b.id!==d[2])return T.find(a);this.length=1;this[0]=b}this.context=s;this.selector=a;return this}else if(!b&&/^\w+$/.test(a)){this.selector=a;this.context=s;a=s.getElementsByTagName(a);return c.merge(this, +a)}else return!b||b.jquery?(b||T).find(a):c(b).find(a);else if(c.isFunction(a))return T.ready(a);if(a.selector!==w){this.selector=a.selector;this.context=a.context}return c.makeArray(a,this)},selector:"",jquery:"1.4.2",length:0,size:function(){return this.length},toArray:function(){return R.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this.slice(a)[0]:this[a]},pushStack:function(a,b,d){var f=c();c.isArray(a)?ba.apply(f,a):c.merge(f,a);f.prevObject=this;f.context=this.context;if(b=== +"find")f.selector=this.selector+(this.selector?" ":"")+d;else if(b)f.selector=this.selector+"."+b+"("+d+")";return f},each:function(a,b){return c.each(this,a,b)},ready:function(a){c.bindReady();if(c.isReady)a.call(s,c);else Q&&Q.push(a);return this},eq:function(a){return a===-1?this.slice(a):this.slice(a,+a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(R.apply(this,arguments),"slice",R.call(arguments).join(","))},map:function(a){return this.pushStack(c.map(this, +function(b,d){return a.call(b,d,b)}))},end:function(){return this.prevObject||c(null)},push:ba,sort:[].sort,splice:[].splice};c.fn.init.prototype=c.fn;c.extend=c.fn.extend=function(){var a=arguments[0]||{},b=1,d=arguments.length,f=false,e,j,i,o;if(typeof a==="boolean"){f=a;a=arguments[1]||{};b=2}if(typeof a!=="object"&&!c.isFunction(a))a={};if(d===b){a=this;--b}for(;b
      a"; +var e=d.getElementsByTagName("*"),j=d.getElementsByTagName("a")[0];if(!(!e||!e.length||!j)){c.support={leadingWhitespace:d.firstChild.nodeType===3,tbody:!d.getElementsByTagName("tbody").length,htmlSerialize:!!d.getElementsByTagName("link").length,style:/red/.test(j.getAttribute("style")),hrefNormalized:j.getAttribute("href")==="/a",opacity:/^0.55$/.test(j.style.opacity),cssFloat:!!j.style.cssFloat,checkOn:d.getElementsByTagName("input")[0].value==="on",optSelected:s.createElement("select").appendChild(s.createElement("option")).selected, +parentNode:d.removeChild(d.appendChild(s.createElement("div"))).parentNode===null,deleteExpando:true,checkClone:false,scriptEval:false,noCloneEvent:true,boxModel:null};b.type="text/javascript";try{b.appendChild(s.createTextNode("window."+f+"=1;"))}catch(i){}a.insertBefore(b,a.firstChild);if(A[f]){c.support.scriptEval=true;delete A[f]}try{delete b.test}catch(o){c.support.deleteExpando=false}a.removeChild(b);if(d.attachEvent&&d.fireEvent){d.attachEvent("onclick",function k(){c.support.noCloneEvent= +false;d.detachEvent("onclick",k)});d.cloneNode(true).fireEvent("onclick")}d=s.createElement("div");d.innerHTML="";a=s.createDocumentFragment();a.appendChild(d.firstChild);c.support.checkClone=a.cloneNode(true).cloneNode(true).lastChild.checked;c(function(){var k=s.createElement("div");k.style.width=k.style.paddingLeft="1px";s.body.appendChild(k);c.boxModel=c.support.boxModel=k.offsetWidth===2;s.body.removeChild(k).style.display="none"});a=function(k){var n= +s.createElement("div");k="on"+k;var r=k in n;if(!r){n.setAttribute(k,"return;");r=typeof n[k]==="function"}return r};c.support.submitBubbles=a("submit");c.support.changeBubbles=a("change");a=b=d=e=j=null}})();c.props={"for":"htmlFor","class":"className",readonly:"readOnly",maxlength:"maxLength",cellspacing:"cellSpacing",rowspan:"rowSpan",colspan:"colSpan",tabindex:"tabIndex",usemap:"useMap",frameborder:"frameBorder"};var G="jQuery"+J(),Ya=0,za={};c.extend({cache:{},expando:G,noData:{embed:true,object:true, +applet:true},data:function(a,b,d){if(!(a.nodeName&&c.noData[a.nodeName.toLowerCase()])){a=a==A?za:a;var f=a[G],e=c.cache;if(!f&&typeof b==="string"&&d===w)return null;f||(f=++Ya);if(typeof b==="object"){a[G]=f;e[f]=c.extend(true,{},b)}else if(!e[f]){a[G]=f;e[f]={}}a=e[f];if(d!==w)a[b]=d;return typeof b==="string"?a[b]:a}},removeData:function(a,b){if(!(a.nodeName&&c.noData[a.nodeName.toLowerCase()])){a=a==A?za:a;var d=a[G],f=c.cache,e=f[d];if(b){if(e){delete e[b];c.isEmptyObject(e)&&c.removeData(a)}}else{if(c.support.deleteExpando)delete a[c.expando]; +else a.removeAttribute&&a.removeAttribute(c.expando);delete f[d]}}}});c.fn.extend({data:function(a,b){if(typeof a==="undefined"&&this.length)return c.data(this[0]);else if(typeof a==="object")return this.each(function(){c.data(this,a)});var d=a.split(".");d[1]=d[1]?"."+d[1]:"";if(b===w){var f=this.triggerHandler("getData"+d[1]+"!",[d[0]]);if(f===w&&this.length)f=c.data(this[0],a);return f===w&&d[1]?this.data(d[0]):f}else return this.trigger("setData"+d[1]+"!",[d[0],b]).each(function(){c.data(this, +a,b)})},removeData:function(a){return this.each(function(){c.removeData(this,a)})}});c.extend({queue:function(a,b,d){if(a){b=(b||"fx")+"queue";var f=c.data(a,b);if(!d)return f||[];if(!f||c.isArray(d))f=c.data(a,b,c.makeArray(d));else f.push(d);return f}},dequeue:function(a,b){b=b||"fx";var d=c.queue(a,b),f=d.shift();if(f==="inprogress")f=d.shift();if(f){b==="fx"&&d.unshift("inprogress");f.call(a,function(){c.dequeue(a,b)})}}});c.fn.extend({queue:function(a,b){if(typeof a!=="string"){b=a;a="fx"}if(b=== +w)return c.queue(this[0],a);return this.each(function(){var d=c.queue(this,a,b);a==="fx"&&d[0]!=="inprogress"&&c.dequeue(this,a)})},dequeue:function(a){return this.each(function(){c.dequeue(this,a)})},delay:function(a,b){a=c.fx?c.fx.speeds[a]||a:a;b=b||"fx";return this.queue(b,function(){var d=this;setTimeout(function(){c.dequeue(d,b)},a)})},clearQueue:function(a){return this.queue(a||"fx",[])}});var Aa=/[\n\t]/g,ca=/\s+/,Za=/\r/g,$a=/href|src|style/,ab=/(button|input)/i,bb=/(button|input|object|select|textarea)/i, +cb=/^(a|area)$/i,Ba=/radio|checkbox/;c.fn.extend({attr:function(a,b){return X(this,a,b,true,c.attr)},removeAttr:function(a){return this.each(function(){c.attr(this,a,"");this.nodeType===1&&this.removeAttribute(a)})},addClass:function(a){if(c.isFunction(a))return this.each(function(n){var r=c(this);r.addClass(a.call(this,n,r.attr("class")))});if(a&&typeof a==="string")for(var b=(a||"").split(ca),d=0,f=this.length;d-1)return true;return false},val:function(a){if(a===w){var b=this[0];if(b){if(c.nodeName(b,"option"))return(b.attributes.value||{}).specified?b.value:b.text;if(c.nodeName(b,"select")){var d=b.selectedIndex,f=[],e=b.options;b=b.type==="select-one";if(d<0)return null;var j=b?d:0;for(d=b?d+1:e.length;j=0;else if(c.nodeName(this,"select")){var u=c.makeArray(r);c("option",this).each(function(){this.selected= +c.inArray(c(this).val(),u)>=0});if(!u.length)this.selectedIndex=-1}else this.value=r}})}});c.extend({attrFn:{val:true,css:true,html:true,text:true,data:true,width:true,height:true,offset:true},attr:function(a,b,d,f){if(!a||a.nodeType===3||a.nodeType===8)return w;if(f&&b in c.attrFn)return c(a)[b](d);f=a.nodeType!==1||!c.isXMLDoc(a);var e=d!==w;b=f&&c.props[b]||b;if(a.nodeType===1){var j=$a.test(b);if(b in a&&f&&!j){if(e){b==="type"&&ab.test(a.nodeName)&&a.parentNode&&c.error("type property can't be changed"); +a[b]=d}if(c.nodeName(a,"form")&&a.getAttributeNode(b))return a.getAttributeNode(b).nodeValue;if(b==="tabIndex")return(b=a.getAttributeNode("tabIndex"))&&b.specified?b.value:bb.test(a.nodeName)||cb.test(a.nodeName)&&a.href?0:w;return a[b]}if(!c.support.style&&f&&b==="style"){if(e)a.style.cssText=""+d;return a.style.cssText}e&&a.setAttribute(b,""+d);a=!c.support.hrefNormalized&&f&&j?a.getAttribute(b,2):a.getAttribute(b);return a===null?w:a}return c.style(a,b,d)}});var O=/\.(.*)$/,db=function(a){return a.replace(/[^\w\s\.\|`]/g, +function(b){return"\\"+b})};c.event={add:function(a,b,d,f){if(!(a.nodeType===3||a.nodeType===8)){if(a.setInterval&&a!==A&&!a.frameElement)a=A;var e,j;if(d.handler){e=d;d=e.handler}if(!d.guid)d.guid=c.guid++;if(j=c.data(a)){var i=j.events=j.events||{},o=j.handle;if(!o)j.handle=o=function(){return typeof c!=="undefined"&&!c.event.triggered?c.event.handle.apply(o.elem,arguments):w};o.elem=a;b=b.split(" ");for(var k,n=0,r;k=b[n++];){j=e?c.extend({},e):{handler:d,data:f};if(k.indexOf(".")>-1){r=k.split("."); +k=r.shift();j.namespace=r.slice(0).sort().join(".")}else{r=[];j.namespace=""}j.type=k;j.guid=d.guid;var u=i[k],z=c.event.special[k]||{};if(!u){u=i[k]=[];if(!z.setup||z.setup.call(a,f,r,o)===false)if(a.addEventListener)a.addEventListener(k,o,false);else a.attachEvent&&a.attachEvent("on"+k,o)}if(z.add){z.add.call(a,j);if(!j.handler.guid)j.handler.guid=d.guid}u.push(j);c.event.global[k]=true}a=null}}},global:{},remove:function(a,b,d,f){if(!(a.nodeType===3||a.nodeType===8)){var e,j=0,i,o,k,n,r,u,z=c.data(a), +C=z&&z.events;if(z&&C){if(b&&b.type){d=b.handler;b=b.type}if(!b||typeof b==="string"&&b.charAt(0)==="."){b=b||"";for(e in C)c.event.remove(a,e+b)}else{for(b=b.split(" ");e=b[j++];){n=e;i=e.indexOf(".")<0;o=[];if(!i){o=e.split(".");e=o.shift();k=new RegExp("(^|\\.)"+c.map(o.slice(0).sort(),db).join("\\.(?:.*\\.)?")+"(\\.|$)")}if(r=C[e])if(d){n=c.event.special[e]||{};for(B=f||0;B=0){a.type= +e=e.slice(0,-1);a.exclusive=true}if(!d){a.stopPropagation();c.event.global[e]&&c.each(c.cache,function(){this.events&&this.events[e]&&c.event.trigger(a,b,this.handle.elem)})}if(!d||d.nodeType===3||d.nodeType===8)return w;a.result=w;a.target=d;b=c.makeArray(b);b.unshift(a)}a.currentTarget=d;(f=c.data(d,"handle"))&&f.apply(d,b);f=d.parentNode||d.ownerDocument;try{if(!(d&&d.nodeName&&c.noData[d.nodeName.toLowerCase()]))if(d["on"+e]&&d["on"+e].apply(d,b)===false)a.result=false}catch(j){}if(!a.isPropagationStopped()&& +f)c.event.trigger(a,b,f,true);else if(!a.isDefaultPrevented()){f=a.target;var i,o=c.nodeName(f,"a")&&e==="click",k=c.event.special[e]||{};if((!k._default||k._default.call(d,a)===false)&&!o&&!(f&&f.nodeName&&c.noData[f.nodeName.toLowerCase()])){try{if(f[e]){if(i=f["on"+e])f["on"+e]=null;c.event.triggered=true;f[e]()}}catch(n){}if(i)f["on"+e]=i;c.event.triggered=false}}},handle:function(a){var b,d,f,e;a=arguments[0]=c.event.fix(a||A.event);a.currentTarget=this;b=a.type.indexOf(".")<0&&!a.exclusive; +if(!b){d=a.type.split(".");a.type=d.shift();f=new RegExp("(^|\\.)"+d.slice(0).sort().join("\\.(?:.*\\.)?")+"(\\.|$)")}e=c.data(this,"events");d=e[a.type];if(e&&d){d=d.slice(0);e=0;for(var j=d.length;e-1?c.map(a.options,function(f){return f.selected}).join("-"):"";else if(a.nodeName.toLowerCase()==="select")d=a.selectedIndex;return d},fa=function(a,b){var d=a.target,f,e;if(!(!da.test(d.nodeName)||d.readOnly)){f=c.data(d,"_change_data");e=Fa(d);if(a.type!=="focusout"||d.type!=="radio")c.data(d,"_change_data", +e);if(!(f===w||e===f))if(f!=null||e){a.type="change";return c.event.trigger(a,b,d)}}};c.event.special.change={filters:{focusout:fa,click:function(a){var b=a.target,d=b.type;if(d==="radio"||d==="checkbox"||b.nodeName.toLowerCase()==="select")return fa.call(this,a)},keydown:function(a){var b=a.target,d=b.type;if(a.keyCode===13&&b.nodeName.toLowerCase()!=="textarea"||a.keyCode===32&&(d==="checkbox"||d==="radio")||d==="select-multiple")return fa.call(this,a)},beforeactivate:function(a){a=a.target;c.data(a, +"_change_data",Fa(a))}},setup:function(){if(this.type==="file")return false;for(var a in ea)c.event.add(this,a+".specialChange",ea[a]);return da.test(this.nodeName)},teardown:function(){c.event.remove(this,".specialChange");return da.test(this.nodeName)}};ea=c.event.special.change.filters}s.addEventListener&&c.each({focus:"focusin",blur:"focusout"},function(a,b){function d(f){f=c.event.fix(f);f.type=b;return c.event.handle.call(this,f)}c.event.special[b]={setup:function(){this.addEventListener(a, +d,true)},teardown:function(){this.removeEventListener(a,d,true)}}});c.each(["bind","one"],function(a,b){c.fn[b]=function(d,f,e){if(typeof d==="object"){for(var j in d)this[b](j,f,d[j],e);return this}if(c.isFunction(f)){e=f;f=w}var i=b==="one"?c.proxy(e,function(k){c(this).unbind(k,i);return e.apply(this,arguments)}):e;if(d==="unload"&&b!=="one")this.one(d,f,e);else{j=0;for(var o=this.length;j0){y=t;break}}t=t[g]}m[q]=y}}}var f=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g, +e=0,j=Object.prototype.toString,i=false,o=true;[0,0].sort(function(){o=false;return 0});var k=function(g,h,l,m){l=l||[];var q=h=h||s;if(h.nodeType!==1&&h.nodeType!==9)return[];if(!g||typeof g!=="string")return l;for(var p=[],v,t,y,S,H=true,M=x(h),I=g;(f.exec(""),v=f.exec(I))!==null;){I=v[3];p.push(v[1]);if(v[2]){S=v[3];break}}if(p.length>1&&r.exec(g))if(p.length===2&&n.relative[p[0]])t=ga(p[0]+p[1],h);else for(t=n.relative[p[0]]?[h]:k(p.shift(),h);p.length;){g=p.shift();if(n.relative[g])g+=p.shift(); +t=ga(g,t)}else{if(!m&&p.length>1&&h.nodeType===9&&!M&&n.match.ID.test(p[0])&&!n.match.ID.test(p[p.length-1])){v=k.find(p.shift(),h,M);h=v.expr?k.filter(v.expr,v.set)[0]:v.set[0]}if(h){v=m?{expr:p.pop(),set:z(m)}:k.find(p.pop(),p.length===1&&(p[0]==="~"||p[0]==="+")&&h.parentNode?h.parentNode:h,M);t=v.expr?k.filter(v.expr,v.set):v.set;if(p.length>0)y=z(t);else H=false;for(;p.length;){var D=p.pop();v=D;if(n.relative[D])v=p.pop();else D="";if(v==null)v=h;n.relative[D](y,v,M)}}else y=[]}y||(y=t);y||k.error(D|| +g);if(j.call(y)==="[object Array]")if(H)if(h&&h.nodeType===1)for(g=0;y[g]!=null;g++){if(y[g]&&(y[g]===true||y[g].nodeType===1&&E(h,y[g])))l.push(t[g])}else for(g=0;y[g]!=null;g++)y[g]&&y[g].nodeType===1&&l.push(t[g]);else l.push.apply(l,y);else z(y,l);if(S){k(S,q,l,m);k.uniqueSort(l)}return l};k.uniqueSort=function(g){if(B){i=o;g.sort(B);if(i)for(var h=1;h":function(g,h){var l=typeof h==="string";if(l&&!/\W/.test(h)){h=h.toLowerCase();for(var m=0,q=g.length;m=0))l||m.push(v);else if(l)h[p]=false;return false},ID:function(g){return g[1].replace(/\\/g,"")},TAG:function(g){return g[1].toLowerCase()}, +CHILD:function(g){if(g[1]==="nth"){var h=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(g[2]==="even"&&"2n"||g[2]==="odd"&&"2n+1"||!/\D/.test(g[2])&&"0n+"+g[2]||g[2]);g[2]=h[1]+(h[2]||1)-0;g[3]=h[3]-0}g[0]=e++;return g},ATTR:function(g,h,l,m,q,p){h=g[1].replace(/\\/g,"");if(!p&&n.attrMap[h])g[1]=n.attrMap[h];if(g[2]==="~=")g[4]=" "+g[4]+" ";return g},PSEUDO:function(g,h,l,m,q){if(g[1]==="not")if((f.exec(g[3])||"").length>1||/^\w/.test(g[3]))g[3]=k(g[3],null,null,h);else{g=k.filter(g[3],h,l,true^q);l||m.push.apply(m, +g);return false}else if(n.match.POS.test(g[0])||n.match.CHILD.test(g[0]))return true;return g},POS:function(g){g.unshift(true);return g}},filters:{enabled:function(g){return g.disabled===false&&g.type!=="hidden"},disabled:function(g){return g.disabled===true},checked:function(g){return g.checked===true},selected:function(g){return g.selected===true},parent:function(g){return!!g.firstChild},empty:function(g){return!g.firstChild},has:function(g,h,l){return!!k(l[3],g).length},header:function(g){return/h\d/i.test(g.nodeName)}, +text:function(g){return"text"===g.type},radio:function(g){return"radio"===g.type},checkbox:function(g){return"checkbox"===g.type},file:function(g){return"file"===g.type},password:function(g){return"password"===g.type},submit:function(g){return"submit"===g.type},image:function(g){return"image"===g.type},reset:function(g){return"reset"===g.type},button:function(g){return"button"===g.type||g.nodeName.toLowerCase()==="button"},input:function(g){return/input|select|textarea|button/i.test(g.nodeName)}}, +setFilters:{first:function(g,h){return h===0},last:function(g,h,l,m){return h===m.length-1},even:function(g,h){return h%2===0},odd:function(g,h){return h%2===1},lt:function(g,h,l){return hl[3]-0},nth:function(g,h,l){return l[3]-0===h},eq:function(g,h,l){return l[3]-0===h}},filter:{PSEUDO:function(g,h,l,m){var q=h[1],p=n.filters[q];if(p)return p(g,l,h,m);else if(q==="contains")return(g.textContent||g.innerText||a([g])||"").indexOf(h[3])>=0;else if(q==="not"){h= +h[3];l=0;for(m=h.length;l=0}},ID:function(g,h){return g.nodeType===1&&g.getAttribute("id")===h},TAG:function(g,h){return h==="*"&&g.nodeType===1||g.nodeName.toLowerCase()===h},CLASS:function(g,h){return(" "+(g.className||g.getAttribute("class"))+" ").indexOf(h)>-1},ATTR:function(g,h){var l=h[1];g=n.attrHandle[l]?n.attrHandle[l](g):g[l]!=null?g[l]:g.getAttribute(l);l=g+"";var m=h[2];h=h[4];return g==null?m==="!=":m=== +"="?l===h:m==="*="?l.indexOf(h)>=0:m==="~="?(" "+l+" ").indexOf(h)>=0:!h?l&&g!==false:m==="!="?l!==h:m==="^="?l.indexOf(h)===0:m==="$="?l.substr(l.length-h.length)===h:m==="|="?l===h||l.substr(0,h.length+1)===h+"-":false},POS:function(g,h,l,m){var q=n.setFilters[h[2]];if(q)return q(g,l,h,m)}}},r=n.match.POS;for(var u in n.match){n.match[u]=new RegExp(n.match[u].source+/(?![^\[]*\])(?![^\(]*\))/.source);n.leftMatch[u]=new RegExp(/(^(?:.|\r|\n)*?)/.source+n.match[u].source.replace(/\\(\d+)/g,function(g, +h){return"\\"+(h-0+1)}))}var z=function(g,h){g=Array.prototype.slice.call(g,0);if(h){h.push.apply(h,g);return h}return g};try{Array.prototype.slice.call(s.documentElement.childNodes,0)}catch(C){z=function(g,h){h=h||[];if(j.call(g)==="[object Array]")Array.prototype.push.apply(h,g);else if(typeof g.length==="number")for(var l=0,m=g.length;l";var l=s.documentElement;l.insertBefore(g,l.firstChild);if(s.getElementById(h)){n.find.ID=function(m,q,p){if(typeof q.getElementById!=="undefined"&&!p)return(q=q.getElementById(m[1]))?q.id===m[1]||typeof q.getAttributeNode!=="undefined"&& +q.getAttributeNode("id").nodeValue===m[1]?[q]:w:[]};n.filter.ID=function(m,q){var p=typeof m.getAttributeNode!=="undefined"&&m.getAttributeNode("id");return m.nodeType===1&&p&&p.nodeValue===q}}l.removeChild(g);l=g=null})();(function(){var g=s.createElement("div");g.appendChild(s.createComment(""));if(g.getElementsByTagName("*").length>0)n.find.TAG=function(h,l){l=l.getElementsByTagName(h[1]);if(h[1]==="*"){h=[];for(var m=0;l[m];m++)l[m].nodeType===1&&h.push(l[m]);l=h}return l};g.innerHTML=""; +if(g.firstChild&&typeof g.firstChild.getAttribute!=="undefined"&&g.firstChild.getAttribute("href")!=="#")n.attrHandle.href=function(h){return h.getAttribute("href",2)};g=null})();s.querySelectorAll&&function(){var g=k,h=s.createElement("div");h.innerHTML="

      ";if(!(h.querySelectorAll&&h.querySelectorAll(".TEST").length===0)){k=function(m,q,p,v){q=q||s;if(!v&&q.nodeType===9&&!x(q))try{return z(q.querySelectorAll(m),p)}catch(t){}return g(m,q,p,v)};for(var l in g)k[l]=g[l];h=null}}(); +(function(){var g=s.createElement("div");g.innerHTML="
      ";if(!(!g.getElementsByClassName||g.getElementsByClassName("e").length===0)){g.lastChild.className="e";if(g.getElementsByClassName("e").length!==1){n.order.splice(1,0,"CLASS");n.find.CLASS=function(h,l,m){if(typeof l.getElementsByClassName!=="undefined"&&!m)return l.getElementsByClassName(h[1])};g=null}}})();var E=s.compareDocumentPosition?function(g,h){return!!(g.compareDocumentPosition(h)&16)}: +function(g,h){return g!==h&&(g.contains?g.contains(h):true)},x=function(g){return(g=(g?g.ownerDocument||g:0).documentElement)?g.nodeName!=="HTML":false},ga=function(g,h){var l=[],m="",q;for(h=h.nodeType?[h]:h;q=n.match.PSEUDO.exec(g);){m+=q[0];g=g.replace(n.match.PSEUDO,"")}g=n.relative[g]?g+"*":g;q=0;for(var p=h.length;q=0===d})};c.fn.extend({find:function(a){for(var b=this.pushStack("","find",a),d=0,f=0,e=this.length;f0)for(var j=d;j0},closest:function(a,b){if(c.isArray(a)){var d=[],f=this[0],e,j= +{},i;if(f&&a.length){e=0;for(var o=a.length;e-1:c(f).is(e)){d.push({selector:i,elem:f});delete j[i]}}f=f.parentNode}}return d}var k=c.expr.match.POS.test(a)?c(a,b||this.context):null;return this.map(function(n,r){for(;r&&r.ownerDocument&&r!==b;){if(k?k.index(r)>-1:c(r).is(a))return r;r=r.parentNode}return null})},index:function(a){if(!a||typeof a=== +"string")return c.inArray(this[0],a?c(a):this.parent().children());return c.inArray(a.jquery?a[0]:a,this)},add:function(a,b){a=typeof a==="string"?c(a,b||this.context):c.makeArray(a);b=c.merge(this.get(),a);return this.pushStack(qa(a[0])||qa(b[0])?b:c.unique(b))},andSelf:function(){return this.add(this.prevObject)}});c.each({parent:function(a){return(a=a.parentNode)&&a.nodeType!==11?a:null},parents:function(a){return c.dir(a,"parentNode")},parentsUntil:function(a,b,d){return c.dir(a,"parentNode", +d)},next:function(a){return c.nth(a,2,"nextSibling")},prev:function(a){return c.nth(a,2,"previousSibling")},nextAll:function(a){return c.dir(a,"nextSibling")},prevAll:function(a){return c.dir(a,"previousSibling")},nextUntil:function(a,b,d){return c.dir(a,"nextSibling",d)},prevUntil:function(a,b,d){return c.dir(a,"previousSibling",d)},siblings:function(a){return c.sibling(a.parentNode.firstChild,a)},children:function(a){return c.sibling(a.firstChild)},contents:function(a){return c.nodeName(a,"iframe")? +a.contentDocument||a.contentWindow.document:c.makeArray(a.childNodes)}},function(a,b){c.fn[a]=function(d,f){var e=c.map(this,b,d);eb.test(a)||(f=d);if(f&&typeof f==="string")e=c.filter(f,e);e=this.length>1?c.unique(e):e;if((this.length>1||gb.test(f))&&fb.test(a))e=e.reverse();return this.pushStack(e,a,R.call(arguments).join(","))}});c.extend({filter:function(a,b,d){if(d)a=":not("+a+")";return c.find.matches(a,b)},dir:function(a,b,d){var f=[];for(a=a[b];a&&a.nodeType!==9&&(d===w||a.nodeType!==1||!c(a).is(d));){a.nodeType=== +1&&f.push(a);a=a[b]}return f},nth:function(a,b,d){b=b||1;for(var f=0;a;a=a[d])if(a.nodeType===1&&++f===b)break;return a},sibling:function(a,b){for(var d=[];a;a=a.nextSibling)a.nodeType===1&&a!==b&&d.push(a);return d}});var Ja=/ jQuery\d+="(?:\d+|null)"/g,V=/^\s+/,Ka=/(<([\w:]+)[^>]*?)\/>/g,hb=/^(?:area|br|col|embed|hr|img|input|link|meta|param)$/i,La=/<([\w:]+)/,ib=/"},F={option:[1,""],legend:[1,"
      ","
      "],thead:[1,"","
      "],tr:[2,"","
      "],td:[3,"","
      "],col:[2,"","
      "],area:[1,"",""],_default:[0,"",""]};F.optgroup=F.option;F.tbody=F.tfoot=F.colgroup=F.caption=F.thead;F.th=F.td;if(!c.support.htmlSerialize)F._default=[1,"div
      ","
      "];c.fn.extend({text:function(a){if(c.isFunction(a))return this.each(function(b){var d= +c(this);d.text(a.call(this,b,d.text()))});if(typeof a!=="object"&&a!==w)return this.empty().append((this[0]&&this[0].ownerDocument||s).createTextNode(a));return c.text(this)},wrapAll:function(a){if(c.isFunction(a))return this.each(function(d){c(this).wrapAll(a.call(this,d))});if(this[0]){var b=c(a,this[0].ownerDocument).eq(0).clone(true);this[0].parentNode&&b.insertBefore(this[0]);b.map(function(){for(var d=this;d.firstChild&&d.firstChild.nodeType===1;)d=d.firstChild;return d}).append(this)}return this}, +wrapInner:function(a){if(c.isFunction(a))return this.each(function(b){c(this).wrapInner(a.call(this,b))});return this.each(function(){var b=c(this),d=b.contents();d.length?d.wrapAll(a):b.append(a)})},wrap:function(a){return this.each(function(){c(this).wrapAll(a)})},unwrap:function(){return this.parent().each(function(){c.nodeName(this,"body")||c(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.appendChild(a)})}, +prepend:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b,this)});else if(arguments.length){var a=c(arguments[0]);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b, +this.nextSibling)});else if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,c(arguments[0]).toArray());return a}},remove:function(a,b){for(var d=0,f;(f=this[d])!=null;d++)if(!a||c.filter(a,[f]).length){if(!b&&f.nodeType===1){c.cleanData(f.getElementsByTagName("*"));c.cleanData([f])}f.parentNode&&f.parentNode.removeChild(f)}return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++)for(b.nodeType===1&&c.cleanData(b.getElementsByTagName("*"));b.firstChild;)b.removeChild(b.firstChild); +return this},clone:function(a){var b=this.map(function(){if(!c.support.noCloneEvent&&!c.isXMLDoc(this)){var d=this.outerHTML,f=this.ownerDocument;if(!d){d=f.createElement("div");d.appendChild(this.cloneNode(true));d=d.innerHTML}return c.clean([d.replace(Ja,"").replace(/=([^="'\>\s]+\/)>/g,'="$1">').replace(V,"")],f)[0]}else return this.cloneNode(true)});if(a===true){ra(this,b);ra(this.find("*"),b.find("*"))}return b},html:function(a){if(a===w)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(Ja, +""):null;else if(typeof a==="string"&&!ta.test(a)&&(c.support.leadingWhitespace||!V.test(a))&&!F[(La.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Ka,Ma);try{for(var b=0,d=this.length;b0||e.cacheable||this.length>1?k.cloneNode(true):k)}o.length&&c.each(o,Qa)}return this}});c.fragments={};c.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){c.fn[a]=function(d){var f=[];d=c(d);var e=this.length===1&&this[0].parentNode;if(e&&e.nodeType===11&&e.childNodes.length===1&&d.length===1){d[b](this[0]); +return this}else{e=0;for(var j=d.length;e0?this.clone(true):this).get();c.fn[b].apply(c(d[e]),i);f=f.concat(i)}return this.pushStack(f,a,d.selector)}}});c.extend({clean:function(a,b,d,f){b=b||s;if(typeof b.createElement==="undefined")b=b.ownerDocument||b[0]&&b[0].ownerDocument||s;for(var e=[],j=0,i;(i=a[j])!=null;j++){if(typeof i==="number")i+="";if(i){if(typeof i==="string"&&!jb.test(i))i=b.createTextNode(i);else if(typeof i==="string"){i=i.replace(Ka,Ma);var o=(La.exec(i)||["", +""])[1].toLowerCase(),k=F[o]||F._default,n=k[0],r=b.createElement("div");for(r.innerHTML=k[1]+i+k[2];n--;)r=r.lastChild;if(!c.support.tbody){n=ib.test(i);o=o==="table"&&!n?r.firstChild&&r.firstChild.childNodes:k[1]===""&&!n?r.childNodes:[];for(k=o.length-1;k>=0;--k)c.nodeName(o[k],"tbody")&&!o[k].childNodes.length&&o[k].parentNode.removeChild(o[k])}!c.support.leadingWhitespace&&V.test(i)&&r.insertBefore(b.createTextNode(V.exec(i)[0]),r.firstChild);i=r.childNodes}if(i.nodeType)e.push(i);else e= +c.merge(e,i)}}if(d)for(j=0;e[j];j++)if(f&&c.nodeName(e[j],"script")&&(!e[j].type||e[j].type.toLowerCase()==="text/javascript"))f.push(e[j].parentNode?e[j].parentNode.removeChild(e[j]):e[j]);else{e[j].nodeType===1&&e.splice.apply(e,[j+1,0].concat(c.makeArray(e[j].getElementsByTagName("script"))));d.appendChild(e[j])}return e},cleanData:function(a){for(var b,d,f=c.cache,e=c.event.special,j=c.support.deleteExpando,i=0,o;(o=a[i])!=null;i++)if(d=o[c.expando]){b=f[d];if(b.events)for(var k in b.events)e[k]? +c.event.remove(o,k):Ca(o,k,b.handle);if(j)delete o[c.expando];else o.removeAttribute&&o.removeAttribute(c.expando);delete f[d]}}});var kb=/z-?index|font-?weight|opacity|zoom|line-?height/i,Na=/alpha\([^)]*\)/,Oa=/opacity=([^)]*)/,ha=/float/i,ia=/-([a-z])/ig,lb=/([A-Z])/g,mb=/^-?\d+(?:px)?$/i,nb=/^-?\d/,ob={position:"absolute",visibility:"hidden",display:"block"},pb=["Left","Right"],qb=["Top","Bottom"],rb=s.defaultView&&s.defaultView.getComputedStyle,Pa=c.support.cssFloat?"cssFloat":"styleFloat",ja= +function(a,b){return b.toUpperCase()};c.fn.css=function(a,b){return X(this,a,b,true,function(d,f,e){if(e===w)return c.curCSS(d,f);if(typeof e==="number"&&!kb.test(f))e+="px";c.style(d,f,e)})};c.extend({style:function(a,b,d){if(!a||a.nodeType===3||a.nodeType===8)return w;if((b==="width"||b==="height")&&parseFloat(d)<0)d=w;var f=a.style||a,e=d!==w;if(!c.support.opacity&&b==="opacity"){if(e){f.zoom=1;b=parseInt(d,10)+""==="NaN"?"":"alpha(opacity="+d*100+")";a=f.filter||c.curCSS(a,"filter")||"";f.filter= +Na.test(a)?a.replace(Na,b):b}return f.filter&&f.filter.indexOf("opacity=")>=0?parseFloat(Oa.exec(f.filter)[1])/100+"":""}if(ha.test(b))b=Pa;b=b.replace(ia,ja);if(e)f[b]=d;return f[b]},css:function(a,b,d,f){if(b==="width"||b==="height"){var e,j=b==="width"?pb:qb;function i(){e=b==="width"?a.offsetWidth:a.offsetHeight;f!=="border"&&c.each(j,function(){f||(e-=parseFloat(c.curCSS(a,"padding"+this,true))||0);if(f==="margin")e+=parseFloat(c.curCSS(a,"margin"+this,true))||0;else e-=parseFloat(c.curCSS(a, +"border"+this+"Width",true))||0})}a.offsetWidth!==0?i():c.swap(a,ob,i);return Math.max(0,Math.round(e))}return c.curCSS(a,b,d)},curCSS:function(a,b,d){var f,e=a.style;if(!c.support.opacity&&b==="opacity"&&a.currentStyle){f=Oa.test(a.currentStyle.filter||"")?parseFloat(RegExp.$1)/100+"":"";return f===""?"1":f}if(ha.test(b))b=Pa;if(!d&&e&&e[b])f=e[b];else if(rb){if(ha.test(b))b="float";b=b.replace(lb,"-$1").toLowerCase();e=a.ownerDocument.defaultView;if(!e)return null;if(a=e.getComputedStyle(a,null))f= +a.getPropertyValue(b);if(b==="opacity"&&f==="")f="1"}else if(a.currentStyle){d=b.replace(ia,ja);f=a.currentStyle[b]||a.currentStyle[d];if(!mb.test(f)&&nb.test(f)){b=e.left;var j=a.runtimeStyle.left;a.runtimeStyle.left=a.currentStyle.left;e.left=d==="fontSize"?"1em":f||0;f=e.pixelLeft+"px";e.left=b;a.runtimeStyle.left=j}}return f},swap:function(a,b,d){var f={};for(var e in b){f[e]=a.style[e];a.style[e]=b[e]}d.call(a);for(e in b)a.style[e]=f[e]}});if(c.expr&&c.expr.filters){c.expr.filters.hidden=function(a){var b= +a.offsetWidth,d=a.offsetHeight,f=a.nodeName.toLowerCase()==="tr";return b===0&&d===0&&!f?true:b>0&&d>0&&!f?false:c.curCSS(a,"display")==="none"};c.expr.filters.visible=function(a){return!c.expr.filters.hidden(a)}}var sb=J(),tb=//gi,ub=/select|textarea/i,vb=/color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week/i,N=/=\?(&|$)/,ka=/\?/,wb=/(\?|&)_=.*?(&|$)/,xb=/^(\w+:)?\/\/([^\/?#]+)/,yb=/%20/g,zb=c.fn.load;c.fn.extend({load:function(a,b,d){if(typeof a!== +"string")return zb.call(this,a);else if(!this.length)return this;var f=a.indexOf(" ");if(f>=0){var e=a.slice(f,a.length);a=a.slice(0,f)}f="GET";if(b)if(c.isFunction(b)){d=b;b=null}else if(typeof b==="object"){b=c.param(b,c.ajaxSettings.traditional);f="POST"}var j=this;c.ajax({url:a,type:f,dataType:"html",data:b,complete:function(i,o){if(o==="success"||o==="notmodified")j.html(e?c("
      ").append(i.responseText.replace(tb,"")).find(e):i.responseText);d&&j.each(d,[i.responseText,o,i])}});return this}, +serialize:function(){return c.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?c.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||ub.test(this.nodeName)||vb.test(this.type))}).map(function(a,b){a=c(this).val();return a==null?null:c.isArray(a)?c.map(a,function(d){return{name:b.name,value:d}}):{name:b.name,value:a}}).get()}});c.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "), +function(a,b){c.fn[b]=function(d){return this.bind(b,d)}});c.extend({get:function(a,b,d,f){if(c.isFunction(b)){f=f||d;d=b;b=null}return c.ajax({type:"GET",url:a,data:b,success:d,dataType:f})},getScript:function(a,b){return c.get(a,null,b,"script")},getJSON:function(a,b,d){return c.get(a,b,d,"json")},post:function(a,b,d,f){if(c.isFunction(b)){f=f||d;d=b;b={}}return c.ajax({type:"POST",url:a,data:b,success:d,dataType:f})},ajaxSetup:function(a){c.extend(c.ajaxSettings,a)},ajaxSettings:{url:location.href, +global:true,type:"GET",contentType:"application/x-www-form-urlencoded",processData:true,async:true,xhr:A.XMLHttpRequest&&(A.location.protocol!=="file:"||!A.ActiveXObject)?function(){return new A.XMLHttpRequest}:function(){try{return new A.ActiveXObject("Microsoft.XMLHTTP")}catch(a){}},accepts:{xml:"application/xml, text/xml",html:"text/html",script:"text/javascript, application/javascript",json:"application/json, text/javascript",text:"text/plain",_default:"*/*"}},lastModified:{},etag:{},ajax:function(a){function b(){e.success&& +e.success.call(k,o,i,x);e.global&&f("ajaxSuccess",[x,e])}function d(){e.complete&&e.complete.call(k,x,i);e.global&&f("ajaxComplete",[x,e]);e.global&&!--c.active&&c.event.trigger("ajaxStop")}function f(q,p){(e.context?c(e.context):c.event).trigger(q,p)}var e=c.extend(true,{},c.ajaxSettings,a),j,i,o,k=a&&a.context||e,n=e.type.toUpperCase();if(e.data&&e.processData&&typeof e.data!=="string")e.data=c.param(e.data,e.traditional);if(e.dataType==="jsonp"){if(n==="GET")N.test(e.url)||(e.url+=(ka.test(e.url)? +"&":"?")+(e.jsonp||"callback")+"=?");else if(!e.data||!N.test(e.data))e.data=(e.data?e.data+"&":"")+(e.jsonp||"callback")+"=?";e.dataType="json"}if(e.dataType==="json"&&(e.data&&N.test(e.data)||N.test(e.url))){j=e.jsonpCallback||"jsonp"+sb++;if(e.data)e.data=(e.data+"").replace(N,"="+j+"$1");e.url=e.url.replace(N,"="+j+"$1");e.dataType="script";A[j]=A[j]||function(q){o=q;b();d();A[j]=w;try{delete A[j]}catch(p){}z&&z.removeChild(C)}}if(e.dataType==="script"&&e.cache===null)e.cache=false;if(e.cache=== +false&&n==="GET"){var r=J(),u=e.url.replace(wb,"$1_="+r+"$2");e.url=u+(u===e.url?(ka.test(e.url)?"&":"?")+"_="+r:"")}if(e.data&&n==="GET")e.url+=(ka.test(e.url)?"&":"?")+e.data;e.global&&!c.active++&&c.event.trigger("ajaxStart");r=(r=xb.exec(e.url))&&(r[1]&&r[1]!==location.protocol||r[2]!==location.host);if(e.dataType==="script"&&n==="GET"&&r){var z=s.getElementsByTagName("head")[0]||s.documentElement,C=s.createElement("script");C.src=e.url;if(e.scriptCharset)C.charset=e.scriptCharset;if(!j){var B= +false;C.onload=C.onreadystatechange=function(){if(!B&&(!this.readyState||this.readyState==="loaded"||this.readyState==="complete")){B=true;b();d();C.onload=C.onreadystatechange=null;z&&C.parentNode&&z.removeChild(C)}}}z.insertBefore(C,z.firstChild);return w}var E=false,x=e.xhr();if(x){e.username?x.open(n,e.url,e.async,e.username,e.password):x.open(n,e.url,e.async);try{if(e.data||a&&a.contentType)x.setRequestHeader("Content-Type",e.contentType);if(e.ifModified){c.lastModified[e.url]&&x.setRequestHeader("If-Modified-Since", +c.lastModified[e.url]);c.etag[e.url]&&x.setRequestHeader("If-None-Match",c.etag[e.url])}r||x.setRequestHeader("X-Requested-With","XMLHttpRequest");x.setRequestHeader("Accept",e.dataType&&e.accepts[e.dataType]?e.accepts[e.dataType]+", */*":e.accepts._default)}catch(ga){}if(e.beforeSend&&e.beforeSend.call(k,x,e)===false){e.global&&!--c.active&&c.event.trigger("ajaxStop");x.abort();return false}e.global&&f("ajaxSend",[x,e]);var g=x.onreadystatechange=function(q){if(!x||x.readyState===0||q==="abort"){E|| +d();E=true;if(x)x.onreadystatechange=c.noop}else if(!E&&x&&(x.readyState===4||q==="timeout")){E=true;x.onreadystatechange=c.noop;i=q==="timeout"?"timeout":!c.httpSuccess(x)?"error":e.ifModified&&c.httpNotModified(x,e.url)?"notmodified":"success";var p;if(i==="success")try{o=c.httpData(x,e.dataType,e)}catch(v){i="parsererror";p=v}if(i==="success"||i==="notmodified")j||b();else c.handleError(e,x,i,p);d();q==="timeout"&&x.abort();if(e.async)x=null}};try{var h=x.abort;x.abort=function(){x&&h.call(x); +g("abort")}}catch(l){}e.async&&e.timeout>0&&setTimeout(function(){x&&!E&&g("timeout")},e.timeout);try{x.send(n==="POST"||n==="PUT"||n==="DELETE"?e.data:null)}catch(m){c.handleError(e,x,null,m);d()}e.async||g();return x}},handleError:function(a,b,d,f){if(a.error)a.error.call(a.context||a,b,d,f);if(a.global)(a.context?c(a.context):c.event).trigger("ajaxError",[b,a,f])},active:0,httpSuccess:function(a){try{return!a.status&&location.protocol==="file:"||a.status>=200&&a.status<300||a.status===304||a.status=== +1223||a.status===0}catch(b){}return false},httpNotModified:function(a,b){var d=a.getResponseHeader("Last-Modified"),f=a.getResponseHeader("Etag");if(d)c.lastModified[b]=d;if(f)c.etag[b]=f;return a.status===304||a.status===0},httpData:function(a,b,d){var f=a.getResponseHeader("content-type")||"",e=b==="xml"||!b&&f.indexOf("xml")>=0;a=e?a.responseXML:a.responseText;e&&a.documentElement.nodeName==="parsererror"&&c.error("parsererror");if(d&&d.dataFilter)a=d.dataFilter(a,b);if(typeof a==="string")if(b=== +"json"||!b&&f.indexOf("json")>=0)a=c.parseJSON(a);else if(b==="script"||!b&&f.indexOf("javascript")>=0)c.globalEval(a);return a},param:function(a,b){function d(i,o){if(c.isArray(o))c.each(o,function(k,n){b||/\[\]$/.test(i)?f(i,n):d(i+"["+(typeof n==="object"||c.isArray(n)?k:"")+"]",n)});else!b&&o!=null&&typeof o==="object"?c.each(o,function(k,n){d(i+"["+k+"]",n)}):f(i,o)}function f(i,o){o=c.isFunction(o)?o():o;e[e.length]=encodeURIComponent(i)+"="+encodeURIComponent(o)}var e=[];if(b===w)b=c.ajaxSettings.traditional; +if(c.isArray(a)||a.jquery)c.each(a,function(){f(this.name,this.value)});else for(var j in a)d(j,a[j]);return e.join("&").replace(yb,"+")}});var la={},Ab=/toggle|show|hide/,Bb=/^([+-]=)?([\d+-.]+)(.*)$/,W,va=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]];c.fn.extend({show:function(a,b){if(a||a===0)return this.animate(K("show",3),a,b);else{a=0;for(b=this.length;a").appendTo("body");f=e.css("display");if(f==="none")f="block";e.remove();la[d]=f}c.data(this[a],"olddisplay",f)}}a=0;for(b=this.length;a=0;f--)if(d[f].elem===this){b&&d[f](true);d.splice(f,1)}});b||this.dequeue();return this}});c.each({slideDown:K("show",1),slideUp:K("hide",1),slideToggle:K("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"}},function(a,b){c.fn[a]=function(d,f){return this.animate(b,d,f)}});c.extend({speed:function(a,b,d){var f=a&&typeof a==="object"?a:{complete:d||!d&&b||c.isFunction(a)&&a,duration:a,easing:d&&b||b&&!c.isFunction(b)&&b};f.duration=c.fx.off?0:typeof f.duration=== +"number"?f.duration:c.fx.speeds[f.duration]||c.fx.speeds._default;f.old=f.complete;f.complete=function(){f.queue!==false&&c(this).dequeue();c.isFunction(f.old)&&f.old.call(this)};return f},easing:{linear:function(a,b,d,f){return d+f*a},swing:function(a,b,d,f){return(-Math.cos(a*Math.PI)/2+0.5)*f+d}},timers:[],fx:function(a,b,d){this.options=b;this.elem=a;this.prop=d;if(!b.orig)b.orig={}}});c.fx.prototype={update:function(){this.options.step&&this.options.step.call(this.elem,this.now,this);(c.fx.step[this.prop]|| +c.fx.step._default)(this);if((this.prop==="height"||this.prop==="width")&&this.elem.style)this.elem.style.display="block"},cur:function(a){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null))return this.elem[this.prop];return(a=parseFloat(c.css(this.elem,this.prop,a)))&&a>-10000?a:parseFloat(c.curCSS(this.elem,this.prop))||0},custom:function(a,b,d){function f(j){return e.step(j)}this.startTime=J();this.start=a;this.end=b;this.unit=d||this.unit||"px";this.now=this.start; +this.pos=this.state=0;var e=this;f.elem=this.elem;if(f()&&c.timers.push(f)&&!W)W=setInterval(c.fx.tick,13)},show:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.show=true;this.custom(this.prop==="width"||this.prop==="height"?1:0,this.cur());c(this.elem).show()},hide:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.hide=true;this.custom(this.cur(),0)},step:function(a){var b=J(),d=true;if(a||b>=this.options.duration+this.startTime){this.now= +this.end;this.pos=this.state=1;this.update();this.options.curAnim[this.prop]=true;for(var f in this.options.curAnim)if(this.options.curAnim[f]!==true)d=false;if(d){if(this.options.display!=null){this.elem.style.overflow=this.options.overflow;a=c.data(this.elem,"olddisplay");this.elem.style.display=a?a:this.options.display;if(c.css(this.elem,"display")==="none")this.elem.style.display="block"}this.options.hide&&c(this.elem).hide();if(this.options.hide||this.options.show)for(var e in this.options.curAnim)c.style(this.elem, +e,this.options.orig[e]);this.options.complete.call(this.elem)}return false}else{e=b-this.startTime;this.state=e/this.options.duration;a=this.options.easing||(c.easing.swing?"swing":"linear");this.pos=c.easing[this.options.specialEasing&&this.options.specialEasing[this.prop]||a](this.state,e,0,1,this.options.duration);this.now=this.start+(this.end-this.start)*this.pos;this.update()}return true}};c.extend(c.fx,{tick:function(){for(var a=c.timers,b=0;b
      "; +a.insertBefore(b,a.firstChild);d=b.firstChild;f=d.firstChild;e=d.nextSibling.firstChild.firstChild;this.doesNotAddBorder=f.offsetTop!==5;this.doesAddBorderForTableAndCells=e.offsetTop===5;f.style.position="fixed";f.style.top="20px";this.supportsFixedPosition=f.offsetTop===20||f.offsetTop===15;f.style.position=f.style.top="";d.style.overflow="hidden";d.style.position="relative";this.subtractsBorderForOverflowNotVisible=f.offsetTop===-5;this.doesNotIncludeMarginInBodyOffset=a.offsetTop!==j;a.removeChild(b); +c.offset.initialize=c.noop},bodyOffset:function(a){var b=a.offsetTop,d=a.offsetLeft;c.offset.initialize();if(c.offset.doesNotIncludeMarginInBodyOffset){b+=parseFloat(c.curCSS(a,"marginTop",true))||0;d+=parseFloat(c.curCSS(a,"marginLeft",true))||0}return{top:b,left:d}},setOffset:function(a,b,d){if(/static/.test(c.curCSS(a,"position")))a.style.position="relative";var f=c(a),e=f.offset(),j=parseInt(c.curCSS(a,"top",true),10)||0,i=parseInt(c.curCSS(a,"left",true),10)||0;if(c.isFunction(b))b=b.call(a, +d,e);d={top:b.top-e.top+j,left:b.left-e.left+i};"using"in b?b.using.call(a,d):f.css(d)}};c.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),d=this.offset(),f=/^body|html$/i.test(b[0].nodeName)?{top:0,left:0}:b.offset();d.top-=parseFloat(c.curCSS(a,"marginTop",true))||0;d.left-=parseFloat(c.curCSS(a,"marginLeft",true))||0;f.top+=parseFloat(c.curCSS(b[0],"borderTopWidth",true))||0;f.left+=parseFloat(c.curCSS(b[0],"borderLeftWidth",true))||0;return{top:d.top- +f.top,left:d.left-f.left}},offsetParent:function(){return this.map(function(){for(var a=this.offsetParent||s.body;a&&!/^body|html$/i.test(a.nodeName)&&c.css(a,"position")==="static";)a=a.offsetParent;return a})}});c.each(["Left","Top"],function(a,b){var d="scroll"+b;c.fn[d]=function(f){var e=this[0],j;if(!e)return null;if(f!==w)return this.each(function(){if(j=wa(this))j.scrollTo(!a?f:c(j).scrollLeft(),a?f:c(j).scrollTop());else this[d]=f});else return(j=wa(e))?"pageXOffset"in j?j[a?"pageYOffset": +"pageXOffset"]:c.support.boxModel&&j.document.documentElement[d]||j.document.body[d]:e[d]}});c.each(["Height","Width"],function(a,b){var d=b.toLowerCase();c.fn["inner"+b]=function(){return this[0]?c.css(this[0],d,false,"padding"):null};c.fn["outer"+b]=function(f){return this[0]?c.css(this[0],d,false,f?"margin":"border"):null};c.fn[d]=function(f){var e=this[0];if(!e)return f==null?null:this;if(c.isFunction(f))return this.each(function(j){var i=c(this);i[d](f.call(this,j,i[d]()))});return"scrollTo"in +e&&e.document?e.document.compatMode==="CSS1Compat"&&e.document.documentElement["client"+b]||e.document.body["client"+b]:e.nodeType===9?Math.max(e.documentElement["client"+b],e.body["scroll"+b],e.documentElement["scroll"+b],e.body["offset"+b],e.documentElement["offset"+b]):f===w?c.css(e,d):this.css(d,typeof f==="string"?f:f+"px")}});A.jQuery=A.$=c})(window); \ No newline at end of file diff --git a/mysite/mysite/site_media/quickselect/jquery.quickselect.css b/mysite/mysite/site_media/quickselect/jquery.quickselect.css new file mode 100755 index 0000000..7a7d252 --- /dev/null +++ b/mysite/mysite/site_media/quickselect/jquery.quickselect.css @@ -0,0 +1,46 @@ +.quickselect_results { + padding: 0px; + border: 1px solid WindowFrame; + background-color: Window; + overflow: hidden; +} + +.quickselect_results ul { + width: 100%; + list-style-position: outside; + list-style: none; + padding: 0; + margin: 0; +} + +.quickselect_results iframe { + display:none;/*sorry for IE5*/ + display/**/:block;/*sorry for IE5*/ + position:absolute; + top:0; + left:0; + z-index:-1; + filter:mask(); + width:3000px; + height:3000px; +} + +.quickselect_results li { + margin: 0px; + padding: 2px 5px; + cursor: pointer; + display: block; + width: 100%; + font: menu; + font-size: 12px; + overflow: hidden; +} + +.quickselect_loading { + background : Window url('./indicator.gif') right center no-repeat; +} + +.quickselect_selected { + background-color: Highlight; + color: HighlightText; +} diff --git a/mysite/mysite/site_media/quickselect/jquery.quickselect.js b/mysite/mysite/site_media/quickselect/jquery.quickselect.js new file mode 100755 index 0000000..51d52ef --- /dev/null +++ b/mysite/mysite/site_media/quickselect/jquery.quickselect.js @@ -0,0 +1,509 @@ +// Credit to Anders Retteras for adding functionality preventing onblur event to fire on text input when clicking on scrollbars in MSIE / Opera. +// Minified version created at http://jsutility.pjoneil.net/ by running Obfuscation with all options unchecked, and then Compact. +// Packed version created at http://jsutility.pjoneil.net/ by running Compress on the Minified version. + +function object(obj){ + var s = function(){}; + s.prototype = obj; + return new s(); +} + +var QuickSelect; + +(function($){ + // The job of the QuickSelect object is to encapsulate all the state of a select control and manipulate the DOM and interface events. + QuickSelect = function($input_element, options){ + var self = this; + $input_element = $($input_element); + $input_element.attr('autocomplete', 'off'); + self.options = options; + + // Save the state of the control + // AllItems: hash of "index" -> [items], where index is the query that retrieves or filters the results. + // clickedLI: just a state variable for IE scrollbars. + self.AllItems = {}; + var clickedLI = false, + activeSelection = -1, + hasFocus = false, + last_keyCode, + previous_value, + timeout, + ie_stupidity = false, + $results_list, + $results_mask; + if(/MSIE (\d+\.\d+);/.test(navigator.userAgent)){ //test for MSIE x.x; + if(Number(RegExp.$1) <= 7) ie_stupidity=true; + } + + // Create the list DOM + $results_list = $('
      ').hide(); + // Supposedly if we position an iframe behind the results list, before we position the results list, it will hide select elements in IE. + $results_mask = $('